aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-06-24 23:28:08 -0400
committerDave Airlie <airlied@redhat.com>2014-06-24 23:28:08 -0400
commitb5f4843c67843588c5ebbe374f586a509bbe237d (patch)
tree44f3a7bc8964bdf9cb4b2d9b51bd9c9354eac41b
parentb0a2c15150a037b3ccd699c71c4aa7462c8b2bd1 (diff)
parent5d39b9ee8b16b57fdbc065b91ebdd4ac03dab568 (diff)
Merge branch 'exynos-drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-fixes
This pull-request fixes hdmi power-off order issue, mixer issues related to power on/off, and includes trivial fixups. * 'exynos-drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: drm/exynos: enable vsync interrupt while waiting for vblank drm/exynos: soft reset mixer before reconfigure after power-on drm/exynos: allow multiple layer updates per vsync for mixer drm/exynos: stop mixer before gating clocks during poweroff drm/exynos: set power state variable after enabling clocks and power drm/exynos: disable unused windows on apply drm/exynos: Fix de-registration ordering drm/exynos: change zero to NULL for sparse drm/exynos: dpi: Fix NULL pointer dereference with legacy bindings drm/exynos: hdmi: fix power order issue
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dpi.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c19
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c50
-rw-r--r--drivers/gpu/drm/exynos/regs-mixer.h1
7 files changed, 63 insertions, 21 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 482127f633c5..9e530f205ad2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -40,7 +40,7 @@ exynos_dpi_detect(struct drm_connector *connector, bool force)
40{ 40{
41 struct exynos_dpi *ctx = connector_to_dpi(connector); 41 struct exynos_dpi *ctx = connector_to_dpi(connector);
42 42
43 if (!ctx->panel->connector) 43 if (ctx->panel && !ctx->panel->connector)
44 drm_panel_attach(ctx->panel, &ctx->connector); 44 drm_panel_attach(ctx->panel, &ctx->connector);
45 45
46 return connector_status_connected; 46 return connector_status_connected;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index d91f27777537..ab7d182063c3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -765,24 +765,24 @@ static int exynos_drm_init(void)
765 765
766 return 0; 766 return 0;
767 767
768err_unregister_pd:
769 platform_device_unregister(exynos_drm_pdev);
770
771err_remove_vidi: 768err_remove_vidi:
772#ifdef CONFIG_DRM_EXYNOS_VIDI 769#ifdef CONFIG_DRM_EXYNOS_VIDI
773 exynos_drm_remove_vidi(); 770 exynos_drm_remove_vidi();
771
772err_unregister_pd:
774#endif 773#endif
774 platform_device_unregister(exynos_drm_pdev);
775 775
776 return ret; 776 return ret;
777} 777}
778 778
779static void exynos_drm_exit(void) 779static void exynos_drm_exit(void)
780{ 780{
781 platform_driver_unregister(&exynos_drm_platform_driver);
781#ifdef CONFIG_DRM_EXYNOS_VIDI 782#ifdef CONFIG_DRM_EXYNOS_VIDI
782 exynos_drm_remove_vidi(); 783 exynos_drm_remove_vidi();
783#endif 784#endif
784 platform_device_unregister(exynos_drm_pdev); 785 platform_device_unregister(exynos_drm_pdev);
785 platform_driver_unregister(&exynos_drm_platform_driver);
786} 786}
787 787
788module_init(exynos_drm_init); 788module_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 36535f398848..06cde4506278 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -343,7 +343,7 @@ struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
343int exynos_dpi_remove(struct device *dev); 343int exynos_dpi_remove(struct device *dev);
344#else 344#else
345static inline struct exynos_drm_display * 345static inline struct exynos_drm_display *
346exynos_dpi_probe(struct device *dev) { return 0; } 346exynos_dpi_probe(struct device *dev) { return NULL; }
347static inline int exynos_dpi_remove(struct device *dev) { return 0; } 347static inline int exynos_dpi_remove(struct device *dev) { return 0; }
348#endif 348#endif
349 349
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index bb45ab2e7384..33161ad38201 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -741,6 +741,8 @@ static void fimd_apply(struct exynos_drm_manager *mgr)
741 win_data = &ctx->win_data[i]; 741 win_data = &ctx->win_data[i];
742 if (win_data->enabled) 742 if (win_data->enabled)
743 fimd_win_commit(mgr, i); 743 fimd_win_commit(mgr, i);
744 else
745 fimd_win_disable(mgr, i);
744 } 746 }
745 747
746 fimd_commit(mgr); 748 fimd_commit(mgr);
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index c104d0c9b385..aa259b0a873a 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -2090,6 +2090,11 @@ out:
2090 2090
2091static void hdmi_dpms(struct exynos_drm_display *display, int mode) 2091static void hdmi_dpms(struct exynos_drm_display *display, int mode)
2092{ 2092{
2093 struct hdmi_context *hdata = display->ctx;
2094 struct drm_encoder *encoder = hdata->encoder;
2095 struct drm_crtc *crtc = encoder->crtc;
2096 struct drm_crtc_helper_funcs *funcs = NULL;
2097
2093 DRM_DEBUG_KMS("mode %d\n", mode); 2098 DRM_DEBUG_KMS("mode %d\n", mode);
2094 2099
2095 switch (mode) { 2100 switch (mode) {
@@ -2099,6 +2104,20 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
2099 case DRM_MODE_DPMS_STANDBY: 2104 case DRM_MODE_DPMS_STANDBY:
2100 case DRM_MODE_DPMS_SUSPEND: 2105 case DRM_MODE_DPMS_SUSPEND:
2101 case DRM_MODE_DPMS_OFF: 2106 case DRM_MODE_DPMS_OFF:
2107 /*
2108 * The SFRs of VP and Mixer are updated by Vertical Sync of
2109 * Timing generator which is a part of HDMI so the sequence
2110 * to disable TV Subsystem should be as following,
2111 * VP -> Mixer -> HDMI
2112 *
2113 * Below codes will try to disable Mixer and VP(if used)
2114 * prior to disabling HDMI.
2115 */
2116 if (crtc)
2117 funcs = crtc->helper_private;
2118 if (funcs && funcs->dpms)
2119 (*funcs->dpms)(crtc, mode);
2120
2102 hdmi_poweroff(display); 2121 hdmi_poweroff(display);
2103 break; 2122 break;
2104 default: 2123 default:
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 4c5aed7e54c8..7529946d0a74 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -377,6 +377,20 @@ static void mixer_run(struct mixer_context *ctx)
377 mixer_regs_dump(ctx); 377 mixer_regs_dump(ctx);
378} 378}
379 379
380static void mixer_stop(struct mixer_context *ctx)
381{
382 struct mixer_resources *res = &ctx->mixer_res;
383 int timeout = 20;
384
385 mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
386
387 while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
388 --timeout)
389 usleep_range(10000, 12000);
390
391 mixer_regs_dump(ctx);
392}
393
380static void vp_video_buffer(struct mixer_context *ctx, int win) 394static void vp_video_buffer(struct mixer_context *ctx, int win)
381{ 395{
382 struct mixer_resources *res = &ctx->mixer_res; 396 struct mixer_resources *res = &ctx->mixer_res;
@@ -497,13 +511,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
497static void mixer_layer_update(struct mixer_context *ctx) 511static void mixer_layer_update(struct mixer_context *ctx)
498{ 512{
499 struct mixer_resources *res = &ctx->mixer_res; 513 struct mixer_resources *res = &ctx->mixer_res;
500 u32 val;
501
502 val = mixer_reg_read(res, MXR_CFG);
503 514
504 /* allow one update per vsync only */ 515 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
505 if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK))
506 mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
507} 516}
508 517
509static void mixer_graph_buffer(struct mixer_context *ctx, int win) 518static void mixer_graph_buffer(struct mixer_context *ctx, int win)
@@ -1010,6 +1019,8 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
1010 } 1019 }
1011 mutex_unlock(&mixer_ctx->mixer_mutex); 1020 mutex_unlock(&mixer_ctx->mixer_mutex);
1012 1021
1022 drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe);
1023
1013 atomic_set(&mixer_ctx->wait_vsync_event, 1); 1024 atomic_set(&mixer_ctx->wait_vsync_event, 1);
1014 1025
1015 /* 1026 /*
@@ -1020,6 +1031,8 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
1020 !atomic_read(&mixer_ctx->wait_vsync_event), 1031 !atomic_read(&mixer_ctx->wait_vsync_event),
1021 HZ/20)) 1032 HZ/20))
1022 DRM_DEBUG_KMS("vblank wait timed out.\n"); 1033 DRM_DEBUG_KMS("vblank wait timed out.\n");
1034
1035 drm_vblank_put(mgr->crtc->dev, mixer_ctx->pipe);
1023} 1036}
1024 1037
1025static void mixer_window_suspend(struct exynos_drm_manager *mgr) 1038static void mixer_window_suspend(struct exynos_drm_manager *mgr)
@@ -1061,7 +1074,7 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
1061 mutex_unlock(&ctx->mixer_mutex); 1074 mutex_unlock(&ctx->mixer_mutex);
1062 return; 1075 return;
1063 } 1076 }
1064 ctx->powered = true; 1077
1065 mutex_unlock(&ctx->mixer_mutex); 1078 mutex_unlock(&ctx->mixer_mutex);
1066 1079
1067 pm_runtime_get_sync(ctx->dev); 1080 pm_runtime_get_sync(ctx->dev);
@@ -1072,6 +1085,12 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
1072 clk_prepare_enable(res->sclk_mixer); 1085 clk_prepare_enable(res->sclk_mixer);
1073 } 1086 }
1074 1087
1088 mutex_lock(&ctx->mixer_mutex);
1089 ctx->powered = true;
1090 mutex_unlock(&ctx->mixer_mutex);
1091
1092 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
1093
1075 mixer_reg_write(res, MXR_INT_EN, ctx->int_en); 1094 mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
1076 mixer_win_reset(ctx); 1095 mixer_win_reset(ctx);
1077 1096
@@ -1084,14 +1103,21 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
1084 struct mixer_resources *res = &ctx->mixer_res; 1103 struct mixer_resources *res = &ctx->mixer_res;
1085 1104
1086 mutex_lock(&ctx->mixer_mutex); 1105 mutex_lock(&ctx->mixer_mutex);
1087 if (!ctx->powered) 1106 if (!ctx->powered) {
1088 goto out; 1107 mutex_unlock(&ctx->mixer_mutex);
1108 return;
1109 }
1089 mutex_unlock(&ctx->mixer_mutex); 1110 mutex_unlock(&ctx->mixer_mutex);
1090 1111
1112 mixer_stop(ctx);
1091 mixer_window_suspend(mgr); 1113 mixer_window_suspend(mgr);
1092 1114
1093 ctx->int_en = mixer_reg_read(res, MXR_INT_EN); 1115 ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
1094 1116
1117 mutex_lock(&ctx->mixer_mutex);
1118 ctx->powered = false;
1119 mutex_unlock(&ctx->mixer_mutex);
1120
1095 clk_disable_unprepare(res->mixer); 1121 clk_disable_unprepare(res->mixer);
1096 if (ctx->vp_enabled) { 1122 if (ctx->vp_enabled) {
1097 clk_disable_unprepare(res->vp); 1123 clk_disable_unprepare(res->vp);
@@ -1099,12 +1125,6 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
1099 } 1125 }
1100 1126
1101 pm_runtime_put_sync(ctx->dev); 1127 pm_runtime_put_sync(ctx->dev);
1102
1103 mutex_lock(&ctx->mixer_mutex);
1104 ctx->powered = false;
1105
1106out:
1107 mutex_unlock(&ctx->mixer_mutex);
1108} 1128}
1109 1129
1110static void mixer_dpms(struct exynos_drm_manager *mgr, int mode) 1130static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h
index 4537026bc385..5f32e1a29411 100644
--- a/drivers/gpu/drm/exynos/regs-mixer.h
+++ b/drivers/gpu/drm/exynos/regs-mixer.h
@@ -78,6 +78,7 @@
78#define MXR_STATUS_BIG_ENDIAN (1 << 3) 78#define MXR_STATUS_BIG_ENDIAN (1 << 3)
79#define MXR_STATUS_ENDIAN_MASK (1 << 3) 79#define MXR_STATUS_ENDIAN_MASK (1 << 3)
80#define MXR_STATUS_SYNC_ENABLE (1 << 2) 80#define MXR_STATUS_SYNC_ENABLE (1 << 2)
81#define MXR_STATUS_REG_IDLE (1 << 1)
81#define MXR_STATUS_REG_RUN (1 << 0) 82#define MXR_STATUS_REG_RUN (1 << 0)
82 83
83/* bits for MXR_CFG */ 84/* bits for MXR_CFG */