summaryrefslogtreecommitdiff
path: root/sys-kernel/linux-sources-redcore/files/5.13-Intel-i915-backport-MSO-fixes-to-kernel-5.12.patch
diff options
context:
space:
mode:
Diffstat (limited to 'sys-kernel/linux-sources-redcore/files/5.13-Intel-i915-backport-MSO-fixes-to-kernel-5.12.patch')
-rw-r--r--sys-kernel/linux-sources-redcore/files/5.13-Intel-i915-backport-MSO-fixes-to-kernel-5.12.patch461
1 files changed, 461 insertions, 0 deletions
diff --git a/sys-kernel/linux-sources-redcore/files/5.13-Intel-i915-backport-MSO-fixes-to-kernel-5.12.patch b/sys-kernel/linux-sources-redcore/files/5.13-Intel-i915-backport-MSO-fixes-to-kernel-5.12.patch
new file mode 100644
index 00000000..b0440c04
--- /dev/null
+++ b/sys-kernel/linux-sources-redcore/files/5.13-Intel-i915-backport-MSO-fixes-to-kernel-5.12.patch
@@ -0,0 +1,461 @@
+diff -Naur linux-5.12/drivers/gpu/drm/i915/display/intel_ddi.c linux-5.12-p/drivers/gpu/drm/i915/display/intel_ddi.c
+--- linux-5.12/drivers/gpu/drm/i915/display/intel_ddi.c 2021-04-25 22:49:08.000000000 +0200
++++ linux-5.12-p/drivers/gpu/drm/i915/display/intel_ddi.c 2021-04-29 21:14:27.250013980 +0200
+@@ -3638,6 +3638,73 @@
+ }
+ }
+
++static void intel_ddi_mso_get_config(struct intel_encoder *encoder,
++ struct intel_crtc_state *pipe_config)
++{
++ struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
++ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
++ enum pipe pipe = crtc->pipe;
++ u32 dss1;
++
++ if (!HAS_MSO(i915))
++ return;
++
++ dss1 = intel_de_read(i915, ICL_PIPE_DSS_CTL1(pipe));
++
++ pipe_config->splitter.enable = dss1 & SPLITTER_ENABLE;
++ if (!pipe_config->splitter.enable)
++ return;
++
++ /* Splitter enable is supported for pipe A only. */
++ if (drm_WARN_ON(&i915->drm, pipe != PIPE_A)) {
++ pipe_config->splitter.enable = false;
++ return;
++ }
++
++ switch (dss1 & SPLITTER_CONFIGURATION_MASK) {
++ default:
++ drm_WARN(&i915->drm, true,
++ "Invalid splitter configuration, dss1=0x%08x\n", dss1);
++ fallthrough;
++ case SPLITTER_CONFIGURATION_2_SEGMENT:
++ pipe_config->splitter.link_count = 2;
++ break;
++ case SPLITTER_CONFIGURATION_4_SEGMENT:
++ pipe_config->splitter.link_count = 4;
++ break;
++ }
++
++ pipe_config->splitter.pixel_overlap = REG_FIELD_GET(OVERLAP_PIXELS_MASK, dss1);
++}
++
++static void intel_ddi_mso_configure(const struct intel_crtc_state *crtc_state)
++{
++ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
++ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
++ enum pipe pipe = crtc->pipe;
++ u32 dss1 = 0;
++
++ if (!HAS_MSO(i915))
++ return;
++
++ if (crtc_state->splitter.enable) {
++ /* Splitter enable is supported for pipe A only. */
++ if (drm_WARN_ON(&i915->drm, pipe != PIPE_A))
++ return;
++
++ dss1 |= SPLITTER_ENABLE;
++ dss1 |= OVERLAP_PIXELS(crtc_state->splitter.pixel_overlap);
++ if (crtc_state->splitter.link_count == 2)
++ dss1 |= SPLITTER_CONFIGURATION_2_SEGMENT;
++ else
++ dss1 |= SPLITTER_CONFIGURATION_4_SEGMENT;
++ }
++
++ intel_de_rmw(i915, ICL_PIPE_DSS_CTL1(pipe),
++ SPLITTER_ENABLE | SPLITTER_CONFIGURATION_MASK |
++ OVERLAP_PIXELS_MASK, dss1);
++}
++
+ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
+ struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+@@ -3732,6 +3799,11 @@
+ intel_ddi_power_up_lanes(encoder, crtc_state);
+
+ /*
++ * 7.g Program CoG/MSO configuration bits in DSS_CTL1 if selected.
++ */
++ intel_ddi_mso_configure(crtc_state);
++
++ /*
+ * 7.g Configure and enable DDI_BUF_CTL
+ * 7.h Wait for DDI_BUF_CTL DDI Idle Status = 0b (Not Idle), timeout
+ * after 500 us.
+@@ -4828,6 +4900,8 @@
+ intel_ddi_read_func_ctl(encoder, pipe_config);
+ }
+
++ intel_ddi_mso_get_config(encoder, pipe_config);
++
+ pipe_config->has_audio =
+ intel_ddi_is_audio_enabled(dev_priv, cpu_transcoder);
+
+@@ -5612,6 +5686,10 @@
+ goto err;
+
+ dig_port->hpd_pulse = intel_dp_hpd_pulse;
++
++ /* Splitter enable for eDP MSO is supported for pipe A only. */
++ if (dig_port->dp.mso_link_count)
++ encoder->pipe_mask = BIT(PIPE_A);
+ }
+
+ /* In theory we don't need the encoder->type check, but leave it just in
+diff -Naur linux-5.12/drivers/gpu/drm/i915/display/intel_display.c linux-5.12-p/drivers/gpu/drm/i915/display/intel_display.c
+--- linux-5.12/drivers/gpu/drm/i915/display/intel_display.c 2021-04-25 22:49:08.000000000 +0200
++++ linux-5.12-p/drivers/gpu/drm/i915/display/intel_display.c 2021-04-29 21:14:27.253013937 +0200
+@@ -6380,8 +6380,30 @@
+ pipe_mode->crtc_clock /= 2;
+ }
+
+- intel_mode_from_crtc_timings(pipe_mode, pipe_mode);
+- intel_mode_from_crtc_timings(adjusted_mode, adjusted_mode);
++ if (crtc_state->splitter.enable) {
++ int n = crtc_state->splitter.link_count;
++ int overlap = crtc_state->splitter.pixel_overlap;
++
++ /*
++ * eDP MSO uses segment timings from EDID for transcoder
++ * timings, but full mode for everything else.
++ *
++ * h_full = (h_segment - pixel_overlap) * link_count
++ */
++ pipe_mode->crtc_hdisplay = (pipe_mode->crtc_hdisplay - overlap) * n;
++ pipe_mode->crtc_hblank_start = (pipe_mode->crtc_hblank_start - overlap) * n;
++ pipe_mode->crtc_hblank_end = (pipe_mode->crtc_hblank_end - overlap) * n;
++ pipe_mode->crtc_hsync_start = (pipe_mode->crtc_hsync_start - overlap) * n;
++ pipe_mode->crtc_hsync_end = (pipe_mode->crtc_hsync_end - overlap) * n;
++ pipe_mode->crtc_htotal = (pipe_mode->crtc_htotal - overlap) * n;
++ pipe_mode->crtc_clock *= n;
++
++ intel_mode_from_crtc_timings(pipe_mode, pipe_mode);
++ intel_mode_from_crtc_timings(adjusted_mode, pipe_mode);
++ } else {
++ intel_mode_from_crtc_timings(pipe_mode, pipe_mode);
++ intel_mode_from_crtc_timings(adjusted_mode, adjusted_mode);
++ }
+
+ intel_crtc_compute_pixel_rate(crtc_state);
+
+@@ -6419,6 +6441,19 @@
+ pipe_config->pipe_src_w /= 2;
+ }
+
++ if (pipe_config->splitter.enable) {
++ int n = pipe_config->splitter.link_count;
++ int overlap = pipe_config->splitter.pixel_overlap;
++
++ pipe_mode->crtc_hdisplay = (pipe_mode->crtc_hdisplay - overlap) * n;
++ pipe_mode->crtc_hblank_start = (pipe_mode->crtc_hblank_start - overlap) * n;
++ pipe_mode->crtc_hblank_end = (pipe_mode->crtc_hblank_end - overlap) * n;
++ pipe_mode->crtc_hsync_start = (pipe_mode->crtc_hsync_start - overlap) * n;
++ pipe_mode->crtc_hsync_end = (pipe_mode->crtc_hsync_end - overlap) * n;
++ pipe_mode->crtc_htotal = (pipe_mode->crtc_htotal - overlap) * n;
++ pipe_mode->crtc_clock *= n;
++ }
++
+ intel_mode_from_crtc_timings(pipe_mode, pipe_mode);
+
+ if (INTEL_GEN(dev_priv) < 4) {
+@@ -10295,6 +10330,11 @@
+ pipe_config->bigjoiner_slave ? "slave" :
+ pipe_config->bigjoiner ? "master" : "no");
+
++ drm_dbg_kms(&dev_priv->drm, "splitter: %s, link count %d, overlap %d\n",
++ enableddisabled(pipe_config->splitter.enable),
++ pipe_config->splitter.link_count,
++ pipe_config->splitter.pixel_overlap);
++
+ if (pipe_config->has_pch_encoder)
+ intel_dump_m_n_config(pipe_config, "fdi",
+ pipe_config->fdi_lanes,
+@@ -11335,6 +11375,10 @@
+ PIPE_CONF_CHECK_I(dsc.dsc_split);
+ PIPE_CONF_CHECK_I(dsc.compressed_bpp);
+
++ PIPE_CONF_CHECK_BOOL(splitter.enable);
++ PIPE_CONF_CHECK_I(splitter.link_count);
++ PIPE_CONF_CHECK_I(splitter.pixel_overlap);
++
+ PIPE_CONF_CHECK_I(mst_master_transcoder);
+
+ PIPE_CONF_CHECK_BOOL(vrr.enable);
+diff -Naur linux-5.12/drivers/gpu/drm/i915/display/intel_display_types.h linux-5.12-p/drivers/gpu/drm/i915/display/intel_display_types.h
+--- linux-5.12/drivers/gpu/drm/i915/display/intel_display_types.h 2021-04-25 22:49:08.000000000 +0200
++++ linux-5.12-p/drivers/gpu/drm/i915/display/intel_display_types.h 2021-04-29 21:14:27.244014066 +0200
+@@ -1159,6 +1159,13 @@
+ u8 pipeline_full;
+ u16 flipline, vmin, vmax;
+ } vrr;
++
++ /* Stream Splitter for eDP MSO */
++ struct {
++ bool enable;
++ u8 link_count;
++ u8 pixel_overlap;
++ } splitter;
+ };
+
+ enum intel_pipe_crc_source {
+@@ -1448,6 +1455,8 @@
+ int max_link_lane_count;
+ /* Max rate for the current link */
+ int max_link_rate;
++ int mso_link_count;
++ int mso_pixel_overlap;
+ /* sink or branch descriptor */
+ struct drm_dp_desc desc;
+ struct drm_dp_aux aux;
+diff -Naur linux-5.12/drivers/gpu/drm/i915/display/intel_dp.c linux-5.12-p/drivers/gpu/drm/i915/display/intel_dp.c
+--- linux-5.12/drivers/gpu/drm/i915/display/intel_dp.c 2021-04-25 22:49:08.000000000 +0200
++++ linux-5.12-p/drivers/gpu/drm/i915/display/intel_dp.c 2021-04-29 21:14:27.254013923 +0200
+@@ -1724,6 +1724,7 @@
+ {
+ struct intel_connector *intel_connector = intel_dp->attached_connector;
+ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
++ int pixel_clock;
+
+ if (pipe_config->vrr.enable)
+ return;
+@@ -1742,10 +1743,18 @@
+ return;
+
+ pipe_config->has_drrs = true;
+- intel_link_compute_m_n(output_bpp, pipe_config->lane_count,
+- intel_connector->panel.downclock_mode->clock,
++
++ pixel_clock = intel_connector->panel.downclock_mode->clock;
++ if (pipe_config->splitter.enable)
++ pixel_clock /= pipe_config->splitter.link_count;
++
++ intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock,
+ pipe_config->port_clock, &pipe_config->dp_m2_n2,
+ constant_n, pipe_config->fec_enable);
++
++ /* FIXME: abstract this better */
++ if (pipe_config->splitter.enable)
++ pipe_config->dp_m2_n2.gmch_m *= pipe_config->splitter.link_count;
+ }
+
+ int
+@@ -1820,6 +1829,26 @@
+ output_bpp = intel_dp_output_bpp(pipe_config->output_format,
+ pipe_config->pipe_bpp);
+
++ if (intel_dp->mso_link_count) {
++ int n = intel_dp->mso_link_count;
++ int overlap = intel_dp->mso_pixel_overlap;
++
++ pipe_config->splitter.enable = true;
++ pipe_config->splitter.link_count = n;
++ pipe_config->splitter.pixel_overlap = overlap;
++
++ drm_dbg_kms(&dev_priv->drm, "MSO link count %d, pixel overlap %d\n",
++ n, overlap);
++
++ adjusted_mode->crtc_hdisplay = adjusted_mode->crtc_hdisplay / n + overlap;
++ adjusted_mode->crtc_hblank_start = adjusted_mode->crtc_hblank_start / n + overlap;
++ adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_end / n + overlap;
++ adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hsync_start / n + overlap;
++ adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_end / n + overlap;
++ adjusted_mode->crtc_htotal = adjusted_mode->crtc_htotal / n + overlap;
++ adjusted_mode->crtc_clock /= n;
++ }
++
+ intel_link_compute_m_n(output_bpp,
+ pipe_config->lane_count,
+ adjusted_mode->crtc_clock,
+@@ -1827,6 +1856,10 @@
+ &pipe_config->dp_m_n,
+ constant_n, pipe_config->fec_enable);
+
++ /* FIXME: abstract this better */
++ if (pipe_config->splitter.enable)
++ pipe_config->dp_m_n.gmch_m *= pipe_config->splitter.link_count;
++
+ if (!HAS_DDI(dev_priv))
+ intel_dp_set_clock(encoder, pipe_config);
+
+@@ -3517,6 +3550,64 @@
+ }
+ }
+
++static void intel_edp_mso_mode_fixup(struct intel_connector *connector,
++ struct drm_display_mode *mode)
++{
++ struct intel_dp *intel_dp = intel_attached_dp(connector);
++ struct drm_i915_private *i915 = to_i915(connector->base.dev);
++ int n = intel_dp->mso_link_count;
++ int overlap = intel_dp->mso_pixel_overlap;
++
++ if (!mode || !n)
++ return;
++
++ mode->hdisplay = (mode->hdisplay - overlap) * n;
++ mode->hsync_start = (mode->hsync_start - overlap) * n;
++ mode->hsync_end = (mode->hsync_end - overlap) * n;
++ mode->htotal = (mode->htotal - overlap) * n;
++ mode->clock *= n;
++
++ drm_mode_set_name(mode);
++
++ drm_dbg_kms(&i915->drm,
++ "[CONNECTOR:%d:%s] using generated MSO mode: ",
++ connector->base.base.id, connector->base.name);
++ drm_mode_debug_printmodeline(mode);
++}
++
++static void intel_edp_mso_init(struct intel_dp *intel_dp)
++{
++ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
++ u8 mso;
++
++ if (intel_dp->edp_dpcd[0] < DP_EDP_14)
++ return;
++
++ if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_MSO_LINK_CAPABILITIES, &mso) != 1) {
++ drm_err(&i915->drm, "Failed to read MSO cap\n");
++ return;
++ }
++
++ /* Valid configurations are SST or MSO 2x1, 2x2, 4x1 */
++ mso &= DP_EDP_MSO_NUMBER_OF_LINKS_MASK;
++ if (mso % 2 || mso > drm_dp_max_lane_count(intel_dp->dpcd)) {
++ drm_err(&i915->drm, "Invalid MSO link count cap %u\n", mso);
++ mso = 0;
++ }
++
++ if (mso) {
++ drm_dbg_kms(&i915->drm, "Sink MSO %ux%u configuration\n",
++ mso, drm_dp_max_lane_count(intel_dp->dpcd) / mso);
++ if (!HAS_MSO(i915)) {
++ drm_err(&i915->drm, "No source MSO support, disabling\n");
++ mso = 0;
++ }
++ }
++
++ intel_dp->mso_link_count = mso;
++ intel_dp->mso_pixel_overlap = 0; /* FIXME: read from DisplayID v2.0 */
++}
++
+ static bool
+ intel_edp_init_dpcd(struct intel_dp *intel_dp)
+ {
+@@ -3600,6 +3691,8 @@
+ */
+ intel_edp_init_source_oui(intel_dp, true);
+
++ intel_edp_mso_init(intel_dp);
++
+ return true;
+ }
+
+@@ -5546,19 +5639,18 @@
+ {
+ struct intel_connector *intel_connector = to_intel_connector(connector);
+ struct edid *edid;
++ int num_modes = 0;
+
+ edid = intel_connector->detect_edid;
+ if (edid) {
+- int ret = intel_connector_update_modes(connector, edid);
++ num_modes = intel_connector_update_modes(connector, edid);
+
+ if (intel_vrr_is_capable(connector))
+ drm_connector_set_vrr_capable_property(connector,
+ true);
+- if (ret)
+- return ret;
+ }
+
+- /* if eDP has no EDID, fall back to fixed mode */
++ /* Also add fixed mode, which may or may not be present in EDID */
+ if (intel_dp_is_edp(intel_attached_dp(intel_connector)) &&
+ intel_connector->panel.fixed_mode) {
+ struct drm_display_mode *mode;
+@@ -5567,10 +5659,13 @@
+ intel_connector->panel.fixed_mode);
+ if (mode) {
+ drm_mode_probed_add(connector, mode);
+- return 1;
++ num_modes++;
+ }
+ }
+
++ if (num_modes)
++ return num_modes;
++
+ if (!edid) {
+ struct intel_dp *intel_dp = intel_attached_dp(intel_connector);
+ struct drm_display_mode *mode;
+@@ -5580,11 +5675,11 @@
+ intel_dp->downstream_ports);
+ if (mode) {
+ drm_mode_probed_add(connector, mode);
+- return 1;
++ num_modes++;
+ }
+ }
+
+- return 0;
++ return num_modes;
+ }
+
+ static int
+@@ -6457,6 +6552,10 @@
+ if (fixed_mode)
+ downclock_mode = intel_dp_drrs_init(intel_connector, fixed_mode);
+
++ /* multiply the mode clock and horizontal timings for MSO */
++ intel_edp_mso_mode_fixup(intel_connector, fixed_mode);
++ intel_edp_mso_mode_fixup(intel_connector, downclock_mode);
++
+ /* fallback to VBT if available for eDP */
+ if (!fixed_mode)
+ fixed_mode = intel_panel_vbt_fixed_mode(intel_connector);
+diff -Naur linux-5.12/drivers/gpu/drm/i915/i915_drv.h linux-5.12-p/drivers/gpu/drm/i915/i915_drv.h
+--- linux-5.12/drivers/gpu/drm/i915/i915_drv.h 2021-04-25 22:49:08.000000000 +0200
++++ linux-5.12-p/drivers/gpu/drm/i915/i915_drv.h 2021-04-29 21:14:27.244014066 +0200
+@@ -1718,6 +1718,8 @@
+
+ #define HAS_CSR(dev_priv) (INTEL_INFO(dev_priv)->display.has_csr)
+
++#define HAS_MSO(i915) (INTEL_GEN(i915) >= 12)
++
+ #define HAS_RUNTIME_PM(dev_priv) (INTEL_INFO(dev_priv)->has_runtime_pm)
+ #define HAS_64BIT_RELOC(dev_priv) (INTEL_INFO(dev_priv)->has_64bit_reloc)
+
+diff -Naur linux-5.12/drivers/gpu/drm/i915/i915_reg.h linux-5.12-p/drivers/gpu/drm/i915/i915_reg.h
+--- linux-5.12/drivers/gpu/drm/i915/i915_reg.h 2021-04-25 22:49:08.000000000 +0200
++++ linux-5.12-p/drivers/gpu/drm/i915/i915_reg.h 2021-04-29 21:14:27.239014138 +0200
+@@ -11427,6 +11427,9 @@
+ #define BIG_JOINER_ENABLE (1 << 29)
+ #define MASTER_BIG_JOINER_ENABLE (1 << 28)
+ #define VGA_CENTERING_ENABLE (1 << 27)
++#define SPLITTER_CONFIGURATION_MASK REG_GENMASK(26, 25)
++#define SPLITTER_CONFIGURATION_2_SEGMENT REG_FIELD_PREP(SPLITTER_CONFIGURATION_MASK, 0)
++#define SPLITTER_CONFIGURATION_4_SEGMENT REG_FIELD_PREP(SPLITTER_CONFIGURATION_MASK, 1)
+
+ #define _ICL_PIPE_DSS_CTL2_PB 0x78204
+ #define _ICL_PIPE_DSS_CTL2_PC 0x78404
+diff -Naur linux-5.12/include/drm/drm_dp_helper.h linux-5.12-p/include/drm/drm_dp_helper.h
+--- linux-5.12/include/drm/drm_dp_helper.h 2021-04-25 22:49:08.000000000 +0200
++++ linux-5.12-p/include/drm/drm_dp_helper.h 2021-04-29 21:14:27.233014224 +0200
+@@ -1016,6 +1016,11 @@
+ #define DP_EDP_REGIONAL_BACKLIGHT_BASE 0x740 /* eDP 1.4 */
+ #define DP_EDP_REGIONAL_BACKLIGHT_0 0x741 /* eDP 1.4 */
+
++#define DP_EDP_MSO_LINK_CAPABILITIES 0x7a4 /* eDP 1.4 */
++# define DP_EDP_MSO_NUMBER_OF_LINKS_MASK (7 << 0)
++# define DP_EDP_MSO_NUMBER_OF_LINKS_SHIFT 0
++# define DP_EDP_MSO_INDEPENDENT_LINK_BIT (1 << 3)
++
+ /* Sideband MSG Buffers */
+ #define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000 /* 1.2 MST */
+ #define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200 /* 1.2 MST */