diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 9ce47096cbd2..8c0394f8b250 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -147,10 +147,11 @@ static const u16 csc_coeff_rgb_in_eitu709[3][4] = { struct hdmi_vmode { bool mdataenablepolarity; + unsigned int previous_pixelclock; unsigned int mpixelclock; unsigned int mpixelrepetitioninput; unsigned int mpixelrepetitionoutput; - + unsigned int previous_tmdsclock; unsigned int mtmdsclock; }; @@ -1806,6 +1807,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; unsigned int hdisplay, vdisplay; + vmode->previous_pixelclock = vmode->mpixelclock; vmode->mpixelclock = mode->crtc_clock * 1000; if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) vmode->mpixelclock /= 2; @@ -1813,7 +1815,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, DRM_MODE_FLAG_3D_FRAME_PACKING) vmode->mpixelclock *= 2; dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock); - + vmode->previous_tmdsclock = vmode->mtmdsclock; vmode->mtmdsclock = hdmi_get_tmdsclock(hdmi, vmode->mpixelclock); dev_dbg(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock); @@ -2118,11 +2120,17 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) hdmi_av_composer(hdmi, mode); /* HDMI Initializateion Step B.2 */ - ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode); - if (ret) - return ret; - hdmi->phy.enabled = true; - + if (!hdmi->phy.enabled || + hdmi->hdmi_data.video_mode.previous_pixelclock != + hdmi->hdmi_data.video_mode.mpixelclock || + hdmi->hdmi_data.video_mode.previous_tmdsclock != + hdmi->hdmi_data.video_mode.mtmdsclock) { + ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, + &hdmi->previous_mode); + if (ret) + return ret; + hdmi->phy.enabled = true; + } /* HDMI Initialization Step B.3 */ dw_hdmi_enable_video_path(hdmi); @@ -2405,6 +2413,64 @@ static void dw_hdmi_connector_destroy(struct drm_connector *connector) drm_connector_cleanup(connector); } +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); + 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; + unsigned int enc_out_encoding; + + 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->plat_data->get_enc_in_encoding) + enc_in_encoding = hdmi->plat_data->get_enc_in_encoding(data); + else + enc_in_encoding = hdmi->hdmi_data.enc_in_encoding; + if (hdmi->plat_data->get_enc_out_encoding) + enc_out_encoding = hdmi->plat_data->get_enc_out_encoding(data); + else + enc_out_encoding = hdmi->hdmi_data.enc_out_encoding; + if (hdmi->plat_data->get_input_bus_format) + enc_in_bus_format = + hdmi->plat_data->get_input_bus_format(data); + else + enc_in_bus_format = hdmi->hdmi_data.enc_in_bus_format; + if (hdmi->plat_data->get_output_bus_format) + enc_out_bus_format = + hdmi->plat_data->get_output_bus_format(data); + else + enc_out_bus_format = hdmi->hdmi_data.enc_out_bus_format; + + 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) + dw_hdmi_setup(hdmi, &hdmi->previous_mode); +} + static int dw_hdmi_atomic_connector_set_property(struct drm_connector *connector, struct drm_connector_state *state, @@ -2495,6 +2561,7 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = .get_modes = dw_hdmi_connector_get_modes, .mode_valid = dw_hdmi_connector_mode_valid, .best_encoder = dw_hdmi_connector_best_encoder, + .atomic_flush = dw_hdmi_connector_atomic_flush, }; static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {