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) ...@@ -40,7 +40,7 @@ exynos_dpi_detect(struct drm_connector *connector, bool force)
{ {
struct exynos_dpi *ctx = connector_to_dpi(connector); 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); drm_panel_attach(ctx->panel, &ctx->connector);
return connector_status_connected; return connector_status_connected;
......
...@@ -765,24 +765,24 @@ static int exynos_drm_init(void) ...@@ -765,24 +765,24 @@ static int exynos_drm_init(void)
return 0; return 0;
err_unregister_pd:
platform_device_unregister(exynos_drm_pdev);
err_remove_vidi: err_remove_vidi:
#ifdef CONFIG_DRM_EXYNOS_VIDI #ifdef CONFIG_DRM_EXYNOS_VIDI
exynos_drm_remove_vidi(); exynos_drm_remove_vidi();
err_unregister_pd:
#endif #endif
platform_device_unregister(exynos_drm_pdev);
return ret; return ret;
} }
static void exynos_drm_exit(void) static void exynos_drm_exit(void)
{ {
platform_driver_unregister(&exynos_drm_platform_driver);
#ifdef CONFIG_DRM_EXYNOS_VIDI #ifdef CONFIG_DRM_EXYNOS_VIDI
exynos_drm_remove_vidi(); exynos_drm_remove_vidi();
#endif #endif
platform_device_unregister(exynos_drm_pdev); platform_device_unregister(exynos_drm_pdev);
platform_driver_unregister(&exynos_drm_platform_driver);
} }
module_init(exynos_drm_init); module_init(exynos_drm_init);
......
...@@ -343,7 +343,7 @@ struct exynos_drm_display * exynos_dpi_probe(struct device *dev); ...@@ -343,7 +343,7 @@ struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
int exynos_dpi_remove(struct device *dev); int exynos_dpi_remove(struct device *dev);
#else #else
static inline struct exynos_drm_display * 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; } static inline int exynos_dpi_remove(struct device *dev) { return 0; }
#endif #endif
......
...@@ -741,6 +741,8 @@ static void fimd_apply(struct exynos_drm_manager *mgr) ...@@ -741,6 +741,8 @@ static void fimd_apply(struct exynos_drm_manager *mgr)
win_data = &ctx->win_data[i]; win_data = &ctx->win_data[i];
if (win_data->enabled) if (win_data->enabled)
fimd_win_commit(mgr, i); fimd_win_commit(mgr, i);
else
fimd_win_disable(mgr, i);
} }
fimd_commit(mgr); fimd_commit(mgr);
......
...@@ -2090,6 +2090,11 @@ static void hdmi_poweroff(struct exynos_drm_display *display) ...@@ -2090,6 +2090,11 @@ static void hdmi_poweroff(struct exynos_drm_display *display)
static void hdmi_dpms(struct exynos_drm_display *display, int mode) 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); DRM_DEBUG_KMS("mode %d\n", mode);
switch (mode) { switch (mode) {
...@@ -2099,6 +2104,20 @@ static void hdmi_dpms(struct exynos_drm_display *display, int 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_STANDBY:
case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF: 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); hdmi_poweroff(display);
break; break;
default: default:
......
...@@ -377,6 +377,20 @@ static void mixer_run(struct mixer_context *ctx) ...@@ -377,6 +377,20 @@ static void mixer_run(struct mixer_context *ctx)
mixer_regs_dump(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) static void vp_video_buffer(struct mixer_context *ctx, int win)
{ {
struct mixer_resources *res = &ctx->mixer_res; struct mixer_resources *res = &ctx->mixer_res;
...@@ -497,13 +511,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) ...@@ -497,13 +511,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
static void mixer_layer_update(struct mixer_context *ctx) static void mixer_layer_update(struct mixer_context *ctx)
{ {
struct mixer_resources *res = &ctx->mixer_res; struct mixer_resources *res = &ctx->mixer_res;
u32 val;
val = mixer_reg_read(res, MXR_CFG);
/* allow one update per vsync only */ mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK))
mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
} }
static void mixer_graph_buffer(struct mixer_context *ctx, int win) 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) ...@@ -1010,6 +1019,8 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
} }
mutex_unlock(&mixer_ctx->mixer_mutex); mutex_unlock(&mixer_ctx->mixer_mutex);
drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe);
atomic_set(&mixer_ctx->wait_vsync_event, 1); atomic_set(&mixer_ctx->wait_vsync_event, 1);
/* /*
...@@ -1020,6 +1031,8 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr) ...@@ -1020,6 +1031,8 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
!atomic_read(&mixer_ctx->wait_vsync_event), !atomic_read(&mixer_ctx->wait_vsync_event),
HZ/20)) HZ/20))
DRM_DEBUG_KMS("vblank wait timed out.\n"); 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) static void mixer_window_suspend(struct exynos_drm_manager *mgr)
...@@ -1061,7 +1074,7 @@ static void mixer_poweron(struct exynos_drm_manager *mgr) ...@@ -1061,7 +1074,7 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
mutex_unlock(&ctx->mixer_mutex); mutex_unlock(&ctx->mixer_mutex);
return; return;
} }
ctx->powered = true;
mutex_unlock(&ctx->mixer_mutex); mutex_unlock(&ctx->mixer_mutex);
pm_runtime_get_sync(ctx->dev); pm_runtime_get_sync(ctx->dev);
...@@ -1072,6 +1085,12 @@ static void mixer_poweron(struct exynos_drm_manager *mgr) ...@@ -1072,6 +1085,12 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
clk_prepare_enable(res->sclk_mixer); 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_reg_write(res, MXR_INT_EN, ctx->int_en);
mixer_win_reset(ctx); mixer_win_reset(ctx);
...@@ -1084,14 +1103,21 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr) ...@@ -1084,14 +1103,21 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
struct mixer_resources *res = &ctx->mixer_res; struct mixer_resources *res = &ctx->mixer_res;
mutex_lock(&ctx->mixer_mutex); mutex_lock(&ctx->mixer_mutex);
if (!ctx->powered) if (!ctx->powered) {
goto out; mutex_unlock(&ctx->mixer_mutex);
return;
}
mutex_unlock(&ctx->mixer_mutex); mutex_unlock(&ctx->mixer_mutex);
mixer_stop(ctx);
mixer_window_suspend(mgr); mixer_window_suspend(mgr);
ctx->int_en = mixer_reg_read(res, MXR_INT_EN); 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); clk_disable_unprepare(res->mixer);
if (ctx->vp_enabled) { if (ctx->vp_enabled) {
clk_disable_unprepare(res->vp); clk_disable_unprepare(res->vp);
...@@ -1099,12 +1125,6 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr) ...@@ -1099,12 +1125,6 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
} }
pm_runtime_put_sync(ctx->dev); 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) static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
......
...@@ -78,6 +78,7 @@ ...@@ -78,6 +78,7 @@
#define MXR_STATUS_BIG_ENDIAN (1 << 3) #define MXR_STATUS_BIG_ENDIAN (1 << 3)
#define MXR_STATUS_ENDIAN_MASK (1 << 3) #define MXR_STATUS_ENDIAN_MASK (1 << 3)
#define MXR_STATUS_SYNC_ENABLE (1 << 2) #define MXR_STATUS_SYNC_ENABLE (1 << 2)
#define MXR_STATUS_REG_IDLE (1 << 1)
#define MXR_STATUS_REG_RUN (1 << 0) #define MXR_STATUS_REG_RUN (1 << 0)
/* bits for MXR_CFG */ /* 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