2014-05-02 14:02:48 +10:00
|
|
|
/*
|
|
|
|
* Copyright © 2008 Intel Corporation
|
|
|
|
* 2014 Red Hat Inc.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
* Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2025-05-09 21:03:35 +03:00
|
|
|
#include <linux/log2.h>
|
|
|
|
#include <linux/math.h>
|
|
|
|
|
drm: Pass the full state to connectors atomic functions
The current atomic helpers have either their object state being passed as
an argument or the full atomic state.
The former is the pattern that was done at first, before switching to the
latter for new hooks or when it was needed.
Now that the CRTCs have been converted, let's move forward with the
connectors to provide a consistent interface.
The conversion was done using the coccinelle script below, and built tested
on all the drivers.
@@
identifier connector, connector_state;
@@
struct drm_connector_helper_funcs {
...
struct drm_encoder* (*atomic_best_encoder)(struct drm_connector *connector,
- struct drm_connector_state *connector_state);
+ struct drm_atomic_state *state);
...
}
@@
identifier connector, connector_state;
@@
struct drm_connector_helper_funcs {
...
void (*atomic_commit)(struct drm_connector *connector,
- struct drm_connector_state *connector_state);
+ struct drm_atomic_state *state);
...
}
@@
struct drm_connector_helper_funcs *FUNCS;
identifier state;
identifier connector, connector_state;
identifier f;
@@
f(..., struct drm_atomic_state *state, ...)
{
<+...
- FUNCS->atomic_commit(connector, connector_state);
+ FUNCS->atomic_commit(connector, state);
...+>
}
@@
struct drm_connector_helper_funcs *FUNCS;
identifier state;
identifier connector, connector_state;
identifier var, f;
@@
f(struct drm_atomic_state *state, ...)
{
<+...
- var = FUNCS->atomic_best_encoder(connector, connector_state);
+ var = FUNCS->atomic_best_encoder(connector, state);
...+>
}
@ connector_atomic_func @
identifier helpers;
identifier func;
@@
(
static struct drm_connector_helper_funcs helpers = {
...,
.atomic_best_encoder = func,
...,
};
|
static struct drm_connector_helper_funcs helpers = {
...,
.atomic_commit = func,
...,
};
)
@@
identifier connector_atomic_func.func;
identifier connector;
symbol state;
@@
func(struct drm_connector *connector,
- struct drm_connector_state *state
+ struct drm_connector_state *connector_state
)
{
...
- state
+ connector_state
...
}
@ ignores_state @
identifier connector_atomic_func.func;
identifier connector, connector_state;
@@
func(struct drm_connector *connector,
struct drm_connector_state *connector_state)
{
... when != connector_state
}
@ adds_state depends on connector_atomic_func && !ignores_state @
identifier connector_atomic_func.func;
identifier connector, connector_state;
@@
func(struct drm_connector *connector, struct drm_connector_state *connector_state)
{
+ struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state, connector);
...
}
@ depends on connector_atomic_func @
identifier connector_atomic_func.func;
identifier connector_state;
identifier connector;
@@
func(struct drm_connector *connector,
- struct drm_connector_state *connector_state
+ struct drm_atomic_state *state
)
{ ... }
@ include depends on adds_state @
@@
#include <drm/drm_atomic.h>
@ no_include depends on !include && adds_state @
@@
+ #include <drm/drm_atomic.h>
#include <drm/...>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Cc: Leo Li <sunpeng.li@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: "Christian König" <christian.koenig@amd.com>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Ben Skeggs <bskeggs@redhat.com>
Cc: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
Cc: Melissa Wen <melissa.srw@gmail.com>
Cc: Haneen Mohammed <hamohammed.sa@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20201118094758.506730-1-maxime@cerno.tech
2020-11-18 10:47:58 +01:00
|
|
|
#include <drm/drm_atomic.h>
|
2015-01-22 16:50:32 -08:00
|
|
|
#include <drm/drm_atomic_helper.h>
|
2014-05-02 14:02:48 +10:00
|
|
|
#include <drm/drm_edid.h>
|
2023-11-16 15:18:31 +02:00
|
|
|
#include <drm/drm_fixed.h>
|
2025-04-17 12:10:37 +03:00
|
|
|
#include <drm/drm_print.h>
|
2019-01-17 22:03:34 +01:00
|
|
|
#include <drm/drm_probe_helper.h>
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2025-04-17 12:10:37 +03:00
|
|
|
#include "i915_utils.h"
|
2019-04-29 15:53:31 +03:00
|
|
|
#include "intel_atomic.h"
|
2019-04-05 14:00:03 +03:00
|
|
|
#include "intel_audio.h"
|
2019-04-05 14:00:06 +03:00
|
|
|
#include "intel_connector.h"
|
2021-04-27 15:03:15 +03:00
|
|
|
#include "intel_crtc.h"
|
2019-04-05 14:00:05 +03:00
|
|
|
#include "intel_ddi.h"
|
2021-04-30 17:39:44 +03:00
|
|
|
#include "intel_de.h"
|
2024-01-04 10:30:05 +02:00
|
|
|
#include "intel_display_driver.h"
|
2025-06-06 13:22:56 +03:00
|
|
|
#include "intel_display_regs.h"
|
2019-08-06 14:39:33 +03:00
|
|
|
#include "intel_display_types.h"
|
2019-04-05 14:00:17 +03:00
|
|
|
#include "intel_dp.h"
|
2021-04-27 14:45:20 +03:00
|
|
|
#include "intel_dp_hdcp.h"
|
2024-09-20 14:56:43 +03:00
|
|
|
#include "intel_dp_link_training.h"
|
2019-04-29 15:29:33 +03:00
|
|
|
#include "intel_dp_mst.h"
|
2024-09-20 14:56:43 +03:00
|
|
|
#include "intel_dp_test.h"
|
2024-02-20 23:18:35 +02:00
|
|
|
#include "intel_dp_tunnel.h"
|
2019-05-02 18:02:40 +03:00
|
|
|
#include "intel_dpio_phy.h"
|
2020-08-18 11:39:05 -04:00
|
|
|
#include "intel_hdcp.h"
|
2021-04-27 14:45:20 +03:00
|
|
|
#include "intel_hotplug.h"
|
2023-10-24 04:09:23 +03:00
|
|
|
#include "intel_link_bw.h"
|
2025-02-26 12:01:08 +02:00
|
|
|
#include "intel_pfit.h"
|
2023-11-08 12:53:00 +05:30
|
|
|
#include "intel_psr.h"
|
2025-04-17 12:10:37 +03:00
|
|
|
#include "intel_step.h"
|
2023-11-02 21:44:34 +02:00
|
|
|
#include "intel_vdsc.h"
|
2025-03-24 19:02:34 +05:30
|
|
|
#include "intel_vrr.h"
|
2021-02-05 16:48:42 +02:00
|
|
|
#include "skl_scaler.h"
|
2019-04-05 14:00:03 +03:00
|
|
|
|
2024-11-25 17:19:33 +02:00
|
|
|
/*
|
|
|
|
* DP MST (DisplayPort Multi-Stream Transport)
|
|
|
|
*
|
|
|
|
* MST support on the source depends on the platform and port. DP initialization
|
|
|
|
* sets up MST for each MST capable encoder. This will become the primary
|
|
|
|
* encoder for the port.
|
|
|
|
*
|
|
|
|
* MST initialization of each primary encoder creates MST stream encoders, one
|
|
|
|
* per pipe, and initializes the MST topology manager. The MST stream encoders
|
|
|
|
* are sometimes called "fake encoders", because they're virtual, not
|
|
|
|
* physical. Thus there are (number of MST capable ports) x (number of pipes)
|
|
|
|
* MST stream encoders in total.
|
|
|
|
*
|
|
|
|
* Decision to use MST for a sink happens at detect on the connector attached to
|
|
|
|
* the primary encoder, and this will not change while the sink is connected. We
|
|
|
|
* always use MST when possible, including for SST sinks with sideband messaging
|
|
|
|
* support.
|
|
|
|
*
|
|
|
|
* The connectors for the MST streams are added and removed dynamically by the
|
|
|
|
* topology manager. Their connection status is also determined by the topology
|
|
|
|
* manager.
|
|
|
|
*
|
|
|
|
* On hardware, each transcoder may be associated with a single DDI
|
|
|
|
* port. Multiple transcoders may be associated with the same DDI port only if
|
|
|
|
* the port is in MST mode.
|
|
|
|
*
|
|
|
|
* On TGL+, all the transcoders streaming on the same DDI port will indicate a
|
|
|
|
* primary transcoder; the TGL_DP_TP_CTL and TGL_DP_TP_STATUS registers are
|
|
|
|
* relevant only on the primary transcoder. Prior to that, they are port
|
|
|
|
* registers.
|
|
|
|
*/
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
/* From fake MST stream encoder to primary encoder */
|
2024-11-12 13:10:39 +02:00
|
|
|
static struct intel_encoder *to_primary_encoder(struct intel_encoder *encoder)
|
|
|
|
{
|
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
|
|
|
struct intel_digital_port *dig_port = intel_mst->primary;
|
|
|
|
|
|
|
|
return &dig_port->base;
|
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
/* From fake MST stream encoder to primary DP */
|
2024-11-12 13:10:39 +02:00
|
|
|
static struct intel_dp *to_primary_dp(struct intel_encoder *encoder)
|
|
|
|
{
|
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
|
|
|
struct intel_digital_port *dig_port = intel_mst->primary;
|
|
|
|
|
|
|
|
return &dig_port->dp;
|
|
|
|
}
|
|
|
|
|
2025-04-04 18:03:08 +03:00
|
|
|
int intel_dp_mst_active_streams(struct intel_dp *intel_dp)
|
|
|
|
{
|
2025-04-04 18:03:10 +03:00
|
|
|
return intel_dp->mst.active_streams;
|
2025-04-04 18:03:08 +03:00
|
|
|
}
|
|
|
|
|
2025-04-04 18:03:06 +03:00
|
|
|
static bool intel_dp_mst_dec_active_streams(struct intel_dp *intel_dp)
|
|
|
|
{
|
|
|
|
struct intel_display *display = to_intel_display(intel_dp);
|
|
|
|
|
|
|
|
drm_dbg_kms(display->drm, "active MST streams %d -> %d\n",
|
2025-04-04 18:03:10 +03:00
|
|
|
intel_dp->mst.active_streams, intel_dp->mst.active_streams - 1);
|
2025-04-04 18:03:06 +03:00
|
|
|
|
2025-04-04 18:03:10 +03:00
|
|
|
if (drm_WARN_ON(display->drm, intel_dp->mst.active_streams == 0))
|
2025-04-04 18:03:06 +03:00
|
|
|
return true;
|
|
|
|
|
2025-04-04 18:03:10 +03:00
|
|
|
return --intel_dp->mst.active_streams == 0;
|
2025-04-04 18:03:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool intel_dp_mst_inc_active_streams(struct intel_dp *intel_dp)
|
|
|
|
{
|
|
|
|
struct intel_display *display = to_intel_display(intel_dp);
|
|
|
|
|
|
|
|
drm_dbg_kms(display->drm, "active MST streams %d -> %d\n",
|
2025-04-04 18:03:10 +03:00
|
|
|
intel_dp->mst.active_streams, intel_dp->mst.active_streams + 1);
|
2025-04-04 18:03:06 +03:00
|
|
|
|
2025-04-04 18:03:10 +03:00
|
|
|
return intel_dp->mst.active_streams++ == 0;
|
2025-04-04 18:03:06 +03:00
|
|
|
}
|
|
|
|
|
2025-05-09 21:03:35 +03:00
|
|
|
/* TODO: return a bpp_x16 value */
|
2024-04-17 01:10:05 +03:00
|
|
|
static int intel_dp_mst_max_dpt_bpp(const struct intel_crtc_state *crtc_state,
|
|
|
|
bool dsc)
|
2023-03-24 15:51:25 +02:00
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(crtc_state);
|
2024-04-17 01:10:05 +03:00
|
|
|
const struct drm_display_mode *adjusted_mode =
|
|
|
|
&crtc_state->hw.adjusted_mode;
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
if (!intel_dp_is_uhbr(crtc_state) || DISPLAY_VER(display) >= 20 || !dsc)
|
2025-02-04 17:37:17 +02:00
|
|
|
return 0;
|
2023-03-24 15:51:25 +02:00
|
|
|
|
2024-04-17 01:10:05 +03:00
|
|
|
/*
|
|
|
|
* DSC->DPT interface width:
|
|
|
|
* ICL-MTL: 72 bits (each branch has 72 bits, only left branch is used)
|
|
|
|
* LNL+: 144 bits (not a bottleneck in any config)
|
|
|
|
*
|
|
|
|
* Bspec/49259 suggests that the FEC overhead needs to be
|
|
|
|
* applied here, though HW people claim that neither this FEC
|
|
|
|
* or any other overhead is applicable here (that is the actual
|
|
|
|
* available_bw is just symbol_clock * 72). However based on
|
|
|
|
* testing on MTL-P the
|
|
|
|
* - DELL U3224KBA display
|
|
|
|
* - Unigraf UCD-500 CTS test sink
|
|
|
|
* devices the
|
|
|
|
* - 5120x2880/995.59Mhz
|
|
|
|
* - 6016x3384/1357.23Mhz
|
|
|
|
* - 6144x3456/1413.39Mhz
|
|
|
|
* modes (all the ones having a DPT limit on the above devices),
|
|
|
|
* both the channel coding efficiency and an additional 3%
|
|
|
|
* overhead needs to be accounted for.
|
|
|
|
*/
|
|
|
|
return div64_u64(mul_u32_u32(intel_dp_link_symbol_clock(crtc_state->port_clock) * 72,
|
|
|
|
drm_dp_bw_channel_coding_efficiency(true)),
|
|
|
|
mul_u32_u32(adjusted_mode->crtc_clock, 1030000));
|
2023-03-24 15:51:25 +02:00
|
|
|
}
|
|
|
|
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
static int intel_dp_mst_bw_overhead(const struct intel_crtc_state *crtc_state,
|
2024-10-09 14:01:34 +03:00
|
|
|
bool ssc, int dsc_slice_count, int bpp_x16)
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
{
|
|
|
|
const struct drm_display_mode *adjusted_mode =
|
|
|
|
&crtc_state->hw.adjusted_mode;
|
|
|
|
unsigned long flags = DRM_DP_BW_OVERHEAD_MST;
|
|
|
|
int overhead;
|
|
|
|
|
|
|
|
flags |= intel_dp_is_uhbr(crtc_state) ? DRM_DP_BW_OVERHEAD_UHBR : 0;
|
|
|
|
flags |= ssc ? DRM_DP_BW_OVERHEAD_SSC_REF_CLK : 0;
|
|
|
|
flags |= crtc_state->fec_enable ? DRM_DP_BW_OVERHEAD_FEC : 0;
|
|
|
|
|
2024-10-09 14:01:34 +03:00
|
|
|
if (dsc_slice_count)
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
flags |= DRM_DP_BW_OVERHEAD_DSC;
|
|
|
|
|
|
|
|
overhead = drm_dp_bw_overhead(crtc_state->lane_count,
|
|
|
|
adjusted_mode->hdisplay,
|
|
|
|
dsc_slice_count,
|
2023-11-10 15:40:12 +05:30
|
|
|
bpp_x16,
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
flags);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: clarify whether a minimum required by the fixed FEC overhead
|
|
|
|
* in the bspec audio programming sequence is required here.
|
|
|
|
*/
|
|
|
|
return max(overhead, intel_dp_bw_fec_overhead(crtc_state->fec_enable));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void intel_dp_mst_compute_m_n(const struct intel_crtc_state *crtc_state,
|
2023-11-16 15:18:37 +02:00
|
|
|
int overhead,
|
2023-11-10 15:40:12 +05:30
|
|
|
int bpp_x16,
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
struct intel_link_m_n *m_n)
|
|
|
|
{
|
|
|
|
const struct drm_display_mode *adjusted_mode =
|
|
|
|
&crtc_state->hw.adjusted_mode;
|
|
|
|
|
2023-11-17 17:09:29 +02:00
|
|
|
/* TODO: Check WA 14013163432 to set data M/N for full BW utilization. */
|
2023-11-10 15:40:12 +05:30
|
|
|
intel_link_compute_m_n(bpp_x16, crtc_state->lane_count,
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
adjusted_mode->crtc_clock,
|
|
|
|
crtc_state->port_clock,
|
|
|
|
overhead,
|
|
|
|
m_n);
|
|
|
|
|
|
|
|
m_n->tu = DIV_ROUND_UP_ULL(mul_u32_u32(m_n->data_m, 64), m_n->data_n);
|
|
|
|
}
|
|
|
|
|
2023-11-17 17:09:29 +02:00
|
|
|
static int intel_dp_mst_calc_pbn(int pixel_clock, int bpp_x16, int bw_overhead)
|
|
|
|
{
|
|
|
|
int effective_data_rate =
|
|
|
|
intel_dp_effective_data_rate(pixel_clock, bpp_x16, bw_overhead);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: Use drm_dp_calc_pbn_mode() instead, once it's converted
|
|
|
|
* to calculate PBN with the BW overhead passed to it.
|
|
|
|
*/
|
|
|
|
return DIV_ROUND_UP(effective_data_rate * 64, 54 * 1000);
|
|
|
|
}
|
|
|
|
|
2024-10-09 14:01:34 +03:00
|
|
|
static int intel_dp_mst_dsc_get_slice_count(const struct intel_connector *connector,
|
|
|
|
const struct intel_crtc_state *crtc_state)
|
|
|
|
{
|
|
|
|
const struct drm_display_mode *adjusted_mode =
|
|
|
|
&crtc_state->hw.adjusted_mode;
|
|
|
|
int num_joined_pipes = intel_crtc_num_joined_pipes(crtc_state);
|
|
|
|
|
|
|
|
return intel_dp_dsc_get_slice_count(connector,
|
|
|
|
adjusted_mode->clock,
|
|
|
|
adjusted_mode->hdisplay,
|
|
|
|
num_joined_pipes);
|
|
|
|
}
|
|
|
|
|
2025-05-09 21:03:31 +03:00
|
|
|
static void mst_stream_update_slots(const struct intel_crtc_state *crtc_state,
|
|
|
|
struct drm_dp_mst_topology_state *topology_state)
|
|
|
|
{
|
|
|
|
u8 link_coding_cap = intel_dp_is_uhbr(crtc_state) ?
|
|
|
|
DP_CAP_ANSI_128B132B : DP_CAP_ANSI_8B10B;
|
|
|
|
|
|
|
|
drm_dp_mst_update_slots(topology_state, link_coding_cap);
|
|
|
|
}
|
|
|
|
|
2025-01-03 15:52:29 +02:00
|
|
|
int intel_dp_mtp_tu_compute_config(struct intel_dp *intel_dp,
|
|
|
|
struct intel_crtc_state *crtc_state,
|
|
|
|
struct drm_connector_state *conn_state,
|
2025-01-31 14:50:07 +02:00
|
|
|
int min_bpp_x16, int max_bpp_x16, int bpp_step_x16, bool dsc)
|
2019-03-26 16:25:53 +02:00
|
|
|
{
|
2024-11-20 14:43:09 +02:00
|
|
|
struct intel_display *display = to_intel_display(intel_dp);
|
2019-10-31 12:26:03 +01:00
|
|
|
struct drm_atomic_state *state = crtc_state->uapi.state;
|
2025-01-29 16:46:36 +02:00
|
|
|
struct drm_dp_mst_topology_state *mst_state = NULL;
|
2019-03-26 16:25:53 +02:00
|
|
|
struct intel_connector *connector =
|
|
|
|
to_intel_connector(conn_state->connector);
|
|
|
|
const struct drm_display_mode *adjusted_mode =
|
2019-10-31 12:26:02 +01:00
|
|
|
&crtc_state->hw.adjusted_mode;
|
2025-05-07 18:19:53 +03:00
|
|
|
bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
|
2025-01-31 14:50:07 +02:00
|
|
|
int bpp_x16, slots = -EINVAL;
|
2024-10-09 14:01:34 +03:00
|
|
|
int dsc_slice_count = 0;
|
2025-01-31 14:50:07 +02:00
|
|
|
int max_dpt_bpp_x16;
|
|
|
|
|
|
|
|
/* shouldn't happen, sanity check */
|
|
|
|
drm_WARN_ON(display->drm, !dsc && (fxp_q4_to_frac(min_bpp_x16) ||
|
|
|
|
fxp_q4_to_frac(max_bpp_x16) ||
|
|
|
|
fxp_q4_to_frac(bpp_step_x16)));
|
2019-03-26 16:25:53 +02:00
|
|
|
|
2025-05-09 21:03:29 +03:00
|
|
|
if (!bpp_step_x16) {
|
|
|
|
/* Allow using zero step only to indicate single try for a given bpp. */
|
|
|
|
drm_WARN_ON(display->drm, min_bpp_x16 != max_bpp_x16);
|
|
|
|
bpp_step_x16 = 1;
|
|
|
|
}
|
|
|
|
|
2025-01-29 16:46:36 +02:00
|
|
|
if (is_mst) {
|
2025-02-28 14:49:29 +02:00
|
|
|
mst_state = drm_atomic_get_mst_topology_state(state, &intel_dp->mst.mgr);
|
2025-01-29 16:46:36 +02:00
|
|
|
if (IS_ERR(mst_state))
|
|
|
|
return PTR_ERR(mst_state);
|
|
|
|
|
|
|
|
mst_state->pbn_div = drm_dp_get_vc_payload_bw(crtc_state->port_clock,
|
|
|
|
crtc_state->lane_count);
|
2025-05-09 21:03:31 +03:00
|
|
|
|
|
|
|
mst_stream_update_slots(crtc_state, mst_state);
|
2025-01-29 16:46:36 +02:00
|
|
|
}
|
|
|
|
|
2023-10-24 04:09:05 +03:00
|
|
|
if (dsc) {
|
|
|
|
if (!intel_dp_supports_fec(intel_dp, connector, crtc_state))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
crtc_state->fec_enable = !intel_dp_is_uhbr(crtc_state);
|
|
|
|
}
|
|
|
|
|
2025-01-31 14:50:07 +02:00
|
|
|
max_dpt_bpp_x16 = fxp_q4_from_int(intel_dp_mst_max_dpt_bpp(crtc_state, dsc));
|
2025-02-04 17:37:17 +02:00
|
|
|
if (max_dpt_bpp_x16 && max_bpp_x16 > max_dpt_bpp_x16) {
|
2025-01-31 14:50:07 +02:00
|
|
|
drm_dbg_kms(display->drm, "Limiting bpp to max DPT bpp (" FXP_Q4_FMT " -> " FXP_Q4_FMT ")\n",
|
|
|
|
FXP_Q4_ARGS(max_bpp_x16), FXP_Q4_ARGS(max_dpt_bpp_x16));
|
|
|
|
max_bpp_x16 = max_dpt_bpp_x16;
|
2024-04-17 01:10:05 +03:00
|
|
|
}
|
|
|
|
|
2025-01-31 14:50:07 +02:00
|
|
|
drm_dbg_kms(display->drm, "Looking for slots in range min bpp " FXP_Q4_FMT " max bpp " FXP_Q4_FMT "\n",
|
|
|
|
FXP_Q4_ARGS(min_bpp_x16), FXP_Q4_ARGS(max_bpp_x16));
|
2023-10-24 04:09:25 +03:00
|
|
|
|
2024-10-09 14:01:34 +03:00
|
|
|
if (dsc) {
|
|
|
|
dsc_slice_count = intel_dp_mst_dsc_get_slice_count(connector, crtc_state);
|
|
|
|
if (!dsc_slice_count) {
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm, "Can't get valid DSC slice count\n");
|
2024-10-09 14:01:34 +03:00
|
|
|
|
|
|
|
return -ENOSPC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-09 21:03:35 +03:00
|
|
|
drm_WARN_ON(display->drm, min_bpp_x16 % bpp_step_x16 || max_bpp_x16 % bpp_step_x16);
|
|
|
|
|
2025-01-31 14:50:07 +02:00
|
|
|
for (bpp_x16 = max_bpp_x16; bpp_x16 >= min_bpp_x16; bpp_x16 -= bpp_step_x16) {
|
2023-11-16 15:18:37 +02:00
|
|
|
int local_bw_overhead;
|
|
|
|
int link_bpp_x16;
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
|
2025-01-31 14:50:07 +02:00
|
|
|
drm_dbg_kms(display->drm, "Trying bpp " FXP_Q4_FMT "\n", FXP_Q4_ARGS(bpp_x16));
|
2023-03-24 15:51:25 +02:00
|
|
|
|
2025-05-09 21:03:30 +03:00
|
|
|
if (dsc && !intel_dp_dsc_valid_compressed_bpp(intel_dp, bpp_x16)) {
|
|
|
|
/* SST must have validated the single bpp tried here already earlier. */
|
|
|
|
drm_WARN_ON(display->drm, !is_mst);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2025-01-31 14:50:07 +02:00
|
|
|
link_bpp_x16 = dsc ? bpp_x16 :
|
|
|
|
fxp_q4_from_int(intel_dp_output_bpp(crtc_state->output_format,
|
|
|
|
fxp_q4_to_int(bpp_x16)));
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
|
2025-01-03 15:52:25 +02:00
|
|
|
local_bw_overhead = intel_dp_mst_bw_overhead(crtc_state,
|
2024-10-09 14:01:34 +03:00
|
|
|
false, dsc_slice_count, link_bpp_x16);
|
2025-01-22 11:25:42 +05:30
|
|
|
|
2025-01-03 15:52:26 +02:00
|
|
|
intel_dp_mst_compute_m_n(crtc_state,
|
2023-11-16 15:18:37 +02:00
|
|
|
local_bw_overhead,
|
|
|
|
link_bpp_x16,
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
&crtc_state->dp_m_n);
|
2023-11-16 15:18:37 +02:00
|
|
|
|
2025-01-29 16:46:36 +02:00
|
|
|
if (is_mst) {
|
2025-01-03 15:52:30 +02:00
|
|
|
int remote_bw_overhead;
|
|
|
|
int remote_tu;
|
|
|
|
fixed20_12 pbn;
|
|
|
|
|
|
|
|
remote_bw_overhead = intel_dp_mst_bw_overhead(crtc_state,
|
|
|
|
true, dsc_slice_count, link_bpp_x16);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The TU size programmed to the HW determines which slots in
|
|
|
|
* an MTP frame are used for this stream, which needs to match
|
|
|
|
* the payload size programmed to the first downstream branch
|
|
|
|
* device's payload table.
|
|
|
|
*
|
|
|
|
* Note that atm the payload's PBN value DRM core sends via
|
|
|
|
* the ALLOCATE_PAYLOAD side-band message matches the payload
|
|
|
|
* size (which it calculates from the PBN value) it programs
|
|
|
|
* to the first branch device's payload table. The allocation
|
|
|
|
* in the payload table could be reduced though (to
|
|
|
|
* crtc_state->dp_m_n.tu), provided that the driver doesn't
|
|
|
|
* enable SSC on the corresponding link.
|
|
|
|
*/
|
|
|
|
pbn.full = dfixed_const(intel_dp_mst_calc_pbn(adjusted_mode->crtc_clock,
|
|
|
|
link_bpp_x16,
|
|
|
|
remote_bw_overhead));
|
2025-01-29 16:46:36 +02:00
|
|
|
remote_tu = DIV_ROUND_UP(pbn.full, mst_state->pbn_div.full);
|
2025-01-03 15:52:30 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Aligning the TUs ensures that symbols consisting of multiple
|
|
|
|
* (4) symbol cycles don't get split between two consecutive
|
|
|
|
* MTPs, as required by Bspec.
|
|
|
|
* TODO: remove the alignment restriction for 128b/132b links
|
|
|
|
* on some platforms, where Bspec allows this.
|
|
|
|
*/
|
|
|
|
remote_tu = ALIGN(remote_tu, 4 / crtc_state->lane_count);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Also align PBNs accordingly, since MST core will derive its
|
|
|
|
* own copy of TU from the PBN in drm_dp_atomic_find_time_slots().
|
|
|
|
* The above comment about the difference between the PBN
|
|
|
|
* allocated for the whole path and the TUs allocated for the
|
|
|
|
* first branch device's link also applies here.
|
|
|
|
*/
|
2025-01-29 16:46:36 +02:00
|
|
|
pbn.full = remote_tu * mst_state->pbn_div.full;
|
2025-01-03 15:52:30 +02:00
|
|
|
|
|
|
|
drm_WARN_ON(display->drm, remote_tu < crtc_state->dp_m_n.tu);
|
|
|
|
crtc_state->dp_m_n.tu = remote_tu;
|
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst.mgr,
|
2025-02-28 14:49:30 +02:00
|
|
|
connector->mst.port,
|
2025-01-03 15:52:30 +02:00
|
|
|
dfixed_trunc(pbn));
|
2025-05-09 21:03:32 +03:00
|
|
|
|
|
|
|
/* TODO: Check this already in drm_dp_atomic_find_time_slots(). */
|
|
|
|
if (slots > mst_state->total_avail_slots)
|
|
|
|
slots = -EINVAL;
|
2025-01-03 15:52:30 +02:00
|
|
|
} else {
|
|
|
|
/* Same as above for remote_tu */
|
|
|
|
crtc_state->dp_m_n.tu = ALIGN(crtc_state->dp_m_n.tu,
|
|
|
|
4 / crtc_state->lane_count);
|
|
|
|
|
|
|
|
if (crtc_state->dp_m_n.tu <= 64)
|
|
|
|
slots = crtc_state->dp_m_n.tu;
|
|
|
|
else
|
|
|
|
slots = -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-03-26 16:25:53 +02:00
|
|
|
if (slots == -EDEADLK)
|
|
|
|
return slots;
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2022-11-01 11:42:18 +02:00
|
|
|
if (slots >= 0) {
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_WARN_ON(display->drm, slots != crtc_state->dp_m_n.tu);
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
|
2023-10-24 04:09:24 +03:00
|
|
|
break;
|
2022-11-01 11:42:18 +02:00
|
|
|
}
|
2019-03-26 16:25:53 +02:00
|
|
|
}
|
|
|
|
|
2022-11-23 12:07:18 +02:00
|
|
|
if (slots < 0) {
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm, "failed finding vcpi slots:%d\n",
|
drm/i915/dp_mst: use struct drm_device based logging
Convert all the DRM_* logging macros to the struct drm_device based
macros to provide device specific logging.
No functional changes.
Generated using the following semantic patch, originally written by
Wambui Karuga <wambui.karugax@gmail.com>, with manual fixups on top:
@@
identifier fn, T;
@@
fn(...,struct drm_i915_private *T,...) {
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
@@
identifier fn, T;
@@
fn(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-DRM_INFO(
+drm_info(&T->drm,
...)
|
-DRM_NOTE(
+drm_notice(&T->drm,
...)
|
-DRM_ERROR(
+drm_err(&T->drm,
...)
|
-DRM_WARN(
+drm_warn(&T->drm,
...)
|
-DRM_DEBUG_DRIVER(
+drm_dbg(&T->drm,
...)
|
-DRM_DEBUG_KMS(
+drm_dbg_kms(&T->drm,
...)
|
-DRM_DEBUG_ATOMIC(
+drm_dbg_atomic(&T->drm,
...)
)
...+>
}
Cc: Wambui Karuga <wambui.karugax@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5ee3b8040658b5b4ef0b8b1a546fa04f554cdf6a.1584714939.git.jani.nikula@intel.com
2020-03-20 16:36:29 +02:00
|
|
|
slots);
|
2025-01-03 15:52:27 +02:00
|
|
|
return slots;
|
2022-11-23 12:07:18 +02:00
|
|
|
}
|
2022-11-01 11:42:19 +02:00
|
|
|
|
2025-01-03 15:52:27 +02:00
|
|
|
if (!dsc)
|
2025-01-31 14:50:07 +02:00
|
|
|
crtc_state->pipe_bpp = fxp_q4_to_int(bpp_x16);
|
2025-01-03 15:52:27 +02:00
|
|
|
else
|
2025-01-31 14:50:07 +02:00
|
|
|
crtc_state->dsc.compressed_bpp_x16 = bpp_x16;
|
2025-01-03 15:52:27 +02:00
|
|
|
|
2025-01-31 14:50:07 +02:00
|
|
|
drm_dbg_kms(display->drm, "Got %d slots for pipe bpp " FXP_Q4_FMT " dsc %d\n",
|
|
|
|
slots, FXP_Q4_ARGS(bpp_x16), dsc);
|
2025-01-03 15:52:27 +02:00
|
|
|
|
|
|
|
return 0;
|
2022-11-01 11:42:19 +02:00
|
|
|
}
|
|
|
|
|
2024-11-20 14:43:09 +02:00
|
|
|
static int mst_stream_compute_link_config(struct intel_dp *intel_dp,
|
2024-11-12 13:10:43 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
|
|
|
struct drm_connector_state *conn_state,
|
2025-01-29 16:46:33 +02:00
|
|
|
const struct link_config_limits *limits)
|
2022-11-01 11:42:19 +02:00
|
|
|
{
|
2025-01-29 16:46:35 +02:00
|
|
|
crtc_state->lane_count = limits->max_lane_count;
|
|
|
|
crtc_state->port_clock = limits->max_rate;
|
|
|
|
|
2023-09-21 22:51:57 +03:00
|
|
|
/*
|
|
|
|
* FIXME: allocate the BW according to link_bpp, which in the case of
|
|
|
|
* YUV420 is only half of the pipe bpp value.
|
|
|
|
*/
|
2025-01-29 16:46:37 +02:00
|
|
|
return intel_dp_mtp_tu_compute_config(intel_dp, crtc_state, conn_state,
|
2025-01-31 14:50:07 +02:00
|
|
|
limits->link.min_bpp_x16,
|
|
|
|
limits->link.max_bpp_x16,
|
|
|
|
fxp_q4_from_int(2 * 3), false);
|
2019-03-26 16:25:53 +02:00
|
|
|
}
|
|
|
|
|
2024-11-20 14:43:09 +02:00
|
|
|
static int mst_stream_dsc_compute_link_config(struct intel_dp *intel_dp,
|
2024-11-12 13:10:43 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
|
|
|
struct drm_connector_state *conn_state,
|
2025-01-29 16:46:33 +02:00
|
|
|
const struct link_config_limits *limits)
|
2022-11-01 11:42:20 +02:00
|
|
|
{
|
2024-11-20 14:43:09 +02:00
|
|
|
struct intel_display *display = to_intel_display(intel_dp);
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
2025-01-29 16:46:38 +02:00
|
|
|
int num_bpc;
|
2023-10-12 15:24:37 +03:00
|
|
|
u8 dsc_bpc[3] = {};
|
2022-11-23 12:07:18 +02:00
|
|
|
int min_bpp, max_bpp, sink_min_bpp, sink_max_bpp;
|
2025-05-09 21:03:35 +03:00
|
|
|
int min_compressed_bpp_x16, max_compressed_bpp_x16;
|
|
|
|
int bpp_step_x16;
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2024-12-17 15:02:40 +05:30
|
|
|
max_bpp = limits->pipe.max_bpp;
|
|
|
|
min_bpp = limits->pipe.min_bpp;
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2023-10-06 16:37:18 +03:00
|
|
|
num_bpc = drm_dp_dsc_sink_supported_input_bpcs(connector->dp.dsc_dpcd,
|
2022-11-01 11:42:20 +02:00
|
|
|
dsc_bpc);
|
2022-11-23 12:07:18 +02:00
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm, "DSC Source supported min bpp %d max bpp %d\n",
|
2022-11-23 12:07:18 +02:00
|
|
|
min_bpp, max_bpp);
|
|
|
|
|
2025-01-29 16:46:38 +02:00
|
|
|
sink_min_bpp = min_array(dsc_bpc, num_bpc) * 3;
|
|
|
|
sink_max_bpp = max_array(dsc_bpc, num_bpc) * 3;
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm, "DSC Sink supported min bpp %d max bpp %d\n",
|
2022-11-23 12:07:18 +02:00
|
|
|
sink_min_bpp, sink_max_bpp);
|
|
|
|
|
|
|
|
if (min_bpp < sink_min_bpp)
|
|
|
|
min_bpp = sink_min_bpp;
|
|
|
|
|
|
|
|
if (max_bpp > sink_max_bpp)
|
|
|
|
max_bpp = sink_max_bpp;
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2024-06-11 18:33:51 +03:00
|
|
|
crtc_state->pipe_bpp = max_bpp;
|
|
|
|
|
2025-05-09 21:03:35 +03:00
|
|
|
min_compressed_bpp_x16 = limits->link.min_bpp_x16;
|
|
|
|
max_compressed_bpp_x16 = limits->link.max_bpp_x16;
|
|
|
|
|
|
|
|
drm_dbg_kms(display->drm,
|
|
|
|
"DSC Sink supported compressed min bpp " FXP_Q4_FMT " compressed max bpp " FXP_Q4_FMT "\n",
|
|
|
|
FXP_Q4_ARGS(min_compressed_bpp_x16), FXP_Q4_ARGS(max_compressed_bpp_x16));
|
|
|
|
|
2025-05-09 21:03:39 +03:00
|
|
|
bpp_step_x16 = intel_dp_dsc_bpp_step_x16(connector);
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2025-05-09 21:03:35 +03:00
|
|
|
max_compressed_bpp_x16 = min(max_compressed_bpp_x16, fxp_q4_from_int(crtc_state->pipe_bpp) - bpp_step_x16);
|
2022-11-23 12:07:18 +02:00
|
|
|
|
2025-05-09 21:03:35 +03:00
|
|
|
drm_WARN_ON(display->drm, !is_power_of_2(bpp_step_x16));
|
|
|
|
min_compressed_bpp_x16 = round_up(min_compressed_bpp_x16, bpp_step_x16);
|
|
|
|
max_compressed_bpp_x16 = round_down(max_compressed_bpp_x16, bpp_step_x16);
|
2022-11-23 12:07:18 +02:00
|
|
|
|
2025-01-29 16:46:35 +02:00
|
|
|
crtc_state->lane_count = limits->max_lane_count;
|
|
|
|
crtc_state->port_clock = limits->max_rate;
|
|
|
|
|
2025-01-29 16:46:37 +02:00
|
|
|
return intel_dp_mtp_tu_compute_config(intel_dp, crtc_state, conn_state,
|
2025-05-09 21:03:35 +03:00
|
|
|
min_compressed_bpp_x16,
|
|
|
|
max_compressed_bpp_x16,
|
|
|
|
bpp_step_x16, true);
|
2022-11-01 11:42:20 +02:00
|
|
|
}
|
2024-11-12 13:10:43 +02:00
|
|
|
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
static int mode_hblank_period_ns(const struct drm_display_mode *mode)
|
|
|
|
{
|
|
|
|
return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(mode->htotal - mode->hdisplay,
|
|
|
|
NSEC_PER_SEC / 1000),
|
|
|
|
mode->crtc_clock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
hblank_expansion_quirk_needs_dsc(const struct intel_connector *connector,
|
2024-04-17 17:22:17 +03:00
|
|
|
const struct intel_crtc_state *crtc_state,
|
|
|
|
const struct link_config_limits *limits)
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
{
|
|
|
|
const struct drm_display_mode *adjusted_mode =
|
|
|
|
&crtc_state->hw.adjusted_mode;
|
2025-02-28 14:49:30 +02:00
|
|
|
bool is_uhbr_sink = connector->mst.dp &&
|
|
|
|
drm_dp_128b132b_supported(connector->mst.dp->dpcd);
|
2024-04-17 17:22:17 +03:00
|
|
|
int hblank_limit = is_uhbr_sink ? 500 : 300;
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
|
|
|
|
if (!connector->dp.dsc_hblank_expansion_quirk)
|
|
|
|
return false;
|
|
|
|
|
2024-04-17 17:22:17 +03:00
|
|
|
if (is_uhbr_sink && !drm_dp_is_uhbr_rate(limits->max_rate))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (mode_hblank_period_ns(adjusted_mode) > hblank_limit)
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
return false;
|
|
|
|
|
2024-10-09 14:01:35 +03:00
|
|
|
if (!intel_dp_mst_dsc_get_slice_count(connector, crtc_state))
|
|
|
|
return false;
|
|
|
|
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2024-12-17 15:02:31 +05:30
|
|
|
adjust_limits_for_dsc_hblank_expansion_quirk(struct intel_dp *intel_dp,
|
|
|
|
const struct intel_connector *connector,
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
const struct intel_crtc_state *crtc_state,
|
|
|
|
struct link_config_limits *limits,
|
|
|
|
bool dsc)
|
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(connector);
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
|
|
|
int min_bpp_x16 = limits->link.min_bpp_x16;
|
|
|
|
|
2024-04-17 17:22:17 +03:00
|
|
|
if (!hblank_expansion_quirk_needs_dsc(connector, crtc_state, limits))
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!dsc) {
|
2024-12-17 15:02:31 +05:30
|
|
|
if (intel_dp_supports_dsc(intel_dp, connector, crtc_state)) {
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm,
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
"[CRTC:%d:%s][CONNECTOR:%d:%s] DSC needed by hblank expansion quirk\n",
|
|
|
|
crtc->base.base.id, crtc->base.name,
|
|
|
|
connector->base.base.id, connector->base.name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm,
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
"[CRTC:%d:%s][CONNECTOR:%d:%s] Increasing link min bpp to 24 due to hblank expansion quirk\n",
|
|
|
|
crtc->base.base.id, crtc->base.name,
|
|
|
|
connector->base.base.id, connector->base.name);
|
|
|
|
|
2024-08-05 18:07:50 +03:00
|
|
|
if (limits->link.max_bpp_x16 < fxp_q4_from_int(24))
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
return false;
|
|
|
|
|
2024-08-05 18:07:50 +03:00
|
|
|
limits->link.min_bpp_x16 = fxp_q4_from_int(24);
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_WARN_ON(display->drm, limits->min_rate != limits->max_rate);
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
|
|
|
|
if (limits->max_rate < 540000)
|
2024-08-05 18:07:50 +03:00
|
|
|
min_bpp_x16 = fxp_q4_from_int(13);
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
else if (limits->max_rate < 810000)
|
2024-08-05 18:07:50 +03:00
|
|
|
min_bpp_x16 = fxp_q4_from_int(10);
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
|
|
|
|
if (limits->link.min_bpp_x16 >= min_bpp_x16)
|
|
|
|
return true;
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm,
|
2024-08-05 18:07:54 +03:00
|
|
|
"[CRTC:%d:%s][CONNECTOR:%d:%s] Increasing link min bpp to " FXP_Q4_FMT " in DSC mode due to hblank expansion quirk\n",
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
crtc->base.base.id, crtc->base.name,
|
|
|
|
connector->base.base.id, connector->base.name,
|
2024-08-05 18:07:54 +03:00
|
|
|
FXP_Q4_ARGS(min_bpp_x16));
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
|
|
|
|
if (limits->link.max_bpp_x16 < min_bpp_x16)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
limits->link.min_bpp_x16 = min_bpp_x16;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-09-21 22:51:52 +03:00
|
|
|
static bool
|
2024-11-12 13:10:43 +02:00
|
|
|
mst_stream_compute_config_limits(struct intel_dp *intel_dp,
|
2025-05-09 21:03:28 +03:00
|
|
|
struct intel_connector *connector,
|
2024-11-12 13:10:43 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
|
|
|
bool dsc,
|
|
|
|
struct link_config_limits *limits)
|
2023-09-21 22:51:49 +03:00
|
|
|
{
|
2025-05-09 21:03:28 +03:00
|
|
|
if (!intel_dp_compute_config_limits(intel_dp, connector,
|
|
|
|
crtc_state, false, dsc,
|
2024-12-11 16:43:10 +02:00
|
|
|
limits))
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
return false;
|
|
|
|
|
2024-12-17 15:02:31 +05:30
|
|
|
return adjust_limits_for_dsc_hblank_expansion_quirk(intel_dp,
|
|
|
|
connector,
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
crtc_state,
|
|
|
|
limits,
|
|
|
|
dsc);
|
2023-09-21 22:51:49 +03:00
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static int mst_stream_compute_config(struct intel_encoder *encoder,
|
|
|
|
struct intel_crtc_state *pipe_config,
|
|
|
|
struct drm_connector_state *conn_state)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(encoder);
|
2024-02-20 23:18:35 +02:00
|
|
|
struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
|
2024-04-09 19:35:02 +03:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
|
2024-11-12 13:10:39 +02:00
|
|
|
struct intel_dp *intel_dp = to_primary_dp(encoder);
|
2024-04-05 00:34:34 +03:00
|
|
|
struct intel_connector *connector =
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
to_intel_connector(conn_state->connector);
|
2019-03-26 16:25:53 +02:00
|
|
|
const struct drm_display_mode *adjusted_mode =
|
2019-10-31 12:26:02 +01:00
|
|
|
&pipe_config->hw.adjusted_mode;
|
2019-03-26 16:25:53 +02:00
|
|
|
struct link_config_limits limits;
|
2024-04-05 00:34:33 +03:00
|
|
|
bool dsc_needed, joiner_needs_dsc;
|
2024-09-16 15:58:34 +05:30
|
|
|
int num_joined_pipes;
|
2023-09-21 22:51:51 +03:00
|
|
|
int ret = 0;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2023-10-24 04:09:23 +03:00
|
|
|
if (pipe_config->fec_enable &&
|
|
|
|
!intel_dp_supports_fec(intel_dp, connector, pipe_config))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-05-24 15:54:03 +03:00
|
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
2019-01-15 15:08:00 -05:00
|
|
|
return -EINVAL;
|
2018-05-24 15:54:03 +03:00
|
|
|
|
2024-09-26 19:13:22 +05:30
|
|
|
num_joined_pipes = intel_dp_num_joined_pipes(intel_dp, connector,
|
|
|
|
adjusted_mode->crtc_hdisplay,
|
|
|
|
adjusted_mode->crtc_clock);
|
|
|
|
if (num_joined_pipes > 1)
|
|
|
|
pipe_config->joiner_pipes = GENMASK(crtc->pipe + num_joined_pipes - 1, crtc->pipe);
|
2024-09-16 15:58:34 +05:30
|
|
|
|
2023-04-27 18:26:00 +05:30
|
|
|
pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
|
2018-10-12 11:53:07 +05:30
|
|
|
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
|
2014-05-02 14:02:48 +10:00
|
|
|
pipe_config->has_pch_encoder = false;
|
2019-03-27 15:19:29 +02:00
|
|
|
|
2024-12-13 11:48:24 +02:00
|
|
|
joiner_needs_dsc = intel_dp_joiner_needs_dsc(display, num_joined_pipes);
|
2024-04-05 00:34:33 +03:00
|
|
|
|
|
|
|
dsc_needed = joiner_needs_dsc || intel_dp->force_dsc_en ||
|
2024-11-12 13:10:43 +02:00
|
|
|
!mst_stream_compute_config_limits(intel_dp, connector,
|
|
|
|
pipe_config, false, &limits);
|
2023-09-21 22:51:51 +03:00
|
|
|
|
|
|
|
if (!dsc_needed) {
|
2024-11-20 14:43:09 +02:00
|
|
|
ret = mst_stream_compute_link_config(intel_dp, pipe_config,
|
2024-11-12 13:10:43 +02:00
|
|
|
conn_state, &limits);
|
2023-09-21 22:51:51 +03:00
|
|
|
|
|
|
|
if (ret == -EDEADLK)
|
|
|
|
return ret;
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2023-09-21 22:51:51 +03:00
|
|
|
if (ret)
|
|
|
|
dsc_needed = true;
|
|
|
|
}
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2025-01-03 08:44:24 +05:30
|
|
|
if (dsc_needed && !intel_dp_supports_dsc(intel_dp, connector, pipe_config)) {
|
|
|
|
drm_dbg_kms(display->drm, "DSC required but not available\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2022-11-01 11:42:20 +02:00
|
|
|
/* enable compression if the mode doesn't fit available BW */
|
2023-09-21 22:51:51 +03:00
|
|
|
if (dsc_needed) {
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm, "Try DSC (fallback=%s, joiner=%s, force=%s)\n",
|
2024-04-05 00:34:33 +03:00
|
|
|
str_yes_no(ret), str_yes_no(joiner_needs_dsc),
|
2023-09-21 22:51:51 +03:00
|
|
|
str_yes_no(intel_dp->force_dsc_en));
|
|
|
|
|
2023-11-02 21:44:34 +02:00
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
if (!mst_stream_compute_config_limits(intel_dp, connector,
|
|
|
|
pipe_config, true,
|
|
|
|
&limits))
|
2023-09-21 22:51:52 +03:00
|
|
|
return -EINVAL;
|
|
|
|
|
2023-08-17 19:54:49 +05:30
|
|
|
/*
|
|
|
|
* FIXME: As bpc is hardcoded to 8, as mentioned above,
|
|
|
|
* WARN and ignore the debug flag force_dsc_bpc for now.
|
|
|
|
*/
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_WARN(display->drm, intel_dp->force_dsc_bpc,
|
|
|
|
"Cannot Force BPC for MST\n");
|
2022-11-01 11:42:20 +02:00
|
|
|
/*
|
|
|
|
* Try to get at least some timeslots and then see, if
|
|
|
|
* we can fit there with DSC.
|
|
|
|
*/
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm, "Trying to find VCPI slots in DSC mode\n");
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2024-11-20 14:43:09 +02:00
|
|
|
ret = mst_stream_dsc_compute_link_config(intel_dp, pipe_config,
|
2024-11-12 13:10:43 +02:00
|
|
|
conn_state, &limits);
|
2022-11-01 11:42:20 +02:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = intel_dp_dsc_compute_config(intel_dp, pipe_config,
|
|
|
|
conn_state, &limits,
|
2025-01-31 14:50:05 +02:00
|
|
|
pipe_config->dp_m_n.tu);
|
2022-11-01 11:42:20 +02:00
|
|
|
}
|
|
|
|
|
2022-02-08 17:23:17 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2019-03-26 16:25:51 +02:00
|
|
|
pipe_config->limited_color_range =
|
|
|
|
intel_dp_limited_color_range(pipe_config, conn_state);
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
if (display->platform.geminilake || display->platform.broxton)
|
2017-10-27 16:43:48 +03:00
|
|
|
pipe_config->lane_lat_optim_mask =
|
2024-04-12 20:58:16 +03:00
|
|
|
bxt_dpio_phy_calc_lane_lat_optim_mask(pipe_config->lane_count);
|
2017-10-27 16:43:48 +03:00
|
|
|
|
2025-04-24 20:45:15 +05:30
|
|
|
ret = intel_dp_compute_min_hblank(pipe_config, conn_state);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2025-03-24 19:02:34 +05:30
|
|
|
intel_vrr_compute_config(pipe_config, conn_state);
|
|
|
|
|
2023-08-22 23:48:18 +03:00
|
|
|
intel_dp_audio_compute_config(encoder, pipe_config, conn_state);
|
|
|
|
|
2023-11-28 13:51:38 +02:00
|
|
|
intel_ddi_compute_min_voltage_level(pipe_config);
|
2017-10-24 12:52:14 +03:00
|
|
|
|
2023-11-08 12:53:00 +05:30
|
|
|
intel_psr_compute_config(intel_dp, pipe_config, conn_state);
|
|
|
|
|
2024-02-20 23:18:35 +02:00
|
|
|
return intel_dp_tunnel_atomic_compute_stream_bw(state, intel_dp, connector,
|
|
|
|
pipe_config);
|
2020-03-13 18:48:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Iterate over all connectors and return a mask of
|
|
|
|
* all CPU transcoders streaming over the same DP link.
|
|
|
|
*/
|
|
|
|
static unsigned int
|
|
|
|
intel_dp_mst_transcoder_mask(struct intel_atomic_state *state,
|
|
|
|
struct intel_dp *mst_port)
|
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(state);
|
2020-03-13 18:48:19 +02:00
|
|
|
const struct intel_digital_connector_state *conn_state;
|
|
|
|
struct intel_connector *connector;
|
|
|
|
u8 transcoders = 0;
|
|
|
|
int i;
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
if (DISPLAY_VER(display) < 12)
|
2020-03-13 18:48:19 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
for_each_new_intel_connector_in_state(state, connector, conn_state, i) {
|
|
|
|
const struct intel_crtc_state *crtc_state;
|
|
|
|
struct intel_crtc *crtc;
|
|
|
|
|
2025-02-28 14:49:30 +02:00
|
|
|
if (connector->mst.dp != mst_port || !conn_state->base.crtc)
|
2020-03-13 18:48:19 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
crtc = to_intel_crtc(conn_state->base.crtc);
|
|
|
|
crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
|
|
|
|
|
|
|
|
if (!crtc_state->hw.active)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
transcoders |= BIT(crtc_state->cpu_transcoder);
|
|
|
|
}
|
|
|
|
|
|
|
|
return transcoders;
|
|
|
|
}
|
|
|
|
|
2023-10-24 04:09:23 +03:00
|
|
|
static u8 get_pipes_downstream_of_mst_port(struct intel_atomic_state *state,
|
|
|
|
struct drm_dp_mst_topology_mgr *mst_mgr,
|
|
|
|
struct drm_dp_mst_port *parent_port)
|
|
|
|
{
|
|
|
|
const struct intel_digital_connector_state *conn_state;
|
|
|
|
struct intel_connector *connector;
|
|
|
|
u8 mask = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for_each_new_intel_connector_in_state(state, connector, conn_state, i) {
|
|
|
|
if (!conn_state->base.crtc)
|
|
|
|
continue;
|
|
|
|
|
2025-02-28 14:49:30 +02:00
|
|
|
if (&connector->mst.dp->mst.mgr != mst_mgr)
|
2023-10-24 04:09:23 +03:00
|
|
|
continue;
|
|
|
|
|
2025-02-28 14:49:30 +02:00
|
|
|
if (connector->mst.port != parent_port &&
|
2023-10-24 04:09:23 +03:00
|
|
|
!drm_dp_mst_port_downstream_of_parent(mst_mgr,
|
2025-02-28 14:49:30 +02:00
|
|
|
connector->mst.port,
|
2023-10-24 04:09:23 +03:00
|
|
|
parent_port))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
mask |= BIT(to_intel_crtc(conn_state->base.crtc)->pipe);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_dp_mst_check_fec_change(struct intel_atomic_state *state,
|
|
|
|
struct drm_dp_mst_topology_mgr *mst_mgr,
|
|
|
|
struct intel_link_bw_limits *limits)
|
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(state);
|
2023-10-24 04:09:23 +03:00
|
|
|
struct intel_crtc *crtc;
|
|
|
|
u8 mst_pipe_mask;
|
|
|
|
u8 fec_pipe_mask = 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
mst_pipe_mask = get_pipes_downstream_of_mst_port(state, mst_mgr, NULL);
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
for_each_intel_crtc_in_pipe_mask(display->drm, crtc, mst_pipe_mask) {
|
2023-10-24 04:09:23 +03:00
|
|
|
struct intel_crtc_state *crtc_state =
|
|
|
|
intel_atomic_get_new_crtc_state(state, crtc);
|
|
|
|
|
|
|
|
/* Atomic connector check should've added all the MST CRTCs. */
|
2024-11-12 13:10:42 +02:00
|
|
|
if (drm_WARN_ON(display->drm, !crtc_state))
|
2023-10-24 04:09:23 +03:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (crtc_state->fec_enable)
|
|
|
|
fec_pipe_mask |= BIT(crtc->pipe);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fec_pipe_mask || mst_pipe_mask == fec_pipe_mask)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
limits->force_fec_pipes |= mst_pipe_mask;
|
|
|
|
|
|
|
|
ret = intel_modeset_pipes_in_mask_early(state, "MST FEC",
|
|
|
|
mst_pipe_mask);
|
|
|
|
|
|
|
|
return ret ? : -EAGAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_dp_mst_check_bw(struct intel_atomic_state *state,
|
|
|
|
struct drm_dp_mst_topology_mgr *mst_mgr,
|
|
|
|
struct drm_dp_mst_topology_state *mst_state,
|
|
|
|
struct intel_link_bw_limits *limits)
|
|
|
|
{
|
|
|
|
struct drm_dp_mst_port *mst_port;
|
|
|
|
u8 mst_port_pipes;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = drm_dp_mst_atomic_check_mgr(&state->base, mst_mgr, mst_state, &mst_port);
|
|
|
|
if (ret != -ENOSPC)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
mst_port_pipes = get_pipes_downstream_of_mst_port(state, mst_mgr, mst_port);
|
|
|
|
|
|
|
|
ret = intel_link_bw_reduce_bpp(state, limits,
|
|
|
|
mst_port_pipes, "MST link BW");
|
|
|
|
|
|
|
|
return ret ? : -EAGAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intel_dp_mst_atomic_check_link - check all modeset MST link configuration
|
|
|
|
* @state: intel atomic state
|
|
|
|
* @limits: link BW limits
|
|
|
|
*
|
|
|
|
* Check the link configuration for all modeset MST outputs. If the
|
|
|
|
* configuration is invalid @limits will be updated if possible to
|
|
|
|
* reduce the total BW, after which the configuration for all CRTCs in
|
|
|
|
* @state must be recomputed with the updated @limits.
|
|
|
|
*
|
|
|
|
* Returns:
|
2025-01-20 13:45:16 +05:30
|
|
|
* - 0 if the configuration is valid
|
2023-10-24 04:09:23 +03:00
|
|
|
* - %-EAGAIN, if the configuration is invalid and @limits got updated
|
|
|
|
* with fallback values with which the configuration of all CRTCs in
|
|
|
|
* @state must be recomputed
|
|
|
|
* - Other negative error, if the configuration is invalid without a
|
|
|
|
* fallback possibility, or the check failed for another reason
|
|
|
|
*/
|
|
|
|
int intel_dp_mst_atomic_check_link(struct intel_atomic_state *state,
|
|
|
|
struct intel_link_bw_limits *limits)
|
|
|
|
{
|
|
|
|
struct drm_dp_mst_topology_mgr *mgr;
|
|
|
|
struct drm_dp_mst_topology_state *mst_state;
|
|
|
|
int ret;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for_each_new_mst_mgr_in_state(&state->base, mgr, mst_state, i) {
|
|
|
|
ret = intel_dp_mst_check_fec_change(state, mgr, limits);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = intel_dp_mst_check_bw(state, mgr, mst_state,
|
|
|
|
limits);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static int mst_stream_compute_config_late(struct intel_encoder *encoder,
|
|
|
|
struct intel_crtc_state *crtc_state,
|
|
|
|
struct drm_connector_state *conn_state)
|
2020-03-13 18:48:19 +02:00
|
|
|
{
|
|
|
|
struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
|
2024-11-12 13:10:39 +02:00
|
|
|
struct intel_dp *intel_dp = to_primary_dp(encoder);
|
2020-03-13 18:48:19 +02:00
|
|
|
|
|
|
|
/* lowest numbered transcoder will be designated master */
|
|
|
|
crtc_state->mst_master_transcoder =
|
|
|
|
ffs(intel_dp_mst_transcoder_mask(state, intel_dp)) - 1;
|
2019-12-22 17:06:49 -08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If one of the connectors in a MST stream needs a modeset, mark all CRTCs
|
|
|
|
* that shares the same MST stream as mode changed,
|
|
|
|
* intel_modeset_pipe_config()+intel_crtc_check_fastset() will take care to do
|
|
|
|
* a fastset when possible.
|
2023-10-24 04:09:09 +03:00
|
|
|
*
|
|
|
|
* On TGL+ this is required since each stream go through a master transcoder,
|
|
|
|
* so if the master transcoder needs modeset, all other streams in the
|
|
|
|
* topology need a modeset. All platforms need to add the atomic state
|
|
|
|
* for all streams in the topology, since a modeset on one may require
|
|
|
|
* changing the MST link BW usage of the others, which in turn needs a
|
|
|
|
* recomputation of the corresponding CRTC states.
|
2019-12-22 17:06:49 -08:00
|
|
|
*/
|
|
|
|
static int
|
2024-11-20 14:43:10 +02:00
|
|
|
mst_connector_atomic_topology_check(struct intel_connector *connector,
|
|
|
|
struct intel_atomic_state *state)
|
2019-12-22 17:06:49 -08:00
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(connector);
|
2019-12-22 17:06:49 -08:00
|
|
|
struct drm_connector_list_iter connector_list_iter;
|
|
|
|
struct intel_connector *connector_iter;
|
2021-10-21 22:22:43 -04:00
|
|
|
int ret = 0;
|
2019-12-22 17:06:49 -08:00
|
|
|
|
|
|
|
if (!intel_connector_needs_modeset(state, &connector->base))
|
|
|
|
return 0;
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_connector_list_iter_begin(display->drm, &connector_list_iter);
|
2019-12-22 17:06:49 -08:00
|
|
|
for_each_intel_connector_iter(connector_iter, &connector_list_iter) {
|
|
|
|
struct intel_digital_connector_state *conn_iter_state;
|
|
|
|
struct intel_crtc_state *crtc_state;
|
|
|
|
struct intel_crtc *crtc;
|
|
|
|
|
2025-02-28 14:49:30 +02:00
|
|
|
if (connector_iter->mst.dp != connector->mst.dp ||
|
2019-12-22 17:06:49 -08:00
|
|
|
connector_iter == connector)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
conn_iter_state = intel_atomic_get_digital_connector_state(state,
|
|
|
|
connector_iter);
|
|
|
|
if (IS_ERR(conn_iter_state)) {
|
2021-10-21 22:22:43 -04:00
|
|
|
ret = PTR_ERR(conn_iter_state);
|
|
|
|
break;
|
2019-12-22 17:06:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!conn_iter_state->base.crtc)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
crtc = to_intel_crtc(conn_iter_state->base.crtc);
|
|
|
|
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
|
|
|
|
if (IS_ERR(crtc_state)) {
|
2021-10-21 22:22:43 -04:00
|
|
|
ret = PTR_ERR(crtc_state);
|
|
|
|
break;
|
2019-12-22 17:06:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
|
2021-10-21 22:22:43 -04:00
|
|
|
if (ret)
|
|
|
|
break;
|
2019-12-22 17:06:49 -08:00
|
|
|
crtc_state->uapi.mode_changed = true;
|
|
|
|
}
|
|
|
|
drm_connector_list_iter_end(&connector_list_iter);
|
|
|
|
|
2021-10-21 22:22:43 -04:00
|
|
|
return ret;
|
2017-04-28 16:14:20 -07:00
|
|
|
}
|
2014-05-02 14:02:48 +10:00
|
|
|
|
drm/dp_mst: Start tracking per-port VCPI allocations
There has been a TODO waiting for quite a long time in
drm_dp_mst_topology.c:
/* We cannot rely on port->vcpi.num_slots to update
* topology_state->avail_slots as the port may not exist if the parent
* branch device was unplugged. This should be fixed by tracking
* per-port slot allocation in drm_dp_mst_topology_state instead of
* depending on the caller to tell us how many slots to release.
*/
That's not the only reason we should fix this: forcing the driver to
track the VCPI allocations throughout a state's atomic check is
error prone, because it means that extra care has to be taken with the
order that drm_dp_atomic_find_vcpi_slots() and
drm_dp_atomic_release_vcpi_slots() are called in in order to ensure
idempotency. Currently the only driver actually using these helpers,
i915, doesn't even do this correctly: multiple ->best_encoder() checks
with i915's current implementation would not be idempotent and would
over-allocate VCPI slots, something I learned trying to implement
fallback retraining in MST.
So: simplify this whole mess, and teach drm_dp_atomic_find_vcpi_slots()
and drm_dp_atomic_release_vcpi_slots() to track the VCPI allocations for
each port. This allows us to ensure idempotency without having to rely
on the driver as much. Additionally: the driver doesn't need to do any
kind of VCPI slot tracking anymore if it doesn't need it for it's own
internal state.
Additionally; this adds a new drm_dp_mst_atomic_check() helper which
must be used by atomic drivers to perform validity checks for the new
VCPI allocations incurred by a state.
Also: update the documentation and make it more obvious that these
/must/ be called by /all/ atomic drivers supporting MST.
Changes since v9:
* Add some missing changes that were requested by danvet that I forgot
about after I redid all of the kref stuff:
* Remove unnecessary state changes in intel_dp_mst_atomic_check
* Cleanup atomic check logic for VCPI allocations - all we need to check in
compute_config is whether or not this state disables a CRTC, then free
VCPI based off that
Changes since v8:
* Fix compile errors, whoops!
Changes since v7:
- Don't check for mixed stale/valid VCPI allocations, just rely on
connector registration to stop such erroneous modesets
Changes since v6:
- Keep a kref to all of the ports we have allocations on. This required
a good bit of changing to when we call drm_dp_find_vcpi_slots(),
mainly that we need to ensure that we only redo VCPI allocations on
actual mode or CRTC changes, not crtc_state->active changes.
Additionally, we no longer take the registration of the DRM connector
for each port into account because so long as we have a kref to the
port in the new or previous atomic state, the connector will stay
registered.
- Use the small changes to drm_dp_put_port() to add even more error
checking to make misusage of the helpers more obvious. I added this
after having to chase down various use-after-free conditions that
started popping up from the new helpers so no one else has to
troubleshoot that.
- Move some accidental DRM_DEBUG_KMS() calls to DRM_DEBUG_ATOMIC()
- Update documentation again, note that find/release() should both not be
called on the same port in a single atomic check phase (but multiple
calls to one or the other is OK)
Changes since v4:
- Don't skip the atomic checks for VCPI allocations if no new VCPI
allocations happen in a state. This makes the next change I'm about
to list here a lot easier to implement.
- Don't ignore VCPI allocations on destroyed ports, instead ensure that
when ports are destroyed and still have VCPI allocations in the
topology state, the only state changes allowed are releasing said
ports' VCPI. This prevents a state with a mix of VCPI allocations
from destroyed ports, and allocations from valid ports.
Changes since v3:
- Don't release VCPI allocations in the topology state immediately in
drm_dp_atomic_release_vcpi_slots(), instead mark them as 0 and skip
over them in drm_dp_mst_duplicate_state(). This makes it so
drm_dp_atomic_release_vcpi_slots() is still idempotent while also
throwing warnings if the driver messes up it's book keeping and tries
to release VCPI slots on a port that doesn't have any pre-existing
VCPI allocation - danvet
- Change mst_state/state in some debugging messages to "mst state"
Changes since v2:
- Use kmemdup() for duplicating MST state - danvet
- Move port validation out of duplicate state callback - danvet
- Handle looping through MST topology states in
drm_dp_mst_atomic_check() so the driver doesn't have to do it
- Fix documentation in drm_dp_atomic_find_vcpi_slots()
- Move the atomic check for each individual topology state into it's
own function, reduces indenting
- Don't consider "stale" MST ports when calculating the bandwidth
requirements. This is needed because originally we relied on the
state duplication functions to prune any stale ports from the new
state, which would prevent us from incorrectly considering their
bandwidth requirements alongside legitimate new payloads.
- Add function references in drm_dp_atomic_release_vcpi_slots() - danvet
- Annotate atomic VCPI and atomic check functions with __must_check
- danvet
Changes since v1:
- Don't use the now-removed ->atomic_check() for private objects hook,
just give drivers a function to call themselves
Signed-off-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Jerry Zuo <Jerry.Zuo@amd.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Juston Li <juston.li@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com
2019-01-10 19:53:41 -05:00
|
|
|
static int
|
2025-01-08 17:19:13 +02:00
|
|
|
mst_connector_atomic_check(struct drm_connector *_connector,
|
2024-11-20 14:43:10 +02:00
|
|
|
struct drm_atomic_state *_state)
|
2017-04-28 16:14:20 -07:00
|
|
|
{
|
2019-12-22 17:06:49 -08:00
|
|
|
struct intel_atomic_state *state = to_intel_atomic_state(_state);
|
2025-01-08 17:19:13 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(_connector);
|
2019-03-26 16:25:51 +02:00
|
|
|
int ret;
|
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
ret = intel_digital_connector_atomic_check(&connector->base, &state->base);
|
2019-12-22 17:06:49 -08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
ret = mst_connector_atomic_topology_check(connector, state);
|
2019-03-26 16:25:51 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
drm/dp_mst: Start tracking per-port VCPI allocations
There has been a TODO waiting for quite a long time in
drm_dp_mst_topology.c:
/* We cannot rely on port->vcpi.num_slots to update
* topology_state->avail_slots as the port may not exist if the parent
* branch device was unplugged. This should be fixed by tracking
* per-port slot allocation in drm_dp_mst_topology_state instead of
* depending on the caller to tell us how many slots to release.
*/
That's not the only reason we should fix this: forcing the driver to
track the VCPI allocations throughout a state's atomic check is
error prone, because it means that extra care has to be taken with the
order that drm_dp_atomic_find_vcpi_slots() and
drm_dp_atomic_release_vcpi_slots() are called in in order to ensure
idempotency. Currently the only driver actually using these helpers,
i915, doesn't even do this correctly: multiple ->best_encoder() checks
with i915's current implementation would not be idempotent and would
over-allocate VCPI slots, something I learned trying to implement
fallback retraining in MST.
So: simplify this whole mess, and teach drm_dp_atomic_find_vcpi_slots()
and drm_dp_atomic_release_vcpi_slots() to track the VCPI allocations for
each port. This allows us to ensure idempotency without having to rely
on the driver as much. Additionally: the driver doesn't need to do any
kind of VCPI slot tracking anymore if it doesn't need it for it's own
internal state.
Additionally; this adds a new drm_dp_mst_atomic_check() helper which
must be used by atomic drivers to perform validity checks for the new
VCPI allocations incurred by a state.
Also: update the documentation and make it more obvious that these
/must/ be called by /all/ atomic drivers supporting MST.
Changes since v9:
* Add some missing changes that were requested by danvet that I forgot
about after I redid all of the kref stuff:
* Remove unnecessary state changes in intel_dp_mst_atomic_check
* Cleanup atomic check logic for VCPI allocations - all we need to check in
compute_config is whether or not this state disables a CRTC, then free
VCPI based off that
Changes since v8:
* Fix compile errors, whoops!
Changes since v7:
- Don't check for mixed stale/valid VCPI allocations, just rely on
connector registration to stop such erroneous modesets
Changes since v6:
- Keep a kref to all of the ports we have allocations on. This required
a good bit of changing to when we call drm_dp_find_vcpi_slots(),
mainly that we need to ensure that we only redo VCPI allocations on
actual mode or CRTC changes, not crtc_state->active changes.
Additionally, we no longer take the registration of the DRM connector
for each port into account because so long as we have a kref to the
port in the new or previous atomic state, the connector will stay
registered.
- Use the small changes to drm_dp_put_port() to add even more error
checking to make misusage of the helpers more obvious. I added this
after having to chase down various use-after-free conditions that
started popping up from the new helpers so no one else has to
troubleshoot that.
- Move some accidental DRM_DEBUG_KMS() calls to DRM_DEBUG_ATOMIC()
- Update documentation again, note that find/release() should both not be
called on the same port in a single atomic check phase (but multiple
calls to one or the other is OK)
Changes since v4:
- Don't skip the atomic checks for VCPI allocations if no new VCPI
allocations happen in a state. This makes the next change I'm about
to list here a lot easier to implement.
- Don't ignore VCPI allocations on destroyed ports, instead ensure that
when ports are destroyed and still have VCPI allocations in the
topology state, the only state changes allowed are releasing said
ports' VCPI. This prevents a state with a mix of VCPI allocations
from destroyed ports, and allocations from valid ports.
Changes since v3:
- Don't release VCPI allocations in the topology state immediately in
drm_dp_atomic_release_vcpi_slots(), instead mark them as 0 and skip
over them in drm_dp_mst_duplicate_state(). This makes it so
drm_dp_atomic_release_vcpi_slots() is still idempotent while also
throwing warnings if the driver messes up it's book keeping and tries
to release VCPI slots on a port that doesn't have any pre-existing
VCPI allocation - danvet
- Change mst_state/state in some debugging messages to "mst state"
Changes since v2:
- Use kmemdup() for duplicating MST state - danvet
- Move port validation out of duplicate state callback - danvet
- Handle looping through MST topology states in
drm_dp_mst_atomic_check() so the driver doesn't have to do it
- Fix documentation in drm_dp_atomic_find_vcpi_slots()
- Move the atomic check for each individual topology state into it's
own function, reduces indenting
- Don't consider "stale" MST ports when calculating the bandwidth
requirements. This is needed because originally we relied on the
state duplication functions to prune any stale ports from the new
state, which would prevent us from incorrectly considering their
bandwidth requirements alongside legitimate new payloads.
- Add function references in drm_dp_atomic_release_vcpi_slots() - danvet
- Annotate atomic VCPI and atomic check functions with __must_check
- danvet
Changes since v1:
- Don't use the now-removed ->atomic_check() for private objects hook,
just give drivers a function to call themselves
Signed-off-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Jerry Zuo <Jerry.Zuo@amd.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Juston Li <juston.li@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190111005343.17443-19-lyude@redhat.com
2019-01-10 19:53:41 -05:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
if (intel_connector_needs_modeset(state, &connector->base)) {
|
2024-02-20 23:18:35 +02:00
|
|
|
ret = intel_dp_tunnel_atomic_check_state(state,
|
2025-02-28 14:49:30 +02:00
|
|
|
connector->mst.dp,
|
2025-01-08 17:19:13 +02:00
|
|
|
connector);
|
2024-02-20 23:18:35 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-09-01 19:19:33 +03:00
|
|
|
return drm_dp_atomic_release_time_slots(&state->base,
|
2025-02-28 14:49:30 +02:00
|
|
|
&connector->mst.dp->mst.mgr,
|
|
|
|
connector->mst.port);
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static void mst_stream_disable(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
|
|
|
const struct intel_crtc_state *old_crtc_state,
|
|
|
|
const struct drm_connector_state *old_conn_state)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2019-12-04 20:05:43 +02:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2024-11-12 13:10:39 +02:00
|
|
|
struct intel_dp *intel_dp = to_primary_dp(encoder);
|
2016-08-09 17:04:12 +02:00
|
|
|
struct intel_connector *connector =
|
|
|
|
to_intel_connector(old_conn_state->connector);
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2025-04-04 18:03:09 +03:00
|
|
|
if (intel_dp_mst_active_streams(intel_dp) == 1)
|
2025-04-04 18:03:05 +03:00
|
|
|
intel_dp->link.active = false;
|
2024-06-10 19:49:27 +03:00
|
|
|
|
2023-11-21 07:43:17 +02:00
|
|
|
intel_hdcp_disable(intel_mst->connector);
|
|
|
|
|
2023-10-24 04:09:20 +03:00
|
|
|
intel_dp_sink_disable_decompression(state, connector, old_crtc_state);
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static void mst_stream_post_disable(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
|
|
|
const struct intel_crtc_state *old_crtc_state,
|
|
|
|
const struct drm_connector_state *old_conn_state)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2024-09-18 12:00:16 +05:30
|
|
|
struct intel_display *display = to_intel_display(encoder);
|
2019-12-04 20:05:43 +02:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2024-11-12 13:10:39 +02:00
|
|
|
struct intel_encoder *primary_encoder = to_primary_encoder(encoder);
|
|
|
|
struct intel_dp *intel_dp = to_primary_dp(encoder);
|
2016-08-09 17:04:12 +02:00
|
|
|
struct intel_connector *connector =
|
|
|
|
to_intel_connector(old_conn_state->connector);
|
2023-08-07 10:56:38 +08:00
|
|
|
struct drm_dp_mst_topology_state *old_mst_state =
|
2025-02-28 14:49:29 +02:00
|
|
|
drm_atomic_get_old_mst_topology_state(&state->base, &intel_dp->mst.mgr);
|
2023-08-07 10:56:38 +08:00
|
|
|
struct drm_dp_mst_topology_state *new_mst_state =
|
2025-02-28 14:49:29 +02:00
|
|
|
drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst.mgr);
|
2023-08-07 10:56:38 +08:00
|
|
|
const struct drm_dp_mst_atomic_payload *old_payload =
|
2025-02-28 14:49:30 +02:00
|
|
|
drm_atomic_get_mst_payload_state(old_mst_state, connector->mst.port);
|
2023-08-07 10:56:38 +08:00
|
|
|
struct drm_dp_mst_atomic_payload *new_payload =
|
2025-02-28 14:49:30 +02:00
|
|
|
drm_atomic_get_mst_payload_state(new_mst_state, connector->mst.port);
|
2024-04-09 19:35:01 +03:00
|
|
|
struct intel_crtc *pipe_crtc;
|
2019-12-05 13:03:49 -08:00
|
|
|
bool last_mst_stream;
|
2024-09-18 12:00:16 +05:30
|
|
|
int i;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2025-04-04 18:03:06 +03:00
|
|
|
last_mst_stream = intel_dp_mst_dec_active_streams(intel_dp);
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 12 && last_mst_stream &&
|
drm/i915/display: Make WARN* drm specific where drm_device ptr is available
drm specific WARN* calls include device information in the
backtrace, so we know what device the warnings originate from.
Covert all the calls of WARN* with device specific drm_WARN*
variants in functions where drm_device or drm_i915_private struct
pointer is readily available.
The conversion was done automatically with below coccinelle semantic
patch. checkpatch errors/warnings are fixed manually.
@rule1@
identifier func, T;
@@
func(...) {
...
struct drm_device *T = ...;
<...
(
-WARN(
+drm_WARN(T,
...)
|
-WARN_ON(
+drm_WARN_ON(T,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(T,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(T,
...)
)
...>
}
@rule2@
identifier func, T;
@@
func(struct drm_device *T,...) {
<...
(
-WARN(
+drm_WARN(T,
...)
|
-WARN_ON(
+drm_WARN_ON(T,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(T,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(T,
...)
)
...>
}
@rule3@
identifier func, T;
@@
func(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-WARN(
+drm_WARN(&T->drm,
...)
|
-WARN_ON(
+drm_WARN_ON(&T->drm,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(&T->drm,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(&T->drm,
...)
)
...+>
}
@rule4@
identifier func, T;
@@
func(struct drm_i915_private *T,...) {
<+...
(
-WARN(
+drm_WARN(&T->drm,
...)
|
-WARN_ON(
+drm_WARN_ON(&T->drm,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(&T->drm,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(&T->drm,
...)
)
...+>
}
Signed-off-by: Pankaj Bharadiya <pankaj.laxminarayan.bharadiya@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200128181603.27767-20-pankaj.laxminarayan.bharadiya@intel.com
2020-01-28 23:46:01 +05:30
|
|
|
!intel_dp_mst_is_master_trans(old_crtc_state));
|
2019-12-05 13:03:49 -08:00
|
|
|
|
2024-09-18 12:00:16 +05:30
|
|
|
for_each_pipe_crtc_modeset_disable(display, pipe_crtc, old_crtc_state, i) {
|
2024-04-09 19:35:01 +03:00
|
|
|
const struct intel_crtc_state *old_pipe_crtc_state =
|
|
|
|
intel_atomic_get_old_crtc_state(state, pipe_crtc);
|
|
|
|
|
|
|
|
intel_crtc_vblank_off(old_pipe_crtc_state);
|
|
|
|
}
|
2019-12-13 21:52:17 +02:00
|
|
|
|
2021-09-13 17:44:29 +03:00
|
|
|
intel_disable_transcoder(old_crtc_state);
|
2019-12-13 21:52:17 +02:00
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
drm_dp_remove_payload_part1(&intel_dp->mst.mgr, new_mst_state, new_payload);
|
2023-10-18 18:41:21 +03:00
|
|
|
|
2024-11-20 14:43:15 +02:00
|
|
|
intel_ddi_clear_act_sent(encoder, old_crtc_state);
|
2020-06-16 17:18:54 +03:00
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
intel_de_rmw(display,
|
|
|
|
TRANS_DDI_FUNC_CTL(display, old_crtc_state->cpu_transcoder),
|
2021-08-13 14:56:10 +03:00
|
|
|
TRANS_DDI_DP_VC_PAYLOAD_ALLOC, 0);
|
2019-12-22 17:06:51 -08:00
|
|
|
|
2024-11-20 14:43:15 +02:00
|
|
|
intel_ddi_wait_for_act_sent(encoder, old_crtc_state);
|
2025-02-28 14:49:29 +02:00
|
|
|
drm_dp_check_act_status(&intel_dp->mst.mgr);
|
2019-12-22 17:06:51 -08:00
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
drm_dp_remove_payload_part2(&intel_dp->mst.mgr, new_mst_state,
|
2023-08-07 10:56:38 +08:00
|
|
|
old_payload, new_payload);
|
|
|
|
|
2025-03-24 19:02:40 +05:30
|
|
|
intel_vrr_transcoder_disable(old_crtc_state);
|
|
|
|
|
2019-12-13 21:52:17 +02:00
|
|
|
intel_ddi_disable_transcoder_func(old_crtc_state);
|
|
|
|
|
2024-09-18 12:00:16 +05:30
|
|
|
for_each_pipe_crtc_modeset_disable(display, pipe_crtc, old_crtc_state, i) {
|
2024-04-09 19:35:01 +03:00
|
|
|
const struct intel_crtc_state *old_pipe_crtc_state =
|
|
|
|
intel_atomic_get_old_crtc_state(state, pipe_crtc);
|
2023-10-24 04:09:12 +03:00
|
|
|
|
2024-04-09 19:35:01 +03:00
|
|
|
intel_dsc_disable(old_pipe_crtc_state);
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
if (DISPLAY_VER(display) >= 9)
|
2024-04-09 19:35:01 +03:00
|
|
|
skl_scaler_disable(old_pipe_crtc_state);
|
|
|
|
else
|
|
|
|
ilk_pfit_disable(old_pipe_crtc_state);
|
|
|
|
}
|
2019-12-13 21:52:17 +02:00
|
|
|
|
2019-12-22 17:06:51 -08:00
|
|
|
/*
|
|
|
|
* Power down mst path before disabling the port, otherwise we end
|
|
|
|
* up getting interrupts from the sink upon detecting link loss.
|
|
|
|
*/
|
2025-02-28 14:49:30 +02:00
|
|
|
drm_dp_send_power_updown_phy(&intel_dp->mst.mgr, connector->mst.port,
|
2019-12-22 17:06:51 -08:00
|
|
|
false);
|
2020-06-10 01:06:16 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* BSpec 4287: disable DIP after the transcoder is disabled and before
|
|
|
|
* the transcoder clock select is set to none.
|
|
|
|
*/
|
2024-11-12 13:10:39 +02:00
|
|
|
intel_dp_set_infoframes(primary_encoder, false, old_crtc_state, NULL);
|
2019-12-05 13:03:49 -08:00
|
|
|
/*
|
|
|
|
* From TGL spec: "If multi-stream slave transcoder: Configure
|
|
|
|
* Transcoder Clock Select to direct no clock to the transcoder"
|
|
|
|
*
|
|
|
|
* From older GENs spec: "Configure Transcoder Clock Select to direct
|
|
|
|
* no clock to the transcoder"
|
|
|
|
*/
|
2024-11-12 13:10:42 +02:00
|
|
|
if (DISPLAY_VER(display) < 12 || !last_mst_stream)
|
2023-02-14 00:52:47 +02:00
|
|
|
intel_ddi_disable_transcoder_clock(old_crtc_state);
|
2018-08-31 20:47:39 +03:00
|
|
|
|
2017-10-03 17:22:11 +03:00
|
|
|
|
2016-03-09 11:14:38 +10:00
|
|
|
intel_mst->connector = NULL;
|
2019-12-05 13:03:49 -08:00
|
|
|
if (last_mst_stream)
|
2024-11-12 13:10:39 +02:00
|
|
|
primary_encoder->post_disable(state, primary_encoder,
|
|
|
|
old_crtc_state, NULL);
|
2017-10-27 22:31:27 +03:00
|
|
|
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static void mst_stream_post_pll_disable(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
|
|
|
const struct intel_crtc_state *old_crtc_state,
|
|
|
|
const struct drm_connector_state *old_conn_state)
|
2023-03-23 16:20:33 +02:00
|
|
|
{
|
2024-11-12 13:10:39 +02:00
|
|
|
struct intel_encoder *primary_encoder = to_primary_encoder(encoder);
|
|
|
|
struct intel_dp *intel_dp = to_primary_dp(encoder);
|
2023-03-23 16:20:33 +02:00
|
|
|
|
2025-04-04 18:03:09 +03:00
|
|
|
if (intel_dp_mst_active_streams(intel_dp) == 0 &&
|
2024-11-12 13:10:39 +02:00
|
|
|
primary_encoder->post_pll_disable)
|
|
|
|
primary_encoder->post_pll_disable(state, primary_encoder, old_crtc_state, old_conn_state);
|
2023-03-23 16:20:33 +02:00
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static void mst_stream_pre_pll_enable(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
|
|
|
const struct intel_crtc_state *pipe_config,
|
|
|
|
const struct drm_connector_state *conn_state)
|
2017-10-27 16:43:48 +03:00
|
|
|
{
|
2024-11-12 13:10:39 +02:00
|
|
|
struct intel_encoder *primary_encoder = to_primary_encoder(encoder);
|
|
|
|
struct intel_dp *intel_dp = to_primary_dp(encoder);
|
2017-10-27 16:43:48 +03:00
|
|
|
|
2025-04-04 18:03:09 +03:00
|
|
|
if (intel_dp_mst_active_streams(intel_dp) == 0)
|
2024-11-12 13:10:39 +02:00
|
|
|
primary_encoder->pre_pll_enable(state, primary_encoder,
|
|
|
|
pipe_config, NULL);
|
2023-04-14 20:38:00 +03:00
|
|
|
else
|
|
|
|
/*
|
|
|
|
* The port PLL state needs to get updated for secondary
|
|
|
|
* streams as for the primary stream.
|
|
|
|
*/
|
2024-11-12 13:10:39 +02:00
|
|
|
intel_ddi_update_active_dpll(state, primary_encoder,
|
2023-04-14 20:38:00 +03:00
|
|
|
to_intel_crtc(pipe_config->uapi.crtc));
|
2017-10-27 16:43:48 +03:00
|
|
|
}
|
|
|
|
|
2024-07-22 19:55:01 +03:00
|
|
|
static bool intel_mst_probed_link_params_valid(struct intel_dp *intel_dp,
|
|
|
|
int link_rate, int lane_count)
|
|
|
|
{
|
|
|
|
return intel_dp->link.mst_probed_rate == link_rate &&
|
|
|
|
intel_dp->link.mst_probed_lane_count == lane_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void intel_mst_set_probed_link_params(struct intel_dp *intel_dp,
|
|
|
|
int link_rate, int lane_count)
|
|
|
|
{
|
|
|
|
intel_dp->link.mst_probed_rate = link_rate;
|
|
|
|
intel_dp->link.mst_probed_lane_count = lane_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void intel_mst_reprobe_topology(struct intel_dp *intel_dp,
|
|
|
|
const struct intel_crtc_state *crtc_state)
|
|
|
|
{
|
|
|
|
if (intel_mst_probed_link_params_valid(intel_dp,
|
|
|
|
crtc_state->port_clock, crtc_state->lane_count))
|
|
|
|
return;
|
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
drm_dp_mst_topology_queue_probe(&intel_dp->mst.mgr);
|
2024-07-22 19:55:01 +03:00
|
|
|
|
|
|
|
intel_mst_set_probed_link_params(intel_dp,
|
|
|
|
crtc_state->port_clock, crtc_state->lane_count);
|
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static void mst_stream_pre_enable(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
|
|
|
const struct intel_crtc_state *pipe_config,
|
|
|
|
const struct drm_connector_state *conn_state)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(state);
|
2019-12-04 20:05:43 +02:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2024-11-12 13:10:39 +02:00
|
|
|
struct intel_encoder *primary_encoder = to_primary_encoder(encoder);
|
|
|
|
struct intel_dp *intel_dp = to_primary_dp(encoder);
|
2016-08-09 17:04:12 +02:00
|
|
|
struct intel_connector *connector =
|
|
|
|
to_intel_connector(conn_state->connector);
|
drm/display/dp_mst: Move all payload info into the atomic state
Now that we've finally gotten rid of the non-atomic MST users leftover in
the kernel, we can finally get rid of all of the legacy payload code we
have and move as much as possible into the MST atomic state structs. The
main purpose of this is to make the MST code a lot less confusing to work
on, as there's a lot of duplicated logic that doesn't really need to be
here. As well, this should make introducing features like fallback link
retraining and DSC support far easier.
Since the old payload code was pretty gnarly and there's a Lot of changes
here, I expect this might be a bit difficult to review. So to make things
as easy as possible for reviewers, I'll sum up how both the old and new
code worked here (it took me a while to figure this out too!).
The old MST code basically worked by maintaining two different payload
tables - proposed_vcpis, and payloads. proposed_vcpis would hold the
modified payload we wanted to push to the topology, while payloads held the
payload table that was currently programmed in hardware. Modifications to
proposed_vcpis would be handled through drm_dp_allocate_vcpi(),
drm_dp_mst_deallocate_vcpi(), and drm_dp_mst_reset_vcpi_slots(). Then, they
would be pushed via drm_dp_mst_update_payload_step1() and
drm_dp_mst_update_payload_step2().
Furthermore, it's important to note how adding and removing VC payloads
actually worked with drm_dp_mst_update_payload_step1(). When a VC payload
is removed from the VC table, all VC payloads which come after the removed
VC payload's slots must have their time slots shifted towards the start of
the table. The old code handles this by looping through the entire payload
table and recomputing the start slot for every payload in the topology from
scratch. While very much overkill, this ends up doing the right thing
because we always order the VCPIs for payloads from first to last starting
timeslot.
It's important to also note that drm_dp_mst_update_payload_step2() isn't
actually limited to updating a single payload - the driver can use it to
queue up multiple payload changes so that as many of them can be sent as
possible before waiting for the ACT. This is -technically- not against
spec, but as Wayne Lin has pointed out it's not consistently implemented
correctly in hubs - so it might as well be.
drm_dp_mst_update_payload_step2() is pretty self explanatory and basically
the same between the old and new code, save for the fact we don't have a
second step for deleting payloads anymore -and thus rename it to
drm_dp_mst_add_payload_step2().
The new payload code stores all of the current payload info within the MST
atomic state and computes as much of the state as possible ahead of time.
This has the one exception of the starting timeslots for payloads, which
can't be determined at atomic check time since the starting time slots will
vary depending on what order CRTCs are enabled in the atomic state - which
varies from driver to driver. These are still stored in the atomic MST
state, but are only copied from the old MST state during atomic commit
time. Likewise, this is when new start slots are determined.
Adding/removing payloads now works much more closely to how things are
described in the spec. When we delete a payload, we loop through the
current list of payloads and update the start slots for any payloads whose
time slots came after the payload we just deleted. Determining the starting
time slots for new payloads being added is done by simply keeping track of
where the end of the VC table is in
drm_dp_mst_topology_mgr->next_start_slot. Additionally, it's worth noting
that we no longer have a single update_payload() function. Instead, we now
have drm_dp_mst_add_payload_step1|2() and drm_dp_mst_remove_payload(). As
such, it's now left it up to the driver to figure out when to add or remove
payloads. The driver already knows when it's disabling/enabling CRTCs, so
it also already knows when payloads should be added or removed.
Changes since v1:
* Refactor around all of the completely dead code changes that are
happening in amdgpu for some reason when they really shouldn't even be
there in the first place… :\
* Remove mention of sending one ACT per series of payload updates. As Wayne
Lin pointed out, there are apparently hubs on the market that don't work
correctly with this scheme and require a separate ACT per payload update.
* Fix accidental drop of mst_mgr.lock - Wayne Lin
* Remove mentions of allowing multiple ACT updates per payload change,
mention that this is a result of vendors not consistently supporting this
part of the spec and requiring a unique ACT for each payload change.
* Get rid of reference to drm_dp_mst_port in DC - turns out I just got
myself confused by DC and we don't actually need this.
Changes since v2:
* Get rid of fix for not sending payload deallocations if ddps=0 and just
go back to wayne's fix
Signed-off-by: Lyude Paul <lyude@redhat.com>
Cc: Wayne Lin <Wayne.Lin@amd.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Fangzhi Zuo <Jerry.Zuo@amd.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Sean Paul <sean@poorly.run>
Acked-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220817193847.557945-18-lyude@redhat.com
2022-08-17 15:38:46 -04:00
|
|
|
struct drm_dp_mst_topology_state *mst_state =
|
2025-02-28 14:49:29 +02:00
|
|
|
drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst.mgr);
|
2014-05-02 14:02:48 +10:00
|
|
|
int ret;
|
2019-10-29 18:24:46 -07:00
|
|
|
bool first_mst_stream;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2015-08-27 13:13:31 +02:00
|
|
|
/* MST encoders are bound to a crtc, not to a connector,
|
|
|
|
* force the mapping here for get_hw_state.
|
|
|
|
*/
|
2016-08-09 17:04:12 +02:00
|
|
|
connector->encoder = encoder;
|
|
|
|
intel_mst->connector = connector;
|
2025-04-04 18:03:06 +03:00
|
|
|
|
|
|
|
first_mst_stream = intel_dp_mst_inc_active_streams(intel_dp);
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 12 && first_mst_stream &&
|
drm/i915/display: Make WARN* drm specific where drm_device ptr is available
drm specific WARN* calls include device information in the
backtrace, so we know what device the warnings originate from.
Covert all the calls of WARN* with device specific drm_WARN*
variants in functions where drm_device or drm_i915_private struct
pointer is readily available.
The conversion was done automatically with below coccinelle semantic
patch. checkpatch errors/warnings are fixed manually.
@rule1@
identifier func, T;
@@
func(...) {
...
struct drm_device *T = ...;
<...
(
-WARN(
+drm_WARN(T,
...)
|
-WARN_ON(
+drm_WARN_ON(T,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(T,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(T,
...)
)
...>
}
@rule2@
identifier func, T;
@@
func(struct drm_device *T,...) {
<...
(
-WARN(
+drm_WARN(T,
...)
|
-WARN_ON(
+drm_WARN_ON(T,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(T,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(T,
...)
)
...>
}
@rule3@
identifier func, T;
@@
func(...) {
...
struct drm_i915_private *T = ...;
<+...
(
-WARN(
+drm_WARN(&T->drm,
...)
|
-WARN_ON(
+drm_WARN_ON(&T->drm,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(&T->drm,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(&T->drm,
...)
)
...+>
}
@rule4@
identifier func, T;
@@
func(struct drm_i915_private *T,...) {
<+...
(
-WARN(
+drm_WARN(&T->drm,
...)
|
-WARN_ON(
+drm_WARN_ON(&T->drm,
...)
|
-WARN_ONCE(
+drm_WARN_ONCE(&T->drm,
...)
|
-WARN_ON_ONCE(
+drm_WARN_ON_ONCE(&T->drm,
...)
)
...+>
}
Signed-off-by: Pankaj Bharadiya <pankaj.laxminarayan.bharadiya@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200128181603.27767-20-pankaj.laxminarayan.bharadiya@intel.com
2020-01-28 23:46:01 +05:30
|
|
|
!intel_dp_mst_is_master_trans(pipe_config));
|
2015-08-27 13:13:31 +02:00
|
|
|
|
2019-10-29 18:24:46 -07:00
|
|
|
if (first_mst_stream)
|
2020-10-16 22:48:00 +03:00
|
|
|
intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
|
2018-04-06 21:10:53 -04:00
|
|
|
|
2025-02-28 14:49:30 +02:00
|
|
|
drm_dp_send_power_updown_phy(&intel_dp->mst.mgr, connector->mst.port, true);
|
2018-04-06 21:10:53 -04:00
|
|
|
|
2023-10-24 04:09:20 +03:00
|
|
|
intel_dp_sink_enable_decompression(state, connector, pipe_config);
|
|
|
|
|
2024-07-22 19:55:01 +03:00
|
|
|
if (first_mst_stream) {
|
2024-11-12 13:10:39 +02:00
|
|
|
primary_encoder->pre_enable(state, primary_encoder,
|
|
|
|
pipe_config, NULL);
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2024-07-22 19:55:01 +03:00
|
|
|
intel_mst_reprobe_topology(intel_dp, pipe_config);
|
|
|
|
}
|
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
ret = drm_dp_add_payload_part1(&intel_dp->mst.mgr, mst_state,
|
2025-02-28 14:49:30 +02:00
|
|
|
drm_atomic_get_mst_payload_state(mst_state, connector->mst.port));
|
drm/display/dp_mst: Move all payload info into the atomic state
Now that we've finally gotten rid of the non-atomic MST users leftover in
the kernel, we can finally get rid of all of the legacy payload code we
have and move as much as possible into the MST atomic state structs. The
main purpose of this is to make the MST code a lot less confusing to work
on, as there's a lot of duplicated logic that doesn't really need to be
here. As well, this should make introducing features like fallback link
retraining and DSC support far easier.
Since the old payload code was pretty gnarly and there's a Lot of changes
here, I expect this might be a bit difficult to review. So to make things
as easy as possible for reviewers, I'll sum up how both the old and new
code worked here (it took me a while to figure this out too!).
The old MST code basically worked by maintaining two different payload
tables - proposed_vcpis, and payloads. proposed_vcpis would hold the
modified payload we wanted to push to the topology, while payloads held the
payload table that was currently programmed in hardware. Modifications to
proposed_vcpis would be handled through drm_dp_allocate_vcpi(),
drm_dp_mst_deallocate_vcpi(), and drm_dp_mst_reset_vcpi_slots(). Then, they
would be pushed via drm_dp_mst_update_payload_step1() and
drm_dp_mst_update_payload_step2().
Furthermore, it's important to note how adding and removing VC payloads
actually worked with drm_dp_mst_update_payload_step1(). When a VC payload
is removed from the VC table, all VC payloads which come after the removed
VC payload's slots must have their time slots shifted towards the start of
the table. The old code handles this by looping through the entire payload
table and recomputing the start slot for every payload in the topology from
scratch. While very much overkill, this ends up doing the right thing
because we always order the VCPIs for payloads from first to last starting
timeslot.
It's important to also note that drm_dp_mst_update_payload_step2() isn't
actually limited to updating a single payload - the driver can use it to
queue up multiple payload changes so that as many of them can be sent as
possible before waiting for the ACT. This is -technically- not against
spec, but as Wayne Lin has pointed out it's not consistently implemented
correctly in hubs - so it might as well be.
drm_dp_mst_update_payload_step2() is pretty self explanatory and basically
the same between the old and new code, save for the fact we don't have a
second step for deleting payloads anymore -and thus rename it to
drm_dp_mst_add_payload_step2().
The new payload code stores all of the current payload info within the MST
atomic state and computes as much of the state as possible ahead of time.
This has the one exception of the starting timeslots for payloads, which
can't be determined at atomic check time since the starting time slots will
vary depending on what order CRTCs are enabled in the atomic state - which
varies from driver to driver. These are still stored in the atomic MST
state, but are only copied from the old MST state during atomic commit
time. Likewise, this is when new start slots are determined.
Adding/removing payloads now works much more closely to how things are
described in the spec. When we delete a payload, we loop through the
current list of payloads and update the start slots for any payloads whose
time slots came after the payload we just deleted. Determining the starting
time slots for new payloads being added is done by simply keeping track of
where the end of the VC table is in
drm_dp_mst_topology_mgr->next_start_slot. Additionally, it's worth noting
that we no longer have a single update_payload() function. Instead, we now
have drm_dp_mst_add_payload_step1|2() and drm_dp_mst_remove_payload(). As
such, it's now left it up to the driver to figure out when to add or remove
payloads. The driver already knows when it's disabling/enabling CRTCs, so
it also already knows when payloads should be added or removed.
Changes since v1:
* Refactor around all of the completely dead code changes that are
happening in amdgpu for some reason when they really shouldn't even be
there in the first place… :\
* Remove mention of sending one ACT per series of payload updates. As Wayne
Lin pointed out, there are apparently hubs on the market that don't work
correctly with this scheme and require a separate ACT per payload update.
* Fix accidental drop of mst_mgr.lock - Wayne Lin
* Remove mentions of allowing multiple ACT updates per payload change,
mention that this is a result of vendors not consistently supporting this
part of the spec and requiring a unique ACT for each payload change.
* Get rid of reference to drm_dp_mst_port in DC - turns out I just got
myself confused by DC and we don't actually need this.
Changes since v2:
* Get rid of fix for not sending payload deallocations if ddps=0 and just
go back to wayne's fix
Signed-off-by: Lyude Paul <lyude@redhat.com>
Cc: Wayne Lin <Wayne.Lin@amd.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Fangzhi Zuo <Jerry.Zuo@amd.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Sean Paul <sean@poorly.run>
Acked-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220817193847.557945-18-lyude@redhat.com
2022-08-17 15:38:46 -04:00
|
|
|
if (ret < 0)
|
2024-11-12 13:10:39 +02:00
|
|
|
intel_dp_queue_modeset_retry_for_link(state, primary_encoder, pipe_config);
|
2018-08-31 20:47:39 +03:00
|
|
|
|
2019-10-29 18:24:46 -07:00
|
|
|
/*
|
|
|
|
* Before Gen 12 this is not done as part of
|
2024-11-12 13:10:39 +02:00
|
|
|
* primary_encoder->pre_enable() and should be done here. For
|
2019-10-29 18:24:46 -07:00
|
|
|
* Gen 12+ the step in which this should be done is different for the
|
|
|
|
* first MST stream, so it's done on the DDI for the first stream and
|
|
|
|
* here for the following ones.
|
|
|
|
*/
|
2024-11-12 13:10:42 +02:00
|
|
|
if (DISPLAY_VER(display) < 12 || !first_mst_stream)
|
2023-02-14 00:52:47 +02:00
|
|
|
intel_ddi_enable_transcoder_clock(encoder, pipe_config);
|
2019-11-06 23:26:36 +02:00
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
if (DISPLAY_VER(display) >= 13 && !first_mst_stream)
|
2024-10-30 21:23:09 +02:00
|
|
|
intel_ddi_config_transcoder_func(encoder, pipe_config);
|
|
|
|
|
2024-11-12 13:10:39 +02:00
|
|
|
intel_dsc_dp_pps_write(primary_encoder, pipe_config);
|
2019-11-06 23:26:36 +02:00
|
|
|
intel_ddi_set_dp_msa(pipe_config, conn_state);
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
|
|
|
|
2024-01-29 19:55:28 +02:00
|
|
|
static void enable_bs_jitter_was(const struct intel_crtc_state *crtc_state)
|
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(crtc_state);
|
2024-01-29 19:55:28 +02:00
|
|
|
u32 clear = 0;
|
|
|
|
u32 set = 0;
|
|
|
|
|
2025-01-08 17:19:16 +02:00
|
|
|
if (!display->platform.alderlake_p)
|
2024-01-29 19:55:28 +02:00
|
|
|
return;
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
if (!IS_DISPLAY_STEP(display, STEP_D0, STEP_FOREVER))
|
2024-01-29 19:55:28 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Wa_14013163432:adlp */
|
|
|
|
if (crtc_state->fec_enable || intel_dp_is_uhbr(crtc_state))
|
|
|
|
set |= DP_MST_FEC_BS_JITTER_WA(crtc_state->cpu_transcoder);
|
|
|
|
|
2024-01-29 19:55:29 +02:00
|
|
|
/* Wa_14014143976:adlp */
|
2024-11-12 13:10:42 +02:00
|
|
|
if (IS_DISPLAY_STEP(display, STEP_E0, STEP_FOREVER)) {
|
2024-01-29 19:55:29 +02:00
|
|
|
if (intel_dp_is_uhbr(crtc_state))
|
|
|
|
set |= DP_MST_SHORT_HBLANK_WA(crtc_state->cpu_transcoder);
|
|
|
|
else if (crtc_state->fec_enable)
|
|
|
|
clear |= DP_MST_SHORT_HBLANK_WA(crtc_state->cpu_transcoder);
|
2024-01-29 19:55:30 +02:00
|
|
|
|
|
|
|
if (crtc_state->fec_enable || intel_dp_is_uhbr(crtc_state))
|
|
|
|
set |= DP_MST_DPT_DPTP_ALIGN_WA(crtc_state->cpu_transcoder);
|
2024-01-29 19:55:29 +02:00
|
|
|
}
|
|
|
|
|
2024-01-29 19:55:28 +02:00
|
|
|
if (!clear && !set)
|
|
|
|
return;
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
intel_de_rmw(display, CHICKEN_MISC_3, clear, set);
|
2024-01-29 19:55:28 +02:00
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static void mst_stream_enable(struct intel_atomic_state *state,
|
|
|
|
struct intel_encoder *encoder,
|
|
|
|
const struct intel_crtc_state *pipe_config,
|
|
|
|
const struct drm_connector_state *conn_state)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2024-09-18 12:00:16 +05:30
|
|
|
struct intel_display *display = to_intel_display(encoder);
|
2024-11-12 13:10:39 +02:00
|
|
|
struct intel_encoder *primary_encoder = to_primary_encoder(encoder);
|
|
|
|
struct intel_dp *intel_dp = to_primary_dp(encoder);
|
drm/display/dp_mst: Move all payload info into the atomic state
Now that we've finally gotten rid of the non-atomic MST users leftover in
the kernel, we can finally get rid of all of the legacy payload code we
have and move as much as possible into the MST atomic state structs. The
main purpose of this is to make the MST code a lot less confusing to work
on, as there's a lot of duplicated logic that doesn't really need to be
here. As well, this should make introducing features like fallback link
retraining and DSC support far easier.
Since the old payload code was pretty gnarly and there's a Lot of changes
here, I expect this might be a bit difficult to review. So to make things
as easy as possible for reviewers, I'll sum up how both the old and new
code worked here (it took me a while to figure this out too!).
The old MST code basically worked by maintaining two different payload
tables - proposed_vcpis, and payloads. proposed_vcpis would hold the
modified payload we wanted to push to the topology, while payloads held the
payload table that was currently programmed in hardware. Modifications to
proposed_vcpis would be handled through drm_dp_allocate_vcpi(),
drm_dp_mst_deallocate_vcpi(), and drm_dp_mst_reset_vcpi_slots(). Then, they
would be pushed via drm_dp_mst_update_payload_step1() and
drm_dp_mst_update_payload_step2().
Furthermore, it's important to note how adding and removing VC payloads
actually worked with drm_dp_mst_update_payload_step1(). When a VC payload
is removed from the VC table, all VC payloads which come after the removed
VC payload's slots must have their time slots shifted towards the start of
the table. The old code handles this by looping through the entire payload
table and recomputing the start slot for every payload in the topology from
scratch. While very much overkill, this ends up doing the right thing
because we always order the VCPIs for payloads from first to last starting
timeslot.
It's important to also note that drm_dp_mst_update_payload_step2() isn't
actually limited to updating a single payload - the driver can use it to
queue up multiple payload changes so that as many of them can be sent as
possible before waiting for the ACT. This is -technically- not against
spec, but as Wayne Lin has pointed out it's not consistently implemented
correctly in hubs - so it might as well be.
drm_dp_mst_update_payload_step2() is pretty self explanatory and basically
the same between the old and new code, save for the fact we don't have a
second step for deleting payloads anymore -and thus rename it to
drm_dp_mst_add_payload_step2().
The new payload code stores all of the current payload info within the MST
atomic state and computes as much of the state as possible ahead of time.
This has the one exception of the starting timeslots for payloads, which
can't be determined at atomic check time since the starting time slots will
vary depending on what order CRTCs are enabled in the atomic state - which
varies from driver to driver. These are still stored in the atomic MST
state, but are only copied from the old MST state during atomic commit
time. Likewise, this is when new start slots are determined.
Adding/removing payloads now works much more closely to how things are
described in the spec. When we delete a payload, we loop through the
current list of payloads and update the start slots for any payloads whose
time slots came after the payload we just deleted. Determining the starting
time slots for new payloads being added is done by simply keeping track of
where the end of the VC table is in
drm_dp_mst_topology_mgr->next_start_slot. Additionally, it's worth noting
that we no longer have a single update_payload() function. Instead, we now
have drm_dp_mst_add_payload_step1|2() and drm_dp_mst_remove_payload(). As
such, it's now left it up to the driver to figure out when to add or remove
payloads. The driver already knows when it's disabling/enabling CRTCs, so
it also already knows when payloads should be added or removed.
Changes since v1:
* Refactor around all of the completely dead code changes that are
happening in amdgpu for some reason when they really shouldn't even be
there in the first place… :\
* Remove mention of sending one ACT per series of payload updates. As Wayne
Lin pointed out, there are apparently hubs on the market that don't work
correctly with this scheme and require a separate ACT per payload update.
* Fix accidental drop of mst_mgr.lock - Wayne Lin
* Remove mentions of allowing multiple ACT updates per payload change,
mention that this is a result of vendors not consistently supporting this
part of the spec and requiring a unique ACT for each payload change.
* Get rid of reference to drm_dp_mst_port in DC - turns out I just got
myself confused by DC and we don't actually need this.
Changes since v2:
* Get rid of fix for not sending payload deallocations if ddps=0 and just
go back to wayne's fix
Signed-off-by: Lyude Paul <lyude@redhat.com>
Cc: Wayne Lin <Wayne.Lin@amd.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Fangzhi Zuo <Jerry.Zuo@amd.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Sean Paul <sean@poorly.run>
Acked-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220817193847.557945-18-lyude@redhat.com
2022-08-17 15:38:46 -04:00
|
|
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
|
|
|
struct drm_dp_mst_topology_state *mst_state =
|
2025-02-28 14:49:29 +02:00
|
|
|
drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst.mgr);
|
2021-07-23 10:06:18 -07:00
|
|
|
enum transcoder trans = pipe_config->cpu_transcoder;
|
2025-04-04 18:03:09 +03:00
|
|
|
bool first_mst_stream = intel_dp_mst_active_streams(intel_dp) == 1;
|
2024-04-09 19:35:01 +03:00
|
|
|
struct intel_crtc *pipe_crtc;
|
2025-04-24 20:45:15 +05:30
|
|
|
int ret, i;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_WARN_ON(display->drm, pipe_config->has_pch_encoder);
|
2020-02-05 10:29:59 +02:00
|
|
|
|
2021-09-09 15:52:04 +03:00
|
|
|
if (intel_dp_is_uhbr(pipe_config)) {
|
|
|
|
const struct drm_display_mode *adjusted_mode =
|
|
|
|
&pipe_config->hw.adjusted_mode;
|
|
|
|
u64 crtc_clock_hz = KHz(adjusted_mode->crtc_clock);
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
intel_de_write(display, TRANS_DP2_VFREQHIGH(pipe_config->cpu_transcoder),
|
2021-09-09 15:52:04 +03:00
|
|
|
TRANS_DP2_VFREQ_PIXEL_CLOCK(crtc_clock_hz >> 24));
|
2024-11-12 13:10:42 +02:00
|
|
|
intel_de_write(display, TRANS_DP2_VFREQLOW(pipe_config->cpu_transcoder),
|
2021-09-09 15:52:04 +03:00
|
|
|
TRANS_DP2_VFREQ_PIXEL_CLOCK(crtc_clock_hz & 0xffffff));
|
|
|
|
}
|
|
|
|
|
2024-01-29 19:55:28 +02:00
|
|
|
enable_bs_jitter_was(pipe_config);
|
|
|
|
|
2020-04-17 16:47:20 +03:00
|
|
|
intel_ddi_enable_transcoder_func(encoder, pipe_config);
|
2020-04-17 16:47:19 +03:00
|
|
|
|
2025-03-24 19:02:40 +05:30
|
|
|
intel_vrr_transcoder_enable(pipe_config);
|
|
|
|
|
2024-11-20 14:43:15 +02:00
|
|
|
intel_ddi_clear_act_sent(encoder, pipe_config);
|
2023-10-18 18:41:22 +03:00
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
intel_de_rmw(display, TRANS_DDI_FUNC_CTL(display, trans), 0,
|
2021-07-23 10:06:18 -07:00
|
|
|
TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
|
2020-06-23 11:24:11 +03:00
|
|
|
|
2024-11-20 14:43:15 +02:00
|
|
|
intel_ddi_wait_for_act_sent(encoder, pipe_config);
|
2025-02-28 14:49:29 +02:00
|
|
|
drm_dp_check_act_status(&intel_dp->mst.mgr);
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2023-10-24 04:09:14 +03:00
|
|
|
if (first_mst_stream)
|
|
|
|
intel_ddi_wait_for_fec_status(encoder, pipe_config, true);
|
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
ret = drm_dp_add_payload_part2(&intel_dp->mst.mgr,
|
2024-07-22 19:55:00 +03:00
|
|
|
drm_atomic_get_mst_payload_state(mst_state,
|
2025-02-28 14:49:30 +02:00
|
|
|
connector->mst.port));
|
2024-07-22 19:55:00 +03:00
|
|
|
if (ret < 0)
|
2024-11-12 13:10:39 +02:00
|
|
|
intel_dp_queue_modeset_retry_for_link(state, primary_encoder, pipe_config);
|
2020-05-07 17:41:25 +03:00
|
|
|
|
2024-11-12 13:10:41 +02:00
|
|
|
if (DISPLAY_VER(display) >= 12)
|
|
|
|
intel_de_rmw(display, CHICKEN_TRANS(display, trans),
|
2023-10-18 18:41:23 +03:00
|
|
|
FECSTALL_DIS_DPTSTREAM_DPTTG,
|
|
|
|
pipe_config->fec_enable ? FECSTALL_DIS_DPTSTREAM_DPTTG : 0);
|
2021-07-23 10:06:18 -07:00
|
|
|
|
2021-09-13 17:44:29 +03:00
|
|
|
intel_enable_transcoder(pipe_config);
|
2020-05-07 17:41:25 +03:00
|
|
|
|
2024-09-18 12:00:16 +05:30
|
|
|
for_each_pipe_crtc_modeset_enable(display, pipe_crtc, pipe_config, i) {
|
2024-04-09 19:35:01 +03:00
|
|
|
const struct intel_crtc_state *pipe_crtc_state =
|
|
|
|
intel_atomic_get_new_crtc_state(state, pipe_crtc);
|
|
|
|
|
|
|
|
intel_crtc_vblank_on(pipe_crtc_state);
|
|
|
|
}
|
2020-05-07 17:41:25 +03:00
|
|
|
|
2023-10-26 17:41:39 +05:30
|
|
|
intel_hdcp_enable(state, encoder, pipe_config, conn_state);
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static bool mst_stream_get_hw_state(struct intel_encoder *encoder,
|
|
|
|
enum pipe *pipe)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2019-12-04 20:05:43 +02:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
2014-05-02 14:02:48 +10:00
|
|
|
*pipe = intel_mst->pipe;
|
2016-03-09 11:14:38 +10:00
|
|
|
if (intel_mst->connector)
|
2014-05-02 14:02:48 +10:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static void mst_stream_get_config(struct intel_encoder *encoder,
|
|
|
|
struct intel_crtc_state *pipe_config)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2024-11-12 13:10:39 +02:00
|
|
|
struct intel_encoder *primary_encoder = to_primary_encoder(encoder);
|
2017-10-24 12:52:14 +03:00
|
|
|
|
2024-11-12 13:10:39 +02:00
|
|
|
primary_encoder->get_config(primary_encoder, pipe_config);
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static bool mst_stream_initial_fastset_check(struct intel_encoder *encoder,
|
|
|
|
struct intel_crtc_state *crtc_state)
|
2020-10-06 00:53:10 +03:00
|
|
|
{
|
2024-11-12 13:10:39 +02:00
|
|
|
struct intel_encoder *primary_encoder = to_primary_encoder(encoder);
|
2020-10-06 00:53:10 +03:00
|
|
|
|
2024-11-12 13:10:39 +02:00
|
|
|
return intel_dp_initial_fastset_check(primary_encoder, crtc_state);
|
2020-10-06 00:53:10 +03:00
|
|
|
}
|
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
static int mst_connector_get_ddc_modes(struct drm_connector *_connector)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2025-01-08 17:19:13 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(_connector);
|
2025-01-08 17:19:14 +02:00
|
|
|
struct intel_display *display = to_intel_display(connector);
|
2025-02-28 14:49:30 +02:00
|
|
|
struct intel_dp *intel_dp = connector->mst.dp;
|
2023-05-30 12:08:25 +03:00
|
|
|
const struct drm_edid *drm_edid;
|
2014-05-02 14:02:48 +10:00
|
|
|
int ret;
|
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
if (drm_connector_is_unregistered(&connector->base))
|
|
|
|
return intel_connector_update_modes(&connector->base, NULL);
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2024-12-04 12:21:50 +02:00
|
|
|
if (!intel_display_driver_check_access(display))
|
2025-01-08 17:19:13 +02:00
|
|
|
return drm_edid_connector_add_modes(&connector->base);
|
2024-02-12 19:52:37 +02:00
|
|
|
|
2025-02-28 14:49:30 +02:00
|
|
|
drm_edid = drm_dp_mst_edid_read(&connector->base, &intel_dp->mst.mgr, connector->mst.port);
|
2023-05-30 12:08:25 +03:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
ret = intel_connector_update_modes(&connector->base, drm_edid);
|
2023-05-30 12:08:25 +03:00
|
|
|
|
|
|
|
drm_edid_free(drm_edid);
|
2014-05-02 14:02:48 +10:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-03-10 15:51:21 -04:00
|
|
|
static int
|
2025-01-08 17:19:13 +02:00
|
|
|
mst_connector_late_register(struct drm_connector *_connector)
|
2020-03-10 15:51:21 -04:00
|
|
|
{
|
2025-01-08 17:19:13 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(_connector);
|
2020-03-10 15:51:21 -04:00
|
|
|
int ret;
|
|
|
|
|
2025-02-28 14:49:30 +02:00
|
|
|
ret = drm_dp_mst_connector_late_register(&connector->base, connector->mst.port);
|
2020-03-10 15:51:21 -04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
ret = intel_connector_register(&connector->base);
|
2020-03-10 15:51:21 -04:00
|
|
|
if (ret < 0)
|
2025-02-28 14:49:30 +02:00
|
|
|
drm_dp_mst_connector_early_unregister(&connector->base, connector->mst.port);
|
2020-03-10 15:51:21 -04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2025-01-08 17:19:13 +02:00
|
|
|
mst_connector_early_unregister(struct drm_connector *_connector)
|
2020-03-10 15:51:21 -04:00
|
|
|
{
|
2025-01-08 17:19:13 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(_connector);
|
2020-03-10 15:51:21 -04:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
intel_connector_unregister(&connector->base);
|
2025-02-28 14:49:30 +02:00
|
|
|
drm_dp_mst_connector_early_unregister(&connector->base, connector->mst.port);
|
2020-03-10 15:51:21 -04:00
|
|
|
}
|
|
|
|
|
2024-11-20 14:43:10 +02:00
|
|
|
static const struct drm_connector_funcs mst_connector_funcs = {
|
2014-05-02 14:02:48 +10:00
|
|
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
2019-03-26 16:25:51 +02:00
|
|
|
.atomic_get_property = intel_digital_connector_atomic_get_property,
|
|
|
|
.atomic_set_property = intel_digital_connector_atomic_set_property,
|
2024-11-20 14:43:10 +02:00
|
|
|
.late_register = mst_connector_late_register,
|
|
|
|
.early_unregister = mst_connector_early_unregister,
|
2018-10-09 17:11:03 +03:00
|
|
|
.destroy = intel_connector_destroy,
|
2015-01-22 16:50:32 -08:00
|
|
|
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
2019-03-26 16:25:51 +02:00
|
|
|
.atomic_duplicate_state = intel_digital_connector_duplicate_state,
|
2014-05-02 14:02:48 +10:00
|
|
|
};
|
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
static int mst_connector_get_modes(struct drm_connector *_connector)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2025-01-08 17:19:13 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(_connector);
|
|
|
|
|
|
|
|
return mst_connector_get_ddc_modes(&connector->base);
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
|
|
|
|
2020-07-13 13:07:46 -04:00
|
|
|
static int
|
2025-01-08 17:19:13 +02:00
|
|
|
mst_connector_mode_valid_ctx(struct drm_connector *_connector,
|
2024-12-14 15:37:08 +02:00
|
|
|
const struct drm_display_mode *mode,
|
2024-11-20 14:43:10 +02:00
|
|
|
struct drm_modeset_acquire_ctx *ctx,
|
|
|
|
enum drm_mode_status *status)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2025-01-08 17:19:13 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(_connector);
|
2025-01-08 17:19:14 +02:00
|
|
|
struct intel_display *display = to_intel_display(connector);
|
2025-02-28 14:49:30 +02:00
|
|
|
struct intel_dp *intel_dp = connector->mst.dp;
|
2025-02-28 14:49:29 +02:00
|
|
|
struct drm_dp_mst_topology_mgr *mgr = &intel_dp->mst.mgr;
|
2025-02-28 14:49:30 +02:00
|
|
|
struct drm_dp_mst_port *port = connector->mst.port;
|
2020-07-13 13:07:46 -04:00
|
|
|
const int min_bpp = 18;
|
2024-11-12 13:10:42 +02:00
|
|
|
int max_dotclk = display->cdclk.max_dotclk_freq;
|
2016-11-15 12:59:06 -08:00
|
|
|
int max_rate, mode_rate, max_lanes, max_link_clock;
|
2020-07-13 13:07:46 -04:00
|
|
|
int ret;
|
2024-09-26 19:13:22 +05:30
|
|
|
bool dsc = false;
|
2023-08-17 19:54:45 +05:30
|
|
|
u16 dsc_max_compressed_bpp = 0;
|
2022-11-01 11:42:20 +02:00
|
|
|
u8 dsc_slice_count = 0;
|
|
|
|
int target_clock = mode->clock;
|
2024-09-16 15:58:34 +05:30
|
|
|
int num_joined_pipes;
|
2016-11-15 12:59:06 -08:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
if (drm_connector_is_unregistered(&connector->base)) {
|
2020-07-13 13:07:46 -04:00
|
|
|
*status = MODE_ERROR;
|
|
|
|
return 0;
|
|
|
|
}
|
2017-08-10 07:50:43 -07:00
|
|
|
|
2025-02-12 18:36:38 +02:00
|
|
|
*status = intel_cpu_transcoder_mode_valid(display, mode);
|
2023-11-27 16:50:25 +02:00
|
|
|
if (*status != MODE_OK)
|
|
|
|
return 0;
|
|
|
|
|
2024-04-02 16:51:43 +03:00
|
|
|
if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
|
|
|
|
*status = MODE_H_ILLEGAL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode->clock < 10000) {
|
|
|
|
*status = MODE_CLOCK_LOW;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-15 12:59:06 -08:00
|
|
|
max_link_clock = intel_dp_max_link_rate(intel_dp);
|
2017-04-06 16:44:14 +03:00
|
|
|
max_lanes = intel_dp_max_lane_count(intel_dp);
|
2016-11-15 12:59:06 -08:00
|
|
|
|
2024-02-20 23:18:30 +02:00
|
|
|
max_rate = intel_dp_max_link_data_rate(intel_dp,
|
|
|
|
max_link_clock, max_lanes);
|
2020-07-13 13:07:46 -04:00
|
|
|
mode_rate = intel_dp_link_required(mode->clock, min_bpp);
|
2016-02-02 15:16:40 +02:00
|
|
|
|
drm/i915/dp_mst: Account for FEC and DSC overhead during BW allocation
Atm, the BW allocated for an MST stream doesn't take into account the
DSC control symbol (EOC) and data alignment overhead on the local (first
downstream) MST link (reflected by the data M/N/TU values) and - besides
the above overheads - the FEC symbol overhead on 8b/10b remote
(after a downstream branch device) MST links.
In addition the FEC overhead used on the local link is a fixed amount,
which only applies to certain modes, but not enough for all modes; add a
code comment clarifying this.
Fix the above by calculating the data M/N values with the total BW
overhead (not including the SSC overhead, since this isn't enabled by
the source device) and using this the PBN and TU values for the local
link and PBN for remote links (including SSC, since this is mandatory
for links after downstream branch devices).
For now keep the current fixed FEC overhead as a minimum, since this is
what bspec requires for audio functionality.
Calculate the effective link BW in a clearer way, applying the channel
coding efficiency based on the coding type. The calculation was correct
for 8b/10b, but not for 128b/132b links; this patch leaves the behavior
for this unchanged, leaving the fix for a follow-up.
v2:
- Fix TU size programmed to the HW, making it match the payload size
programmed to the payload table.
v3:
- Add code comment about the connection between the payload's size in
the payload table and the corresponding PBN value. (Ville)
- Add WARN_ON(remote_m_n.tu < dp_m_n.tu). (Ville)
- Add code comment about factors not accounted for by the BW
calculation in intel_dp_mst_mode_valid_ctx() (and compute config).
(Ville)
- Simplify calculation of PBN to remote_m_n.tu * mst_state->pbn_div.
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-2-imre.deak@intel.com
2023-10-24 04:09:08 +03:00
|
|
|
/*
|
|
|
|
* TODO:
|
|
|
|
* - Also check if compression would allow for the mode
|
|
|
|
* - Calculate the overhead using drm_dp_bw_overhead() /
|
|
|
|
* drm_dp_bw_channel_coding_efficiency(), similarly to the
|
|
|
|
* compute config code, as drm_dp_calc_pbn_mode() doesn't
|
|
|
|
* account with all the overheads.
|
|
|
|
* - Check here and during compute config the BW reported by
|
|
|
|
* DFP_Link_Available_Payload_Bandwidth_Number (or the
|
|
|
|
* corresponding link capabilities of the sink) in case the
|
|
|
|
* stream is uncompressed for it by the last branch device.
|
|
|
|
*/
|
2025-01-08 17:19:13 +02:00
|
|
|
num_joined_pipes = intel_dp_num_joined_pipes(intel_dp, connector,
|
2024-09-26 19:13:22 +05:30
|
|
|
mode->hdisplay, target_clock);
|
|
|
|
max_dotclk *= num_joined_pipes;
|
2024-09-16 15:58:34 +05:30
|
|
|
|
2024-04-09 19:35:02 +03:00
|
|
|
ret = drm_modeset_lock(&mgr->base.lock, ctx);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2023-11-27 16:50:27 +02:00
|
|
|
|
2024-04-09 19:35:02 +03:00
|
|
|
if (mode_rate > max_rate || mode->clock > max_dotclk ||
|
|
|
|
drm_dp_calc_pbn_mode(mode->clock, min_bpp << 4) > port->full_pbn) {
|
2023-11-27 16:50:27 +02:00
|
|
|
*status = MODE_CLOCK_HIGH;
|
|
|
|
return 0;
|
2022-11-01 11:42:20 +02:00
|
|
|
}
|
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
if (intel_dp_has_dsc(connector)) {
|
2022-11-01 11:42:20 +02:00
|
|
|
/*
|
|
|
|
* TBD pass the connector BPC,
|
|
|
|
* for now U8_MAX so that max BPC on that platform would be picked
|
|
|
|
*/
|
2025-01-08 17:19:13 +02:00
|
|
|
int pipe_bpp = intel_dp_dsc_compute_max_bpp(connector, U8_MAX);
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
if (drm_dp_sink_supports_fec(connector->dp.fec_capability)) {
|
2023-08-17 19:54:45 +05:30
|
|
|
dsc_max_compressed_bpp =
|
2024-12-13 11:48:24 +02:00
|
|
|
intel_dp_dsc_get_max_compressed_bpp(display,
|
2023-08-17 19:54:45 +05:30
|
|
|
max_link_clock,
|
|
|
|
max_lanes,
|
|
|
|
target_clock,
|
|
|
|
mode->hdisplay,
|
2024-09-16 15:58:36 +05:30
|
|
|
num_joined_pipes,
|
2023-08-17 19:54:45 +05:30
|
|
|
INTEL_OUTPUT_FORMAT_RGB,
|
2023-08-17 19:54:52 +05:30
|
|
|
pipe_bpp, 64);
|
2022-11-01 11:42:20 +02:00
|
|
|
dsc_slice_count =
|
2025-01-08 17:19:13 +02:00
|
|
|
intel_dp_dsc_get_slice_count(connector,
|
2022-11-01 11:42:20 +02:00
|
|
|
target_clock,
|
|
|
|
mode->hdisplay,
|
2024-09-16 15:58:36 +05:30
|
|
|
num_joined_pipes);
|
2022-11-01 11:42:20 +02:00
|
|
|
}
|
|
|
|
|
2023-08-17 19:54:45 +05:30
|
|
|
dsc = dsc_max_compressed_bpp && dsc_slice_count;
|
2022-11-01 11:42:20 +02:00
|
|
|
}
|
|
|
|
|
2024-12-13 11:48:24 +02:00
|
|
|
if (intel_dp_joiner_needs_dsc(display, num_joined_pipes) && !dsc) {
|
2023-11-27 16:50:26 +02:00
|
|
|
*status = MODE_CLOCK_HIGH;
|
|
|
|
return 0;
|
|
|
|
}
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2023-11-27 16:50:26 +02:00
|
|
|
if (mode_rate > max_rate && !dsc) {
|
|
|
|
*status = MODE_CLOCK_HIGH;
|
|
|
|
return 0;
|
|
|
|
}
|
2022-11-01 11:42:20 +02:00
|
|
|
|
2025-02-12 18:36:39 +02:00
|
|
|
*status = intel_mode_valid_max_plane_size(display, mode, num_joined_pipes);
|
2020-07-13 13:07:46 -04:00
|
|
|
return 0;
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
|
|
|
|
2024-11-20 14:43:10 +02:00
|
|
|
static struct drm_encoder *
|
2025-01-08 17:19:13 +02:00
|
|
|
mst_connector_atomic_best_encoder(struct drm_connector *_connector,
|
2024-11-20 14:43:10 +02:00
|
|
|
struct drm_atomic_state *state)
|
2015-08-03 17:24:09 +02:00
|
|
|
{
|
2025-01-08 17:19:13 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(_connector);
|
|
|
|
struct drm_connector_state *connector_state =
|
|
|
|
drm_atomic_get_new_connector_state(state, &connector->base);
|
2025-02-28 14:49:30 +02:00
|
|
|
struct intel_dp *intel_dp = connector->mst.dp;
|
drm: Pass the full state to connectors atomic functions
The current atomic helpers have either their object state being passed as
an argument or the full atomic state.
The former is the pattern that was done at first, before switching to the
latter for new hooks or when it was needed.
Now that the CRTCs have been converted, let's move forward with the
connectors to provide a consistent interface.
The conversion was done using the coccinelle script below, and built tested
on all the drivers.
@@
identifier connector, connector_state;
@@
struct drm_connector_helper_funcs {
...
struct drm_encoder* (*atomic_best_encoder)(struct drm_connector *connector,
- struct drm_connector_state *connector_state);
+ struct drm_atomic_state *state);
...
}
@@
identifier connector, connector_state;
@@
struct drm_connector_helper_funcs {
...
void (*atomic_commit)(struct drm_connector *connector,
- struct drm_connector_state *connector_state);
+ struct drm_atomic_state *state);
...
}
@@
struct drm_connector_helper_funcs *FUNCS;
identifier state;
identifier connector, connector_state;
identifier f;
@@
f(..., struct drm_atomic_state *state, ...)
{
<+...
- FUNCS->atomic_commit(connector, connector_state);
+ FUNCS->atomic_commit(connector, state);
...+>
}
@@
struct drm_connector_helper_funcs *FUNCS;
identifier state;
identifier connector, connector_state;
identifier var, f;
@@
f(struct drm_atomic_state *state, ...)
{
<+...
- var = FUNCS->atomic_best_encoder(connector, connector_state);
+ var = FUNCS->atomic_best_encoder(connector, state);
...+>
}
@ connector_atomic_func @
identifier helpers;
identifier func;
@@
(
static struct drm_connector_helper_funcs helpers = {
...,
.atomic_best_encoder = func,
...,
};
|
static struct drm_connector_helper_funcs helpers = {
...,
.atomic_commit = func,
...,
};
)
@@
identifier connector_atomic_func.func;
identifier connector;
symbol state;
@@
func(struct drm_connector *connector,
- struct drm_connector_state *state
+ struct drm_connector_state *connector_state
)
{
...
- state
+ connector_state
...
}
@ ignores_state @
identifier connector_atomic_func.func;
identifier connector, connector_state;
@@
func(struct drm_connector *connector,
struct drm_connector_state *connector_state)
{
... when != connector_state
}
@ adds_state depends on connector_atomic_func && !ignores_state @
identifier connector_atomic_func.func;
identifier connector, connector_state;
@@
func(struct drm_connector *connector, struct drm_connector_state *connector_state)
{
+ struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state, connector);
...
}
@ depends on connector_atomic_func @
identifier connector_atomic_func.func;
identifier connector_state;
identifier connector;
@@
func(struct drm_connector *connector,
- struct drm_connector_state *connector_state
+ struct drm_atomic_state *state
)
{ ... }
@ include depends on adds_state @
@@
#include <drm/drm_atomic.h>
@ no_include depends on !include && adds_state @
@@
+ #include <drm/drm_atomic.h>
#include <drm/...>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Cc: Leo Li <sunpeng.li@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: "Christian König" <christian.koenig@amd.com>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Ben Skeggs <bskeggs@redhat.com>
Cc: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
Cc: Melissa Wen <melissa.srw@gmail.com>
Cc: Haneen Mohammed <hamohammed.sa@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20201118094758.506730-1-maxime@cerno.tech
2020-11-18 10:47:58 +01:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(connector_state->crtc);
|
2015-08-03 17:24:09 +02:00
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
return &intel_dp->mst.stream_encoders[crtc->pipe]->base.base;
|
2015-08-03 17:24:09 +02:00
|
|
|
}
|
|
|
|
|
drm/dp_mst: Protect drm_dp_mst_port members with locking
This is a complicated one. Essentially, there's currently a problem in the MST
core that hasn't really caused any issues that we're aware of (emphasis on "that
we're aware of"): locking.
When we go through and probe the link addresses and path resources in a
topology, we hold no locks when updating ports with said information. The
members I'm referring to in particular are:
- ldps
- ddps
- mcs
- pdt
- dpcd_rev
- num_sdp_streams
- num_sdp_stream_sinks
- available_pbn
- input
- connector
Now that we're handling UP requests asynchronously and will be using some of
the struct members mentioned above in atomic modesetting in the future for
features such as PBN validation, this is going to become a lot more important.
As well, the next few commits that prepare us for and introduce suspend/resume
reprobing will also need clear locking in order to prevent from additional
racing hilarities that we never could have hit in the past.
So, let's solve this issue by using &mgr->base.lock, the modesetting
lock which currently only protects &mgr->base.state. This works
perfectly because it allows us to avoid blocking connection_mutex
unnecessarily, and we can grab this in connector detection paths since
it's a ww mutex. We start by having drm_dp_mst_handle_up_req() hold this
when updating ports. For drm_dp_mst_handle_link_address_port() things
are a bit more complicated. As I've learned the hard way, we can grab
&mgr->lock.base for everything except for port->connector. See, our
normal driver probing paths end up generating this rather obvious
lockdep chain:
&drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
However, sysfs grabs &drm->mode_config.mutex in order to protect itself
from connector state changing under it. Because this entails grabbing
kn->count, e.g. the lock that the kernel provides for protecting sysfs
contexts, we end up grabbing kn->count followed by
&drm->mode_config.mutex. This ends up creating an extremely rude chain:
&kn->count
-> &drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
I mean, look at that thing! It's just evil!!! This gross thing ends up
making any calls to drm_connector_register()/drm_connector_unregister()
impossible when holding any kind of modesetting lock. This is annoying
because ideally, we always want to ensure that
drm_dp_mst_port->connector never changes when doing an atomic commit or
check that would affect the atomic topology state so that it can
reliably and easily be used from future DRM DP MST helpers to assist
with tasks such as scanning through the current VCPI allocations and
adding connectors which need to have their allocations updated in
response to a bandwidth change or the like.
Being able to hold &mgr->base.lock throughout the entire link probe
process would have been _great_, since we could prevent userspace from
ever seeing any states in-between individual port changes and as a
result likely end up with a much faster probe and more consistent
results from said probes. But without some rework of how we handle
connector probing in sysfs it's not at all currently possible. In the
future, maybe we can try using the sysfs locks to protect updates to
connector probing state and fix this mess.
So for now, to protect everything other than port->connector under
&mgr->base.lock and ensure that we still have the guarantee that atomic
check/commit contexts will never see port->connector change we use a
silly trick. See: port->connector only needs to change in order to
ensure that input ports (see the MST spec) never have a ghost connector
associated with them. But, there's nothing stopping us from simply
throwing the entire port out and creating a new one in order to maintain
that requirement while still keeping port->connector consistent across
the lifetime of the port in atomic check/commit contexts. For all
intended purposes this works fine, as we validate ports in any contexts
we care about before using them and as such will end up reporting the
connector as disconnected until it's port's destruction finalizes. So,
we just do that in cases where we detect port->input has transitioned
from true->false. We don't need to worry about the other direction,
since a port without a connector isn't visible to userspace and as such
doesn't need to be protected by &mgr->base.lock until we finish
registering a connector for it.
For updating members of drm_dp_mst_port other than port->connector, we
simply grab &mgr->base.lock in drm_dp_mst_link_probe_work() for already
registered ports, update said members and drop the lock before
potentially registering a connector and probing the link address of it's
children.
Finally, we modify drm_dp_mst_detect_port() to take a modesetting lock
acquisition context in order to acquire &mgr->base.lock under
&connection_mutex and convert all it's users over to using the
.detect_ctx probe hooks.
With that, we finally have well defined locking.
Changes since v4:
* Get rid of port->mutex, stop using connection_mutex and just use our own
modesetting lock - mgr->base.lock. Also, add a probe_lock that comes
before this patch.
* Just throw out ports that get changed from an output to an input, and
replace them with new ports. This lets us ensure that modesetting
contexts never see port->connector go from having a connector to being
NULL.
* Write an extremely detailed explanation of what problems this is
trying to fix, since there's a _lot_ of context here and I honestly
forgot some of it myself a couple times.
* Don't grab mgr->lock when reading port->mstb in
drm_dp_mst_handle_link_address_port(). It's not needed.
Cc: Juston Li <juston.li@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harry Wentland <hwentlan@amd.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Sean Paul <sean@poorly.run>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191022023641.8026-7-lyude@redhat.com
2019-06-17 17:59:29 -04:00
|
|
|
static int
|
2025-01-08 17:19:13 +02:00
|
|
|
mst_connector_detect_ctx(struct drm_connector *_connector,
|
2024-11-20 14:43:10 +02:00
|
|
|
struct drm_modeset_acquire_ctx *ctx, bool force)
|
drm/dp_mst: Protect drm_dp_mst_port members with locking
This is a complicated one. Essentially, there's currently a problem in the MST
core that hasn't really caused any issues that we're aware of (emphasis on "that
we're aware of"): locking.
When we go through and probe the link addresses and path resources in a
topology, we hold no locks when updating ports with said information. The
members I'm referring to in particular are:
- ldps
- ddps
- mcs
- pdt
- dpcd_rev
- num_sdp_streams
- num_sdp_stream_sinks
- available_pbn
- input
- connector
Now that we're handling UP requests asynchronously and will be using some of
the struct members mentioned above in atomic modesetting in the future for
features such as PBN validation, this is going to become a lot more important.
As well, the next few commits that prepare us for and introduce suspend/resume
reprobing will also need clear locking in order to prevent from additional
racing hilarities that we never could have hit in the past.
So, let's solve this issue by using &mgr->base.lock, the modesetting
lock which currently only protects &mgr->base.state. This works
perfectly because it allows us to avoid blocking connection_mutex
unnecessarily, and we can grab this in connector detection paths since
it's a ww mutex. We start by having drm_dp_mst_handle_up_req() hold this
when updating ports. For drm_dp_mst_handle_link_address_port() things
are a bit more complicated. As I've learned the hard way, we can grab
&mgr->lock.base for everything except for port->connector. See, our
normal driver probing paths end up generating this rather obvious
lockdep chain:
&drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
However, sysfs grabs &drm->mode_config.mutex in order to protect itself
from connector state changing under it. Because this entails grabbing
kn->count, e.g. the lock that the kernel provides for protecting sysfs
contexts, we end up grabbing kn->count followed by
&drm->mode_config.mutex. This ends up creating an extremely rude chain:
&kn->count
-> &drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
I mean, look at that thing! It's just evil!!! This gross thing ends up
making any calls to drm_connector_register()/drm_connector_unregister()
impossible when holding any kind of modesetting lock. This is annoying
because ideally, we always want to ensure that
drm_dp_mst_port->connector never changes when doing an atomic commit or
check that would affect the atomic topology state so that it can
reliably and easily be used from future DRM DP MST helpers to assist
with tasks such as scanning through the current VCPI allocations and
adding connectors which need to have their allocations updated in
response to a bandwidth change or the like.
Being able to hold &mgr->base.lock throughout the entire link probe
process would have been _great_, since we could prevent userspace from
ever seeing any states in-between individual port changes and as a
result likely end up with a much faster probe and more consistent
results from said probes. But without some rework of how we handle
connector probing in sysfs it's not at all currently possible. In the
future, maybe we can try using the sysfs locks to protect updates to
connector probing state and fix this mess.
So for now, to protect everything other than port->connector under
&mgr->base.lock and ensure that we still have the guarantee that atomic
check/commit contexts will never see port->connector change we use a
silly trick. See: port->connector only needs to change in order to
ensure that input ports (see the MST spec) never have a ghost connector
associated with them. But, there's nothing stopping us from simply
throwing the entire port out and creating a new one in order to maintain
that requirement while still keeping port->connector consistent across
the lifetime of the port in atomic check/commit contexts. For all
intended purposes this works fine, as we validate ports in any contexts
we care about before using them and as such will end up reporting the
connector as disconnected until it's port's destruction finalizes. So,
we just do that in cases where we detect port->input has transitioned
from true->false. We don't need to worry about the other direction,
since a port without a connector isn't visible to userspace and as such
doesn't need to be protected by &mgr->base.lock until we finish
registering a connector for it.
For updating members of drm_dp_mst_port other than port->connector, we
simply grab &mgr->base.lock in drm_dp_mst_link_probe_work() for already
registered ports, update said members and drop the lock before
potentially registering a connector and probing the link address of it's
children.
Finally, we modify drm_dp_mst_detect_port() to take a modesetting lock
acquisition context in order to acquire &mgr->base.lock under
&connection_mutex and convert all it's users over to using the
.detect_ctx probe hooks.
With that, we finally have well defined locking.
Changes since v4:
* Get rid of port->mutex, stop using connection_mutex and just use our own
modesetting lock - mgr->base.lock. Also, add a probe_lock that comes
before this patch.
* Just throw out ports that get changed from an output to an input, and
replace them with new ports. This lets us ensure that modesetting
contexts never see port->connector go from having a connector to being
NULL.
* Write an extremely detailed explanation of what problems this is
trying to fix, since there's a _lot_ of context here and I honestly
forgot some of it myself a couple times.
* Don't grab mgr->lock when reading port->mstb in
drm_dp_mst_handle_link_address_port(). It's not needed.
Cc: Juston Li <juston.li@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harry Wentland <hwentlan@amd.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Sean Paul <sean@poorly.run>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191022023641.8026-7-lyude@redhat.com
2019-06-17 17:59:29 -04:00
|
|
|
{
|
2025-01-08 17:19:13 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(_connector);
|
2025-01-08 17:19:14 +02:00
|
|
|
struct intel_display *display = to_intel_display(connector);
|
2025-02-28 14:49:30 +02:00
|
|
|
struct intel_dp *intel_dp = connector->mst.dp;
|
drm/dp_mst: Protect drm_dp_mst_port members with locking
This is a complicated one. Essentially, there's currently a problem in the MST
core that hasn't really caused any issues that we're aware of (emphasis on "that
we're aware of"): locking.
When we go through and probe the link addresses and path resources in a
topology, we hold no locks when updating ports with said information. The
members I'm referring to in particular are:
- ldps
- ddps
- mcs
- pdt
- dpcd_rev
- num_sdp_streams
- num_sdp_stream_sinks
- available_pbn
- input
- connector
Now that we're handling UP requests asynchronously and will be using some of
the struct members mentioned above in atomic modesetting in the future for
features such as PBN validation, this is going to become a lot more important.
As well, the next few commits that prepare us for and introduce suspend/resume
reprobing will also need clear locking in order to prevent from additional
racing hilarities that we never could have hit in the past.
So, let's solve this issue by using &mgr->base.lock, the modesetting
lock which currently only protects &mgr->base.state. This works
perfectly because it allows us to avoid blocking connection_mutex
unnecessarily, and we can grab this in connector detection paths since
it's a ww mutex. We start by having drm_dp_mst_handle_up_req() hold this
when updating ports. For drm_dp_mst_handle_link_address_port() things
are a bit more complicated. As I've learned the hard way, we can grab
&mgr->lock.base for everything except for port->connector. See, our
normal driver probing paths end up generating this rather obvious
lockdep chain:
&drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
However, sysfs grabs &drm->mode_config.mutex in order to protect itself
from connector state changing under it. Because this entails grabbing
kn->count, e.g. the lock that the kernel provides for protecting sysfs
contexts, we end up grabbing kn->count followed by
&drm->mode_config.mutex. This ends up creating an extremely rude chain:
&kn->count
-> &drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
I mean, look at that thing! It's just evil!!! This gross thing ends up
making any calls to drm_connector_register()/drm_connector_unregister()
impossible when holding any kind of modesetting lock. This is annoying
because ideally, we always want to ensure that
drm_dp_mst_port->connector never changes when doing an atomic commit or
check that would affect the atomic topology state so that it can
reliably and easily be used from future DRM DP MST helpers to assist
with tasks such as scanning through the current VCPI allocations and
adding connectors which need to have their allocations updated in
response to a bandwidth change or the like.
Being able to hold &mgr->base.lock throughout the entire link probe
process would have been _great_, since we could prevent userspace from
ever seeing any states in-between individual port changes and as a
result likely end up with a much faster probe and more consistent
results from said probes. But without some rework of how we handle
connector probing in sysfs it's not at all currently possible. In the
future, maybe we can try using the sysfs locks to protect updates to
connector probing state and fix this mess.
So for now, to protect everything other than port->connector under
&mgr->base.lock and ensure that we still have the guarantee that atomic
check/commit contexts will never see port->connector change we use a
silly trick. See: port->connector only needs to change in order to
ensure that input ports (see the MST spec) never have a ghost connector
associated with them. But, there's nothing stopping us from simply
throwing the entire port out and creating a new one in order to maintain
that requirement while still keeping port->connector consistent across
the lifetime of the port in atomic check/commit contexts. For all
intended purposes this works fine, as we validate ports in any contexts
we care about before using them and as such will end up reporting the
connector as disconnected until it's port's destruction finalizes. So,
we just do that in cases where we detect port->input has transitioned
from true->false. We don't need to worry about the other direction,
since a port without a connector isn't visible to userspace and as such
doesn't need to be protected by &mgr->base.lock until we finish
registering a connector for it.
For updating members of drm_dp_mst_port other than port->connector, we
simply grab &mgr->base.lock in drm_dp_mst_link_probe_work() for already
registered ports, update said members and drop the lock before
potentially registering a connector and probing the link address of it's
children.
Finally, we modify drm_dp_mst_detect_port() to take a modesetting lock
acquisition context in order to acquire &mgr->base.lock under
&connection_mutex and convert all it's users over to using the
.detect_ctx probe hooks.
With that, we finally have well defined locking.
Changes since v4:
* Get rid of port->mutex, stop using connection_mutex and just use our own
modesetting lock - mgr->base.lock. Also, add a probe_lock that comes
before this patch.
* Just throw out ports that get changed from an output to an input, and
replace them with new ports. This lets us ensure that modesetting
contexts never see port->connector go from having a connector to being
NULL.
* Write an extremely detailed explanation of what problems this is
trying to fix, since there's a _lot_ of context here and I honestly
forgot some of it myself a couple times.
* Don't grab mgr->lock when reading port->mstb in
drm_dp_mst_handle_link_address_port(). It's not needed.
Cc: Juston Li <juston.li@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harry Wentland <hwentlan@amd.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Sean Paul <sean@poorly.run>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191022023641.8026-7-lyude@redhat.com
2019-06-17 17:59:29 -04:00
|
|
|
|
2024-11-11 12:34:02 +02:00
|
|
|
if (!intel_display_device_enabled(display))
|
2020-09-10 19:42:56 +03:00
|
|
|
return connector_status_disconnected;
|
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
if (drm_connector_is_unregistered(&connector->base))
|
drm/dp_mst: Protect drm_dp_mst_port members with locking
This is a complicated one. Essentially, there's currently a problem in the MST
core that hasn't really caused any issues that we're aware of (emphasis on "that
we're aware of"): locking.
When we go through and probe the link addresses and path resources in a
topology, we hold no locks when updating ports with said information. The
members I'm referring to in particular are:
- ldps
- ddps
- mcs
- pdt
- dpcd_rev
- num_sdp_streams
- num_sdp_stream_sinks
- available_pbn
- input
- connector
Now that we're handling UP requests asynchronously and will be using some of
the struct members mentioned above in atomic modesetting in the future for
features such as PBN validation, this is going to become a lot more important.
As well, the next few commits that prepare us for and introduce suspend/resume
reprobing will also need clear locking in order to prevent from additional
racing hilarities that we never could have hit in the past.
So, let's solve this issue by using &mgr->base.lock, the modesetting
lock which currently only protects &mgr->base.state. This works
perfectly because it allows us to avoid blocking connection_mutex
unnecessarily, and we can grab this in connector detection paths since
it's a ww mutex. We start by having drm_dp_mst_handle_up_req() hold this
when updating ports. For drm_dp_mst_handle_link_address_port() things
are a bit more complicated. As I've learned the hard way, we can grab
&mgr->lock.base for everything except for port->connector. See, our
normal driver probing paths end up generating this rather obvious
lockdep chain:
&drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
However, sysfs grabs &drm->mode_config.mutex in order to protect itself
from connector state changing under it. Because this entails grabbing
kn->count, e.g. the lock that the kernel provides for protecting sysfs
contexts, we end up grabbing kn->count followed by
&drm->mode_config.mutex. This ends up creating an extremely rude chain:
&kn->count
-> &drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
I mean, look at that thing! It's just evil!!! This gross thing ends up
making any calls to drm_connector_register()/drm_connector_unregister()
impossible when holding any kind of modesetting lock. This is annoying
because ideally, we always want to ensure that
drm_dp_mst_port->connector never changes when doing an atomic commit or
check that would affect the atomic topology state so that it can
reliably and easily be used from future DRM DP MST helpers to assist
with tasks such as scanning through the current VCPI allocations and
adding connectors which need to have their allocations updated in
response to a bandwidth change or the like.
Being able to hold &mgr->base.lock throughout the entire link probe
process would have been _great_, since we could prevent userspace from
ever seeing any states in-between individual port changes and as a
result likely end up with a much faster probe and more consistent
results from said probes. But without some rework of how we handle
connector probing in sysfs it's not at all currently possible. In the
future, maybe we can try using the sysfs locks to protect updates to
connector probing state and fix this mess.
So for now, to protect everything other than port->connector under
&mgr->base.lock and ensure that we still have the guarantee that atomic
check/commit contexts will never see port->connector change we use a
silly trick. See: port->connector only needs to change in order to
ensure that input ports (see the MST spec) never have a ghost connector
associated with them. But, there's nothing stopping us from simply
throwing the entire port out and creating a new one in order to maintain
that requirement while still keeping port->connector consistent across
the lifetime of the port in atomic check/commit contexts. For all
intended purposes this works fine, as we validate ports in any contexts
we care about before using them and as such will end up reporting the
connector as disconnected until it's port's destruction finalizes. So,
we just do that in cases where we detect port->input has transitioned
from true->false. We don't need to worry about the other direction,
since a port without a connector isn't visible to userspace and as such
doesn't need to be protected by &mgr->base.lock until we finish
registering a connector for it.
For updating members of drm_dp_mst_port other than port->connector, we
simply grab &mgr->base.lock in drm_dp_mst_link_probe_work() for already
registered ports, update said members and drop the lock before
potentially registering a connector and probing the link address of it's
children.
Finally, we modify drm_dp_mst_detect_port() to take a modesetting lock
acquisition context in order to acquire &mgr->base.lock under
&connection_mutex and convert all it's users over to using the
.detect_ctx probe hooks.
With that, we finally have well defined locking.
Changes since v4:
* Get rid of port->mutex, stop using connection_mutex and just use our own
modesetting lock - mgr->base.lock. Also, add a probe_lock that comes
before this patch.
* Just throw out ports that get changed from an output to an input, and
replace them with new ports. This lets us ensure that modesetting
contexts never see port->connector go from having a connector to being
NULL.
* Write an extremely detailed explanation of what problems this is
trying to fix, since there's a _lot_ of context here and I honestly
forgot some of it myself a couple times.
* Don't grab mgr->lock when reading port->mstb in
drm_dp_mst_handle_link_address_port(). It's not needed.
Cc: Juston Li <juston.li@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harry Wentland <hwentlan@amd.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Sean Paul <sean@poorly.run>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191022023641.8026-7-lyude@redhat.com
2019-06-17 17:59:29 -04:00
|
|
|
return connector_status_disconnected;
|
|
|
|
|
2024-12-04 12:21:50 +02:00
|
|
|
if (!intel_display_driver_check_access(display))
|
2025-01-08 17:19:13 +02:00
|
|
|
return connector->base.status;
|
2024-01-04 10:30:05 +02:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
intel_dp_flush_connector_commits(connector);
|
2024-10-25 19:02:52 +03:00
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
return drm_dp_mst_detect_port(&connector->base, ctx, &intel_dp->mst.mgr,
|
2025-02-28 14:49:30 +02:00
|
|
|
connector->mst.port);
|
drm/dp_mst: Protect drm_dp_mst_port members with locking
This is a complicated one. Essentially, there's currently a problem in the MST
core that hasn't really caused any issues that we're aware of (emphasis on "that
we're aware of"): locking.
When we go through and probe the link addresses and path resources in a
topology, we hold no locks when updating ports with said information. The
members I'm referring to in particular are:
- ldps
- ddps
- mcs
- pdt
- dpcd_rev
- num_sdp_streams
- num_sdp_stream_sinks
- available_pbn
- input
- connector
Now that we're handling UP requests asynchronously and will be using some of
the struct members mentioned above in atomic modesetting in the future for
features such as PBN validation, this is going to become a lot more important.
As well, the next few commits that prepare us for and introduce suspend/resume
reprobing will also need clear locking in order to prevent from additional
racing hilarities that we never could have hit in the past.
So, let's solve this issue by using &mgr->base.lock, the modesetting
lock which currently only protects &mgr->base.state. This works
perfectly because it allows us to avoid blocking connection_mutex
unnecessarily, and we can grab this in connector detection paths since
it's a ww mutex. We start by having drm_dp_mst_handle_up_req() hold this
when updating ports. For drm_dp_mst_handle_link_address_port() things
are a bit more complicated. As I've learned the hard way, we can grab
&mgr->lock.base for everything except for port->connector. See, our
normal driver probing paths end up generating this rather obvious
lockdep chain:
&drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
However, sysfs grabs &drm->mode_config.mutex in order to protect itself
from connector state changing under it. Because this entails grabbing
kn->count, e.g. the lock that the kernel provides for protecting sysfs
contexts, we end up grabbing kn->count followed by
&drm->mode_config.mutex. This ends up creating an extremely rude chain:
&kn->count
-> &drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex
I mean, look at that thing! It's just evil!!! This gross thing ends up
making any calls to drm_connector_register()/drm_connector_unregister()
impossible when holding any kind of modesetting lock. This is annoying
because ideally, we always want to ensure that
drm_dp_mst_port->connector never changes when doing an atomic commit or
check that would affect the atomic topology state so that it can
reliably and easily be used from future DRM DP MST helpers to assist
with tasks such as scanning through the current VCPI allocations and
adding connectors which need to have their allocations updated in
response to a bandwidth change or the like.
Being able to hold &mgr->base.lock throughout the entire link probe
process would have been _great_, since we could prevent userspace from
ever seeing any states in-between individual port changes and as a
result likely end up with a much faster probe and more consistent
results from said probes. But without some rework of how we handle
connector probing in sysfs it's not at all currently possible. In the
future, maybe we can try using the sysfs locks to protect updates to
connector probing state and fix this mess.
So for now, to protect everything other than port->connector under
&mgr->base.lock and ensure that we still have the guarantee that atomic
check/commit contexts will never see port->connector change we use a
silly trick. See: port->connector only needs to change in order to
ensure that input ports (see the MST spec) never have a ghost connector
associated with them. But, there's nothing stopping us from simply
throwing the entire port out and creating a new one in order to maintain
that requirement while still keeping port->connector consistent across
the lifetime of the port in atomic check/commit contexts. For all
intended purposes this works fine, as we validate ports in any contexts
we care about before using them and as such will end up reporting the
connector as disconnected until it's port's destruction finalizes. So,
we just do that in cases where we detect port->input has transitioned
from true->false. We don't need to worry about the other direction,
since a port without a connector isn't visible to userspace and as such
doesn't need to be protected by &mgr->base.lock until we finish
registering a connector for it.
For updating members of drm_dp_mst_port other than port->connector, we
simply grab &mgr->base.lock in drm_dp_mst_link_probe_work() for already
registered ports, update said members and drop the lock before
potentially registering a connector and probing the link address of it's
children.
Finally, we modify drm_dp_mst_detect_port() to take a modesetting lock
acquisition context in order to acquire &mgr->base.lock under
&connection_mutex and convert all it's users over to using the
.detect_ctx probe hooks.
With that, we finally have well defined locking.
Changes since v4:
* Get rid of port->mutex, stop using connection_mutex and just use our own
modesetting lock - mgr->base.lock. Also, add a probe_lock that comes
before this patch.
* Just throw out ports that get changed from an output to an input, and
replace them with new ports. This lets us ensure that modesetting
contexts never see port->connector go from having a connector to being
NULL.
* Write an extremely detailed explanation of what problems this is
trying to fix, since there's a _lot_ of context here and I honestly
forgot some of it myself a couple times.
* Don't grab mgr->lock when reading port->mstb in
drm_dp_mst_handle_link_address_port(). It's not needed.
Cc: Juston Li <juston.li@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harry Wentland <hwentlan@amd.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Sean Paul <sean@poorly.run>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191022023641.8026-7-lyude@redhat.com
2019-06-17 17:59:29 -04:00
|
|
|
}
|
|
|
|
|
2024-11-20 14:43:10 +02:00
|
|
|
static const struct drm_connector_helper_funcs mst_connector_helper_funcs = {
|
|
|
|
.get_modes = mst_connector_get_modes,
|
|
|
|
.mode_valid_ctx = mst_connector_mode_valid_ctx,
|
|
|
|
.atomic_best_encoder = mst_connector_atomic_best_encoder,
|
|
|
|
.atomic_check = mst_connector_atomic_check,
|
|
|
|
.detect_ctx = mst_connector_detect_ctx,
|
2014-05-02 14:02:48 +10:00
|
|
|
};
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static void mst_stream_encoder_destroy(struct drm_encoder *encoder)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2019-12-04 20:05:43 +02:00
|
|
|
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(to_intel_encoder(encoder));
|
2014-05-02 14:02:48 +10:00
|
|
|
|
|
|
|
drm_encoder_cleanup(encoder);
|
|
|
|
kfree(intel_mst);
|
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
static const struct drm_encoder_funcs mst_stream_encoder_funcs = {
|
|
|
|
.destroy = mst_stream_encoder_destroy,
|
2014-05-02 14:02:48 +10:00
|
|
|
};
|
|
|
|
|
2024-11-20 14:43:10 +02:00
|
|
|
static bool mst_connector_get_hw_state(struct intel_connector *connector)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2024-11-20 14:43:11 +02:00
|
|
|
/* This is the MST stream encoder set in ->pre_enable, if any */
|
|
|
|
struct intel_encoder *encoder = intel_attached_encoder(connector);
|
|
|
|
enum pipe pipe;
|
|
|
|
|
|
|
|
if (!encoder || !connector->base.state->crtc)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return encoder->get_hw_state(encoder, &pipe);
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
|
|
|
|
2024-11-20 14:43:12 +02:00
|
|
|
static int mst_topology_add_connector_properties(struct intel_dp *intel_dp,
|
2025-01-08 17:19:13 +02:00
|
|
|
struct drm_connector *_connector,
|
2024-11-20 14:43:12 +02:00
|
|
|
const char *pathprop)
|
2022-09-12 14:18:07 +03:00
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(intel_dp);
|
2025-01-08 17:19:13 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(_connector);
|
2022-09-12 14:18:07 +03:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
drm_object_attach_property(&connector->base.base,
|
2024-11-12 13:10:42 +02:00
|
|
|
display->drm->mode_config.path_property, 0);
|
2025-01-08 17:19:13 +02:00
|
|
|
drm_object_attach_property(&connector->base.base,
|
2024-11-12 13:10:42 +02:00
|
|
|
display->drm->mode_config.tile_property, 0);
|
2022-09-12 14:18:07 +03:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
intel_attach_force_audio_property(&connector->base);
|
|
|
|
intel_attach_broadcast_rgb_property(&connector->base);
|
2022-09-12 14:18:07 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Reuse the prop from the SST connector because we're
|
|
|
|
* not allowed to create new props after device registration.
|
|
|
|
*/
|
2025-01-08 17:19:13 +02:00
|
|
|
connector->base.max_bpc_property =
|
2022-09-12 14:18:07 +03:00
|
|
|
intel_dp->attached_connector->base.max_bpc_property;
|
2025-01-08 17:19:13 +02:00
|
|
|
if (connector->base.max_bpc_property)
|
|
|
|
drm_connector_attach_max_bpc_property(&connector->base, 6, 12);
|
2022-09-12 14:18:07 +03:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
return drm_connector_set_path_property(&connector->base, pathprop);
|
2022-09-12 14:18:07 +03:00
|
|
|
}
|
|
|
|
|
2023-10-10 14:25:03 +03:00
|
|
|
static void
|
|
|
|
intel_dp_mst_read_decompression_port_dsc_caps(struct intel_dp *intel_dp,
|
|
|
|
struct intel_connector *connector)
|
|
|
|
{
|
|
|
|
u8 dpcd_caps[DP_RECEIVER_CAP_SIZE];
|
|
|
|
|
|
|
|
if (!connector->dp.dsc_decompression_aux)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (drm_dp_read_dpcd_caps(connector->dp.dsc_decompression_aux, dpcd_caps) < 0)
|
|
|
|
return;
|
|
|
|
|
2023-10-11 20:16:06 +03:00
|
|
|
intel_dp_get_dsc_sink_cap(dpcd_caps[DP_DPCD_REV], connector);
|
2023-10-10 14:25:03 +03:00
|
|
|
}
|
|
|
|
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
static bool detect_dsc_hblank_expansion_quirk(const struct intel_connector *connector)
|
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(connector);
|
2024-04-17 01:10:09 +03:00
|
|
|
struct drm_dp_aux *aux = connector->dp.dsc_decompression_aux;
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
struct drm_dp_desc desc;
|
|
|
|
u8 dpcd[DP_RECEIVER_CAP_SIZE];
|
|
|
|
|
2024-04-17 01:10:09 +03:00
|
|
|
if (!aux)
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
return false;
|
|
|
|
|
2024-04-17 01:10:09 +03:00
|
|
|
/*
|
|
|
|
* A logical port's OUI (at least for affected sinks) is all 0, so
|
|
|
|
* instead of that the parent port's OUI is used for identification.
|
|
|
|
*/
|
2025-02-28 14:49:30 +02:00
|
|
|
if (drm_dp_mst_port_is_logical(connector->mst.port)) {
|
|
|
|
aux = drm_dp_mst_aux_for_parent(connector->mst.port);
|
2024-04-17 01:10:09 +03:00
|
|
|
if (!aux)
|
2025-02-28 14:49:30 +02:00
|
|
|
aux = &connector->mst.dp->aux;
|
2024-04-17 01:10:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (drm_dp_read_dpcd_caps(aux, dpcd) < 0)
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
return false;
|
|
|
|
|
2024-04-17 01:10:09 +03:00
|
|
|
if (drm_dp_read_desc(aux, &desc, drm_dp_is_branch(dpcd)) < 0)
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
return false;
|
|
|
|
|
2024-04-17 01:10:09 +03:00
|
|
|
if (!drm_dp_has_quirk(&desc,
|
|
|
|
DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC))
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
return false;
|
|
|
|
|
2024-04-17 17:22:17 +03:00
|
|
|
/*
|
|
|
|
* UHBR (MST sink) devices requiring this quirk don't advertise the
|
|
|
|
* HBLANK expansion support. Presuming that they perform HBLANK
|
|
|
|
* expansion internally, or are affected by this issue on modes with a
|
|
|
|
* short HBLANK for other reasons.
|
|
|
|
*/
|
|
|
|
if (!drm_dp_128b132b_supported(dpcd) &&
|
|
|
|
!(dpcd[DP_RECEIVE_PORT_0_CAP_0] & DP_HBLANK_EXPANSION_CAPABLE))
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
return false;
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm,
|
drm/i915/dp_mst: Handle the Synaptics HBlank expansion quirk
The Synaptics MST hubs expose some sink EDID modes with a reduced HBLANK
period, presumedly to save BW, which the hub expands before forwarding
the stream to the sink. In particular a 4k mode with a standard CVT
HBLANK period is exposed with either a CVT reduced blank RBv1,v2 (80,
160 pixel) or a non-CVT 56 pixel HBLANK period. The DP standard
describes the above HBLANK expansion functionality, but it requires
enabling this explicitly, whereas these hubs apply the expansion
transparently.
In some TBT docks with such a Synaptics hub (DELL WD22TB4) the above modes
will work okay until DSC decompression is enabled in the hub for the given
sink, but after this the same mode will not work reliably in decompressed
mode. In another TBT dock (Thinkpad 40B0) the above modes will not work
in uncompressed/18bpp mode (regardless of whether DSC decompression was
enabled before or not).
As a workaround force enable DSC for such modes. Apply the WA when the
HBLANK period is 300ns or below, matching the above tested modes with a
533.25MHz dotclock and maximum 160 HBLANK pixels.
OTOH DSC for these modes will only work above a certain compressed bpp
threshold which depends on the link rate, so apply this limit as well
in the workaround.
On platforms, pipe/port configurations where DSC is not supported, for
instance on ICL where DSC/MST is still work-in-progress, limit the
minimum link bpp to 24.
Apply the workaround only for Synaptics hubs which support the HBLANK
expansion.
v2:
- Apply the WA whenever the HBLANK period is 300ns or below.
v3:
- Clarify in the commit log the failure modes of the different docks.
- Handle platforms/pipe/port configurations without DSC support.
Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v1)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231107001505.3370108-4-imre.deak@intel.com
2023-10-24 04:09:16 +03:00
|
|
|
"[CONNECTOR:%d:%s] DSC HBLANK expansion quirk detected\n",
|
|
|
|
connector->base.base.id, connector->base.name);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-11-20 14:43:12 +02:00
|
|
|
static struct drm_connector *
|
|
|
|
mst_topology_add_connector(struct drm_dp_mst_topology_mgr *mgr,
|
|
|
|
struct drm_dp_mst_port *port,
|
|
|
|
const char *pathprop)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2025-02-28 14:49:29 +02:00
|
|
|
struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst.mgr);
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(intel_dp);
|
2020-06-30 21:50:54 -07:00
|
|
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
2025-01-08 17:19:13 +02:00
|
|
|
struct intel_connector *connector;
|
2017-10-13 13:24:46 +03:00
|
|
|
enum pipe pipe;
|
2017-10-13 11:01:44 -07:00
|
|
|
int ret;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
connector = intel_connector_alloc();
|
|
|
|
if (!connector)
|
2014-05-02 14:02:48 +10:00
|
|
|
return NULL;
|
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
connector->get_hw_state = mst_connector_get_hw_state;
|
|
|
|
connector->sync_state = intel_dp_connector_sync_state;
|
2025-02-28 14:49:30 +02:00
|
|
|
connector->mst.dp = intel_dp;
|
|
|
|
connector->mst.port = port;
|
2019-01-10 19:53:33 -05:00
|
|
|
drm_dp_mst_get_port_malloc(port);
|
2018-11-06 16:30:12 -05:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
ret = drm_connector_dynamic_init(display->drm, &connector->base, &mst_connector_funcs,
|
2024-12-12 01:03:22 +02:00
|
|
|
DRM_MODE_CONNECTOR_DisplayPort, NULL);
|
2025-01-08 17:19:12 +02:00
|
|
|
if (ret)
|
|
|
|
goto err_put_port;
|
2017-10-13 11:01:44 -07:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
connector->dp.dsc_decompression_aux = drm_dp_mst_dsc_aux_for_port(port);
|
|
|
|
intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, connector);
|
|
|
|
connector->dp.dsc_hblank_expansion_quirk =
|
|
|
|
detect_dsc_hblank_expansion_quirk(connector);
|
2024-12-12 01:03:22 +02:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
drm_connector_helper_add(&connector->base, &mst_connector_helper_funcs);
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
for_each_pipe(display, pipe) {
|
2017-10-13 11:01:44 -07:00
|
|
|
struct drm_encoder *enc =
|
2025-02-28 14:49:29 +02:00
|
|
|
&intel_dp->mst.stream_encoders[pipe]->base.base;
|
2017-10-13 11:01:44 -07:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
ret = drm_connector_attach_encoder(&connector->base, enc);
|
2017-10-13 11:01:44 -07:00
|
|
|
if (ret)
|
2025-01-08 17:19:12 +02:00
|
|
|
goto err_cleanup_connector;
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
ret = mst_topology_add_connector_properties(intel_dp, &connector->base, pathprop);
|
2017-10-13 11:01:44 -07:00
|
|
|
if (ret)
|
2025-01-08 17:19:12 +02:00
|
|
|
goto err_cleanup_connector;
|
2017-10-13 11:01:44 -07:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
ret = intel_dp_hdcp_init(dig_port, connector);
|
2021-07-05 17:52:08 +05:30
|
|
|
if (ret)
|
2024-11-12 13:10:42 +02:00
|
|
|
drm_dbg_kms(display->drm, "[%s:%d] HDCP MST init failed, skipping.\n",
|
2025-01-08 17:19:13 +02:00
|
|
|
connector->base.name, connector->base.base.id);
|
2019-03-26 16:25:51 +02:00
|
|
|
|
2025-01-08 17:19:13 +02:00
|
|
|
return &connector->base;
|
2017-10-13 11:01:44 -07:00
|
|
|
|
2025-01-08 17:19:12 +02:00
|
|
|
err_cleanup_connector:
|
2025-01-08 17:19:13 +02:00
|
|
|
drm_connector_cleanup(&connector->base);
|
2025-01-08 17:19:12 +02:00
|
|
|
err_put_port:
|
|
|
|
drm_dp_mst_put_port_malloc(port);
|
2025-01-08 17:19:13 +02:00
|
|
|
intel_connector_free(connector);
|
2025-01-08 17:19:12 +02:00
|
|
|
|
2017-10-13 11:01:44 -07:00
|
|
|
return NULL;
|
2015-09-16 17:55:23 +10:00
|
|
|
}
|
|
|
|
|
2020-06-04 21:45:00 +03:00
|
|
|
static void
|
2024-11-20 14:43:12 +02:00
|
|
|
mst_topology_poll_hpd_irq(struct drm_dp_mst_topology_mgr *mgr)
|
2020-06-04 21:45:00 +03:00
|
|
|
{
|
2025-02-28 14:49:29 +02:00
|
|
|
struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst.mgr);
|
2020-06-04 21:45:00 +03:00
|
|
|
|
|
|
|
intel_hpd_trigger_irq(dp_to_dig_port(intel_dp));
|
|
|
|
}
|
|
|
|
|
2024-11-20 14:43:12 +02:00
|
|
|
static const struct drm_dp_mst_topology_cbs mst_topology_cbs = {
|
|
|
|
.add_connector = mst_topology_add_connector,
|
|
|
|
.poll_hpd_irq = mst_topology_poll_hpd_irq,
|
2014-05-02 14:02:48 +10:00
|
|
|
};
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
/* Create a fake encoder for an individual MST stream */
|
2014-05-02 14:02:48 +10:00
|
|
|
static struct intel_dp_mst_encoder *
|
2024-11-12 13:10:43 +02:00
|
|
|
mst_stream_encoder_create(struct intel_digital_port *dig_port, enum pipe pipe)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(dig_port);
|
2024-11-12 13:10:40 +02:00
|
|
|
struct intel_encoder *primary_encoder = &dig_port->base;
|
2014-05-02 14:02:48 +10:00
|
|
|
struct intel_dp_mst_encoder *intel_mst;
|
2024-11-12 13:10:38 +02:00
|
|
|
struct intel_encoder *encoder;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
|
|
|
intel_mst = kzalloc(sizeof(*intel_mst), GFP_KERNEL);
|
|
|
|
|
|
|
|
if (!intel_mst)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
intel_mst->pipe = pipe;
|
2024-11-12 13:10:38 +02:00
|
|
|
encoder = &intel_mst->base;
|
2020-06-30 21:50:54 -07:00
|
|
|
intel_mst->primary = dig_port;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
drm_encoder_init(display->drm, &encoder->base, &mst_stream_encoder_funcs,
|
2016-05-27 20:59:24 +03:00
|
|
|
DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe));
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2024-11-12 13:10:38 +02:00
|
|
|
encoder->type = INTEL_OUTPUT_DP_MST;
|
2024-11-12 13:10:40 +02:00
|
|
|
encoder->power_domain = primary_encoder->power_domain;
|
|
|
|
encoder->port = primary_encoder->port;
|
2024-11-12 13:10:38 +02:00
|
|
|
encoder->cloneable = 0;
|
2019-10-02 19:25:05 +03:00
|
|
|
/*
|
|
|
|
* This is wrong, but broken userspace uses the intersection
|
|
|
|
* of possible_crtcs of all the encoders of a given connector
|
|
|
|
* to figure out which crtcs can drive said connector. What
|
|
|
|
* should be used instead is the union of possible_crtcs.
|
|
|
|
* To keep such userspace functioning we must misconfigure
|
|
|
|
* this to make sure the intersection is not empty :(
|
|
|
|
*/
|
2024-11-12 13:10:38 +02:00
|
|
|
encoder->pipe_mask = ~0;
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
encoder->compute_config = mst_stream_compute_config;
|
|
|
|
encoder->compute_config_late = mst_stream_compute_config_late;
|
|
|
|
encoder->disable = mst_stream_disable;
|
|
|
|
encoder->post_disable = mst_stream_post_disable;
|
|
|
|
encoder->post_pll_disable = mst_stream_post_pll_disable;
|
2024-11-12 13:10:38 +02:00
|
|
|
encoder->update_pipe = intel_ddi_update_pipe;
|
2024-11-12 13:10:43 +02:00
|
|
|
encoder->pre_pll_enable = mst_stream_pre_pll_enable;
|
|
|
|
encoder->pre_enable = mst_stream_pre_enable;
|
|
|
|
encoder->enable = mst_stream_enable;
|
2024-11-12 13:10:38 +02:00
|
|
|
encoder->audio_enable = intel_audio_codec_enable;
|
|
|
|
encoder->audio_disable = intel_audio_codec_disable;
|
2024-11-12 13:10:43 +02:00
|
|
|
encoder->get_hw_state = mst_stream_get_hw_state;
|
|
|
|
encoder->get_config = mst_stream_get_config;
|
|
|
|
encoder->initial_fastset_check = mst_stream_initial_fastset_check;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
|
|
|
return intel_mst;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-11-12 13:10:43 +02:00
|
|
|
/* Create the fake encoders for MST streams */
|
2014-05-02 14:02:48 +10:00
|
|
|
static bool
|
2024-11-12 13:10:43 +02:00
|
|
|
mst_stream_encoders_create(struct intel_digital_port *dig_port)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(dig_port);
|
2020-06-30 21:50:54 -07:00
|
|
|
struct intel_dp *intel_dp = &dig_port->dp;
|
2017-10-13 13:24:46 +03:00
|
|
|
enum pipe pipe;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
for_each_pipe(display, pipe)
|
2025-02-28 14:49:29 +02:00
|
|
|
intel_dp->mst.stream_encoders[pipe] = mst_stream_encoder_create(dig_port, pipe);
|
2014-05-02 14:02:48 +10:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2020-06-30 21:50:54 -07:00
|
|
|
intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_base_id)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2024-11-12 13:10:42 +02:00
|
|
|
struct intel_display *display = to_intel_display(dig_port);
|
2020-06-30 21:50:54 -07:00
|
|
|
struct intel_dp *intel_dp = &dig_port->dp;
|
|
|
|
enum port port = dig_port->base.port;
|
2014-05-02 14:02:48 +10:00
|
|
|
int ret;
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
if (!HAS_DP_MST(display) || intel_dp_is_edp(intel_dp))
|
2019-10-10 18:09:03 -07:00
|
|
|
return 0;
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
if (DISPLAY_VER(display) < 12 && port == PORT_A)
|
2019-10-10 18:09:03 -07:00
|
|
|
return 0;
|
|
|
|
|
2024-11-12 13:10:42 +02:00
|
|
|
if (DISPLAY_VER(display) < 11 && port == PORT_E)
|
2019-10-10 18:09:03 -07:00
|
|
|
return 0;
|
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
intel_dp->mst.mgr.cbs = &mst_topology_cbs;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
|
|
|
/* create encoders */
|
2024-11-12 13:10:43 +02:00
|
|
|
mst_stream_encoders_create(dig_port);
|
2025-02-28 14:49:29 +02:00
|
|
|
ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst.mgr, display->drm,
|
2025-02-26 15:56:26 +02:00
|
|
|
&intel_dp->aux, 16,
|
|
|
|
INTEL_NUM_PIPES(display), conn_base_id);
|
2021-10-06 13:16:18 +03:00
|
|
|
if (ret) {
|
2025-02-28 14:49:29 +02:00
|
|
|
intel_dp->mst.mgr.cbs = NULL;
|
2014-05-02 14:02:48 +10:00
|
|
|
return ret;
|
2021-10-06 13:16:18 +03:00
|
|
|
}
|
2019-10-10 18:09:03 -07:00
|
|
|
|
2014-05-02 14:02:48 +10:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-10-06 13:16:18 +03:00
|
|
|
bool intel_dp_mst_source_support(struct intel_dp *intel_dp)
|
|
|
|
{
|
2025-02-28 14:49:29 +02:00
|
|
|
return intel_dp->mst.mgr.cbs;
|
2021-10-06 13:16:18 +03:00
|
|
|
}
|
|
|
|
|
2014-05-02 14:02:48 +10:00
|
|
|
void
|
2020-06-30 21:50:54 -07:00
|
|
|
intel_dp_mst_encoder_cleanup(struct intel_digital_port *dig_port)
|
2014-05-02 14:02:48 +10:00
|
|
|
{
|
2020-06-30 21:50:54 -07:00
|
|
|
struct intel_dp *intel_dp = &dig_port->dp;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2021-10-06 13:16:18 +03:00
|
|
|
if (!intel_dp_mst_source_support(intel_dp))
|
2014-05-02 14:02:48 +10:00
|
|
|
return;
|
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
drm_dp_mst_topology_mgr_destroy(&intel_dp->mst.mgr);
|
2014-05-02 14:02:48 +10:00
|
|
|
/* encoders will get killed by normal cleanup */
|
2021-10-06 13:16:18 +03:00
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
intel_dp->mst.mgr.cbs = NULL;
|
2014-05-02 14:02:48 +10:00
|
|
|
}
|
2019-12-22 17:06:49 -08:00
|
|
|
|
|
|
|
bool intel_dp_mst_is_master_trans(const struct intel_crtc_state *crtc_state)
|
|
|
|
{
|
|
|
|
return crtc_state->mst_master_transcoder == crtc_state->cpu_transcoder;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state)
|
|
|
|
{
|
|
|
|
return crtc_state->mst_master_transcoder != INVALID_TRANSCODER &&
|
|
|
|
crtc_state->mst_master_transcoder != crtc_state->cpu_transcoder;
|
|
|
|
}
|
2023-02-06 13:48:53 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* intel_dp_mst_add_topology_state_for_connector - add MST topology state for a connector
|
|
|
|
* @state: atomic state
|
|
|
|
* @connector: connector to add the state for
|
|
|
|
* @crtc: the CRTC @connector is attached to
|
|
|
|
*
|
|
|
|
* Add the MST topology state for @connector to @state.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, negative error code on failure.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
intel_dp_mst_add_topology_state_for_connector(struct intel_atomic_state *state,
|
|
|
|
struct intel_connector *connector,
|
|
|
|
struct intel_crtc *crtc)
|
|
|
|
{
|
|
|
|
struct drm_dp_mst_topology_state *mst_state;
|
|
|
|
|
2025-02-28 14:49:30 +02:00
|
|
|
if (!connector->mst.dp)
|
2023-02-06 13:48:53 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
mst_state = drm_atomic_get_mst_topology_state(&state->base,
|
2025-02-28 14:49:30 +02:00
|
|
|
&connector->mst.dp->mst.mgr);
|
2023-02-06 13:48:53 +02:00
|
|
|
if (IS_ERR(mst_state))
|
|
|
|
return PTR_ERR(mst_state);
|
|
|
|
|
|
|
|
mst_state->pending_crtc_mask |= drm_crtc_mask(&crtc->base);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intel_dp_mst_add_topology_state_for_crtc - add MST topology state for a CRTC
|
|
|
|
* @state: atomic state
|
|
|
|
* @crtc: CRTC to add the state for
|
|
|
|
*
|
|
|
|
* Add the MST topology state for @crtc to @state.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, negative error code on failure.
|
|
|
|
*/
|
|
|
|
int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state,
|
|
|
|
struct intel_crtc *crtc)
|
|
|
|
{
|
|
|
|
struct drm_connector *_connector;
|
|
|
|
struct drm_connector_state *conn_state;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for_each_new_connector_in_state(&state->base, _connector, conn_state, i) {
|
|
|
|
struct intel_connector *connector = to_intel_connector(_connector);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (conn_state->crtc != &crtc->base)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = intel_dp_mst_add_topology_state_for_connector(state, connector, crtc);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2023-10-24 04:09:22 +03:00
|
|
|
|
|
|
|
static struct intel_connector *
|
|
|
|
get_connector_in_state_for_crtc(struct intel_atomic_state *state,
|
|
|
|
const struct intel_crtc *crtc)
|
|
|
|
{
|
|
|
|
struct drm_connector_state *old_conn_state;
|
|
|
|
struct drm_connector_state *new_conn_state;
|
|
|
|
struct drm_connector *_connector;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for_each_oldnew_connector_in_state(&state->base, _connector,
|
|
|
|
old_conn_state, new_conn_state, i) {
|
|
|
|
struct intel_connector *connector =
|
|
|
|
to_intel_connector(_connector);
|
|
|
|
|
|
|
|
if (old_conn_state->crtc == &crtc->base ||
|
|
|
|
new_conn_state->crtc == &crtc->base)
|
|
|
|
return connector;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intel_dp_mst_crtc_needs_modeset - check if changes in topology need to modeset the given CRTC
|
|
|
|
* @state: atomic state
|
|
|
|
* @crtc: CRTC for which to check the modeset requirement
|
|
|
|
*
|
|
|
|
* Check if any change in a MST topology requires a forced modeset on @crtc in
|
|
|
|
* this topology. One such change is enabling/disabling the DSC decompression
|
|
|
|
* state in the first branch device's UFP DPCD as required by one CRTC, while
|
|
|
|
* the other @crtc in the same topology is still active, requiring a full modeset
|
|
|
|
* on @crtc.
|
|
|
|
*/
|
|
|
|
bool intel_dp_mst_crtc_needs_modeset(struct intel_atomic_state *state,
|
|
|
|
struct intel_crtc *crtc)
|
|
|
|
{
|
|
|
|
const struct intel_connector *crtc_connector;
|
|
|
|
const struct drm_connector_state *conn_state;
|
|
|
|
const struct drm_connector *_connector;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!intel_crtc_has_type(intel_atomic_get_new_crtc_state(state, crtc),
|
|
|
|
INTEL_OUTPUT_DP_MST))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
crtc_connector = get_connector_in_state_for_crtc(state, crtc);
|
|
|
|
|
|
|
|
if (!crtc_connector)
|
|
|
|
/* None of the connectors in the topology needs modeset */
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for_each_new_connector_in_state(&state->base, _connector, conn_state, i) {
|
|
|
|
const struct intel_connector *connector =
|
|
|
|
to_intel_connector(_connector);
|
|
|
|
const struct intel_crtc_state *new_crtc_state;
|
|
|
|
const struct intel_crtc_state *old_crtc_state;
|
|
|
|
struct intel_crtc *crtc_iter;
|
|
|
|
|
2025-02-28 14:49:30 +02:00
|
|
|
if (connector->mst.dp != crtc_connector->mst.dp ||
|
2023-10-24 04:09:22 +03:00
|
|
|
!conn_state->crtc)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
crtc_iter = to_intel_crtc(conn_state->crtc);
|
|
|
|
|
|
|
|
new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc_iter);
|
|
|
|
old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc_iter);
|
|
|
|
|
|
|
|
if (!intel_crtc_needs_modeset(new_crtc_state))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (old_crtc_state->dsc.compression_enable ==
|
|
|
|
new_crtc_state->dsc.compression_enable)
|
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* Toggling the decompression flag because of this stream in
|
|
|
|
* the first downstream branch device's UFP DPCD may reset the
|
|
|
|
* whole branch device. To avoid the reset while other streams
|
|
|
|
* are also active modeset the whole MST topology in this
|
|
|
|
* case.
|
|
|
|
*/
|
|
|
|
if (connector->dp.dsc_decompression_aux ==
|
2025-02-28 14:49:30 +02:00
|
|
|
&connector->mst.dp->aux)
|
2023-10-24 04:09:22 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2024-07-22 19:55:02 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* intel_dp_mst_prepare_probe - Prepare an MST link for topology probing
|
|
|
|
* @intel_dp: DP port object
|
|
|
|
*
|
|
|
|
* Prepare an MST link for topology probing, programming the target
|
2025-01-20 13:45:16 +05:30
|
|
|
* link parameters to DPCD. This step is a requirement of the enumeration
|
2024-07-22 19:55:02 +03:00
|
|
|
* of path resources during probing.
|
|
|
|
*/
|
|
|
|
void intel_dp_mst_prepare_probe(struct intel_dp *intel_dp)
|
|
|
|
{
|
|
|
|
int link_rate = intel_dp_max_link_rate(intel_dp);
|
|
|
|
int lane_count = intel_dp_max_lane_count(intel_dp);
|
|
|
|
u8 rate_select;
|
|
|
|
u8 link_bw;
|
|
|
|
|
2025-04-04 18:03:05 +03:00
|
|
|
if (intel_dp->link.active)
|
2024-07-22 19:55:02 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (intel_mst_probed_link_params_valid(intel_dp, link_rate, lane_count))
|
|
|
|
return;
|
|
|
|
|
|
|
|
intel_dp_compute_rate(intel_dp, link_rate, &link_bw, &rate_select);
|
|
|
|
|
|
|
|
intel_dp_link_training_set_mode(intel_dp, link_rate, false);
|
|
|
|
intel_dp_link_training_set_bw(intel_dp, link_bw, rate_select, lane_count,
|
|
|
|
drm_dp_enhanced_frame_cap(intel_dp->dpcd));
|
|
|
|
|
|
|
|
intel_mst_set_probed_link_params(intel_dp, link_rate, lane_count);
|
|
|
|
}
|
2024-08-23 19:29:18 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* intel_dp_mst_verify_dpcd_state - verify the MST SW enabled state wrt. the DPCD
|
|
|
|
* @intel_dp: DP port object
|
|
|
|
*
|
|
|
|
* Verify if @intel_dp's MST enabled SW state matches the corresponding DPCD
|
|
|
|
* state. A long HPD pulse - not long enough to be detected as a disconnected
|
|
|
|
* state - could've reset the DPCD state, which requires tearing
|
|
|
|
* down/recreating the MST topology.
|
|
|
|
*
|
|
|
|
* Returns %true if the SW MST enabled and DPCD states match, %false
|
|
|
|
* otherwise.
|
|
|
|
*/
|
|
|
|
bool intel_dp_mst_verify_dpcd_state(struct intel_dp *intel_dp)
|
|
|
|
{
|
|
|
|
struct intel_display *display = to_intel_display(intel_dp);
|
|
|
|
struct intel_connector *connector = intel_dp->attached_connector;
|
|
|
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
|
|
|
struct intel_encoder *encoder = &dig_port->base;
|
|
|
|
int ret;
|
|
|
|
u8 val;
|
|
|
|
|
|
|
|
if (!intel_dp->is_mst)
|
|
|
|
return true;
|
|
|
|
|
2025-02-28 14:49:29 +02:00
|
|
|
ret = drm_dp_dpcd_readb(intel_dp->mst.mgr.aux, DP_MSTM_CTRL, &val);
|
2024-08-23 19:29:18 +03:00
|
|
|
|
|
|
|
/* Adjust the expected register value for SST + SideBand. */
|
|
|
|
if (ret < 0 || val != (DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC)) {
|
|
|
|
drm_dbg_kms(display->drm,
|
|
|
|
"[CONNECTOR:%d:%s][ENCODER:%d:%s] MST mode got reset, removing topology (ret=%d, ctrl=0x%02x)\n",
|
|
|
|
connector->base.base.id, connector->base.name,
|
|
|
|
encoder->base.base.id, encoder->base.name,
|
|
|
|
ret, val);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|