aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c5
-rw-r--r--drivers/gpu/drm/imx/imx-drm.h3
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c124
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,
39void imx_drm_connector_destroy(struct drm_connector *connector); 39void imx_drm_connector_destroy(struct drm_connector *connector);
40void imx_drm_encoder_destroy(struct drm_encoder *encoder); 40void imx_drm_encoder_destroy(struct drm_encoder *encoder);
41 41
42int 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
26struct ipu_plane_state {
27 struct drm_plane_state base;
28 bool use_pre;
29};
30
31static inline struct ipu_plane_state *
32to_ipu_plane_state(struct drm_plane_state *p)
33{
34 return container_of(p, struct ipu_plane_state, base);
35}
36
26static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p) 37static 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
228void ipu_plane_disable_deferred(struct drm_plane *plane) 241void 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
262void 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
282struct 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
296void 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
249static const struct drm_plane_funcs ipu_plane_funcs = { 305static 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
258static int ipu_plane_atomic_check(struct drm_plane *plane, 314static 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
485static 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
429static void ipu_plane_atomic_update(struct drm_plane *plane, 499static 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
670int 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}
697EXPORT_SYMBOL_GPL(ipu_planes_assign_pre);
698
581struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, 699struct 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)