Commit 98025a62 authored by Nikola Cornij's avatar Nikola Cornij Committed by Lyude Paul

drm/dp_mst: Use Extended Base Receiver Capability DPCD space

[why]
DP 1.4a spec mandates that if DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT is
set, Extended Base Receiver Capability DPCD space must be used. Without
doing that, the three DPCD values that differ will be wrong, leading to
incorrect or limited functionality. MST link rate, for example, could
have a lower value. Also, Synaptics quirk wouldn't work out well when
Extended DPCD was not read, resulting in no DSC for such hubs.

[how]
Modify MST topology manager to use the values from Extended DPCD where
applicable.

To prevent regression on the sources that have a lower maximum link rate
capability than MAX_LINK_RATE from Extended DPCD, have the drivers
supply maximum lane count and rate at initialization time.

This also reverts commit 2dcab875 ("Revert drm/dp_mst: Retrieve
extended DPCD caps for topology manager"), brining the change back to the
original commit ad44c032 ("drm/dp_mst: Retrieve extended DPCD caps for
topology manager").
Signed-off-by: default avatarNikola Cornij <nikola.cornij@amd.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
Signed-off-by: default avatarLyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210429221151.22020-2-nikola.cornij@amd.com
parent 310e506c
...@@ -429,6 +429,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, ...@@ -429,6 +429,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
struct amdgpu_dm_connector *aconnector, struct amdgpu_dm_connector *aconnector,
int link_index) int link_index)
{ {
struct dc_link_settings max_link_enc_cap = {0};
aconnector->dm_dp_aux.aux.name = aconnector->dm_dp_aux.aux.name =
kasprintf(GFP_KERNEL, "AMDGPU DM aux hw bus %d", kasprintf(GFP_KERNEL, "AMDGPU DM aux hw bus %d",
link_index); link_index);
...@@ -443,6 +445,7 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, ...@@ -443,6 +445,7 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_eDP) if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_eDP)
return; return;
dc_link_dp_get_max_link_enc_cap(aconnector->dc_link, &max_link_enc_cap);
aconnector->mst_mgr.cbs = &dm_mst_cbs; aconnector->mst_mgr.cbs = &dm_mst_cbs;
drm_dp_mst_topology_mgr_init( drm_dp_mst_topology_mgr_init(
&aconnector->mst_mgr, &aconnector->mst_mgr,
...@@ -450,6 +453,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, ...@@ -450,6 +453,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
&aconnector->dm_dp_aux.aux, &aconnector->dm_dp_aux.aux,
16, 16,
4, 4,
(u8)max_link_enc_cap.lane_count,
(u8)max_link_enc_cap.link_rate,
aconnector->connector_id); aconnector->connector_id);
drm_connector_attach_dp_subconnector_property(&aconnector->base); drm_connector_attach_dp_subconnector_property(&aconnector->base);
......
...@@ -1894,6 +1894,24 @@ bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down) ...@@ -1894,6 +1894,24 @@ bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down)
return true; return true;
} }
bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap)
{
if (!max_link_enc_cap) {
DC_LOG_ERROR("%s: Could not return max link encoder caps", __func__);
return false;
}
if (link->link_enc->funcs->get_max_link_cap) {
link->link_enc->funcs->get_max_link_cap(link->link_enc, max_link_enc_cap);
return true;
}
DC_LOG_ERROR("%s: Max link encoder caps unknown", __func__);
max_link_enc_cap->lane_count = 1;
max_link_enc_cap->link_rate = 6;
return false;
}
static struct dc_link_settings get_max_link_cap(struct dc_link *link) static struct dc_link_settings get_max_link_cap(struct dc_link *link)
{ {
struct dc_link_settings max_link_cap = {0}; struct dc_link_settings max_link_cap = {0};
......
...@@ -346,6 +346,8 @@ bool dc_link_dp_set_test_pattern( ...@@ -346,6 +346,8 @@ bool dc_link_dp_set_test_pattern(
const unsigned char *p_custom_pattern, const unsigned char *p_custom_pattern,
unsigned int cust_pattern_size); unsigned int cust_pattern_size);
bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap);
void dc_link_enable_hpd_filter(struct dc_link *link, bool enable); void dc_link_enable_hpd_filter(struct dc_link *link, bool enable);
bool dc_link_is_dp_sink_present(struct dc_link *link); bool dc_link_is_dp_sink_present(struct dc_link *link);
......
...@@ -3708,19 +3708,24 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms ...@@ -3708,19 +3708,24 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
/* set the device into MST mode */ /* set the device into MST mode */
if (mst_state) { if (mst_state) {
struct drm_dp_payload reset_pay; struct drm_dp_payload reset_pay;
int lane_count;
int link_rate;
WARN_ON(mgr->mst_primary); WARN_ON(mgr->mst_primary);
/* get dpcd info */ /* get dpcd info */
ret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, mgr->dpcd, DP_RECEIVER_CAP_SIZE); ret = drm_dp_read_dpcd_caps(mgr->aux, mgr->dpcd);
if (ret != DP_RECEIVER_CAP_SIZE) { if (ret < 0) {
drm_dbg_kms(mgr->dev, "failed to read DPCD\n"); drm_dbg_kms(mgr->dev, "%s: failed to read DPCD, ret %d\n",
mgr->aux->name, ret);
goto out_unlock; goto out_unlock;
} }
lane_count = min_t(int, mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK, mgr->max_lane_count);
link_rate = min_t(int, mgr->dpcd[1], mgr->max_link_rate);
mgr->pbn_div = drm_dp_get_vc_payload_bw(mgr, mgr->pbn_div = drm_dp_get_vc_payload_bw(mgr,
drm_dp_bw_code_to_link_rate(mgr->dpcd[1]), drm_dp_bw_code_to_link_rate(link_rate),
mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK); lane_count);
if (mgr->pbn_div == 0) { if (mgr->pbn_div == 0) {
ret = -EINVAL; ret = -EINVAL;
goto out_unlock; goto out_unlock;
...@@ -5448,14 +5453,17 @@ EXPORT_SYMBOL(drm_atomic_get_mst_topology_state); ...@@ -5448,14 +5453,17 @@ EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
* @aux: DP helper aux channel to talk to this device * @aux: DP helper aux channel to talk to this device
* @max_dpcd_transaction_bytes: hw specific DPCD transaction limit * @max_dpcd_transaction_bytes: hw specific DPCD transaction limit
* @max_payloads: maximum number of payloads this GPU can source * @max_payloads: maximum number of payloads this GPU can source
* @max_lane_count: maximum number of lanes this GPU supports
* @max_link_rate: maximum link rate this GPU supports, units as in DPCD
* @conn_base_id: the connector object ID the MST device is connected to. * @conn_base_id: the connector object ID the MST device is connected to.
* *
* Return 0 for success, or negative error code on failure * Return 0 for success, or negative error code on failure
*/ */
int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
struct drm_device *dev, struct drm_dp_aux *aux, struct drm_device *dev, struct drm_dp_aux *aux,
int max_dpcd_transaction_bytes, int max_dpcd_transaction_bytes, int max_payloads,
int max_payloads, int conn_base_id) u8 max_lane_count, u8 max_link_rate,
int conn_base_id)
{ {
struct drm_dp_mst_topology_state *mst_state; struct drm_dp_mst_topology_state *mst_state;
...@@ -5490,6 +5498,8 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, ...@@ -5490,6 +5498,8 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
mgr->aux = aux; mgr->aux = aux;
mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes; mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes;
mgr->max_payloads = max_payloads; mgr->max_payloads = max_payloads;
mgr->max_lane_count = max_lane_count;
mgr->max_link_rate = max_link_rate;
mgr->conn_base_id = conn_base_id; mgr->conn_base_id = conn_base_id;
if (max_payloads + 1 > sizeof(mgr->payload_mask) * 8 || if (max_payloads + 1 > sizeof(mgr->payload_mask) * 8 ||
max_payloads + 1 > sizeof(mgr->vcpi_mask) * 8) max_payloads + 1 > sizeof(mgr->vcpi_mask) * 8)
...@@ -5896,14 +5906,13 @@ struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port) ...@@ -5896,14 +5906,13 @@ struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port)
if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) && if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) &&
port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 && port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 &&
port->parent == port->mgr->mst_primary) { port->parent == port->mgr->mst_primary) {
u8 downstreamport; u8 dpcd_ext[DP_RECEIVER_CAP_SIZE];
if (drm_dp_dpcd_read(&port->aux, DP_DOWNSTREAMPORT_PRESENT, if (drm_dp_read_dpcd_caps(port->mgr->aux, dpcd_ext) < 0)
&downstreamport, 1) < 0)
return NULL; return NULL;
if ((downstreamport & DP_DWN_STRM_PORT_PRESENT) && if ((dpcd_ext[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) &&
((downstreamport & DP_DWN_STRM_PORT_TYPE_MASK) ((dpcd_ext[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK)
!= DP_DWN_STRM_PORT_TYPE_ANALOG)) != DP_DWN_STRM_PORT_TYPE_ANALOG))
return port->mgr->aux; return port->mgr->aux;
} }
......
...@@ -942,6 +942,7 @@ intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_base_id) ...@@ -942,6 +942,7 @@ intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_base_id)
struct intel_dp *intel_dp = &dig_port->dp; struct intel_dp *intel_dp = &dig_port->dp;
enum port port = dig_port->base.port; enum port port = dig_port->base.port;
int ret; int ret;
int bios_max_link_rate;
if (!HAS_DP_MST(i915) || intel_dp_is_edp(intel_dp)) if (!HAS_DP_MST(i915) || intel_dp_is_edp(intel_dp))
return 0; return 0;
...@@ -956,8 +957,11 @@ intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_base_id) ...@@ -956,8 +957,11 @@ intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_base_id)
/* create encoders */ /* create encoders */
intel_dp_create_fake_mst_encoders(dig_port); intel_dp_create_fake_mst_encoders(dig_port);
bios_max_link_rate = intel_bios_dp_max_link_rate(&dig_port->base);
ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, &i915->drm, ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, &i915->drm,
&intel_dp->aux, 16, 3, conn_base_id); &intel_dp->aux, 16, 3,
(u8)dig_port->max_lanes,
(u8)(bios_max_link_rate / 27000), conn_base_id);
if (ret) if (ret)
return ret; return ret;
......
...@@ -1617,7 +1617,8 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max, ...@@ -1617,7 +1617,8 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max,
mstm->mgr.cbs = &nv50_mstm; mstm->mgr.cbs = &nv50_mstm;
ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev, aux, aux_max, ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev, aux, aux_max,
max_payloads, conn_base_id); (u8)max_payloads, outp->dcb->dpconf.link_nr,
(u8)outp->dcb->dpconf.link_bw, conn_base_id);
if (ret) if (ret)
return ret; return ret;
......
...@@ -629,13 +629,20 @@ int ...@@ -629,13 +629,20 @@ int
radeon_dp_mst_init(struct radeon_connector *radeon_connector) radeon_dp_mst_init(struct radeon_connector *radeon_connector)
{ {
struct drm_device *dev = radeon_connector->base.dev; struct drm_device *dev = radeon_connector->base.dev;
int max_link_rate;
if (!radeon_connector->ddc_bus->has_aux) if (!radeon_connector->ddc_bus->has_aux)
return 0; return 0;
if (radeon_connector_is_dp12_capable(&radeon_connector->base))
max_link_rate = 0x14;
else
max_link_rate = 0x0a;
radeon_connector->mst_mgr.cbs = &mst_cbs; radeon_connector->mst_mgr.cbs = &mst_cbs;
return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev, return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev,
&radeon_connector->ddc_bus->aux, 16, 6, &radeon_connector->ddc_bus->aux, 16, 6,
4, (u8)max_link_rate,
radeon_connector->base.base.id); radeon_connector->base.base.id);
} }
......
...@@ -593,6 +593,14 @@ struct drm_dp_mst_topology_mgr { ...@@ -593,6 +593,14 @@ struct drm_dp_mst_topology_mgr {
* @max_payloads: maximum number of payloads the GPU can generate. * @max_payloads: maximum number of payloads the GPU can generate.
*/ */
int max_payloads; int max_payloads;
/**
* @max_lane_count: maximum number of lanes the GPU can drive.
*/
u8 max_lane_count;
/**
* @max_link_rate: maximum link rate per lane GPU can output.
*/
u8 max_link_rate;
/** /**
* @conn_base_id: DRM connector ID this mgr is connected to. Only used * @conn_base_id: DRM connector ID this mgr is connected to. Only used
* to build the MST connector path value. * to build the MST connector path value.
...@@ -765,7 +773,9 @@ struct drm_dp_mst_topology_mgr { ...@@ -765,7 +773,9 @@ struct drm_dp_mst_topology_mgr {
int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
struct drm_device *dev, struct drm_dp_aux *aux, struct drm_device *dev, struct drm_dp_aux *aux,
int max_dpcd_transaction_bytes, int max_dpcd_transaction_bytes,
int max_payloads, int conn_base_id); int max_payloads,
u8 max_lane_count, u8 max_link_rate,
int conn_base_id);
void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr); void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment