From b318f175080ca98173d75fcf436beeee64092303 Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Fri, 17 Nov 2023 09:55:52 +0800 Subject: [PATCH] drm/bridge: synopsys: Support hdmi force output Support hdmi output specific resolution and color format regardless of whether hdmi is connected. Signed-off-by: Algea Cao Change-Id: I228a74d128aa818166f589798897729473d97610 --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 61 +++++++--- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 117 ++++++++++++++------ include/drm/bridge/dw_hdmi.h | 1 + 3 files changed, 130 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index e936d05102ae..619f08947a44 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -285,8 +285,9 @@ struct dw_hdmi { bool sink_has_audio; bool hpd_state; bool support_hdmi; - bool force_logo; - int force_output; + bool force_logo; /* force uboot hdmi output specific resolution */ + bool force_kernel_output; /* force kernel hdmi output specific resolution */ + int force_output; /* force hdmi/dvi output mode */ struct delayed_work work; struct workqueue_struct *workqueue; @@ -1786,6 +1787,9 @@ static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, if (hdmi->version < 0x200a) return false; + if (hdmi->force_kernel_output) + return true; + /* Disable if no DDC bus */ if (!hdmi->ddc) return false; @@ -2108,17 +2112,14 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, const struct drm_display_info *display, const struct drm_display_mode *mode) { - int i, ret; + int ret; - /* HDMI Phy spec says to do the phy initialization sequence twice */ - for (i = 0; i < 2; i++) { - dw_hdmi_phy_sel_data_en_pol(hdmi, 1); - dw_hdmi_phy_sel_interface_control(hdmi, 0); + dw_hdmi_phy_sel_data_en_pol(hdmi, 1); + dw_hdmi_phy_sel_interface_control(hdmi, 0); - ret = hdmi_phy_configure(hdmi, display); - if (ret) - return ret; - } + ret = hdmi_phy_configure(hdmi, display); + if (ret) + return ret; return 0; } @@ -3067,7 +3068,7 @@ static void dw_hdmi_update_power(struct dw_hdmi *hdmi) } if (force == DRM_FORCE_OFF) { - if (hdmi->initialized) { + if (hdmi->initialized && !hdmi->force_kernel_output) { hdmi->initialized = false; hdmi->disabled = true; hdmi->logo_plug_out = true; @@ -3112,6 +3113,9 @@ static enum drm_connector_status dw_hdmi_detect(struct dw_hdmi *hdmi) mutex_unlock(&hdmi->mutex); } + if (hdmi->force_kernel_output) + return connector_status_connected; + result = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); mutex_lock(&hdmi->mutex); if (result != hdmi->last_connector_result) { @@ -3206,6 +3210,22 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) void *data = hdmi->plat_data->phy_data; int i, ret = 0; + if (hdmi->force_kernel_output) { + mode = hdmi->plat_data->get_force_timing(data); + hdmi->support_hdmi = true; + hdmi->sink_is_hdmi = true; + hdmi->sink_has_audio = true; + mode = drm_mode_duplicate(connector->dev, mode); + drm_mode_debug_printmodeline(mode); + drm_mode_probed_add(connector, mode); + info->edid_hdmi_rgb444_dc_modes = 0; + info->edid_hdmi_ycbcr444_dc_modes = 0; + info->hdmi.y420_dc_modes = 0; + info->color_formats = 0; + + return 1; + } + memset(metedata, 0, sizeof(*metedata)); edid = dw_hdmi_get_edid(hdmi, connector); if (edid) { @@ -3408,7 +3428,8 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, drm_scdc_readb(hdmi->ddc, SCDC_TMDS_CONFIG, &val); /* if plug out before hdmi bind, reset hdmi */ - if (vmode->mtmdsclock >= 340000000 && !(val & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40)) + if (vmode->mtmdsclock >= 340000000 && !(val & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40) + && !hdmi->force_kernel_output) hdmi->logo_plug_out = true; } @@ -4077,6 +4098,9 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; enum drm_mode_status mode_status = MODE_OK; + if (hdmi->force_kernel_output) + return MODE_OK; + if (hdmi->next_bridge) return MODE_OK; @@ -4230,7 +4254,7 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense) { mutex_lock(&hdmi->mutex); - if (!hdmi->force && !hdmi->force_logo) { + if (!hdmi->force && !hdmi->force_logo && !hdmi->force_kernel_output) { /* * If the RX sense status indicates we're disconnected, * clear the software rxsense status. @@ -4795,6 +4819,12 @@ static int get_force_logo_property(struct dw_hdmi *hdmi) } of_node_put(route); + if (!of_device_is_available(route_hdmi)) { + dev_dbg(hdmi->dev, "route-hdmi is disabled\n"); + of_node_put(route_hdmi); + return 0; + } + hdmi->force_logo = of_property_read_bool(route_hdmi, "force-output"); @@ -5027,6 +5057,9 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, if (ret) goto err_iahb; + if (hdmi->plat_data->get_force_timing(hdmi->plat_data->phy_data)) + hdmi->force_kernel_output = true; + hdmi->logo_plug_out = false; hdmi->initialized = false; ret = hdmi_readb(hdmi, HDMI_PHY_STAT0); diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index b0c66938de76..d8e40cd75daa 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -25,6 +25,10 @@ #include #include +#include