Commit 18442d08 authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Daniel Vetter

drm/i915: Fix port_clock and adjusted_mode.clock readout all over

Now that adjusted_mode.clock no longer contains the pixel_multiplier, we
can kill the get_clock() callback and instead do the clock readout
in get_pipe_config().

Also i9xx_crtc_clock_get() can now extract the frequency of the PCH
DPLL, so use it to populate port_clock accurately for PCH encoders.
For DP in port A the encoder is still responsible for filling in
port_clock. The FDI adjusted_mode.clock extraction is kept in place
for some extra sanity checking, but we no longer need to pretend it's
also the port_clock.

In the encoder get_config() functions fill out adjusted_mode.clock
based on port_clock and other details such as the DP M/N values,
HDMI 12bpc and SDVO pixel_multiplier. For PCH encoders we will then
do an extra sanity check to make sure the dotclock we derived from
the FDI configuratiuon matches the one we derive from port_clock.

DVO doesn't exist on PCH platforms, so it doesn't need to anything
but assign adjusted_mode.clock=port_clock. And DDI is HSW only, so
none of the changes apply there.

v2: Use hdmi_reg color format to detect 12bpc HDMI case
v3: Set adjusted_mode.clock for LVDS too
v4: Rename ironlake_crtc_clock_get to ironlake_pch_clock_get,
    eliminate the useless link_freq variable.
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarJani Nikula <jani.nikula@intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent da4a1efa
...@@ -371,7 +371,6 @@ struct drm_i915_display_funcs { ...@@ -371,7 +371,6 @@ struct drm_i915_display_funcs {
* fills out the pipe-config with the hw state. */ * fills out the pipe-config with the hw state. */
bool (*get_pipe_config)(struct intel_crtc *, bool (*get_pipe_config)(struct intel_crtc *,
struct intel_crtc_config *); struct intel_crtc_config *);
void (*get_clock)(struct intel_crtc *, struct intel_crtc_config *);
int (*crtc_mode_set)(struct drm_crtc *crtc, int (*crtc_mode_set)(struct drm_crtc *crtc,
int x, int y, int x, int y,
struct drm_framebuffer *old_fb); struct drm_framebuffer *old_fb);
......
...@@ -2071,6 +2071,7 @@ ...@@ -2071,6 +2071,7 @@
/* Gen 4 SDVO/HDMI bits: */ /* Gen 4 SDVO/HDMI bits: */
#define SDVO_COLOR_FORMAT_8bpc (0 << 26) #define SDVO_COLOR_FORMAT_8bpc (0 << 26)
#define SDVO_COLOR_FORMAT_MASK (7 << 26)
#define SDVO_ENCODING_SDVO (0 << 10) #define SDVO_ENCODING_SDVO (0 << 10)
#define SDVO_ENCODING_HDMI (2 << 10) #define SDVO_ENCODING_HDMI (2 << 10)
#define HDMI_MODE_SELECT_HDMI (1 << 9) /* HDMI only */ #define HDMI_MODE_SELECT_HDMI (1 << 9) /* HDMI only */
......
...@@ -89,6 +89,7 @@ static void intel_crt_get_config(struct intel_encoder *encoder, ...@@ -89,6 +89,7 @@ static void intel_crt_get_config(struct intel_encoder *encoder,
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_crt *crt = intel_encoder_to_crt(encoder); struct intel_crt *crt = intel_encoder_to_crt(encoder);
u32 tmp, flags = 0; u32 tmp, flags = 0;
int dotclock;
tmp = I915_READ(crt->adpa_reg); tmp = I915_READ(crt->adpa_reg);
...@@ -103,6 +104,13 @@ static void intel_crt_get_config(struct intel_encoder *encoder, ...@@ -103,6 +104,13 @@ static void intel_crt_get_config(struct intel_encoder *encoder,
flags |= DRM_MODE_FLAG_NVSYNC; flags |= DRM_MODE_FLAG_NVSYNC;
pipe_config->adjusted_mode.flags |= flags; pipe_config->adjusted_mode.flags |= flags;
dotclock = pipe_config->port_clock;
if (HAS_PCH_SPLIT(dev_priv->dev))
ironlake_check_encoder_dotclock(pipe_config, dotclock);
pipe_config->adjusted_mode.clock = dotclock;
} }
/* Note: The caller is required to filter out dpms modes not supported by the /* Note: The caller is required to filter out dpms modes not supported by the
......
...@@ -47,7 +47,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); ...@@ -47,7 +47,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
static void i9xx_crtc_clock_get(struct intel_crtc *crtc, static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
struct intel_crtc_config *pipe_config); struct intel_crtc_config *pipe_config);
static void ironlake_crtc_clock_get(struct intel_crtc *crtc, static void ironlake_pch_clock_get(struct intel_crtc *crtc,
struct intel_crtc_config *pipe_config); struct intel_crtc_config *pipe_config);
static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
...@@ -5068,6 +5068,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, ...@@ -5068,6 +5068,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
DPLL_PORTB_READY_MASK); DPLL_PORTB_READY_MASK);
} }
i9xx_crtc_clock_get(crtc, pipe_config);
return true; return true;
} }
...@@ -6026,6 +6028,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, ...@@ -6026,6 +6028,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
pipe_config->pixel_multiplier = pipe_config->pixel_multiplier =
((tmp & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK) ((tmp & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK)
>> PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT) + 1; >> PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT) + 1;
ironlake_pch_clock_get(crtc, pipe_config);
} else { } else {
pipe_config->pixel_multiplier = 1; pipe_config->pixel_multiplier = 1;
} }
...@@ -7433,7 +7437,12 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, ...@@ -7433,7 +7437,12 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
i9xx_clock(refclk, &clock); i9xx_clock(refclk, &clock);
} }
pipe_config->adjusted_mode.clock = clock.dot; /*
* This value includes pixel_multiplier. We will use
* port_clock to compute adjusted_mode.clock in the
* encoder's get_config() function.
*/
pipe_config->port_clock = clock.dot;
} }
int intel_dotclock_calculate(int link_freq, int intel_dotclock_calculate(int link_freq,
...@@ -7455,31 +7464,23 @@ int intel_dotclock_calculate(int link_freq, ...@@ -7455,31 +7464,23 @@ int intel_dotclock_calculate(int link_freq,
return div_u64((u64)m_n->link_m * link_freq, m_n->link_n); return div_u64((u64)m_n->link_m * link_freq, m_n->link_n);
} }
static void ironlake_crtc_clock_get(struct intel_crtc *crtc, static void ironlake_pch_clock_get(struct intel_crtc *crtc,
struct intel_crtc_config *pipe_config) struct intel_crtc_config *pipe_config)
{ {
struct drm_device *dev = crtc->base.dev; struct drm_device *dev = crtc->base.dev;
int link_freq;
/* read out port_clock from the DPLL */
i9xx_crtc_clock_get(crtc, pipe_config);
/* /*
* We need to get the FDI or DP link clock here to derive * This value does not include pixel_multiplier.
* the M/N dividers. * We will check that port_clock and adjusted_mode.clock
* * agree once we know their relationship in the encoder's
* For FDI, we read it from the BIOS or use a fixed 2.7GHz. * get_config() function.
* For DP, it's either 1.62GHz or 2.7GHz.
* We do our calculations in 10*MHz since we don't need much precison.
*/ */
if (pipe_config->has_pch_encoder) {
link_freq = intel_fdi_link_freq(dev) * 10000;
pipe_config->adjusted_mode.clock =
intel_dotclock_calculate(link_freq, &pipe_config->fdi_m_n);
} else {
link_freq = pipe_config->port_clock;
pipe_config->adjusted_mode.clock = pipe_config->adjusted_mode.clock =
intel_dotclock_calculate(link_freq, &pipe_config->dp_m_n); intel_dotclock_calculate(intel_fdi_link_freq(dev) * 10000,
} &pipe_config->fdi_m_n);
} }
/** Returns the currently programmed mode of the given pipe. */ /** Returns the currently programmed mode of the given pipe. */
...@@ -8895,9 +8896,6 @@ check_crtc_state(struct drm_device *dev) ...@@ -8895,9 +8896,6 @@ check_crtc_state(struct drm_device *dev)
encoder->get_config(encoder, &pipe_config); encoder->get_config(encoder, &pipe_config);
} }
if (dev_priv->display.get_clock)
dev_priv->display.get_clock(crtc, &pipe_config);
WARN(crtc->active != active, WARN(crtc->active != active,
"crtc active state doesn't match with hw state " "crtc active state doesn't match with hw state "
"(expected %i, found %i)\n", crtc->active, active); "(expected %i, found %i)\n", crtc->active, active);
...@@ -8972,6 +8970,18 @@ intel_modeset_check_state(struct drm_device *dev) ...@@ -8972,6 +8970,18 @@ intel_modeset_check_state(struct drm_device *dev)
check_shared_dpll_state(dev); check_shared_dpll_state(dev);
} }
void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
int dotclock)
{
/*
* FDI already provided one idea for the dotclock.
* Yell if the encoder disagrees.
*/
WARN(!intel_fuzzy_clock_check(pipe_config->adjusted_mode.clock, dotclock),
"FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n",
pipe_config->adjusted_mode.clock, dotclock);
}
static int __intel_set_mode(struct drm_crtc *crtc, static int __intel_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *mode,
int x, int y, struct drm_framebuffer *fb) int x, int y, struct drm_framebuffer *fb)
...@@ -9923,7 +9933,6 @@ static void intel_init_display(struct drm_device *dev) ...@@ -9923,7 +9933,6 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.update_plane = ironlake_update_plane; dev_priv->display.update_plane = ironlake_update_plane;
} else if (HAS_PCH_SPLIT(dev)) { } else if (HAS_PCH_SPLIT(dev)) {
dev_priv->display.get_pipe_config = ironlake_get_pipe_config; dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
dev_priv->display.get_clock = ironlake_crtc_clock_get;
dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_enable = ironlake_crtc_enable;
dev_priv->display.crtc_disable = ironlake_crtc_disable; dev_priv->display.crtc_disable = ironlake_crtc_disable;
...@@ -9931,7 +9940,6 @@ static void intel_init_display(struct drm_device *dev) ...@@ -9931,7 +9940,6 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.update_plane = ironlake_update_plane; dev_priv->display.update_plane = ironlake_update_plane;
} else if (IS_VALLEYVIEW(dev)) { } else if (IS_VALLEYVIEW(dev)) {
dev_priv->display.get_pipe_config = i9xx_get_pipe_config; dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
dev_priv->display.get_clock = i9xx_crtc_clock_get;
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
dev_priv->display.crtc_enable = valleyview_crtc_enable; dev_priv->display.crtc_enable = valleyview_crtc_enable;
dev_priv->display.crtc_disable = i9xx_crtc_disable; dev_priv->display.crtc_disable = i9xx_crtc_disable;
...@@ -9939,7 +9947,6 @@ static void intel_init_display(struct drm_device *dev) ...@@ -9939,7 +9947,6 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.update_plane = i9xx_update_plane; dev_priv->display.update_plane = i9xx_update_plane;
} else { } else {
dev_priv->display.get_pipe_config = i9xx_get_pipe_config; dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
dev_priv->display.get_clock = i9xx_crtc_clock_get;
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
dev_priv->display.crtc_enable = i9xx_crtc_enable; dev_priv->display.crtc_enable = i9xx_crtc_enable;
dev_priv->display.crtc_disable = i9xx_crtc_disable; dev_priv->display.crtc_disable = i9xx_crtc_disable;
...@@ -10553,15 +10560,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) ...@@ -10553,15 +10560,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
pipe); pipe);
} }
list_for_each_entry(crtc, &dev->mode_config.crtc_list,
base.head) {
if (!crtc->active)
continue;
if (dev_priv->display.get_clock)
dev_priv->display.get_clock(crtc,
&crtc->config);
}
list_for_each_entry(connector, &dev->mode_config.connector_list, list_for_each_entry(connector, &dev->mode_config.connector_list,
base.head) { base.head) {
if (connector->get_hw_state(connector)) { if (connector->get_hw_state(connector)) {
......
...@@ -1417,6 +1417,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder, ...@@ -1417,6 +1417,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
enum port port = dp_to_dig_port(intel_dp)->port; enum port port = dp_to_dig_port(intel_dp)->port;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
int dotclock;
if ((port == PORT_A) || !HAS_PCH_CPT(dev)) { if ((port == PORT_A) || !HAS_PCH_CPT(dev)) {
tmp = I915_READ(intel_dp->output_reg); tmp = I915_READ(intel_dp->output_reg);
...@@ -1448,12 +1449,20 @@ static void intel_dp_get_config(struct intel_encoder *encoder, ...@@ -1448,12 +1449,20 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
intel_dp_get_m_n(crtc, pipe_config); intel_dp_get_m_n(crtc, pipe_config);
if (dp_to_dig_port(intel_dp)->port == PORT_A) { if (port == PORT_A) {
if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ) if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ)
pipe_config->port_clock = 162000; pipe_config->port_clock = 162000;
else else
pipe_config->port_clock = 270000; pipe_config->port_clock = 270000;
} }
dotclock = intel_dotclock_calculate(pipe_config->port_clock,
&pipe_config->dp_m_n);
if (HAS_PCH_SPLIT(dev_priv->dev) && port != PORT_A)
ironlake_check_encoder_dotclock(pipe_config, dotclock);
pipe_config->adjusted_mode.clock = dotclock;
} }
static bool is_edp_psr(struct intel_dp *intel_dp) static bool is_edp_psr(struct intel_dp *intel_dp)
......
...@@ -805,5 +805,7 @@ extern void intel_dp_get_m_n(struct intel_crtc *crtc, ...@@ -805,5 +805,7 @@ extern void intel_dp_get_m_n(struct intel_crtc *crtc,
struct intel_crtc_config *pipe_config); struct intel_crtc_config *pipe_config);
extern int intel_dotclock_calculate(int link_freq, extern int intel_dotclock_calculate(int link_freq,
const struct intel_link_m_n *m_n); const struct intel_link_m_n *m_n);
extern void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
int dotclock);
#endif /* __INTEL_DRV_H__ */ #endif /* __INTEL_DRV_H__ */
...@@ -153,6 +153,8 @@ static void intel_dvo_get_config(struct intel_encoder *encoder, ...@@ -153,6 +153,8 @@ static void intel_dvo_get_config(struct intel_encoder *encoder,
flags |= DRM_MODE_FLAG_NVSYNC; flags |= DRM_MODE_FLAG_NVSYNC;
pipe_config->adjusted_mode.flags |= flags; pipe_config->adjusted_mode.flags |= flags;
pipe_config->adjusted_mode.clock = pipe_config->port_clock;
} }
static void intel_disable_dvo(struct intel_encoder *encoder) static void intel_disable_dvo(struct intel_encoder *encoder)
......
...@@ -713,6 +713,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, ...@@ -713,6 +713,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
u32 tmp, flags = 0; u32 tmp, flags = 0;
int dotclock;
tmp = I915_READ(intel_hdmi->hdmi_reg); tmp = I915_READ(intel_hdmi->hdmi_reg);
...@@ -727,6 +728,16 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, ...@@ -727,6 +728,16 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
flags |= DRM_MODE_FLAG_NVSYNC; flags |= DRM_MODE_FLAG_NVSYNC;
pipe_config->adjusted_mode.flags |= flags; pipe_config->adjusted_mode.flags |= flags;
if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc)
dotclock = pipe_config->port_clock * 2 / 3;
else
dotclock = pipe_config->port_clock;
if (HAS_PCH_SPLIT(dev_priv->dev))
ironlake_check_encoder_dotclock(pipe_config, dotclock);
pipe_config->adjusted_mode.clock = dotclock;
} }
static void intel_enable_hdmi(struct intel_encoder *encoder) static void intel_enable_hdmi(struct intel_encoder *encoder)
......
...@@ -92,6 +92,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder, ...@@ -92,6 +92,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
struct drm_device *dev = encoder->base.dev; struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 lvds_reg, tmp, flags = 0; u32 lvds_reg, tmp, flags = 0;
int dotclock;
if (HAS_PCH_SPLIT(dev)) if (HAS_PCH_SPLIT(dev))
lvds_reg = PCH_LVDS; lvds_reg = PCH_LVDS;
...@@ -116,6 +117,13 @@ static void intel_lvds_get_config(struct intel_encoder *encoder, ...@@ -116,6 +117,13 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE; pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE;
} }
dotclock = pipe_config->port_clock;
if (HAS_PCH_SPLIT(dev_priv->dev))
ironlake_check_encoder_dotclock(pipe_config, dotclock);
pipe_config->adjusted_mode.clock = dotclock;
} }
/* The LVDS pin pair needs to be on before the DPLLs are enabled. /* The LVDS pin pair needs to be on before the DPLLs are enabled.
......
...@@ -1316,6 +1316,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, ...@@ -1316,6 +1316,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
struct intel_sdvo *intel_sdvo = to_sdvo(encoder); struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
struct intel_sdvo_dtd dtd; struct intel_sdvo_dtd dtd;
int encoder_pixel_multiplier = 0; int encoder_pixel_multiplier = 0;
int dotclock;
u32 flags = 0, sdvox; u32 flags = 0, sdvox;
u8 val; u8 val;
bool ret; bool ret;
...@@ -1354,6 +1355,13 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, ...@@ -1354,6 +1355,13 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
>> SDVO_PORT_MULTIPLY_SHIFT) + 1; >> SDVO_PORT_MULTIPLY_SHIFT) + 1;
} }
dotclock = pipe_config->port_clock / pipe_config->pixel_multiplier;
if (HAS_PCH_SPLIT(dev))
ironlake_check_encoder_dotclock(pipe_config, dotclock);
pipe_config->adjusted_mode.clock = dotclock;
/* Cross check the port pixel multiplier with the sdvo encoder state. */ /* Cross check the port pixel multiplier with the sdvo encoder state. */
if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT,
&val, 1)) { &val, 1)) {
......
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