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 <algea.cao@rock-chips.com>
This commit is contained in:
Algea Cao
2025-08-12 11:09:17 +08:00
committed by Tao Huang
parent c79104d972
commit 949befa2e7
2 changed files with 67 additions and 78 deletions

View File

@@ -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);
}

View File

@@ -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,