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
This commit is contained in:
commit
b5f4843c67
|
@ -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 @@ out:
|
|||
|
||||
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,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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue