@@ -261,10 +261,17 @@ static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ /* When powering up, we must first power up the HDMI component, as
+ * otherwise mixer register accesses will sometimes hang.
+ * When powering down, we do the opposite: mixer off, HDMI off. */
+
+ if (mode == DRM_MODE_DPMS_ON && hdmi_ops && hdmi_ops->dpms)
+ hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
+
if (mixer_ops && mixer_ops->dpms)
mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
- if (hdmi_ops && hdmi_ops->dpms)
+ if (mode != DRM_MODE_DPMS_ON && hdmi_ops && hdmi_ops->dpms)
hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
}
Testing on Exynos4412, when changing screen resolution under GNOME/X11, first DPMS is set to OFF via drm_mode_obj_set_property_ioctl. This is done via drm_hdmi_dpms which powers down the mixer then the HDMI component. Then the mode change happens. We then see this call chain, powering things back on: exynos_drm_crtc_commit exynos_drm_crtc_dpms exynos_drm_encoder_crtc_dpms drm_hdmi_dpms And at this point, drm_hdmi_dpms first powers on the mixer, then the HDMI component. Strangely enough, this works fine on the first resolution change, but on the second it hangs in mixer_poweron() in: mixer_reg_write(res, MXR_INT_EN, ctx->int_en); Through some experiments I determined that this register write will hang the machine here unless the hdmi_resources.hdmi clock is running. I can't explain why there is a difference between the first and second time; I did check that the underlying clock gating register has the same value in both cases. Anyway, the mixer clearly has some kind of dependency on the HDMI component, so lets make sure we power that up first. Signed-off-by: Daniel Drake <drake@endlessm.com> --- drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)