From 9a139f87711c914dd10484234f02b522ddb57c40 Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Fri, 17 Nov 2023 09:55:52 +0800 Subject: [PATCH 1/3] 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 | 60 +++++++--- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 117 ++++++++++++++------ include/drm/bridge/dw_hdmi.h | 1 + 3 files changed, 129 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 3ac72c2bcb2c..1ff62d7612d2 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -284,8 +284,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; @@ -1665,6 +1666,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; @@ -1979,17 +1983,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; } @@ -2946,7 +2947,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; @@ -2991,6 +2992,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) { @@ -3085,6 +3089,21 @@ 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_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) { @@ -3286,7 +3305,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; } @@ -3955,6 +3975,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; @@ -4108,7 +4131,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. @@ -4673,6 +4696,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"); @@ -4854,6 +4883,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 3253cf215c5f..624c2442d237 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -24,6 +24,10 @@ #include #include +#include