diff options
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.c | 124 |
3 files changed, 129 insertions, 3 deletions
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index cd3c2013ea70..f42cf9ea911b 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c | |||
@@ -110,6 +110,11 @@ static int imx_drm_atomic_check(struct drm_device *dev, | |||
110 | if (ret) | 110 | if (ret) |
111 | return ret; | 111 | return ret; |
112 | 112 | ||
113 | /* Assign PRG/PRE channels and check if all constrains are satisfied. */ | ||
114 | ret = ipu_planes_assign_pre(dev, state); | ||
115 | if (ret) | ||
116 | return ret; | ||
117 | |||
113 | return ret; | 118 | return ret; |
114 | } | 119 | } |
115 | 120 | ||
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index cc003334505d..295434b199db 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h | |||
@@ -39,4 +39,7 @@ int imx_drm_encoder_parse_of(struct drm_device *drm, | |||
39 | void imx_drm_connector_destroy(struct drm_connector *connector); | 39 | void imx_drm_connector_destroy(struct drm_connector *connector); |
40 | void imx_drm_encoder_destroy(struct drm_encoder *encoder); | 40 | void imx_drm_encoder_destroy(struct drm_encoder *encoder); |
41 | 41 | ||
42 | int ipu_planes_assign_pre(struct drm_device *dev, | ||
43 | struct drm_atomic_state *state); | ||
44 | |||
42 | #endif /* _IMX_DRM_H_ */ | 45 | #endif /* _IMX_DRM_H_ */ |
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index cecb8eba5c32..d63e853a0300 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c | |||
@@ -23,6 +23,17 @@ | |||
23 | #include "video/imx-ipu-v3.h" | 23 | #include "video/imx-ipu-v3.h" |
24 | #include "ipuv3-plane.h" | 24 | #include "ipuv3-plane.h" |
25 | 25 | ||
26 | struct ipu_plane_state { | ||
27 | struct drm_plane_state base; | ||
28 | bool use_pre; | ||
29 | }; | ||
30 | |||
31 | static inline struct ipu_plane_state * | ||
32 | to_ipu_plane_state(struct drm_plane_state *p) | ||
33 | { | ||
34 | return container_of(p, struct ipu_plane_state, base); | ||
35 | } | ||
36 | |||
26 | static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p) | 37 | static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p) |
27 | { | 38 | { |
28 | return container_of(p, struct ipu_plane, base); | 39 | return container_of(p, struct ipu_plane, base); |
@@ -223,6 +234,8 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel) | |||
223 | ipu_dmfc_disable_channel(ipu_plane->dmfc); | 234 | ipu_dmfc_disable_channel(ipu_plane->dmfc); |
224 | if (ipu_plane->dp) | 235 | if (ipu_plane->dp) |
225 | ipu_dp_disable(ipu_plane->ipu); | 236 | ipu_dp_disable(ipu_plane->ipu); |
237 | if (ipu_prg_present(ipu_plane->ipu)) | ||
238 | ipu_prg_channel_disable(ipu_plane->ipu_ch); | ||
226 | } | 239 | } |
227 | 240 | ||
228 | void ipu_plane_disable_deferred(struct drm_plane *plane) | 241 | void ipu_plane_disable_deferred(struct drm_plane *plane) |
@@ -246,13 +259,56 @@ static void ipu_plane_destroy(struct drm_plane *plane) | |||
246 | kfree(ipu_plane); | 259 | kfree(ipu_plane); |
247 | } | 260 | } |
248 | 261 | ||
262 | void ipu_plane_state_reset(struct drm_plane *plane) | ||
263 | { | ||
264 | struct ipu_plane_state *ipu_state; | ||
265 | |||
266 | if (plane->state) { | ||
267 | ipu_state = to_ipu_plane_state(plane->state); | ||
268 | __drm_atomic_helper_plane_destroy_state(plane->state); | ||
269 | kfree(ipu_state); | ||
270 | } | ||
271 | |||
272 | ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL); | ||
273 | |||
274 | if (ipu_state) { | ||
275 | ipu_state->base.plane = plane; | ||
276 | ipu_state->base.rotation = DRM_ROTATE_0; | ||
277 | } | ||
278 | |||
279 | plane->state = &ipu_state->base; | ||
280 | } | ||
281 | |||
282 | struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane) | ||
283 | { | ||
284 | struct ipu_plane_state *state; | ||
285 | |||
286 | if (WARN_ON(!plane->state)) | ||
287 | return NULL; | ||
288 | |||
289 | state = kmalloc(sizeof(*state), GFP_KERNEL); | ||
290 | if (state) | ||
291 | __drm_atomic_helper_plane_duplicate_state(plane, &state->base); | ||
292 | |||
293 | return &state->base; | ||
294 | } | ||
295 | |||
296 | void ipu_plane_destroy_state(struct drm_plane *plane, | ||
297 | struct drm_plane_state *state) | ||
298 | { | ||
299 | struct ipu_plane_state *ipu_state = to_ipu_plane_state(state); | ||
300 | |||
301 | __drm_atomic_helper_plane_destroy_state(state); | ||
302 | kfree(ipu_state); | ||
303 | } | ||
304 | |||
249 | static const struct drm_plane_funcs ipu_plane_funcs = { | 305 | static const struct drm_plane_funcs ipu_plane_funcs = { |
250 | .update_plane = drm_atomic_helper_update_plane, | 306 | .update_plane = drm_atomic_helper_update_plane, |
251 | .disable_plane = drm_atomic_helper_disable_plane, | 307 | .disable_plane = drm_atomic_helper_disable_plane, |
252 | .destroy = ipu_plane_destroy, | 308 | .destroy = ipu_plane_destroy, |
253 | .reset = drm_atomic_helper_plane_reset, | 309 | .reset = ipu_plane_state_reset, |
254 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | 310 | .atomic_duplicate_state = ipu_plane_duplicate_state, |
255 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | 311 | .atomic_destroy_state = ipu_plane_destroy_state, |
256 | }; | 312 | }; |
257 | 313 | ||
258 | static int ipu_plane_atomic_check(struct drm_plane *plane, | 314 | static int ipu_plane_atomic_check(struct drm_plane *plane, |
@@ -426,17 +482,33 @@ static void ipu_plane_atomic_disable(struct drm_plane *plane, | |||
426 | ipu_plane->disabling = true; | 482 | ipu_plane->disabling = true; |
427 | } | 483 | } |
428 | 484 | ||
485 | static int ipu_chan_assign_axi_id(int ipu_chan) | ||
486 | { | ||
487 | switch (ipu_chan) { | ||
488 | case IPUV3_CHANNEL_MEM_BG_SYNC: | ||
489 | return 1; | ||
490 | case IPUV3_CHANNEL_MEM_FG_SYNC: | ||
491 | return 2; | ||
492 | case IPUV3_CHANNEL_MEM_DC_SYNC: | ||
493 | return 3; | ||
494 | default: | ||
495 | return 0; | ||
496 | } | ||
497 | } | ||
498 | |||
429 | static void ipu_plane_atomic_update(struct drm_plane *plane, | 499 | static void ipu_plane_atomic_update(struct drm_plane *plane, |
430 | struct drm_plane_state *old_state) | 500 | struct drm_plane_state *old_state) |
431 | { | 501 | { |
432 | struct ipu_plane *ipu_plane = to_ipu_plane(plane); | 502 | struct ipu_plane *ipu_plane = to_ipu_plane(plane); |
433 | struct drm_plane_state *state = plane->state; | 503 | struct drm_plane_state *state = plane->state; |
504 | struct ipu_plane_state *ipu_state = to_ipu_plane_state(state); | ||
434 | struct drm_crtc_state *crtc_state = state->crtc->state; | 505 | struct drm_crtc_state *crtc_state = state->crtc->state; |
435 | struct drm_framebuffer *fb = state->fb; | 506 | struct drm_framebuffer *fb = state->fb; |
436 | struct drm_rect *dst = &state->dst; | 507 | struct drm_rect *dst = &state->dst; |
437 | unsigned long eba, ubo, vbo; | 508 | unsigned long eba, ubo, vbo; |
438 | unsigned long alpha_eba = 0; | 509 | unsigned long alpha_eba = 0; |
439 | enum ipu_color_space ics; | 510 | enum ipu_color_space ics; |
511 | unsigned int axi_id = 0; | ||
440 | int active; | 512 | int active; |
441 | 513 | ||
442 | if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG) | 514 | if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG) |
@@ -444,7 +516,23 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, | |||
444 | 516 | ||
445 | eba = drm_plane_state_to_eba(state, 0); | 517 | eba = drm_plane_state_to_eba(state, 0); |
446 | 518 | ||
519 | /* | ||
520 | * Configure PRG channel and attached PRE, this changes the EBA to an | ||
521 | * internal SRAM location. | ||
522 | */ | ||
523 | if (ipu_state->use_pre) { | ||
524 | axi_id = ipu_chan_assign_axi_id(ipu_plane->dma); | ||
525 | ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id, | ||
526 | drm_rect_width(&state->src) >> 16, | ||
527 | drm_rect_height(&state->src) >> 16, | ||
528 | state->fb->pitches[0], | ||
529 | state->fb->format->format, &eba); | ||
530 | } | ||
531 | |||
447 | if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) { | 532 | if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) { |
533 | /* nothing to do if PRE is used */ | ||
534 | if (ipu_state->use_pre) | ||
535 | return; | ||
448 | active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); | 536 | active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); |
449 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); | 537 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); |
450 | ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); | 538 | ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); |
@@ -503,6 +591,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, | |||
503 | ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); | 591 | ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); |
504 | ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); | 592 | ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); |
505 | ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]); | 593 | ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]); |
594 | ipu_cpmem_set_axi_id(ipu_plane->ipu_ch, axi_id); | ||
506 | switch (fb->format->format) { | 595 | switch (fb->format->format) { |
507 | case DRM_FORMAT_YUV420: | 596 | case DRM_FORMAT_YUV420: |
508 | case DRM_FORMAT_YVU420: | 597 | case DRM_FORMAT_YVU420: |
@@ -578,6 +667,35 @@ static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { | |||
578 | .atomic_update = ipu_plane_atomic_update, | 667 | .atomic_update = ipu_plane_atomic_update, |
579 | }; | 668 | }; |
580 | 669 | ||
670 | int ipu_planes_assign_pre(struct drm_device *dev, | ||
671 | struct drm_atomic_state *state) | ||
672 | { | ||
673 | struct drm_plane_state *plane_state; | ||
674 | struct drm_plane *plane; | ||
675 | int available_pres = ipu_prg_max_active_channels(); | ||
676 | int i; | ||
677 | |||
678 | for_each_plane_in_state(state, plane, plane_state, i) { | ||
679 | struct ipu_plane_state *ipu_state = | ||
680 | to_ipu_plane_state(plane_state); | ||
681 | struct ipu_plane *ipu_plane = to_ipu_plane(plane); | ||
682 | |||
683 | if (ipu_prg_present(ipu_plane->ipu) && available_pres && | ||
684 | plane_state->fb && | ||
685 | ipu_prg_format_supported(ipu_plane->ipu, | ||
686 | plane_state->fb->format->format, | ||
687 | plane_state->fb->modifier)) { | ||
688 | ipu_state->use_pre = true; | ||
689 | available_pres--; | ||
690 | } else { | ||
691 | ipu_state->use_pre = false; | ||
692 | } | ||
693 | } | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | EXPORT_SYMBOL_GPL(ipu_planes_assign_pre); | ||
698 | |||
581 | struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, | 699 | struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, |
582 | int dma, int dp, unsigned int possible_crtcs, | 700 | int dma, int dp, unsigned int possible_crtcs, |
583 | enum drm_plane_type type) | 701 | enum drm_plane_type type) |