Commit 7e175377 authored by Imre Deak's avatar Imre Deak

drm/i915/dp: Fix UHBR link M/N values

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: default avatarArun R Murthy <arun.r.murthy@intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231116131841.1588781-7-imre.deak@intel.com
parent c7ae0978
...@@ -2410,6 +2410,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes, ...@@ -2410,6 +2410,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes,
struct intel_link_m_n *m_n) struct intel_link_m_n *m_n)
{ {
u32 data_clock = DIV_ROUND_UP(bits_per_pixel_x16 * pixel_clock, 16); 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_m;
u32 data_n; u32 data_n;
...@@ -2430,7 +2431,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes, ...@@ -2430,7 +2431,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes,
0x8000000); 0x8000000);
compute_m_n(&m_n->link_m, &m_n->link_n, compute_m_n(&m_n->link_m, &m_n->link_n,
pixel_clock, link_clock, pixel_clock, link_symbol_clock,
0x80000); 0x80000);
} }
...@@ -3772,20 +3773,23 @@ int intel_dotclock_calculate(int link_freq, ...@@ -3772,20 +3773,23 @@ int intel_dotclock_calculate(int link_freq,
const struct intel_link_m_n *m_n) 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 * pixel_clock = ((m/n)*(link_clock * nr_lanes))/bpp
* But we want to avoid losing precison if possible, so: * But we want to avoid losing precison if possible, so:
* pixel_clock = ((m * link_clock * nr_lanes)/(n*bpp)) * pixel_clock = ((m * link_clock * nr_lanes)/(n*bpp))
* *
* and the link clock is simpler: * and for link freq (10kbs units) -> pixel clock it is:
* link_clock = (m * link_clock) / n * 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) if (!m_n->link_n)
return 0; return 0;
return DIV_ROUND_UP_ULL(mul_u32_u32(m_n->link_m, link_freq), return DIV_ROUND_UP_ULL(mul_u32_u32(m_n->link_m, link_freq * 10),
m_n->link_n); m_n->link_n * intel_dp_link_symbol_size(link_freq));
} }
int intel_crtc_dotclock(const struct intel_crtc_state *pipe_config) int intel_crtc_dotclock(const struct intel_crtc_state *pipe_config)
......
...@@ -127,6 +127,30 @@ bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state) ...@@ -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); 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) static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp)
{ {
intel_dp->sink_rates[0] = 162000; intel_dp->sink_rates[0] = 162000;
......
...@@ -81,6 +81,8 @@ void intel_dp_audio_compute_config(struct intel_encoder *encoder, ...@@ -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_has_hdmi_sink(struct intel_dp *intel_dp);
bool intel_dp_is_edp(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); 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); 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, enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *dig_port,
bool long_hpd); bool long_hpd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment