diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index a5f7a695b8d1..02f5f5c99302 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -170,6 +170,7 @@ struct hdmi_data_info { unsigned int pix_repet_factor; unsigned int hdcp_enable; struct hdmi_vmode video_mode; + bool update; }; struct dw_hdmi_i2c { @@ -2015,6 +2016,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) { int ret; void *data = hdmi->plat_data->phy_data; + bool need_delay = false; hdmi_disable_overflow_interrupts(hdmi); @@ -2098,6 +2100,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) if (ret) return ret; hdmi->phy.enabled = true; + } else { + need_delay = true; } /* HDMI Initialization Step B.3 */ dw_hdmi_enable_video_path(hdmi); @@ -2128,6 +2132,9 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) dw_hdmi_clear_overflow(hdmi); + /* XXX: Add delay to make csc work before unmute video. */ + if (need_delay) + msleep(50); return 0; } @@ -2294,13 +2301,12 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) } static void -dw_hdmi_connector_atomic_flush(struct drm_connector *connector, +dw_hdmi_connector_atomic_begin(struct drm_connector *connector, struct drm_connector_state *conn_state) { struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); + connector); void *data = hdmi->plat_data->phy_data; - struct drm_display_mode *mode = NULL; unsigned int enc_in_bus_format; unsigned int enc_out_bus_format; unsigned int enc_in_encoding; @@ -2309,21 +2315,8 @@ dw_hdmi_connector_atomic_flush(struct drm_connector *connector, if (!hdmi->hpd_state || !conn_state->crtc) return; - DRM_DEBUG("%s\n", __func__); - - /* - * If HDMI is enabled in uboot, it's need to record - * drm_display_mode and set phy status to enabled. - */ - if (!hdmi->hdmi_data.video_mode.mpixelclock) { - mode = &conn_state->crtc->mode; - memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); - hdmi->hdmi_data.video_mode.mpixelclock = mode->clock; - hdmi->hdmi_data.video_mode.previous_pixelclock = mode->clock; - hdmi->hdmi_data.video_mode.previous_tmdsclock = mode->clock; - hdmi->phy.enabled = true; + if (!hdmi->hdmi_data.video_mode.mpixelclock) return; - } if (hdmi->plat_data->get_enc_in_encoding) enc_in_encoding = hdmi->plat_data->get_enc_in_encoding(data); @@ -2347,8 +2340,48 @@ dw_hdmi_connector_atomic_flush(struct drm_connector *connector, if (enc_in_encoding != hdmi->hdmi_data.enc_in_encoding || enc_out_encoding != hdmi->hdmi_data.enc_out_encoding || enc_in_bus_format != hdmi->hdmi_data.enc_in_bus_format || - enc_out_bus_format != hdmi->hdmi_data.enc_out_bus_format) + enc_out_bus_format != hdmi->hdmi_data.enc_out_bus_format) { + hdmi->hdmi_data.update = true; + hdmi_writeb(hdmi, HDMI_FC_GCP_SET_AVMUTE, HDMI_FC_GCP); + /* XXX: Add delay to make av mute work on sink*/ + msleep(50); + } else { + hdmi->hdmi_data.update = false; + } +} + +static void +dw_hdmi_connector_atomic_flush(struct drm_connector *connector, + struct drm_connector_state *conn_state) +{ + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, + connector); + struct drm_display_mode *mode = NULL; + + if (!hdmi->hpd_state || !conn_state->crtc) + return; + + DRM_DEBUG("%s\n", __func__); + + /* + * If HDMI is enabled in uboot, it's need to record + * drm_display_mode and set phy status to enabled. + */ + if (!hdmi->hdmi_data.video_mode.mpixelclock) { + mode = &conn_state->crtc->mode; + memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); + hdmi->hdmi_data.video_mode.mpixelclock = mode->clock; + hdmi->hdmi_data.video_mode.previous_pixelclock = mode->clock; + hdmi->hdmi_data.video_mode.previous_tmdsclock = mode->clock; + hdmi->phy.enabled = true; + return; + } + + if (hdmi->hdmi_data.update) { dw_hdmi_setup(hdmi, &hdmi->previous_mode); + hdmi_writeb(hdmi, HDMI_FC_GCP_CLEAR_AVMUTE, HDMI_FC_GCP); + hdmi->hdmi_data.update = false; + } } static int @@ -2423,6 +2456,7 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = { static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { .get_modes = dw_hdmi_connector_get_modes, .best_encoder = drm_atomic_helper_best_encoder, + .atomic_begin = dw_hdmi_connector_atomic_begin, .atomic_flush = dw_hdmi_connector_atomic_flush, }; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h index 2a4d70bc637c..6acb401ed2db 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h @@ -853,6 +853,10 @@ enum { HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00, HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04, +/* HDMI_FC_GCP */ + HDMI_FC_GCP_SET_AVMUTE = 0x2, + HDMI_FC_GCP_CLEAR_AVMUTE = 0x1, + /* FC_DBGFORCE field values */ HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10, HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,