|
@@ -2709,27 +2709,19 @@ fdi_reduce_ratio(u32 *num, u32 *den)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#define DATA_N 0x800000
|
|
|
-#define LINK_N 0x80000
|
|
|
-
|
|
|
static void
|
|
|
ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock,
|
|
|
int link_clock, struct fdi_m_n *m_n)
|
|
|
{
|
|
|
- u64 temp;
|
|
|
-
|
|
|
m_n->tu = 64; /* default size */
|
|
|
|
|
|
- temp = (u64) DATA_N * pixel_clock;
|
|
|
- temp = div_u64(temp, link_clock);
|
|
|
- m_n->gmch_m = div_u64(temp * bits_per_pixel, nlanes);
|
|
|
- m_n->gmch_m >>= 3; /* convert to bytes_per_pixel */
|
|
|
- m_n->gmch_n = DATA_N;
|
|
|
+ /* BUG_ON(pixel_clock > INT_MAX / 36); */
|
|
|
+ m_n->gmch_m = bits_per_pixel * pixel_clock;
|
|
|
+ m_n->gmch_n = link_clock * nlanes * 8;
|
|
|
fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
|
|
|
|
|
|
- temp = (u64) LINK_N * pixel_clock;
|
|
|
- m_n->link_m = div_u64(temp, link_clock);
|
|
|
- m_n->link_n = LINK_N;
|
|
|
+ m_n->link_m = pixel_clock;
|
|
|
+ m_n->link_n = link_clock;
|
|
|
fdi_reduce_ratio(&m_n->link_m, &m_n->link_n);
|
|
|
}
|
|
|
|
|
@@ -3713,6 +3705,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
|
|
|
/* FDI link */
|
|
|
if (HAS_PCH_SPLIT(dev)) {
|
|
|
+ int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
|
|
|
int lane = 0, link_bw, bpp;
|
|
|
/* CPU eDP doesn't require FDI link, so just set DP M/N
|
|
|
according to current link config */
|
|
@@ -3796,6 +3789,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
|
|
|
intel_crtc->fdi_lanes = lane;
|
|
|
|
|
|
+ if (pixel_multiplier > 1)
|
|
|
+ link_bw *= pixel_multiplier;
|
|
|
ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
|
|
|
}
|
|
|
|
|
@@ -5263,6 +5258,55 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
|
|
|
.page_flip = intel_crtc_page_flip,
|
|
|
};
|
|
|
|
|
|
+static void intel_sanitize_modesetting(struct drm_device *dev,
|
|
|
+ int pipe, int plane)
|
|
|
+{
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+ u32 reg, val;
|
|
|
+
|
|
|
+ if (HAS_PCH_SPLIT(dev))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Who knows what state these registers were left in by the BIOS or
|
|
|
+ * grub?
|
|
|
+ *
|
|
|
+ * If we leave the registers in a conflicting state (e.g. with the
|
|
|
+ * display plane reading from the other pipe than the one we intend
|
|
|
+ * to use) then when we attempt to teardown the active mode, we will
|
|
|
+ * not disable the pipes and planes in the correct order -- leaving
|
|
|
+ * a plane reading from a disabled pipe and possibly leading to
|
|
|
+ * undefined behaviour.
|
|
|
+ */
|
|
|
+
|
|
|
+ reg = DSPCNTR(plane);
|
|
|
+ val = I915_READ(reg);
|
|
|
+
|
|
|
+ if ((val & DISPLAY_PLANE_ENABLE) == 0)
|
|
|
+ return;
|
|
|
+ if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* This display plane is active and attached to the other CPU pipe. */
|
|
|
+ pipe = !pipe;
|
|
|
+
|
|
|
+ /* Disable the plane and wait for it to stop reading from the pipe. */
|
|
|
+ I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
|
|
|
+ intel_flush_display_plane(dev, plane);
|
|
|
+
|
|
|
+ if (IS_GEN2(dev))
|
|
|
+ intel_wait_for_vblank(dev, pipe);
|
|
|
+
|
|
|
+ if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Switch off the pipe. */
|
|
|
+ reg = PIPECONF(pipe);
|
|
|
+ val = I915_READ(reg);
|
|
|
+ if (val & PIPECONF_ENABLE) {
|
|
|
+ I915_WRITE(reg, val & ~PIPECONF_ENABLE);
|
|
|
+ intel_wait_for_pipe_off(dev, pipe);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
static void intel_crtc_init(struct drm_device *dev, int pipe)
|
|
|
{
|
|
@@ -5314,6 +5358,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
|
|
|
|
|
|
setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
|
|
|
(unsigned long)intel_crtc);
|
|
|
+
|
|
|
+ intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
|
|
|
}
|
|
|
|
|
|
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
|