Commit b5f4843c authored by Dave Airlie's avatar Dave Airlie

Merge branch 'exynos-drm-fixes' of...

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
parents b0a2c151 5d39b9ee
......@@ -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;
......
......@@ -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);
......
......@@ -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
......
......@@ -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);
......
......@@ -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:
......
......@@ -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,12 +511,7 @@ 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);
}
......@@ -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)
......
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment