drm/i915/dp: Fix UHBR link M/N values
authorImre Deak <imre.deak@intel.com>
Thu, 16 Nov 2023 13:18:36 +0000 (15:18 +0200)
committerImre Deak <imre.deak@intel.com>
Tue, 21 Nov 2023 14:32:44 +0000 (16:32 +0200)
The link M/N ratio is the data rate / link symbol clock rate, fix things
up accordingly. On DP 1.4 this ratio was correct as the link symbol clock
rate in that case matched the link data rate (in bytes/sec units, the
symbol size being 8 bits), however it wasn't correct for UHBR rates
where the symbol size is 32 bits.

Kudos to Arun noticing in Bspec the incorrect use of link data rate in
the ratio's N value.

Reviewed-by: Arun R Murthy <arun.r.murthy@intel.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231116131841.1588781-7-imre.deak@intel.com
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_dp.h

index dd8ac647fe0eac45befae995645f978b706d130e..c6a2e217a7dc7a33f6b0fbb0cdadc22989955378 100644 (file)
@@ -2410,6 +2410,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes,
                       struct intel_link_m_n *m_n)
 {
        u32 data_clock = DIV_ROUND_UP(bits_per_pixel_x16 * pixel_clock, 16);
+       u32 link_symbol_clock = intel_dp_link_symbol_clock(link_clock);
        u32 data_m;
        u32 data_n;
 
@@ -2430,7 +2431,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes,
                    0x8000000);
 
        compute_m_n(&m_n->link_m, &m_n->link_n,
-                   pixel_clock, link_clock,
+                   pixel_clock, link_symbol_clock,
                    0x80000);
 }
 
@@ -3772,20 +3773,23 @@ int intel_dotclock_calculate(int link_freq,
                             const struct intel_link_m_n *m_n)
 {
        /*
-        * The calculation for the data clock is:
+        * The calculation for the data clock -> pixel clock is:
         * pixel_clock = ((m/n)*(link_clock * nr_lanes))/bpp
         * But we want to avoid losing precison if possible, so:
         * pixel_clock = ((m * link_clock * nr_lanes)/(n*bpp))
         *
-        * and the link clock is simpler:
-        * link_clock = (m * link_clock) / n
+        * and for link freq (10kbs units) -> pixel clock it is:
+        * link_symbol_clock = link_freq * 10 / link_symbol_size
+        * pixel_clock = (m * link_symbol_clock) / n
+        *    or for more precision:
+        * pixel_clock = (m * link_freq * 10) / (n * link_symbol_size)
         */
 
        if (!m_n->link_n)
                return 0;
 
-       return DIV_ROUND_UP_ULL(mul_u32_u32(m_n->link_m, link_freq),
-                               m_n->link_n);
+       return DIV_ROUND_UP_ULL(mul_u32_u32(m_n->link_m, link_freq * 10),
+                               m_n->link_n * intel_dp_link_symbol_size(link_freq));
 }
 
 int intel_crtc_dotclock(const struct intel_crtc_state *pipe_config)
index fb1557912791895421b58f8f51e0e71127c1da34..d58acc36e3be356c65c1933641ce391235e25452 100644 (file)
@@ -127,6 +127,30 @@ bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state)
        return drm_dp_is_uhbr_rate(crtc_state->port_clock);
 }
 
+/**
+ * intel_dp_link_symbol_size - get the link symbol size for a given link rate
+ * @rate: link rate in 10kbit/s units
+ *
+ * Returns the link symbol size in bits/symbol units depending on the link
+ * rate -> channel coding.
+ */
+int intel_dp_link_symbol_size(int rate)
+{
+       return drm_dp_is_uhbr_rate(rate) ? 32 : 10;
+}
+
+/**
+ * intel_dp_link_symbol_clock - convert link rate to link symbol clock
+ * @rate: link rate in 10kbit/s units
+ *
+ * Returns the link symbol clock frequency in kHz units depending on the
+ * link rate and channel coding.
+ */
+int intel_dp_link_symbol_clock(int rate)
+{
+       return DIV_ROUND_CLOSEST(rate * 10, intel_dp_link_symbol_size(rate));
+}
+
 static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp)
 {
        intel_dp->sink_rates[0] = 162000;
index 664fa93bbf53431f6298cbc9c3103a4c310a6831..777aa858f899cad35fc45ecdfbe269cc69a460f7 100644 (file)
@@ -81,6 +81,8 @@ void intel_dp_audio_compute_config(struct intel_encoder *encoder,
 bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp);
 bool intel_dp_is_edp(struct intel_dp *intel_dp);
 bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state);
+int intel_dp_link_symbol_size(int rate);
+int intel_dp_link_symbol_clock(int rate);
 bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port);
 enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *dig_port,
                                  bool long_hpd);