Просмотр исходного кода

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
Dave Airlie 11 лет назад
Родитель
Сommit
b5f4843c67

+ 1 - 1
drivers/gpu/drm/exynos/exynos_drm_dpi.c

@@ -40,7 +40,7 @@ exynos_dpi_detect(struct drm_connector *connector, bool force)
 {
 	struct exynos_dpi *ctx = connector_to_dpi(connector);
 
-	if (!ctx->panel->connector)
+	if (ctx->panel && !ctx->panel->connector)
 		drm_panel_attach(ctx->panel, &ctx->connector);
 
 	return connector_status_connected;

+ 4 - 4
drivers/gpu/drm/exynos/exynos_drm_drv.c

@@ -765,24 +765,24 @@ static int exynos_drm_init(void)
 
 	return 0;
 
-err_unregister_pd:
-	platform_device_unregister(exynos_drm_pdev);
-
 err_remove_vidi:
 #ifdef CONFIG_DRM_EXYNOS_VIDI
 	exynos_drm_remove_vidi();
+
+err_unregister_pd:
 #endif
+	platform_device_unregister(exynos_drm_pdev);
 
 	return ret;
 }
 
 static void exynos_drm_exit(void)
 {
+	platform_driver_unregister(&exynos_drm_platform_driver);
 #ifdef CONFIG_DRM_EXYNOS_VIDI
 	exynos_drm_remove_vidi();
 #endif
 	platform_device_unregister(exynos_drm_pdev);
-	platform_driver_unregister(&exynos_drm_platform_driver);
 }
 
 module_init(exynos_drm_init);

+ 1 - 1
drivers/gpu/drm/exynos/exynos_drm_drv.h

@@ -343,7 +343,7 @@ struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
 int exynos_dpi_remove(struct device *dev);
 #else
 static inline struct exynos_drm_display *
-exynos_dpi_probe(struct device *dev) { return 0; }
+exynos_dpi_probe(struct device *dev) { return NULL; }
 static inline int exynos_dpi_remove(struct device *dev) { return 0; }
 #endif
 

+ 2 - 0
drivers/gpu/drm/exynos/exynos_drm_fimd.c

@@ -741,6 +741,8 @@ static void fimd_apply(struct exynos_drm_manager *mgr)
 		win_data = &ctx->win_data[i];
 		if (win_data->enabled)
 			fimd_win_commit(mgr, i);
+		else
+			fimd_win_disable(mgr, i);
 	}
 
 	fimd_commit(mgr);

+ 19 - 0
drivers/gpu/drm/exynos/exynos_hdmi.c

@@ -2090,6 +2090,11 @@ static void hdmi_poweroff(struct exynos_drm_display *display)
 
 static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 {
+	struct hdmi_context *hdata = display->ctx;
+	struct drm_encoder *encoder = hdata->encoder;
+	struct drm_crtc *crtc = encoder->crtc;
+	struct drm_crtc_helper_funcs *funcs = NULL;
+
 	DRM_DEBUG_KMS("mode %d\n", mode);
 
 	switch (mode) {
@@ -2099,6 +2104,20 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
+		/*
+		 * The SFRs of VP and Mixer are updated by Vertical Sync of
+		 * Timing generator which is a part of HDMI so the sequence
+		 * to disable TV Subsystem should be as following,
+		 *	VP -> Mixer -> HDMI
+		 *
+		 * Below codes will try to disable Mixer and VP(if used)
+		 * prior to disabling HDMI.
+		 */
+		if (crtc)
+			funcs = crtc->helper_private;
+		if (funcs && funcs->dpms)
+			(*funcs->dpms)(crtc, mode);
+
 		hdmi_poweroff(display);
 		break;
 	default:

+ 35 - 15
drivers/gpu/drm/exynos/exynos_mixer.c

@@ -377,6 +377,20 @@ static void mixer_run(struct mixer_context *ctx)
 	mixer_regs_dump(ctx);
 }
 
+static void mixer_stop(struct mixer_context *ctx)
+{
+	struct mixer_resources *res = &ctx->mixer_res;
+	int timeout = 20;
+
+	mixer_reg_writemask(res, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
+
+	while (!(mixer_reg_read(res, MXR_STATUS) & MXR_STATUS_REG_IDLE) &&
+			--timeout)
+		usleep_range(10000, 12000);
+
+	mixer_regs_dump(ctx);
+}
+
 static void vp_video_buffer(struct mixer_context *ctx, int win)
 {
 	struct mixer_resources *res = &ctx->mixer_res;
@@ -497,13 +511,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
 static void mixer_layer_update(struct mixer_context *ctx)
 {
 	struct mixer_resources *res = &ctx->mixer_res;
-	u32 val;
-
-	val = mixer_reg_read(res, MXR_CFG);
 
-	/* allow one update per vsync only */
-	if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK))
-		mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
+	mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
 }
 
 static 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)
 	}
 	mutex_unlock(&mixer_ctx->mixer_mutex);
 
+	drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe);
+
 	atomic_set(&mixer_ctx->wait_vsync_event, 1);
 
 	/*
@@ -1020,6 +1031,8 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
 				!atomic_read(&mixer_ctx->wait_vsync_event),
 				HZ/20))
 		DRM_DEBUG_KMS("vblank wait timed out.\n");
+
+	drm_vblank_put(mgr->crtc->dev, mixer_ctx->pipe);
 }
 
 static void mixer_window_suspend(struct exynos_drm_manager *mgr)
@@ -1061,7 +1074,7 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
 		mutex_unlock(&ctx->mixer_mutex);
 		return;
 	}
-	ctx->powered = true;
+
 	mutex_unlock(&ctx->mixer_mutex);
 
 	pm_runtime_get_sync(ctx->dev);
@@ -1072,6 +1085,12 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
 		clk_prepare_enable(res->sclk_mixer);
 	}
 
+	mutex_lock(&ctx->mixer_mutex);
+	ctx->powered = true;
+	mutex_unlock(&ctx->mixer_mutex);
+
+	mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
+
 	mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
 	mixer_win_reset(ctx);
 
@@ -1084,14 +1103,21 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
 	struct mixer_resources *res = &ctx->mixer_res;
 
 	mutex_lock(&ctx->mixer_mutex);
-	if (!ctx->powered)
-		goto out;
+	if (!ctx->powered) {
+		mutex_unlock(&ctx->mixer_mutex);
+		return;
+	}
 	mutex_unlock(&ctx->mixer_mutex);
 
+	mixer_stop(ctx);
 	mixer_window_suspend(mgr);
 
 	ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
 
+	mutex_lock(&ctx->mixer_mutex);
+	ctx->powered = false;
+	mutex_unlock(&ctx->mixer_mutex);
+
 	clk_disable_unprepare(res->mixer);
 	if (ctx->vp_enabled) {
 		clk_disable_unprepare(res->vp);
@@ -1099,12 +1125,6 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
 	}
 
 	pm_runtime_put_sync(ctx->dev);
-
-	mutex_lock(&ctx->mixer_mutex);
-	ctx->powered = false;
-
-out:
-	mutex_unlock(&ctx->mixer_mutex);
 }
 
 static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)

+ 1 - 0
drivers/gpu/drm/exynos/regs-mixer.h

@@ -78,6 +78,7 @@
 #define MXR_STATUS_BIG_ENDIAN		(1 << 3)
 #define MXR_STATUS_ENDIAN_MASK		(1 << 3)
 #define MXR_STATUS_SYNC_ENABLE		(1 << 2)
+#define MXR_STATUS_REG_IDLE		(1 << 1)
 #define MXR_STATUS_REG_RUN		(1 << 0)
 
 /* bits for MXR_CFG */