Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/mediatek: Move DP training to hotplug thread

By adjusting the order of link training and relocating it to HPD,
link training can identify the usability of each lane in the current link.

It also supports handling signal instability and weakness due to
environmental issues, enabling the acquisition of a stable bandwidth
for the current link. Subsequently, DP work can proceed based on
the actual maximum bandwidth.

It should training in the hpd event thread.
Check the mode with lane count and link rate of training.

If we're eDP and capabilities were already parsed we can skip
reading again because eDP panels aren't hotpluggable hence the
caps and training information won't ever change in a boot life

Therefore, bridge typec judgment is required for edp training in
atomic_enable function.

`mtk_dp_parse_capabilities` is related to DP training, it is
used in `mtk_dp_hpd_event_thread` before DP training, and then only
used by eDP when read edid.

-Modify part of in `mtk_dp_bridge_atomic_disable`
if (mtk_dp->train_info.cable_plugged_in) {
drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
usleep_range(2000, 3000);
}

/* power off aux */
mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
DP_PWR_STATE_BANDGAP_TPLL,
DP_PWR_STATE_MASK);

-Modify part of in `mtk_dp_aux_panel_poweron(mtk_dp, false);`
if (pwron) {
....
} else {
/* power off panel */
drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
usleep_range(2000, 3000);

/* power off aux */
mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
DP_PWR_STATE_BANDGAP_TPLL,
DP_PWR_STATE_MASK);
}

The `mtk_dp_aux_panel_poweron` function fails to align.
Within the `mtk_dp_hpd_event_thread`, if DP is disconnected,
the `mtk_dp_aux_panel_poweron` function will write from `aux`
to `DPRX`, causing a failure and thus preventing symmetry.

This shows the current timings after the DP cable is plugged in,
as well as the modified timings.

current timings: Fix timings:

mtk_dp_hpd_event_thread() mtk_dp_hpd_event_thread()
(including DP link training)
| |
... ...
mtk_dp_bridge_mode_valid() mtk_dp_bridge_mode_valid()
|
... ...
mtk_dp_bridge_atomic_check() mtk_dp_bridge_atomic_check()
|
... ...
mtk_dp_bridge_atomic_enable() mtk_dp_bridge_atomic_enable()
(including DP link training)

PS:
1. "..." represents ommited steps;

2. `mtk_dp_bridge_mode_valid()` calculates the bandwidth using the
current lane count and link rate, and then filters each mode to
determine if it supports returning a status.

3. In the `drm_display_mode_to_videomode(&crtc_state->adjusted_mode,
&mtk_dp->info.vm);` function, within the `mtk_dp_bridge_atomic_check()`
function, `adjusted_mode` sets the currently selected display mode for
the DRM.

4. DP link training tests the signal conditions of the link between
DPTX and DPRX, and selects the lane count and link rate that meet
the signal conditions.

5. For example, the platform support DP 4lane 5.4G,
but panel A support DP 2lane 5.4G.

This is a time sequence:

a).Plug in panel A. According to the platform, it can output 4K60Hz.
b).Timing mode set 4K 60Hz(Including in mtk_dp_bridge_atomic_check
function).
c).Atomic enable(Based on panel A ability, training pass 2lane
5.4G).
d).Finally, due to 2lane 5.4G bandwidth limitation, the platform
cannot output 4K 60Hz, resulting in a black sreen.

If apply this patch.

a).Plug in panel A.
b).Training pass 2lane 5.4G
c).Timing mode set 2K 60Hz(Based on the 2lane 5.4G bandwidth limit
and including in mtk_dp_bridge_atomic_che

Signed-off-by: Liankun Yang <liankun.yang@mediatek.com>
Link: https://patchwork.kernel.org/project/dri-devel/patch/20251223061755.7717-1-liankun.yang@mediatek.com/
Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>

authored by

Liankun Yang and committed by
Chun-Kuang Hu
65155d16 f9c68b1c

+38 -19
+38 -19
drivers/gpu/drm/mediatek/mtk_dp.c
··· 1976 1976 struct mtk_dp *mtk_dp = dev; 1977 1977 unsigned long flags; 1978 1978 u32 status; 1979 + int ret; 1979 1980 1980 1981 if (mtk_dp->need_debounce && mtk_dp->train_info.cable_plugged_in) 1981 1982 msleep(100); ··· 1995 1994 memset(&mtk_dp->info.audio_cur_cfg, 0, 1996 1995 sizeof(mtk_dp->info.audio_cur_cfg)); 1997 1996 1997 + mtk_dp->enabled = false; 1998 + /* power off aux */ 1999 + mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, 2000 + DP_PWR_STATE_BANDGAP_TPLL, 2001 + DP_PWR_STATE_MASK); 2002 + 1998 2003 mtk_dp->need_debounce = false; 1999 2004 mod_timer(&mtk_dp->debounce_timer, 2000 2005 jiffies + msecs_to_jiffies(100) - 1); 2006 + } else { 2007 + mtk_dp_aux_panel_poweron(mtk_dp, true); 2008 + 2009 + ret = mtk_dp_parse_capabilities(mtk_dp); 2010 + if (ret) 2011 + drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n"); 2012 + 2013 + /* Training */ 2014 + ret = mtk_dp_training(mtk_dp); 2015 + if (ret) 2016 + drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret); 2017 + 2018 + mtk_dp->enabled = true; 2001 2019 } 2002 2020 } 2003 2021 ··· 2188 2168 * Parse capability here to let atomic_get_input_bus_fmts and 2189 2169 * mode_valid use the capability to calculate sink bitrates. 2190 2170 */ 2191 - if (mtk_dp_parse_capabilities(mtk_dp)) { 2171 + if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP && 2172 + mtk_dp_parse_capabilities(mtk_dp)) { 2192 2173 drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n"); 2193 2174 drm_edid_free(drm_edid); 2194 2175 drm_edid = NULL; ··· 2387 2366 return; 2388 2367 } 2389 2368 2390 - mtk_dp_aux_panel_poweron(mtk_dp, true); 2369 + if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) { 2370 + mtk_dp_aux_panel_poweron(mtk_dp, true); 2391 2371 2392 - /* Training */ 2393 - ret = mtk_dp_training(mtk_dp); 2394 - if (ret) { 2395 - drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret); 2396 - goto power_off_aux; 2372 + /* Training */ 2373 + ret = mtk_dp_training(mtk_dp); 2374 + if (ret) { 2375 + drm_err(mtk_dp->drm_dev, "Training failed, %d\n", ret); 2376 + goto power_off_aux; 2377 + } 2397 2378 } 2398 2379 2399 2380 ret = mtk_dp_video_config(mtk_dp); ··· 2415 2392 sizeof(mtk_dp->info.audio_cur_cfg)); 2416 2393 } 2417 2394 2418 - mtk_dp->enabled = true; 2395 + if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) 2396 + mtk_dp->enabled = true; 2397 + 2419 2398 mtk_dp_update_plugged_status(mtk_dp); 2420 2399 2421 2400 return; ··· 2432 2407 { 2433 2408 struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge); 2434 2409 2435 - mtk_dp->enabled = false; 2410 + if (mtk_dp->data->bridge_type == DRM_MODE_CONNECTOR_eDP) { 2411 + mtk_dp->enabled = false; 2412 + mtk_dp_aux_panel_poweron(mtk_dp, false); 2413 + } 2414 + 2436 2415 mtk_dp_update_plugged_status(mtk_dp); 2437 2416 mtk_dp_video_enable(mtk_dp, false); 2438 2417 mtk_dp_audio_mute(mtk_dp, true); 2439 - 2440 - if (mtk_dp->train_info.cable_plugged_in) { 2441 - drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3); 2442 - usleep_range(2000, 3000); 2443 - } 2444 - 2445 - /* power off aux */ 2446 - mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, 2447 - DP_PWR_STATE_BANDGAP_TPLL, 2448 - DP_PWR_STATE_MASK); 2449 2418 2450 2419 /* SDP path reset sw*/ 2451 2420 mtk_dp_sdp_path_reset(mtk_dp);