b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From 9ff3c9d6063c6464e243b85bbbbd03e2096a57c0 Mon Sep 17 00:00:00 2001 |
| 2 | From: Sandor Yu <Sandor.yu@nxp.com> |
| 3 | Date: Mon, 28 Oct 2019 17:07:06 +0800 |
| 4 | Subject: [PATCH] drm: mhdp: reset video mode after hdmi/dp cable plugin |
| 5 | |
| 6 | DP need setup link training, and HDMI need reset hdmi sink SCDC |
| 7 | status after cable reconnected. |
| 8 | Add video mode_set function when cable plugin. |
| 9 | Add 20ms/50ms delay for hdmi/dp to waite FW stable. |
| 10 | |
| 11 | Signed-off-by: Sandor Yu <Sandor.yu@nxp.com> |
| 12 | --- |
| 13 | drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 20 ++++---- |
| 14 | drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 63 ++++++++++++------------- |
| 15 | 2 files changed, 43 insertions(+), 40 deletions(-) |
| 16 | |
| 17 | --- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c |
| 18 | +++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c |
| 19 | @@ -108,19 +108,19 @@ static void dp_pixel_clk_reset(struct cd |
| 20 | cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val); |
| 21 | } |
| 22 | |
| 23 | -static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp, |
| 24 | - const struct drm_display_mode *mode) |
| 25 | +static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp) |
| 26 | { |
| 27 | u32 lane_mapping = mhdp->lane_mapping; |
| 28 | struct drm_dp_link *link = &mhdp->dp.link; |
| 29 | char linkid[6]; |
| 30 | int ret; |
| 31 | |
| 32 | - memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode)); |
| 33 | + cdns_mhdp_plat_call(mhdp, pclk_rate); |
| 34 | |
| 35 | - dp_pixel_clk_reset(mhdp); |
| 36 | + /* delay for DP FW stable after pixel clock relock */ |
| 37 | + msleep(50); |
| 38 | |
| 39 | - cdns_mhdp_plat_call(mhdp, pclk_rate); |
| 40 | + dp_pixel_clk_reset(mhdp); |
| 41 | |
| 42 | ret = drm_dp_downstream_id(&mhdp->dp.aux, linkid); |
| 43 | if (ret < 0) { |
| 44 | @@ -330,11 +330,10 @@ static void cdns_dp_bridge_mode_set(stru |
| 45 | video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); |
| 46 | |
| 47 | DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); |
| 48 | + memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode)); |
| 49 | |
| 50 | mutex_lock(&mhdp->lock); |
| 51 | - |
| 52 | - cdns_dp_mode_set(mhdp, mode); |
| 53 | - |
| 54 | + cdns_dp_mode_set(mhdp); |
| 55 | mutex_unlock(&mhdp->lock); |
| 56 | } |
| 57 | |
| 58 | @@ -367,6 +366,11 @@ static void hotplug_work_func(struct wor |
| 59 | drm_helper_hpd_irq_event(connector->dev); |
| 60 | |
| 61 | if (connector->status == connector_status_connected) { |
| 62 | + /* reset video mode after cable plugin */ |
| 63 | + mutex_lock(&mhdp->lock); |
| 64 | + cdns_dp_mode_set(mhdp); |
| 65 | + mutex_unlock(&mhdp->lock); |
| 66 | + |
| 67 | DRM_INFO("HDMI/DP Cable Plug In\n"); |
| 68 | enable_irq(mhdp->irq[IRQ_OUT]); |
| 69 | } else if (connector->status == connector_status_disconnected) { |
| 70 | --- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c |
| 71 | +++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c |
| 72 | @@ -11,11 +11,11 @@ |
| 73 | */ |
| 74 | #include <drm/bridge/cdns-mhdp-common.h> |
| 75 | #include <drm/drm_atomic_helper.h> |
| 76 | -#include <drm/drm_crtc_helper.h> |
| 77 | #include <drm/drm_edid.h> |
| 78 | #include <drm/drm_encoder_slave.h> |
| 79 | #include <drm/drm_of.h> |
| 80 | #include <drm/drm_probe_helper.h> |
| 81 | +#include <drm/drm_scdc_helper.h> |
| 82 | #include <drm/drmP.h> |
| 83 | #include <linux/delay.h> |
| 84 | #include <linux/err.h> |
| 85 | @@ -26,25 +26,30 @@ |
| 86 | #include <linux/mutex.h> |
| 87 | #include <linux/of_device.h> |
| 88 | |
| 89 | -static int hdmi_sink_config(struct cdns_mhdp_device *mhdp) |
| 90 | +static void hdmi_sink_config(struct cdns_mhdp_device *mhdp) |
| 91 | { |
| 92 | struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc; |
| 93 | u8 buff; |
| 94 | - int ret; |
| 95 | + |
| 96 | + /* check sink support SCDC or not */ |
| 97 | + if (scdc->supported != true) { |
| 98 | + DRM_INFO("Sink Not Support SCDC\n"); |
| 99 | + return; |
| 100 | + } |
| 101 | |
| 102 | if (mhdp->hdmi.char_rate > 340000) { |
| 103 | /* |
| 104 | * TMDS Character Rate above 340MHz should working in HDMI2.0 |
| 105 | * Enable scrambling and TMDS_Bit_Clock_Ratio |
| 106 | */ |
| 107 | - buff = 3; |
| 108 | + buff = SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE; |
| 109 | mhdp->hdmi.hdmi_type = MODE_HDMI_2_0; |
| 110 | } else if (scdc->scrambling.low_rates) { |
| 111 | /* |
| 112 | * Enable scrambling and HDMI2.0 when scrambling capability of sink |
| 113 | * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit |
| 114 | */ |
| 115 | - buff = 1; |
| 116 | + buff = SCDC_SCRAMBLING_ENABLE; |
| 117 | mhdp->hdmi.hdmi_type = MODE_HDMI_2_0; |
| 118 | } else { |
| 119 | /* Default work in HDMI1.4 */ |
| 120 | @@ -53,8 +58,7 @@ static int hdmi_sink_config(struct cdns_ |
| 121 | } |
| 122 | |
| 123 | /* TMDS config */ |
| 124 | - ret = cdns_hdmi_scdc_write(mhdp, 0x20, buff); |
| 125 | - return ret; |
| 126 | + cdns_hdmi_scdc_write(mhdp, 0x20, buff); |
| 127 | } |
| 128 | |
| 129 | static void hdmi_lanes_config(struct cdns_mhdp_device *mhdp) |
| 130 | @@ -142,7 +146,7 @@ static int hdmi_avi_info_set(struct cdns |
| 131 | return 0; |
| 132 | } |
| 133 | |
| 134 | -static int hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp, |
| 135 | +static void hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp, |
| 136 | struct drm_display_mode *mode) |
| 137 | { |
| 138 | struct hdmi_vendor_infoframe frame; |
| 139 | @@ -152,19 +156,18 @@ static int hdmi_vendor_info_set(struct c |
| 140 | /* Initialise vendor frame from DRM mode */ |
| 141 | ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode); |
| 142 | if (ret < 0) { |
| 143 | - DRM_WARN("Unable to init vendor infoframe: %d\n", ret); |
| 144 | - return -1; |
| 145 | + DRM_INFO("No vendor infoframe\n"); |
| 146 | + return; |
| 147 | } |
| 148 | |
| 149 | ret = hdmi_vendor_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1); |
| 150 | if (ret < 0) { |
| 151 | DRM_WARN("Unable to pack vendor infoframe: %d\n", ret); |
| 152 | - return -1; |
| 153 | + return; |
| 154 | } |
| 155 | |
| 156 | buf[0] = 0; |
| 157 | cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR); |
| 158 | - return 0; |
| 159 | } |
| 160 | |
| 161 | void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp) |
| 162 | @@ -172,9 +175,16 @@ void cdns_hdmi_mode_set(struct cdns_mhdp |
| 163 | struct drm_display_mode *mode = &mhdp->mode; |
| 164 | int ret; |
| 165 | |
| 166 | - ret = hdmi_sink_config(mhdp); |
| 167 | - if (ret < 0) |
| 168 | - DRM_DEBUG("%s failed\n", __func__); |
| 169 | + hdmi_lanes_config(mhdp); |
| 170 | + |
| 171 | + cdns_mhdp_plat_call(mhdp, pclk_rate); |
| 172 | + |
| 173 | + /* delay for HDMI FW stable after pixel clock relock */ |
| 174 | + msleep(20); |
| 175 | + |
| 176 | + cdns_mhdp_plat_call(mhdp, phy_set); |
| 177 | + |
| 178 | + hdmi_sink_config(mhdp); |
| 179 | |
| 180 | ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type, mhdp->hdmi.char_rate); |
| 181 | if (ret < 0) { |
| 182 | @@ -195,18 +205,13 @@ void cdns_hdmi_mode_set(struct cdns_mhdp |
| 183 | } |
| 184 | |
| 185 | /* vendor info frame is enable only when HDMI1.4 4K mode */ |
| 186 | - ret = hdmi_vendor_info_set(mhdp, mode); |
| 187 | - if (ret < 0) |
| 188 | - DRM_WARN("Unable to configure Vendor infoframe\n"); |
| 189 | + hdmi_vendor_info_set(mhdp, mode); |
| 190 | |
| 191 | ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info); |
| 192 | if (ret < 0) { |
| 193 | DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret); |
| 194 | return; |
| 195 | } |
| 196 | - |
| 197 | - /* wait HDMI PHY pixel clock stable */ |
| 198 | - msleep(50); |
| 199 | } |
| 200 | |
| 201 | static enum drm_connector_status |
| 202 | @@ -335,20 +340,11 @@ static void cdns_hdmi_bridge_mode_set(st |
| 203 | video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); |
| 204 | video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); |
| 205 | |
| 206 | - mutex_lock(&mhdp->lock); |
| 207 | - |
| 208 | DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); |
| 209 | - |
| 210 | memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode)); |
| 211 | |
| 212 | - hdmi_lanes_config(mhdp); |
| 213 | - |
| 214 | - cdns_mhdp_plat_call(mhdp, pclk_rate); |
| 215 | - |
| 216 | - cdns_mhdp_plat_call(mhdp, phy_set); |
| 217 | - |
| 218 | + mutex_lock(&mhdp->lock); |
| 219 | cdns_hdmi_mode_set(mhdp); |
| 220 | - |
| 221 | mutex_unlock(&mhdp->lock); |
| 222 | } |
| 223 | |
| 224 | @@ -367,8 +363,11 @@ static void hotplug_work_func(struct wor |
| 225 | drm_helper_hpd_irq_event(connector->dev); |
| 226 | |
| 227 | if (connector->status == connector_status_connected) { |
| 228 | - /* Cable Connected */ |
| 229 | DRM_INFO("HDMI Cable Plug In\n"); |
| 230 | + /* reset video mode after cable plugin */ |
| 231 | + mutex_lock(&mhdp->lock); |
| 232 | + cdns_hdmi_mode_set(mhdp); |
| 233 | + mutex_unlock(&mhdp->lock); |
| 234 | enable_irq(mhdp->irq[IRQ_OUT]); |
| 235 | } else if (connector->status == connector_status_disconnected) { |
| 236 | /* Cable Disconnedted */ |