Commit 7389829f authored by Imre Deak's avatar Imre Deak

drm/i915/dp: Store DSC DPCD capabilities in the connector

In an MST topology the DSC capabilities are specific to each connector,
retrieved either from the sink if it decompresses the stream, or from a
branch device between the source and the sink in case this branch device
does the decompression. Accordingly each connector needs to cache its
own DSC DPCD and FEC capabilities, along with the AUX device through
which the decompression can be enabled. This patch prepares for that by
storing the capabilities and the DSC AUX device in the connector, for
now these just matching the version stored in intel_dp. The follow-up
patches will convert all users to look up these in the connector instead
of intel_dp, after which the intel_dp copies are removed.

v2:
- Rebased on intel_edp_get_dsc_sink_cap() addition in previous patch.
v3:
- Rebased on read-out fix for eDP in previous patch.

Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231011171606.2540078-2-imre.deak@intel.com
parent 90780a63
......@@ -620,6 +620,12 @@ struct intel_connector {
struct intel_dp *mst_port;
struct {
struct drm_dp_aux *dsc_decompression_aux;
u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
u8 fec_capability;
} dp;
/* Work struct to schedule a uevent on link train failure */
struct work_struct modeset_retry_work;
......
......@@ -3483,7 +3483,8 @@ static void intel_dp_read_dsc_dpcd(struct drm_dp_aux *aux,
dsc_dpcd);
}
static void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, struct intel_dp *intel_dp)
static void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, struct intel_dp *intel_dp,
struct intel_connector *connector)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
......@@ -3491,32 +3492,46 @@ static void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, struct intel_dp *intel_dp)
* Clear the cached register set to avoid using stale values
* for the sinks that do not support DSC.
*/
memset(intel_dp->dsc_dpcd, 0, sizeof(intel_dp->dsc_dpcd));
memset(connector->dp.dsc_dpcd, 0, sizeof(connector->dp.dsc_dpcd));
/* Clear fec_capable to avoid using stale values */
intel_dp->fec_capable = 0;
connector->dp.fec_capability = 0;
if (dpcd_rev < DP_DPCD_REV_14)
return;
intel_dp_read_dsc_dpcd(&intel_dp->aux, intel_dp->dsc_dpcd);
intel_dp_read_dsc_dpcd(connector->dp.dsc_decompression_aux,
connector->dp.dsc_dpcd);
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_FEC_CAPABILITY,
&intel_dp->fec_capable) < 0) {
if (drm_dp_dpcd_readb(connector->dp.dsc_decompression_aux, DP_FEC_CAPABILITY,
&connector->dp.fec_capability) < 0) {
drm_err(&i915->drm, "Failed to read FEC DPCD register\n");
return;
}
drm_dbg_kms(&i915->drm, "FEC CAPABILITY: %x\n",
intel_dp->fec_capable);
connector->dp.fec_capability);
/*
* TODO: remove the following intel_dp copies once all users
* are converted to look up DSC DPCD/FEC capability via the
* connector.
*/
memcpy(intel_dp->dsc_dpcd, connector->dp.dsc_dpcd,
sizeof(intel_dp->dsc_dpcd));
intel_dp->fec_capable = connector->dp.fec_capability;
}
static void intel_edp_get_dsc_sink_cap(u8 edp_dpcd_rev, struct intel_dp *intel_dp)
static void intel_edp_get_dsc_sink_cap(u8 edp_dpcd_rev, struct intel_dp *intel_dp,
struct intel_connector *connector)
{
if (edp_dpcd_rev < DP_EDP_14)
return;
intel_dp_read_dsc_dpcd(&intel_dp->aux, intel_dp->dsc_dpcd);
intel_dp_read_dsc_dpcd(connector->dp.dsc_decompression_aux, connector->dp.dsc_dpcd);
memcpy(intel_dp->dsc_dpcd, connector->dp.dsc_dpcd,
sizeof(intel_dp->dsc_dpcd));
}
static void intel_edp_mso_mode_fixup(struct intel_connector *connector,
......@@ -3608,7 +3623,7 @@ static void intel_edp_mso_init(struct intel_dp *intel_dp)
}
static bool
intel_edp_init_dpcd(struct intel_dp *intel_dp)
intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector)
{
struct drm_i915_private *dev_priv =
to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
......@@ -3688,7 +3703,8 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
/* Read the eDP DSC DPCD registers */
if (HAS_DSC(dev_priv))
intel_edp_get_dsc_sink_cap(intel_dp->edp_dpcd[0],
intel_dp);
intel_dp,
connector);
/*
* If needed, program our source OUI so we can make various Intel-specific AUX services
......@@ -5357,7 +5373,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp)
}
static void
intel_dp_detect_dsc_caps(struct intel_dp *intel_dp)
intel_dp_detect_dsc_caps(struct intel_dp *intel_dp, struct intel_connector *connector)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
......@@ -5367,10 +5383,10 @@ intel_dp_detect_dsc_caps(struct intel_dp *intel_dp)
if (intel_dp_is_edp(intel_dp))
intel_edp_get_dsc_sink_cap(intel_dp->edp_dpcd[0],
intel_dp);
intel_dp, connector);
else
intel_dp_get_dsc_sink_cap(intel_dp->dpcd[DP_DPCD_REV],
intel_dp);
intel_dp, connector);
}
static int
......@@ -5379,7 +5395,9 @@ intel_dp_detect(struct drm_connector *connector,
bool force)
{
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector));
struct intel_connector *intel_connector =
to_intel_connector(connector);
struct intel_dp *intel_dp = intel_attached_dp(intel_connector);
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct intel_encoder *encoder = &dig_port->base;
enum drm_connector_status status;
......@@ -5402,7 +5420,12 @@ intel_dp_detect(struct drm_connector *connector,
if (status == connector_status_disconnected) {
memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
/*
* TODO: Remove clearing the DPCD in intel_dp, once all
* user are converted to using the DPCD in connector.
*/
memset(intel_dp->dsc_dpcd, 0, sizeof(intel_dp->dsc_dpcd));
memset(intel_connector->dp.dsc_dpcd, 0, sizeof(intel_connector->dp.dsc_dpcd));
if (intel_dp->is_mst) {
drm_dbg_kms(&dev_priv->drm,
......@@ -5417,7 +5440,7 @@ intel_dp_detect(struct drm_connector *connector,
goto out;
}
intel_dp_detect_dsc_caps(intel_dp);
intel_dp_detect_dsc_caps(intel_dp, intel_connector);
intel_dp_configure_mst(intel_dp);
......@@ -6002,7 +6025,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
intel_hpd_enable_detection(encoder);
/* Cache DPCD and EDID for edp. */
has_dpcd = intel_edp_init_dpcd(intel_dp);
has_dpcd = intel_edp_init_dpcd(intel_dp, intel_connector);
if (!has_dpcd) {
/* if this fails, presume the device is a ghost */
......@@ -6176,6 +6199,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
intel_dp->pps.active_pipe = vlv_active_pipe(intel_dp);
intel_dp_aux_init(intel_dp);
intel_connector->dp.dsc_decompression_aux = &intel_dp->aux;
drm_dbg_kms(&dev_priv->drm,
"Adding %s connector on [ENCODER:%d:%s]\n",
......
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