[PATCH 3/4] drm/i915/display: Add bits for Wa_14021768792 for linkm/n ratio > 10
To support Link M/N ratio between 10.0 and 15.0, for some BMG ultrajoiner cases we need Wa_14021768792. To bypass the hardware limitation within the Timing Generator DDA (TGDDA), we need to program the LINKM and LINKN registers as defined in the WA. Along with this we also need relvant bits in HDMI_EMP_DATA and CHICKEN_TRANS regs. Add the bits for the WA and a new member 'bmg_bypass_m_n_ratio_limit' to track if we need to bypass the Link M/N ratio limit in intel_link_m_n structure. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_display.c | 117 +- .../drm/i915/display/intel_display_types.h| 2 + drivers/gpu/drm/i915/i915_reg.h | 5 + 3 files changed, 118 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index c50dce9afd9b..8a6b9196ef9b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2606,6 +2606,20 @@ void intel_zero_m_n(struct intel_link_m_n *m_n) m_n->tu = 1; } +static +u8 bmg_get_link_n_ext(const struct intel_link_m_n *m_n) +{ + int m_n_ratio, m_n_frac; + + if (!m_n->link_n) + return 0; + + m_n_ratio = DIV_ROUND_UP(m_n->link_m, m_n->link_n); + m_n_frac = m_n->link_m % m_n->link_n; + + return m_n_ratio + (m_n_frac > 0 ? 1 : 0); +} + void intel_set_m_n(struct intel_display *display, const struct intel_link_m_n *m_n, i915_reg_t data_m_reg, i915_reg_t data_n_reg, @@ -2617,7 +2631,9 @@ void intel_set_m_n(struct intel_display *display, intel_de_write(display, data_n_reg, m_n->data_n); intel_de_write(display, link_m_reg, m_n->link_m); - if (DISPLAY_VER(display) >= 14) + if (DISPLAY_VER(display) >= 14 && m_n->bypass_m_n_ratio_limit) + link_n |= PIPE_LINK_N1_EXTENDED(bmg_get_link_n_ext(m_n)); + else if (DISPLAY_VER(display) >= 14) link_n &= ~PIPE_LINK_N1_EXTENDED_MASK; else link_n &= DATA_LINK_M_N_MASK; @@ -2638,6 +2654,24 @@ bool intel_cpu_transcoder_has_m2_n2(struct intel_display *display, return IS_DISPLAY_VER(display, 5, 7) || display->platform.cherryview; } +static +void bmg_bypass_m_n_limit_write(struct intel_crtc *crtc, + enum transcoder transcoder, + const struct intel_link_m_n *m_n) +{ + struct intel_display *display = to_intel_display(crtc); + int m_n_frac; + enum pipe pipe = crtc->pipe; + + if (!m_n->link_n) + return; + + m_n_frac = m_n->link_m % m_n->link_n; + + intel_de_rmw(display, CHICKEN_TRANS(display, transcoder), 0, BMG_DP_BYPASS_M_N_LIMIT); + intel_de_write(display, HDMI_EMP_DATA(pipe), m_n_frac); +} + void intel_cpu_transcoder_set_m1_n1(struct intel_crtc *crtc, enum transcoder transcoder, const struct intel_link_m_n *m_n) @@ -2655,6 +2689,9 @@ void intel_cpu_transcoder_set_m1_n1(struct intel_crtc *crtc, intel_set_m_n(display, m_n, PIPE_DATA_M_G4X(pipe), PIPE_DATA_N_G4X(pipe), PIPE_LINK_M_G4X(pipe), PIPE_LINK_N_G4X(pipe)); + + if (m_n->bypass_m_n_ratio_limit) + bmg_bypass_m_n_limit_write(crtc, transcoder, m_n); } void intel_cpu_transcoder_set_m2_n2(struct intel_crtc *crtc, @@ -2671,6 +2708,9 @@ void intel_cpu_transcoder_set_m2_n2(struct intel_crtc *crtc, PIPE_DATA_N2(display, transcoder), PIPE_LINK_M2(display, transcoder), PIPE_LINK_N2(display, transcoder)); + + if (m_n->bypass_m_n_ratio_limit) + bmg_bypass_m_n_limit_write(crtc, transcoder, m_n); } static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state) @@ -3317,22 +3357,67 @@ void intel_get_m_n(struct intel_display *display, m_n->link_m = intel_de_read(display, link_m_reg) & DATA_LINK_M_N_MASK; m_n->link_n = intel_de_read(display, link_n_reg); - if (DISPLAY_VER(display) >= 14) + if (DISPLAY_VER(display) >= 14) { + u8 link_n_ext = REG_FIELD_GET(PIPE_LINK_N1_EXTENDED_MASK, m_n->link_n); + m_n->link_n &= ~PIPE_LINK_N1_EXTENDED_MASK; - else + drm_WARN_ON(display->drm, link_n_ext && link_n_ext != bmg_get_link_n_ext(m_n)); + } else { m_n->link_n &= DATA_LINK_M_N_MASK; + } m_n->data_m = intel_de_read(display, data_m_reg) & DATA_LINK_M_N_MASK; m_n->data_n = intel_de_read(display, data_n_reg) & DATA_LINK_M_N_MASK; m_n->tu = REG_FIELD_GET(TU_SIZE_MASK, intel_de_read(display, data_m_reg)) + 1; } +static +void bmg_bypass_m_n_limit_read(struct intel_crtc *crtc, + enum transcoder
[PATCH 3/4] drm/i915/display: Add bits for Wa_14021768792 for linkm/n ratio > 10
To support Link M/N ratio between 10.0 and 15.0, for some BMG ultrajoiner cases we need Wa_14021768792. To bypass the hardware limitation within the Timing Generator DDA (TGDDA), we need to program the LINKM and LINKN registers as defined in the WA. Along with this we also need relvant bits in HDMI_EMP_DATA and CHICKEN_TRANS regs. Add the bits for the WA and a new member 'bmg_bypass_m_n_ratio_limit' to track if we need to bypass the Link M/N ratio limit in intel_link_m_n structure. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_display.c | 119 +- .../drm/i915/display/intel_display_types.h| 2 + drivers/gpu/drm/i915/i915_reg.h | 5 + 3 files changed, 120 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9407eebf731b..75274f567ee6 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2744,6 +2744,20 @@ void intel_zero_m_n(struct intel_link_m_n *m_n) m_n->tu = 1; } +static +u8 bmg_get_link_n_ext(const struct intel_link_m_n *m_n) +{ + int m_n_ratio, m_n_frac; + + if (!m_n->link_n) + return 0; + + m_n_ratio = DIV_ROUND_UP(m_n->link_m, m_n->link_n); + m_n_frac = m_n->link_m % m_n->link_n; + + return m_n_ratio + (m_n_frac > 0 ? 1 : 0); +} + void intel_set_m_n(struct drm_i915_private *i915, const struct intel_link_m_n *m_n, i915_reg_t data_m_reg, i915_reg_t data_n_reg, @@ -2755,7 +2769,9 @@ void intel_set_m_n(struct drm_i915_private *i915, intel_de_write(i915, data_n_reg, m_n->data_n); intel_de_write(i915, link_m_reg, m_n->link_m); - if (DISPLAY_VER(i915) >= 14) + if (DISPLAY_VER(i915) >= 14 && m_n->bypass_m_n_ratio_limit) + link_n |= PIPE_LINK_N1_EXTENDED(bmg_get_link_n_ext(m_n)); + else if (DISPLAY_VER(i915) >= 14) link_n &= ~PIPE_LINK_N1_EXTENDED_MASK; else link_n &= DATA_LINK_M_N_MASK; @@ -2775,6 +2791,24 @@ bool intel_cpu_transcoder_has_m2_n2(struct drm_i915_private *dev_priv, return IS_DISPLAY_VER(dev_priv, 5, 7) || IS_CHERRYVIEW(dev_priv); } +static +void bmg_bypass_m_n_limit_write(struct intel_crtc *crtc, + enum transcoder transcoder, + const struct intel_link_m_n *m_n) +{ + struct intel_display *display = to_intel_display(crtc); + int m_n_frac; + enum pipe pipe = crtc->pipe; + + if (!m_n->link_n) + return; + + m_n_frac = m_n->link_m % m_n->link_n; + + intel_de_rmw(display, MTL_CHICKEN_TRANS(transcoder), 0, BMG_DP_BYPASS_M_N_LIMIT); + intel_de_write(display, HDMI_EMP_DATA(pipe), m_n_frac); +} + void intel_cpu_transcoder_set_m1_n1(struct intel_crtc *crtc, enum transcoder transcoder, const struct intel_link_m_n *m_n) @@ -2792,6 +2826,9 @@ void intel_cpu_transcoder_set_m1_n1(struct intel_crtc *crtc, intel_set_m_n(dev_priv, m_n, PIPE_DATA_M_G4X(pipe), PIPE_DATA_N_G4X(pipe), PIPE_LINK_M_G4X(pipe), PIPE_LINK_N_G4X(pipe)); + + if (m_n->bypass_m_n_ratio_limit) + bmg_bypass_m_n_limit_write(crtc, transcoder, m_n); } void intel_cpu_transcoder_set_m2_n2(struct intel_crtc *crtc, @@ -2808,6 +2845,9 @@ void intel_cpu_transcoder_set_m2_n2(struct intel_crtc *crtc, PIPE_DATA_N2(dev_priv, transcoder), PIPE_LINK_M2(dev_priv, transcoder), PIPE_LINK_N2(dev_priv, transcoder)); + + if (m_n->bypass_m_n_ratio_limit) + bmg_bypass_m_n_limit_write(crtc, transcoder, m_n); } static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state) @@ -3475,22 +3515,68 @@ void intel_get_m_n(struct drm_i915_private *i915, m_n->link_m = intel_de_read(i915, link_m_reg) & DATA_LINK_M_N_MASK; m_n->link_n = intel_de_read(i915, link_n_reg); - if (DISPLAY_VER(i915) >= 14) + if (DISPLAY_VER(i915) >= 14) { + u8 link_n_ext = REG_FIELD_GET(PIPE_LINK_N1_EXTENDED_MASK, m_n->link_n); + m_n->link_n &= ~PIPE_LINK_N1_EXTENDED_MASK; - else + drm_WARN_ON(&i915->drm, link_n_ext && link_n_ext != bmg_get_link_n_ext(m_n)); + } else { m_n->link_n &= DATA_LINK_M_N_MASK; + } m_n->data_m = intel_de_read(i915, data_m_reg) & DATA_LINK_M_N_MASK; m_n->data_n = intel_de_read(i915, data_n_reg) & DATA_LINK_M_N_MASK; m_n->tu = REG_FIELD_GET(TU_SIZE_MASK, intel_de_read(i915, data_m_reg)) + 1; } +static +void bmg_bypass_m_n_limit_read(struct intel_crtc *crtc, + enum transcoder transcoder, +
[PATCH 3/4] drm/i915/display: Add bits for Wa_14021768792 for linkm/n ratio > 10
To support Link M/N ratio between 10.0 and 15.0, for some BMG ultrajoiner cases we need Wa_14021768792. To bypass the hardware limitation within the Timing Generator DDA (TGDDA), we need to program the LINKM and LINKN registers as defined in the WA. Along with this we also need relvant bits in HDMI_EMP_DATA and CHICKEN_TRANS regs. Add the bits for the WA and a new member 'bmg_bypass_m_n_ratio_limit' to track if we need to bypass the Link M/N ratio limit in intel_link_m_n structure. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_display.c | 102 +- .../drm/i915/display/intel_display_types.h| 2 + drivers/gpu/drm/i915/i915_reg.h | 5 + 3 files changed, 104 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 57a438d8ecfc..abb499de1c56 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2687,15 +2687,43 @@ bool intel_cpu_transcoder_has_m2_n2(struct drm_i915_private *dev_priv, return IS_DISPLAY_VER(dev_priv, 5, 7) || IS_CHERRYVIEW(dev_priv); } +static +void bmg_bypass_m_n_limit_write(struct intel_crtc *crtc, + enum transcoder transcoder, + const struct intel_link_m_n *m_n) +{ + struct intel_display *display = to_intel_display(crtc); + int m_n_frac = m_n->link_m % m_n->link_n; + enum pipe pipe = crtc->pipe; + + intel_de_rmw(display, MTL_CHICKEN_TRANS(transcoder), 0, BMG_DP_BYPASS_M_N_LIMIT); + intel_de_write(display, HDMI_EMP_DATA(pipe), m_n_frac); +} + +static +u8 bmg_get_link_n_ext(const struct intel_link_m_n *m_n) +{ + int m_n_ratio, m_n_frac; + + m_n_ratio = DIV_ROUND_UP(m_n->link_m, m_n->link_n); + m_n_frac = m_n->link_m % m_n->link_n; + + return m_n_ratio + (m_n_frac > 0 ? 1 : 0); +} + void intel_cpu_transcoder_set_m1_n1(struct intel_crtc *crtc, enum transcoder transcoder, const struct intel_link_m_n *m_n) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; + u8 link_n_ext = 0; + + if (m_n->bypass_m_n_ratio_limit) + link_n_ext = bmg_get_link_n_ext(m_n); if (DISPLAY_VER(dev_priv) >= 5) - intel_set_m_n(dev_priv, m_n, 0, + intel_set_m_n(dev_priv, m_n, link_n_ext, PIPE_DATA_M1(dev_priv, transcoder), PIPE_DATA_N1(dev_priv, transcoder), PIPE_LINK_M1(dev_priv, transcoder), @@ -2704,6 +2732,9 @@ void intel_cpu_transcoder_set_m1_n1(struct intel_crtc *crtc, intel_set_m_n(dev_priv, m_n, 0, PIPE_DATA_M_G4X(pipe), PIPE_DATA_N_G4X(pipe), PIPE_LINK_M_G4X(pipe), PIPE_LINK_N_G4X(pipe)); + + if (m_n->bypass_m_n_ratio_limit) + bmg_bypass_m_n_limit_write(crtc, transcoder, m_n); } void intel_cpu_transcoder_set_m2_n2(struct intel_crtc *crtc, @@ -2711,15 +2742,22 @@ void intel_cpu_transcoder_set_m2_n2(struct intel_crtc *crtc, const struct intel_link_m_n *m_n) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + u8 link_n_ext = 0; if (!intel_cpu_transcoder_has_m2_n2(dev_priv, transcoder)) return; - intel_set_m_n(dev_priv, m_n, 0, + if (m_n->bypass_m_n_ratio_limit) + link_n_ext = bmg_get_link_n_ext(m_n); + + intel_set_m_n(dev_priv, m_n, link_n_ext, PIPE_DATA_M2(dev_priv, transcoder), PIPE_DATA_N2(dev_priv, transcoder), PIPE_LINK_M2(dev_priv, transcoder), PIPE_LINK_N2(dev_priv, transcoder)); + + if (m_n->bypass_m_n_ratio_limit) + bmg_bypass_m_n_limit_write(crtc, transcoder, m_n); } static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state) @@ -3393,12 +3431,51 @@ void intel_get_m_n(struct drm_i915_private *i915, m_n->tu = REG_FIELD_GET(TU_SIZE_MASK, intel_de_read(i915, data_m_reg)) + 1; } +static +void bmg_bypass_m_n_limit_read(struct intel_crtc *crtc, + enum transcoder transcoder, + struct intel_link_m_n *m_n) +{ + struct intel_display *display = to_intel_display(crtc); + enum pipe pipe = crtc->pipe; + u32 chicken_trans, m_n_frac; + + chicken_trans = intel_de_read(display, MTL_CHICKEN_TRANS(transcoder)); + m_n_frac = intel_de_read(display, HDMI_EMP_DATA(pipe)); + + if ((chicken_trans & BMG_DP_BYPASS_M_N_LIMIT) && + m_n_frac == (m_n->link_m % m_n->link_n)) + m_n->bypass_m_n_ratio_limit = true; +} + +static +int bmg_can_bypass_m_n_