From afaf848dc74c61463faac14a32e53bcc68b377c8 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Mon, 1 Jun 2015 12:04:39 -0300 Subject: [PATCH 01/50] drm/exynos: fix source data argument for plane The exynos_update_plane function needs 16.16 fixed point source data. Signed-off-by: Joonyoung Shim Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 9006b947e03c0..363b0193d5808 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -127,7 +127,8 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, crtc_h = fb->height - y; return exynos_update_plane(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, x, y, crtc_w, crtc_h); + crtc_w, crtc_h, x << 16, y << 16, + crtc_w << 16, crtc_h << 16); } static void exynos_drm_crtc_disable(struct drm_crtc *crtc) @@ -202,8 +203,8 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, crtc_w = fb->width - crtc->x; crtc_h = fb->height - crtc->y; ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, crtc->x, crtc->y, - crtc_w, crtc_h); + crtc_w, crtc_h, crtc->x << 16, crtc->y << 16, + crtc_w << 16, crtc_h << 16); if (ret) { crtc->primary->fb = old_fb; spin_lock_irq(&dev->event_lock); From 43dbdad2a9a6c64e3ce8339107d8666006ca2b5d Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:41 -0300 Subject: [PATCH 02/50] drm/exynos: atomic phase 1: use drm_plane_helper_update() Rip out the check from exynos_update_plane() and create exynos_check_plane() for the check phase enabling use to use the atomic helpers to call our check and update phases when updating planes. Update all users of exynos_update_plane() accordingly to call exynos_check_plane() before. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi y Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 31 +++++++++--------- drivers/gpu/drm/exynos/exynos_drm_plane.c | 40 +++++++++++++++++------ drivers/gpu/drm/exynos/exynos_drm_plane.h | 2 +- 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 363b0193d5808..ba44c9b490eca 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -116,6 +116,7 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *fb = crtc->primary->fb; unsigned int crtc_w; unsigned int crtc_h; + int ret; /* when framebuffer changing is requested, crtc's dpms should be on */ if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { @@ -123,12 +124,17 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, return -EPERM; } + ret = exynos_check_plane(crtc->primary, fb); + if (ret) + return ret; + crtc_w = fb->width - x; crtc_h = fb->height - y; + exynos_update_plane(crtc->primary, crtc, fb, 0, 0, + crtc_w, crtc_h, x << 16, y << 16, + crtc_w << 16, crtc_h << 16); - return exynos_update_plane(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, x << 16, y << 16, - crtc_w << 16, crtc_h << 16); + return 0; } static void exynos_drm_crtc_disable(struct drm_crtc *crtc) @@ -165,7 +171,6 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct drm_framebuffer *old_fb = crtc->primary->fb; unsigned int crtc_w, crtc_h; int ret; @@ -184,6 +189,10 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, goto out; } + ret = exynos_check_plane(crtc->primary, fb); + if (ret) + goto out; + ret = drm_vblank_get(dev, exynos_crtc->pipe); if (ret) { DRM_DEBUG("failed to acquire vblank counter\n"); @@ -202,17 +211,9 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, crtc->primary->fb = fb; crtc_w = fb->width - crtc->x; crtc_h = fb->height - crtc->y; - ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, crtc->x << 16, crtc->y << 16, - crtc_w << 16, crtc_h << 16); - if (ret) { - crtc->primary->fb = old_fb; - spin_lock_irq(&dev->event_lock); - exynos_crtc->event = NULL; - drm_vblank_put(dev, exynos_crtc->pipe); - spin_unlock_irq(&dev->event_lock); - return ret; - } + exynos_update_plane(crtc->primary, crtc, fb, 0, 0, + crtc_w, crtc_h, crtc->x << 16, crtc->y << 16, + crtc_w << 16, crtc_h << 16); return 0; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index b1180fbe75469..2aaed648d3463 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -144,21 +144,15 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, plane->crtc = crtc; } -int +void exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - int ret; - - ret = exynos_check_plane(plane, fb); - if (ret < 0) - return ret; exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x >> 16, src_y >> 16, @@ -166,8 +160,6 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (exynos_crtc->ops->win_commit) exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); - - return 0; } static int exynos_disable_plane(struct drm_plane *plane) @@ -183,11 +175,37 @@ static int exynos_disable_plane(struct drm_plane *plane) } static struct drm_plane_funcs exynos_plane_funcs = { - .update_plane = exynos_update_plane, + .update_plane = drm_plane_helper_update, .disable_plane = exynos_disable_plane, .destroy = drm_plane_cleanup, }; +static int exynos_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + return exynos_check_plane(plane, state->fb); +} + +static void exynos_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct drm_plane_state *state = plane->state; + + if (!state->crtc) + return; + + exynos_update_plane(plane, state->crtc, state->fb, + state->crtc_x, state->crtc_y, + state->crtc_w, state->crtc_h, + state->src_x, state->src_y, + state->src_w, state->src_h); +} + +static const struct drm_plane_helper_funcs plane_helper_funcs = { + .atomic_check = exynos_plane_atomic_check, + .atomic_update = exynos_plane_atomic_update, +}; + static void exynos_plane_attach_zpos_property(struct drm_plane *plane, unsigned int zpos) { @@ -223,6 +241,8 @@ int exynos_plane_init(struct drm_device *dev, return err; } + drm_plane_helper_add(&exynos_plane->base, &plane_helper_funcs); + exynos_plane->zpos = zpos; if (type == DRM_PLANE_TYPE_OVERLAY) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h index f360590d14128..560ca71b57e71 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.h +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h @@ -15,7 +15,7 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h); -int exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, +void exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, From b744868cd2372c3783e460ec3c5b026a69c39332 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:42 -0300 Subject: [PATCH 03/50] drm/exynos: atomic phase 1: use drm_plane_helper_disable() The atomic helper to disable planes also uses the optional .atomic_disable() helper. The unique operation it does is calling .win_disable() Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_plane.c | 32 ++++++++++++++--------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 2aaed648d3463..6e1341e5a7b06 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -67,6 +67,9 @@ int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb) int nr; int i; + if (!fb) + return 0; + nr = exynos_drm_fb_get_buf_cnt(fb); for (i = 0; i < nr; i++) { struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i); @@ -162,21 +165,9 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); } -static int exynos_disable_plane(struct drm_plane *plane) -{ - struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc); - - if (exynos_crtc && exynos_crtc->ops->win_disable) - exynos_crtc->ops->win_disable(exynos_crtc, - exynos_plane->zpos); - - return 0; -} - static struct drm_plane_funcs exynos_plane_funcs = { .update_plane = drm_plane_helper_update, - .disable_plane = exynos_disable_plane, + .disable_plane = drm_plane_helper_disable, .destroy = drm_plane_cleanup, }; @@ -201,9 +192,24 @@ static void exynos_plane_atomic_update(struct drm_plane *plane, state->src_w, state->src_h); } +static void exynos_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(old_state->crtc); + + if (!old_state->crtc) + return; + + if (exynos_crtc->ops->win_disable) + exynos_crtc->ops->win_disable(exynos_crtc, + exynos_plane->zpos); +} + static const struct drm_plane_helper_funcs plane_helper_funcs = { .atomic_check = exynos_plane_atomic_check, .atomic_update = exynos_plane_atomic_update, + .atomic_disable = exynos_plane_atomic_disable, }; static void exynos_plane_attach_zpos_property(struct drm_plane *plane, From 199329cb3713c93c9e96831398a2e17a1e170e95 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:43 -0300 Subject: [PATCH 04/50] drm/exynos: atomic phase 1: add .mode_set_nofb() callback The new atomic infrastructure needs the .mode_set_nofb() callback to update CRTC timings before setting any plane. v2: remove WARN_ON(!crtc->state) from mode_set_nofb Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 63 +++--------------------- 1 file changed, 7 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index ba44c9b490eca..75eb61b201cad 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -62,9 +62,6 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc) if (exynos_crtc->ops->win_commit) exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); - - if (exynos_crtc->ops->commit) - exynos_crtc->ops->commit(exynos_crtc); } static bool @@ -81,60 +78,13 @@ exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static int -exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, - struct drm_framebuffer *old_fb) -{ - struct drm_framebuffer *fb = crtc->primary->fb; - unsigned int crtc_w; - unsigned int crtc_h; - int ret; - - /* - * copy the mode data adjusted by mode_fixup() into crtc->mode - * so that hardware can be seet to proper mode. - */ - memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); - - ret = exynos_check_plane(crtc->primary, fb); - if (ret < 0) - return ret; - - crtc_w = fb->width - x; - crtc_h = fb->height - y; - exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, x, y, crtc_w, crtc_h); - - return 0; -} - -static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) +static void +exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct drm_framebuffer *fb = crtc->primary->fb; - unsigned int crtc_w; - unsigned int crtc_h; - int ret; - - /* when framebuffer changing is requested, crtc's dpms should be on */ - if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { - DRM_ERROR("failed framebuffer changing request.\n"); - return -EPERM; - } - ret = exynos_check_plane(crtc->primary, fb); - if (ret) - return ret; - - crtc_w = fb->width - x; - crtc_h = fb->height - y; - exynos_update_plane(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, x << 16, y << 16, - crtc_w << 16, crtc_h << 16); - - return 0; + if (exynos_crtc->ops->commit) + exynos_crtc->ops->commit(exynos_crtc); } static void exynos_drm_crtc_disable(struct drm_crtc *crtc) @@ -159,8 +109,9 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { .prepare = exynos_drm_crtc_prepare, .commit = exynos_drm_crtc_commit, .mode_fixup = exynos_drm_crtc_mode_fixup, - .mode_set = exynos_drm_crtc_mode_set, - .mode_set_base = exynos_drm_crtc_mode_set_base, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, + .mode_set_base = drm_helper_crtc_mode_set_base, .disable = exynos_drm_crtc_disable, }; From 020e79de26599621d25001c9c1293bc8087dbedc Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 2 Jun 2015 21:04:42 +0900 Subject: [PATCH 05/50] drm/exynos: use adjusted_mode of crtc_state instead of mode Handle changes by removing copy from adjusted_mode to mode as using adjusted_mode of crtc_state. Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_plane.c | 13 +++++++------ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 6714e5b193ead..f29e4be0430ce 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -175,7 +175,7 @@ static bool decon_mode_fixup(struct exynos_drm_crtc *crtc, static void decon_commit(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; - struct drm_display_mode *mode = &crtc->base.mode; + struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; u32 val, clkdiv; if (ctx->suspended) @@ -395,7 +395,7 @@ static void decon_shadow_protect_win(struct decon_context *ctx, static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) { struct decon_context *ctx = crtc->ctx; - struct drm_display_mode *mode = &crtc->base.mode; + struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; struct exynos_drm_plane *plane; int padding; unsigned long val, alpha; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index a0edab833148a..b326b31725c16 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -337,7 +337,7 @@ static bool fimd_mode_fixup(struct exynos_drm_crtc *crtc, static void fimd_commit(struct exynos_drm_crtc *crtc) { struct fimd_context *ctx = crtc->ctx; - struct drm_display_mode *mode = &crtc->base.mode; + struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; struct fimd_driver_data *driver_data = ctx->driver_data; void *timing_base = ctx->regs + driver_data->timing_base; u32 val, clkdiv; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 6e1341e5a7b06..f0067f785c6e0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -95,11 +95,12 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_w, uint32_t src_h) { struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; unsigned int actual_w; unsigned int actual_h; - actual_w = exynos_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay); - actual_h = exynos_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay); + actual_w = exynos_plane_get_size(crtc_x, crtc_w, mode->hdisplay); + actual_h = exynos_plane_get_size(crtc_y, crtc_h, mode->vdisplay); if (crtc_x < 0) { if (actual_w) @@ -135,10 +136,10 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, exynos_plane->crtc_height = actual_h; /* set drm mode data. */ - exynos_plane->mode_width = crtc->mode.hdisplay; - exynos_plane->mode_height = crtc->mode.vdisplay; - exynos_plane->refresh = crtc->mode.vrefresh; - exynos_plane->scan_flag = crtc->mode.flags; + exynos_plane->mode_width = mode->hdisplay; + exynos_plane->mode_height = mode->vdisplay; + exynos_plane->refresh = mode->vrefresh; + exynos_plane->scan_flag = mode->flags; DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)", exynos_plane->crtc_x, exynos_plane->crtc_y, From 4ea9526b09d337b36852989c6cebf252824c867f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:44 -0300 Subject: [PATCH 06/50] drm/exynos: atomic phase 2: wire up state reset(), duplicate() and destroy() Set CRTC, planes and connectors to use the default implementations from the atomic helper library. The helpers will work to keep track of state for each DRM object. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/ps8622.c | 4 ++++ drivers/gpu/drm/bridge/ptn3460.c | 4 ++++ drivers/gpu/drm/exynos/exynos_dp_core.c | 4 ++++ drivers/gpu/drm/exynos/exynos_drm_crtc.c | 5 +++++ drivers/gpu/drm/exynos/exynos_drm_dpi.c | 4 ++++ drivers/gpu/drm/exynos/exynos_drm_drv.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_dsi.c | 4 ++++ drivers/gpu/drm/exynos/exynos_drm_plane.c | 4 ++++ drivers/gpu/drm/exynos/exynos_drm_vidi.c | 4 ++++ drivers/gpu/drm/exynos/exynos_hdmi.c | 4 ++++ 10 files changed, 39 insertions(+) diff --git a/drivers/gpu/drm/bridge/ps8622.c b/drivers/gpu/drm/bridge/ps8622.c index 32c4601141dea..4043a0f156291 100644 --- a/drivers/gpu/drm/bridge/ps8622.c +++ b/drivers/gpu/drm/bridge/ps8622.c @@ -32,6 +32,7 @@ #include "drmP.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" +#include "drm_atomic_helper.h" /* Brightness scale on the Parade chip */ #define PS8622_MAX_BRIGHTNESS 0xff @@ -503,6 +504,9 @@ static const struct drm_connector_funcs ps8622_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .detect = ps8622_detect, .destroy = ps8622_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int ps8622_attach(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c index 0e081564e70de..737aa74a51c63 100644 --- a/drivers/gpu/drm/bridge/ptn3460.c +++ b/drivers/gpu/drm/bridge/ptn3460.c @@ -26,6 +26,7 @@ #include "drm_crtc.h" #include "drm_crtc_helper.h" +#include "drm_atomic_helper.h" #include "drm_edid.h" #include "drmP.h" @@ -262,6 +263,9 @@ static struct drm_connector_funcs ptn3460_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .detect = ptn3460_detect, .destroy = ptn3460_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int ptn3460_bridge_attach(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 15b0865ecf97f..b8dd3e91fe190 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "exynos_dp_core.h" @@ -956,6 +957,9 @@ static struct drm_connector_funcs exynos_dp_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .detect = exynos_dp_detect, .destroy = exynos_dp_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int exynos_dp_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 75eb61b201cad..73ccfa70d1ef5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -14,6 +14,8 @@ #include #include +#include +#include #include "exynos_drm_crtc.h" #include "exynos_drm_drv.h" @@ -188,6 +190,9 @@ static struct drm_crtc_funcs exynos_crtc_funcs = { .set_config = drm_crtc_helper_set_config, .page_flip = exynos_drm_crtc_page_flip, .destroy = exynos_drm_crtc_destroy, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, }; struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 37678cf4425ad..ced5c236365dd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -63,6 +64,9 @@ static struct drm_connector_funcs exynos_dpi_connector_funcs = { .detect = exynos_dpi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = exynos_dpi_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int exynos_dpi_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 8ac465208eae1..08b9a8caadb7b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -98,6 +98,8 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto err_cleanup_vblank; + drm_mode_config_reset(dev); + /* * enable drm irq mode. * - with irq_enabled = true, we can use the vblank feature. diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 04927153bf38d..e4e7f749921c2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -1461,6 +1462,9 @@ static struct drm_connector_funcs exynos_dsi_connector_funcs = { .detect = exynos_dsi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = exynos_dsi_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int exynos_dsi_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index f0067f785c6e0..42fcaca7087b3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -13,6 +13,7 @@ #include #include +#include #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" #include "exynos_drm_fb.h" @@ -170,6 +171,9 @@ static struct drm_plane_funcs exynos_plane_funcs = { .update_plane = drm_plane_helper_update, .disable_plane = drm_plane_helper_disable, .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; static int exynos_plane_atomic_check(struct drm_plane *plane, diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 1b3479a8db5f0..fc3a14b3eccfc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -20,6 +20,7 @@ #include #include +#include #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" @@ -388,6 +389,9 @@ static struct drm_connector_funcs vidi_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .detect = vidi_detect, .destroy = vidi_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int vidi_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 5eba971f394a4..471e4860ead0e 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "regs-hdmi.h" @@ -1054,6 +1055,9 @@ static struct drm_connector_funcs hdmi_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .detect = hdmi_detect, .destroy = hdmi_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int hdmi_get_modes(struct drm_connector *connector) From 7cf1ff2571215fbd32967ec465a79d3f1528cc19 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:45 -0300 Subject: [PATCH 07/50] drm/exynos: atomic phase 2: keep track of framebuffer pointer Use drm_atomic_set_fb_for_plane() in the legacy page_flip path to keep track of the framebuffer pointer and reference. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 73ccfa70d1ef5..f782d1f6f796d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -168,6 +168,9 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, crtc_w, crtc_h, crtc->x << 16, crtc->y << 16, crtc_w << 16, crtc_h << 16); + if (crtc->primary->state) + drm_atomic_set_fb_for_plane(crtc->primary->state, fb); + return 0; out: From 910874a8bd2b4a09c6abb963926e076fe1471863 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:46 -0300 Subject: [PATCH 08/50] drm/exynos: atomic phase 3: atomic updates of planes Now that phase 1 and 2 are complete we can switch the update/disable_plane callbacks to their atomic version. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 3 +++ drivers/gpu/drm/exynos/exynos_drm_plane.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 142eb4e3f59ea..19c06429fc45a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "exynos_drm_drv.h" @@ -268,6 +269,8 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev) static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { .fb_create = exynos_user_fb_create, .output_poll_changed = exynos_drm_output_poll_changed, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, }; void exynos_drm_mode_config_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 42fcaca7087b3..fc332b409870f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -168,8 +168,8 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static struct drm_plane_funcs exynos_plane_funcs = { - .update_plane = drm_plane_helper_update, - .disable_plane = drm_plane_helper_disable, + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_plane_cleanup, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, From 47a7deff3606c4455f0abf0cdb1a9c89ba722a6b Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:47 -0300 Subject: [PATCH 09/50] drm/exynos: atomic phase 3: use atomic .set_config helper Now that phase 1 and 2 are complete switch .set_config helper to use the atomic one. v2: also remove .prepare() callback v3: remove .mode_set() and .mode_set_base() and encoder's .prepare() callbacks Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 10 +--------- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 6 ------ 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index f782d1f6f796d..dd1ee7f383cdd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -50,11 +50,6 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) drm_crtc_vblank_on(crtc); } -static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) -{ - /* drm framework doesn't check NULL. */ -} - static void exynos_drm_crtc_commit(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); @@ -108,12 +103,9 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { .dpms = exynos_drm_crtc_dpms, - .prepare = exynos_drm_crtc_prepare, .commit = exynos_drm_crtc_commit, .mode_fixup = exynos_drm_crtc_mode_fixup, - .mode_set = drm_helper_crtc_mode_set, .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, - .mode_set_base = drm_helper_crtc_mode_set_base, .disable = exynos_drm_crtc_disable, }; @@ -190,7 +182,7 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) } static struct drm_crtc_funcs exynos_crtc_funcs = { - .set_config = drm_crtc_helper_set_config, + .set_config = drm_atomic_helper_set_config, .page_flip = exynos_drm_crtc_page_flip, .destroy = exynos_drm_crtc_destroy, .reset = drm_atomic_helper_crtc_reset, diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 57de0bdc5a3b4..915de13842c00 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -76,11 +76,6 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, display->ops->mode_set(display, adjusted_mode); } -static void exynos_drm_encoder_prepare(struct drm_encoder *encoder) -{ - /* drm framework doesn't check NULL. */ -} - static void exynos_drm_encoder_commit(struct drm_encoder *encoder) { struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); @@ -111,7 +106,6 @@ static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { .dpms = exynos_drm_encoder_dpms, .mode_fixup = exynos_drm_encoder_mode_fixup, .mode_set = exynos_drm_encoder_mode_set, - .prepare = exynos_drm_encoder_prepare, .commit = exynos_drm_encoder_commit, .disable = exynos_drm_encoder_disable, }; From 9d5ab6a0ff7bb9565e8e1bcce5648964b6434470 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:48 -0300 Subject: [PATCH 10/50] drm/exynos: atomic phase 3: convert page flips PageFlips now use the atomic helper to work through the atomic modesetting API. Async page flips are not supported yet. v2: Add .atomic_begin() step to handle the vblank part we removed from exynos page_flip code. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 79 +++++------------------- drivers/gpu/drm/exynos/exynos_drm_fb.c | 9 ++- 2 files changed, 25 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index dd1ee7f383cdd..a13779915cde3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -101,75 +101,30 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) } } +static void exynos_crtc_atomic_begin(struct drm_crtc *crtc) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (crtc->state->event) { + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + exynos_crtc->event = crtc->state->event; + } +} + +static void exynos_crtc_atomic_flush(struct drm_crtc *crtc) +{ +} + static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { .dpms = exynos_drm_crtc_dpms, .commit = exynos_drm_crtc_commit, .mode_fixup = exynos_drm_crtc_mode_fixup, .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, .disable = exynos_drm_crtc_disable, + .atomic_begin = exynos_crtc_atomic_begin, + .atomic_flush = exynos_crtc_atomic_flush, }; -static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) -{ - struct drm_device *dev = crtc->dev; - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - unsigned int crtc_w, crtc_h; - int ret; - - /* when the page flip is requested, crtc's dpms should be on */ - if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { - DRM_ERROR("failed page flip request.\n"); - return -EINVAL; - } - - if (!event) - return -EINVAL; - - spin_lock_irq(&dev->event_lock); - if (exynos_crtc->event) { - ret = -EBUSY; - goto out; - } - - ret = exynos_check_plane(crtc->primary, fb); - if (ret) - goto out; - - ret = drm_vblank_get(dev, exynos_crtc->pipe); - if (ret) { - DRM_DEBUG("failed to acquire vblank counter\n"); - goto out; - } - - exynos_crtc->event = event; - spin_unlock_irq(&dev->event_lock); - - /* - * the pipe from user always is 0 so we can set pipe number - * of current owner to event. - */ - event->pipe = exynos_crtc->pipe; - - crtc->primary->fb = fb; - crtc_w = fb->width - crtc->x; - crtc_h = fb->height - crtc->y; - exynos_update_plane(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, crtc->x << 16, crtc->y << 16, - crtc_w << 16, crtc_h << 16); - - if (crtc->primary->state) - drm_atomic_set_fb_for_plane(crtc->primary->state, fb); - - return 0; - -out: - spin_unlock_irq(&dev->event_lock); - return ret; -} - static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); @@ -183,7 +138,7 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) static struct drm_crtc_funcs exynos_crtc_funcs = { .set_config = drm_atomic_helper_set_config, - .page_flip = exynos_drm_crtc_page_flip, + .page_flip = drm_atomic_helper_page_flip, .destroy = exynos_drm_crtc_destroy, .reset = drm_atomic_helper_crtc_reset, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 19c06429fc45a..05d229c1629a5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -266,11 +266,18 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev) exynos_drm_fbdev_init(dev); } +static int exynos_atomic_commit(struct drm_device *dev, + struct drm_atomic_state *state, + bool async) +{ + return drm_atomic_helper_commit(dev, state, false); +} + static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { .fb_create = exynos_user_fb_create, .output_poll_changed = exynos_drm_output_poll_changed, .atomic_check = drm_atomic_helper_check, - .atomic_commit = drm_atomic_helper_commit, + .atomic_commit = exynos_atomic_commit, }; void exynos_drm_mode_config_init(struct drm_device *dev) From d5f5223c464110919bb5439888eaaa72ece6ddb8 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:49 -0300 Subject: [PATCH 11/50] drm/exynos: remove exported functions from exynos_drm_plane Now that no one is using the functions exported by exynos_drm_plane due to the atomic conversion we can make remove some of the them or make them static. v2: remove unused exynos_drm_crtc v3: fix checkpatch error (reported by Joonyoung) Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_plane.c | 98 ++++++++++------------- drivers/gpu/drm/exynos/exynos_drm_plane.h | 11 --- 2 files changed, 42 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index fc332b409870f..a729980d3c2f1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -62,38 +62,13 @@ static int exynos_plane_get_size(int start, unsigned length, unsigned last) return size; } -int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb) -{ - struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - int nr; - int i; - - if (!fb) - return 0; - - nr = exynos_drm_fb_get_buf_cnt(fb); - for (i = 0; i < nr; i++) { - struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i); - - if (!buffer) { - DRM_DEBUG_KMS("buffer is null\n"); - return -EFAULT; - } - - exynos_plane->dma_addr[i] = buffer->dma_addr + fb->offsets[i]; - - DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n", - i, (unsigned long)exynos_plane->dma_addr[i]); - } - - return 0; -} - -void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) +static void exynos_plane_mode_set(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) { struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); struct drm_display_mode *mode = &crtc->state->adjusted_mode; @@ -149,24 +124,6 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, plane->crtc = crtc; } -void -exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) -{ - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - - exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, - crtc_w, crtc_h, src_x >> 16, src_y >> 16, - src_w >> 16, src_h >> 16); - - if (exynos_crtc->ops->win_commit) - exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); -} - static struct drm_plane_funcs exynos_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -179,22 +136,51 @@ static struct drm_plane_funcs exynos_plane_funcs = { static int exynos_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { - return exynos_check_plane(plane, state->fb); + struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); + int nr; + int i; + + if (!state->fb) + return 0; + + nr = exynos_drm_fb_get_buf_cnt(state->fb); + for (i = 0; i < nr; i++) { + struct exynos_drm_gem_buf *buffer = + exynos_drm_fb_buffer(state->fb, i); + + if (!buffer) { + DRM_DEBUG_KMS("buffer is null\n"); + return -EFAULT; + } + + exynos_plane->dma_addr[i] = buffer->dma_addr + + state->fb->offsets[i]; + + DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n", + i, (unsigned long)exynos_plane->dma_addr[i]); + } + + return 0; } static void exynos_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { struct drm_plane_state *state = plane->state; + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(state->crtc); + struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); if (!state->crtc) return; - exynos_update_plane(plane, state->crtc, state->fb, - state->crtc_x, state->crtc_y, - state->crtc_w, state->crtc_h, - state->src_x, state->src_y, - state->src_w, state->src_h); + exynos_plane_mode_set(plane, state->crtc, state->fb, + state->crtc_x, state->crtc_y, + state->crtc_w, state->crtc_h, + state->src_x >> 16, state->src_y >> 16, + state->src_w >> 16, state->src_h >> 16); + + if (exynos_crtc->ops->win_commit) + exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); } static void exynos_plane_atomic_disable(struct drm_plane *plane, diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h index 560ca71b57e71..8c88ae983c38c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.h +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h @@ -9,17 +9,6 @@ * */ -int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb); -void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); -void exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *exynos_plane, unsigned long possible_crtcs, enum drm_plane_type type, From bbcf7bd6406e4aee0379ecca4f160215fefec7e2 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:50 -0300 Subject: [PATCH 12/50] drm/exynos: don't disable unused functions at init Everything starts disabled so we don't really need to disable anything. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index e71e331f0188c..e0b085b4bdfac 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -275,9 +275,6 @@ int exynos_drm_fbdev_init(struct drm_device *dev) } - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); - ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); if (ret < 0) { DRM_ERROR("failed to set up hw configuration.\n"); From 3fc4867c5dc4565992533b03ce02e47cb430d789 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:51 -0300 Subject: [PATCH 13/50] drm/exynos: move exynos_drm_crtc_disable() This is a preparation commit to move exynos_drm_crtc_disable() together with the future exynos_drm_crtc_enable() that will come from the split of exynos_drm_crtc_dpms() callback. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index a13779915cde3..7125fbe02040e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -50,6 +50,23 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) drm_crtc_vblank_on(crtc); } +static void exynos_drm_crtc_disable(struct drm_crtc *crtc) +{ + struct drm_plane *plane; + int ret; + + exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + + drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { + if (plane->crtc != crtc) + continue; + + ret = plane->funcs->disable_plane(plane); + if (ret) + DRM_ERROR("Failed to disable plane %d\n", ret); + } +} + static void exynos_drm_crtc_commit(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); @@ -84,23 +101,6 @@ exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) exynos_crtc->ops->commit(exynos_crtc); } -static void exynos_drm_crtc_disable(struct drm_crtc *crtc) -{ - struct drm_plane *plane; - int ret; - - exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - - drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { - if (plane->crtc != crtc) - continue; - - ret = plane->funcs->disable_plane(plane); - if (ret) - DRM_ERROR("Failed to disable plane %d\n", ret); - } -} - static void exynos_crtc_atomic_begin(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); @@ -117,10 +117,10 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc) static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { .dpms = exynos_drm_crtc_dpms, + .disable = exynos_drm_crtc_disable, .commit = exynos_drm_crtc_commit, .mode_fixup = exynos_drm_crtc_mode_fixup, .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, - .disable = exynos_drm_crtc_disable, .atomic_begin = exynos_crtc_atomic_begin, .atomic_flush = exynos_crtc_atomic_flush, }; From d6562a291ed0b48db520f2da83faee48d1216cab Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:52 -0300 Subject: [PATCH 14/50] drm/exynos: add exynos specific .atomic_commit() exynos needs to update planes with the crtc enabled (mainly for the FIMD case) so this specific atomic commit changes the order of drm_atomic_helper_commit_modeset_enables() and drm_atomic_helper_commit_planes() to commit planes after we enable crtc and encoders. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 33 +++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 05d229c1629a5..789db6f29f316 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -270,7 +271,37 @@ static int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async) { - return drm_atomic_helper_commit(dev, state, false); + int ret; + + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) + return ret; + + /* This is the point of no return */ + + drm_atomic_helper_swap_state(dev, state); + + drm_atomic_helper_commit_modeset_disables(dev, state); + + drm_atomic_helper_commit_modeset_enables(dev, state); + + /* + * Exynos can't update planes with CRTCs and encoders disabled, + * its updates routines, specially for FIMD, requires the clocks + * to be enabled. So it is necessary to handle the modeset operations + * *before* the commit_planes() step, this way it will always + * have the relevant clocks enabled to perform the update. + */ + + drm_atomic_helper_commit_planes(dev, state); + + drm_atomic_helper_wait_for_vblanks(dev, state); + + drm_atomic_helper_cleanup_planes(dev, state); + + drm_atomic_state_free(state); + + return 0; } static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { From 63498e30652ee9b1c16b66129080749e2fa0d79e Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:53 -0300 Subject: [PATCH 15/50] drm/exynos: atomic dpms support Run dpms operations through the atomic intefaces. This basically removes the .dpms() callback from econders and crtcs and use .disable() and .enable() to turn the crtc on and off. v2: Address comments by Joonyoung: - make hdmi code call ->disable() instead of ->dpms() - do not use WARN_ON on crtc enable/disable v3: - Fix build failure after the hdmi change in v2 - Change dpms helper of ptn3460 bridge v4: - remove win_commit() call from .enable() v5: - move .atomic_check() to the atomic PageFlip patch, and transform it in .atomic_begin() Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/ps8622.c | 2 +- drivers/gpu/drm/bridge/ptn3460.c | 2 +- drivers/gpu/drm/exynos/exynos_dp_core.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 58 ++++++++------------- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_drv.h | 4 +- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 21 +++----- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 2 +- drivers/gpu/drm/exynos/exynos_hdmi.c | 6 +-- 10 files changed, 40 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/bridge/ps8622.c b/drivers/gpu/drm/bridge/ps8622.c index 4043a0f156291..1a6607beb29f2 100644 --- a/drivers/gpu/drm/bridge/ps8622.c +++ b/drivers/gpu/drm/bridge/ps8622.c @@ -500,7 +500,7 @@ static void ps8622_connector_destroy(struct drm_connector *connector) } static const struct drm_connector_funcs ps8622_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = ps8622_detect, .destroy = ps8622_connector_destroy, diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c index 737aa74a51c63..1b1bf2384815b 100644 --- a/drivers/gpu/drm/bridge/ptn3460.c +++ b/drivers/gpu/drm/bridge/ptn3460.c @@ -259,7 +259,7 @@ static void ptn3460_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs ptn3460_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = ptn3460_detect, .destroy = ptn3460_connector_destroy, diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index b8dd3e91fe190..27768d874a5ef 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -953,7 +953,7 @@ static void exynos_dp_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs exynos_dp_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = exynos_dp_detect, .destroy = exynos_dp_connector_destroy, diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 7125fbe02040e..dd8e4549ea019 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -22,40 +22,41 @@ #include "exynos_drm_encoder.h" #include "exynos_drm_plane.h" -static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) +static void exynos_drm_crtc_enable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); - - if (exynos_crtc->dpms == mode) { - DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); + if (exynos_crtc->enabled) return; - } - - if (mode > DRM_MODE_DPMS_ON) { - /* wait for the completion of page flip. */ - if (!wait_event_timeout(exynos_crtc->pending_flip_queue, - (exynos_crtc->event == NULL), HZ/20)) - exynos_crtc->event = NULL; - drm_crtc_vblank_off(crtc); - } if (exynos_crtc->ops->dpms) - exynos_crtc->ops->dpms(exynos_crtc, mode); + exynos_crtc->ops->dpms(exynos_crtc, DRM_MODE_DPMS_ON); - exynos_crtc->dpms = mode; + exynos_crtc->enabled = true; - if (mode == DRM_MODE_DPMS_ON) - drm_crtc_vblank_on(crtc); + drm_crtc_vblank_on(crtc); } static void exynos_drm_crtc_disable(struct drm_crtc *crtc) { + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct drm_plane *plane; int ret; - exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + if (!exynos_crtc->enabled) + return; + + /* wait for the completion of page flip. */ + if (!wait_event_timeout(exynos_crtc->pending_flip_queue, + (exynos_crtc->event == NULL), HZ/20)) + exynos_crtc->event = NULL; + + drm_crtc_vblank_off(crtc); + + if (exynos_crtc->ops->dpms) + exynos_crtc->ops->dpms(exynos_crtc, DRM_MODE_DPMS_OFF); + + exynos_crtc->enabled = false; drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { if (plane->crtc != crtc) @@ -67,17 +68,6 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) } } -static void exynos_drm_crtc_commit(struct drm_crtc *crtc) -{ - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct exynos_drm_plane *exynos_plane = to_exynos_plane(crtc->primary); - - exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); - - if (exynos_crtc->ops->win_commit) - exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); -} - static bool exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, @@ -116,9 +106,8 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc) } static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { - .dpms = exynos_drm_crtc_dpms, + .enable = exynos_drm_crtc_enable, .disable = exynos_drm_crtc_disable, - .commit = exynos_drm_crtc_commit, .mode_fixup = exynos_drm_crtc_mode_fixup, .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, .atomic_begin = exynos_crtc_atomic_begin, @@ -163,7 +152,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, init_waitqueue_head(&exynos_crtc->pending_flip_queue); - exynos_crtc->dpms = DRM_MODE_DPMS_OFF; exynos_crtc->pipe = pipe; exynos_crtc->type = type; exynos_crtc->ops = ops; @@ -194,7 +182,7 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(private->crtc[pipe]); - if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) + if (!exynos_crtc->enabled) return -EPERM; if (exynos_crtc->ops->enable_vblank) @@ -209,7 +197,7 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(private->crtc[pipe]); - if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) + if (!exynos_crtc->enabled) return; if (exynos_crtc->ops->disable_vblank) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index ced5c236365dd..6dc328e22ec90 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -60,7 +60,7 @@ static void exynos_dpi_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs exynos_dpi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .detect = exynos_dpi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = exynos_dpi_connector_destroy, diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 29e3fb78c615f..86d68945f1274 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -201,7 +201,7 @@ struct exynos_drm_crtc_ops { * drm framework doesn't support multiple irq yet. * we can refer to the crtc to current hardware interrupt occurred through * this pipe value. - * @dpms: store the crtc dpms value + * @enabled: if the crtc is enabled or not * @event: vblank event that is currently queued for flip * @ops: pointer to callbacks for exynos drm specific functionality * @ctx: A pointer to the crtc's implementation specific context @@ -210,7 +210,7 @@ struct exynos_drm_crtc { struct drm_crtc base; enum exynos_drm_output_type type; unsigned int pipe; - unsigned int dpms; + bool enabled; wait_queue_head_t pending_flip_queue; struct drm_pending_vblank_event *event; const struct exynos_drm_crtc_ops *ops; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index e4e7f749921c2..190f3b3c595ea 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1458,7 +1458,7 @@ static void exynos_dsi_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs exynos_dsi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .detect = exynos_dsi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = exynos_dsi_connector_destroy, diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 915de13842c00..0648ba4a520ce 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -32,17 +32,6 @@ struct exynos_drm_encoder { struct exynos_drm_display *display; }; -static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - struct exynos_drm_display *display = exynos_encoder->display; - - DRM_DEBUG_KMS("encoder dpms: %d\n", mode); - - if (display->ops->dpms) - display->ops->dpms(display, mode); -} - static bool exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, @@ -76,7 +65,7 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, display->ops->mode_set(display, adjusted_mode); } -static void exynos_drm_encoder_commit(struct drm_encoder *encoder) +static void exynos_drm_encoder_enable(struct drm_encoder *encoder) { struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); struct exynos_drm_display *display = exynos_encoder->display; @@ -90,10 +79,13 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder) static void exynos_drm_encoder_disable(struct drm_encoder *encoder) { + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); + struct exynos_drm_display *display = exynos_encoder->display; struct drm_plane *plane; struct drm_device *dev = encoder->dev; - exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + if (display->ops->dpms) + display->ops->dpms(display, DRM_MODE_DPMS_OFF); /* all planes connected to this encoder should be also disabled. */ drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { @@ -103,10 +95,9 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder) } static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { - .dpms = exynos_drm_encoder_dpms, .mode_fixup = exynos_drm_encoder_mode_fixup, .mode_set = exynos_drm_encoder_mode_set, - .commit = exynos_drm_encoder_commit, + .enable = exynos_drm_encoder_enable, .disable = exynos_drm_encoder_disable, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index fc3a14b3eccfc..63c1536aac091 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -385,7 +385,7 @@ static void vidi_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs vidi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = vidi_detect, .destroy = vidi_connector_destroy, diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 471e4860ead0e..8c3c27b6475a4 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1051,7 +1051,7 @@ static void hdmi_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs hdmi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = hdmi_detect, .destroy = hdmi_connector_destroy, @@ -2127,8 +2127,8 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode) */ if (crtc) funcs = crtc->helper_private; - if (funcs && funcs->dpms) - (*funcs->dpms)(crtc, mode); + if (funcs && funcs->disable) + (*funcs->disable)(crtc); hdmi_poweroff(hdata); break; From c4d96f1689226a2342962f2c70b16b0a3b8343ff Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:54 -0300 Subject: [PATCH 16/50] drm/exynos: remove unnecessary calls to disable_plane() The planes are already disabled by the drm_atomic_helper_commit() code so we don't need to disable the in these two places. Signed-off-by: Gustavo Padovan Reviewed-by: Joonyoung Shim Tested-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 11 ----------- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 8 -------- 2 files changed, 19 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index dd8e4549ea019..b7c6d5150345b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -40,8 +40,6 @@ static void exynos_drm_crtc_enable(struct drm_crtc *crtc) static void exynos_drm_crtc_disable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct drm_plane *plane; - int ret; if (!exynos_crtc->enabled) return; @@ -57,15 +55,6 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) exynos_crtc->ops->dpms(exynos_crtc, DRM_MODE_DPMS_OFF); exynos_crtc->enabled = false; - - drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { - if (plane->crtc != crtc) - continue; - - ret = plane->funcs->disable_plane(plane); - if (ret) - DRM_ERROR("Failed to disable plane %d\n", ret); - } } static bool diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 0648ba4a520ce..7b89fd520e457 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -81,17 +81,9 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder) { struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); struct exynos_drm_display *display = exynos_encoder->display; - struct drm_plane *plane; - struct drm_device *dev = encoder->dev; if (display->ops->dpms) display->ops->dpms(display, DRM_MODE_DPMS_OFF); - - /* all planes connected to this encoder should be also disabled. */ - drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { - if (plane->crtc && (plane->crtc == encoder->crtc)) - plane->funcs->disable_plane(plane); - } } static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { From 3cecda030f03efe5ce064f0263cd8ad2dc1e21ac Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Jun 2015 12:04:55 -0300 Subject: [PATCH 17/50] drm/exynos: split exynos_crtc->dpms in enable() and disable() To follow more closely the new atomic API we split the dpms() helper into the enable() and disable() helper to get exactly the same semantics. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 87 ++++------------------ drivers/gpu/drm/exynos/exynos_drm_crtc.c | 8 +- drivers/gpu/drm/exynos/exynos_drm_drv.h | 6 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 69 ++++------------- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 53 +++++-------- drivers/gpu/drm/exynos/exynos_mixer.c | 26 ++----- 6 files changed, 62 insertions(+), 187 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index f29e4be0430ce..d659ba24c8c2a 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -603,75 +603,39 @@ static void decon_init(struct decon_context *ctx) writel(VIDCON1_VCLK_HOLD, ctx->regs + VIDCON1(0)); } -static int decon_poweron(struct decon_context *ctx) +static void decon_enable(struct exynos_drm_crtc *crtc) { - int ret; + struct decon_context *ctx = crtc->ctx; if (!ctx->suspended) - return 0; + return; ctx->suspended = false; pm_runtime_get_sync(ctx->dev); - ret = clk_prepare_enable(ctx->pclk); - if (ret < 0) { - DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret); - goto pclk_err; - } - - ret = clk_prepare_enable(ctx->aclk); - if (ret < 0) { - DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret); - goto aclk_err; - } - - ret = clk_prepare_enable(ctx->eclk); - if (ret < 0) { - DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret); - goto eclk_err; - } - - ret = clk_prepare_enable(ctx->vclk); - if (ret < 0) { - DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret); - goto vclk_err; - } + clk_prepare_enable(ctx->pclk); + clk_prepare_enable(ctx->aclk); + clk_prepare_enable(ctx->eclk); + clk_prepare_enable(ctx->vclk); decon_init(ctx); /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(0, &ctx->irq_flags)) { - ret = decon_enable_vblank(ctx->crtc); - if (ret) { - DRM_ERROR("Failed to re-enable vblank [%d]\n", ret); - goto err; - } - } + if (test_and_clear_bit(0, &ctx->irq_flags)) + decon_enable_vblank(ctx->crtc); decon_window_resume(ctx); decon_apply(ctx); - - return 0; - -err: - clk_disable_unprepare(ctx->vclk); -vclk_err: - clk_disable_unprepare(ctx->eclk); -eclk_err: - clk_disable_unprepare(ctx->aclk); -aclk_err: - clk_disable_unprepare(ctx->pclk); -pclk_err: - ctx->suspended = true; - return ret; } -static int decon_poweroff(struct decon_context *ctx) +static void decon_disable(struct exynos_drm_crtc *crtc) { + struct decon_context *ctx = crtc->ctx; + if (ctx->suspended) - return 0; + return; /* * We need to make sure that all windows are disabled before we @@ -688,30 +652,11 @@ static int decon_poweroff(struct decon_context *ctx) pm_runtime_put_sync(ctx->dev); ctx->suspended = true; - return 0; -} - -static void decon_dpms(struct exynos_drm_crtc *crtc, int mode) -{ - DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); - - switch (mode) { - case DRM_MODE_DPMS_ON: - decon_poweron(crtc->ctx); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - decon_poweroff(crtc->ctx); - break; - default: - DRM_DEBUG_KMS("unspecified mode %d\n", mode); - break; - } } static const struct exynos_drm_crtc_ops decon_crtc_ops = { - .dpms = decon_dpms, + .enable = decon_enable, + .disable = decon_disable, .mode_fixup = decon_mode_fixup, .commit = decon_commit, .enable_vblank = decon_enable_vblank, @@ -796,7 +741,7 @@ static void decon_unbind(struct device *dev, struct device *master, { struct decon_context *ctx = dev_get_drvdata(dev); - decon_dpms(ctx->crtc, DRM_MODE_DPMS_OFF); + decon_disable(ctx->crtc); if (ctx->display) exynos_dpi_remove(ctx->display); diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index b7c6d5150345b..644b4b76e0717 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -29,8 +29,8 @@ static void exynos_drm_crtc_enable(struct drm_crtc *crtc) if (exynos_crtc->enabled) return; - if (exynos_crtc->ops->dpms) - exynos_crtc->ops->dpms(exynos_crtc, DRM_MODE_DPMS_ON); + if (exynos_crtc->ops->enable) + exynos_crtc->ops->enable(exynos_crtc); exynos_crtc->enabled = true; @@ -51,8 +51,8 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) drm_crtc_vblank_off(crtc); - if (exynos_crtc->ops->dpms) - exynos_crtc->ops->dpms(exynos_crtc, DRM_MODE_DPMS_OFF); + if (exynos_crtc->ops->disable) + exynos_crtc->ops->disable(exynos_crtc); exynos_crtc->enabled = false; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 86d68945f1274..1c66f65e8b829 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -157,7 +157,8 @@ struct exynos_drm_display { /* * Exynos drm crtc ops * - * @dpms: control device power. + * @enable: enable the device + * @disable: disable the device * @mode_fixup: fix mode data before applying it * @commit: set current hw specific display mode to hw. * @enable_vblank: specific driver callback for enabling vblank interrupt. @@ -175,7 +176,8 @@ struct exynos_drm_display { */ struct exynos_drm_crtc; struct exynos_drm_crtc_ops { - void (*dpms)(struct exynos_drm_crtc *crtc, int mode); + void (*enable)(struct exynos_drm_crtc *crtc); + void (*disable)(struct exynos_drm_crtc *crtc); bool (*mode_fixup)(struct exynos_drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index b326b31725c16..96618534358e1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -805,57 +805,35 @@ static void fimd_apply(struct fimd_context *ctx) fimd_commit(ctx->crtc); } -static int fimd_poweron(struct fimd_context *ctx) +static void fimd_enable(struct exynos_drm_crtc *crtc) { - int ret; + struct fimd_context *ctx = crtc->ctx; if (!ctx->suspended) - return 0; + return; ctx->suspended = false; pm_runtime_get_sync(ctx->dev); - ret = clk_prepare_enable(ctx->bus_clk); - if (ret < 0) { - DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret); - goto bus_clk_err; - } - - ret = clk_prepare_enable(ctx->lcd_clk); - if (ret < 0) { - DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret); - goto lcd_clk_err; - } + clk_prepare_enable(ctx->bus_clk); + clk_prepare_enable(ctx->lcd_clk); /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(0, &ctx->irq_flags)) { - ret = fimd_enable_vblank(ctx->crtc); - if (ret) { - DRM_ERROR("Failed to re-enable vblank [%d]\n", ret); - goto enable_vblank_err; - } - } + if (test_and_clear_bit(0, &ctx->irq_flags)) + fimd_enable_vblank(ctx->crtc); fimd_window_resume(ctx); fimd_apply(ctx); - - return 0; - -enable_vblank_err: - clk_disable_unprepare(ctx->lcd_clk); -lcd_clk_err: - clk_disable_unprepare(ctx->bus_clk); -bus_clk_err: - ctx->suspended = true; - return ret; } -static int fimd_poweroff(struct fimd_context *ctx) +static void fimd_disable(struct exynos_drm_crtc *crtc) { + struct fimd_context *ctx = crtc->ctx; + if (ctx->suspended) - return 0; + return; /* * We need to make sure that all windows are disabled before we @@ -870,26 +848,6 @@ static int fimd_poweroff(struct fimd_context *ctx) pm_runtime_put_sync(ctx->dev); ctx->suspended = true; - return 0; -} - -static void fimd_dpms(struct exynos_drm_crtc *crtc, int mode) -{ - DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); - - switch (mode) { - case DRM_MODE_DPMS_ON: - fimd_poweron(crtc->ctx); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - fimd_poweroff(crtc->ctx); - break; - default: - DRM_DEBUG_KMS("unspecified mode %d\n", mode); - break; - } } static void fimd_trigger(struct device *dev) @@ -964,7 +922,8 @@ static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) } static const struct exynos_drm_crtc_ops fimd_crtc_ops = { - .dpms = fimd_dpms, + .enable = fimd_enable, + .disable = fimd_disable, .mode_fixup = fimd_mode_fixup, .commit = fimd_commit, .enable_vblank = fimd_enable_vblank, @@ -1051,7 +1010,7 @@ static void fimd_unbind(struct device *dev, struct device *master, { struct fimd_context *ctx = dev_get_drvdata(dev); - fimd_dpms(ctx->crtc, DRM_MODE_DPMS_OFF); + fimd_disable(ctx->crtc); fimd_iommu_detach_devices(ctx); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 63c1536aac091..abe4ee00654ba 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -153,56 +153,38 @@ static void vidi_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) /* TODO. */ } -static int vidi_power_on(struct vidi_context *ctx, bool enable) +static void vidi_enable(struct exynos_drm_crtc *crtc) { + struct vidi_context *ctx = crtc->ctx; struct exynos_drm_plane *plane; int i; - DRM_DEBUG_KMS("%s\n", __FILE__); - - if (enable != false && enable != true) - return -EINVAL; + mutex_lock(&ctx->lock); - if (enable) { - ctx->suspended = false; + ctx->suspended = false; - /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(0, &ctx->irq_flags)) - vidi_enable_vblank(ctx->crtc); + /* if vblank was enabled status, enable it again. */ + if (test_and_clear_bit(0, &ctx->irq_flags)) + vidi_enable_vblank(ctx->crtc); - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - if (plane->enabled) - vidi_win_commit(ctx->crtc, i); - } - } else { - ctx->suspended = true; + for (i = 0; i < WINDOWS_NR; i++) { + plane = &ctx->planes[i]; + if (plane->enabled) + vidi_win_commit(ctx->crtc, i); } - return 0; + mutex_unlock(&ctx->lock); } -static void vidi_dpms(struct exynos_drm_crtc *crtc, int mode) +static void vidi_disable(struct exynos_drm_crtc *crtc) { struct vidi_context *ctx = crtc->ctx; - - DRM_DEBUG_KMS("%d\n", mode); + struct exynos_drm_plane *plane; + int i; mutex_lock(&ctx->lock); - switch (mode) { - case DRM_MODE_DPMS_ON: - vidi_power_on(ctx, true); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - vidi_power_on(ctx, false); - break; - default: - DRM_DEBUG_KMS("unspecified mode %d\n", mode); - break; - } + ctx->suspended = true; mutex_unlock(&ctx->lock); } @@ -219,7 +201,8 @@ static int vidi_ctx_initialize(struct vidi_context *ctx, } static const struct exynos_drm_crtc_ops vidi_crtc_ops = { - .dpms = vidi_dpms, + .enable = vidi_enable, + .disable = vidi_disable, .enable_vblank = vidi_enable_vblank, .disable_vblank = vidi_disable_vblank, .win_commit = vidi_win_commit, diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 8874c1fcb3ab7..6bab71704bab4 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1027,8 +1027,9 @@ static void mixer_window_resume(struct mixer_context *ctx) } } -static void mixer_poweron(struct mixer_context *ctx) +static void mixer_enable(struct exynos_drm_crtc *crtc) { + struct mixer_context *ctx = crtc->ctx; struct mixer_resources *res = &ctx->mixer_res; mutex_lock(&ctx->mixer_mutex); @@ -1061,8 +1062,9 @@ static void mixer_poweron(struct mixer_context *ctx) mixer_window_resume(ctx); } -static void mixer_poweroff(struct mixer_context *ctx) +static void mixer_disable(struct exynos_drm_crtc *crtc) { + struct mixer_context *ctx = crtc->ctx; struct mixer_resources *res = &ctx->mixer_res; mutex_lock(&ctx->mixer_mutex); @@ -1093,23 +1095,6 @@ static void mixer_poweroff(struct mixer_context *ctx) pm_runtime_put_sync(ctx->dev); } -static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode) -{ - switch (mode) { - case DRM_MODE_DPMS_ON: - mixer_poweron(crtc->ctx); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - mixer_poweroff(crtc->ctx); - break; - default: - DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); - break; - } -} - /* Only valid for Mixer version 16.0.33.0 */ int mixer_check_mode(struct drm_display_mode *mode) { @@ -1131,7 +1116,8 @@ int mixer_check_mode(struct drm_display_mode *mode) } static const struct exynos_drm_crtc_ops mixer_crtc_ops = { - .dpms = mixer_dpms, + .enable = mixer_enable, + .disable = mixer_disable, .enable_vblank = mixer_enable_vblank, .disable_vblank = mixer_disable_vblank, .wait_for_vblank = mixer_wait_for_vblank, From 7491e5b48eefd426c8059388470c268d7508ef50 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Wed, 3 Jun 2015 11:25:00 +0900 Subject: [PATCH 18/50] drm/exynos: vidi: remove unused varables This patch removes unnsed varables in vidi_disable function. Signed-off-by: Inki Dae Reviewed-by: Gustavo Padovan --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index abe4ee00654ba..16dc68cf7c88a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -179,8 +179,6 @@ static void vidi_enable(struct exynos_drm_crtc *crtc) static void vidi_disable(struct exynos_drm_crtc *crtc) { struct vidi_context *ctx = crtc->ctx; - struct exynos_drm_plane *plane; - int i; mutex_lock(&ctx->lock); From 1e5507cecbf3fdb2bd7914b8ebc396ad23f3da67 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Wed, 3 Jun 2015 11:31:23 +0900 Subject: [PATCH 19/50] drm/exynos: add a dependency on FB_S3C to DECON driver This patch makes one of Linux framebuffer and DRM CRTC drivers to be enabled. Display controllers, FIMD and DECON, can be controlled by Linux framebuffer or DRM CRTC drivers so only one of them should be enabled. Signed-off-by: Inki Dae Reviewed-by: Gustavo Padovan --- drivers/gpu/drm/exynos/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 0a6780367d286..8203283dc3c25 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -26,7 +26,7 @@ config DRM_EXYNOS_FIMD config DRM_EXYNOS7_DECON bool "Exynos DRM DECON" - depends on DRM_EXYNOS + depends on DRM_EXYNOS && !FB_S3C select FB_MODE_HELPERS help Choose this option if you want to use Exynos DECON for DRM. From 38000dbb71ded4121b27338a2d41ad060001592a Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 3 Jun 2015 17:17:16 -0300 Subject: [PATCH 20/50] drm/exynos: add error messages if clks failed to get enabled Check error and call DRM_ERROR if clk_prepare_enable() fails. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 28 ++++++++++++++++--- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 14 ++++++++-- drivers/gpu/drm/exynos/exynos_mixer.c | 31 ++++++++++++++++++---- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index d659ba24c8c2a..d9798e2aedda5 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -606,6 +606,7 @@ static void decon_init(struct decon_context *ctx) static void decon_enable(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; + int ret; if (!ctx->suspended) return; @@ -614,10 +615,29 @@ static void decon_enable(struct exynos_drm_crtc *crtc) pm_runtime_get_sync(ctx->dev); - clk_prepare_enable(ctx->pclk); - clk_prepare_enable(ctx->aclk); - clk_prepare_enable(ctx->eclk); - clk_prepare_enable(ctx->vclk); + ret = clk_prepare_enable(ctx->pclk); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret); + return; + } + + ret = clk_prepare_enable(ctx->aclk); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret); + return; + } + + ret = clk_prepare_enable(ctx->eclk); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret); + return; + } + + ret = clk_prepare_enable(ctx->vclk); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret); + return; + } decon_init(ctx); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 96618534358e1..7c8ba614cd441 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -808,6 +808,7 @@ static void fimd_apply(struct fimd_context *ctx) static void fimd_enable(struct exynos_drm_crtc *crtc) { struct fimd_context *ctx = crtc->ctx; + int ret; if (!ctx->suspended) return; @@ -816,8 +817,17 @@ static void fimd_enable(struct exynos_drm_crtc *crtc) pm_runtime_get_sync(ctx->dev); - clk_prepare_enable(ctx->bus_clk); - clk_prepare_enable(ctx->lcd_clk); + ret = clk_prepare_enable(ctx->bus_clk); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret); + return; + } + + ret = clk_prepare_enable(ctx->lcd_clk); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret); + return; + } /* if vblank was enabled status, enable it again. */ if (test_and_clear_bit(0, &ctx->irq_flags)) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 6bab71704bab4..1b77fc7660512 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1031,6 +1031,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) { struct mixer_context *ctx = crtc->ctx; struct mixer_resources *res = &ctx->mixer_res; + int ret; mutex_lock(&ctx->mixer_mutex); if (ctx->powered) { @@ -1042,12 +1043,32 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) pm_runtime_get_sync(ctx->dev); - clk_prepare_enable(res->mixer); - clk_prepare_enable(res->hdmi); + ret = clk_prepare_enable(res->mixer); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret); + return; + } + ret = clk_prepare_enable(res->hdmi); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret); + return; + } if (ctx->vp_enabled) { - clk_prepare_enable(res->vp); - if (ctx->has_sclk) - clk_prepare_enable(res->sclk_mixer); + ret = clk_prepare_enable(res->vp); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n", + ret); + return; + } + if (ctx->has_sclk) { + ret = clk_prepare_enable(res->sclk_mixer); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the " \ + "sclk_mixer clk [%d]\n", + ret); + return; + } + } } mutex_lock(&ctx->mixer_mutex); From 417133e46924a9aa7bfa0e17dab01a1b475878c4 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 11 Jun 2015 23:20:52 +0900 Subject: [PATCH 21/50] drm/exynos: consolidate driver/device initialization code Code registering different drivers and simple platform devices was dispersed across multiple sub-modules. This patch moves it to one place. As a result initialization code is shorter and cleaner and should simplify further development. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 220 ++++++++++++++--------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 17 -- drivers/gpu/drm/exynos/exynos_drm_ipp.c | 27 --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 35 ---- 4 files changed, 138 insertions(+), 161 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 08b9a8caadb7b..835dec1c8fea8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -38,8 +38,6 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 -static struct platform_device *exynos_drm_pdev; - static DEFINE_MUTEX(drm_component_lock); static LIST_HEAD(drm_component_list); @@ -527,7 +525,40 @@ static const struct component_master_ops exynos_drm_ops = { .unbind = exynos_drm_unbind, }; +static int exynos_drm_platform_probe(struct platform_device *pdev) +{ + struct component_match *match; + + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls); + + match = exynos_drm_match_add(&pdev->dev); + if (IS_ERR(match)) + return PTR_ERR(match); + + return component_master_add_with_match(&pdev->dev, &exynos_drm_ops, + match); +} + +static int exynos_drm_platform_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &exynos_drm_ops); + return 0; +} + +static struct platform_driver exynos_drm_platform_driver = { + .probe = exynos_drm_platform_probe, + .remove = exynos_drm_platform_remove, + .driver = { + .name = "exynos-drm", + .pm = &exynos_drm_pm_ops, + }, +}; + static struct platform_driver *const exynos_drm_kms_drivers[] = { +#ifdef CONFIG_DRM_EXYNOS_VIDI + &vidi_driver, +#endif #ifdef CONFIG_DRM_EXYNOS_FIMD &fimd_driver, #endif @@ -562,30 +593,109 @@ static struct platform_driver *const exynos_drm_non_kms_drivers[] = { #ifdef CONFIG_DRM_EXYNOS_IPP &ipp_driver, #endif + &exynos_drm_platform_driver, }; -static int exynos_drm_platform_probe(struct platform_device *pdev) + +static struct platform_driver *const exynos_drm_drv_with_simple_dev[] = { +#ifdef CONFIG_DRM_EXYNOS_VIDI + &vidi_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_IPP + &ipp_driver, +#endif + &exynos_drm_platform_driver, +}; + +#define PDEV_COUNT ARRAY_SIZE(exynos_drm_drv_with_simple_dev) + +static struct platform_device *exynos_drm_pdevs[PDEV_COUNT]; + +static void exynos_drm_unregister_devices(void) { - struct component_match *match; + int i = PDEV_COUNT; - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls); + while (--i >= 0) { + platform_device_unregister(exynos_drm_pdevs[i]); + exynos_drm_pdevs[i] = NULL; + } +} - match = exynos_drm_match_add(&pdev->dev); - if (IS_ERR(match)) { - return PTR_ERR(match); +static int exynos_drm_register_devices(void) +{ + int i; + + for (i = 0; i < PDEV_COUNT; ++i) { + struct platform_driver *d = exynos_drm_drv_with_simple_dev[i]; + struct platform_device *pdev = + platform_device_register_simple(d->driver.name, -1, + NULL, 0); + + if (!IS_ERR(pdev)) { + exynos_drm_pdevs[i] = pdev; + continue; + } + while (--i >= 0) { + platform_device_unregister(exynos_drm_pdevs[i]); + exynos_drm_pdevs[i] = NULL; + } + + return PTR_ERR(pdev); } - return component_master_add_with_match(&pdev->dev, &exynos_drm_ops, - match); + return 0; } -static int exynos_drm_platform_remove(struct platform_device *pdev) +static void exynos_drm_unregister_drivers(struct platform_driver * const *drv, + int count) { - component_master_del(&pdev->dev, &exynos_drm_ops); + while (--count >= 0) + platform_driver_unregister(drv[count]); +} + +static int exynos_drm_register_drivers(struct platform_driver * const *drv, + int count) +{ + int i, ret; + + for (i = 0; i < count; ++i) { + ret = platform_driver_register(drv[i]); + if (!ret) + continue; + + while (--i >= 0) + platform_driver_unregister(drv[i]); + + return ret; + } + return 0; } +static inline int exynos_drm_register_kms_drivers(void) +{ + return exynos_drm_register_drivers(exynos_drm_kms_drivers, + ARRAY_SIZE(exynos_drm_kms_drivers)); +} + +static inline int exynos_drm_register_non_kms_drivers(void) +{ + return exynos_drm_register_drivers(exynos_drm_non_kms_drivers, + ARRAY_SIZE(exynos_drm_non_kms_drivers)); +} + +static inline void exynos_drm_unregister_kms_drivers(void) +{ + exynos_drm_unregister_drivers(exynos_drm_kms_drivers, + ARRAY_SIZE(exynos_drm_kms_drivers)); +} + +static inline void exynos_drm_unregister_non_kms_drivers(void) +{ + exynos_drm_unregister_drivers(exynos_drm_non_kms_drivers, + ARRAY_SIZE(exynos_drm_non_kms_drivers)); +} + static const char * const strings[] = { "samsung,exynos3", "samsung,exynos4", @@ -593,19 +703,10 @@ static const char * const strings[] = { "samsung,exynos7", }; -static struct platform_driver exynos_drm_platform_driver = { - .probe = exynos_drm_platform_probe, - .remove = exynos_drm_platform_remove, - .driver = { - .name = "exynos-drm", - .pm = &exynos_drm_pm_ops, - }, -}; - static int exynos_drm_init(void) { bool is_exynos = false; - int ret, i, j; + int ret, i; /* * Register device object only in case of Exynos SoC. @@ -624,79 +725,34 @@ static int exynos_drm_init(void) if (!is_exynos) return -ENODEV; - exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, - NULL, 0); - if (IS_ERR(exynos_drm_pdev)) - return PTR_ERR(exynos_drm_pdev); - - ret = exynos_drm_probe_vidi(); - if (ret < 0) - goto err_unregister_pd; - - for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { - ret = platform_driver_register(exynos_drm_kms_drivers[i]); - if (ret < 0) - goto err_unregister_kms_drivers; - } - - for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { - ret = platform_driver_register(exynos_drm_non_kms_drivers[j]); - if (ret < 0) - goto err_unregister_non_kms_drivers; - } + ret = exynos_drm_register_devices(); + if (ret) + return ret; -#ifdef CONFIG_DRM_EXYNOS_IPP - ret = exynos_platform_device_ipp_register(); - if (ret < 0) - goto err_unregister_non_kms_drivers; -#endif + ret = exynos_drm_register_kms_drivers(); + if (ret) + goto err_unregister_pdevs; - ret = platform_driver_register(&exynos_drm_platform_driver); + ret = exynos_drm_register_non_kms_drivers(); if (ret) - goto err_unregister_resources; + goto err_unregister_kms_drivers; return 0; -err_unregister_resources: -#ifdef CONFIG_DRM_EXYNOS_IPP - exynos_platform_device_ipp_unregister(); -#endif - -err_unregister_non_kms_drivers: - while (--j >= 0) - platform_driver_unregister(exynos_drm_non_kms_drivers[j]); - err_unregister_kms_drivers: - while (--i >= 0) - platform_driver_unregister(exynos_drm_kms_drivers[i]); + exynos_drm_unregister_kms_drivers(); - exynos_drm_remove_vidi(); - -err_unregister_pd: - platform_device_unregister(exynos_drm_pdev); +err_unregister_pdevs: + exynos_drm_unregister_devices(); return ret; } static void exynos_drm_exit(void) { - int i; - -#ifdef CONFIG_DRM_EXYNOS_IPP - exynos_platform_device_ipp_unregister(); -#endif - - for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i) - platform_driver_unregister(exynos_drm_non_kms_drivers[i]); - - for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i) - platform_driver_unregister(exynos_drm_kms_drivers[i]); - - platform_driver_unregister(&exynos_drm_platform_driver); - - exynos_drm_remove_vidi(); - - platform_device_unregister(exynos_drm_pdev); + exynos_drm_unregister_non_kms_drivers(); + exynos_drm_unregister_kms_drivers(); + exynos_drm_unregister_devices(); } module_init(exynos_drm_init); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 1c66f65e8b829..b308e908dd2b6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -295,15 +295,6 @@ int exynos_drm_device_subdrv_remove(struct drm_device *dev); int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); -#ifdef CONFIG_DRM_EXYNOS_IPP -int exynos_platform_device_ipp_register(void); -void exynos_platform_device_ipp_unregister(void); -#else -static inline int exynos_platform_device_ipp_register(void) { return 0; } -static inline void exynos_platform_device_ipp_unregister(void) {} -#endif - - #ifdef CONFIG_DRM_EXYNOS_DPI struct exynos_drm_display * exynos_dpi_probe(struct device *dev); int exynos_dpi_remove(struct exynos_drm_display *display); @@ -316,14 +307,6 @@ static inline int exynos_dpi_remove(struct exynos_drm_display *display) } #endif -#ifdef CONFIG_DRM_EXYNOS_VIDI -int exynos_drm_probe_vidi(void); -void exynos_drm_remove_vidi(void); -#else -static inline int exynos_drm_probe_vidi(void) { return 0; } -static inline void exynos_drm_remove_vidi(void) {} -#endif - /* This function creates a encoder and a connector, and initializes them. */ int exynos_drm_create_enc_conn(struct drm_device *dev, struct exynos_drm_display *display); diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index b7f1cbc46cc2c..f594dd78963aa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -45,9 +45,6 @@ #define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev)) #define ipp_is_m2m_cmd(c) (c == IPP_CMD_M2M) -/* platform device pointer for ipp device. */ -static struct platform_device *exynos_drm_ipp_pdev; - /* * A structure of event. * @@ -102,30 +99,6 @@ static LIST_HEAD(exynos_drm_ippdrv_list); static DEFINE_MUTEX(exynos_drm_ippdrv_lock); static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list); -int exynos_platform_device_ipp_register(void) -{ - struct platform_device *pdev; - - if (exynos_drm_ipp_pdev) - return -EEXIST; - - pdev = platform_device_register_simple("exynos-drm-ipp", -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - exynos_drm_ipp_pdev = pdev; - - return 0; -} - -void exynos_platform_device_ipp_unregister(void) -{ - if (exynos_drm_ipp_pdev) { - platform_device_unregister(exynos_drm_ipp_pdev); - exynos_drm_ipp_pdev = NULL; - } -} - int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) { mutex_lock(&exynos_drm_ippdrv_lock); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 16dc68cf7c88a..a12ae38502566 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -569,38 +569,3 @@ struct platform_driver vidi_driver = { .owner = THIS_MODULE, }, }; - -int exynos_drm_probe_vidi(void) -{ - struct platform_device *pdev; - int ret; - - pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - ret = platform_driver_register(&vidi_driver); - if (ret) { - platform_device_unregister(pdev); - return ret; - } - - return ret; -} - -static int exynos_drm_remove_vidi_device(struct device *dev, void *data) -{ - platform_device_unregister(to_platform_device(dev)); - - return 0; -} - -void exynos_drm_remove_vidi(void) -{ - int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL, - exynos_drm_remove_vidi_device); - /* silence compiler warning */ - (void)ret; - - platform_driver_unregister(&vidi_driver); -} From 8665040850e3cb1a5d288bcb2c5164538e80373e Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 11 Jun 2015 23:23:37 +0900 Subject: [PATCH 22/50] drm/exynos: fix broken component binding in case of multiple pipelines In case there are multiple pipelines and deferred probe occurs, only components of the first pipeline were bound. As a result only one pipeline was available. The main cause of this issue was dynamic generation of component match table - every component driver during probe registered itself on helper list, if there was at least one pipeline present on this list component match table were created without deferred components. This patch removes this helper list, instead it creates match table from existing devices requiring exynos_drm KMS drivers. This way match table do not depend on probe/deferral order and contains all KMS components. As a side effect patch makes the code cleaner and significantly smaller. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 14 +- drivers/gpu/drm/exynos/exynos_dp_core.c | 14 +- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 20 +- drivers/gpu/drm/exynos/exynos_drm_drv.c | 280 ++++++--------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 14 -- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 35 +-- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 28 +-- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 18 +- drivers/gpu/drm/exynos/exynos_hdmi.c | 22 +- drivers/gpu/drm/exynos/exynos_mixer.c | 14 +- 10 files changed, 100 insertions(+), 359 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index d9798e2aedda5..7d0955d9bf940 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -789,11 +789,6 @@ static int decon_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC, - EXYNOS_DISPLAY_TYPE_LCD); - if (ret) - return ret; - ctx->dev = dev; ctx->suspended = true; @@ -803,10 +798,8 @@ static int decon_probe(struct platform_device *pdev) of_node_put(i80_if_timings); ctx->regs = of_iomap(dev->of_node, 0); - if (!ctx->regs) { - ret = -ENOMEM; - goto err_del_component; - } + if (!ctx->regs) + return -ENOMEM; ctx->pclk = devm_clk_get(dev, "pclk_decon0"); if (IS_ERR(ctx->pclk)) { @@ -876,8 +869,6 @@ static int decon_probe(struct platform_device *pdev) err_iounmap: iounmap(ctx->regs); -err_del_component: - exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC); return ret; } @@ -890,7 +881,6 @@ static int decon_remove(struct platform_device *pdev) iounmap(ctx->regs); component_del(&pdev->dev, &decon_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 27768d874a5ef..172b8002a2c82 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1332,7 +1332,6 @@ static int exynos_dp_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *panel_node, *bridge_node, *endpoint; struct exynos_dp_device *dp; - int ret; dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), GFP_KERNEL); @@ -1343,11 +1342,6 @@ static int exynos_dp_probe(struct platform_device *pdev) dp->display.ops = &exynos_dp_display_ops; platform_set_drvdata(pdev, dp); - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - dp->display.type); - if (ret) - return ret; - panel_node = of_parse_phandle(dev->of_node, "panel", 0); if (panel_node) { dp->panel = of_drm_find_panel(panel_node); @@ -1368,18 +1362,12 @@ static int exynos_dp_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - ret = component_add(&pdev->dev, &exynos_dp_ops); - if (ret) - exynos_drm_component_del(&pdev->dev, - EXYNOS_DEVICE_TYPE_CONNECTOR); - - return ret; + return component_add(&pdev->dev, &exynos_dp_ops); } static int exynos_dp_remove(struct platform_device *pdev) { component_del(&pdev->dev, &exynos_dp_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 6dc328e22ec90..7cb6595c18941 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -313,33 +313,19 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) ctx->dev = dev; ctx->dpms_mode = DRM_MODE_DPMS_OFF; - ret = exynos_drm_component_add(dev, - EXYNOS_DEVICE_TYPE_CONNECTOR, - ctx->display.type); - if (ret) - return ERR_PTR(ret); - ret = exynos_dpi_parse_dt(ctx); if (ret < 0) { devm_kfree(dev, ctx); - goto err_del_component; + return NULL; } if (ctx->panel_node) { ctx->panel = of_drm_find_panel(ctx->panel_node); - if (!ctx->panel) { - exynos_drm_component_del(dev, - EXYNOS_DEVICE_TYPE_CONNECTOR); + if (!ctx->panel) return ERR_PTR(-EPROBE_DEFER); - } } return &ctx->display; - -err_del_component: - exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR); - - return NULL; } int exynos_dpi_remove(struct exynos_drm_display *display) @@ -351,7 +337,5 @@ int exynos_dpi_remove(struct exynos_drm_display *display) if (ctx->panel) drm_panel_detach(ctx->panel); - exynos_drm_component_del(ctx->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); - return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 835dec1c8fea8..af1ec13cefee5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -38,17 +38,6 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 -static DEFINE_MUTEX(drm_component_lock); -static LIST_HEAD(drm_component_list); - -struct component_dev { - struct list_head list; - struct device *crtc_dev; - struct device *conn_dev; - enum exynos_drm_output_type out_type; - unsigned int dev_type_flag; -}; - static int exynos_drm_load(struct drm_device *dev, unsigned long flags) { struct exynos_drm_private *private; @@ -348,108 +337,70 @@ static const struct dev_pm_ops exynos_drm_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume) }; -int exynos_drm_component_add(struct device *dev, - enum exynos_drm_device_type dev_type, - enum exynos_drm_output_type out_type) -{ - struct component_dev *cdev; - - if (dev_type != EXYNOS_DEVICE_TYPE_CRTC && - dev_type != EXYNOS_DEVICE_TYPE_CONNECTOR) { - DRM_ERROR("invalid device type.\n"); - return -EINVAL; - } - - mutex_lock(&drm_component_lock); +/* forward declaration */ +static struct platform_driver exynos_drm_platform_driver; - /* - * Make sure to check if there is a component which has two device - * objects, for connector and for encoder/connector. - * It should make sure that crtc and encoder/connector drivers are - * ready before exynos drm core binds them. - */ - list_for_each_entry(cdev, &drm_component_list, list) { - if (cdev->out_type == out_type) { - /* - * If crtc and encoder/connector device objects are - * added already just return. - */ - if (cdev->dev_type_flag == (EXYNOS_DEVICE_TYPE_CRTC | - EXYNOS_DEVICE_TYPE_CONNECTOR)) { - mutex_unlock(&drm_component_lock); - return 0; - } - - if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) { - cdev->crtc_dev = dev; - cdev->dev_type_flag |= dev_type; - } - - if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) { - cdev->conn_dev = dev; - cdev->dev_type_flag |= dev_type; - } - - mutex_unlock(&drm_component_lock); - return 0; - } - } - - mutex_unlock(&drm_component_lock); - - cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); - if (!cdev) - return -ENOMEM; - - if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) - cdev->crtc_dev = dev; - if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) - cdev->conn_dev = dev; - - cdev->out_type = out_type; - cdev->dev_type_flag = dev_type; - - mutex_lock(&drm_component_lock); - list_add_tail(&cdev->list, &drm_component_list); - mutex_unlock(&drm_component_lock); - - return 0; -} - -void exynos_drm_component_del(struct device *dev, - enum exynos_drm_device_type dev_type) -{ - struct component_dev *cdev, *next; - - mutex_lock(&drm_component_lock); - - list_for_each_entry_safe(cdev, next, &drm_component_list, list) { - if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) { - if (cdev->crtc_dev == dev) { - cdev->crtc_dev = NULL; - cdev->dev_type_flag &= ~dev_type; - } - } - - if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) { - if (cdev->conn_dev == dev) { - cdev->conn_dev = NULL; - cdev->dev_type_flag &= ~dev_type; - } - } +/* + * Connector drivers should not be placed before associated crtc drivers, + * because connector requires pipe number of its crtc during initialization. + */ +static struct platform_driver *const exynos_drm_kms_drivers[] = { +#ifdef CONFIG_DRM_EXYNOS_VIDI + &vidi_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_FIMD + &fimd_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS5433_DECON + &exynos5433_decon_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS7_DECON + &decon_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_DP + &dp_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_DSI + &dsi_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_HDMI + &mixer_driver, + &hdmi_driver, +#endif +}; - /* - * Release cdev object only in case that both of crtc and - * encoder/connector device objects are NULL. - */ - if (!cdev->crtc_dev && !cdev->conn_dev) { - list_del(&cdev->list); - kfree(cdev); - } - } +static struct platform_driver *const exynos_drm_non_kms_drivers[] = { +#ifdef CONFIG_DRM_EXYNOS_MIC + &mic_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_G2D + &g2d_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_FIMC + &fimc_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_ROTATOR + &rotator_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_GSC + &gsc_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_IPP + &ipp_driver, +#endif + &exynos_drm_platform_driver, +}; - mutex_unlock(&drm_component_lock); -} +static struct platform_driver *const exynos_drm_drv_with_simple_dev[] = { +#ifdef CONFIG_DRM_EXYNOS_VIDI + &vidi_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_IPP + &ipp_driver, +#endif + &exynos_drm_platform_driver, +}; +#define PDEV_COUNT ARRAY_SIZE(exynos_drm_drv_with_simple_dev) static int compare_dev(struct device *dev, void *data) { @@ -459,55 +410,22 @@ static int compare_dev(struct device *dev, void *data) static struct component_match *exynos_drm_match_add(struct device *dev) { struct component_match *match = NULL; - struct component_dev *cdev; - unsigned int attach_cnt = 0; - - mutex_lock(&drm_component_lock); - - /* Do not retry to probe if there is no any kms driver regitered. */ - if (list_empty(&drm_component_list)) { - mutex_unlock(&drm_component_lock); - return ERR_PTR(-ENODEV); - } - - list_for_each_entry(cdev, &drm_component_list, list) { - /* - * Add components to master only in case that crtc and - * encoder/connector device objects exist. - */ - if (!cdev->crtc_dev || !cdev->conn_dev) - continue; - - attach_cnt++; + int i; - mutex_unlock(&drm_component_lock); + for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { + struct device_driver *drv = &exynos_drm_kms_drivers[i]->driver; + struct device *p = NULL, *d; - /* - * fimd and dpi modules have same device object so add - * only crtc device object in this case. - */ - if (cdev->crtc_dev == cdev->conn_dev) { - component_match_add(dev, &match, compare_dev, - cdev->crtc_dev); - goto out_lock; + while ((d = bus_find_device(&platform_bus_type, p, drv, + (void *)platform_bus_type.match))) { + put_device(p); + component_match_add(dev, &match, compare_dev, d); + p = d; } - - /* - * Do not chage below call order. - * crtc device first should be added to master because - * connector/encoder need pipe number of crtc when they - * are created. - */ - component_match_add(dev, &match, compare_dev, cdev->crtc_dev); - component_match_add(dev, &match, compare_dev, cdev->conn_dev); - -out_lock: - mutex_lock(&drm_component_lock); + put_device(p); } - mutex_unlock(&drm_component_lock); - - return attach_cnt ? match : ERR_PTR(-EPROBE_DEFER); + return match ?: ERR_PTR(-ENODEV); } static int exynos_drm_bind(struct device *dev) @@ -555,60 +473,6 @@ static struct platform_driver exynos_drm_platform_driver = { }, }; -static struct platform_driver *const exynos_drm_kms_drivers[] = { -#ifdef CONFIG_DRM_EXYNOS_VIDI - &vidi_driver, -#endif -#ifdef CONFIG_DRM_EXYNOS_FIMD - &fimd_driver, -#endif -#ifdef CONFIG_DRM_EXYNOS7_DECON - &decon_driver, -#endif -#ifdef CONFIG_DRM_EXYNOS_DP - &dp_driver, -#endif -#ifdef CONFIG_DRM_EXYNOS_DSI - &dsi_driver, -#endif -#ifdef CONFIG_DRM_EXYNOS_HDMI - &mixer_driver, - &hdmi_driver, -#endif -}; - -static struct platform_driver *const exynos_drm_non_kms_drivers[] = { -#ifdef CONFIG_DRM_EXYNOS_G2D - &g2d_driver, -#endif -#ifdef CONFIG_DRM_EXYNOS_FIMC - &fimc_driver, -#endif -#ifdef CONFIG_DRM_EXYNOS_ROTATOR - &rotator_driver, -#endif -#ifdef CONFIG_DRM_EXYNOS_GSC - &gsc_driver, -#endif -#ifdef CONFIG_DRM_EXYNOS_IPP - &ipp_driver, -#endif - &exynos_drm_platform_driver, -}; - - -static struct platform_driver *const exynos_drm_drv_with_simple_dev[] = { -#ifdef CONFIG_DRM_EXYNOS_VIDI - &vidi_driver, -#endif -#ifdef CONFIG_DRM_EXYNOS_IPP - &ipp_driver, -#endif - &exynos_drm_platform_driver, -}; - -#define PDEV_COUNT ARRAY_SIZE(exynos_drm_drv_with_simple_dev) - static struct platform_device *exynos_drm_pdevs[PDEV_COUNT]; static void exynos_drm_unregister_devices(void) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index b308e908dd2b6..6b4958bd4fc3f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -25,13 +25,6 @@ #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc, base) #define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base) -/* This enumerates device type. */ -enum exynos_drm_device_type { - EXYNOS_DEVICE_TYPE_NONE, - EXYNOS_DEVICE_TYPE_CRTC, - EXYNOS_DEVICE_TYPE_CONNECTOR, -}; - /* this enumerates display type. */ enum exynos_drm_output_type { EXYNOS_DISPLAY_TYPE_NONE, @@ -311,13 +304,6 @@ static inline int exynos_dpi_remove(struct exynos_drm_display *display) int exynos_drm_create_enc_conn(struct drm_device *dev, struct exynos_drm_display *display); -int exynos_drm_component_add(struct device *dev, - enum exynos_drm_device_type dev_type, - enum exynos_drm_output_type out_type); - -void exynos_drm_component_del(struct device *dev, - enum exynos_drm_device_type dev_type); - extern struct platform_driver fimd_driver; extern struct platform_driver decon_driver; extern struct platform_driver dp_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 190f3b3c595ea..0fe32b8ee09b6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1686,11 +1686,6 @@ static int exynos_dsi_probe(struct platform_device *pdev) dsi->display.type = EXYNOS_DISPLAY_TYPE_LCD; dsi->display.ops = &exynos_dsi_display_ops; - ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - dsi->display.type); - if (ret) - return ret; - /* To be checked as invalid one */ dsi->te_gpio = -ENOENT; @@ -1706,7 +1701,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) ret = exynos_dsi_parse_dt(dsi); if (ret) - goto err_del_component; + return ret; dsi->supplies[0].supply = "vddcore"; dsi->supplies[1].supply = "vddio"; @@ -1720,37 +1715,32 @@ static int exynos_dsi_probe(struct platform_device *pdev) dsi->pll_clk = devm_clk_get(dev, "pll_clk"); if (IS_ERR(dsi->pll_clk)) { dev_info(dev, "failed to get dsi pll input clock\n"); - ret = PTR_ERR(dsi->pll_clk); - goto err_del_component; + return PTR_ERR(dsi->pll_clk); } dsi->bus_clk = devm_clk_get(dev, "bus_clk"); if (IS_ERR(dsi->bus_clk)) { dev_info(dev, "failed to get dsi bus clock\n"); - ret = PTR_ERR(dsi->bus_clk); - goto err_del_component; + return PTR_ERR(dsi->bus_clk); } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dsi->reg_base = devm_ioremap_resource(dev, res); if (IS_ERR(dsi->reg_base)) { dev_err(dev, "failed to remap io region\n"); - ret = PTR_ERR(dsi->reg_base); - goto err_del_component; + return PTR_ERR(dsi->reg_base); } dsi->phy = devm_phy_get(dev, "dsim"); if (IS_ERR(dsi->phy)) { dev_info(dev, "failed to get dsim phy\n"); - ret = PTR_ERR(dsi->phy); - goto err_del_component; + return PTR_ERR(dsi->phy); } dsi->irq = platform_get_irq(pdev, 0); if (dsi->irq < 0) { dev_err(dev, "failed to request dsi irq resource\n"); - ret = dsi->irq; - goto err_del_component; + return dsi->irq; } irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN); @@ -1759,26 +1749,17 @@ static int exynos_dsi_probe(struct platform_device *pdev) dev_name(dev), dsi); if (ret) { dev_err(dev, "failed to request dsi irq\n"); - goto err_del_component; + return ret; } platform_set_drvdata(pdev, &dsi->display); - ret = component_add(dev, &exynos_dsi_component_ops); - if (ret) - goto err_del_component; - - return ret; - -err_del_component: - exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR); - return ret; + return component_add(dev, &exynos_dsi_component_ops); } static int exynos_dsi_remove(struct platform_device *pdev) { component_del(&pdev->dev, &exynos_dsi_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 7c8ba614cd441..9cce2bca74c45 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1048,11 +1048,6 @@ static int fimd_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC, - EXYNOS_DISPLAY_TYPE_LCD); - if (ret) - return ret; - ctx->dev = dev; ctx->suspended = true; ctx->driver_data = drm_fimd_get_driver_data(pdev); @@ -1103,38 +1098,33 @@ static int fimd_probe(struct platform_device *pdev) ctx->bus_clk = devm_clk_get(dev, "fimd"); if (IS_ERR(ctx->bus_clk)) { dev_err(dev, "failed to get bus clock\n"); - ret = PTR_ERR(ctx->bus_clk); - goto err_del_component; + return PTR_ERR(ctx->bus_clk); } ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd"); if (IS_ERR(ctx->lcd_clk)) { dev_err(dev, "failed to get lcd clock\n"); - ret = PTR_ERR(ctx->lcd_clk); - goto err_del_component; + return PTR_ERR(ctx->lcd_clk); } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ctx->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(ctx->regs)) { - ret = PTR_ERR(ctx->regs); - goto err_del_component; - } + if (IS_ERR(ctx->regs)) + return PTR_ERR(ctx->regs); res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, ctx->i80_if ? "lcd_sys" : "vsync"); if (!res) { dev_err(dev, "irq request failed.\n"); - ret = -ENXIO; - goto err_del_component; + return -ENXIO; } ret = devm_request_irq(dev, res->start, fimd_irq_handler, 0, "drm_fimd", ctx); if (ret) { dev_err(dev, "irq request failed.\n"); - goto err_del_component; + return ret; } init_waitqueue_head(&ctx->wait_vsync_queue); @@ -1144,8 +1134,7 @@ static int fimd_probe(struct platform_device *pdev) ctx->display = exynos_dpi_probe(dev); if (IS_ERR(ctx->display)) { - ret = PTR_ERR(ctx->display); - goto err_del_component; + return PTR_ERR(ctx->display); } pm_runtime_enable(dev); @@ -1159,8 +1148,6 @@ static int fimd_probe(struct platform_device *pdev) err_disable_pm_runtime: pm_runtime_disable(dev); -err_del_component: - exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC); return ret; } @@ -1169,7 +1156,6 @@ static int fimd_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &fimd_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index a12ae38502566..a277191343ba8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -505,16 +505,6 @@ static int vidi_probe(struct platform_device *pdev) ctx->default_win = 0; ctx->pdev = pdev; - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, - EXYNOS_DISPLAY_TYPE_VIDI); - if (ret) - return ret; - - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - ctx->display.type); - if (ret) - goto err_del_crtc_component; - INIT_WORK(&ctx->work, vidi_fake_vblank_handler); mutex_init(&ctx->lock); @@ -524,7 +514,7 @@ static int vidi_probe(struct platform_device *pdev) ret = device_create_file(&pdev->dev, &dev_attr_connection); if (ret < 0) { DRM_ERROR("failed to create connection sysfs.\n"); - goto err_del_conn_component; + return ret; } ret = component_add(&pdev->dev, &vidi_component_ops); @@ -535,10 +525,6 @@ static int vidi_probe(struct platform_device *pdev) err_remove_file: device_remove_file(&pdev->dev, &dev_attr_connection); -err_del_conn_component: - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); -err_del_crtc_component: - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); return ret; } @@ -555,8 +541,6 @@ static int vidi_remove(struct platform_device *pdev) } component_del(&pdev->dev, &vidi_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 8c3c27b6475a4..99e286489031c 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2360,20 +2360,13 @@ static int hdmi_probe(struct platform_device *pdev) hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI; hdata->display.ops = &hdmi_display_ops; - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - hdata->display.type); - if (ret) - return ret; - mutex_init(&hdata->hdmi_mutex); platform_set_drvdata(pdev, hdata); match = of_match_node(hdmi_match_types, dev->of_node); - if (!match) { - ret = -ENODEV; - goto err_del_component; - } + if (!match) + return -ENODEV; drv_data = (struct hdmi_driver_data *)match->data; hdata->type = drv_data->type; @@ -2393,13 +2386,13 @@ static int hdmi_probe(struct platform_device *pdev) hdata->regs = devm_ioremap_resource(dev, res); if (IS_ERR(hdata->regs)) { ret = PTR_ERR(hdata->regs); - goto err_del_component; + return ret; } ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD"); if (ret) { DRM_ERROR("failed to request HPD gpio\n"); - goto err_del_component; + return ret; } ddc_node = hdmi_legacy_ddc_dt_binding(dev); @@ -2410,8 +2403,7 @@ static int hdmi_probe(struct platform_device *pdev) ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); if (!ddc_node) { DRM_ERROR("Failed to find ddc node in device tree\n"); - ret = -ENODEV; - goto err_del_component; + return -ENODEV; } out_get_ddc_adpt: @@ -2495,9 +2487,6 @@ static int hdmi_probe(struct platform_device *pdev) err_ddc: put_device(&hdata->ddc_adpt->dev); -err_del_component: - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); - return ret; } @@ -2517,7 +2506,6 @@ static int hdmi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &hdmi_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 1b77fc7660512..854b6d8e3db00 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1287,18 +1287,9 @@ static int mixer_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, - EXYNOS_DISPLAY_TYPE_HDMI); - if (ret) - return ret; - ret = component_add(&pdev->dev, &mixer_component_ops); - if (ret) { - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); - return ret; - } - - pm_runtime_enable(dev); + if (!ret) + pm_runtime_enable(dev); return ret; } @@ -1308,7 +1299,6 @@ static int mixer_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &mixer_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); return 0; } From e3b9e4602a9e832f46592daed0138543897e9b18 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 8 Jun 2015 12:15:42 +0200 Subject: [PATCH 23/50] drm/exynos: remove SoC checking code SoC checking code is not necessary anymore, as exynos_drm_match_add and exynos_drm_platform_probe already properly handles situation when there are no Exynos DRM components. Signed-off-by: Andrzej Hajda Tested-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 27 +------------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index af1ec13cefee5..591bdecd58dae 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -560,34 +560,9 @@ static inline void exynos_drm_unregister_non_kms_drivers(void) ARRAY_SIZE(exynos_drm_non_kms_drivers)); } -static const char * const strings[] = { - "samsung,exynos3", - "samsung,exynos4", - "samsung,exynos5", - "samsung,exynos7", -}; - static int exynos_drm_init(void) { - bool is_exynos = false; - int ret, i; - - /* - * Register device object only in case of Exynos SoC. - * - * Below codes resolves temporarily infinite loop issue incurred - * by Exynos drm driver when using multi-platform kernel. - * So these codes will be replaced with more generic way later. - */ - for (i = 0; i < ARRAY_SIZE(strings); i++) { - if (of_machine_is_compatible(strings[i])) { - is_exynos = true; - break; - } - } - - if (!is_exynos) - return -ENODEV; + int ret; ret = exynos_drm_register_devices(); if (ret) From 0e480f6ffb9497a96bac6d8aed8f958e75777b32 Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Thu, 11 Jun 2015 23:40:30 +0900 Subject: [PATCH 24/50] drm/exynos: dsi: check whether dsi is enabled before sending data exynos_dsi_host_transfer() can be called through a panel driver while DSI is turning down. It is possible because the function checks only whether DSI is initialized or not, and there is a moment which DSI is set by uninitialized, but DSI is still turning down. To prevent it, DSI must be set by disabled before starting to be turned down, and exynos_dsi_host_transfer() must check whether DSI is enabled or not. Kernel dump: [ 4721.351448] Unhandled fault: synchronous external abort (0x96000210) at 0xffffff800015e018 [ 4721.351809] Internal error: : 96000210 [#1] PREEMPT SMP [ 4721.352031] Modules linked in: [ 4721.352173] CPU: 2 PID: 300 Comm: deviced Tainted: G W 4.0.4-01017-g7964a87 #1 [ 4721.353989] Hardware name: Samsung DRACO board (DT) [ 4721.358852] task: ffffffc0a0b70000 ti: ffffffc0a00ec000 task.ti: ffffffc0a00ec000 [ 4721.366327] PC is at exynos_dsi_enable_lane+0x14/0x5c [ 4721.371353] LR is at exynos_dsi_host_transfer+0x834/0x8d8 [ 4721.376731] pc : [] lr : [] pstate: 60000145 [ 4721.384107] sp : ffffffc0a00efbe0 [ 4721.387405] x29: ffffffc0a00efbe0 x28: ffffffc0a00ec000 [ 4721.392699] x27: ffffffc000968000 x26: 0000000000000040 [ 4721.397994] x25: ffffffc000f74dc0 x24: ffffffc0a00efec8 [ 4721.403290] x23: ffffffc0a4815400 x22: ffffffc0009f2729 [ 4721.408584] x21: ffffffc0a00efcc8 x20: ffffffc0a4a2a848 [ 4721.413879] x19: ffffffc0a4a2a818 x18: 0000000000000004 [ 4721.419173] x17: 0000007faa5cddf0 x16: ffffffc0001a40a8 [ 4721.424469] x15: 0000000000000009 x14: 000000000000000d [ 4721.429762] x13: 6e6e6f63206b726f x12: 0000000000000010 [ 4721.435058] x11: 0101010101010101 x10: 0000000000000000 [ 4721.440353] x9 : 000000000000000a x8 : 8386838282818381 [ 4721.445648] x7 : ffffffc0a201efe8 x6 : 0000000000000000 [ 4721.450943] x5 : 00000000fffffffa x4 : ffffffc0a201f170 [ 4721.456237] x3 : ffffff800015e000 x2 : ffffff800015e018 [ 4721.461531] x1 : 000000000000000f x0 : ffffffc0a4a2a818 [ 4721.466826] [ 4721.468305] Process deviced (pid: 300, stack limit = 0xffffffc0a00ec028) [ 4721.474989] Stack: (0xffffffc0a00efbe0 to 0xffffffc0a00f0000) [ 4721.480720] fbe0: a00efca0 ffffffc0 0042c944 ffffffc0 a0f2d680 ffffffc0 00000024 00000000 [ 4721.488895] fc00: a4b6d000 ffffffc0 009f2729 ffffffc0 a4815400 ffffffc0 a00efec8 ffffffc0 Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 0fe32b8ee09b6..c1999ad4cdcbb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -260,6 +260,7 @@ struct exynos_dsi_transfer { #define DSIM_STATE_ENABLED BIT(0) #define DSIM_STATE_INITIALIZED BIT(1) #define DSIM_STATE_CMD_LPM BIT(2) +#define DSIM_STATE_VIDOUT_AVAILABLE BIT(3) struct exynos_dsi_driver_data { unsigned int plltmr_reg; @@ -1119,7 +1120,7 @@ static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id) struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id; struct drm_encoder *encoder = dsi->display.encoder; - if (dsi->state & DSIM_STATE_ENABLED) + if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE) exynos_drm_crtc_te_handler(encoder->crtc); return IRQ_HANDLED; @@ -1252,6 +1253,9 @@ static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host, struct exynos_dsi_transfer xfer; int ret; + if (!(dsi->state & DSIM_STATE_ENABLED)) + return -EINVAL; + if (!(dsi->state & DSIM_STATE_INITIALIZED)) { ret = exynos_dsi_init(dsi); if (ret) @@ -1370,8 +1374,11 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) if (ret < 0) return ret; + dsi->state |= DSIM_STATE_ENABLED; + ret = drm_panel_prepare(dsi->panel); if (ret < 0) { + dsi->state &= ~DSIM_STATE_ENABLED; exynos_dsi_poweroff(dsi); return ret; } @@ -1379,8 +1386,6 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) exynos_dsi_set_display_mode(dsi); exynos_dsi_set_display_enable(dsi, true); - dsi->state |= DSIM_STATE_ENABLED; - ret = drm_panel_enable(dsi->panel); if (ret < 0) { dsi->state &= ~DSIM_STATE_ENABLED; @@ -1390,6 +1395,8 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) return ret; } + dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; + return 0; } @@ -1398,12 +1405,15 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi) if (!(dsi->state & DSIM_STATE_ENABLED)) return; + dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; + drm_panel_disable(dsi->panel); exynos_dsi_set_display_enable(dsi, false); drm_panel_unprepare(dsi->panel); - exynos_dsi_poweroff(dsi); dsi->state &= ~DSIM_STATE_ENABLED; + + exynos_dsi_poweroff(dsi); } static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode) From b224fa9f25963736407982423e7aa7160222b1f0 Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Tue, 9 Jun 2015 12:45:14 +0900 Subject: [PATCH 25/50] drm/exynos: ipp: fix wrong index referencing a config element Config depends on the opreation. So it must be referenced by an operation id, not a property id. Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_ipp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index f594dd78963aa..ef98afb3055d3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -459,8 +459,7 @@ static int ipp_validate_mem_node(struct drm_device *drm_dev, unsigned int bpp; int i; - /* The property id should already be varified */ - ipp_cfg = &c_node->property.config[m_node->prop_id]; + ipp_cfg = &c_node->property.config[m_node->ops_id]; num_plane = drm_format_num_planes(ipp_cfg->fmt); /** From 3c10473bc87d81897e3a98f3eeca2264e61b4ad9 Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Tue, 9 Jun 2015 12:45:15 +0900 Subject: [PATCH 26/50] drm/exynos: ipp: validate a GEM handle with multiple planes FIMC & GSC driver can calculate the offset of planes. So there are use cases which IPP receives just one GEM handle of an image with multiple plane. This patch extends ipp_validate_mem_node() to validate this case. Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_ipp.c | 51 ++++++++++++++++++------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index ef98afb3055d3..67e5451e066fe 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -455,8 +455,8 @@ static int ipp_validate_mem_node(struct drm_device *drm_dev, { struct drm_exynos_ipp_config *ipp_cfg; unsigned int num_plane; - unsigned long min_size, size; - unsigned int bpp; + unsigned long size, buf_size = 0, plane_size, img_size = 0; + unsigned int bpp, width, height; int i; ipp_cfg = &c_node->property.config[m_node->ops_id]; @@ -470,20 +470,45 @@ static int ipp_validate_mem_node(struct drm_device *drm_dev, * but it seems more than enough */ for (i = 0; i < num_plane; ++i) { - if (!m_node->buf_info.handles[i]) { - DRM_ERROR("invalid handle for plane %d\n", i); - return -EINVAL; - } + width = ipp_cfg->sz.hsize; + height = ipp_cfg->sz.vsize; bpp = drm_format_plane_cpp(ipp_cfg->fmt, i); - min_size = (ipp_cfg->sz.hsize * ipp_cfg->sz.vsize * bpp) >> 3; - size = exynos_drm_gem_get_size(drm_dev, - m_node->buf_info.handles[i], - c_node->filp); - if (min_size > size) { - DRM_ERROR("invalid size for plane %d\n", i); - return -EINVAL; + + /* + * The result of drm_format_plane_cpp() for chroma planes must + * be used with drm_format_xxxx_chroma_subsampling() for + * correct result. + */ + if (i > 0) { + width /= drm_format_horz_chroma_subsampling( + ipp_cfg->fmt); + height /= drm_format_vert_chroma_subsampling( + ipp_cfg->fmt); } + plane_size = width * height * bpp; + img_size += plane_size; + + if (m_node->buf_info.handles[i]) { + size = exynos_drm_gem_get_size(drm_dev, + m_node->buf_info.handles[i], + c_node->filp); + if (plane_size > size) { + DRM_ERROR( + "buffer %d is smaller than required\n", + i); + return -EINVAL; + } + + buf_size += size; + } + } + + if (buf_size < img_size) { + DRM_ERROR("size of buffers(%lu) is smaller than image(%lu)\n", + buf_size, img_size); + return -EINVAL; } + return 0; } From ba4b77c4856a26b926d3892511568b9f4c6102e1 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 12 Jun 2015 17:27:14 +0900 Subject: [PATCH 27/50] drm/exynos: remove to call mixer_wait_for_vblank The reason waiting vblank is to be power gated and disabled clocks after dma operation is completed. The dma operation is stopped already before be power gated and clocks are disabled when mixer is disabled by commit 381be025ac1a6("drm/exynos: stop mixer before gating clocks during poweroff"). Don't need to wait vblank anymore. Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 854b6d8e3db00..24f0c22ff4950 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1010,7 +1010,6 @@ static void mixer_window_suspend(struct mixer_context *ctx) plane->resume = plane->enabled; mixer_win_disable(ctx->crtc, i); } - mixer_wait_for_vblank(ctx->crtc); } static void mixer_window_resume(struct mixer_context *ctx) From c329f667ba3392c3270902335690f548a2778374 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 12 Jun 2015 20:34:28 +0900 Subject: [PATCH 28/50] drm/exynos: remove chained calls to enable With atomic modesetting all the control for CRTC, Planes, Encoders and Connectors should come from DRM core, so the driver is not allowed to enable or disable planes from inside the crtc_enable()/disable() call. But it needs to disable planes with crtc_disable in exynos driver internally. Because crtc is disabled before plane is disabled, it means plane_disable just returns without any register changes, then we cannot be sure setting register to disable plane when crtc is disable. This patch removes this chainned calls to enable plane from exynos hw drivers code letting only DRM core touch planes except to disable plane. Also it leads eliminable enabled and resume of struct exynos_drm_plane. Signed-off-by: Gustavo Padovan Signed-off-by: Joonyoung Shim Tested-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 63 +++------------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 -- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 63 +++------------------- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 25 --------- drivers/gpu/drm/exynos/exynos_mixer.c | 38 ++----------- 5 files changed, 16 insertions(+), 178 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 7d0955d9bf940..2b9221cc811f9 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -410,11 +410,8 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - /* If suspended, enable this on resume */ - if (ctx->suspended) { - plane->resume = true; + if (ctx->suspended) return; - } /* * SHADOWCON/PRTCON register is used for enabling timing. @@ -506,8 +503,6 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) val = readl(ctx->regs + DECON_UPDATE); val |= DECON_UPDATE_STANDALONE_F; writel(val, ctx->regs + DECON_UPDATE); - - plane->enabled = true; } static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) @@ -521,11 +516,8 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - if (ctx->suspended) { - /* do not resume this window*/ - plane->resume = false; + if (ctx->suspended) return; - } /* protect windows */ decon_shadow_protect_win(ctx, win, true); @@ -541,49 +533,6 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) val = readl(ctx->regs + DECON_UPDATE); val |= DECON_UPDATE_STANDALONE_F; writel(val, ctx->regs + DECON_UPDATE); - - plane->enabled = false; -} - -static void decon_window_suspend(struct decon_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - plane->resume = plane->enabled; - if (plane->enabled) - decon_win_disable(ctx->crtc, i); - } -} - -static void decon_window_resume(struct decon_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - plane->enabled = plane->resume; - plane->resume = false; - } -} - -static void decon_apply(struct decon_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - if (plane->enabled) - decon_win_commit(ctx->crtc, i); - else - decon_win_disable(ctx->crtc, i); - } - - decon_commit(ctx->crtc); } static void decon_init(struct decon_context *ctx) @@ -645,14 +594,13 @@ static void decon_enable(struct exynos_drm_crtc *crtc) if (test_and_clear_bit(0, &ctx->irq_flags)) decon_enable_vblank(ctx->crtc); - decon_window_resume(ctx); - - decon_apply(ctx); + decon_commit(ctx->crtc); } static void decon_disable(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; + int i; if (ctx->suspended) return; @@ -662,7 +610,8 @@ static void decon_disable(struct exynos_drm_crtc *crtc) * suspend that connector. Otherwise we might try to scan from * a destroyed buffer later. */ - decon_window_suspend(ctx); + for (i = 0; i < WINDOWS_NR; i++) + decon_win_disable(crtc, i); clk_disable_unprepare(ctx->vclk); clk_disable_unprepare(ctx->eclk); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 6b4958bd4fc3f..a3845693c6345 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -64,8 +64,6 @@ enum exynos_drm_output_type { * @dma_addr: array of bus(accessed by dma) address to the memory region * allocated for a overlay. * @zpos: order of overlay layer(z position). - * @enabled: enabled or not. - * @resume: to resume or not. * * this structure is common to exynos SoC and its contents would be copied * to hardware specific overlay info. @@ -94,9 +92,6 @@ struct exynos_drm_plane { uint32_t pixel_format; dma_addr_t dma_addr[MAX_FB_BUFFER]; unsigned int zpos; - - bool enabled:1; - bool resume:1; }; /* diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 9cce2bca74c45..eafcf07987a64 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -634,11 +634,8 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - /* If suspended, enable this on resume */ - if (ctx->suspended) { - plane->resume = true; + if (ctx->suspended) return; - } /* * SHADOWCON/PRTCON register is used for enabling timing. @@ -728,8 +725,6 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) /* Enable DMA channel and unprotect windows */ fimd_shadow_protect_win(ctx, win, false); - plane->enabled = true; - if (ctx->i80_if) atomic_set(&ctx->win_updated, 1); } @@ -744,11 +739,8 @@ static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - if (ctx->suspended) { - /* do not resume this window*/ - plane->resume = false; + if (ctx->suspended) return; - } /* protect windows */ fimd_shadow_protect_win(ctx, win, true); @@ -760,49 +752,6 @@ static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) /* unprotect windows */ fimd_shadow_protect_win(ctx, win, false); - - plane->enabled = false; -} - -static void fimd_window_suspend(struct fimd_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - plane->resume = plane->enabled; - if (plane->enabled) - fimd_win_disable(ctx->crtc, i); - } -} - -static void fimd_window_resume(struct fimd_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - plane->enabled = plane->resume; - plane->resume = false; - } -} - -static void fimd_apply(struct fimd_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - if (plane->enabled) - fimd_win_commit(ctx->crtc, i); - else - fimd_win_disable(ctx->crtc, i); - } - - fimd_commit(ctx->crtc); } static void fimd_enable(struct exynos_drm_crtc *crtc) @@ -833,14 +782,13 @@ static void fimd_enable(struct exynos_drm_crtc *crtc) if (test_and_clear_bit(0, &ctx->irq_flags)) fimd_enable_vblank(ctx->crtc); - fimd_window_resume(ctx); - - fimd_apply(ctx); + fimd_commit(ctx->crtc); } static void fimd_disable(struct exynos_drm_crtc *crtc) { struct fimd_context *ctx = crtc->ctx; + int i; if (ctx->suspended) return; @@ -850,7 +798,8 @@ static void fimd_disable(struct exynos_drm_crtc *crtc) * suspend that connector. Otherwise we might try to scan from * a destroyed buffer later. */ - fimd_window_suspend(ctx); + for (i = 0; i < WINDOWS_NR; i++) + fimd_win_disable(crtc, i); clk_disable_unprepare(ctx->lcd_clk); clk_disable_unprepare(ctx->bus_clk); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index a277191343ba8..3413393d8a165 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -131,33 +131,15 @@ static void vidi_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - plane->enabled = true; - DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr); if (ctx->vblank_on) schedule_work(&ctx->work); } -static void vidi_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) -{ - struct vidi_context *ctx = crtc->ctx; - struct exynos_drm_plane *plane; - - if (win < 0 || win >= WINDOWS_NR) - return; - - plane = &ctx->planes[win]; - plane->enabled = false; - - /* TODO. */ -} - static void vidi_enable(struct exynos_drm_crtc *crtc) { struct vidi_context *ctx = crtc->ctx; - struct exynos_drm_plane *plane; - int i; mutex_lock(&ctx->lock); @@ -167,12 +149,6 @@ static void vidi_enable(struct exynos_drm_crtc *crtc) if (test_and_clear_bit(0, &ctx->irq_flags)) vidi_enable_vblank(ctx->crtc); - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - if (plane->enabled) - vidi_win_commit(ctx->crtc, i); - } - mutex_unlock(&ctx->lock); } @@ -204,7 +180,6 @@ static const struct exynos_drm_crtc_ops vidi_crtc_ops = { .enable_vblank = vidi_enable_vblank, .disable_vblank = vidi_disable_vblank, .win_commit = vidi_win_commit, - .win_disable = vidi_win_disable, }; static void vidi_fake_vblank_handler(struct work_struct *work) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 24f0c22ff4950..f57068781a371 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -937,8 +937,6 @@ static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) vp_video_buffer(mixer_ctx, win); else mixer_graph_buffer(mixer_ctx, win); - - mixer_ctx->planes[win].enabled = true; } static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) @@ -952,7 +950,6 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) mutex_lock(&mixer_ctx->mixer_mutex); if (!mixer_ctx->powered) { mutex_unlock(&mixer_ctx->mixer_mutex); - mixer_ctx->planes[win].resume = false; return; } mutex_unlock(&mixer_ctx->mixer_mutex); @@ -964,8 +961,6 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) mixer_vsync_set_update(mixer_ctx, true); spin_unlock_irqrestore(&res->reg_slock, flags); - - mixer_ctx->planes[win].enabled = false; } static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc) @@ -1000,32 +995,6 @@ static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc) drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe); } -static void mixer_window_suspend(struct mixer_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < MIXER_WIN_NR; i++) { - plane = &ctx->planes[i]; - plane->resume = plane->enabled; - mixer_win_disable(ctx->crtc, i); - } -} - -static void mixer_window_resume(struct mixer_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < MIXER_WIN_NR; i++) { - plane = &ctx->planes[i]; - plane->enabled = plane->resume; - plane->resume = false; - if (plane->enabled) - mixer_win_commit(ctx->crtc, i); - } -} - static void mixer_enable(struct exynos_drm_crtc *crtc) { struct mixer_context *ctx = crtc->ctx; @@ -1078,14 +1047,13 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) mixer_reg_write(res, MXR_INT_EN, ctx->int_en); mixer_win_reset(ctx); - - mixer_window_resume(ctx); } static void mixer_disable(struct exynos_drm_crtc *crtc) { struct mixer_context *ctx = crtc->ctx; struct mixer_resources *res = &ctx->mixer_res; + int i; mutex_lock(&ctx->mixer_mutex); if (!ctx->powered) { @@ -1096,7 +1064,9 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) mixer_stop(ctx); mixer_regs_dump(ctx); - mixer_window_suspend(ctx); + + for (i = 0; i < MIXER_WIN_NR; i++) + mixer_win_disable(crtc, i); ctx->int_en = mixer_reg_read(res, MXR_INT_EN); From b74f14fd5c98b4cbd0763ea1841478eef5bdb7d8 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 12 Jun 2015 17:27:16 +0900 Subject: [PATCH 29/50] drm/exynos: initialize VIDCON0 when fimd is disabled When the fimd is disabled by fimd_disable(), enabled overlay layers also are disabled. If clocks for fimd are enabled by fimd_enable() on this case, it can lead IOMMU page fault. The reason is that VIDCON0_ENVID and VIDCON0_ENVID_F bits of VIDCON0 register are set still even though fimd is disabled, so it may continue display output of prior when clocks for fimd are enabled again. Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index eafcf07987a64..324055f032eca 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -801,6 +801,8 @@ static void fimd_disable(struct exynos_drm_crtc *crtc) for (i = 0; i < WINDOWS_NR; i++) fimd_win_disable(crtc, i); + writel(0, ctx->regs + VIDCON0); + clk_disable_unprepare(ctx->lcd_clk); clk_disable_unprepare(ctx->bus_clk); From fb88e2141222ad93c594f2babc806d71cfb65e0d Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 12 Jun 2015 11:07:17 +0200 Subject: [PATCH 30/50] drm/exynos: fimd: ensure proper hw state in fimd_clear_channel() One should not do any assumptions on the stare of the fimd hardware during driver initialization, so to properly reset fimd before enabling IOMMU, one should ensure that all power domains and clocks are really enabled. This patch adds pm_runtime and clocks management in the fimd_clear_channel() function to ensure that any access to fimd registers will be performed with clocks and power domains enabled. Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 135 +++++++++++++---------- 1 file changed, 77 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 324055f032eca..b5bd16ceaa968 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -196,6 +196,62 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data( return (struct fimd_driver_data *)of_id->data; } +static int fimd_enable_vblank(struct exynos_drm_crtc *crtc) +{ + struct fimd_context *ctx = crtc->ctx; + u32 val; + + if (ctx->suspended) + return -EPERM; + + if (!test_and_set_bit(0, &ctx->irq_flags)) { + val = readl(ctx->regs + VIDINTCON0); + + val |= VIDINTCON0_INT_ENABLE; + + if (ctx->i80_if) { + val |= VIDINTCON0_INT_I80IFDONE; + val |= VIDINTCON0_INT_SYSMAINCON; + val &= ~VIDINTCON0_INT_SYSSUBCON; + } else { + val |= VIDINTCON0_INT_FRAME; + + val &= ~VIDINTCON0_FRAMESEL0_MASK; + val |= VIDINTCON0_FRAMESEL0_VSYNC; + val &= ~VIDINTCON0_FRAMESEL1_MASK; + val |= VIDINTCON0_FRAMESEL1_NONE; + } + + writel(val, ctx->regs + VIDINTCON0); + } + + return 0; +} + +static void fimd_disable_vblank(struct exynos_drm_crtc *crtc) +{ + struct fimd_context *ctx = crtc->ctx; + u32 val; + + if (ctx->suspended) + return; + + if (test_and_clear_bit(0, &ctx->irq_flags)) { + val = readl(ctx->regs + VIDINTCON0); + + val &= ~VIDINTCON0_INT_ENABLE; + + if (ctx->i80_if) { + val &= ~VIDINTCON0_INT_I80IFDONE; + val &= ~VIDINTCON0_INT_SYSMAINCON; + val &= ~VIDINTCON0_INT_SYSSUBCON; + } else + val &= ~VIDINTCON0_INT_FRAME; + + writel(val, ctx->regs + VIDINTCON0); + } +} + static void fimd_wait_for_vblank(struct exynos_drm_crtc *crtc) { struct fimd_context *ctx = crtc->ctx; @@ -248,6 +304,12 @@ static void fimd_clear_channel(struct fimd_context *ctx) DRM_DEBUG_KMS("%s\n", __FILE__); + /* Hardware is in unknown state, so ensure it gets enabled properly */ + pm_runtime_get_sync(ctx->dev); + + clk_prepare_enable(ctx->bus_clk); + clk_prepare_enable(ctx->lcd_clk); + /* Check if any channel is enabled. */ for (win = 0; win < WINDOWS_NR; win++) { u32 val = readl(ctx->regs + WINCON(win)); @@ -265,12 +327,24 @@ static void fimd_clear_channel(struct fimd_context *ctx) /* Wait for vsync, as disable channel takes effect at next vsync */ if (ch_enabled) { - unsigned int state = ctx->suspended; + int pipe = ctx->pipe; + + /* ensure that vblank interrupt won't be reported to core */ + ctx->suspended = false; + ctx->pipe = -1; - ctx->suspended = 0; + fimd_enable_vblank(ctx->crtc); fimd_wait_for_vblank(ctx->crtc); - ctx->suspended = state; + fimd_disable_vblank(ctx->crtc); + + ctx->suspended = true; + ctx->pipe = pipe; } + + clk_disable_unprepare(ctx->lcd_clk); + clk_disable_unprepare(ctx->bus_clk); + + pm_runtime_put(ctx->dev); } static int fimd_iommu_attach_devices(struct fimd_context *ctx, @@ -434,61 +508,6 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) writel(val, ctx->regs + VIDCON0); } -static int fimd_enable_vblank(struct exynos_drm_crtc *crtc) -{ - struct fimd_context *ctx = crtc->ctx; - u32 val; - - if (ctx->suspended) - return -EPERM; - - if (!test_and_set_bit(0, &ctx->irq_flags)) { - val = readl(ctx->regs + VIDINTCON0); - - val |= VIDINTCON0_INT_ENABLE; - - if (ctx->i80_if) { - val |= VIDINTCON0_INT_I80IFDONE; - val |= VIDINTCON0_INT_SYSMAINCON; - val &= ~VIDINTCON0_INT_SYSSUBCON; - } else { - val |= VIDINTCON0_INT_FRAME; - - val &= ~VIDINTCON0_FRAMESEL0_MASK; - val |= VIDINTCON0_FRAMESEL0_VSYNC; - val &= ~VIDINTCON0_FRAMESEL1_MASK; - val |= VIDINTCON0_FRAMESEL1_NONE; - } - - writel(val, ctx->regs + VIDINTCON0); - } - - return 0; -} - -static void fimd_disable_vblank(struct exynos_drm_crtc *crtc) -{ - struct fimd_context *ctx = crtc->ctx; - u32 val; - - if (ctx->suspended) - return; - - if (test_and_clear_bit(0, &ctx->irq_flags)) { - val = readl(ctx->regs + VIDINTCON0); - - val &= ~VIDINTCON0_INT_ENABLE; - - if (ctx->i80_if) { - val &= ~VIDINTCON0_INT_I80IFDONE; - val &= ~VIDINTCON0_INT_SYSMAINCON; - val &= ~VIDINTCON0_INT_SYSSUBCON; - } else - val &= ~VIDINTCON0_INT_FRAME; - - writel(val, ctx->regs + VIDINTCON0); - } -} static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) { From 452868581da254b03c54912f8f780bd0a4d3bcfb Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 3 Jun 2015 10:26:23 +0200 Subject: [PATCH 31/50] drm/exynos: iommu: detach from default dma-mapping domain on init This patch adds code, which detach sub-device nodes from default iommu domain if such has been configured. This lets Exynos DRM driver to properly attach sub-devices to its own, common for all sub-devices domain. Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_iommu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c index b32b291f88ff0..323601a52a250 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c @@ -100,6 +100,9 @@ int drm_iommu_attach_device(struct drm_device *drm_dev, dma_set_max_seg_size(subdrv_dev, 0xffffffffu); + if (subdrv_dev->archdata.mapping) + arm_iommu_detach_device(subdrv_dev); + ret = arm_iommu_attach_device(subdrv_dev, dev->archdata.mapping); if (ret < 0) { DRM_DEBUG_KMS("failed iommu attach.\n"); From bcfe4e25aa0385dc7bb1061595f8e4d69f74c61d Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 3 Jun 2015 10:26:24 +0200 Subject: [PATCH 32/50] drm/exynos: iommu: improve a check for non-iommu dma_ops DRM Exynos driver is relying on dma-mapping internal structures when used with IOMMU enabled. This patch partially hides dma-mapping internal things by using proper get_dma_ops/set_dma_ops calls. Signed-off-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c index 323601a52a250..34596da7be33b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c @@ -117,8 +117,8 @@ int drm_iommu_attach_device(struct drm_device *drm_dev, * If iommu attach succeeded, the sub driver would have dma_ops * for iommu and also all sub drivers have same dma_ops. */ - if (!dev->archdata.dma_ops) - dev->archdata.dma_ops = subdrv_dev->archdata.dma_ops; + if (get_dma_ops(dev) == get_dma_ops(NULL)) + set_dma_ops(dev, get_dma_ops(subdrv_dev)); return 0; } From 94ab95a94c1f8a5e7ff3930010a2afaba1448e9d Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 12 Jun 2015 22:19:22 +0900 Subject: [PATCH 33/50] drm/exynos: fimd: fix page fault issue with iommu This patch resolves page fault issue with iommu and atomic feature when modetest test application is terminated. ENWIN_F field of WINCONx register enables or disable a dma channel to each hardware overlay - the value of the field will be updated to real register after vsync. So this patch makes sure the dma channel is disabled by waiting for vsync one time after clearing shadow registers to all dma channels. Below shows the page fault issue: setting mode 720x1280-60Hz@XR24 on connectors 31, crtc 29 freq: 59.99Hz [ 34.831025] PAGE FAULT occurred at 0x20400000 by 11e20000.sysmmu(Page table base: 0x6e324000) [ 34.838072] Lv1 entry: 0x6e92dc01 [ 34.841489] ------------[ cut here ]------------ [ 34.846058] kernel BUG at drivers/iommu/exynos-iommu.c:364! [ 34.851614] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM [ 34.857428] Modules linked in: <--snip--> [ 35.210894] [] (exynos_sysmmu_irq) from [] (handle_irq_event_percpu+0x78/0x134) [ 35.219914] [] (handle_irq_event_percpu) from [] (handle_irq_event+0x3c/0x5c) [ 35.228768] [] (handle_irq_event) from [] (handle_level_irq+0xc4/0x13c) [ 35.237101] [] (handle_level_irq) from [] (generic_handle_irq+0x2c/0x3c) [ 35.245521] [] (generic_handle_irq) from [] (combiner_handle_cascade_irq+0x94/0x100) [ 35.254980] [] (combiner_handle_cascade_irq) from [] (generic_handle_irq+0x2c/0x3c) [ 35.264353] [] (generic_handle_irq) from [] (__handle_domain_irq+0x7c/0xec) [ 35.273034] [] (__handle_domain_irq) from [] (gic_handle_irq+0x30/0x68) [ 35.281366] [] (gic_handle_irq) from [] (__irq_svc+0x40/0x74) Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index b5bd16ceaa968..1e3bb72184d28 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -820,6 +820,10 @@ static void fimd_disable(struct exynos_drm_crtc *crtc) for (i = 0; i < WINDOWS_NR; i++) fimd_win_disable(crtc, i); + fimd_enable_vblank(crtc); + fimd_wait_for_vblank(crtc); + fimd_disable_vblank(crtc); + writel(0, ctx->regs + VIDCON0); clk_disable_unprepare(ctx->lcd_clk); From 286bd022303e230d608aa4bd36cb1f438b85c78e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 19 Jun 2015 14:23:29 +0900 Subject: [PATCH 34/50] drm/exynos: Remove unused vma field of exynos_drm_gem_obj The field 'vma' of 'exynos_drm_gem_obj' structure was introduced in 2a3098ff6c21 ("drm/exynos: add userptr feature for g2d module") but is not referenced anywhere. One instance of 'exynos_drm_gem_obj' may be mapped to multiple user-space VMAs so 'vma' field does not look useful anyway. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_gem.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 308173cb4f0a0..6f42e22482889 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -61,7 +61,6 @@ struct exynos_drm_gem_buf { * or at framebuffer creation. * @size: size requested from user, in bytes and this size is aligned * in page unit. - * @vma: a pointer to vm_area. * @flags: indicate memory type to allocated buffer and cache attruibute. * * P.S. this object would be transferred to user as kms_bo.handle so @@ -71,7 +70,6 @@ struct exynos_drm_gem_obj { struct drm_gem_object base; struct exynos_drm_gem_buf *buffer; unsigned long size; - struct vm_area_struct *vma; unsigned int flags; }; From ad533ade869d33f496d96e6aa639a51e9c06e241 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 19 Jun 2015 20:53:03 +0900 Subject: [PATCH 35/50] drm/exynos: do not wait for vblank at atomic operation This patch resolves the issue that refresh rate got low at extension mode test with fimd and vidi combination. The problem was because atomic_commit callback waited for the completion of vblank to gaurantee crtc relevant registers are updated from shadow registers to real ones. However, the waiting there is really unnecessary because page flip operation does already it. Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 789db6f29f316..2b6320e6eae2f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -295,8 +295,6 @@ static int exynos_atomic_commit(struct drm_device *dev, drm_atomic_helper_commit_planes(dev, state); - drm_atomic_helper_wait_for_vblanks(dev, state); - drm_atomic_helper_cleanup_planes(dev, state); drm_atomic_state_free(state); From f4137df22a0d78d05e377e1d1519160ddfa3624d Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Fri, 12 Jun 2015 21:58:56 +0900 Subject: [PATCH 36/50] drm/exynos: remove the dependency of DP driver for ARCH_EXYNOS This dependency is a historical thing. It is added when this DP driver is under media subsystem. Now because it is under Exynos DRM, this dependency is not needed anymore. Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 8203283dc3c25..926ed3603ff90 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -50,7 +50,7 @@ config DRM_EXYNOS_DSI config DRM_EXYNOS_DP bool "EXYNOS DRM DP driver support" - depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) + depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) default DRM_EXYNOS select DRM_PANEL help From 3f46d807f861fb7304c9890fb091efb80161f2c7 Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Fri, 12 Jun 2015 21:58:57 +0900 Subject: [PATCH 37/50] drm/exynos: Add the dependency for DRM_EXYNOS to DPI/DSI/DP Without this dependency, Kbuild is confused and the configs below them are not placed under Exynos DRM. This patch fixes it, so the configs below them become to be placed under Exynos DRM. Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 926ed3603ff90..f1b1239d2f450 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -33,7 +33,7 @@ config DRM_EXYNOS7_DECON config DRM_EXYNOS_DPI bool "EXYNOS DRM parallel output support" - depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) + depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) select DRM_PANEL default n help @@ -41,7 +41,7 @@ config DRM_EXYNOS_DPI config DRM_EXYNOS_DSI bool "EXYNOS DRM MIPI-DSI driver support" - depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) + depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) select DRM_MIPI_DSI select DRM_PANEL default n @@ -50,7 +50,7 @@ config DRM_EXYNOS_DSI config DRM_EXYNOS_DP bool "EXYNOS DRM DP driver support" - depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) + depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) default DRM_EXYNOS select DRM_PANEL help From fc2e013f78c42fdafcb48f4922c2ae6d2c8e7d09 Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Mon, 22 Jun 2015 19:05:04 +0900 Subject: [PATCH 38/50] drm/exynos: add drm_iommu_attach_device_if_possible() Every CRTC drivers in Exynos DRM implements the code which checks whether IOMMU is supported or not, and if supported enable it. Making new helper for it generalize each CRTC drivers. Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 25 +++++----------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 + drivers/gpu/drm/exynos/exynos_drm_fimd.c | 34 +++++----------------- drivers/gpu/drm/exynos/exynos_drm_iommu.c | 14 +++++++++ drivers/gpu/drm/exynos/exynos_drm_iommu.h | 11 +++++++ drivers/gpu/drm/exynos/exynos_mixer.c | 8 +++-- 6 files changed, 47 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 2b9221cc811f9..362532afd1a52 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -89,8 +89,9 @@ static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc) DRM_DEBUG_KMS("vblank wait timed out.\n"); } -static void decon_clear_channel(struct decon_context *ctx) +static void decon_clear_channels(struct exynos_drm_crtc *crtc) { + struct decon_context *ctx = crtc->ctx; unsigned int win, ch_enabled = 0; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -120,27 +121,16 @@ static int decon_ctx_initialize(struct decon_context *ctx, struct drm_device *drm_dev) { struct exynos_drm_private *priv = drm_dev->dev_private; + int ret; ctx->drm_dev = drm_dev; ctx->pipe = priv->pipe++; - /* attach this sub driver to iommu mapping if supported. */ - if (is_drm_iommu_supported(ctx->drm_dev)) { - int ret; - - /* - * If any channel is already active, iommu will throw - * a PAGE FAULT when enabled. So clear any channel if enabled. - */ - decon_clear_channel(ctx); - ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev); - if (ret) { - DRM_ERROR("drm_iommu_attach failed.\n"); - return ret; - } - } + ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, ctx->dev); + if (ret) + priv->pipe--; - return 0; + return ret; } static void decon_ctx_remove(struct decon_context *ctx) @@ -633,6 +623,7 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { .wait_for_vblank = decon_wait_for_vblank, .win_commit = decon_win_commit, .win_disable = decon_win_disable, + .clear_channels = decon_clear_channels, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index a3845693c6345..61a9a9ed37f0a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -177,6 +177,7 @@ struct exynos_drm_crtc_ops { void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos); void (*te_handler)(struct exynos_drm_crtc *crtc); void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); + void (*clear_channels)(struct exynos_drm_crtc *crtc); }; /* diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 1e3bb72184d28..794e56c8798e7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -298,8 +298,9 @@ static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, writel(val, ctx->regs + SHADOWCON); } -static void fimd_clear_channel(struct fimd_context *ctx) +static void fimd_clear_channels(struct exynos_drm_crtc *crtc) { + struct fimd_context *ctx = crtc->ctx; unsigned int win, ch_enabled = 0; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -347,30 +348,6 @@ static void fimd_clear_channel(struct fimd_context *ctx) pm_runtime_put(ctx->dev); } -static int fimd_iommu_attach_devices(struct fimd_context *ctx, - struct drm_device *drm_dev) -{ - - /* attach this sub driver to iommu mapping if supported. */ - if (is_drm_iommu_supported(ctx->drm_dev)) { - int ret; - - /* - * If any channel is already active, iommu will throw - * a PAGE FAULT when enabled. So clear any channel if enabled. - */ - fimd_clear_channel(ctx); - ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev); - if (ret) { - DRM_ERROR("drm_iommu_attach failed.\n"); - return ret; - } - - } - - return 0; -} - static void fimd_iommu_detach_devices(struct fimd_context *ctx) { /* detach this sub driver from iommu mapping if supported. */ @@ -917,6 +894,7 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { .win_disable = fimd_win_disable, .te_handler = fimd_te_handler, .clock_enable = fimd_dp_clock_enable, + .clear_channels = fimd_clear_channels, }; static irqreturn_t fimd_irq_handler(int irq, void *dev_id) @@ -986,7 +964,11 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) if (ctx->display) exynos_drm_create_enc_conn(drm_dev, ctx->display); - return fimd_iommu_attach_devices(ctx, drm_dev); + ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev); + if (ret) + priv->pipe--; + + return ret; } static void fimd_unbind(struct device *dev, struct device *master, diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c index 34596da7be33b..d4ec7465e9ccd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c @@ -144,3 +144,17 @@ void drm_iommu_detach_device(struct drm_device *drm_dev, iommu_detach_device(mapping->domain, subdrv_dev); drm_release_iommu_mapping(drm_dev); } + +int drm_iommu_attach_device_if_possible(struct exynos_drm_crtc *exynos_crtc, + struct drm_device *drm_dev, struct device *subdrv_dev) +{ + int ret = 0; + + if (is_drm_iommu_supported(drm_dev)) { + if (exynos_crtc->ops->clear_channels) + exynos_crtc->ops->clear_channels(exynos_crtc); + return drm_iommu_attach_device(drm_dev, subdrv_dev); + } + + return ret; +} diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h index 35d25889b476e..8341c7a475b4e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h @@ -38,6 +38,10 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) #endif } +int drm_iommu_attach_device_if_possible( + struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev, + struct device *subdrv_dev); + #else static inline int drm_create_iommu_mapping(struct drm_device *drm_dev) @@ -65,5 +69,12 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) return false; } +static inline int drm_iommu_attach_device_if_possible( + struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev, + struct device *subdrv_dev) +{ + return 0; +} + #endif #endif diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index f57068781a371..cae98db330620 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -882,10 +882,12 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, } } - if (!is_drm_iommu_supported(mixer_ctx->drm_dev)) - return 0; + ret = drm_iommu_attach_device_if_possible(mixer_ctx->crtc, drm_dev, + mixer_ctx->dev); + if (ret) + priv->pipe--; - return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev); + return ret; } static void mixer_ctx_remove(struct mixer_context *mixer_ctx) From 9a09a69a87f640c5fe1a39b5cde3280273d535ba Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Fri, 12 Jun 2015 21:58:59 +0900 Subject: [PATCH 39/50] drm/exynos: fix the input prompt of Exynos7 DECON This patch is a preparation patch for adding support for Exynos5433 DECON. Exynos7 DECON have to be distinguished from Exynos5433 DECON. Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index f1b1239d2f450..ddb7c8a26bfc5 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -25,7 +25,7 @@ config DRM_EXYNOS_FIMD Choose this option if you want to use Exynos FIMD for DRM. config DRM_EXYNOS7_DECON - bool "Exynos DRM DECON" + bool "Exynos7 DRM DECON" depends on DRM_EXYNOS && !FB_S3C select FB_MODE_HELPERS help From c8466a9166b00ecb0c6f768baf70636fe15f63ef Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 12 Jun 2015 21:59:00 +0900 Subject: [PATCH 40/50] drm/exynos: add Exynos5433 decon driver DECON(Display and Enhancement Controller) is new IP replacing FIMD in Exynos5433. This patch adds Exynos5433 decon driver. Signed-off-by: Joonyoung Shim Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae --- .../bindings/video/exynos5433-decon.txt | 65 ++ drivers/gpu/drm/exynos/Kconfig | 6 + drivers/gpu/drm/exynos/Makefile | 1 + drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 660 ++++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 + include/video/exynos5433_decon.h | 165 +++++ 6 files changed, 898 insertions(+) create mode 100644 Documentation/devicetree/bindings/video/exynos5433-decon.txt create mode 100644 drivers/gpu/drm/exynos/exynos5433_drm_decon.c create mode 100644 include/video/exynos5433_decon.h diff --git a/Documentation/devicetree/bindings/video/exynos5433-decon.txt b/Documentation/devicetree/bindings/video/exynos5433-decon.txt new file mode 100644 index 0000000000000..377afbf5122a7 --- /dev/null +++ b/Documentation/devicetree/bindings/video/exynos5433-decon.txt @@ -0,0 +1,65 @@ +Device-Tree bindings for Samsung Exynos SoC display controller (DECON) + +DECON (Display and Enhancement Controller) is the Display Controller for the +Exynos series of SoCs which transfers the image data from a video memory +buffer to an external LCD interface. + +Required properties: +- compatible: value should be "samsung,exynos5433-decon"; +- reg: physical base address and length of the DECON registers set. +- interrupts: should contain a list of all DECON IP block interrupts in the + order: VSYNC, LCD_SYSTEM. The interrupt specifier format + depends on the interrupt controller used. +- interrupt-names: should contain the interrupt names: "vsync", "lcd_sys" + in the same order as they were listed in the interrupts + property. +- clocks: must include clock specifiers corresponding to entries in the + clock-names property. +- clock-names: list of clock names sorted in the same order as the clocks + property. Must contain "aclk_decon", "aclk_smmu_decon0x", + "aclk_xiu_decon0x", "pclk_smmu_decon0x", clk_decon_vclk", + "sclk_decon_eclk" +- ports: contains a port which is connected to mic node. address-cells and + size-cells must 1 and 0, respectively. +- port: contains an endpoint node which is connected to the endpoint in the mic + node. The reg value muset be 0. +- i80-if-timings: specify whether the panel which is connected to decon uses + i80 lcd interface or mipi video interface. This node contains + no timing information as that of fimd does. Because there is + no register in decon to specify i80 interface timing value, + it is not needed, but make it remain to use same kind of node + in fimd and exynos7 decon. + +Example: +SoC specific DT entry: +decon: decon@13800000 { + compatible = "samsung,exynos5433-decon"; + reg = <0x13800000 0x2104>; + clocks = <&cmu_disp CLK_ACLK_DECON>, <&cmu_disp CLK_ACLK_SMMU_DECON0X>, + <&cmu_disp CLK_ACLK_XIU_DECON0X>, + <&cmu_disp CLK_PCLK_SMMU_DECON0X>, + <&cmu_disp CLK_SCLK_DECON_VCLK>, + <&cmu_disp CLK_SCLK_DECON_ECLK>; + clock-names = "aclk_decon", "aclk_smmu_decon0x", "aclk_xiu_decon0x", + "pclk_smmu_decon0x", "sclk_decon_vclk", "sclk_decon_eclk"; + interrupt-names = "vsync", "lcd_sys"; + interrupts = <0 202 0>, <0 203 0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + decon_to_mic: endpoint { + remote-endpoint = <&mic_to_decon>; + }; + }; + }; +}; + +Board specific DT entry: +&decon { + i80-if-timings { + }; +}; diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index ddb7c8a26bfc5..51a4eb5644972 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -24,6 +24,12 @@ config DRM_EXYNOS_FIMD help Choose this option if you want to use Exynos FIMD for DRM. +config DRM_EXYNOS5433_DECON + bool "Exynos5433 DRM DECON" + depends on DRM_EXYNOS + help + Choose this option if you want to use Exynos5433 DECON for DRM. + config DRM_EXYNOS7_DECON bool "Exynos7 DRM DECON" depends on DRM_EXYNOS && !FB_S3C diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index cc90679cfc061..fbd084d3f658d 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile @@ -10,6 +10,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \ exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o +exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON) += exynos5433_drm_decon.o exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c new file mode 100644 index 0000000000000..8b1225f245fc4 --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -0,0 +1,660 @@ +/* drivers/gpu/drm/exynos5433_drm_decon.c + * + * Copyright (C) 2015 Samsung Electronics Co.Ltd + * Authors: + * Joonyoung Shim + * Hyungwon Hwang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundationr + */ + +#include +#include +#include +#include +#include + +#include