diff options
author | Kuogee Hsieh <khsieh@codeaurora.org> | 2020-09-11 22:36:42 +0200 |
---|---|---|
committer | Rob Clark <robdclark@chromium.org> | 2020-09-15 19:54:34 +0200 |
commit | 8ede2ecc3e5ee327923f6e3cfe52761ce73607d1 (patch) | |
tree | 2c36060e4f032d16e90e1480f790c359b06f5350 /drivers/gpu/drm/msm/dp/dp_panel.c | |
parent | drm/msm/dp: Add Display Port HPD feature (diff) | |
download | linux-8ede2ecc3e5ee327923f6e3cfe52761ce73607d1.tar.xz linux-8ede2ecc3e5ee327923f6e3cfe52761ce73607d1.zip |
drm/msm/dp: Add DP compliance tests on Snapdragon Chipsets
add event thread to execute events serially from event queue. Also
timeout mode is supported which allow an event be deferred to be
executed at later time. Both link and phy compliant tests had been
done successfully.
Changes in v2:
-- Fix potential deadlock by removing redundant connect_mutex
-- Check and enable link clock during modeset
-- Drop unused code and fix function prototypes.
-- set sink power to normal operation state (D0) before DPCD read
Changes in v3:
-- push idle pattern at main link before timing generator off
-- add timeout handles for both connect and disconnect
Changes in v4:
-- add ST_SUSPEND_PENDING to handles suspend/modeset test operations
-- clear dp phy aux interrupt status when ERR_DPPHY_AUX error
-- send segment addr during edid read
-- clear bpp depth before MISC register write
Changes in v5:
-- add ST_SUSPENDED to fix crash at resume
Changes in v6:
-- at msm_dp_display_enable() do not return until resume_done to avoid
kms commit timeout
Signed-off-by: Kuogee Hsieh <khsieh@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@chromium.org>
Diffstat (limited to 'drivers/gpu/drm/msm/dp/dp_panel.c')
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_panel.c | 78 |
1 files changed, 51 insertions, 27 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 5ac4b017da8f..7cdf37c525d8 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -8,8 +8,6 @@ #include <drm/drm_connector.h> #include <drm/drm_edid.h> -#define DP_MAX_DS_PORT_COUNT 1 - struct dp_panel_private { struct device *dev; struct dp_panel dp_panel; @@ -23,26 +21,32 @@ struct dp_panel_private { static int dp_panel_read_dpcd(struct dp_panel *dp_panel) { int rc = 0; - size_t rlen; + size_t len; + ssize_t rlen; struct dp_panel_private *panel; struct dp_link_info *link_info; u8 *dpcd, major = 0, minor = 0, temp; - u32 dfp_count = 0, offset = DP_DPCD_REV; + u32 offset = DP_DPCD_REV; dpcd = dp_panel->dpcd; panel = container_of(dp_panel, struct dp_panel_private, dp_panel); link_info = &dp_panel->link_info; - rlen = drm_dp_dpcd_read(panel->aux, - DP_TRAINING_AUX_RD_INTERVAL, &temp, 1); - if (rlen < 0) { - DRM_ERROR("err reading DP_TRAINING_AUX_RD_INTERVAL,rlen=%zd\n", - rlen); - rc = -EINVAL; + rlen = drm_dp_dpcd_read(panel->aux, offset, + dpcd, (DP_RECEIVER_CAP_SIZE + 1)); + if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) { + DRM_ERROR("dpcd read failed, rlen=%zd\n", rlen); + if (rlen == -ETIMEDOUT) + rc = rlen; + else + rc = -EINVAL; + goto end; } + temp = dpcd[DP_TRAINING_AUX_RD_INTERVAL]; + /* check for EXTENDED_RECEIVER_CAPABILITY_FIELD_PRESENT */ if (temp & BIT(7)) { DRM_DEBUG_DP("using EXTENDED_RECEIVER_CAPABILITY_FIELD\n"); @@ -61,9 +65,6 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) goto end; } - print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DPCD: ", - DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false); - link_info->revision = dpcd[DP_DPCD_REV]; major = (link_info->revision >> 4) & 0x0f; minor = link_info->revision & 0x0f; @@ -85,14 +86,23 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) if (drm_dp_enhanced_frame_cap(dpcd)) link_info->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; - dfp_count = dpcd[DP_DOWN_STREAM_PORT_COUNT] & - DP_DOWN_STREAM_PORT_COUNT; + dp_panel->dfp_present = dpcd[DP_DOWNSTREAMPORT_PRESENT]; + dp_panel->dfp_present &= DP_DWN_STRM_PORT_PRESENT; - if (dfp_count > DP_MAX_DS_PORT_COUNT) { - DRM_ERROR("DS port count %d greater that max (%d) supported\n", - dfp_count, DP_MAX_DS_PORT_COUNT); - return -EINVAL; + if (dp_panel->dfp_present && (dpcd[DP_DPCD_REV] > 0x10)) { + dp_panel->ds_port_cnt = dpcd[DP_DOWN_STREAM_PORT_COUNT]; + dp_panel->ds_port_cnt &= DP_PORT_COUNT_MASK; + len = DP_DOWNSTREAM_PORTS * DP_DOWNSTREAM_CAP_SIZE; + + rlen = drm_dp_dpcd_read(panel->aux, + DP_DOWNSTREAM_PORT_0, dp_panel->ds_cap_info, len); + if (rlen < len) { + DRM_ERROR("ds port status failed, rlen=%zd\n", rlen); + rc = -EINVAL; + goto end; + } } + end: return rc; } @@ -185,6 +195,7 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel, struct drm_connector *connector) { int rc = 0, bw_code; + int rlen, count; struct dp_panel_private *panel; if (!dp_panel || !connector) { @@ -202,11 +213,19 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel, DRM_ERROR("read dpcd failed %d\n", rc); return rc; } - rc = drm_dp_read_desc(panel->aux, &dp_panel->desc, - drm_dp_is_branch(dp_panel->dpcd)); - if (rc) { - DRM_ERROR("read sink/branch descriptor failed %d\n", rc); - return rc; + + if (dp_panel->dfp_present) { + rlen = drm_dp_dpcd_read(panel->aux, DP_SINK_COUNT, + &count, 1); + if (rlen == 1) { + count = DP_GET_SINK_COUNT(count); + if (!count) { + DRM_ERROR("no downstream ports connected\n"); + panel->link->sink_count = 0; + rc = -ENOTCONN; + goto end; + } + } } kfree(dp_panel->edid); @@ -216,7 +235,12 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel, &panel->aux->ddc); if (!dp_panel->edid) { DRM_ERROR("panel edid read failed\n"); - return -EINVAL; + + /* fail safe edid */ + mutex_lock(&connector->dev->mode_config.mutex); + if (drm_add_modes_noedid(connector, 640, 480)) + drm_set_preferred_mode(connector, 640, 480); + mutex_unlock(&connector->dev->mode_config.mutex); } if (panel->aux_cfg_update_done) { @@ -231,8 +255,8 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel, } panel->aux_cfg_update_done = false; } - - return 0; +end: + return rc; } u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, |