From 949befa2e728b18654e0fcc217fc480ac2cf52de Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Tue, 12 Aug 2025 11:09:17 +0800 Subject: [PATCH] drm/bridge: synopsys: dw-hdmi-qp: Independently configure color and infoframe When the HDMI status changes, there is no need to call dw_hdmi_qp_setup() function every time. The configuration can be carried out independently for specific changed parts. This can reduce delays and avoid mutual interference. Change-Id: I5999961893d517cba04c58ca0c96fe201d413ee0 Signed-off-by: Algea Cao --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 140 ++++++++----------- include/drm/bridge/dw_hdmi.h | 5 + 2 files changed, 67 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 4f3602d98d35..118153b0572d 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -302,7 +302,6 @@ struct dw_hdmi_qp { bool sink_is_hdmi; bool sink_has_audio; bool dclk_en; - bool frl_switch; /* when frl mode switch color and freq is equal set true */ bool cec_enable; bool allm_enable; bool support_hdmi; @@ -321,6 +320,7 @@ struct dw_hdmi_qp { u8 phy_mask; /* desired phy int mask settings */ u8 mc_clkdis; /* clock disable register */ u8 hdcp_status; + u8 hdmi_changed_status; u32 max_ffe_lv; bool update; @@ -2263,9 +2263,6 @@ static int dw_hdmi_qp_flt_ltsp(struct dw_hdmi_qp *hdmi) /* exit frl mode, maybe it was a training failure or hdmi was disabled */ static int dw_hdmi_qp_flt_ltsl(struct dw_hdmi_qp *hdmi) { - if (hdmi->frl_switch) - return -EINVAL; - drm_scdc_writeb(hdmi->ddc, SCDC_CONFIG_1, 0); drm_scdc_writeb(hdmi->ddc, SCDC_UPDATE_0, BIT(5)); @@ -2280,9 +2277,6 @@ static int hdmi_set_op_mode(struct dw_hdmi_qp *hdmi, { int ret = 0; - if (hdmi->frl_switch) - return 0; - if (!link_cfg->frl_mode) { dev_info(hdmi->dev, "dw hdmi qp use tmds mode\n"); hdmi_modb(hdmi, 0, AVP_DATAPATH_VIDEO_SWDISABLE, GLOBAL_SWDISABLE); @@ -2420,9 +2414,6 @@ static void dw_hdmi_qp_flt_work(struct work_struct *p_work) u8 frl_rate; int state = LTS1; - if (hdmi->frl_switch) - return; - frl_rate = link_cfg->frl_lanes * link_cfg->rate_per_lane; while (1) { @@ -2532,7 +2523,7 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, hdmi->phy.ops->set_mode(hdmi, hdmi->phy.data, HDMI_MODE_FRL_MASK, link_cfg->frl_mode); - if (!hdmi->update && !hdmi->frl_switch && hdmi->plat_data->link_clk_set) + if (!hdmi->update && hdmi->plat_data->link_clk_set) hdmi->plat_data->link_clk_set(data, true); /* @@ -2601,7 +2592,6 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, ret = hdmi_set_op_mode(hdmi, link_cfg, connector); if (ret) { dev_err(hdmi->dev, "%s hdmi set operation mode failed\n", __func__); - hdmi->frl_switch = false; return ret; } } else { @@ -2613,7 +2603,6 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, dev_info(hdmi->dev, "%s DVI mode\n", __func__); } - hdmi->frl_switch = false; return 0; } @@ -3158,27 +3147,6 @@ dw_hdmi_connector_best_encoder(struct drm_connector *connector) return hdmi->bridge.encoder; } -static bool dw_hdmi_color_changed(struct drm_connector *connector, - struct drm_atomic_state *state) -{ - struct dw_hdmi_qp *hdmi = - container_of(connector, struct dw_hdmi_qp, connector); - void *data = hdmi->plat_data->phy_data; - struct drm_connector_state *old_state = - drm_atomic_get_old_connector_state(state, connector); - struct drm_connector_state *new_state = - drm_atomic_get_new_connector_state(state, connector); - bool ret = false; - - if (hdmi->plat_data->get_color_changed) - ret = hdmi->plat_data->get_color_changed(data); - - if (new_state->colorspace != old_state->colorspace) - ret = true; - - return ret; -} - static bool hdr_metadata_equal(struct dw_hdmi_qp *hdmi, const struct drm_connector_state *old_state, const struct drm_connector_state *new_state) { @@ -3231,20 +3199,6 @@ static bool hdr_metadata_equal(struct dw_hdmi_qp *hdmi, const struct drm_connect return ret; } -static bool check_hdr_color_change(struct drm_connector_state *old_state, - struct drm_connector_state *new_state, - struct dw_hdmi_qp *hdmi) -{ - void *data = hdmi->plat_data->phy_data; - - if (!hdr_metadata_equal(hdmi, old_state, new_state)) { - hdmi->plat_data->check_hdr_color_change(new_state, data); - return true; - } - - return false; -} - static void dw_hdmi_qp_hdcp_disable(struct dw_hdmi_qp *hdmi, const struct drm_connector_state *conn_state) { @@ -3311,6 +3265,53 @@ static bool dovi_vsif_equal(struct dw_hdmi_qp *hdmi) } } +static u8 dw_hdmi_qp_state_changed(struct dw_hdmi_qp *hdmi, struct drm_connector *connector, + struct drm_atomic_state *state) +{ + struct drm_connector_state *old_state = + drm_atomic_get_old_connector_state(state, connector); + struct drm_connector_state *new_state = + drm_atomic_get_new_connector_state(state, connector); + void *data = hdmi->plat_data->phy_data; + u32 old_enc_in_encoding = hdmi->hdmi_data.enc_in_encoding; + u32 old_enc_out_encoding = hdmi->hdmi_data.enc_out_encoding; + u32 old_enc_in_bus_format = hdmi->hdmi_data.enc_in_bus_format; + u32 old_enc_out_bus_format = hdmi->hdmi_data.enc_out_bus_format; + + if (hdmi->plat_data->update_color_format) + hdmi->plat_data->update_color_format(new_state, data); + if (hdmi->plat_data->get_enc_in_encoding) + hdmi->hdmi_data.enc_in_encoding = hdmi->plat_data->get_enc_in_encoding(data); + if (hdmi->plat_data->get_enc_out_encoding) + hdmi->hdmi_data.enc_out_encoding = hdmi->plat_data->get_enc_out_encoding(data); + if (hdmi->plat_data->get_input_bus_format) + hdmi->hdmi_data.enc_in_bus_format = hdmi->plat_data->get_input_bus_format(data); + if (hdmi->plat_data->get_output_bus_format) + hdmi->hdmi_data.enc_out_bus_format = hdmi->plat_data->get_output_bus_format(data); + + hdmi->hdmi_changed_status = 0; + + if (!dovi_vsif_equal(hdmi)) + hdmi->hdmi_changed_status |= HDMI_VSIF_CHANGED; + + if (!hdr_metadata_equal(hdmi, old_state, new_state)) + hdmi->hdmi_changed_status |= HDMI_HDR_STATUS_CHANGED; + + if (old_enc_in_bus_format != hdmi->hdmi_data.enc_in_bus_format || + old_enc_out_bus_format != hdmi->hdmi_data.enc_out_bus_format || + old_enc_in_encoding != hdmi->hdmi_data.enc_in_encoding || + old_enc_out_encoding != hdmi->hdmi_data.enc_out_encoding) { + hdmi->hdmi_changed_status |= HDMI_COLOR_FMT_CHANGED; + if (hdmi->plat_data->set_prev_bus_format) + hdmi->plat_data->set_prev_bus_format(data, old_enc_out_bus_format); + } + + if (dw_hdmi_qp_check_output_type_changed(hdmi)) + hdmi->hdmi_changed_status |= HDMI_OUTPUT_MODE_CHANGED; + + return hdmi->hdmi_changed_status; +} + static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, struct drm_atomic_state *state) { @@ -3414,44 +3415,25 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, hdmi->logo_plug_out = true; } - if (check_hdr_color_change(old_state, new_state, hdmi) || hdmi->logo_plug_out || - dw_hdmi_color_changed(connector, state) || - dw_hdmi_qp_check_output_type_changed(hdmi)) { + if (dw_hdmi_qp_state_changed(hdmi, connector, state) || hdmi->logo_plug_out) { u32 mtmdsclk; crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (hdmi->plat_data->update_color_format) - hdmi->plat_data->update_color_format(new_state, data); - if (hdmi->plat_data->get_enc_in_encoding) - hdmi->hdmi_data.enc_in_encoding = - hdmi->plat_data->get_enc_in_encoding(data); - if (hdmi->plat_data->get_enc_out_encoding) - hdmi->hdmi_data.enc_out_encoding = - hdmi->plat_data->get_enc_out_encoding(data); - if (hdmi->plat_data->get_input_bus_format) - hdmi->hdmi_data.enc_in_bus_format = - hdmi->plat_data->get_input_bus_format(data); - if (hdmi->plat_data->get_output_bus_format) - hdmi->hdmi_data.enc_out_bus_format = - hdmi->plat_data->get_output_bus_format(data); - mtmdsclk = hdmi_get_tmdsclock(hdmi, mode.clock); if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) mtmdsclk /= 2; if (hdmi->hdmi_data.video_mode.mpixelclock == (mode.clock * 1000) && hdmi->hdmi_data.video_mode.mtmdsclock == (mtmdsclk * 1000) && - mode.clock <= 600000 && !hdmi->disabled && !hdmi->logo_plug_out) { + !hdmi->disabled && !hdmi->logo_plug_out) { hdmi->update = true; hdmi_writel(hdmi, 1, PKTSCHED_PKT_CONTROL0); hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); mdelay(50); } else if (!hdmi->disabled) { - if (hdmi->previous_mode.clock > 600000 && mode.clock > 600000) - hdmi->frl_switch = true; hdmi->update = false; crtc_state->mode_changed = true; hdmi->logo_plug_out = false; @@ -3468,7 +3450,14 @@ static void dw_hdmi_connector_atomic_commit(struct drm_connector *connector, container_of(connector, struct dw_hdmi_qp, connector); if (hdmi->update) { - dw_hdmi_qp_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); + if (hdmi->hdmi_changed_status & HDMI_COLOR_FMT_CHANGED) { + if (hdmi->plat_data->set_grf_cfg) + hdmi->plat_data->set_grf_cfg(hdmi->plat_data->phy_data); + hdmi_config_AVI(hdmi, connector, &hdmi->previous_mode); + } + if (hdmi->hdmi_changed_status & HDMI_HDR_STATUS_CHANGED) + hdmi_config_drm_infoframe(hdmi, connector); + msleep(50); hdmi_writel(hdmi, 2, PKTSCHED_PKT_CONTROL0); hdmi->update = false; @@ -3476,7 +3465,7 @@ static void dw_hdmi_connector_atomic_commit(struct drm_connector *connector, if (!hdmi->disabled) { set_dw_hdmi_hdcp_enable(hdmi, connector, state); - if (!dovi_vsif_equal(hdmi)) + if (hdmi->hdmi_changed_status & HDMI_VSIF_CHANGED) hdmi_config_vendor_specific_infoframe(hdmi, hdmi->curr_conn, &hdmi->previous_mode); } @@ -3658,8 +3647,6 @@ static void dw_hdmi_qp_bridge_mode_set(struct drm_bridge *bridge, mutex_lock(&hdmi->mutex); - if (!drm_mode_equal(orig_mode, mode)) - hdmi->frl_switch = false; /* Store the display mode for plugin/DKMS poweron events */ drm_mode_copy(&hdmi->previous_mode, mode); if (hdmi->plat_data->split_mode || hdmi->plat_data->dual_connector_split) @@ -3687,9 +3674,6 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge, return; } - if (link_cfg->dsc_mode) - hdmi->frl_switch = false; - /* set avmute */ hdmi_writel(hdmi, 1, PKTSCHED_PKT_CONTROL0); mdelay(50); @@ -3708,7 +3692,7 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge, mutex_unlock(&hdmi->audio_mutex); }; - if (hdmi->phy.ops->disable && !hdmi->frl_switch) { + if (hdmi->phy.ops->disable) { hdmi_writel(hdmi, 0, FLT_CONFIG0); hdmi_writel(hdmi, 0, SCRAMB_CONFIG0); @@ -3756,7 +3740,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge, dw_hdmi_qp_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); - if ((link_cfg && !link_cfg->frl_mode) || hdmi->frl_switch) { + if (link_cfg && !link_cfg->frl_mode) { hdmi_writel(hdmi, 2, PKTSCHED_PKT_CONTROL0); hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); } diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 796c146c2555..820a3c24c209 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -82,6 +82,11 @@ struct platform_device; #define SUPPORT_HDMI_ALLM BIT(1) #define DOVI_VSIF_LEN 8 +#define HDMI_HDR_STATUS_CHANGED BIT(0) +#define HDMI_COLOR_FMT_CHANGED BIT(1) +#define HDMI_OUTPUT_MODE_CHANGED BIT(2) +#define HDMI_VSIF_CHANGED BIT(3) + enum { DW_HDMI_RES_8, DW_HDMI_RES_10,