summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/dp/dp_panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/dp/dp_panel.c')
-rw-r--r--drivers/gpu/drm/msm/dp/dp_panel.c78
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,