aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c388
1 files changed, 240 insertions, 148 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 397087cf689e..d514719f65e2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -75,7 +75,7 @@ struct intel_limit {
intel_range_t dot, vco, n, m, m1, m2, p, p1;
intel_p2_t p2;
bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
- int, int, intel_clock_t *);
+ int, int, intel_clock_t *, intel_clock_t *);
};
/* FDI */
@@ -83,17 +83,21 @@ struct intel_limit {
static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock);
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock);
static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock);
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock);
static bool
intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock);
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock);
static bool
intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock);
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock);
static inline u32 /* units of 100MHz */
intel_fdi_link_freq(struct drm_device *dev)
@@ -515,7 +519,8 @@ static bool intel_PLL_is_valid(struct drm_device *dev,
static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock)
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
@@ -562,6 +567,9 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
if (!intel_PLL_is_valid(dev, limit,
&clock))
continue;
+ if (match_clock &&
+ clock.p != match_clock->p)
+ continue;
this_err = abs(clock.dot - target);
if (this_err < err) {
@@ -578,7 +586,8 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock)
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -625,6 +634,9 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
if (!intel_PLL_is_valid(dev, limit,
&clock))
continue;
+ if (match_clock &&
+ clock.p != match_clock->p)
+ continue;
this_err = abs(clock.dot - target);
if (this_err < err_most) {
@@ -642,7 +654,8 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
static bool
intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock)
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
intel_clock_t clock;
@@ -668,7 +681,8 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
/* DisplayPort has only two frequencies, 162MHz and 270MHz */
static bool
intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock)
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
{
intel_clock_t clock;
if (target < 200000) {
@@ -922,6 +936,10 @@ void assert_pipe(struct drm_i915_private *dev_priv,
u32 val;
bool cur_state;
+ /* if we need the pipe A quirk it must be always on */
+ if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
+ state = true;
+
reg = PIPECONF(pipe);
val = I915_READ(reg);
cur_state = !!(val & PIPECONF_ENABLE);
@@ -930,19 +948,24 @@ void assert_pipe(struct drm_i915_private *dev_priv,
pipe_name(pipe), state_string(state), state_string(cur_state));
}
-static void assert_plane_enabled(struct drm_i915_private *dev_priv,
- enum plane plane)
+static void assert_plane(struct drm_i915_private *dev_priv,
+ enum plane plane, bool state)
{
int reg;
u32 val;
+ bool cur_state;
reg = DSPCNTR(plane);
val = I915_READ(reg);
- WARN(!(val & DISPLAY_PLANE_ENABLE),
- "plane %c assertion failure, should be active but is disabled\n",
- plane_name(plane));
+ cur_state = !!(val & DISPLAY_PLANE_ENABLE);
+ WARN(cur_state != state,
+ "plane %c assertion failure (expected %s, current %s)\n",
+ plane_name(plane), state_string(state), state_string(cur_state));
}
+#define assert_plane_enabled(d, p) assert_plane(d, p, true)
+#define assert_plane_disabled(d, p) assert_plane(d, p, false)
+
static void assert_planes_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
@@ -951,8 +974,14 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
int cur_pipe;
/* Planes are fixed to pipes on ILK+ */
- if (HAS_PCH_SPLIT(dev_priv->dev))
+ if (HAS_PCH_SPLIT(dev_priv->dev)) {
+ reg = DSPCNTR(pipe);
+ val = I915_READ(reg);
+ WARN((val & DISPLAY_PLANE_ENABLE),
+ "plane %c assertion failure, should be disabled but not\n",
+ plane_name(pipe));
return;
+ }
/* Need to check both planes against the pipe */
for (i = 0; i < 2; i++) {
@@ -1071,7 +1100,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
{
u32 val = I915_READ(reg);
WARN(hdmi_pipe_enabled(dev_priv, val, pipe),
- "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
+ "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
reg, pipe_name(pipe));
}
@@ -1237,7 +1266,8 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
int reg;
- u32 val;
+ u32 val, pipeconf_val;
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
/* PCH only available on ILK+ */
BUG_ON(dev_priv->info->gen < 5);
@@ -1251,6 +1281,7 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
reg = TRANSCONF(pipe);
val = I915_READ(reg);
+ pipeconf_val = I915_READ(PIPECONF(pipe));
if (HAS_PCH_IBX(dev_priv->dev)) {
/*
@@ -1258,8 +1289,19 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
* that in pipeconf reg.
*/
val &= ~PIPE_BPC_MASK;
- val |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
+ val |= pipeconf_val & PIPE_BPC_MASK;
}
+
+ val &= ~TRANS_INTERLACE_MASK;
+ if ((pipeconf_val & PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK)
+ if (HAS_PCH_IBX(dev_priv->dev) &&
+ intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO))
+ val |= TRANS_LEGACY_INTERLACED_ILK;
+ else
+ val |= TRANS_INTERLACED;
+ else
+ val |= TRANS_PROGRESSIVE;
+
I915_WRITE(reg, val | TRANS_ENABLE);
if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
DRM_ERROR("failed to enable transcoder %d\n", pipe);
@@ -2012,6 +2054,8 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
ret = i915_gem_object_get_fence(obj, pipelined);
if (ret)
goto err_unpin;
+
+ i915_gem_object_pin_fence(obj);
}
dev_priv->mm.interruptible = true;
@@ -2024,6 +2068,12 @@ err_interruptible:
return ret;
}
+void intel_unpin_fb_obj(struct drm_i915_gem_object *obj)
+{
+ i915_gem_object_unpin_fence(obj);
+ i915_gem_object_unpin(obj);
+}
+
static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
int x, int y)
{
@@ -2255,7 +2305,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
LEAVE_ATOMIC_MODE_SET);
if (ret) {
- i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+ intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
mutex_unlock(&dev->struct_mutex);
DRM_ERROR("failed to update base address\n");
return ret;
@@ -2263,7 +2313,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
if (old_fb) {
intel_wait_for_vblank(dev, intel_crtc->pipe);
- i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj);
+ intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
}
mutex_unlock(&dev->struct_mutex);
@@ -2936,6 +2986,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe)));
+ I915_WRITE(TRANS_VSYNCSHIFT(pipe), I915_READ(VSYNCSHIFT(pipe)));
intel_fdi_normal_train(crtc);
@@ -3321,10 +3372,12 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+ assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane);
+ assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
if (crtc->fb) {
mutex_lock(&dev->struct_mutex);
- i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+ intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
mutex_unlock(&dev->struct_mutex);
}
}
@@ -3398,11 +3451,8 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
return false;
}
- /* XXX some encoders set the crtcinfo, others don't.
- * Obviously we need some form of conflict resolution here...
- */
- if (adjusted_mode->crtc_htotal == 0)
- drm_mode_set_crtcinfo(adjusted_mode, 0);
+ /* All interlaced capable intel hw wants timings in frames. */
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
return true;
}
@@ -4521,6 +4571,7 @@ void sandybridge_update_wm(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
+ u32 val;
int fbc_wm, plane_wm, cursor_wm;
unsigned int enabled;
@@ -4529,8 +4580,10 @@ void sandybridge_update_wm(struct drm_device *dev)
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
- I915_WRITE(WM0_PIPEA_ILK,
- (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ val = I915_READ(WM0_PIPEA_ILK);
+ val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+ I915_WRITE(WM0_PIPEA_ILK, val |
+ ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
" plane %d, " "cursor: %d\n",
plane_wm, cursor_wm);
@@ -4541,8 +4594,10 @@ void sandybridge_update_wm(struct drm_device *dev)
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
- I915_WRITE(WM0_PIPEB_ILK,
- (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ val = I915_READ(WM0_PIPEB_ILK);
+ val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+ I915_WRITE(WM0_PIPEB_ILK, val |
+ ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
" plane %d, cursor: %d\n",
plane_wm, cursor_wm);
@@ -4555,8 +4610,10 @@ void sandybridge_update_wm(struct drm_device *dev)
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
- I915_WRITE(WM0_PIPEC_IVB,
- (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ val = I915_READ(WM0_PIPEC_IVB);
+ val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+ I915_WRITE(WM0_PIPEC_IVB, val |
+ ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
" plane %d, cursor: %d\n",
plane_wm, cursor_wm);
@@ -4709,6 +4766,7 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
{
struct drm_i915_private *dev_priv = dev->dev_private;
int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
+ u32 val;
int sprite_wm, reg;
int ret;
@@ -4735,7 +4793,9 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
return;
}
- I915_WRITE(reg, I915_READ(reg) | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
+ val = I915_READ(reg);
+ val &= ~WM0_PIPE_SPRITE_MASK;
+ I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm);
@@ -4977,6 +5037,82 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
return display_bpc != bpc;
}
+static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int refclk;
+
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+ intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
+ refclk = dev_priv->lvds_ssc_freq * 1000;
+ DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+ refclk / 1000);
+ } else if (!IS_GEN2(dev)) {
+ refclk = 96000;
+ } else {
+ refclk = 48000;
+ }
+
+ return refclk;
+}
+
+static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode,
+ intel_clock_t *clock)
+{
+ /* SDVO TV has fixed PLL values depend on its clock range,
+ this mirrors vbios setting. */
+ if (adjusted_mode->clock >= 100000
+ && adjusted_mode->clock < 140500) {
+ clock->p1 = 2;
+ clock->p2 = 10;
+ clock->n = 3;
+ clock->m1 = 16;
+ clock->m2 = 8;
+ } else if (adjusted_mode->clock >= 140500
+ && adjusted_mode->clock <= 200000) {
+ clock->p1 = 1;
+ clock->p2 = 10;
+ clock->n = 6;
+ clock->m1 = 12;
+ clock->m2 = 8;
+ }
+}
+
+static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
+ intel_clock_t *clock,
+ intel_clock_t *reduced_clock)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ u32 fp, fp2 = 0;
+
+ if (IS_PINEVIEW(dev)) {
+ fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2;
+ if (reduced_clock)
+ fp2 = (1 << reduced_clock->n) << 16 |
+ reduced_clock->m1 << 8 | reduced_clock->m2;
+ } else {
+ fp = clock->n << 16 | clock->m1 << 8 | clock->m2;
+ if (reduced_clock)
+ fp2 = reduced_clock->n << 16 | reduced_clock->m1 << 8 |
+ reduced_clock->m2;
+ }
+
+ I915_WRITE(FP0(pipe), fp);
+
+ intel_crtc->lowfreq_avail = false;
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+ reduced_clock && i915_powersave) {
+ I915_WRITE(FP1(pipe), fp2);
+ intel_crtc->lowfreq_avail = true;
+ } else {
+ I915_WRITE(FP1(pipe), fp);
+ }
+}
+
static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -4990,7 +5126,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
int plane = intel_crtc->plane;
int refclk, num_connectors = 0;
intel_clock_t clock, reduced_clock;
- u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
+ u32 dpll, dspcntr, pipeconf, vsyncshift;
bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
struct drm_mode_config *mode_config = &dev->mode_config;
@@ -5031,15 +5167,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
num_connectors++;
}
- if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
- refclk = dev_priv->lvds_ssc_freq * 1000;
- DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
- refclk / 1000);
- } else if (!IS_GEN2(dev)) {
- refclk = 96000;
- } else {
- refclk = 48000;
- }
+ refclk = i9xx_get_refclk(crtc, num_connectors);
/*
* Returns a set of divisors for the desired target clock with the given
@@ -5047,7 +5175,8 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/
limit = intel_limit(crtc, refclk);
- ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+ ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+ &clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
return -EINVAL;
@@ -5057,53 +5186,24 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
intel_crtc_update_cursor(crtc, true);
if (is_lvds && dev_priv->lvds_downclock_avail) {
+ /*
+ * Ensure we match the reduced clock's P to the target clock.
+ * If the clocks don't match, we can't switch the display clock
+ * by using the FP0/FP1. In such case we will disable the LVDS
+ * downclock feature.
+ */
has_reduced_clock = limit->find_pll(limit, crtc,
dev_priv->lvds_downclock,
refclk,
+ &clock,
&reduced_clock);
- if (has_reduced_clock && (clock.p != reduced_clock.p)) {
- /*
- * If the different P is found, it means that we can't
- * switch the display clock by using the FP0/FP1.
- * In such case we will disable the LVDS downclock
- * feature.
- */
- DRM_DEBUG_KMS("Different P is found for "
- "LVDS clock/downclock\n");
- has_reduced_clock = 0;
- }
- }
- /* SDVO TV has fixed PLL values depend on its clock range,
- this mirrors vbios setting. */
- if (is_sdvo && is_tv) {
- if (adjusted_mode->clock >= 100000
- && adjusted_mode->clock < 140500) {
- clock.p1 = 2;
- clock.p2 = 10;
- clock.n = 3;
- clock.m1 = 16;
- clock.m2 = 8;
- } else if (adjusted_mode->clock >= 140500
- && adjusted_mode->clock <= 200000) {
- clock.p1 = 1;
- clock.p2 = 10;
- clock.n = 6;
- clock.m1 = 12;
- clock.m2 = 8;
- }
}
- if (IS_PINEVIEW(dev)) {
- fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
- if (has_reduced_clock)
- fp2 = (1 << reduced_clock.n) << 16 |
- reduced_clock.m1 << 8 | reduced_clock.m2;
- } else {
- fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
- if (has_reduced_clock)
- fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
- reduced_clock.m2;
- }
+ if (is_sdvo && is_tv)
+ i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
+
+ i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ?
+ &reduced_clock : NULL);
dpll = DPLL_VGA_MODE_DIS;
@@ -5177,8 +5277,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
- /* Ironlake's plane is forced to pipe, bit 24 is to
- enable color space conversion */
if (pipe == 0)
dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
else
@@ -5213,7 +5311,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
drm_mode_debug_printmodeline(mode);
- I915_WRITE(FP0(pipe), fp);
I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
POSTING_READ(DPLL(pipe));
@@ -5300,34 +5397,32 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(DPLL(pipe), dpll);
}
- intel_crtc->lowfreq_avail = false;
- if (is_lvds && has_reduced_clock && i915_powersave) {
- I915_WRITE(FP1(pipe), fp2);
- intel_crtc->lowfreq_avail = true;
- if (HAS_PIPE_CXSR(dev)) {
+ if (HAS_PIPE_CXSR(dev)) {
+ if (intel_crtc->lowfreq_avail) {
DRM_DEBUG_KMS("enabling CxSR downclocking\n");
pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
- }
- } else {
- I915_WRITE(FP1(pipe), fp);
- if (HAS_PIPE_CXSR(dev)) {
+ } else {
DRM_DEBUG_KMS("disabling CxSR downclocking\n");
pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
}
}
pipeconf &= ~PIPECONF_INTERLACE_MASK;
- if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ if (!IS_GEN2(dev) &&
+ adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
/* the chip adds 2 halflines automatically */
- adjusted_mode->crtc_vdisplay -= 1;
adjusted_mode->crtc_vtotal -= 1;
- adjusted_mode->crtc_vblank_start -= 1;
adjusted_mode->crtc_vblank_end -= 1;
- adjusted_mode->crtc_vsync_end -= 1;
- adjusted_mode->crtc_vsync_start -= 1;
- } else
+ vsyncshift = adjusted_mode->crtc_hsync_start
+ - adjusted_mode->crtc_htotal/2;
+ } else {
pipeconf |= PIPECONF_PROGRESSIVE;
+ vsyncshift = 0;
+ }
+
+ if (!IS_GEN3(dev))
+ I915_WRITE(VSYNCSHIFT(pipe), vsyncshift);
I915_WRITE(HTOTAL(pipe),
(adjusted_mode->crtc_hdisplay - 1) |
@@ -5593,7 +5688,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/
limit = intel_limit(crtc, refclk);
- ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+ ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+ &clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
return -EINVAL;
@@ -5603,21 +5699,17 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
intel_crtc_update_cursor(crtc, true);
if (is_lvds && dev_priv->lvds_downclock_avail) {
+ /*
+ * Ensure we match the reduced clock's P to the target clock.
+ * If the clocks don't match, we can't switch the display clock
+ * by using the FP0/FP1. In such case we will disable the LVDS
+ * downclock feature.
+ */
has_reduced_clock = limit->find_pll(limit, crtc,
dev_priv->lvds_downclock,
refclk,
+ &clock,
&reduced_clock);
- if (has_reduced_clock && (clock.p != reduced_clock.p)) {
- /*
- * If the different P is found, it means that we can't
- * switch the display clock by using the FP0/FP1.
- * In such case we will disable the LVDS downclock
- * feature.
- */
- DRM_DEBUG_KMS("Different P is found for "
- "LVDS clock/downclock\n");
- has_reduced_clock = 0;
- }
}
/* SDVO TV has fixed PLL values depend on its clock range,
this mirrors vbios setting. */
@@ -5914,16 +6006,17 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
pipeconf &= ~PIPECONF_INTERLACE_MASK;
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
- pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+ pipeconf |= PIPECONF_INTERLACED_ILK;
/* the chip adds 2 halflines automatically */
- adjusted_mode->crtc_vdisplay -= 1;
adjusted_mode->crtc_vtotal -= 1;
- adjusted_mode->crtc_vblank_start -= 1;
adjusted_mode->crtc_vblank_end -= 1;
- adjusted_mode->crtc_vsync_end -= 1;
- adjusted_mode->crtc_vsync_start -= 1;
- } else
+ I915_WRITE(VSYNCSHIFT(pipe),
+ adjusted_mode->crtc_hsync_start
+ - adjusted_mode->crtc_htotal/2);
+ } else {
pipeconf |= PIPECONF_PROGRESSIVE;
+ I915_WRITE(VSYNCSHIFT(pipe), 0);
+ }
I915_WRITE(HTOTAL(pipe),
(adjusted_mode->crtc_hdisplay - 1) |
@@ -5966,12 +6059,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
intel_wait_for_vblank(dev, pipe);
- if (IS_GEN5(dev)) {
- /* enable address swizzle for tiling buffer */
- temp = I915_READ(DISP_ARB_CTL);
- I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
- }
-
I915_WRITE(DSPCNTR(plane), dspcntr);
POSTING_READ(DSPCNTR(plane));
@@ -6086,15 +6173,18 @@ static void ironlake_write_eld(struct drm_connector *connector,
uint32_t i;
int len;
int hdmiw_hdmiedid;
+ int aud_config;
int aud_cntl_st;
int aud_cntrl_st2;
if (HAS_PCH_IBX(connector->dev)) {
hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID_A;
+ aud_config = IBX_AUD_CONFIG_A;
aud_cntl_st = IBX_AUD_CNTL_ST_A;
aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
} else {
hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID_A;
+ aud_config = CPT_AUD_CONFIG_A;
aud_cntl_st = CPT_AUD_CNTL_ST_A;
aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
}
@@ -6102,6 +6192,7 @@ static void ironlake_write_eld(struct drm_connector *connector,
i = to_intel_crtc(crtc)->pipe;
hdmiw_hdmiedid += i * 0x100;
aud_cntl_st += i * 0x100;
+ aud_config += i * 0x100;
DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(i));
@@ -6121,7 +6212,9 @@ static void ironlake_write_eld(struct drm_connector *connector,
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n");
eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */
- }
+ I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */
+ } else
+ I915_WRITE(aud_config, 0);
if (intel_eld_uptodate(connector,
aud_cntrl_st2, eldv,
@@ -6927,9 +7020,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
DRM_DEBUG_DRIVER("upclocking LVDS\n");
- /* Unlock panel regs */
- I915_WRITE(PP_CONTROL,
- I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+ assert_panel_unlocked(dev_priv, pipe);
dpll &= ~DISPLAY_RATE_SELECT_FPA1;
I915_WRITE(dpll_reg, dpll);
@@ -6938,9 +7029,6 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
dpll = I915_READ(dpll_reg);
if (dpll & DISPLAY_RATE_SELECT_FPA1)
DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
-
- /* ...and lock them again */
- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
}
/* Schedule downclock */
@@ -6970,9 +7058,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
DRM_DEBUG_DRIVER("downclocking LVDS\n");
- /* Unlock panel regs */
- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
- PANEL_UNLOCK_REGS);
+ assert_panel_unlocked(dev_priv, pipe);
dpll |= DISPLAY_RATE_SELECT_FPA1;
I915_WRITE(dpll_reg, dpll);
@@ -6980,9 +7066,6 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
dpll = I915_READ(dpll_reg);
if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
DRM_DEBUG_DRIVER("failed to downclock LVDS!\n");
-
- /* ...and lock them again */
- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
}
}
@@ -7097,7 +7180,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
container_of(__work, struct intel_unpin_work, work);
mutex_lock(&work->dev->struct_mutex);
- i915_gem_object_unpin(work->old_fb_obj);
+ intel_unpin_fb_obj(work->old_fb_obj);
drm_gem_object_unreference(&work->pending_flip_obj->base);
drm_gem_object_unreference(&work->old_fb_obj->base);
@@ -7247,7 +7330,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitches[0]);
OUT_RING(obj->gtt_offset + offset);
- OUT_RING(MI_NOOP);
+ OUT_RING(0); /* aux display base address, unused */
ADVANCE_LP_RING();
out:
return ret;
@@ -7681,10 +7764,9 @@ static void intel_setup_outputs(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder;
bool dpd_is_edp = false;
- bool has_lvds = false;
+ bool has_lvds;
- if (IS_MOBILE(dev) && !IS_I830(dev))
- has_lvds = intel_lvds_init(dev);
+ has_lvds = intel_lvds_init(dev);
if (!has_lvds && !HAS_PCH_SPLIT(dev)) {
/* disable the panel fitter on everything but LVDS */
I915_WRITE(PFIT_CONTROL, 0);
@@ -7840,7 +7922,8 @@ int intel_framebuffer_init(struct drm_device *dev,
case DRM_FORMAT_VYUY:
break;
default:
- DRM_ERROR("unsupported pixel format\n");
+ DRM_DEBUG_KMS("unsupported pixel format %u\n",
+ mode_cmd->pixel_format);
return -EINVAL;
}
@@ -8162,6 +8245,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
u32 pcu_mbox, rc6_mask = 0;
+ u32 gtfifodbg;
int cur_freq, min_freq, max_freq;
int i;
@@ -8173,6 +8257,13 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
*/
I915_WRITE(GEN6_RC_STATE, 0);
mutex_lock(&dev_priv->dev->struct_mutex);
+
+ /* Clear the DBG now so we don't confuse earlier errors */
+ if ((gtfifodbg = I915_READ(GTFIFODBG))) {
+ DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
+ I915_WRITE(GTFIFODBG, gtfifodbg);
+ }
+
gen6_gt_force_wake_get(dev_priv);
/* disable the counters and set deterministic thresholds */
@@ -8959,8 +9050,6 @@ struct intel_quirk {
};
struct intel_quirk intel_quirks[] = {
- /* HP Compaq 2730p needs pipe A force quirk (LP: #291555) */
- { 0x2a42, 0x103c, 0x30eb, quirk_pipea_force },
/* HP Mini needs pipe A force quirk (LP: #322104) */
{ 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
@@ -9037,6 +9126,9 @@ void intel_modeset_init(struct drm_device *dev)
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.prefer_shadow = 1;
+
dev->mode_config.funcs = (void *)&intel_mode_funcs;
intel_init_quirks(dev);