From c77ba21d742f33dbb561cba1fe7aac669f5f0339 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 8 Oct 2013 12:25:43 +0200 Subject: [PATCH 001/595] drm/i915/ns2501: Rip out the reenable hack With the change in the modeset sequence this shouldn't be required any more since the ->mode_set callback now gets called when the dvo port is fully up and running. Also limit the retry loop to 10 tries to avoid hanging the machine while holding important modeset locks. Cc: Thomas Richter Tested-by: Thomas Richter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/dvo_ns2501.c | 73 ++----------------------------- 1 file changed, 4 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c index c4a255be6979..954acb2c7021 100644 --- a/drivers/gpu/drm/i915/dvo_ns2501.c +++ b/drivers/gpu/drm/i915/dvo_ns2501.c @@ -87,49 +87,6 @@ struct ns2501_priv { * when switching the resolution. */ -static void enable_dvo(struct intel_dvo_device *dvo) -{ - struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); - struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_gmbus *bus = container_of(adapter, - struct intel_gmbus, - adapter); - struct drm_i915_private *dev_priv = bus->dev_priv; - - DRM_DEBUG_KMS("%s: Trying to re-enable the DVO\n", __FUNCTION__); - - ns->dvoc = I915_READ(DVO_C); - ns->pll_a = I915_READ(_DPLL_A); - ns->srcdim = I915_READ(DVOC_SRCDIM); - ns->fw_blc = I915_READ(FW_BLC); - - I915_WRITE(DVOC, 0x10004084); - I915_WRITE(_DPLL_A, 0xd0820000); - I915_WRITE(DVOC_SRCDIM, 0x400300); // 1024x768 - I915_WRITE(FW_BLC, 0x1080304); - - I915_WRITE(DVOC, 0x90004084); -} - -/* - * Restore the I915 registers modified by the above - * trigger function. - */ -static void restore_dvo(struct intel_dvo_device *dvo) -{ - struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_gmbus *bus = container_of(adapter, - struct intel_gmbus, - adapter); - struct drm_i915_private *dev_priv = bus->dev_priv; - struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); - - I915_WRITE(DVOC, ns->dvoc); - I915_WRITE(_DPLL_A, ns->pll_a); - I915_WRITE(DVOC_SRCDIM, ns->srcdim); - I915_WRITE(FW_BLC, ns->fw_blc); -} - /* ** Read a register from the ns2501. ** Returns true if successful, false otherwise. @@ -300,7 +257,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo, struct drm_display_mode *adjusted_mode) { bool ok; - bool restore = false; + int retries = 10; struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); DRM_DEBUG_KMS @@ -476,20 +433,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo, ns->reg_8_shadow |= NS2501_8_BPAS; } ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow); - - if (!ok) { - if (restore) - restore_dvo(dvo); - enable_dvo(dvo); - restore = true; - } - } while (!ok); - /* - * Restore the old i915 registers before - * forcing the ns2501 on. - */ - if (restore) - restore_dvo(dvo); + } while (!ok && retries--); } /* set the NS2501 power state */ @@ -510,7 +454,7 @@ static bool ns2501_get_hw_state(struct intel_dvo_device *dvo) static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable) { bool ok; - bool restore = false; + int retries = 10; struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); unsigned char ch; @@ -537,16 +481,7 @@ static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable) ok &= ns2501_writeb(dvo, 0x35, enable ? 0xff : 0x00); - if (!ok) { - if (restore) - restore_dvo(dvo); - enable_dvo(dvo); - restore = true; - } - } while (!ok); - - if (restore) - restore_dvo(dvo); + } while (!ok && retries--); } } From f34191585ff30849ab80a03c2bb4294db4cfbffc Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 4 Nov 2013 11:52:44 -0800 Subject: [PATCH 002/595] drm/i915: add bunit read/write routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For modifying self-refresh exit latency. Reviewed-by: Ville Syrjälä Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_sideband.c | 16 ++++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b12d942ab09c..3ffe330fe026 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2400,6 +2400,8 @@ u32 vlv_cck_read(struct drm_i915_private *dev_priv, u32 reg); void vlv_cck_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); u32 vlv_ccu_read(struct drm_i915_private *dev_priv, u32 reg); void vlv_ccu_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); +u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg); +void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); u32 vlv_gps_core_read(struct drm_i915_private *dev_priv, u32 reg); void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3f303ba995c5..0de97adc4fcb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -349,6 +349,7 @@ #define IOSF_BYTE_ENABLES_SHIFT 4 #define IOSF_BAR_SHIFT 1 #define IOSF_SB_BUSY (1<<0) +#define IOSF_PORT_BUNIT 0x3 #define IOSF_PORT_PUNIT 0x4 #define IOSF_PORT_NC 0x11 #define IOSF_PORT_DPIO 0x12 diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index 9944d8135e87..d43e457b6961 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -90,6 +90,22 @@ void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) mutex_unlock(&dev_priv->dpio_lock); } +u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT, + PUNIT_OPCODE_REG_READ, reg, &val); + + return val; +} + +void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT, + PUNIT_OPCODE_REG_WRITE, reg, &val); +} + u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr) { u32 val = 0; From 85b1d7b3f475c6425707b2e064f9c0f54058019d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 4 Nov 2013 11:52:45 -0800 Subject: [PATCH 003/595] drm/i915: move VLV DDR freq fetch into init_clock_gating We don't want it delayed with the RPS work. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 09ac9e79830f..13afd54ca6e9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4064,19 +4064,6 @@ static void valleyview_enable_rps(struct drm_device *dev) I915_WRITE(GEN6_RC_CONTROL, rc6_mode); val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); - switch ((val >> 6) & 3) { - case 0: - case 1: - dev_priv->mem_freq = 800; - break; - case 2: - dev_priv->mem_freq = 1066; - break; - case 3: - dev_priv->mem_freq = 1333; - break; - } - DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq); DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no"); DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val); @@ -5325,6 +5312,24 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) static void valleyview_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + mutex_lock(&dev_priv->rps.hw_lock); + val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); + mutex_unlock(&dev_priv->rps.hw_lock); + switch ((val >> 6) & 3) { + case 0: + case 1: + dev_priv->mem_freq = 800; + break; + case 2: + dev_priv->mem_freq = 1066; + break; + case 3: + dev_priv->mem_freq = 1333; + break; + } + DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq); I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE); From 30a970c6a6ff734eda7cefe7e88f030157a6c939 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 4 Nov 2013 13:48:12 -0800 Subject: [PATCH 004/595] drm/i915/vlv: modeset_global_* for VLV v7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On VLV/BYT, we can adjust the CDclk frequency up or down based on the max pixel clock we need to drive. Lowering it can save power, while raising it is necessary to support high resolution. Add a new callback in modeset_affected_pipes and a modeset_global_resources function to perform this adjustment as necessary. v2: use punit interface for 320 and 266 MHz CDclk adjustments (Ville) v3: reset GMBUS dividers too, since we changed CDclk (Ville) v4: jump to highest voltage when going to 400MHz CDclk (Jesse) v5: drop duplicate define (Ville) use shifts by 1 for fixed point (Ville) drop new callback (Daniel) v6: fixup adjusted_mode.clock -> adjusted_mode.crtc_clock again (Ville) document Bunit reg access better (Ville) v7: pass modeset_pipes and pipe_config to global_pipes so we get the right clock data (Ville) Signed-off-by: Jesse Barnes Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 9 ++ drivers/gpu/drm/i915/intel_display.c | 189 +++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_i2c.c | 4 - 3 files changed, 198 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0de97adc4fcb..86a1ad86aa7b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -360,9 +360,17 @@ #define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104) #define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108) +/* See configdb bunit SB addr map */ +#define BUNIT_REG_BISOC 0x11 + #define PUNIT_OPCODE_REG_READ 6 #define PUNIT_OPCODE_REG_WRITE 7 +#define PUNIT_REG_DSPFREQ 0x36 +#define DSPFREQSTAT_SHIFT 30 +#define DSPFREQSTAT_MASK (0x3 << DSPFREQSTAT_SHIFT) +#define DSPFREQGUAR_SHIFT 14 +#define DSPFREQGUAR_MASK (0x3 << DSPFREQGUAR_SHIFT) #define PUNIT_REG_PWRGT_CTRL 0x60 #define PUNIT_REG_PWRGT_STATUS 0x61 #define PUNIT_CLK_GATE 1 @@ -425,6 +433,7 @@ #define DSI_PLL_N1_DIV_MASK (3 << 16) #define DSI_PLL_M1_DIV_SHIFT 0 #define DSI_PLL_M1_DIV_MASK (0x1ff << 0) +#define CCK_DISPLAY_CLOCK_CONTROL 0x6b /* * DPIO - a special bus for various display related registers to hide behind diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f34252d134b6..c034413a1584 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3894,6 +3894,181 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) I915_WRITE(BCLRPAT(crtc->pipe), 0); } +static int valleyview_get_vco(struct drm_i915_private *dev_priv) +{ + int vco; + + switch (dev_priv->mem_freq) { + default: + case 800: + vco = 800; + break; + case 1066: + vco = 1600; + break; + case 1333: + vco = 2000; + break; + } + + return vco; +} + +/* Adjust CDclk dividers to allow high res or save power if possible */ +static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val, cmd; + + if (cdclk >= 320) /* jump to highest voltage for 400MHz too */ + cmd = 2; + else if (cdclk == 266) + cmd = 1; + else + cmd = 0; + + mutex_lock(&dev_priv->rps.hw_lock); + val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ); + val &= ~DSPFREQGUAR_MASK; + val |= (cmd << DSPFREQGUAR_SHIFT); + vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val); + if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & + DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT), + 50)) { + DRM_ERROR("timed out waiting for CDclk change\n"); + } + mutex_unlock(&dev_priv->rps.hw_lock); + + if (cdclk == 400) { + u32 divider, vco; + + vco = valleyview_get_vco(dev_priv); + divider = ((vco << 1) / cdclk) - 1; + + mutex_lock(&dev_priv->dpio_lock); + /* adjust cdclk divider */ + val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); + val &= ~0xf; + val |= divider; + vlv_cck_write(dev_priv, CCK_DISPLAY_CLOCK_CONTROL, val); + mutex_unlock(&dev_priv->dpio_lock); + } + + mutex_lock(&dev_priv->dpio_lock); + /* adjust self-refresh exit latency value */ + val = vlv_bunit_read(dev_priv, BUNIT_REG_BISOC); + val &= ~0x7f; + + /* + * For high bandwidth configs, we set a higher latency in the bunit + * so that the core display fetch happens in time to avoid underruns. + */ + if (cdclk == 400) + val |= 4500 / 250; /* 4.5 usec */ + else + val |= 3000 / 250; /* 3.0 usec */ + vlv_bunit_write(dev_priv, BUNIT_REG_BISOC, val); + mutex_unlock(&dev_priv->dpio_lock); + + /* Since we changed the CDclk, we need to update the GMBUSFREQ too */ + intel_i2c_reset(dev); +} + +static int valleyview_cur_cdclk(struct drm_i915_private *dev_priv) +{ + int cur_cdclk, vco; + int divider; + + vco = valleyview_get_vco(dev_priv); + + mutex_lock(&dev_priv->dpio_lock); + divider = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); + mutex_unlock(&dev_priv->dpio_lock); + + divider &= 0xf; + + cur_cdclk = (vco << 1) / (divider + 1); + + return cur_cdclk; +} + +static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, + int max_pixclk) +{ + int cur_cdclk; + + cur_cdclk = valleyview_cur_cdclk(dev_priv); + + /* + * Really only a few cases to deal with, as only 4 CDclks are supported: + * 200MHz + * 267MHz + * 320MHz + * 400MHz + * So we check to see whether we're above 90% of the lower bin and + * adjust if needed. + */ + if (max_pixclk > 288000) { + return 400; + } else if (max_pixclk > 240000) { + return 320; + } else + return 266; + /* Looks like the 200MHz CDclk freq doesn't work on some configs */ +} + +static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv, + unsigned modeset_pipes, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *intel_crtc; + int max_pixclk = 0; + + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) { + if (modeset_pipes & (1 << intel_crtc->pipe)) + max_pixclk = max(max_pixclk, + pipe_config->adjusted_mode.crtc_clock); + else if (intel_crtc->base.enabled) + max_pixclk = max(max_pixclk, + intel_crtc->config.adjusted_mode.crtc_clock); + } + + return max_pixclk; +} + +static void valleyview_modeset_global_pipes(struct drm_device *dev, + unsigned *prepare_pipes, + unsigned modeset_pipes, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc; + int max_pixclk = intel_mode_max_pixclk(dev_priv, modeset_pipes, + pipe_config); + int cur_cdclk = valleyview_cur_cdclk(dev_priv); + + if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk) + return; + + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) + if (intel_crtc->base.enabled) + *prepare_pipes |= (1 << intel_crtc->pipe); +} + +static void valleyview_modeset_global_resources(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixclk = intel_mode_max_pixclk(dev_priv, 0, NULL); + int cur_cdclk = valleyview_cur_cdclk(dev_priv); + int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); + + if (req_cdclk != cur_cdclk) + valleyview_set_cdclk(dev, req_cdclk); +} + static void valleyview_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -9318,6 +9493,17 @@ static int __intel_set_mode(struct drm_crtc *crtc, "[modeset]"); } + /* + * See if the config requires any additional preparation, e.g. + * to adjust global state with pipes off. We need to do this + * here so we can get the modeset_pipe updated config for the new + * mode set on this crtc. For other crtcs we need to use the + * adjusted_mode bits in the crtc directly. + */ + if (IS_VALLEYVIEW(dev)) + valleyview_modeset_global_pipes(dev, &prepare_pipes, + modeset_pipes, pipe_config); + for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) intel_crtc_disable(&intel_crtc->base); @@ -10317,6 +10503,9 @@ static void intel_init_display(struct drm_device *dev) } } else if (IS_G4X(dev)) { dev_priv->display.write_eld = g4x_write_eld; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.modeset_global_resources = + valleyview_modeset_global_resources; } /* Default just returns -ENODEV to indicate unsupported */ diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 2ca17b14b6c1..1263409d00b3 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -87,10 +87,6 @@ static void gmbus_set_freq(struct drm_i915_private *dev_priv) BUG_ON(!IS_VALLEYVIEW(dev_priv->dev)); - /* Skip setting the gmbus freq if BIOS has already programmed it */ - if (I915_READ(GMBUSFREQ_VLV) != 0xA0) - return; - /* Obtain SKU information */ mutex_lock(&dev_priv->dpio_lock); hpll_freq = From 586f49dc781314f1e6b1133f6d966d670c219a67 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 4 Nov 2013 16:06:59 -0800 Subject: [PATCH 005/595] drm/i915/vlv: split CCK and DDR freq usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's possible that the CCK clock could run at a different rate than the DDR clock, so use the same method to get CCK as the GMBUS code does when calculating the new CDclk divider in the VLV display code. Reported-by: Ville Syrjälä Signed-off-by: Jesse Barnes Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 23 ++++++++--------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_i2c.c | 11 +++-------- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c034413a1584..3c17e959a0eb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3894,24 +3894,17 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) I915_WRITE(BCLRPAT(crtc->pipe), 0); } -static int valleyview_get_vco(struct drm_i915_private *dev_priv) +int valleyview_get_vco(struct drm_i915_private *dev_priv) { - int vco; + int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; - switch (dev_priv->mem_freq) { - default: - case 800: - vco = 800; - break; - case 1066: - vco = 1600; - break; - case 1333: - vco = 2000; - break; - } + /* Obtain SKU information */ + mutex_lock(&dev_priv->dpio_lock); + hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) & + CCK_FUSE_HPLL_FREQ_MASK; + mutex_unlock(&dev_priv->dpio_lock); - return vco; + return vco_freq[hpll_freq]; } /* Adjust CDclk dividers to allow high res or save power if possible */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9d2624fd92c2..6d701e79b611 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -693,7 +693,7 @@ void i915_disable_vga_mem(struct drm_device *dev); void hsw_enable_ips(struct intel_crtc *crtc); void hsw_disable_ips(struct intel_crtc *crtc); void intel_display_set_init_power(struct drm_device *dev, bool enable); - +int valleyview_get_vco(struct drm_i915_private *dev_priv); /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 1263409d00b3..b1dc33f47899 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -82,16 +82,11 @@ static int get_disp_clk_div(struct drm_i915_private *dev_priv, static void gmbus_set_freq(struct drm_i915_private *dev_priv) { - int vco_freq[] = { 800, 1600, 2000, 2400 }; - int gmbus_freq = 0, cdclk_div, hpll_freq; + int vco, gmbus_freq = 0, cdclk_div; BUG_ON(!IS_VALLEYVIEW(dev_priv->dev)); - /* Obtain SKU information */ - mutex_lock(&dev_priv->dpio_lock); - hpll_freq = - vlv_cck_read(dev_priv, CCK_FUSE_REG) & CCK_FUSE_HPLL_FREQ_MASK; - mutex_unlock(&dev_priv->dpio_lock); + vco = valleyview_get_vco(dev_priv); /* Get the CDCLK divide ratio */ cdclk_div = get_disp_clk_div(dev_priv, CDCLK); @@ -102,7 +97,7 @@ static void gmbus_set_freq(struct drm_i915_private *dev_priv) * in fact 1MHz is the correct frequency. */ if (cdclk_div) - gmbus_freq = (vco_freq[hpll_freq] << 1) / cdclk_div; + gmbus_freq = (vco << 1) / cdclk_div; if (WARN_ON(gmbus_freq == 0)) return; From f64a28a7c5ab2fc342326de9e126acf3cc0f91d6 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 4 Nov 2013 16:07:00 -0800 Subject: [PATCH 006/595] drm/i915/vlv: fixup DDR freq detection per Punit spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Either the docs were wrong or the values have changed since the old days before we had wheels. Reported-by: Ville Syrjälä Signed-off-by: Jesse Barnes Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 13afd54ca6e9..a5778e59cc15 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5319,15 +5319,22 @@ static void valleyview_init_clock_gating(struct drm_device *dev) mutex_unlock(&dev_priv->rps.hw_lock); switch ((val >> 6) & 3) { case 0: - case 1: dev_priv->mem_freq = 800; break; - case 2: + case 1: dev_priv->mem_freq = 1066; break; - case 3: + case 2: dev_priv->mem_freq = 1333; break; + case 3: + /* + * Probably a BIOS/Punit bug, or a new platform we don't + * support yet. + */ + WARN(1, "invalid DDR freq detected, assuming 800MHz\n"); + dev_priv->mem_freq = 800; + break; } DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq); From c164f833cc842b427f817c3a6f30d806b1d57ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 Nov 2013 22:34:12 +0200 Subject: [PATCH 007/595] drm/i915: Sanitize prepare_pipes after valleyview_modeset_global_pipes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit valleyview_modeset_global_pipes() may add pipes that are getting fully disabled to prepare_pipes bitmask. The rest of the code doesn't expect this, so clear out any such pipes from the prepare_pipes bitmask. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3c17e959a0eb..e36b3b057801 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9493,10 +9493,14 @@ static int __intel_set_mode(struct drm_crtc *crtc, * mode set on this crtc. For other crtcs we need to use the * adjusted_mode bits in the crtc directly. */ - if (IS_VALLEYVIEW(dev)) + if (IS_VALLEYVIEW(dev)) { valleyview_modeset_global_pipes(dev, &prepare_pipes, modeset_pipes, pipe_config); + /* may have added more to prepare_pipes than we should */ + prepare_pipes &= ~disable_pipes; + } + for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) intel_crtc_disable(&intel_crtc->base); From 07ab118b393410c65146f44c17b0ae5373eb972e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 Nov 2013 22:42:28 +0200 Subject: [PATCH 008/595] drm/i915: Improve vlv_gpu_freq() and vlv_freq_opcode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're currently miscalculating the VLV graphics clock a little bit. This is caused by rounding the step to integer MHz, which does not match reality. Change the formula to match the GUnit HAS to give more accurate answers. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 35 +++++++++++---------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a5778e59cc15..865035beccc7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5947,57 +5947,46 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val) int vlv_gpu_freq(int ddr_freq, int val) { - int mult, base; + int div; + /* 4 x czclk */ switch (ddr_freq) { case 800: - mult = 20; - base = 120; + div = 10; break; case 1066: - mult = 22; - base = 133; + div = 12; break; case 1333: - mult = 21; - base = 125; + div = 16; break; default: return -1; } - return ((val - 0xbd) * mult) + base; + return DIV_ROUND_CLOSEST(ddr_freq * (val + 6 - 0xbd), 4 * div); } int vlv_freq_opcode(int ddr_freq, int val) { - int mult, base; + int mul; + /* 4 x czclk */ switch (ddr_freq) { case 800: - mult = 20; - base = 120; + mul = 10; break; case 1066: - mult = 22; - base = 133; + mul = 12; break; case 1333: - mult = 21; - base = 125; + mul = 16; break; default: return -1; } - val /= mult; - val -= base / mult; - val += 0xbd; - - if (val > 0xea) - val = 0xea; - - return val; + return DIV_ROUND_CLOSEST(4 * mul * val, ddr_freq) + 0xbd - 6; } void intel_pm_init(struct drm_device *dev) From 2ec3815f29d1b7659ecf3f1791e7e394efdd6969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 Nov 2013 22:42:29 +0200 Subject: [PATCH 009/595] drm/i915: Pass dev_priv to vlv_gpu_freq() and vlv_freq_opcode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'll be looking at more than just mem_freq from dev_priv, so just pass the whole thing. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 17 ++++++------- drivers/gpu/drm/i915/i915_drv.h | 4 +-- drivers/gpu/drm/i915/i915_sysfs.c | 13 +++++----- drivers/gpu/drm/i915/intel_pm.c | 38 ++++++++++++----------------- 4 files changed, 31 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7008aacfc3c9..9770c2f81196 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -974,15 +974,14 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) val = vlv_punit_read(dev_priv, PUNIT_FUSE_BUS1); seq_printf(m, "max GPU freq: %d MHz\n", - vlv_gpu_freq(dev_priv->mem_freq, val)); + vlv_gpu_freq(dev_priv, val)); val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM); seq_printf(m, "min GPU freq: %d MHz\n", - vlv_gpu_freq(dev_priv->mem_freq, val)); + vlv_gpu_freq(dev_priv, val)); seq_printf(m, "current GPU freq: %d MHz\n", - vlv_gpu_freq(dev_priv->mem_freq, - (freq_sts >> 8) & 0xff)); + vlv_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff)); mutex_unlock(&dev_priv->rps.hw_lock); } else { seq_puts(m, "no P-state info available\n"); @@ -2725,8 +2724,7 @@ i915_max_freq_get(void *data, u64 *val) return ret; if (IS_VALLEYVIEW(dev)) - *val = vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.max_delay); + *val = vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay); else *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); @@ -2756,7 +2754,7 @@ i915_max_freq_set(void *data, u64 val) * Turbo will still be enabled, but won't go above the set value. */ if (IS_VALLEYVIEW(dev)) { - val = vlv_freq_opcode(dev_priv->mem_freq, val); + val = vlv_freq_opcode(dev_priv, val); dev_priv->rps.max_delay = val; gen6_set_rps(dev, val); } else { @@ -2791,8 +2789,7 @@ i915_min_freq_get(void *data, u64 *val) return ret; if (IS_VALLEYVIEW(dev)) - *val = vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.min_delay); + *val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay); else *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); @@ -2822,7 +2819,7 @@ i915_min_freq_set(void *data, u64 val) * Turbo will still be enabled, but won't go below the set value. */ if (IS_VALLEYVIEW(dev)) { - val = vlv_freq_opcode(dev_priv->mem_freq, val); + val = vlv_freq_opcode(dev_priv, val); dev_priv->rps.min_delay = val; valleyview_set_rps(dev, val); } else { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3ffe330fe026..e2d974594b2b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2411,8 +2411,8 @@ u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, enum intel_sbi_destination destination); -int vlv_gpu_freq(int ddr_freq, int val); -int vlv_freq_opcode(int ddr_freq, int val); +int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val); +int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val); #define I915_READ8(reg) dev_priv->uncore.funcs.mmio_readb(dev_priv, (reg), true) #define I915_WRITE8(reg, val) dev_priv->uncore.funcs.mmio_writeb(dev_priv, (reg), (val), true) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 9ff1e4d96909..2fc8d2f401be 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -257,7 +257,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, if (IS_VALLEYVIEW(dev_priv->dev)) { u32 freq; freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); - ret = vlv_gpu_freq(dev_priv->mem_freq, (freq >> 8) & 0xff); + ret = vlv_gpu_freq(dev_priv, (freq >> 8) & 0xff); } else { ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; } @@ -274,8 +274,7 @@ static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev, struct drm_i915_private *dev_priv = dev->dev_private; return snprintf(buf, PAGE_SIZE, "%d\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.rpe_delay)); + vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay)); } static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf) @@ -289,7 +288,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) - ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.max_delay); + ret = vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay); else ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); @@ -316,7 +315,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) { - val = vlv_freq_opcode(dev_priv->mem_freq, val); + val = vlv_freq_opcode(dev_priv, val); hw_max = valleyview_rps_max_freq(dev_priv); hw_min = valleyview_rps_min_freq(dev_priv); @@ -365,7 +364,7 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) - ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.min_delay); + ret = vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay); else ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); @@ -392,7 +391,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev)) { - val = vlv_freq_opcode(dev_priv->mem_freq, val); + val = vlv_freq_opcode(dev_priv, val); hw_max = valleyview_rps_max_freq(dev_priv); hw_min = valleyview_rps_min_freq(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 865035beccc7..f5bb9b349487 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3609,9 +3609,9 @@ static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv) if (pval != dev_priv->rps.cur_delay) DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay), dev_priv->rps.cur_delay, - vlv_gpu_freq(dev_priv->mem_freq, pval), pval); + vlv_gpu_freq(dev_priv, pval), pval); dev_priv->rps.cur_delay = pval; } @@ -3629,10 +3629,9 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) vlv_update_rps_cur_delay(dev_priv); DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.cur_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay), dev_priv->rps.cur_delay, - vlv_gpu_freq(dev_priv->mem_freq, val), val); + vlv_gpu_freq(dev_priv, val), val); if (val == dev_priv->rps.cur_delay) return; @@ -3641,7 +3640,7 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) dev_priv->rps.cur_delay = val; - trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val)); + trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val)); } static void gen6_disable_rps_interrupts(struct drm_device *dev) @@ -4070,32 +4069,27 @@ static void valleyview_enable_rps(struct drm_device *dev) dev_priv->rps.cur_delay = (val >> 8) & 0xff; DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.cur_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay), dev_priv->rps.cur_delay); dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv); dev_priv->rps.hw_max = dev_priv->rps.max_delay; DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.max_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay), dev_priv->rps.max_delay); dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv); DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.rpe_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay), dev_priv->rps.rpe_delay); dev_priv->rps.min_delay = valleyview_rps_min_freq(dev_priv); DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.min_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay), dev_priv->rps.min_delay); DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.rpe_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay), dev_priv->rps.rpe_delay); valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); @@ -5945,12 +5939,12 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val) return 0; } -int vlv_gpu_freq(int ddr_freq, int val) +int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val) { int div; /* 4 x czclk */ - switch (ddr_freq) { + switch (dev_priv->mem_freq) { case 800: div = 10; break; @@ -5964,15 +5958,15 @@ int vlv_gpu_freq(int ddr_freq, int val) return -1; } - return DIV_ROUND_CLOSEST(ddr_freq * (val + 6 - 0xbd), 4 * div); + return DIV_ROUND_CLOSEST(dev_priv->mem_freq * (val + 6 - 0xbd), 4 * div); } -int vlv_freq_opcode(int ddr_freq, int val) +int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val) { int mul; /* 4 x czclk */ - switch (ddr_freq) { + switch (dev_priv->mem_freq) { case 800: mul = 10; break; @@ -5986,7 +5980,7 @@ int vlv_freq_opcode(int ddr_freq, int val) return -1; } - return DIV_ROUND_CLOSEST(4 * mul * val, ddr_freq) + 0xbd - 6; + return DIV_ROUND_CLOSEST(4 * mul * val, dev_priv->mem_freq) + 0xbd - 6; } void intel_pm_init(struct drm_device *dev) From 8245be31391974dc756a21cf2f2e25c7f53637c5 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 6 Nov 2013 13:56:29 -0200 Subject: [PATCH 010/595] drm/i915: Require HW contexts (when possible) v2: Fixed the botched locking on init_hw failure in i915_reset (Ville) Call cleanup_ringbuffer on failed context create in init_hw (Ville) v3: Add dev argument ti clean_ringbuffer Reviewed-by: Kenneth Graunke Signed-off-by: Ben Widawsky Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 3 -- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/i915_gem.c | 8 ++++- drivers/gpu/drm/i915/i915_gem_context.c | 43 ++++++++++++------------- drivers/gpu/drm/i915/i915_sysfs.c | 6 ++-- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a0804fa1e306..65447572b129 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -755,12 +755,9 @@ int i915_reset(struct drm_device *dev) */ if (drm_core_check_feature(dev, DRIVER_MODESET) || !dev_priv->ums.mm_suspended) { - bool hw_contexts_disabled = dev_priv->hw_contexts_disabled; dev_priv->ums.mm_suspended = 0; ret = i915_gem_init_hw(dev); - if (!hw_contexts_disabled && dev_priv->hw_contexts_disabled) - DRM_ERROR("HW contexts didn't survive reset\n"); mutex_unlock(&dev->struct_mutex); if (ret) { DRM_ERROR("Failed hw init on reset %d\n", ret); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e2d974594b2b..efca30dc6c57 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1447,7 +1447,6 @@ typedef struct drm_i915_private { struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; - bool hw_contexts_disabled; uint32_t hw_context_size; struct list_head context_list; @@ -2151,7 +2150,7 @@ i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj, } /* i915_gem_context.c */ -void i915_gem_context_init(struct drm_device *dev); +int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_ring_buffer *ring, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e7b39d731db6..bc528201caca 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4463,7 +4463,13 @@ i915_gem_init_hw(struct drm_device *dev) * XXX: There was some w/a described somewhere suggesting loading * contexts before PPGTT. */ - i915_gem_context_init(dev); + ret = i915_gem_context_init(dev); + if (ret) { + i915_gem_cleanup_ringbuffer(dev); + DRM_ERROR("Context initialization failed %d\n", ret); + return ret; + } + if (dev_priv->mm.aliasing_ppgtt) { ret = dev_priv->mm.aliasing_ppgtt->enable(dev); if (ret) { diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index cc619c138777..4625670bcadb 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -244,36 +244,34 @@ static int create_default_context(struct drm_i915_private *dev_priv) return ret; } -void i915_gem_context_init(struct drm_device *dev) +int i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + int ret; - if (!HAS_HW_CONTEXTS(dev)) { - dev_priv->hw_contexts_disabled = true; - DRM_DEBUG_DRIVER("Disabling HW Contexts; old hardware\n"); - return; - } + if (!HAS_HW_CONTEXTS(dev)) + return 0; /* If called from reset, or thaw... we've been here already */ - if (dev_priv->hw_contexts_disabled || - dev_priv->ring[RCS].default_context) - return; + if (dev_priv->ring[RCS].default_context) + return 0; dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); if (dev_priv->hw_context_size > (1<<20)) { - dev_priv->hw_contexts_disabled = true; DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n"); - return; + return -E2BIG; } - if (create_default_context(dev_priv)) { - dev_priv->hw_contexts_disabled = true; - DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed\n"); - return; + ret = create_default_context(dev_priv); + if (ret) { + DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %d\n", + ret); + return ret; } DRM_DEBUG_DRIVER("HW context support initialized\n"); + return 0; } void i915_gem_context_fini(struct drm_device *dev) @@ -281,7 +279,7 @@ void i915_gem_context_fini(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context; - if (dev_priv->hw_contexts_disabled) + if (!HAS_HW_CONTEXTS(dev)) return; /* The only known way to stop the gpu from accessing the hw context is @@ -324,16 +322,16 @@ i915_gem_context_get_hang_stats(struct drm_device *dev, struct drm_file *file, u32 id) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_file_private *file_priv = file->driver_priv; struct i915_hw_context *ctx; if (id == DEFAULT_CONTEXT_ID) return &file_priv->hang_stats; - ctx = NULL; - if (!dev_priv->hw_contexts_disabled) - ctx = i915_gem_context_get(file->driver_priv, id); + if (!HAS_HW_CONTEXTS(dev)) + return ERR_PTR(-ENOENT); + + ctx = i915_gem_context_get(file->driver_priv, id); if (ctx == NULL) return ERR_PTR(-ENOENT); @@ -506,7 +504,7 @@ int i915_switch_context(struct intel_ring_buffer *ring, struct drm_i915_private *dev_priv = ring->dev->dev_private; struct i915_hw_context *to; - if (dev_priv->hw_contexts_disabled) + if (!HAS_HW_CONTEXTS(ring->dev)) return 0; WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); @@ -531,7 +529,6 @@ int i915_switch_context(struct intel_ring_buffer *ring, int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_context_create *args = data; struct drm_i915_file_private *file_priv = file->driver_priv; struct i915_hw_context *ctx; @@ -540,7 +537,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; - if (dev_priv->hw_contexts_disabled) + if (!HAS_HW_CONTEXTS(dev)) return -ENODEV; ret = i915_mutex_lock_interruptible(dev); diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 2fc8d2f401be..85b98111d995 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -181,13 +181,13 @@ i915_l3_write(struct file *filp, struct kobject *kobj, int slice = (int)(uintptr_t)attr->private; int ret; + if (!HAS_HW_CONTEXTS(drm_dev)) + return -ENXIO; + ret = l3_access_valid(drm_dev, offset); if (ret) return ret; - if (dev_priv->hw_contexts_disabled) - return -ENXIO; - ret = i915_mutex_lock_interruptible(drm_dev); if (ret) return ret; From 2325991e021fb0da21d8d08009d1eea78133745a Mon Sep 17 00:00:00 2001 From: Chon Ming Lee Date: Thu, 7 Nov 2013 15:23:26 +0800 Subject: [PATCH 011/595] drm/i915/vlv: Workaround a punit issue in DDR data rate for 1333. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For DDR data rate reporting by Punit in PUNIT_GPU_FREQ_STS, the actual data encoding is 00b=800, 01b=1066, 10b=1333, 11b=1333. Some premium VLV sku will get the DDR_DATA_RATE set as 11. As a result, the turbo frequency reporting will be incorrect without this workaround. Signed-off-by: Chon Ming Lee Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f5bb9b349487..38943f8ef260 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5322,12 +5322,7 @@ static void valleyview_init_clock_gating(struct drm_device *dev) dev_priv->mem_freq = 1333; break; case 3: - /* - * Probably a BIOS/Punit bug, or a new platform we don't - * support yet. - */ - WARN(1, "invalid DDR freq detected, assuming 800MHz\n"); - dev_priv->mem_freq = 800; + dev_priv->mem_freq = 1333; break; } DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq); From edc08d0a40f7ddab6bf7249e59ecf692d36c7192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Nov 2013 13:56:27 -0200 Subject: [PATCH 012/595] drm/i915: Fix gen3/4 vblank counter wraparound MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the hardware frame counter reads 0xffffff and we're already past vblank start, we'd return 0x1000000 as the vblank counter value. Once we'd cross into the next frame's active portion, the vblank counter would wrap to 0. So we're reporting two different vblank counter values for the same frame. Fix the problem by masking the cooked value by 0xffffff to make sure the counter wraps already after vblank start. Signed-off-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a228176676b2..c6176f337452 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -583,7 +583,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) * Cook up a vblank counter by also checking the pixel * counter against vblank start. */ - return ((high1 << 8) | low) + (pixel >= vbl_start); + return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff; } static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) From 57e22f4add51b0f42b76a6960c4a4daa71e8f832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Nov 2013 13:56:28 -0200 Subject: [PATCH 013/595] drm/i915: Use frame counter for intel_wait_for_vblank() on CTG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the same wait_for_vblank code for CTG that we use for ILK+. Also fix the name of the frame counter register while at it. Signed-off-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e36b3b057801..0980bd95e372 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -748,10 +748,10 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, return intel_crtc->config.cpu_transcoder; } -static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe) +static void g4x_wait_for_vblank(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 frame, frame_reg = PIPEFRAME(pipe); + u32 frame, frame_reg = PIPE_FRMCOUNT_GM45(pipe); frame = I915_READ(frame_reg); @@ -772,8 +772,8 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) struct drm_i915_private *dev_priv = dev->dev_private; int pipestat_reg = PIPESTAT(pipe); - if (INTEL_INFO(dev)->gen >= 5) { - ironlake_wait_for_vblank(dev, pipe); + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + g4x_wait_for_vblank(dev, pipe); return; } From c5bd2bf61d487cd0125433aeaadd8bb87a11ccff Mon Sep 17 00:00:00 2001 From: Chon Ming Lee Date: Thu, 7 Nov 2013 15:23:27 +0800 Subject: [PATCH 014/595] drm/i915/vlv: For i915_cur_delayinfo, the max frequency reporting wrong value. The max frequency reporting is not correct. But there is already an existing valleyview_rps_max_freq and valleyview_rps_min_freq to get the frequency. Use that for i915_cur_delayinfo. Signed-off-by: Chon Ming Lee Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9770c2f81196..6889d81dc559 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -972,11 +972,11 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq); - val = vlv_punit_read(dev_priv, PUNIT_FUSE_BUS1); + val = valleyview_rps_max_freq(dev_priv); seq_printf(m, "max GPU freq: %d MHz\n", vlv_gpu_freq(dev_priv, val)); - val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM); + val = valleyview_rps_min_freq(dev_priv); seq_printf(m, "min GPU freq: %d MHz\n", vlv_gpu_freq(dev_priv, val)); From 6917c7b9d9083272ddf7e64f5482e8820a31fb3c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 6 Nov 2013 13:56:26 -0200 Subject: [PATCH 015/595] drm/i915: Initialise min/max frequencies before updating RPS registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RPS register writing routines use the current value of min/max to set certain limits and interrupt gating. If we set those afterwards, we risk setting up the hw incorrectly and losing power management events, and worse, trigger some internal assertions. Reorder the calling sequences to be correct, and remove the then unrequired clamping from inside set_rps(). And for a bonus, fix the bug of calling gen6_set_rps() from Valleyview. Signed-off-by: Chris Wilson Signed-off-by: Rodrigo Vivi Reviewed-by: Ville Syrjälä CC: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_sysfs.c | 20 ++++++++++---------- drivers/gpu/drm/i915/intel_pm.c | 19 +++++-------------- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6889d81dc559..b5df88fa890a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2756,7 +2756,7 @@ i915_max_freq_set(void *data, u64 val) if (IS_VALLEYVIEW(dev)) { val = vlv_freq_opcode(dev_priv, val); dev_priv->rps.max_delay = val; - gen6_set_rps(dev, val); + valleyview_set_rps(dev, val); } else { do_div(val, GT_FREQUENCY_MULTIPLIER); dev_priv->rps.max_delay = val; diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 85b98111d995..fdce8824723c 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -339,15 +339,15 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, DRM_DEBUG("User requested overclocking to %d\n", val * GT_FREQUENCY_MULTIPLIER); - if (dev_priv->rps.cur_delay > val) { - if (IS_VALLEYVIEW(dev_priv->dev)) - valleyview_set_rps(dev_priv->dev, val); - else - gen6_set_rps(dev_priv->dev, val); - } - dev_priv->rps.max_delay = val; + if (dev_priv->rps.cur_delay > val) { + if (IS_VALLEYVIEW(dev)) + valleyview_set_rps(dev, val); + else + gen6_set_rps(dev, val); + } + mutex_unlock(&dev_priv->rps.hw_lock); return count; @@ -408,15 +408,15 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, return -EINVAL; } + dev_priv->rps.min_delay = val; + if (dev_priv->rps.cur_delay < val) { if (IS_VALLEYVIEW(dev)) valleyview_set_rps(dev, val); else - gen6_set_rps(dev_priv->dev, val); + gen6_set_rps(dev, val); } - dev_priv->rps.min_delay = val; - mutex_unlock(&dev_priv->rps.hw_lock); return count; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 38943f8ef260..e37860377285 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3414,26 +3414,19 @@ static void ironlake_disable_drps(struct drm_device *dev) * ourselves, instead of doing a rmw cycle (which might result in us clearing * all limits and the gpu stuck at whatever frequency it is at atm). */ -static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 *val) +static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val) { u32 limits; - limits = 0; - - if (*val >= dev_priv->rps.max_delay) - *val = dev_priv->rps.max_delay; - limits |= dev_priv->rps.max_delay << 24; - /* Only set the down limit when we've reached the lowest level to avoid * getting more interrupts, otherwise leave this clear. This prevents a * race in the hw when coming out of rc6: There's a tiny window where * the hw runs at the minimal clock before selecting the desired * frequency, if the down threshold expires in that window we will not * receive a down interrupt. */ - if (*val <= dev_priv->rps.min_delay) { - *val = dev_priv->rps.min_delay; + limits = dev_priv->rps.max_delay << 24; + if (val <= dev_priv->rps.min_delay) limits |= dev_priv->rps.min_delay << 16; - } return limits; } @@ -3533,7 +3526,6 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val) void gen6_set_rps(struct drm_device *dev, u8 val) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 limits = gen6_rps_limits(dev_priv, &val); WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); WARN_ON(val > dev_priv->rps.max_delay); @@ -3556,7 +3548,8 @@ void gen6_set_rps(struct drm_device *dev, u8 val) /* Make sure we continue to get interrupts * until we hit the minimum or maximum frequencies. */ - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, + gen6_rps_limits(dev_priv, val)); POSTING_READ(GEN6_RPNSWREQ); @@ -3620,8 +3613,6 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) { struct drm_i915_private *dev_priv = dev->dev_private; - gen6_rps_limits(dev_priv, &val); - WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); WARN_ON(val > dev_priv->rps.max_delay); WARN_ON(val < dev_priv->rps.min_delay); From 4c7915616a7a09be0c1e5b76c26381df15fe671b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Nov 2013 19:57:48 +0200 Subject: [PATCH 016/595] drm/i915: Kill vlv_update_rps_cur_delay() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Polling to make sure the current GPU frequency matches the last requested frequency should not be necessay, and if there's some throttling involved, the two might not match anyway. Since we're still seeing this trigger occasionally, and it just introduces a rather pointless 10 ms delay, it seems like better to kill it off. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e37860377285..542b4448ccb7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3584,31 +3584,6 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv) mutex_unlock(&dev_priv->rps.hw_lock); } -/* - * Wait until the previous freq change has completed, - * or the timeout elapsed, and then update our notion - * of the current GPU frequency. - */ -static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv) -{ - u32 pval; - - WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); - - if (wait_for(((pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS)) & GENFREQSTATUS) == 0, 10)) - DRM_DEBUG_DRIVER("timed out waiting for Punit\n"); - - pval >>= 8; - - if (pval != dev_priv->rps.cur_delay) - DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n", - vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay), - dev_priv->rps.cur_delay, - vlv_gpu_freq(dev_priv, pval), pval); - - dev_priv->rps.cur_delay = pval; -} - void valleyview_set_rps(struct drm_device *dev, u8 val) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3617,8 +3592,6 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) WARN_ON(val > dev_priv->rps.max_delay); WARN_ON(val < dev_priv->rps.min_delay); - vlv_update_rps_cur_delay(dev_priv); - DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n", vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay), dev_priv->rps.cur_delay, From 1272e7b854e768ede5279de57b78a54cb39f5da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 7 Nov 2013 19:57:49 +0200 Subject: [PATCH 017/595] drm/i915: Use clamp_t() when limiting cur_delay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the cur_delay limiting code a bit less prone to typo errors by using clamp_t(). Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c6176f337452..e14285bafbd4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -966,10 +966,8 @@ static void gen6_pm_rps_work(struct work_struct *work) /* sysfs frequency interfaces may have snuck in while servicing the * interrupt */ - if (new_delay < (int)dev_priv->rps.min_delay) - new_delay = dev_priv->rps.min_delay; - if (new_delay > (int)dev_priv->rps.max_delay) - new_delay = dev_priv->rps.max_delay; + new_delay = clamp_t(int, new_delay, + dev_priv->rps.min_delay, dev_priv->rps.max_delay); dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay; if (IS_VALLEYVIEW(dev_priv->dev)) From ab3c759a0461528fcfab155b97da69edbc24b5d0 Mon Sep 17 00:00:00 2001 From: Chon Ming Lee Date: Thu, 7 Nov 2013 10:43:30 +0800 Subject: [PATCH 018/595] drm/i915/vlv: Rename VLV DPIO register to be more structure to match configdb document. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some VLV PHY/PLL DPIO registers have group/lane/channel access. Current DPIO register definition doesn't have a structure way to break them down. As a result it is not easy to match the PHY/PLL registers with the configdb document. Rename those registers based on the configdb for easy cross references, and without the need to check the offset in the header file. New format is as following. __DW_ For example, VLV_PCS_DW0 - Group access to PCS for lane 0 to 3 for PCS DWORD 0. VLV_PCS01_DW0_CH0 - PCS access to lane 0/1, channel 0 for PCS DWORD 0. Another example is VLV_TX_DW0 - Group access to TX lane 0 to 3 for TX DWORD 0 VLV_TX0_DW0 - Refer to TX Lane 0 access only for TX DWORD 0. There is no functional change on this patch. v2: Rebase based on previous patch change. v3: There may be configdb different version that document the start DW differently. Add a comment to clarify. Fix up some mismatch start DW for second PLL block. (Ville) Suggested-by: Ville Syrjälä Signed-off-by: Chon Ming Lee Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 34 +++--- drivers/gpu/drm/i915/i915_reg.h | 169 +++++++++++++-------------- drivers/gpu/drm/i915/intel_display.c | 48 ++++---- drivers/gpu/drm/i915/intel_dp.c | 32 ++--- drivers/gpu/drm/i915/intel_hdmi.c | 52 ++++----- 5 files changed, 157 insertions(+), 178 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index b5df88fa890a..1dbcc64f9ddb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1649,28 +1649,28 @@ static int i915_dpio_info(struct seq_file *m, void *data) seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL)); - seq_printf(m, "DPIO_DIV_A: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_DIV_A)); - seq_printf(m, "DPIO_DIV_B: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_DIV_B)); + seq_printf(m, "DPIO PLL DW3 CH0 : 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW3(0))); + seq_printf(m, "DPIO PLL DW3 CH1: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW3(1))); - seq_printf(m, "DPIO_REFSFR_A: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_REFSFR_A)); - seq_printf(m, "DPIO_REFSFR_B: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_REFSFR_B)); + seq_printf(m, "DPIO PLL DW5 CH0: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW5(0))); + seq_printf(m, "DPIO PLL DW5 CH1: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW5(1))); - seq_printf(m, "DPIO_CORE_CLK_A: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_CORE_CLK_A)); - seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_CORE_CLK_B)); + seq_printf(m, "DPIO PLL DW7 CH0: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW7(0))); + seq_printf(m, "DPIO PLL DW7 CH1: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW7(1))); - seq_printf(m, "DPIO_LPF_COEFF_A: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_LPF_COEFF_A)); - seq_printf(m, "DPIO_LPF_COEFF_B: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_LPF_COEFF_B)); + seq_printf(m, "DPIO PLL DW10 CH0: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW10(0))); + seq_printf(m, "DPIO PLL DW10 CH1: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW10(1))); seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, DPIO_FASTCLK_DISABLE)); + vlv_dpio_read(dev_priv, PIPE_A, VLV_CMN_DW0)); mutex_unlock(&dev_priv->dpio_lock); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 86a1ad86aa7b..29265638bf56 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -452,15 +452,10 @@ #define DPIO_SFR_BYPASS (1<<1) #define DPIO_CMNRST (1<<0) -#define _DPIO_TX3_SWING_CTL4_A 0x690 -#define _DPIO_TX3_SWING_CTL4_B 0x2a90 -#define DPIO_TX3_SWING_CTL4(pipe) _PIPE(pipe, _DPIO_TX3_SWING_CTL4_A, \ - _DPIO_TX3_SWING_CTL4_B) - /* * Per pipe/PLL DPIO regs */ -#define _DPIO_DIV_A 0x800c +#define _VLV_PLL_DW3_CH0 0x800c #define DPIO_POST_DIV_SHIFT (28) /* 3 bits */ #define DPIO_POST_DIV_DAC 0 #define DPIO_POST_DIV_HDMIDP 1 /* DAC 225-400M rate */ @@ -473,10 +468,10 @@ #define DPIO_ENABLE_CALIBRATION (1<<11) #define DPIO_M1DIV_SHIFT (8) /* 3 bits */ #define DPIO_M2DIV_MASK 0xff -#define _DPIO_DIV_B 0x802c -#define DPIO_DIV(pipe) _PIPE(pipe, _DPIO_DIV_A, _DPIO_DIV_B) +#define _VLV_PLL_DW3_CH1 0x802c +#define VLV_PLL_DW3(ch) _PIPE(ch, _VLV_PLL_DW3_CH0, _VLV_PLL_DW3_CH1) -#define _DPIO_REFSFR_A 0x8014 +#define _VLV_PLL_DW5_CH0 0x8014 #define DPIO_REFSEL_OVERRIDE 27 #define DPIO_PLL_MODESEL_SHIFT 24 /* 3 bits */ #define DPIO_BIAS_CURRENT_CTL_SHIFT 21 /* 3 bits, always 0x7 */ @@ -484,118 +479,112 @@ #define DPIO_PLL_REFCLK_SEL_MASK 3 #define DPIO_DRIVER_CTL_SHIFT 12 /* always set to 0x8 */ #define DPIO_CLK_BIAS_CTL_SHIFT 8 /* always set to 0x5 */ -#define _DPIO_REFSFR_B 0x8034 -#define DPIO_REFSFR(pipe) _PIPE(pipe, _DPIO_REFSFR_A, _DPIO_REFSFR_B) +#define _VLV_PLL_DW5_CH1 0x8034 +#define VLV_PLL_DW5(ch) _PIPE(ch, _VLV_PLL_DW5_CH0, _VLV_PLL_DW5_CH1) -#define _DPIO_CORE_CLK_A 0x801c -#define _DPIO_CORE_CLK_B 0x803c -#define DPIO_CORE_CLK(pipe) _PIPE(pipe, _DPIO_CORE_CLK_A, _DPIO_CORE_CLK_B) +#define _VLV_PLL_DW7_CH0 0x801c +#define _VLV_PLL_DW7_CH1 0x803c +#define VLV_PLL_DW7(ch) _PIPE(ch, _VLV_PLL_DW7_CH0, _VLV_PLL_DW7_CH1) -#define _DPIO_IREF_CTL_A 0x8040 -#define _DPIO_IREF_CTL_B 0x8060 -#define DPIO_IREF_CTL(pipe) _PIPE(pipe, _DPIO_IREF_CTL_A, _DPIO_IREF_CTL_B) +#define _VLV_PLL_DW8_CH0 0x8040 +#define _VLV_PLL_DW8_CH1 0x8060 +#define VLV_PLL_DW8(ch) _PIPE(ch, _VLV_PLL_DW8_CH0, _VLV_PLL_DW8_CH1) -#define DPIO_IREF_BCAST 0xc044 -#define _DPIO_IREF_A 0x8044 -#define _DPIO_IREF_B 0x8064 -#define DPIO_IREF(pipe) _PIPE(pipe, _DPIO_IREF_A, _DPIO_IREF_B) +#define VLV_PLL_DW9_BCAST 0xc044 +#define _VLV_PLL_DW9_CH0 0x8044 +#define _VLV_PLL_DW9_CH1 0x8064 +#define VLV_PLL_DW9(ch) _PIPE(ch, _VLV_PLL_DW9_CH0, _VLV_PLL_DW9_CH1) -#define _DPIO_PLL_CML_A 0x804c -#define _DPIO_PLL_CML_B 0x806c -#define DPIO_PLL_CML(pipe) _PIPE(pipe, _DPIO_PLL_CML_A, _DPIO_PLL_CML_B) +#define _VLV_PLL_DW10_CH0 0x8048 +#define _VLV_PLL_DW10_CH1 0x8068 +#define VLV_PLL_DW10(ch) _PIPE(ch, _VLV_PLL_DW10_CH0, _VLV_PLL_DW10_CH1) -#define _DPIO_LPF_COEFF_A 0x8048 -#define _DPIO_LPF_COEFF_B 0x8068 -#define DPIO_LPF_COEFF(pipe) _PIPE(pipe, _DPIO_LPF_COEFF_A, _DPIO_LPF_COEFF_B) +#define _VLV_PLL_DW11_CH0 0x804c +#define _VLV_PLL_DW11_CH1 0x806c +#define VLV_PLL_DW11(ch) _PIPE(ch, _VLV_PLL_DW11_CH0, _VLV_PLL_DW11_CH1) -#define DPIO_CALIBRATION 0x80ac +/* Spec for ref block start counts at DW10 */ +#define VLV_REF_DW13 0x80ac -#define DPIO_FASTCLK_DISABLE 0x8100 +#define VLV_CMN_DW0 0x8100 /* * Per DDI channel DPIO regs */ -#define _DPIO_PCS_TX_0 0x8200 -#define _DPIO_PCS_TX_1 0x8400 +#define _VLV_PCS_DW0_CH0 0x8200 +#define _VLV_PCS_DW0_CH1 0x8400 #define DPIO_PCS_TX_LANE2_RESET (1<<16) #define DPIO_PCS_TX_LANE1_RESET (1<<7) -#define DPIO_PCS_TX(port) _PORT(port, _DPIO_PCS_TX_0, _DPIO_PCS_TX_1) +#define VLV_PCS_DW0(ch) _PORT(ch, _VLV_PCS_DW0_CH0, _VLV_PCS_DW0_CH1) -#define _DPIO_PCS_CLK_0 0x8204 -#define _DPIO_PCS_CLK_1 0x8404 +#define _VLV_PCS_DW1_CH0 0x8204 +#define _VLV_PCS_DW1_CH1 0x8404 #define DPIO_PCS_CLK_CRI_RXEB_EIOS_EN (1<<22) #define DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN (1<<21) #define DPIO_PCS_CLK_DATAWIDTH_SHIFT (6) #define DPIO_PCS_CLK_SOFT_RESET (1<<5) -#define DPIO_PCS_CLK(port) _PORT(port, _DPIO_PCS_CLK_0, _DPIO_PCS_CLK_1) +#define VLV_PCS_DW1(ch) _PORT(ch, _VLV_PCS_DW1_CH0, _VLV_PCS_DW1_CH1) -#define _DPIO_PCS_CTL_OVR1_A 0x8224 -#define _DPIO_PCS_CTL_OVR1_B 0x8424 -#define DPIO_PCS_CTL_OVER1(port) _PORT(port, _DPIO_PCS_CTL_OVR1_A, \ - _DPIO_PCS_CTL_OVR1_B) +#define _VLV_PCS_DW8_CH0 0x8220 +#define _VLV_PCS_DW8_CH1 0x8420 +#define VLV_PCS_DW8(ch) _PORT(ch, _VLV_PCS_DW8_CH0, _VLV_PCS_DW8_CH1) -#define _DPIO_PCS_STAGGER0_A 0x822c -#define _DPIO_PCS_STAGGER0_B 0x842c -#define DPIO_PCS_STAGGER0(port) _PORT(port, _DPIO_PCS_STAGGER0_A, \ - _DPIO_PCS_STAGGER0_B) +#define _VLV_PCS01_DW8_CH0 0x0220 +#define _VLV_PCS23_DW8_CH0 0x0420 +#define _VLV_PCS01_DW8_CH1 0x2620 +#define _VLV_PCS23_DW8_CH1 0x2820 +#define VLV_PCS01_DW8(port) _PORT(port, _VLV_PCS01_DW8_CH0, _VLV_PCS01_DW8_CH1) +#define VLV_PCS23_DW8(port) _PORT(port, _VLV_PCS23_DW8_CH0, _VLV_PCS23_DW8_CH1) -#define _DPIO_PCS_STAGGER1_A 0x8230 -#define _DPIO_PCS_STAGGER1_B 0x8430 -#define DPIO_PCS_STAGGER1(port) _PORT(port, _DPIO_PCS_STAGGER1_A, \ - _DPIO_PCS_STAGGER1_B) +#define _VLV_PCS_DW9_CH0 0x8224 +#define _VLV_PCS_DW9_CH1 0x8424 +#define VLV_PCS_DW9(ch) _PORT(ch, _VLV_PCS_DW9_CH0, _VLV_PCS_DW9_CH1) -#define _DPIO_PCS_CLOCKBUF0_A 0x8238 -#define _DPIO_PCS_CLOCKBUF0_B 0x8438 -#define DPIO_PCS_CLOCKBUF0(port) _PORT(port, _DPIO_PCS_CLOCKBUF0_A, \ - _DPIO_PCS_CLOCKBUF0_B) +#define _VLV_PCS_DW11_CH0 0x822c +#define _VLV_PCS_DW11_CH1 0x842c +#define VLV_PCS_DW11(ch) _PORT(ch, _VLV_PCS_DW11_CH0, _VLV_PCS_DW11_CH1) -#define _DPIO_PCS_CLOCKBUF8_A 0x825c -#define _DPIO_PCS_CLOCKBUF8_B 0x845c -#define DPIO_PCS_CLOCKBUF8(port) _PORT(port, _DPIO_PCS_CLOCKBUF8_A, \ - _DPIO_PCS_CLOCKBUF8_B) +#define _VLV_PCS_DW12_CH0 0x8230 +#define _VLV_PCS_DW12_CH1 0x8430 +#define VLV_PCS_DW12(ch) _PORT(ch, _VLV_PCS_DW12_CH0, _VLV_PCS_DW12_CH1) -#define _DPIO_TX_SWING_CTL2_A 0x8288 -#define _DPIO_TX_SWING_CTL2_B 0x8488 -#define DPIO_TX_SWING_CTL2(port) _PORT(port, _DPIO_TX_SWING_CTL2_A, \ - _DPIO_TX_SWING_CTL2_B) +#define _VLV_PCS_DW14_CH0 0x8238 +#define _VLV_PCS_DW14_CH1 0x8438 +#define VLV_PCS_DW14(ch) _PORT(ch, _VLV_PCS_DW14_CH0, _VLV_PCS_DW14_CH1) -#define _DPIO_TX_SWING_CTL3_A 0x828c -#define _DPIO_TX_SWING_CTL3_B 0x848c -#define DPIO_TX_SWING_CTL3(port) _PORT(port, _DPIO_TX_SWING_CTL3_A, \ - _DPIO_TX_SWING_CTL3_B) +#define _VLV_PCS_DW23_CH0 0x825c +#define _VLV_PCS_DW23_CH1 0x845c +#define VLV_PCS_DW23(ch) _PORT(ch, _VLV_PCS_DW23_CH0, _VLV_PCS_DW23_CH1) -#define _DPIO_TX_SWING_CTL4_A 0x8290 -#define _DPIO_TX_SWING_CTL4_B 0x8490 -#define DPIO_TX_SWING_CTL4(port) _PORT(port, _DPIO_TX_SWING_CTL4_A, \ - _DPIO_TX_SWING_CTL4_B) +#define _VLV_TX_DW2_CH0 0x8288 +#define _VLV_TX_DW2_CH1 0x8488 +#define VLV_TX_DW2(ch) _PORT(ch, _VLV_TX_DW2_CH0, _VLV_TX_DW2_CH1) -#define _DPIO_TX_OCALINIT_0 0x8294 -#define _DPIO_TX_OCALINIT_1 0x8494 +#define _VLV_TX_DW3_CH0 0x828c +#define _VLV_TX_DW3_CH1 0x848c +#define VLV_TX_DW3(ch) _PORT(ch, _VLV_TX_DW3_CH0, _VLV_TX_DW3_CH1) + +#define _VLV_TX_DW4_CH0 0x8290 +#define _VLV_TX_DW4_CH1 0x8490 +#define VLV_TX_DW4(ch) _PORT(ch, _VLV_TX_DW4_CH0, _VLV_TX_DW4_CH1) + +#define _VLV_TX3_DW4_CH0 0x690 +#define _VLV_TX3_DW4_CH1 0x2a90 +#define VLV_TX3_DW4(ch) _PORT(ch, _VLV_TX3_DW4_CH0, _VLV_TX3_DW4_CH1) + +#define _VLV_TX_DW5_CH0 0x8294 +#define _VLV_TX_DW5_CH1 0x8494 #define DPIO_TX_OCALINIT_EN (1<<31) -#define DPIO_TX_OCALINIT(port) _PORT(port, _DPIO_TX_OCALINIT_0, \ - _DPIO_TX_OCALINIT_1) +#define VLV_TX_DW5(ch) _PORT(ch, _VLV_TX_DW5_CH0, _VLV_TX_DW5_CH1) -#define _DPIO_TX_CTL_0 0x82ac -#define _DPIO_TX_CTL_1 0x84ac -#define DPIO_TX_CTL(port) _PORT(port, _DPIO_TX_CTL_0, _DPIO_TX_CTL_1) +#define _VLV_TX_DW11_CH0 0x82ac +#define _VLV_TX_DW11_CH1 0x84ac +#define VLV_TX_DW11(ch) _PORT(ch, _VLV_TX_DW11_CH0, _VLV_TX_DW11_CH1) -#define _DPIO_TX_LANE_0 0x82b8 -#define _DPIO_TX_LANE_1 0x84b8 -#define DPIO_TX_LANE(port) _PORT(port, _DPIO_TX_LANE_0, _DPIO_TX_LANE_1) - -#define _DPIO_DATA_CHANNEL1 0x8220 -#define _DPIO_DATA_CHANNEL2 0x8420 -#define DPIO_DATA_CHANNEL(port) _PORT(port, _DPIO_DATA_CHANNEL1, _DPIO_DATA_CHANNEL2) - -#define _DPIO_PORT0_PCS0 0x0220 -#define _DPIO_PORT0_PCS1 0x0420 -#define _DPIO_PORT1_PCS2 0x2620 -#define _DPIO_PORT1_PCS3 0x2820 -#define DPIO_DATA_LANE_A(port) _PORT(port, _DPIO_PORT0_PCS0, _DPIO_PORT1_PCS2) -#define DPIO_DATA_LANE_B(port) _PORT(port, _DPIO_PORT0_PCS1, _DPIO_PORT1_PCS3) -#define DPIO_DATA_CHANNEL1 0x8220 -#define DPIO_DATA_CHANNEL2 0x8420 +#define _VLV_TX_DW14_CH0 0x82b8 +#define _VLV_TX_DW14_CH1 0x84b8 +#define VLV_TX_DW14(ch) _PORT(ch, _VLV_TX_DW14_CH0, _VLV_TX_DW14_CH1) /* * Fence registers diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0980bd95e372..abf509ce5e26 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4786,24 +4786,24 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe * PLLB opamp always calibrates to max value of 0x3f, force enable it * and set it to a reasonable value instead. */ - reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF(1)); + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); reg_val &= 0xffffff00; reg_val |= 0x00000030; - vlv_dpio_write(dev_priv, pipe, DPIO_IREF(1), reg_val); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_CALIBRATION); + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); reg_val &= 0x8cffffff; reg_val = 0x8c000000; - vlv_dpio_write(dev_priv, pipe, DPIO_CALIBRATION, reg_val); + vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF(1)); + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); reg_val &= 0xffffff00; - vlv_dpio_write(dev_priv, pipe, DPIO_IREF(1), reg_val); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_CALIBRATION); + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); reg_val &= 0x00ffffff; reg_val |= 0xb0000000; - vlv_dpio_write(dev_priv, pipe, DPIO_CALIBRATION, reg_val); + vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); } static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, @@ -4872,15 +4872,15 @@ static void vlv_update_pll(struct intel_crtc *crtc) vlv_pllb_recal_opamp(dev_priv, pipe); /* Set up Tx target for periodic Rcomp update */ - vlv_dpio_write(dev_priv, pipe, DPIO_IREF_BCAST, 0x0100000f); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f); /* Disable target IRef on PLL */ - reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF_CTL(pipe)); + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe)); reg_val &= 0x00ffffff; - vlv_dpio_write(dev_priv, pipe, DPIO_IREF_CTL(pipe), reg_val); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val); /* Disable fast lock */ - vlv_dpio_write(dev_priv, pipe, DPIO_FASTCLK_DISABLE, 0x610); + vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610); /* Set idtafcrecal before PLL is enabled */ mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); @@ -4894,48 +4894,48 @@ static void vlv_update_pll(struct intel_crtc *crtc) * Note: don't use the DAC post divider as it seems unstable. */ mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); - vlv_dpio_write(dev_priv, pipe, DPIO_DIV(pipe), mdiv); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); mdiv |= DPIO_ENABLE_CALIBRATION; - vlv_dpio_write(dev_priv, pipe, DPIO_DIV(pipe), mdiv); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); /* Set HBR and RBR LPF coefficients */ if (crtc->config.port_clock == 162000 || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) - vlv_dpio_write(dev_priv, pipe, DPIO_LPF_COEFF(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), 0x009f0003); else - vlv_dpio_write(dev_priv, pipe, DPIO_LPF_COEFF(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), 0x00d0000f); if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) { /* Use SSC source */ if (!pipe) - vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), 0x0df40000); else - vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), 0x0df70000); } else { /* HDMI or VGA */ /* Use bend source */ if (!pipe) - vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), 0x0df70000); else - vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), 0x0df40000); } - coreclk = vlv_dpio_read(dev_priv, pipe, DPIO_CORE_CLK(pipe)); + coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe)); coreclk = (coreclk & 0x0000ff00) | 0x01c00000; if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) coreclk |= 0x01000000; - vlv_dpio_write(dev_priv, pipe, DPIO_CORE_CLK(pipe), coreclk); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk); - vlv_dpio_write(dev_priv, pipe, DPIO_PLL_CML(pipe), 0x87871000); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000); /* Enable DPIO clock input */ dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV | @@ -5413,7 +5413,7 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc, int refclk = 100000; mutex_lock(&dev_priv->dpio_lock); - mdiv = vlv_dpio_read(dev_priv, pipe, DPIO_DIV(pipe)); + mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe)); mutex_unlock(&dev_priv->dpio_lock); clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7619eae35b25..2584eb4bbf0b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1846,16 +1846,16 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder) mutex_lock(&dev_priv->dpio_lock); - val = vlv_dpio_read(dev_priv, pipe, DPIO_DATA_LANE_A(port)); + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); val = 0; if (pipe) val |= (1<<21); else val &= ~(1<<21); val |= 0x001000c4; - vlv_dpio_write(dev_priv, pipe, DPIO_DATA_CHANNEL(port), val); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF0(port), 0x00760018); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF8(port), 0x00400888); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); mutex_unlock(&dev_priv->dpio_lock); @@ -1881,19 +1881,19 @@ static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder) /* Program Tx lane resets to default */ mutex_lock(&dev_priv->dpio_lock); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_TX(port), + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLK(port), + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | (1<dpio_lock); } @@ -2110,14 +2110,14 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) } mutex_lock(&dev_priv->dpio_lock); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), 0x00000000); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL4(port), demph_reg_value); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL2(port), + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0x00000000); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), demph_reg_value); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), uniqtranscale_reg_value); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL3(port), 0x0C782040); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_STAGGER0(port), 0x00030000); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CTL_OVER1(port), preemph_reg_value); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), 0x80000000); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0C782040); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), preemph_reg_value); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0x80000000); mutex_unlock(&dev_priv->dpio_lock); return 0; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 51a8336dec2e..5b9143fc9b5a 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1090,36 +1090,28 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) /* Enable clock channels for this port */ mutex_lock(&dev_priv->dpio_lock); - val = vlv_dpio_read(dev_priv, pipe, DPIO_DATA_LANE_A(port)); + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); val = 0; if (pipe) val |= (1<<21); else val &= ~(1<<21); val |= 0x001000c4; - vlv_dpio_write(dev_priv, pipe, DPIO_DATA_CHANNEL(port), val); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val); /* HDMI 1.0V-2dB */ - vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), 0); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL4(port), - 0x2b245f5f); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL2(port), - 0x5578b83a); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL3(port), - 0x0c782040); - vlv_dpio_write(dev_priv, pipe, DPIO_TX3_SWING_CTL4(port), - 0x2b247878); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_STAGGER0(port), 0x00030000); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CTL_OVER1(port), - 0x00002000); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), - DPIO_TX_OCALINIT_EN); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), 0x2b245f5f); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), 0x5578b83a); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0c782040); + vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), 0x2b247878); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); /* Program lane clock */ - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF0(port), - 0x00760018); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF8(port), - 0x00400888); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); mutex_unlock(&dev_priv->dpio_lock); intel_enable_hdmi(encoder); @@ -1142,24 +1134,22 @@ static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) /* Program Tx lane resets to default */ mutex_lock(&dev_priv->dpio_lock); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_TX(port), + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLK(port), + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | (1<dpio_lock); } @@ -1174,8 +1164,8 @@ static void vlv_hdmi_post_disable(struct intel_encoder *encoder) /* Reset lanes to avoid HDMI flicker (VLV w/a) */ mutex_lock(&dev_priv->dpio_lock); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_TX(port), 0x00000000); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLK(port), 0x00e00060); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060); mutex_unlock(&dev_priv->dpio_lock); } From 00fe639a56b40930bf27eabeef9a826344d8f4c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 Nov 2013 14:00:08 +0200 Subject: [PATCH 019/595] drm/i915: Make AGP support optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only depend on the intel-gtt module for GTT frobbign on older gens. The intel_agp module is optional, except for UMS and some old XvMC userland on gen3. So make AGP support optional. As before, we will fail the i915 init for UMS and gen3 KMS the same as before if intel_agp isn't around. intel-gtt.c is left with a somewhat ugly ifdef mess, but I'm going to save that for a later cleaning. At least my gen2 still works with the patch and CONFIG_AGP=n. v2: Make i915 depend on X86 and PCI, and intel-gtt depend on PCI Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/char/Makefile | 2 +- drivers/char/agp/Kconfig | 5 +++++ drivers/char/agp/Makefile | 2 +- drivers/char/agp/intel-gtt.c | 18 ++++++++++++++++++ drivers/gpu/drm/i915/Kconfig | 6 ++++-- drivers/gpu/drm/i915/i915_drv.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 7ff1d0d208a7..2d68054f9795 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -50,7 +50,7 @@ obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_MWAVE) += mwave/ -obj-$(CONFIG_AGP) += agp/ +obj-y += agp/ obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index d8b1b576556c..c528f96ee204 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -68,6 +68,7 @@ config AGP_AMD64 config AGP_INTEL tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support" depends on AGP && X86 + select INTEL_GTT help This option gives you AGP support for the GLX component of X on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875, @@ -155,3 +156,7 @@ config AGP_SGI_TIOCA This option gives you AGP GART support for the SGI TIO chipset for IA64 processors. +config INTEL_GTT + tristate + depends on X86 && PCI + diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 8eb56e273e75..604489bcdbf9 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o obj-$(CONFIG_AGP_PARISC) += parisc-agp.o obj-$(CONFIG_AGP_I460) += i460-agp.o obj-$(CONFIG_AGP_INTEL) += intel-agp.o -obj-$(CONFIG_AGP_INTEL) += intel-gtt.o +obj-$(CONFIG_INTEL_GTT) += intel-gtt.o obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o obj-$(CONFIG_AGP_SGI_TIOCA) += sgi-agp.o obj-$(CONFIG_AGP_SIS) += sis-agp.o diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index b8e2014cb9cb..078968d8d07d 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -94,6 +94,7 @@ static struct _intel_private { #define IS_IRONLAKE intel_private.driver->is_ironlake #define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_gtt_map_memory(struct page **pages, unsigned int num_entries, struct sg_table *st) @@ -168,6 +169,7 @@ static void i8xx_destroy_pages(struct page *page) __free_pages(page, 2); atomic_dec(&agp_bridge->current_memory_agp); } +#endif #define I810_GTT_ORDER 4 static int i810_setup(void) @@ -209,6 +211,7 @@ static void i810_cleanup(void) free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER); } +#if IS_ENABLED(CONFIG_AGP_INTEL) static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -289,6 +292,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr) } kfree(curr); } +#endif static int intel_gtt_setup_scratch_page(void) { @@ -647,7 +651,9 @@ static int intel_gtt_init(void) return -ENOMEM; } +#if IS_ENABLED(CONFIG_AGP_INTEL) global_cache_flush(); /* FIXME: ? */ +#endif intel_private.stolen_size = intel_gtt_stolen_size(); @@ -671,6 +677,7 @@ static int intel_gtt_init(void) return 0; } +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_fake_agp_fetch_size(void) { int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); @@ -689,6 +696,7 @@ static int intel_fake_agp_fetch_size(void) return 0; } +#endif static void i830_cleanup(void) { @@ -801,6 +809,7 @@ static int i830_setup(void) return 0; } +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) { agp_bridge->gatt_table_real = NULL; @@ -825,6 +834,7 @@ static int intel_fake_agp_configure(void) return 0; } +#endif static bool i830_check_flags(unsigned int flags) { @@ -863,6 +873,7 @@ void intel_gtt_insert_sg_entries(struct sg_table *st, } EXPORT_SYMBOL(intel_gtt_insert_sg_entries); +#if IS_ENABLED(CONFIG_AGP_INTEL) static void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries, struct page **pages, @@ -928,6 +939,7 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, mem->is_flushed = true; return ret; } +#endif void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) { @@ -941,6 +953,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) } EXPORT_SYMBOL(intel_gtt_clear_range); +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_fake_agp_remove_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -982,6 +995,7 @@ static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, /* always return NULL for other allocation types for now */ return NULL; } +#endif static int intel_alloc_chipset_flush_resource(void) { @@ -1138,6 +1152,7 @@ static int i9xx_setup(void) return 0; } +#if IS_ENABLED(CONFIG_AGP_INTEL) static const struct agp_bridge_driver intel_fake_agp_driver = { .owner = THIS_MODULE, .size_type = FIXED_APER_SIZE, @@ -1159,6 +1174,7 @@ static const struct agp_bridge_driver intel_fake_agp_driver = { .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, }; +#endif static const struct intel_gtt_driver i81x_gtt_driver = { .gen = 1, @@ -1376,11 +1392,13 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, intel_private.refcount++; +#if IS_ENABLED(CONFIG_AGP_INTEL) if (bridge) { bridge->driver = &intel_fake_agp_driver; bridge->dev_private_data = &intel_private; bridge->dev = bridge_pdev; } +#endif intel_private.bridge_dev = pci_dev_get(bridge_pdev); diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 6199d0b5b958..b0f61679c598 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -1,8 +1,10 @@ config DRM_I915 tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics" depends on DRM - depends on AGP - depends on AGP_INTEL + depends on X86 && PCI + depends on (AGP || AGP=n) + select INTEL_GTT + select AGP_INTEL if AGP # we need shmfs for the swappable backing store, and in particular # the shmem_readpage() which depends upon tmpfs select SHMEM diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 65447572b129..38a344694e35 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -155,7 +155,11 @@ MODULE_PARM_DESC(prefault_disable, "Disable page prefaulting for pread/pwrite/reloc (default:false). For developers only."); static struct drm_driver driver; +#if IS_ENABLED(CONFIG_AGP_INTEL) extern int intel_agp_enabled; +#else +static int intel_agp_enabled; +#endif static const struct intel_device_info intel_i830_info = { .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2, From e4607fcfb1cd5d869425e190a85f841fc910c4ca Mon Sep 17 00:00:00 2001 From: Chon Ming Lee Date: Wed, 6 Nov 2013 14:36:35 +0800 Subject: [PATCH 020/595] drm/i915/vlv: Make the vlv_dpio_read/vlv_dpio_write more PHY centric MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vlv_dpio_read/write should be describe more in PHY centric instead of display controller centric. Create a enum dpio_channel for channel index and enum dpio_phy for PHY index. This should better to gather for upcoming platform. v2: Rebase the code based on drm/i915/vlv: Fix typo in the DPIO register define. v3: Rename vlv_phy to dpio_phy_iosf_port and define additional macro DPIO_PHY, and remove unrelated change. (Ville) Suggested-by: Ville Syrjälä Signed-off-by: Chon Ming Lee Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 13 +++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_display.c | 16 ++++++++++++---- drivers/gpu/drm/i915/intel_dp.c | 8 ++++---- drivers/gpu/drm/i915/intel_drv.h | 7 ++++--- drivers/gpu/drm/i915/intel_hdmi.c | 8 ++++---- drivers/gpu/drm/i915/intel_sideband.c | 13 ++----------- 7 files changed, 42 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index efca30dc6c57..c546316ac649 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -88,6 +88,18 @@ enum port { }; #define port_name(p) ((p) + 'A') +#define I915_NUM_PHYS_VLV 1 + +enum dpio_channel { + DPIO_CH0, + DPIO_CH1 +}; + +enum dpio_phy { + DPIO_PHY0, + DPIO_PHY1 +}; + enum intel_display_power_domain { POWER_DOMAIN_PIPE_A, POWER_DOMAIN_PIPE_B, @@ -1403,6 +1415,7 @@ typedef struct drm_i915_private { int num_shared_dpll; struct intel_shared_dpll shared_dplls[I915_NUM_PLLS]; struct intel_ddi_plls ddi_plls; + int dpio_phy_iosf_port[I915_NUM_PHYS_VLV]; /* Reclocking support */ bool render_reclock_avail; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 29265638bf56..a8a5bcb521c7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -452,6 +452,9 @@ #define DPIO_SFR_BYPASS (1<<1) #define DPIO_CMNRST (1<<0) +#define DPIO_PHY(pipe) ((pipe) >> 1) +#define DPIO_PHY_IOSF_PORT(phy) (dev_priv->dpio_phy_iosf_port[phy]) + /* * Per pipe/PLL DPIO regs */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index abf509ce5e26..752d83019f36 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1361,6 +1361,7 @@ static void intel_init_dpio(struct drm_device *dev) if (!IS_VALLEYVIEW(dev)) return; + DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO; /* * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx - * 6. De-assert cmn_reset/side_reset. Same as VLV X0. @@ -1494,18 +1495,25 @@ static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) POSTING_READ(DPLL(pipe)); } -void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port) +void vlv_wait_port_ready(struct drm_i915_private *dev_priv, + struct intel_digital_port *dport) { u32 port_mask; - if (!port) + switch (dport->port) { + case PORT_B: port_mask = DPLL_PORTB_READY_MASK; - else + break; + case PORT_C: port_mask = DPLL_PORTC_READY_MASK; + break; + default: + BUG(); + } if (wait_for((I915_READ(DPLL(0)) & port_mask) == 0, 1000)) WARN(1, "timed out waiting for port %c ready: 0x%08x\n", - 'B' + port, I915_READ(DPLL(0))); + 'B' + dport->port, I915_READ(DPLL(0))); } /** diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 2584eb4bbf0b..34d605762a60 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1839,7 +1839,7 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder) struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; struct edp_power_seq power_seq; u32 val; @@ -1866,7 +1866,7 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder) intel_enable_dp(encoder); - vlv_wait_port_ready(dev_priv, port); + vlv_wait_port_ready(dev_priv, dport); } static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder) @@ -1876,7 +1876,7 @@ static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; /* Program Tx lane resets to default */ @@ -2033,7 +2033,7 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) unsigned long demph_reg_value, preemph_reg_value, uniqtranscale_reg_value; uint8_t train_set = intel_dp->train_set[0]; - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6d701e79b611..9134a5464dd5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -490,9 +490,9 @@ vlv_dport_to_channel(struct intel_digital_port *dport) { switch (dport->port) { case PORT_B: - return 0; + return DPIO_CH0; case PORT_C: - return 1; + return DPIO_CH1; default: BUG(); } @@ -637,7 +637,8 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, void intel_wait_for_vblank(struct drm_device *dev, int pipe); void intel_wait_for_pipe_off(struct drm_device *dev, int pipe); int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp); -void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port); +void vlv_wait_port_ready(struct drm_i915_private *dev_priv, + struct intel_digital_port *dport); bool intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_display_mode *mode, struct intel_load_detect_pipe *old); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 5b9143fc9b5a..61cff670ff3f 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1081,7 +1081,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; u32 val; @@ -1116,7 +1116,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) intel_enable_hdmi(encoder); - vlv_wait_port_ready(dev_priv, port); + vlv_wait_port_ready(dev_priv, dport); } static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) @@ -1126,7 +1126,7 @@ static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; if (!IS_VALLEYVIEW(dev)) @@ -1159,7 +1159,7 @@ static void vlv_hdmi_post_disable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; /* Reset lanes to avoid HDMI flicker (VLV w/a) */ diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index d43e457b6961..cc6fbcde7d3d 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -176,27 +176,18 @@ void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) PUNIT_OPCODE_REG_WRITE, reg, &val); } -static u32 vlv_get_phy_port(enum pipe pipe) -{ - u32 port = IOSF_PORT_DPIO; - - WARN_ON ((pipe != PIPE_A) && (pipe != PIPE_B)); - - return port; -} - u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = 0; - vlv_sideband_rw(dev_priv, DPIO_DEVFN, vlv_get_phy_port(pipe), + vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)), DPIO_OPCODE_REG_READ, reg, &val); return val; } void vlv_dpio_write(struct drm_i915_private *dev_priv, enum pipe pipe, int reg, u32 val) { - vlv_sideband_rw(dev_priv, DPIO_DEVFN, vlv_get_phy_port(pipe), + vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)), DPIO_OPCODE_REG_WRITE, reg, &val); } From f2d91a2c556479713abbefec237cad4bc1d54b0d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 7 Nov 2013 09:48:57 +0100 Subject: [PATCH 021/595] drm/i915: tune reset dmesg output a bit We don't want any ERROR for simulated gpu hangs, otoh printing the error code when the reset failed for real should be interesting. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=71333 lu hua Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 38a344694e35..c3e9485f38fe 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -731,14 +731,14 @@ int i915_reset(struct drm_device *dev) DRM_INFO("Simulated gpu hang, resetting stop_rings\n"); dev_priv->gpu_error.stop_rings = 0; if (ret == -ENODEV) { - DRM_ERROR("Reset not implemented, but ignoring " - "error for simulated gpu hangs\n"); + DRM_INFO("Reset not implemented, but ignoring " + "error for simulated gpu hangs\n"); ret = 0; } } if (ret) { - DRM_ERROR("Failed to reset chip.\n"); + DRM_ERROR("Failed to reset chip: %i\n", ret); mutex_unlock(&dev->struct_mutex); return ret; } From 2ac0f45099d2d3b8918d63e1bac698b5cb272aa1 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 12 Nov 2013 14:44:19 +0200 Subject: [PATCH 022/595] drm/i915: add i915_reset_count reset_counter will be incremented twice per successful reset. Odd values mean reset is in progress and even values mean that reset has completed. Reset status ioctl introduced in following commit needs to deliver global reset count to userspace so use reset_counter to derive the actual reset count for the gpu Note that reset in progress is enough to increment the counter. v2: wedged equals reset in progress (Daniel Vetter) v3: Fixed stale comments (Damien Lespiau) Signed-off-by: Mika Kuoppala Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 43 +++++++++++++++++---------------- drivers/gpu/drm/i915/i915_irq.c | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c546316ac649..4c0f751d1c88 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1069,34 +1069,30 @@ struct i915_gpu_error { unsigned long missed_irq_rings; /** - * State variable and reset counter controlling the reset flow + * State variable controlling the reset flow and count * - * Upper bits are for the reset counter. This counter is used by the - * wait_seqno code to race-free noticed that a reset event happened and - * that it needs to restart the entire ioctl (since most likely the - * seqno it waited for won't ever signal anytime soon). + * This is a counter which gets incremented when reset is triggered, + * and again when reset has been handled. So odd values (lowest bit set) + * means that reset is in progress and even values that + * (reset_counter >> 1):th reset was successfully completed. + * + * If reset is not completed succesfully, the I915_WEDGE bit is + * set meaning that hardware is terminally sour and there is no + * recovery. All waiters on the reset_queue will be woken when + * that happens. + * + * This counter is used by the wait_seqno code to notice that reset + * event happened and it needs to restart the entire ioctl (since most + * likely the seqno it waited for won't ever signal anytime soon). * * This is important for lock-free wait paths, where no contended lock * naturally enforces the correct ordering between the bail-out of the * waiter and the gpu reset work code. - * - * Lowest bit controls the reset state machine: Set means a reset is in - * progress. This state will (presuming we don't have any bugs) decay - * into either unset (successful reset) or the special WEDGED value (hw - * terminally sour). All waiters on the reset_queue will be woken when - * that happens. */ atomic_t reset_counter; - /** - * Special values/flags for reset_counter - * - * Note that the code relies on - * I915_WEDGED & I915_RESET_IN_PROGRESS_FLAG - * being true. - */ #define I915_RESET_IN_PROGRESS_FLAG 1 -#define I915_WEDGED 0xffffffff +#define I915_WEDGED (1 << 31) /** * Waitqueue to signal when the reset has completed. Used by clients @@ -2046,12 +2042,17 @@ int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, static inline bool i915_reset_in_progress(struct i915_gpu_error *error) { return unlikely(atomic_read(&error->reset_counter) - & I915_RESET_IN_PROGRESS_FLAG); + & (I915_RESET_IN_PROGRESS_FLAG | I915_WEDGED)); } static inline bool i915_terminally_wedged(struct i915_gpu_error *error) { - return atomic_read(&error->reset_counter) == I915_WEDGED; + return atomic_read(&error->reset_counter) & I915_WEDGED; +} + +static inline u32 i915_reset_count(struct i915_gpu_error *error) +{ + return ((atomic_read(&error->reset_counter) & ~I915_WEDGED) + 1) / 2; } void i915_gem_reset(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e14285bafbd4..19949e8b36c5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1781,7 +1781,7 @@ static void i915_error_work_func(struct work_struct *work) kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); } else { - atomic_set(&error->reset_counter, I915_WEDGED); + atomic_set_mask(I915_WEDGED, &error->reset_counter); } /* From b6359918b885da7c7b58c050674278dbd06020ab Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 30 Oct 2013 15:44:16 +0200 Subject: [PATCH 023/595] drm/i915: add i915_get_reset_stats_ioctl This ioctl returns reset stats for specified context. The struct returned contains context loss counters. reset_count: all resets across all contexts batch_active: active batches lost on resets batch_pending: pending batches lost on resets v2: get rid of state tracking completely and deliver only counts. Idea from Chris Wilson. v3: fix commit message v4: default context handled inside i915_gem_context_get_hang_stats v5: reset_count only for priviledged process v6: ctx=0 needs CAP_SYS_ADMIN for batch_* counters (Chris Wilson) v7: context hang stats never returns NULL v8: rebased on top of reworked context hang stats DRM_RENDER_ALLOW for ioctl v9: use DEFAULT_CONTEXT_ID. Improve comments for ioctl struct members Signed-off-by: Mika Kuoppala Cc: Ian Romanick Cc: Chris Wilson Cc: Daniel Vetter Reviewed-by: Damien Lespiau Reviewed-by: Ian Romanick Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_uncore.c | 34 +++++++++++++++++++++++++++++ include/uapi/drm/i915_drm.h | 19 ++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 0cab2d045135..00d74f816a72 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1908,6 +1908,7 @@ const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4c0f751d1c88..6d2a9a1c8379 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2382,6 +2382,8 @@ extern int intel_enable_rc6(const struct drm_device *dev); extern bool i915_semaphore_is_enabled(struct drm_device *dev); int i915_reg_read_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +int i915_get_reset_stats_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); /* overlay */ extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index f6fae35c568e..21cf9519be78 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -633,6 +633,40 @@ int i915_reg_read_ioctl(struct drm_device *dev, return 0; } +int i915_get_reset_stats_ioctl(struct drm_device *dev, + void *data, struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_reset_stats *args = data; + struct i915_ctx_hang_stats *hs; + int ret; + + if (args->ctx_id == DEFAULT_CONTEXT_ID && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + hs = i915_gem_context_get_hang_stats(dev, file, args->ctx_id); + if (IS_ERR(hs)) { + mutex_unlock(&dev->struct_mutex); + return PTR_ERR(hs); + } + + if (capable(CAP_SYS_ADMIN)) + args->reset_count = i915_reset_count(&dev_priv->gpu_error); + else + args->reset_count = 0; + + args->batch_active = hs->batch_active; + args->batch_pending = hs->batch_pending; + + mutex_unlock(&dev->struct_mutex); + + return 0; +} + static int i965_reset_complete(struct drm_device *dev) { u8 gdrst; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 3a4e97bd8607..52aed893710a 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -222,6 +222,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_GEM_SET_CACHING 0x2f #define DRM_I915_GEM_GET_CACHING 0x30 #define DRM_I915_REG_READ 0x31 +#define DRM_I915_GET_RESET_STATS 0x32 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -271,6 +272,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create) #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy) #define DRM_IOCTL_I915_REG_READ DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read) +#define DRM_IOCTL_I915_GET_RESET_STATS DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -1030,4 +1032,21 @@ struct drm_i915_reg_read { __u64 offset; __u64 val; /* Return value */ }; + +struct drm_i915_reset_stats { + __u32 ctx_id; + __u32 flags; + + /* All resets since boot/module reload, for all contexts */ + __u32 reset_count; + + /* Number of batches lost when active in GPU, for this context */ + __u32 batch_active; + + /* Number of batches lost pending for execution, for this context */ + __u32 batch_pending; + + __u32 pad; +}; + #endif /* _UAPI_I915_DRM_H_ */ From db31af1d4e815e141295b0bdf8da3e77885001d5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:48:53 +0200 Subject: [PATCH 024/595] drm/i915: clean up backlight conditional build I've always felt the backlight device conditional build has been all backwards. Make it feel right. Gently move things towards connector based stuff while at it. There should be no functional changes. Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 9 ++-- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_panel.c | 65 ++++++++++++++++------------ 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3cddd508d110..9cb36a42783e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11070,12 +11070,11 @@ void intel_modeset_cleanup(struct drm_device *dev) /* flush any delayed tasks or pending work */ flush_scheduled_work(); - /* destroy backlight, if any, before the connectors */ - intel_panel_destroy_backlight(dev); - - /* destroy the sysfs files before encoders/connectors */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + /* destroy the backlight and sysfs files before encoders/connectors */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + intel_panel_destroy_backlight(connector); drm_sysfs_connector_remove(connector); + } drm_mode_config_cleanup(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1e49aa8f5377..5548180e5558 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -808,7 +808,7 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, int intel_panel_setup_backlight(struct drm_connector *connector); void intel_panel_enable_backlight(struct intel_connector *connector); void intel_panel_disable_backlight(struct intel_connector *connector); -void intel_panel_destroy_backlight(struct drm_device *dev); +void intel_panel_destroy_backlight(struct drm_connector *connector); enum drm_connector_status intel_panel_detect(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index f161ac02c4f6..a0d13d3173ee 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -709,16 +709,6 @@ static void intel_panel_init_backlight_regs(struct drm_device *dev) } } -static void intel_panel_init_backlight(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - intel_panel_init_backlight_regs(dev); - - dev_priv->backlight.level = intel_panel_get_backlight(dev, 0); - dev_priv->backlight.enabled = dev_priv->backlight.level != 0; -} - enum drm_connector_status intel_panel_detect(struct drm_device *dev) { @@ -742,7 +732,7 @@ intel_panel_detect(struct drm_device *dev) } #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) -static int intel_panel_update_status(struct backlight_device *bd) +static int intel_backlight_device_update_status(struct backlight_device *bd) { struct intel_connector *connector = bl_get_data(bd); struct drm_device *dev = connector->base.dev; @@ -756,7 +746,7 @@ static int intel_panel_update_status(struct backlight_device *bd) return 0; } -static int intel_panel_get_brightness(struct backlight_device *bd) +static int intel_backlight_device_get_brightness(struct backlight_device *bd) { struct intel_connector *connector = bl_get_data(bd); struct drm_device *dev = connector->base.dev; @@ -771,20 +761,18 @@ static int intel_panel_get_brightness(struct backlight_device *bd) return intel_panel_get_backlight(connector->base.dev, pipe); } -static const struct backlight_ops intel_panel_bl_ops = { - .update_status = intel_panel_update_status, - .get_brightness = intel_panel_get_brightness, +static const struct backlight_ops intel_backlight_device_ops = { + .update_status = intel_backlight_device_update_status, + .get_brightness = intel_backlight_device_get_brightness, }; -int intel_panel_setup_backlight(struct drm_connector *connector) +static int intel_backlight_device_register(struct intel_connector *connector) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct backlight_properties props; unsigned long flags; - intel_panel_init_backlight(dev); - if (WARN_ON(dev_priv->backlight.device)) return -ENODEV; @@ -802,9 +790,9 @@ int intel_panel_setup_backlight(struct drm_connector *connector) } dev_priv->backlight.device = backlight_device_register("intel_backlight", - connector->kdev, - to_intel_connector(connector), - &intel_panel_bl_ops, &props); + connector->base.kdev, + connector, + &intel_backlight_device_ops, &props); if (IS_ERR(dev_priv->backlight.device)) { DRM_ERROR("Failed to register backlight: %ld\n", @@ -815,26 +803,47 @@ int intel_panel_setup_backlight(struct drm_connector *connector) return 0; } -void intel_panel_destroy_backlight(struct drm_device *dev) +static void intel_backlight_device_unregister(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->backlight.device) { backlight_device_unregister(dev_priv->backlight.device); dev_priv->backlight.device = NULL; } } -#else +#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ +static int intel_backlight_device_register(struct intel_connector *connector) +{ + return 0; +} +static void intel_backlight_device_unregister(struct intel_connector *connector) +{ +} +#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ + int intel_panel_setup_backlight(struct drm_connector *connector) { - intel_panel_init_backlight(connector->dev); + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_connector *intel_connector = to_intel_connector(connector); + + intel_panel_init_backlight_regs(dev); + + dev_priv->backlight.level = intel_panel_get_backlight(dev, 0); + dev_priv->backlight.enabled = dev_priv->backlight.level != 0; + + intel_backlight_device_register(intel_connector); + return 0; } -void intel_panel_destroy_backlight(struct drm_device *dev) +void intel_panel_destroy_backlight(struct drm_connector *connector) { - return; + struct intel_connector *intel_connector = to_intel_connector(connector); + + intel_backlight_device_unregister(intel_connector); } -#endif int intel_panel_init(struct intel_panel *panel, struct drm_display_mode *fixed_mode) From 58c68779e48fa6d60b97fadc3dcac61a6c318c4c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:48:54 +0200 Subject: [PATCH 025/595] drm/i915: make backlight info per-connector Move from dev_priv to connector->panel. We still don't allow multiple sysfs interfaces, though. There should be no functional changes, except for a slight reordering of connector backlight and sysfs destroy calls. (This change happens now that the backlight device is actually per-connector, even though the destroy calls became per-connector earlier.) Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 9 +-- drivers/gpu/drm/i915/i915_suspend.c | 8 +-- drivers/gpu/drm/i915/intel_drv.h | 7 +++ drivers/gpu/drm/i915/intel_panel.c | 85 ++++++++++++++++------------- 5 files changed, 61 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 0cab2d045135..9a2a17507df4 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1486,7 +1486,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->gpu_error.lock); - spin_lock_init(&dev_priv->backlight.lock); + spin_lock_init(&dev_priv->backlight_lock); spin_lock_init(&dev_priv->uncore.lock); spin_lock_init(&dev_priv->mm.object_stat_lock); mutex_init(&dev_priv->dpio_lock); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8600c315b4c4..a2009bff2f36 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1368,13 +1368,8 @@ typedef struct drm_i915_private { struct intel_overlay *overlay; unsigned int sprite_scaling_enabled; - /* backlight */ - struct { - int level; - bool enabled; - spinlock_t lock; /* bl registers and the above bl fields */ - struct backlight_device *device; - } backlight; + /* backlight registers and fields in struct intel_panel */ + spinlock_t backlight_lock; /* LVDS info */ bool no_aux_handshake; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 98790c7cccb1..eadf8e19d2c4 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -203,7 +203,7 @@ static void i915_save_display(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_save_display_reg(dev); - spin_lock_irqsave(&dev_priv->backlight.lock, flags); + spin_lock_irqsave(&dev_priv->backlight_lock, flags); /* LVDS state */ if (HAS_PCH_SPLIT(dev)) { @@ -241,7 +241,7 @@ static void i915_save_display(struct drm_device *dev) dev_priv->regfile.saveLVDS = I915_READ(LVDS); } - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL); @@ -287,7 +287,7 @@ static void i915_restore_display(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_restore_display_reg(dev); - spin_lock_irqsave(&dev_priv->backlight.lock, flags); + spin_lock_irqsave(&dev_priv->backlight_lock, flags); /* LVDS state */ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) @@ -341,7 +341,7 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); } - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); /* only restore FBC info on the platform that supports FBC*/ intel_disable_fbc(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5548180e5558..9460e54cf140 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -156,6 +156,13 @@ struct intel_encoder { struct intel_panel { struct drm_display_mode *fixed_mode; int fitting_mode; + + /* backlight */ + struct { + u32 level; + bool enabled; + struct backlight_device *device; + } backlight; }; struct intel_connector { diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index a0d13d3173ee..0a4aeaf96865 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -346,7 +346,7 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev, enum pipe pipe) struct drm_i915_private *dev_priv = dev->dev_private; u32 val; - WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock)); + WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight_lock)); /* Restore the CTL value if it lost, e.g. GPU reset */ @@ -449,7 +449,7 @@ static u32 intel_panel_get_backlight(struct drm_device *dev, unsigned long flags; int reg; - spin_lock_irqsave(&dev_priv->backlight.lock, flags); + spin_lock_irqsave(&dev_priv->backlight_lock, flags); if (HAS_PCH_SPLIT(dev)) { val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; @@ -473,7 +473,7 @@ static u32 intel_panel_get_backlight(struct drm_device *dev, val = intel_panel_compute_brightness(dev, pipe, val); - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); return val; @@ -530,6 +530,7 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); u32 freq; unsigned long flags; @@ -537,7 +538,7 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, if (pipe == INVALID_PIPE) return; - spin_lock_irqsave(&dev_priv->backlight.lock, flags); + spin_lock_irqsave(&dev_priv->backlight_lock, flags); freq = intel_panel_get_max_backlight(dev, pipe); if (!freq) { @@ -551,20 +552,21 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, else level = freq / max * level; - dev_priv->backlight.level = level; - if (dev_priv->backlight.device) - dev_priv->backlight.device->props.brightness = level; + panel->backlight.level = level; + if (panel->backlight.device) + panel->backlight.device->props.brightness = level; - if (dev_priv->backlight.enabled) + if (panel->backlight.enabled) intel_panel_actually_set_backlight(dev, pipe, level); out: - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); } void intel_panel_disable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); unsigned long flags; @@ -582,9 +584,9 @@ void intel_panel_disable_backlight(struct intel_connector *connector) return; } - spin_lock_irqsave(&dev_priv->backlight.lock, flags); + spin_lock_irqsave(&dev_priv->backlight_lock, flags); - dev_priv->backlight.enabled = false; + panel->backlight.enabled = false; intel_panel_actually_set_backlight(dev, pipe, 0); if (INTEL_INFO(dev)->gen >= 4) { @@ -606,13 +608,14 @@ void intel_panel_disable_backlight(struct intel_connector *connector) } } - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); } void intel_panel_enable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); @@ -623,14 +626,14 @@ void intel_panel_enable_backlight(struct intel_connector *connector) DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); - spin_lock_irqsave(&dev_priv->backlight.lock, flags); + spin_lock_irqsave(&dev_priv->backlight_lock, flags); - if (dev_priv->backlight.level == 0) { - dev_priv->backlight.level = intel_panel_get_max_backlight(dev, - pipe); - if (dev_priv->backlight.device) - dev_priv->backlight.device->props.brightness = - dev_priv->backlight.level; + if (panel->backlight.level == 0) { + panel->backlight.level = intel_panel_get_max_backlight(dev, + pipe); + if (panel->backlight.device) + panel->backlight.device->props.brightness = + panel->backlight.level; } if (INTEL_INFO(dev)->gen >= 4) { @@ -680,11 +683,11 @@ void intel_panel_enable_backlight(struct intel_connector *connector) * BLC_PWM_CPU_CTL may be cleared to zero automatically when these * registers are set. */ - dev_priv->backlight.enabled = true; + panel->backlight.enabled = true; intel_panel_actually_set_backlight(dev, pipe, - dev_priv->backlight.level); + panel->backlight.level); - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); } /* FIXME: use VBT vals to init PWM_CTL and PWM_CTL2 correctly */ @@ -770,34 +773,40 @@ static int intel_backlight_device_register(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; struct backlight_properties props; unsigned long flags; - if (WARN_ON(dev_priv->backlight.device)) + if (WARN_ON(panel->backlight.device)) return -ENODEV; memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; - props.brightness = dev_priv->backlight.level; + props.brightness = panel->backlight.level; - spin_lock_irqsave(&dev_priv->backlight.lock, flags); + spin_lock_irqsave(&dev_priv->backlight_lock, flags); props.max_brightness = intel_panel_get_max_backlight(dev, 0); - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); if (props.max_brightness == 0) { DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); return -ENODEV; } - dev_priv->backlight.device = + + /* + * Note: using the same name independent of the connector prevents + * registration of multiple backlight devices in the driver. + */ + panel->backlight.device = backlight_device_register("intel_backlight", connector->base.kdev, connector, &intel_backlight_device_ops, &props); - if (IS_ERR(dev_priv->backlight.device)) { + if (IS_ERR(panel->backlight.device)) { DRM_ERROR("Failed to register backlight: %ld\n", - PTR_ERR(dev_priv->backlight.device)); - dev_priv->backlight.device = NULL; + PTR_ERR(panel->backlight.device)); + panel->backlight.device = NULL; return -ENODEV; } return 0; @@ -805,11 +814,11 @@ static int intel_backlight_device_register(struct intel_connector *connector) static void intel_backlight_device_unregister(struct intel_connector *connector) { - struct drm_device *dev = connector->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->backlight.device) { - backlight_device_unregister(dev_priv->backlight.device); - dev_priv->backlight.device = NULL; + struct intel_panel *panel = &connector->panel; + + if (panel->backlight.device) { + backlight_device_unregister(panel->backlight.device); + panel->backlight.device = NULL; } } #else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ @@ -825,13 +834,13 @@ static void intel_backlight_device_unregister(struct intel_connector *connector) int intel_panel_setup_backlight(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_panel *panel = &intel_connector->panel; intel_panel_init_backlight_regs(dev); - dev_priv->backlight.level = intel_panel_get_backlight(dev, 0); - dev_priv->backlight.enabled = dev_priv->backlight.level != 0; + panel->backlight.level = intel_panel_get_backlight(dev, 0); + panel->backlight.enabled = panel->backlight.level != 0; intel_backlight_device_register(intel_connector); From c91c9f32843a1b433de5a1ead4789a6bc8d3d914 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:48:55 +0200 Subject: [PATCH 026/595] drm/i915: make asle notifications update backlight on all connectors ALthough usually there's only one connector that supports backlight, this also finds the correct connector. Before, we only updated the connector on pipe A, which might not be the one with backlight. (This only made a difference on BYT.) Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_opregion.c | 43 ++++++++------------------- drivers/gpu/drm/i915/intel_panel.c | 4 +++ 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9460e54cf140..bcb47b83787d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -159,6 +159,7 @@ struct intel_panel { /* backlight */ struct { + bool present; u32 level; bool enabled; struct backlight_device *device; diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 91b68dca0641..a0b5a99204a8 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -396,13 +396,10 @@ int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state) static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_encoder *encoder; struct drm_connector *connector; - struct intel_connector *intel_connector = NULL; - struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0]; + struct intel_connector *intel_connector; + struct intel_panel *panel; struct opregion_asle __iomem *asle = dev_priv->opregion.asle; - u32 ret = 0; - bool found = false; DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp); @@ -414,38 +411,24 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) return ASLC_BACKLIGHT_FAILED; mutex_lock(&dev->mode_config.mutex); + /* - * Could match the OpRegion connector here instead, but we'd also need - * to verify the connector could handle a backlight call. + * Update backlight on all connectors that support backlight (usually + * only one). */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) - if (encoder->crtc == crtc) { - found = true; - break; - } - - if (!found) { - ret = ASLC_BACKLIGHT_FAILED; - goto out; - } - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - if (connector->encoder == encoder) - intel_connector = to_intel_connector(connector); - - if (!intel_connector) { - ret = ASLC_BACKLIGHT_FAILED; - goto out; - } - DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp); - intel_panel_set_backlight(intel_connector, bclp, 255); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + intel_connector = to_intel_connector(connector); + panel = &intel_connector->panel; + if (panel->backlight.present) + intel_panel_set_backlight(intel_connector, bclp, 255); + } iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv); -out: mutex_unlock(&dev->mode_config.mutex); - return ret; + + return 0; } static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 0a4aeaf96865..c80bffc21b5b 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -844,13 +844,17 @@ int intel_panel_setup_backlight(struct drm_connector *connector) intel_backlight_device_register(intel_connector); + panel->backlight.present = true; + return 0; } void intel_panel_destroy_backlight(struct drm_connector *connector) { struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_panel *panel = &intel_connector->panel; + panel->backlight.present = false; intel_backlight_device_unregister(intel_connector); } From 7bd688cd66db93f6430f6e2b3145ee5686daa315 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:48:56 +0200 Subject: [PATCH 027/595] drm/i915: handle backlight through chip specific functions The backlight code has grown rather hairy, not least because the hardware registers and bits have repeatedly been shuffled around. And this isn't expected to get any easier with new hardware. Make things easier for our (read: my) poor brains, and split the code up into chip specific functions. There should be no functional changes. Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 9 + drivers/gpu/drm/i915/intel_display.c | 2 + drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_panel.c | 664 ++++++++++++++++++--------- 4 files changed, 458 insertions(+), 219 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a2009bff2f36..c243b8e954a0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -351,6 +351,7 @@ struct drm_i915_error_state { enum intel_ring_hangcheck_action hangcheck_action[I915_NUM_RINGS]; }; +struct intel_connector; struct intel_crtc_config; struct intel_crtc; struct intel_limit; @@ -413,6 +414,14 @@ struct drm_i915_display_funcs { /* render clock increase/decrease */ /* display clock increase/decrease */ /* pll clock increase/decrease */ + + int (*setup_backlight)(struct intel_connector *connector); + uint32_t (*get_max_backlight)(struct intel_connector *connector); + uint32_t (*get_backlight)(struct intel_connector *connector); + void (*set_backlight)(struct intel_connector *connector, + uint32_t level); + void (*disable_backlight)(struct intel_connector *connector); + void (*enable_backlight)(struct intel_connector *connector); }; struct intel_uncore_funcs { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9cb36a42783e..25ef080d1bc2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10418,6 +10418,8 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.queue_flip = intel_gen7_queue_flip; break; } + + intel_panel_init_backlight_funcs(dev); } /* diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bcb47b83787d..819d0d2f0142 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -161,6 +161,7 @@ struct intel_panel { struct { bool present; u32 level; + u32 max; bool enabled; struct backlight_device *device; } backlight; @@ -817,6 +818,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector); void intel_panel_enable_backlight(struct intel_connector *connector); void intel_panel_disable_backlight(struct intel_connector *connector); void intel_panel_destroy_backlight(struct drm_connector *connector); +void intel_panel_init_backlight_funcs(struct drm_device *dev); enum drm_connector_status intel_panel_detect(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index c80bffc21b5b..a821949a9c7a 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -338,78 +338,116 @@ static int is_backlight_combination_mode(struct drm_device *dev) return 0; } -/* XXX: query mode clock or hardware clock and program max PWM appropriately - * when it's 0. - */ -static u32 i915_read_blc_pwm_ctl(struct drm_device *dev, enum pipe pipe) +static u32 pch_get_max_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 val; - WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight_lock)); - - /* Restore the CTL value if it lost, e.g. GPU reset */ - - if (HAS_PCH_SPLIT(dev_priv->dev)) { - val = I915_READ(BLC_PWM_PCH_CTL2); - if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) { - dev_priv->regfile.saveBLC_PWM_CTL2 = val; - } else if (val == 0) { - val = dev_priv->regfile.saveBLC_PWM_CTL2; - I915_WRITE(BLC_PWM_PCH_CTL2, val); - } - } else if (IS_VALLEYVIEW(dev)) { - val = I915_READ(VLV_BLC_PWM_CTL(pipe)); - if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { - dev_priv->regfile.saveBLC_PWM_CTL = val; - dev_priv->regfile.saveBLC_PWM_CTL2 = - I915_READ(VLV_BLC_PWM_CTL2(pipe)); - } else if (val == 0) { - val = dev_priv->regfile.saveBLC_PWM_CTL; - I915_WRITE(VLV_BLC_PWM_CTL(pipe), val); - I915_WRITE(VLV_BLC_PWM_CTL2(pipe), - dev_priv->regfile.saveBLC_PWM_CTL2); - } - - if (!val) - val = 0x0f42ffff; - } else { - val = I915_READ(BLC_PWM_CTL); - if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { - dev_priv->regfile.saveBLC_PWM_CTL = val; - if (INTEL_INFO(dev)->gen >= 4) - dev_priv->regfile.saveBLC_PWM_CTL2 = - I915_READ(BLC_PWM_CTL2); - } else if (val == 0) { - val = dev_priv->regfile.saveBLC_PWM_CTL; - I915_WRITE(BLC_PWM_CTL, val); - if (INTEL_INFO(dev)->gen >= 4) - I915_WRITE(BLC_PWM_CTL2, - dev_priv->regfile.saveBLC_PWM_CTL2); - } + val = I915_READ(BLC_PWM_PCH_CTL2); + if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) { + dev_priv->regfile.saveBLC_PWM_CTL2 = val; + } else if (val == 0) { + val = dev_priv->regfile.saveBLC_PWM_CTL2; + I915_WRITE(BLC_PWM_PCH_CTL2, val); } + val >>= 16; + return val; } -static u32 intel_panel_get_max_backlight(struct drm_device *dev, - enum pipe pipe) +static u32 i9xx_get_max_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + val = I915_READ(BLC_PWM_CTL); + if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { + dev_priv->regfile.saveBLC_PWM_CTL = val; + } else if (val == 0) { + val = dev_priv->regfile.saveBLC_PWM_CTL; + I915_WRITE(BLC_PWM_CTL, val); + } + + val >>= 17; + + if (is_backlight_combination_mode(dev)) + val *= 0xff; + + return val; +} + +static u32 i965_get_max_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + val = I915_READ(BLC_PWM_CTL); + if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { + dev_priv->regfile.saveBLC_PWM_CTL = val; + dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); + } else if (val == 0) { + val = dev_priv->regfile.saveBLC_PWM_CTL; + I915_WRITE(BLC_PWM_CTL, val); + I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); + } + + val >>= 16; + + if (is_backlight_combination_mode(dev)) + val *= 0xff; + + return val; +} + +static u32 _vlv_get_max_backlight(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + val = I915_READ(VLV_BLC_PWM_CTL(pipe)); + if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { + dev_priv->regfile.saveBLC_PWM_CTL = val; + dev_priv->regfile.saveBLC_PWM_CTL2 = + I915_READ(VLV_BLC_PWM_CTL2(pipe)); + } else if (val == 0) { + val = dev_priv->regfile.saveBLC_PWM_CTL; + I915_WRITE(VLV_BLC_PWM_CTL(pipe), val); + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), + dev_priv->regfile.saveBLC_PWM_CTL2); + } + + if (!val) + val = 0x0f42ffff; + + val >>= 16; + + return val; +} + +static u32 vlv_get_max_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + enum pipe pipe = intel_get_pipe_from_connector(connector); + + return _vlv_get_max_backlight(dev, pipe); +} + +/* XXX: query mode clock or hardware clock and program max PWM appropriately + * when it's 0. + */ +static u32 intel_panel_get_max_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; u32 max; - max = i915_read_blc_pwm_ctl(dev, pipe); + WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight_lock)); - if (HAS_PCH_SPLIT(dev)) { - max >>= 16; - } else { - if (INTEL_INFO(dev)->gen < 4) - max >>= 17; - else - max >>= 16; - - if (is_backlight_combination_mode(dev)) - max *= 0xff; - } + max = dev_priv->display.get_max_backlight(connector); DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); @@ -423,9 +461,10 @@ MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " "to dri-devel@lists.freedesktop.org, if your machine needs it. " "It will then be included in an upcoming module version."); module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); -static u32 intel_panel_compute_brightness(struct drm_device *dev, - enum pipe pipe, u32 val) +static u32 intel_panel_compute_brightness(struct intel_connector *connector, + u32 val) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; if (i915_panel_invert_brightness < 0) @@ -433,7 +472,7 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, if (i915_panel_invert_brightness > 0 || dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { - u32 max = intel_panel_get_max_backlight(dev, pipe); + u32 max = intel_panel_get_max_backlight(connector); if (max) return max - val; } @@ -441,37 +480,60 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, return val; } -static u32 intel_panel_get_backlight(struct drm_device *dev, - enum pipe pipe) +static u32 pch_get_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; +} + +static u32 i9xx_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; + if (INTEL_INFO(dev)->gen < 4) + val >>= 1; + + if (is_backlight_combination_mode(dev)) { + u8 lbpc; + + pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); + val *= lbpc; + } + + return val; +} + +static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; +} + +static u32 vlv_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + enum pipe pipe = intel_get_pipe_from_connector(connector); + + return _vlv_get_backlight(dev, pipe); +} + +static u32 intel_panel_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 val; unsigned long flags; - int reg; spin_lock_irqsave(&dev_priv->backlight_lock, flags); - if (HAS_PCH_SPLIT(dev)) { - val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; - } else { - if (IS_VALLEYVIEW(dev)) - reg = VLV_BLC_PWM_CTL(pipe); - else - reg = BLC_PWM_CTL; - - val = I915_READ(reg) & BACKLIGHT_DUTY_CYCLE_MASK; - if (INTEL_INFO(dev)->gen < 4) - val >>= 1; - - if (is_backlight_combination_mode(dev)) { - u8 lbpc; - - pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); - val *= lbpc; - } - } - - val = intel_panel_compute_brightness(dev, pipe, val); + val = dev_priv->display.get_backlight(connector); + val = intel_panel_compute_brightness(connector, val); spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); @@ -479,28 +541,24 @@ static u32 intel_panel_get_backlight(struct drm_device *dev, return val; } -static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(BLC_PWM_CPU_CTL, val | level); -} - -static void intel_panel_actually_set_backlight(struct drm_device *dev, - enum pipe pipe, u32 level) +static void pch_set_backlight(struct intel_connector *connector, u32 level) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 tmp; - int reg; - DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); - level = intel_panel_compute_brightness(dev, pipe, level); + tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_CPU_CTL, tmp | level); +} - if (HAS_PCH_SPLIT(dev)) - return intel_pch_panel_set_backlight(dev, level); +static void i9xx_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; if (is_backlight_combination_mode(dev)) { - u32 max = intel_panel_get_max_backlight(dev, pipe); + u32 max = intel_panel_get_max_backlight(connector); u8 lbpc; /* we're screwed, but keep behaviour backwards compatible */ @@ -512,16 +570,34 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); } - if (IS_VALLEYVIEW(dev)) - reg = VLV_BLC_PWM_CTL(pipe); - else - reg = BLC_PWM_CTL; - - tmp = I915_READ(reg); if (INTEL_INFO(dev)->gen < 4) level <<= 1; - tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(reg, tmp | level); + + tmp = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_CTL, tmp | level); +} + +static void vlv_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 tmp; + + tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level); +} + +static void +intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); + + level = intel_panel_compute_brightness(connector, level); + dev_priv->display.set_backlight(connector, level); } /* set backlight brightness to level in range [0..max] */ @@ -540,7 +616,7 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, spin_lock_irqsave(&dev_priv->backlight_lock, flags); - freq = intel_panel_get_max_backlight(dev, pipe); + freq = intel_panel_get_max_backlight(connector); if (!freq) { /* we are screwed, bail out */ goto out; @@ -557,11 +633,45 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, panel->backlight.device->props.brightness = level; if (panel->backlight.enabled) - intel_panel_actually_set_backlight(dev, pipe, level); + intel_panel_actually_set_backlight(connector, level); out: spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); } +static void pch_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + tmp = I915_READ(BLC_PWM_CPU_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); + + tmp = I915_READ(BLC_PWM_PCH_CTL1); + I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); +} + +static void i965_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + tmp = I915_READ(BLC_PWM_CTL2); + I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); +} + +static void vlv_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 tmp; + + tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe)); + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE); +} + void intel_panel_disable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -587,38 +697,108 @@ void intel_panel_disable_backlight(struct intel_connector *connector) spin_lock_irqsave(&dev_priv->backlight_lock, flags); panel->backlight.enabled = false; - intel_panel_actually_set_backlight(dev, pipe, 0); + intel_panel_actually_set_backlight(connector, 0); - if (INTEL_INFO(dev)->gen >= 4) { - uint32_t reg, tmp; - - if (HAS_PCH_SPLIT(dev)) - reg = BLC_PWM_CPU_CTL2; - else if (IS_VALLEYVIEW(dev)) - reg = VLV_BLC_PWM_CTL2(pipe); - else - reg = BLC_PWM_CTL2; - - I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE); - - if (HAS_PCH_SPLIT(dev)) { - tmp = I915_READ(BLC_PWM_PCH_CTL1); - tmp &= ~BLM_PCH_PWM_ENABLE; - I915_WRITE(BLC_PWM_PCH_CTL1, tmp); - } - } + if (dev_priv->display.disable_backlight) + dev_priv->display.disable_backlight(connector); spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); } +static void pch_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_get_pipe_from_connector(connector); + enum transcoder cpu_transcoder = + intel_pipe_to_cpu_transcoder(dev_priv, pipe); + u32 tmp; + + tmp = I915_READ(BLC_PWM_CPU_CTL2); + + /* Note that this can also get called through dpms changes. And + * we don't track the backlight dpms state, hence check whether + * we have to do anything first. */ + if (tmp & BLM_PWM_ENABLE) + return; + + if (INTEL_INFO(dev)->num_pipes == 3) + tmp &= ~BLM_PIPE_SELECT_IVB; + else + tmp &= ~BLM_PIPE_SELECT; + + if (cpu_transcoder == TRANSCODER_EDP) + tmp |= BLM_TRANSCODER_EDP; + else + tmp |= BLM_PIPE(cpu_transcoder); + tmp &= ~BLM_PWM_ENABLE; + + I915_WRITE(BLC_PWM_CPU_CTL2, tmp); + POSTING_READ(BLC_PWM_CPU_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL2, tmp | BLM_PWM_ENABLE); + + if (!(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) { + tmp = I915_READ(BLC_PWM_PCH_CTL1); + tmp |= BLM_PCH_PWM_ENABLE; + tmp &= ~BLM_PCH_OVERRIDE_ENABLE; + I915_WRITE(BLC_PWM_PCH_CTL1, tmp); + } +} + +static void i965_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 tmp; + + tmp = I915_READ(BLC_PWM_CTL2); + + /* Note that this can also get called through dpms changes. And + * we don't track the backlight dpms state, hence check whether + * we have to do anything first. */ + if (tmp & BLM_PWM_ENABLE) + return; + + tmp &= ~BLM_PIPE_SELECT; + tmp |= BLM_PIPE(pipe); + tmp &= ~BLM_PWM_ENABLE; + + I915_WRITE(BLC_PWM_CTL2, tmp); + POSTING_READ(BLC_PWM_CTL2); + I915_WRITE(BLC_PWM_CTL2, tmp | BLM_PWM_ENABLE); +} + +static void vlv_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 tmp; + + tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe)); + + /* Note that this can also get called through dpms changes. And + * we don't track the backlight dpms state, hence check whether + * we have to do anything first. */ + if (tmp & BLM_PWM_ENABLE) + return; + + tmp &= ~BLM_PIPE_SELECT; + tmp |= BLM_PIPE(pipe); + tmp &= ~BLM_PWM_ENABLE; + + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp); + POSTING_READ(VLV_BLC_PWM_CTL2(pipe)); + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp | BLM_PWM_ENABLE); +} + void intel_panel_enable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); - enum transcoder cpu_transcoder = - intel_pipe_to_cpu_transcoder(dev_priv, pipe); unsigned long flags; if (pipe == INVALID_PIPE) @@ -629,89 +809,25 @@ void intel_panel_enable_backlight(struct intel_connector *connector) spin_lock_irqsave(&dev_priv->backlight_lock, flags); if (panel->backlight.level == 0) { - panel->backlight.level = intel_panel_get_max_backlight(dev, - pipe); + panel->backlight.level = intel_panel_get_max_backlight(connector); if (panel->backlight.device) panel->backlight.device->props.brightness = panel->backlight.level; } - if (INTEL_INFO(dev)->gen >= 4) { - uint32_t reg, tmp; + if (dev_priv->display.enable_backlight) + dev_priv->display.enable_backlight(connector); - if (HAS_PCH_SPLIT(dev)) - reg = BLC_PWM_CPU_CTL2; - else if (IS_VALLEYVIEW(dev)) - reg = VLV_BLC_PWM_CTL2(pipe); - else - reg = BLC_PWM_CTL2; - - tmp = I915_READ(reg); - - /* Note that this can also get called through dpms changes. And - * we don't track the backlight dpms state, hence check whether - * we have to do anything first. */ - if (tmp & BLM_PWM_ENABLE) - goto set_level; - - if (INTEL_INFO(dev)->num_pipes == 3) - tmp &= ~BLM_PIPE_SELECT_IVB; - else - tmp &= ~BLM_PIPE_SELECT; - - if (cpu_transcoder == TRANSCODER_EDP) - tmp |= BLM_TRANSCODER_EDP; - else - tmp |= BLM_PIPE(cpu_transcoder); - tmp &= ~BLM_PWM_ENABLE; - - I915_WRITE(reg, tmp); - POSTING_READ(reg); - I915_WRITE(reg, tmp | BLM_PWM_ENABLE); - - if (HAS_PCH_SPLIT(dev) && - !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) { - tmp = I915_READ(BLC_PWM_PCH_CTL1); - tmp |= BLM_PCH_PWM_ENABLE; - tmp &= ~BLM_PCH_OVERRIDE_ENABLE; - I915_WRITE(BLC_PWM_PCH_CTL1, tmp); - } - } - -set_level: /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. * BLC_PWM_CPU_CTL may be cleared to zero automatically when these * registers are set. */ panel->backlight.enabled = true; - intel_panel_actually_set_backlight(dev, pipe, - panel->backlight.level); + intel_panel_actually_set_backlight(connector, panel->backlight.level); spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); } -/* FIXME: use VBT vals to init PWM_CTL and PWM_CTL2 correctly */ -static void intel_panel_init_backlight_regs(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (IS_VALLEYVIEW(dev)) { - enum pipe pipe; - - for_each_pipe(pipe) { - u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe)); - - /* Skip if the modulation freq is already set */ - if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK) - continue; - - cur_val &= BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) | - cur_val); - } - } -} - enum drm_connector_status intel_panel_detect(struct drm_device *dev) { @@ -753,15 +869,13 @@ static int intel_backlight_device_get_brightness(struct backlight_device *bd) { struct intel_connector *connector = bl_get_data(bd); struct drm_device *dev = connector->base.dev; - enum pipe pipe; + int ret; mutex_lock(&dev->mode_config.mutex); - pipe = intel_get_pipe_from_connector(connector); + ret = intel_panel_get_backlight(connector); mutex_unlock(&dev->mode_config.mutex); - if (pipe == INVALID_PIPE) - return 0; - return intel_panel_get_backlight(connector->base.dev, pipe); + return ret; } static const struct backlight_ops intel_backlight_device_ops = { @@ -771,27 +885,18 @@ static const struct backlight_ops intel_backlight_device_ops = { static int intel_backlight_device_register(struct intel_connector *connector) { - struct drm_device *dev = connector->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; struct backlight_properties props; - unsigned long flags; if (WARN_ON(panel->backlight.device)) return -ENODEV; + BUG_ON(panel->backlight.max == 0); + memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.brightness = panel->backlight.level; - - spin_lock_irqsave(&dev_priv->backlight_lock, flags); - props.max_brightness = intel_panel_get_max_backlight(dev, 0); - spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); - - if (props.max_brightness == 0) { - DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); - return -ENODEV; - } + props.max_brightness = panel->backlight.max; /* * Note: using the same name independent of the connector prevents @@ -831,15 +936,102 @@ static void intel_backlight_device_unregister(struct intel_connector *connector) } #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ +/* Note: The setup hooks can't assume pipe is set! */ +static int pch_setup_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + u32 val; + + panel->backlight.max = pch_get_max_backlight(connector); + if (!panel->backlight.max) + return -ENODEV; + + val = pch_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + return 0; +} + +static int i9xx_setup_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + u32 val; + + panel->backlight.max = i9xx_get_max_backlight(connector); + if (!panel->backlight.max) + return -ENODEV; + + val = i9xx_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + return 0; +} + +static int i965_setup_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + u32 val; + + panel->backlight.max = i965_get_max_backlight(connector); + if (!panel->backlight.max) + return -ENODEV; + + val = i9xx_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + return 0; +} + +static int vlv_setup_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe; + u32 val; + + for_each_pipe(pipe) { + u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe)); + + /* Skip if the modulation freq is already set */ + if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK) + continue; + + cur_val &= BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) | + cur_val); + } + + panel->backlight.max = _vlv_get_max_backlight(dev, PIPE_A); + if (!panel->backlight.max) + return -ENODEV; + + val = _vlv_get_backlight(dev, PIPE_A); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + return 0; +} + int intel_panel_setup_backlight(struct drm_connector *connector) { struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_panel *panel = &intel_connector->panel; + unsigned long flags; + int ret; - intel_panel_init_backlight_regs(dev); + /* set level and max in panel struct */ + spin_lock_irqsave(&dev_priv->backlight_lock, flags); + ret = dev_priv->display.setup_backlight(intel_connector); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); + + if (ret) { + DRM_DEBUG_KMS("failed to setup backlight for connector %s\n", + drm_get_connector_name(connector)); + return ret; + } - panel->backlight.level = intel_panel_get_backlight(dev, 0); panel->backlight.enabled = panel->backlight.level != 0; intel_backlight_device_register(intel_connector); @@ -858,6 +1050,40 @@ void intel_panel_destroy_backlight(struct drm_connector *connector) intel_backlight_device_unregister(intel_connector); } +/* Set up chip specific backlight functions */ +void intel_panel_init_backlight_funcs(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.setup_backlight = pch_setup_backlight; + dev_priv->display.enable_backlight = pch_enable_backlight; + dev_priv->display.disable_backlight = pch_disable_backlight; + dev_priv->display.set_backlight = pch_set_backlight; + dev_priv->display.get_backlight = pch_get_backlight; + dev_priv->display.get_max_backlight = pch_get_max_backlight; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.setup_backlight = vlv_setup_backlight; + dev_priv->display.enable_backlight = vlv_enable_backlight; + dev_priv->display.disable_backlight = vlv_disable_backlight; + dev_priv->display.set_backlight = vlv_set_backlight; + dev_priv->display.get_backlight = vlv_get_backlight; + dev_priv->display.get_max_backlight = vlv_get_max_backlight; + } else if (IS_GEN4(dev)) { + dev_priv->display.setup_backlight = i965_setup_backlight; + dev_priv->display.enable_backlight = i965_enable_backlight; + dev_priv->display.disable_backlight = i965_disable_backlight; + dev_priv->display.set_backlight = i9xx_set_backlight; + dev_priv->display.get_backlight = i9xx_get_backlight; + dev_priv->display.get_max_backlight = i965_get_max_backlight; + } else { + dev_priv->display.setup_backlight = i9xx_setup_backlight; + dev_priv->display.set_backlight = i9xx_set_backlight; + dev_priv->display.get_backlight = i9xx_get_backlight; + dev_priv->display.get_max_backlight = i9xx_get_max_backlight; + } +} + int intel_panel_init(struct intel_panel *panel, struct drm_display_mode *fixed_mode) { From b53c8c3577150a70e94b10090f68cfe3a4b601a5 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 12 Nov 2013 14:53:08 -0800 Subject: [PATCH 028/595] drm/i915: drop duplicate ggtt vma list add in setup_global_gtt Preallocated objects will already have been added to the vma_list when creating their ggtt vma entry, and coincidentally also marked as holding a ggtt mapping. Repeating the vma_list manipulation when setting up the ggtt after preallocation is a recipe for an unhappy kernel. Signed-off-by: Jesse Barnes Reviewed-by: Chris Wilson [danvet: Use the improve commit message suggest by Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index c4c42e7cbd7b..2b4c530d74a3 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -759,7 +759,6 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, if (ret) DRM_DEBUG_KMS("Reservation failed\n"); obj->has_global_gtt_mapping = 1; - list_add(&vma->vma_link, &obj->vma_list); } dev_priv->gtt.base.start = start; From b329b32854eca71853ce1e3e06b573c25b262d5f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:48:57 +0200 Subject: [PATCH 029/595] drm/i915: fix gen2-gen3 backlight set Citing Jani's response to Imre's question in the review discussion: > According to the gen2/3 bspec I have, the correct mask is > BACKLIGHT_DUTY_CYCLE_MASK_PNV only in case of IS_PINEVIEW(dev), for > everything else it's BACKLIGHT_DUTY_CYCLE_MASK. What you say is correct, but we've treated all gen2/3 similar to PNV since commit ca88479c1c3b7b1a9f94320745f5331e1de77f80 Author: Keith Packard Date: Fri Nov 18 11:09:24 2011 -0800 drm/i915: Treat pre-gen4 backlight duty cycle value consistently i.e. we only use the high 15 bits for all gen2/3. For non-PNV this just means the lowest bit is always zero. For PNV the lowest bit has a different meaning in both the PWM freq and duty cycle fields. Signed-off-by: Jani Nikula Reviewed-by: Imre Deak [danvet: Make the commit message less empty.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index a821949a9c7a..e82b2dd93eef 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -555,7 +555,7 @@ static void i9xx_set_backlight(struct intel_connector *connector, u32 level) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 tmp; + u32 tmp, mask; if (is_backlight_combination_mode(dev)) { u32 max = intel_panel_get_max_backlight(connector); @@ -570,10 +570,14 @@ static void i9xx_set_backlight(struct intel_connector *connector, u32 level) pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); } - if (INTEL_INFO(dev)->gen < 4) + if (IS_GEN4(dev)) { + mask = BACKLIGHT_DUTY_CYCLE_MASK; + } else { level <<= 1; + mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; + } - tmp = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + tmp = I915_READ(BLC_PWM_CTL) & ~mask; I915_WRITE(BLC_PWM_CTL, tmp | level); } From ab51c86a88ba09ec657b1e02aa7824938afb7bd3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:48:58 +0200 Subject: [PATCH 030/595] drm/i915: vlv does not have pipe field in backlight registers It has per pipe registers. Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e82b2dd93eef..5bd64db9a9bf 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -788,8 +788,6 @@ static void vlv_enable_backlight(struct intel_connector *connector) if (tmp & BLM_PWM_ENABLE) return; - tmp &= ~BLM_PIPE_SELECT; - tmp |= BLM_PIPE(pipe); tmp &= ~BLM_PWM_ENABLE; I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp); From 3bd712e545996658f4bc6c61ff99d7bae2a8cfcf Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:48:59 +0200 Subject: [PATCH 031/595] drm/i915: move backlight level setting in enable/disable to hooks This allows more flexibility in the ordering of the register writes, and lets us drop level setting altogether as necessary on a per platform basis. For gen2-gen3, this is the only thing that happens in enable/disable. Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 48 ++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 5bd64db9a9bf..ed6b1eccb7dd 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -648,6 +648,8 @@ static void pch_disable_backlight(struct intel_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; u32 tmp; + intel_panel_actually_set_backlight(connector, 0); + tmp = I915_READ(BLC_PWM_CPU_CTL2); I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); @@ -655,12 +657,19 @@ static void pch_disable_backlight(struct intel_connector *connector) I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); } +static void i9xx_disable_backlight(struct intel_connector *connector) +{ + intel_panel_actually_set_backlight(connector, 0); +} + static void i965_disable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 tmp; + intel_panel_actually_set_backlight(connector, 0); + tmp = I915_READ(BLC_PWM_CTL2); I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); } @@ -672,6 +681,8 @@ static void vlv_disable_backlight(struct intel_connector *connector) enum pipe pipe = intel_get_pipe_from_connector(connector); u32 tmp; + intel_panel_actually_set_backlight(connector, 0); + tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe)); I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE); } @@ -701,10 +712,7 @@ void intel_panel_disable_backlight(struct intel_connector *connector) spin_lock_irqsave(&dev_priv->backlight_lock, flags); panel->backlight.enabled = false; - intel_panel_actually_set_backlight(connector, 0); - - if (dev_priv->display.disable_backlight) - dev_priv->display.disable_backlight(connector); + dev_priv->display.disable_backlight(connector); spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); } @@ -713,6 +721,7 @@ static void pch_enable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); @@ -747,12 +756,27 @@ static void pch_enable_backlight(struct intel_connector *connector) tmp &= ~BLM_PCH_OVERRIDE_ENABLE; I915_WRITE(BLC_PWM_PCH_CTL1, tmp); } + + /* + * Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. + * BLC_PWM_CPU_CTL may be cleared to zero automatically when these + * registers are set. + */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); +} + +static void i9xx_enable_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + + intel_panel_actually_set_backlight(connector, panel->backlight.level); } static void i965_enable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); u32 tmp; @@ -771,12 +795,15 @@ static void i965_enable_backlight(struct intel_connector *connector) I915_WRITE(BLC_PWM_CTL2, tmp); POSTING_READ(BLC_PWM_CTL2); I915_WRITE(BLC_PWM_CTL2, tmp | BLM_PWM_ENABLE); + + intel_panel_actually_set_backlight(connector, panel->backlight.level); } static void vlv_enable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); u32 tmp; @@ -793,6 +820,8 @@ static void vlv_enable_backlight(struct intel_connector *connector) I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp); POSTING_READ(VLV_BLC_PWM_CTL2(pipe)); I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp | BLM_PWM_ENABLE); + + intel_panel_actually_set_backlight(connector, panel->backlight.level); } void intel_panel_enable_backlight(struct intel_connector *connector) @@ -817,15 +846,8 @@ void intel_panel_enable_backlight(struct intel_connector *connector) panel->backlight.level; } - if (dev_priv->display.enable_backlight) - dev_priv->display.enable_backlight(connector); - - /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. - * BLC_PWM_CPU_CTL may be cleared to zero automatically when these - * registers are set. - */ + dev_priv->display.enable_backlight(connector); panel->backlight.enabled = true; - intel_panel_actually_set_backlight(connector, panel->backlight.level); spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); } @@ -1080,6 +1102,8 @@ void intel_panel_init_backlight_funcs(struct drm_device *dev) dev_priv->display.get_max_backlight = i965_get_max_backlight; } else { dev_priv->display.setup_backlight = i9xx_setup_backlight; + dev_priv->display.enable_backlight = i9xx_enable_backlight; + dev_priv->display.disable_backlight = i9xx_disable_backlight; dev_priv->display.set_backlight = i9xx_set_backlight; dev_priv->display.get_backlight = i9xx_get_backlight; dev_priv->display.get_max_backlight = i9xx_get_max_backlight; From f91c15e0808e612abacdb0fbca557b23fe2aa4d1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:49:00 +0200 Subject: [PATCH 032/595] drm/i915: use the initialized backlight max value instead of reading it We now have the max backlight value cached. Use it. Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 45 ++++++++++++++++-------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index ed6b1eccb7dd..9a55b36370b3 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -436,9 +436,6 @@ static u32 vlv_get_max_backlight(struct intel_connector *connector) return _vlv_get_max_backlight(dev, pipe); } -/* XXX: query mode clock or hardware clock and program max PWM appropriately - * when it's 0. - */ static u32 intel_panel_get_max_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -466,15 +463,16 @@ static u32 intel_panel_compute_brightness(struct intel_connector *connector, { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + + WARN_ON(panel->backlight.max == 0); if (i915_panel_invert_brightness < 0) return val; if (i915_panel_invert_brightness > 0 || dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { - u32 max = intel_panel_get_max_backlight(connector); - if (max) - return max - val; + return panel->backlight.max - val; } return val; @@ -555,17 +553,15 @@ static void i9xx_set_backlight(struct intel_connector *connector, u32 level) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; u32 tmp, mask; + WARN_ON(panel->backlight.max == 0); + if (is_backlight_combination_mode(dev)) { - u32 max = intel_panel_get_max_backlight(connector); u8 lbpc; - /* we're screwed, but keep behaviour backwards compatible */ - if (!max) - max = 1; - - lbpc = level * 0xfe / max + 1; + lbpc = level * 0xfe / panel->backlight.max + 1; level /= lbpc; pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); } @@ -620,13 +616,10 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, spin_lock_irqsave(&dev_priv->backlight_lock, flags); - freq = intel_panel_get_max_backlight(connector); - if (!freq) { - /* we are screwed, bail out */ - goto out; - } + WARN_ON(panel->backlight.max == 0); - /* scale to hardware, but be careful to not overflow */ + /* scale to hardware max, but be careful to not overflow */ + freq = panel->backlight.max; if (freq < max) level = level * freq / max; else @@ -638,7 +631,7 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, if (panel->backlight.enabled) intel_panel_actually_set_backlight(connector, level); -out: + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); } @@ -839,8 +832,13 @@ void intel_panel_enable_backlight(struct intel_connector *connector) spin_lock_irqsave(&dev_priv->backlight_lock, flags); + /* XXX: transitional, call to make sure freq is set */ + intel_panel_get_max_backlight(connector); + + WARN_ON(panel->backlight.max == 0); + if (panel->backlight.level == 0) { - panel->backlight.level = intel_panel_get_max_backlight(connector); + panel->backlight.level = panel->backlight.max; if (panel->backlight.device) panel->backlight.device->props.brightness = panel->backlight.level; @@ -960,7 +958,12 @@ static void intel_backlight_device_unregister(struct intel_connector *connector) } #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ -/* Note: The setup hooks can't assume pipe is set! */ +/* + * Note: The setup hooks can't assume pipe is set! + * + * XXX: Query mode clock or hardware clock and program PWM modulation frequency + * appropriately when it's 0. Use VBT and/or sane defaults. + */ static int pch_setup_backlight(struct intel_connector *connector) { struct intel_panel *panel = &connector->panel; From c445b3b1e02a40666b7e4bea58bce0c4723eba4f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:49:01 +0200 Subject: [PATCH 033/595] drm/i915: debug print on backlight register Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 9a55b36370b3..3dd9f57da69c 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -1065,6 +1065,12 @@ int intel_panel_setup_backlight(struct drm_connector *connector) panel->backlight.present = true; + DRM_DEBUG_KMS("backlight initialized, %s, brightness %u/%u, " + "sysfs interface %sregistered\n", + panel->backlight.enabled ? "enabled" : "disabled", + panel->backlight.level, panel->backlight.max, + panel->backlight.device ? "" : "not "); + return 0; } From 661df0415e6f6bfaade501fb94cc324fa44f29b4 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 12 Nov 2013 19:49:35 +0200 Subject: [PATCH 034/595] drm/i915: check i915_get_reset_stats_ioctl args Insist that flags and pad fields are zero, so that we can safely extend the interface in future. Testcase: igt/gem_reset_stats/params Suggested-by: Daniel Vetter Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 21cf9519be78..a881906969eb 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -641,6 +641,9 @@ int i915_get_reset_stats_ioctl(struct drm_device *dev, struct i915_ctx_hang_stats *hs; int ret; + if (args->flags || args->pad) + return -EINVAL; + if (args->ctx_id == DEFAULT_CONTEXT_ID && !capable(CAP_SYS_ADMIN)) return -EPERM; From ea8eea73ac62fab878912a74df7fb586586238e7 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 11 Nov 2013 09:35:17 +0100 Subject: [PATCH 035/595] drm/i915: Make AGP=n work even on gen3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most platforms din't hit this condition, but if we want to allow building without agp we should also make this allowed on gen3. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c3e9485f38fe..a19940f5ef06 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -158,7 +158,7 @@ static struct drm_driver driver; #if IS_ENABLED(CONFIG_AGP_INTEL) extern int intel_agp_enabled; #else -static int intel_agp_enabled; +static int intel_agp_enabled = 1; #endif static const struct intel_device_info intel_i830_info = { From 3bb6ce66866310f50d461b9eff949c1ce95560ce Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 13 Nov 2013 22:14:16 +0100 Subject: [PATCH 036/595] drm/i915: Kill legeacy AGP for gen3 kms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thus far we've tried to carefully work around the fact that old userspace relied on the AGP-backed legacy buffer mapping ioctls for a bit too long. But it's really horribly, and now some new users for it started to show up again: http://www.mail-archive.com/mesa-dev@lists.freedesktop.org/msg45547.html This uses drmAgpSize to figure out the GTT size, which is both the wrong thing to inquire and also might force us to keep this crap around for another few years. So I want to stop this particular zombie from raising ever again. Now it's only been 4 years since XvMC was fixed for gen3, so a bit early by the usual rules. But since Linus explicitly said that an ABI breakage only counts if someone actually observes it I want to tempt fate an accelarate the demise of AGP. We probably need to wait 2-3 kernel releases with this shipping until we go on a killing spree code-wise. v2: Remove intel_agp_enabled since it's unused (Ville). Cc: Ville Syrjälä Cc: Dave Airlie Acked-by: Dave Airlie Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/char/agp/intel-agp.c | 5 ----- drivers/gpu/drm/i915/i915_drv.c | 17 +---------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index a426ee1f57a6..9ef0a48a5b28 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -14,9 +14,6 @@ #include "intel-agp.h" #include -int intel_agp_enabled; -EXPORT_SYMBOL(intel_agp_enabled); - static int intel_fetch_size(void) { int i; @@ -814,8 +811,6 @@ static int agp_intel_probe(struct pci_dev *pdev, found_gmch: pci_set_drvdata(pdev, bridge); err = agp_add_bridge(bridge); - if (!err) - intel_agp_enabled = 1; return err; } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a19940f5ef06..b16a6eca795f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -155,11 +155,6 @@ MODULE_PARM_DESC(prefault_disable, "Disable page prefaulting for pread/pwrite/reloc (default:false). For developers only."); static struct drm_driver driver; -#if IS_ENABLED(CONFIG_AGP_INTEL) -extern int intel_agp_enabled; -#else -static int intel_agp_enabled = 1; -#endif static const struct intel_device_info intel_i830_info = { .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2, @@ -797,17 +792,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (PCI_FUNC(pdev->devfn)) return -ENODEV; - /* We've managed to ship a kms-enabled ddx that shipped with an XvMC - * implementation for gen3 (and only gen3) that used legacy drm maps - * (gasp!) to share buffers between X and the client. Hence we need to - * keep around the fake agp stuff for gen3, even when kms is enabled. */ - if (intel_info->gen != 3) { - driver.driver_features &= - ~(DRIVER_USE_AGP | DRIVER_REQUIRE_AGP); - } else if (!intel_agp_enabled) { - DRM_ERROR("drm/i915 can't work without intel_agp module!\n"); - return -ENODEV; - } + driver.driver_features &= ~(DRIVER_USE_AGP | DRIVER_REQUIRE_AGP); return drm_get_pci_dev(pdev, ent, &driver); } From b30324adaf8d2e5950a602bde63030d15a61826f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 13 Nov 2013 22:11:25 +0100 Subject: [PATCH 037/595] drm/i915: Deprecated UMS support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's been 5 years since kms support was merged and roughly 4 years since UMS support was ripped out from userspace drivers. Thus far it's not been a big burden to keep the ums paths alive, and we've made some good progress in better separating it from the kms code by sprinkling DRIVER_MODESET checks all over the place. But now that the drm demidlayering is within reach this changes. I want to make the driver loading code more robust using devres.c and other cool tricks. But that doesn't work with ums due to the shadow-attach trick. Which means we either a) need to split out a complete ums codebase like radeon has b) kill it for good. The 2nd option is obviously much less work than the first, so I think it's time to test the waters and see how many people out there still use ums. I've decided that silently failing to initialize the driver (and not e.g. failing to load the module) is the right thing. That way we should only get reports from users that actually care about some ums features (like accelerated gl or support for secondary outputs). Everyone else will just fall back to the vesa X driver. For developers there's a small info level dmesg output. The plan is to drop this Kconfig option after 3.16 (so gives us 2 full releases) and then start killing code for real 2-3 releases afterwards. That should be more than enough time for users to pipe up. Of course if anyone does we need to revisit this plan and maybe go with option a) above. Also enable the KMS support by default in Kconfig and polish the help texts a bit. v2: Add the missing hunk of actual code changes. Oops. (Ville) Cc: Ville Syrjälä Cc: Dave Airlie Acked-by: Dave Airlie Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Kconfig | 24 +++++++++++++++++++----- drivers/gpu/drm/i915/i915_drv.c | 7 ++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index b0f61679c598..b0fa4c4055ee 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -37,12 +37,11 @@ config DRM_I915 config DRM_I915_KMS bool "Enable modesetting on intel by default" depends on DRM_I915 + default y help - Choose this option if you want kernel modesetting enabled by default, - and you have a new enough userspace to support this. Running old - userspaces with this enabled will cause pain. Note that this causes - the driver to bind to PCI devices, which precludes loading things - like intelfb. + Choose this option if you want kernel modesetting enabled by default. + + If in doubt, say "Y". config DRM_I915_FBDEV bool "Enable legacy fbdev support for the modesettting intel driver" @@ -57,9 +56,12 @@ config DRM_I915_FBDEV support. Note that this support also provide the linux console support on top of the intel modesetting driver. + If in doubt, say "Y". + config DRM_I915_PRELIMINARY_HW_SUPPORT bool "Enable preliminary support for prerelease Intel hardware by default" depends on DRM_I915 + default n help Choose this option if you have prerelease Intel hardware and want the i915 driver to support it by default. You can enable such support at @@ -67,3 +69,15 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT option changes the default for that module option. If in doubt, say "N". + +config DRM_I915_UMS + bool "Enable userspace modesetting on Intel hardware (DEPRECATED)" + depends on DRM_I915 + default n + help + Choose this option if you still need userspace modesetting. + + Userspace modesetting is deprecated for quite some time now, so + enable this only if you have ancient versions of the DDX drivers. + + If in doubt, say "N". diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b16a6eca795f..92ad319164d7 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -975,8 +975,13 @@ static int __init i915_init(void) driver.driver_features &= ~DRIVER_MODESET; #endif - if (!(driver.driver_features & DRIVER_MODESET)) + if (!(driver.driver_features & DRIVER_MODESET)) { driver.get_vblank_timestamp = NULL; +#ifndef CONFIG_DRM_I915_UMS + /* Silently fail loading to not upset userspace. */ + return 0; +#endif + } return drm_pci_init(&driver, &i915_pci_driver); } From 636baebfa62fa31b204bc5a816700bd2fd135e57 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:49:02 +0200 Subject: [PATCH 038/595] drm/i915: gather backlight information at setup Prepare for being able to use the information at enable. Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_panel.c | 68 ++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 819d0d2f0142..4fbd073810ef 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -163,6 +163,8 @@ struct intel_panel { u32 level; u32 max; bool enabled; + bool combination_mode; /* gen 2/4 only */ + bool active_low_pwm; struct backlight_device *device; } backlight; }; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 3dd9f57da69c..0e8f0a3d3bf6 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -490,13 +490,14 @@ static u32 i9xx_get_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; u32 val; val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; if (INTEL_INFO(dev)->gen < 4) val >>= 1; - if (is_backlight_combination_mode(dev)) { + if (panel->backlight.combination_mode) { u8 lbpc; pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); @@ -558,7 +559,7 @@ static void i9xx_set_backlight(struct intel_connector *connector, u32 level) WARN_ON(panel->backlight.max == 0); - if (is_backlight_combination_mode(dev)) { + if (panel->backlight.combination_mode) { u8 lbpc; lbpc = level * 0xfe / panel->backlight.max + 1; @@ -966,46 +967,84 @@ static void intel_backlight_device_unregister(struct intel_connector *connector) */ static int pch_setup_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; - u32 val; + u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; - panel->backlight.max = pch_get_max_backlight(connector); + pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); + panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; + + pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); + panel->backlight.max = pch_ctl2 >> 16; if (!panel->backlight.max) return -ENODEV; val = pch_get_backlight(connector); panel->backlight.level = intel_panel_compute_brightness(connector, val); + cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); + panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && + (pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0; + return 0; } static int i9xx_setup_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; - u32 val; + u32 ctl, val; + + ctl = I915_READ(BLC_PWM_CTL); + + if (IS_GEN2(dev)) + panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; + + if (IS_PINEVIEW(dev)) + panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; + + panel->backlight.max = ctl >> 17; + if (panel->backlight.combination_mode) + panel->backlight.max *= 0xff; - panel->backlight.max = i9xx_get_max_backlight(connector); if (!panel->backlight.max) return -ENODEV; val = i9xx_get_backlight(connector); panel->backlight.level = intel_panel_compute_brightness(connector, val); + panel->backlight.enabled = panel->backlight.level != 0; + return 0; } static int i965_setup_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; - u32 val; + u32 ctl, ctl2, val; + + ctl2 = I915_READ(BLC_PWM_CTL2); + panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; + panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; + + ctl = I915_READ(BLC_PWM_CTL); + panel->backlight.max = ctl >> 16; + if (panel->backlight.combination_mode) + panel->backlight.max *= 0xff; - panel->backlight.max = i965_get_max_backlight(connector); if (!panel->backlight.max) return -ENODEV; val = i9xx_get_backlight(connector); panel->backlight.level = intel_panel_compute_brightness(connector, val); + panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && + panel->backlight.level != 0; + return 0; } @@ -1015,7 +1054,7 @@ static int vlv_setup_backlight(struct intel_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; enum pipe pipe; - u32 val; + u32 ctl, ctl2, val; for_each_pipe(pipe) { u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe)); @@ -1029,13 +1068,20 @@ static int vlv_setup_backlight(struct intel_connector *connector) cur_val); } - panel->backlight.max = _vlv_get_max_backlight(dev, PIPE_A); + ctl2 = I915_READ(VLV_BLC_PWM_CTL2(PIPE_A)); + panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; + + ctl = I915_READ(VLV_BLC_PWM_CTL(PIPE_A)); + panel->backlight.max = ctl >> 16; if (!panel->backlight.max) return -ENODEV; val = _vlv_get_backlight(dev, PIPE_A); panel->backlight.level = intel_panel_compute_brightness(connector, val); + panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && + panel->backlight.level != 0; + return 0; } @@ -1059,8 +1105,6 @@ int intel_panel_setup_backlight(struct drm_connector *connector) return ret; } - panel->backlight.enabled = panel->backlight.level != 0; - intel_backlight_device_register(intel_connector); panel->backlight.present = true; From b35684b8fa94e04f55fd38bf672b737741d2f9e2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 14 Nov 2013 12:13:41 +0200 Subject: [PATCH 039/595] drm/i915: do full backlight setup at enable time We should now have all the information we need to do a full initialization of the backlight registers. v2: Keep QUIRK_NO_PCH_PWM_ENABLE for now (Imre). Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 159 ++++++++++++++++++----------- 1 file changed, 98 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 0e8f0a3d3bf6..0986472d4254 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -719,50 +719,75 @@ static void pch_enable_backlight(struct intel_connector *connector) enum pipe pipe = intel_get_pipe_from_connector(connector); enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); - u32 tmp; + u32 cpu_ctl2, pch_ctl1, pch_ctl2; - tmp = I915_READ(BLC_PWM_CPU_CTL2); - - /* Note that this can also get called through dpms changes. And - * we don't track the backlight dpms state, hence check whether - * we have to do anything first. */ - if (tmp & BLM_PWM_ENABLE) - return; - - if (INTEL_INFO(dev)->num_pipes == 3) - tmp &= ~BLM_PIPE_SELECT_IVB; - else - tmp &= ~BLM_PIPE_SELECT; - - if (cpu_transcoder == TRANSCODER_EDP) - tmp |= BLM_TRANSCODER_EDP; - else - tmp |= BLM_PIPE(cpu_transcoder); - tmp &= ~BLM_PWM_ENABLE; - - I915_WRITE(BLC_PWM_CPU_CTL2, tmp); - POSTING_READ(BLC_PWM_CPU_CTL2); - I915_WRITE(BLC_PWM_CPU_CTL2, tmp | BLM_PWM_ENABLE); - - if (!(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) { - tmp = I915_READ(BLC_PWM_PCH_CTL1); - tmp |= BLM_PCH_PWM_ENABLE; - tmp &= ~BLM_PCH_OVERRIDE_ENABLE; - I915_WRITE(BLC_PWM_PCH_CTL1, tmp); + cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); + if (cpu_ctl2 & BLM_PWM_ENABLE) { + WARN(1, "cpu backlight already enabled\n"); + cpu_ctl2 &= ~BLM_PWM_ENABLE; + I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); } - /* - * Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. - * BLC_PWM_CPU_CTL may be cleared to zero automatically when these - * registers are set. - */ + pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); + if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { + DRM_DEBUG_KMS("pch backlight already enabled\n"); + pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); + } + + if (cpu_transcoder == TRANSCODER_EDP) + cpu_ctl2 = BLM_TRANSCODER_EDP; + else + cpu_ctl2 = BLM_PIPE(cpu_transcoder); + I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); + POSTING_READ(BLC_PWM_CPU_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); + + /* This won't stick until the above enable. */ intel_panel_actually_set_backlight(connector, panel->backlight.level); + + pch_ctl2 = panel->backlight.max << 16; + I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); + + /* XXX: transitional */ + if (dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE) + return; + + pch_ctl1 = 0; + if (panel->backlight.active_low_pwm) + pch_ctl1 |= BLM_PCH_POLARITY; + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); + POSTING_READ(BLC_PWM_PCH_CTL1); + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); } static void i9xx_enable_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; + u32 ctl, freq; + ctl = I915_READ(BLC_PWM_CTL); + if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { + WARN(1, "backlight already enabled\n"); + I915_WRITE(BLC_PWM_CTL, 0); + } + + freq = panel->backlight.max; + if (panel->backlight.combination_mode) + freq /= 0xff; + + ctl = freq << 17; + if (IS_GEN2(dev) && panel->backlight.combination_mode) + ctl |= BLM_LEGACY_MODE; + if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm) + ctl |= BLM_POLARITY_PNV; + + I915_WRITE(BLC_PWM_CTL, ctl); + POSTING_READ(BLC_PWM_CTL); + + /* XXX: combine this into above write? */ intel_panel_actually_set_backlight(connector, panel->backlight.level); } @@ -772,25 +797,33 @@ static void i965_enable_backlight(struct intel_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); - u32 tmp; + u32 ctl, ctl2, freq; - tmp = I915_READ(BLC_PWM_CTL2); + ctl2 = I915_READ(BLC_PWM_CTL2); + if (ctl2 & BLM_PWM_ENABLE) { + WARN(1, "backlight already enabled\n"); + ctl2 &= ~BLM_PWM_ENABLE; + I915_WRITE(BLC_PWM_CTL2, ctl2); + } - /* Note that this can also get called through dpms changes. And - * we don't track the backlight dpms state, hence check whether - * we have to do anything first. */ - if (tmp & BLM_PWM_ENABLE) - return; + freq = panel->backlight.max; + if (panel->backlight.combination_mode) + freq /= 0xff; - tmp &= ~BLM_PIPE_SELECT; - tmp |= BLM_PIPE(pipe); - tmp &= ~BLM_PWM_ENABLE; - - I915_WRITE(BLC_PWM_CTL2, tmp); - POSTING_READ(BLC_PWM_CTL2); - I915_WRITE(BLC_PWM_CTL2, tmp | BLM_PWM_ENABLE); + ctl = freq << 16; + I915_WRITE(BLC_PWM_CTL, ctl); + /* XXX: combine this into above write? */ intel_panel_actually_set_backlight(connector, panel->backlight.level); + + ctl2 = BLM_PIPE(pipe); + if (panel->backlight.combination_mode) + ctl2 |= BLM_COMBINATION_MODE; + if (panel->backlight.active_low_pwm) + ctl2 |= BLM_POLARITY_I965; + I915_WRITE(BLC_PWM_CTL2, ctl2); + POSTING_READ(BLC_PWM_CTL2); + I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); } static void vlv_enable_backlight(struct intel_connector *connector) @@ -799,23 +832,27 @@ static void vlv_enable_backlight(struct intel_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); - u32 tmp; + u32 ctl, ctl2; - tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe)); + ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe)); + if (ctl2 & BLM_PWM_ENABLE) { + WARN(1, "backlight already enabled\n"); + ctl2 &= ~BLM_PWM_ENABLE; + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); + } - /* Note that this can also get called through dpms changes. And - * we don't track the backlight dpms state, hence check whether - * we have to do anything first. */ - if (tmp & BLM_PWM_ENABLE) - return; - - tmp &= ~BLM_PWM_ENABLE; - - I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp); - POSTING_READ(VLV_BLC_PWM_CTL2(pipe)); - I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp | BLM_PWM_ENABLE); + ctl = panel->backlight.max << 16; + I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl); + /* XXX: combine this into above write? */ intel_panel_actually_set_backlight(connector, panel->backlight.level); + + ctl2 = 0; + if (panel->backlight.active_low_pwm) + ctl2 |= BLM_POLARITY_I965; + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); + POSTING_READ(VLV_BLC_PWM_CTL2(pipe)); + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE); } void intel_panel_enable_backlight(struct intel_connector *connector) From bc0bb9fd1c7810407ab810d204bbaecb255fddde Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 14 Nov 2013 12:14:29 +0200 Subject: [PATCH 040/595] drm/i915: remove QUIRK_NO_PCH_PWM_ENABLE The quirk was added as what I'd say was a stopgap measure in commit e85843bec6c2ea7c10ec61238396891cc2b753a9 Author: Kamal Mostafa Date: Fri Jul 19 15:02:01 2013 -0700 drm/i915: quirk no PCH_PWM_ENABLE for Dell XPS13 backlight without really digging into what was going on. Also, as mentioned in the related bug [1], having the quirk regressed some of the machines it was supposed to fix to begin with, and there were patches posted to disable the quirk on such machines [2]! The fact is, we do need the BLM_PCH_PWM_ENABLE bit set to have backlight. With the quirk, we've relied on BIOS to have set it, and our save/restore code to retain it. With the full backlight setup at enable, we have no place for things that rely on previous state. With the per platform hooks, we've also made a change in the PCH platform enable order: setting the backlight duty cycle between CPU and PCH PWM enable. Some experimenting and commit 770c12312ad617172b1a65b911d3e6564fc5aca8 Author: Takashi Iwai Date: Sat Aug 11 08:56:42 2012 +0200 drm/i915: Fix blank panel at reopening lid indicate that we can't set the backlight before enabling CPU PWM; the value just won't stick. But AFAICT we should do it before enabling the PCH PWM. Finally, any fallout we should fix properly, preferrably without quirks, and absolutely without quirks that rely on existing state. With the per platform hooks have much more flexibility to adjust the sequence as required by platforms. [1] https://bugzilla.kernel.org/show_bug.cgi?id=47941 [2] http://lkml.kernel.org/r/1378229848-29113-1-git-send-email-kamal@canonical.com Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_display.c | 16 ---------------- drivers/gpu/drm/i915/intel_panel.c | 4 ---- 3 files changed, 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c243b8e954a0..e726ab985100 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -717,7 +717,6 @@ enum intel_sbi_destination { #define QUIRK_PIPEA_FORCE (1<<0) #define QUIRK_LVDS_SSC_DISABLE (1<<1) #define QUIRK_INVERT_BRIGHTNESS (1<<2) -#define QUIRK_NO_PCH_PWM_ENABLE (1<<3) struct intel_fbdev; struct intel_fbc_work; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 25ef080d1bc2..b9f763c637ec 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10456,17 +10456,6 @@ static void quirk_invert_brightness(struct drm_device *dev) DRM_INFO("applying inverted panel brightness quirk\n"); } -/* - * Some machines (Dell XPS13) suffer broken backlight controls if - * BLM_PCH_PWM_ENABLE is set. - */ -static void quirk_no_pcm_pwm_enable(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->quirks |= QUIRK_NO_PCH_PWM_ENABLE; - DRM_INFO("applying no-PCH_PWM_ENABLE quirk\n"); -} - struct intel_quirk { int device; int subsystem_vendor; @@ -10526,11 +10515,6 @@ static struct intel_quirk intel_quirks[] = { * seem to use inverted backlight PWM. */ { 0x2a42, 0x1025, PCI_ANY_ID, quirk_invert_brightness }, - - /* Dell XPS13 HD Sandy Bridge */ - { 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable }, - /* Dell XPS13 HD and XPS13 FHD Ivy Bridge */ - { 0x0166, 0x1028, 0x058b, quirk_no_pcm_pwm_enable }, }; static void intel_init_quirks(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 0986472d4254..da088e33dd19 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -749,10 +749,6 @@ static void pch_enable_backlight(struct intel_connector *connector) pch_ctl2 = panel->backlight.max << 16; I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); - /* XXX: transitional */ - if (dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE) - return; - pch_ctl1 = 0; if (panel->backlight.active_low_pwm) pch_ctl1 |= BLM_PCH_POLARITY; From 58cad0768ca204599561bdb5509fb4ffc92603cb Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 8 Nov 2013 16:49:04 +0200 Subject: [PATCH 041/595] drm/i915: nuke get max backlight functions No longer needed. We now have fully cached max backlight values. Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_panel.c | 133 ----------------------------- 2 files changed, 134 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e726ab985100..247e922942dd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -416,7 +416,6 @@ struct drm_i915_display_funcs { /* pll clock increase/decrease */ int (*setup_backlight)(struct intel_connector *connector); - uint32_t (*get_max_backlight)(struct intel_connector *connector); uint32_t (*get_backlight)(struct intel_connector *connector); void (*set_backlight)(struct intel_connector *connector, uint32_t level); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index da088e33dd19..eadfe338dbeb 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -325,132 +325,6 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, pipe_config->gmch_pfit.lvds_border_bits = border; } -static int is_backlight_combination_mode(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (IS_GEN4(dev)) - return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; - - if (IS_GEN2(dev)) - return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; - - return 0; -} - -static u32 pch_get_max_backlight(struct intel_connector *connector) -{ - struct drm_device *dev = connector->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 val; - - val = I915_READ(BLC_PWM_PCH_CTL2); - if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) { - dev_priv->regfile.saveBLC_PWM_CTL2 = val; - } else if (val == 0) { - val = dev_priv->regfile.saveBLC_PWM_CTL2; - I915_WRITE(BLC_PWM_PCH_CTL2, val); - } - - val >>= 16; - - return val; -} - -static u32 i9xx_get_max_backlight(struct intel_connector *connector) -{ - struct drm_device *dev = connector->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 val; - - val = I915_READ(BLC_PWM_CTL); - if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { - dev_priv->regfile.saveBLC_PWM_CTL = val; - } else if (val == 0) { - val = dev_priv->regfile.saveBLC_PWM_CTL; - I915_WRITE(BLC_PWM_CTL, val); - } - - val >>= 17; - - if (is_backlight_combination_mode(dev)) - val *= 0xff; - - return val; -} - -static u32 i965_get_max_backlight(struct intel_connector *connector) -{ - struct drm_device *dev = connector->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 val; - - val = I915_READ(BLC_PWM_CTL); - if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { - dev_priv->regfile.saveBLC_PWM_CTL = val; - dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); - } else if (val == 0) { - val = dev_priv->regfile.saveBLC_PWM_CTL; - I915_WRITE(BLC_PWM_CTL, val); - I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); - } - - val >>= 16; - - if (is_backlight_combination_mode(dev)) - val *= 0xff; - - return val; -} - -static u32 _vlv_get_max_backlight(struct drm_device *dev, enum pipe pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 val; - - val = I915_READ(VLV_BLC_PWM_CTL(pipe)); - if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { - dev_priv->regfile.saveBLC_PWM_CTL = val; - dev_priv->regfile.saveBLC_PWM_CTL2 = - I915_READ(VLV_BLC_PWM_CTL2(pipe)); - } else if (val == 0) { - val = dev_priv->regfile.saveBLC_PWM_CTL; - I915_WRITE(VLV_BLC_PWM_CTL(pipe), val); - I915_WRITE(VLV_BLC_PWM_CTL2(pipe), - dev_priv->regfile.saveBLC_PWM_CTL2); - } - - if (!val) - val = 0x0f42ffff; - - val >>= 16; - - return val; -} - -static u32 vlv_get_max_backlight(struct intel_connector *connector) -{ - struct drm_device *dev = connector->base.dev; - enum pipe pipe = intel_get_pipe_from_connector(connector); - - return _vlv_get_max_backlight(dev, pipe); -} - -static u32 intel_panel_get_max_backlight(struct intel_connector *connector) -{ - struct drm_device *dev = connector->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 max; - - WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight_lock)); - - max = dev_priv->display.get_max_backlight(connector); - - DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); - - return max; -} - static int i915_panel_invert_brightness; MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " "(-1 force normal, 0 machine defaults, 1 force inversion), please " @@ -866,9 +740,6 @@ void intel_panel_enable_backlight(struct intel_connector *connector) spin_lock_irqsave(&dev_priv->backlight_lock, flags); - /* XXX: transitional, call to make sure freq is set */ - intel_panel_get_max_backlight(connector); - WARN_ON(panel->backlight.max == 0); if (panel->backlight.level == 0) { @@ -1171,28 +1042,24 @@ void intel_panel_init_backlight_funcs(struct drm_device *dev) dev_priv->display.disable_backlight = pch_disable_backlight; dev_priv->display.set_backlight = pch_set_backlight; dev_priv->display.get_backlight = pch_get_backlight; - dev_priv->display.get_max_backlight = pch_get_max_backlight; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.setup_backlight = vlv_setup_backlight; dev_priv->display.enable_backlight = vlv_enable_backlight; dev_priv->display.disable_backlight = vlv_disable_backlight; dev_priv->display.set_backlight = vlv_set_backlight; dev_priv->display.get_backlight = vlv_get_backlight; - dev_priv->display.get_max_backlight = vlv_get_max_backlight; } else if (IS_GEN4(dev)) { dev_priv->display.setup_backlight = i965_setup_backlight; dev_priv->display.enable_backlight = i965_enable_backlight; dev_priv->display.disable_backlight = i965_disable_backlight; dev_priv->display.set_backlight = i9xx_set_backlight; dev_priv->display.get_backlight = i9xx_get_backlight; - dev_priv->display.get_max_backlight = i965_get_max_backlight; } else { dev_priv->display.setup_backlight = i9xx_setup_backlight; dev_priv->display.enable_backlight = i9xx_enable_backlight; dev_priv->display.disable_backlight = i9xx_disable_backlight; dev_priv->display.set_backlight = i9xx_set_backlight; dev_priv->display.get_backlight = i9xx_get_backlight; - dev_priv->display.get_max_backlight = i9xx_get_max_backlight; } } From 565ee3897f0cb1e9b09905747b3784e6605767e8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 13 Nov 2013 12:56:29 +0200 Subject: [PATCH 042/595] drm/i915: do not save/restore backlight registers in KMS The backlight enable code now has the smarts to do the right thing. Only do backlight register save/restore in UMS. Some VLV specific code gets dropped as UMS is not supported on VLV. v2: Move save/restore to UMS instead of removing completely (Daniel). Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/i915_suspend.c | 45 ----------------------------- drivers/gpu/drm/i915/i915_ums.c | 27 +++++++++++++++++ 3 files changed, 27 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 247e922942dd..d069f6ba4286 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -768,8 +768,6 @@ struct i915_suspend_saved_registers { u32 saveBLC_PWM_CTL; u32 saveBLC_PWM_CTL2; u32 saveBLC_HIST_CTL_B; - u32 saveBLC_PWM_CTL_B; - u32 saveBLC_PWM_CTL2_B; u32 saveBLC_CPU_PWM_CTL; u32 saveBLC_CPU_PWM_CTL2; u32 saveFPB0; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index eadf8e19d2c4..6b8fef7fb3bb 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -192,7 +192,6 @@ static void i915_restore_vga(struct drm_device *dev) static void i915_save_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long flags; /* Display arbitration control */ if (INTEL_INFO(dev)->gen <= 4) @@ -203,46 +202,27 @@ static void i915_save_display(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_save_display_reg(dev); - spin_lock_irqsave(&dev_priv->backlight_lock, flags); - /* LVDS state */ if (HAS_PCH_SPLIT(dev)) { dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL); - dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); - dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); - dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL); - dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2); if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); } else if (IS_VALLEYVIEW(dev)) { dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); - dev_priv->regfile.saveBLC_PWM_CTL = - I915_READ(VLV_BLC_PWM_CTL(PIPE_A)); dev_priv->regfile.saveBLC_HIST_CTL = I915_READ(VLV_BLC_HIST_CTL(PIPE_A)); - dev_priv->regfile.saveBLC_PWM_CTL2 = - I915_READ(VLV_BLC_PWM_CTL2(PIPE_A)); - dev_priv->regfile.saveBLC_PWM_CTL_B = - I915_READ(VLV_BLC_PWM_CTL(PIPE_B)); dev_priv->regfile.saveBLC_HIST_CTL_B = I915_READ(VLV_BLC_HIST_CTL(PIPE_B)); - dev_priv->regfile.saveBLC_PWM_CTL2_B = - I915_READ(VLV_BLC_PWM_CTL2(PIPE_B)); } else { dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); - dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); dev_priv->regfile.saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL); - if (INTEL_INFO(dev)->gen >= 4) - dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); if (IS_MOBILE(dev) && !IS_I830(dev)) dev_priv->regfile.saveLVDS = I915_READ(LVDS); } - spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); - if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL); @@ -278,7 +258,6 @@ static void i915_restore_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 mask = 0xffffffff; - unsigned long flags; /* Display arbitration */ if (INTEL_INFO(dev)->gen <= 4) @@ -287,12 +266,6 @@ static void i915_restore_display(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_restore_display_reg(dev); - spin_lock_irqsave(&dev_priv->backlight_lock, flags); - - /* LVDS state */ - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); - if (drm_core_check_feature(dev, DRIVER_MODESET)) mask = ~LVDS_PORT_EN; @@ -305,13 +278,6 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL); if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL); - I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); - /* NOTE: BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2; - * otherwise we get blank eDP screen after S3 on some machines - */ - I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->regfile.saveBLC_CPU_PWM_CTL2); - I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->regfile.saveBLC_CPU_PWM_CTL); I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR); @@ -319,21 +285,12 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(RSTDBYCTL, dev_priv->regfile.saveMCHBAR_RENDER_STANDBY); } else if (IS_VALLEYVIEW(dev)) { - I915_WRITE(VLV_BLC_PWM_CTL(PIPE_A), - dev_priv->regfile.saveBLC_PWM_CTL); I915_WRITE(VLV_BLC_HIST_CTL(PIPE_A), dev_priv->regfile.saveBLC_HIST_CTL); - I915_WRITE(VLV_BLC_PWM_CTL2(PIPE_A), - dev_priv->regfile.saveBLC_PWM_CTL2); - I915_WRITE(VLV_BLC_PWM_CTL(PIPE_B), - dev_priv->regfile.saveBLC_PWM_CTL); I915_WRITE(VLV_BLC_HIST_CTL(PIPE_B), dev_priv->regfile.saveBLC_HIST_CTL); - I915_WRITE(VLV_BLC_PWM_CTL2(PIPE_B), - dev_priv->regfile.saveBLC_PWM_CTL2); } else { I915_WRITE(PFIT_PGM_RATIOS, dev_priv->regfile.savePFIT_PGM_RATIOS); - I915_WRITE(BLC_PWM_CTL, dev_priv->regfile.saveBLC_PWM_CTL); I915_WRITE(BLC_HIST_CTL, dev_priv->regfile.saveBLC_HIST_CTL); I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); @@ -341,8 +298,6 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); } - spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); - /* only restore FBC info on the platform that supports FBC*/ intel_disable_fbc(dev); if (I915_HAS_FBC(dev)) { diff --git a/drivers/gpu/drm/i915/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c index 967da4772c44..caa18e855815 100644 --- a/drivers/gpu/drm/i915/i915_ums.c +++ b/drivers/gpu/drm/i915/i915_ums.c @@ -270,6 +270,18 @@ void i915_save_display_reg(struct drm_device *dev) } /* FIXME: regfile.save TV & SDVO state */ + /* Backlight */ + if (HAS_PCH_SPLIT(dev)) { + dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); + dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); + dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL); + dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2); + } else { + dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + if (INTEL_INFO(dev)->gen >= 4) + dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); + } + return; } @@ -280,6 +292,21 @@ void i915_restore_display_reg(struct drm_device *dev) int dpll_b_reg, fpb0_reg, fpb1_reg; int i; + /* Backlight */ + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL); + I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); + /* NOTE: BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2; + * otherwise we get blank eDP screen after S3 on some machines + */ + I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->regfile.saveBLC_CPU_PWM_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->regfile.saveBLC_CPU_PWM_CTL); + } else { + if (INTEL_INFO(dev)->gen >= 4) + I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); + I915_WRITE(BLC_PWM_CTL, dev_priv->regfile.saveBLC_PWM_CTL); + } + /* Display port ratios (must be done before clock is set) */ if (SUPPORTS_INTEGRATED_DP(dev)) { I915_WRITE(_PIPEA_DATA_M_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_M); From b378360e8fa4a2f21960747f194c1c7c1f3ae7f9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 14 Nov 2013 11:30:42 +0100 Subject: [PATCH 043/595] drm/i915: Use for_each_pipe in intel_display_crc_init We have a nice macro, so use it. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 1dbcc64f9ddb..8362dc154af4 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3014,10 +3014,10 @@ static struct i915_debugfs_files { void intel_display_crc_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int i; + enum pipe pipe; - for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { - struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[i]; + for_each_pipe(pipe) { + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; pipe_crc->opened = false; spin_lock_init(&pipe_crc->lock); From 7eb1c496f7ac0f386552c0cd9144f6965fc61da5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 14 Nov 2013 11:30:43 +0100 Subject: [PATCH 044/595] drm/i915: Reject opening of pipe crc files for invalid pipes We don't init the lock nor set up all the other state. And it doesn't make sense anyway. This appeases lockdep when running the igt/drv_debugfs_reader test. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 8362dc154af4..506f8efeb519 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1771,6 +1771,9 @@ static int i915_pipe_crc_open(struct inode *inode, struct file *filep) struct drm_i915_private *dev_priv = info->dev->dev_private; struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; + if (info->pipe >= INTEL_INFO(info->dev)->num_pipes) + return -ENODEV; + spin_lock_irq(&pipe_crc->lock); if (pipe_crc->opened) { From 4aeebd7443e36b0a40032e518a9338f48bd27efc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 31 Oct 2013 09:53:36 +0100 Subject: [PATCH 045/595] drm/i915: dp aux irq support for g4x/vlv Now we have this everywhere. Next up would be to wire up the DP hotplug pin to speed up panel power sequencing for eDP panels ... I've decided to leave the has_aux_irq logic in the code, it should come handy for hw bringup. For testing/fail-safety the dp aux code already has a timeout when waiting for interrupts to signal completion and screams rather loud if they don't arrive in time. Given that we need a real piece of hw to talk to anyway this is probably as good as it gets. v2: Don't check the dp aux channel bits on i965 machines, they have a different meaning there. Yay for reusing bits at will! Spotted by Jani. Cc: Jani Nikula Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 7 +++++++ drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_dp.c | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 931ee5d8cdb1..271560080ad5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1472,6 +1472,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); + if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) + dp_aux_irq_handler(dev); + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } @@ -3653,6 +3656,10 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) intel_hpd_irq_handler(dev, hotplug_trigger, IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915); + if (IS_G4X(dev) && + (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)) + dp_aux_irq_handler(dev); + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 849e595ed19d..04d46b23d97c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2131,6 +2131,10 @@ #define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) #define CRT_HOTPLUG_MONITOR_MONO (2 << 8) #define CRT_HOTPLUG_MONITOR_NONE (0 << 8) +#define DP_AUX_CHANNEL_D_INT_STATUS_G4X (1 << 6) +#define DP_AUX_CHANNEL_C_INT_STATUS_G4X (1 << 5) +#define DP_AUX_CHANNEL_B_INT_STATUS_G4X (1 << 4) +#define DP_AUX_CHANNEL_MASK_INT_STATUS_G4X (1 << 4) /* SDVO is different across gen3/4 */ #define SDVOC_HOTPLUG_INT_STATUS_G4X (1 << 3) #define SDVOB_HOTPLUG_INT_STATUS_G4X (1 << 2) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index dbe4840d6fb8..3b22e726585e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -404,7 +404,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, int i, ret, recv_bytes; uint32_t status; int try, precharge, clock = 0; - bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev); + bool has_aux_irq = true; uint32_t timeout; /* dp aux is extremely sensitive to irq latency, hence request the From 0694001b27efe5878ba5bd273e39b384821d865e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 30 Oct 2013 18:27:43 -0200 Subject: [PATCH 046/595] drm/i915: reuse WRPLL when possible It seems we do have machines with 3 HDMI/DVI outputs, so sharing WRPLLs is the only way to get 3 pipes working. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=68485 Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 51 ++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 1591576a6101..e5eecfd5e47c 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -713,8 +713,6 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) uint32_t reg, val; int clock = intel_crtc->config.port_clock; - /* TODO: reuse PLLs when possible (compare values) */ - intel_ddi_put_crtc_pll(crtc); if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { @@ -742,32 +740,41 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) } else if (type == INTEL_OUTPUT_HDMI) { unsigned p, n2, r2; - if (plls->wrpll1_refcount == 0) { - DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n", - pipe_name(pipe)); - plls->wrpll1_refcount++; - reg = WRPLL_CTL1; - intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1; - } else if (plls->wrpll2_refcount == 0) { - DRM_DEBUG_KMS("Using WRPLL 2 on pipe %c\n", - pipe_name(pipe)); - plls->wrpll2_refcount++; - reg = WRPLL_CTL2; - intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2; - } else { - DRM_ERROR("No WRPLLs available!\n"); - return false; - } - - WARN(I915_READ(reg) & WRPLL_PLL_ENABLE, - "WRPLL already enabled\n"); - intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | WRPLL_DIVIDER_POST(p); + if (val == I915_READ(WRPLL_CTL1)) { + DRM_DEBUG_KMS("Reusing WRPLL 1 on pipe %c\n", + pipe_name(pipe)); + reg = WRPLL_CTL1; + } else if (val == I915_READ(WRPLL_CTL2)) { + DRM_DEBUG_KMS("Reusing WRPLL 2 on pipe %c\n", + pipe_name(pipe)); + reg = WRPLL_CTL2; + } else if (plls->wrpll1_refcount == 0) { + DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n", + pipe_name(pipe)); + reg = WRPLL_CTL1; + } else if (plls->wrpll2_refcount == 0) { + DRM_DEBUG_KMS("Using WRPLL 2 on pipe %c\n", + pipe_name(pipe)); + reg = WRPLL_CTL2; + } else { + DRM_ERROR("No WRPLLs available!\n"); + return false; + } + + if (reg == WRPLL_CTL1) { + plls->wrpll1_refcount++; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1; + } else { + plls->wrpll2_refcount++; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2; + } + } else if (type == INTEL_OUTPUT_ANALOG) { if (plls->spll_refcount == 0) { DRM_DEBUG_KMS("Using SPLL on pipe %c\n", From f671d117bc0338b67b0a7485882d332fe6c4b570 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 16 Nov 2013 16:02:04 +0100 Subject: [PATCH 047/595] drm/i915: remove intel_uncore_clear_errors This was forgotten in commit 9d1cb9147dbe45f6e94dc796518ecf67cb64b359 Author: Paulo Zanoni Date: Fri Nov 1 13:32:08 2013 -0200 drm/i915: avoid unclaimed registers when capturing the error state Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_uncore.c | 9 --------- 2 files changed, 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6b96e91c6f1a..18ff544670d8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1920,7 +1920,6 @@ extern void intel_pm_init(struct drm_device *dev); extern void intel_uncore_sanitize(struct drm_device *dev); extern void intel_uncore_early_sanitize(struct drm_device *dev); extern void intel_uncore_init(struct drm_device *dev); -extern void intel_uncore_clear_errors(struct drm_device *dev); extern void intel_uncore_check_errors(struct drm_device *dev); extern void intel_uncore_fini(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 5103d80fc3ae..07c0ad0e1583 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -828,15 +828,6 @@ int intel_gpu_reset(struct drm_device *dev) } } -void intel_uncore_clear_errors(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* XXX needs spinlock around caller's grouping */ - if (HAS_FPGA_DBG_UNCLAIMED(dev)) - __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM); -} - void intel_uncore_check_errors(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; From 9688ecadd268770834cca72ac81c9aec8fb8cf2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Nov 2013 23:02:19 +0200 Subject: [PATCH 048/595] drm/i915: Limit FBC flush to post batch flush MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't issue the FBC nuke/cache clean command when invalidate_domains!=0. That would indicate that we're not being called for the post-batch flush. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c2f09d456300..e26e18a1d916 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -354,7 +354,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, 0); intel_ring_advance(ring); - if (flush_domains) + if (!invalidate_domains && flush_domains) return gen7_ring_fbc_flush(ring, FBC_REND_NUKE); return 0; @@ -1838,7 +1838,7 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring, } intel_ring_advance(ring); - if (IS_GEN7(dev) && flush) + if (IS_GEN7(dev) && !invalidate && flush) return gen7_ring_fbc_flush(ring, FBC_REND_CACHE_CLEAN); return 0; From 37c1d94fa83482c308f14ec671910278e8647934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Nov 2013 23:02:20 +0200 Subject: [PATCH 049/595] drm/i915: Emit SRM after the MSG_FBC_REND_STATE LRI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec tells us that we need to emit an SRM after the LRI to MSG_FBC_REND_STATE. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 04d46b23d97c..1777bebc664b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -235,6 +235,7 @@ */ #define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*x-1) #define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*x-1) +#define MI_SRM_LRM_GLOBAL_GTT (1<<22) #define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ #define MI_FLUSH_DW_STORE_INDEX (1<<21) #define MI_INVALIDATE_TLB (1<<18) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e26e18a1d916..b65f4d77e3ed 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -285,14 +285,16 @@ static int gen7_ring_fbc_flush(struct intel_ring_buffer *ring, u32 value) if (!ring->fbc_dirty) return 0; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(ring, 6); if (ret) return ret; - intel_ring_emit(ring, MI_NOOP); /* WaFbcNukeOn3DBlt:ivb/hsw */ intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); intel_ring_emit(ring, MSG_FBC_REND_STATE); intel_ring_emit(ring, value); + intel_ring_emit(ring, MI_STORE_REGISTER_MEM(1) | MI_SRM_LRM_GLOBAL_GTT); + intel_ring_emit(ring, MSG_FBC_REND_STATE); + intel_ring_emit(ring, ring->scratch.gtt_offset + 256); intel_ring_advance(ring); ring->fbc_dirty = false; From cbaef0f173c7c8bb14976f3928e5876efec444e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Nov 2013 23:02:24 +0200 Subject: [PATCH 050/595] drm/i915: Set has_fbc=true for all SNB+, except VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least since SNB (perhaps even earlier) even the desktop parts should have FBC. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c2e00ed23195..583adcbef5e4 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -264,6 +264,7 @@ static const struct intel_device_info intel_ironlake_m_info = { static const struct intel_device_info intel_sandybridge_d_info = { .gen = 6, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, + .has_fbc = 1, .ring_mask = RENDER_RING | BSD_RING | BLT_RING, .has_llc = 1, }; @@ -279,6 +280,7 @@ static const struct intel_device_info intel_sandybridge_m_info = { #define GEN7_FEATURES \ .gen = 7, .num_pipes = 3, \ .need_gfx_hws = 1, .has_hotplug = 1, \ + .has_fbc = 1, \ .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \ .has_llc = 1 @@ -291,7 +293,6 @@ static const struct intel_device_info intel_ivybridge_m_info = { GEN7_FEATURES, .is_ivybridge = 1, .is_mobile = 1, - .has_fbc = 1, }; static const struct intel_device_info intel_ivybridge_q_info = { @@ -306,6 +307,7 @@ static const struct intel_device_info intel_valleyview_m_info = { .num_pipes = 2, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, + .has_fbc = 0, /* legal, last one wins */ .has_llc = 0, /* legal, last one wins */ }; @@ -314,6 +316,7 @@ static const struct intel_device_info intel_valleyview_d_info = { .num_pipes = 2, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, + .has_fbc = 0, /* legal, last one wins */ .has_llc = 0, /* legal, last one wins */ }; @@ -331,7 +334,6 @@ static const struct intel_device_info intel_haswell_m_info = { .is_mobile = 1, .has_ddi = 1, .has_fpga_dbg = 1, - .has_fbc = 1, .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, }; From b19870ee67ad8b552db0e7456a8d1d33f96421c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Nov 2013 23:02:25 +0200 Subject: [PATCH 051/595] drm/i915: Use plane_name() in gen7_enable_fbc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the other .enable_fbc() funcs use plane_name(). Make gen7_enable_fbc() do the same. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 172efa0bfb86..0fcd591b0a4b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -295,7 +295,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) sandybridge_blit_fbc_update(dev); - DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); } bool intel_fbc_enabled(struct drm_device *dev) From 4ea67bc700c0c085e0428b6cb75071ec8c858f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 18 Nov 2013 18:32:38 -0800 Subject: [PATCH 052/595] drm/i915: Enable pipe gamma for sprites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We send the primary and cursor plane data through the gamma unit. In order to get matching output from sprites, also send the sprite data through the gamma unit. In the future we should add some properties to control this explicitly, and also add properties for the per-sprite gamma ramps what have you, but for now this seems like a reasonable thing to do. Signed-off-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 +- drivers/gpu/drm/i915/intel_sprite.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1777bebc664b..f2104f5e3af7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3793,7 +3793,7 @@ #define _SPACNTR (VLV_DISPLAY_BASE + 0x72180) #define SP_ENABLE (1<<31) -#define SP_GEAMMA_ENABLE (1<<30) +#define SP_GAMMA_ENABLE (1<<30) #define SP_PIXFORMAT_MASK (0xf<<26) #define SP_FORMAT_YUV422 (0<<26) #define SP_FORMAT_BGR565 (5<<26) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index b9fabf826f7d..90a3f6db8288 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -104,6 +104,12 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, break; } + /* + * Enable gamma to match primary/cursor plane behaviour. + * FIXME should be user controllable via propertiesa. + */ + sprctl |= SP_GAMMA_ENABLE; + if (obj->tiling_mode != I915_TILING_NONE) sprctl |= SP_TILED; @@ -257,6 +263,12 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, BUG(); } + /* + * Enable gamma to match primary/cursor plane behaviour. + * FIXME should be user controllable via propertiesa. + */ + sprctl |= SPRITE_GAMMA_ENABLE; + if (obj->tiling_mode != I915_TILING_NONE) sprctl |= SPRITE_TILED; @@ -453,6 +465,12 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, BUG(); } + /* + * Enable gamma to match primary/cursor plane behaviour. + * FIXME should be user controllable via propertiesa. + */ + dvscntr |= DVS_GAMMA_ENABLE; + if (obj->tiling_mode != I915_TILING_NONE) dvscntr |= DVS_TILED; From 3458122e27fd381411e0cd4c45c28816fcffbe20 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 18 Nov 2013 18:32:36 -0800 Subject: [PATCH 053/595] drm/i915: Hold pc8 lock around toggling pc8.gpu_idle We need to hold the pc8 lock around toggling the value of gpu_idle. Signed-off-by: Chris Wilson Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3b7f1c4eb48e..54e7fa6d9628 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6761,18 +6761,22 @@ static void hsw_update_package_c8(struct drm_device *dev) static void hsw_package_c8_gpu_idle(struct drm_i915_private *dev_priv) { + mutex_lock(&dev_priv->pc8.lock); if (!dev_priv->pc8.gpu_idle) { dev_priv->pc8.gpu_idle = true; - hsw_enable_package_c8(dev_priv); + __hsw_enable_package_c8(dev_priv); } + mutex_unlock(&dev_priv->pc8.lock); } static void hsw_package_c8_gpu_busy(struct drm_i915_private *dev_priv) { + mutex_lock(&dev_priv->pc8.lock); if (dev_priv->pc8.gpu_idle) { dev_priv->pc8.gpu_idle = false; - hsw_disable_package_c8(dev_priv); + __hsw_disable_package_c8(dev_priv); } + mutex_unlock(&dev_priv->pc8.lock); } #define for_each_power_domain(domain, mask) \ From 432f3342e0fc4d5601b2168fe251f9219bdc97d3 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 21 Nov 2013 16:49:46 +0100 Subject: [PATCH 054/595] i915, debugfs: Fix uninitialized warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc complains that: drivers/gpu/drm/i915/i915_debugfs.c: In function ‘display_crc_ctl_write’: drivers/gpu/drm/i915/i915_debugfs.c:2393:2: warning: ‘val’ may be used uninitialized in this function [-Wuninitialized] drivers/gpu/drm/i915/i915_debugfs.c:2350:6: note: ‘val’ was declared here but it can't see that we're going to use val only in the success case. So shut it up. Cc: Daniel Vetter Cc: David Airlie Cc: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Signed-off-by: Borislav Petkov Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d1491f8e0f39..97c304ea4760 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2349,7 +2349,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; - u32 val; + u32 val = 0; /* shut up gcc */ int ret; if (pipe_crc->source == source) From 6605782f79ccb3b840e302079770d24f2c1be96e Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 21 Nov 2013 15:29:55 +0100 Subject: [PATCH 055/595] i915, fbdev: Fix Kconfig typo Too many t's. Cc: Daniel Vetter Cc: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Signed-off-by: Borislav Petkov Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index b0fa4c4055ee..73ed59eff139 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -44,7 +44,7 @@ config DRM_I915_KMS If in doubt, say "Y". config DRM_I915_FBDEV - bool "Enable legacy fbdev support for the modesettting intel driver" + bool "Enable legacy fbdev support for the modesetting intel driver" depends on DRM_I915 select DRM_KMS_FB_HELPER select FB_CFB_FILLRECT From b33ecdd1cdeb90ca07dd28d648558e87c8680443 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 15 Nov 2013 17:16:33 +0100 Subject: [PATCH 056/595] drm/i915: Fix module unloading with DRM_I915_UMS=n Oops, makes testing early boot failures in i915.ko a bit more pain, so let's fix it. v2: We already have a bit of static storage to track this (Chris). Reviewed-by: Paulo Zanoni Tested-by: Paulo Zanoni Cc: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 583adcbef5e4..804a139901a2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1022,6 +1022,11 @@ static int __init i915_init(void) static void __exit i915_exit(void) { +#ifndef CONFIG_DRM_I915_UMS + if (!(driver.driver_features & DRIVER_MODESET)) + return; /* Never loaded a driver. */ +#endif + drm_pci_exit(&driver, &i915_pci_driver); } From d629336b6af9ff214e9d1e7224946a000fc8f70f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 21 Nov 2013 21:29:45 +0200 Subject: [PATCH 057/595] drm/i915: Don't set the fence number in DPFC_CTL on SNB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SNB has another register where the actual FBC CPU fence number is stored. The documenation explicitly states that the fence number in DPFC_CTL must be 0 on SNB. And in fact when it's not zero, the GTT tracking simply doesn't work. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0fcd591b0a4b..de4cf565ec4c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -222,7 +222,9 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); /* Set persistent mode for front-buffer rendering, ala X. */ dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE; - dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg); + dpfc_ctl |= DPFC_CTL_FENCE_EN; + if (IS_GEN5(dev)) + dpfc_ctl |= obj->fence_reg; I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | From d595bd4bbd853106e3926176fa8a677963337d38 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 25 Nov 2013 09:54:32 -0800 Subject: [PATCH 058/595] drm/i915: Fix BDW PPGTT error path When we fail for some reason on loading the PDPs, it would be wise to disable the PPGTT in the ring registers. If we do not do this, we have undefined results. Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index efb5dab61c81..1a5272c172c8 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -238,10 +238,16 @@ static int gen8_ppgtt_enable(struct drm_device *dev) for_each_ring(ring, dev_priv, j) { ret = gen8_write_pdp(ring, i, addr); if (ret) - return ret; + goto err_out; } } return 0; + +err_out: + for_each_ring(ring, dev_priv, j) + I915_WRITE(RING_MODE_GEN7(ring), + _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE)); + return ret; } static void gen8_ppgtt_clear_range(struct i915_address_space *vm, From 686e1f6f87985bc05d38d90d483f3765d47780cc Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 25 Nov 2013 09:54:34 -0800 Subject: [PATCH 059/595] drm/i915: Add a few missed bits to the mm This should really have been added in BDW integration, as well as: commit 93bd8649dba3155d1a0ba2a902d9c49f1c75a1da Author: Ben Widawsky Date: Tue Jul 16 16:50:06 2013 -0700 drm/i915: Put the mm in the parent address space It didn't really matter before, but it will in the future. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 1a5272c172c8..c1d04a36688f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -322,6 +322,8 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) container_of(vm, struct i915_hw_ppgtt, base); int i, j; + drm_mm_takedown(&vm->mm); + for (i = 0; i < ppgtt->num_pd_pages ; i++) { if (ppgtt->pd_dma_addr[i]) { pci_unmap_page(ppgtt->base.dev->pdev, @@ -385,6 +387,8 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size) ppgtt->base.clear_range = gen8_ppgtt_clear_range; ppgtt->base.insert_entries = gen8_ppgtt_insert_entries; ppgtt->base.cleanup = gen8_ppgtt_cleanup; + ppgtt->base.start = 0; + ppgtt->base.total = ppgtt->num_pt_pages * GEN8_PTES_PER_PAGE * PAGE_SIZE; BUG_ON(ppgtt->num_pd_pages > GEN8_LEGACY_PDPS); @@ -636,6 +640,8 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; ppgtt->base.cleanup = gen6_ppgtt_cleanup; ppgtt->base.scratch = dev_priv->gtt.base.scratch; + ppgtt->base.start = 0; + ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE; ppgtt->pt_pages = kcalloc(ppgtt->num_pd_entries, sizeof(struct page *), GFP_KERNEL); if (!ppgtt->pt_pages) From ad52546e4336661c21b5ae927d8a9349e4a930cd Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 25 Nov 2013 09:54:36 -0800 Subject: [PATCH 060/595] drm/i915: Disallow dynamic ppgtt param modification This would have never worked. Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 804a139901a2..13076db65eb9 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -114,7 +114,7 @@ MODULE_PARM_DESC(enable_hangcheck, "(default: true)"); int i915_enable_ppgtt __read_mostly = -1; -module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0600); +module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0400); MODULE_PARM_DESC(i915_enable_ppgtt, "Enable PPGTT (default: true)"); From 2f9fe5ff3e1f450f6ea7771d1d2645b522116c68 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 25 Nov 2013 09:54:37 -0800 Subject: [PATCH 061/595] drm/i915: Demote drop_caches_set print Many tests call this ad naseum now (in an infinite loop, very often). It clutters the logs. Actually, I'd rather drop it completely... Cc: Daniel Vetter Cc: Chris Wilson Signed-off-by: Ben Widawsky Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 97c304ea4760..ee4d46593aae 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2744,7 +2744,7 @@ i915_drop_caches_set(void *data, u64 val) struct i915_vma *vma, *x; int ret; - DRM_DEBUG_DRIVER("Dropping caches: 0x%08llx\n", val); + DRM_DEBUG("Dropping caches: 0x%08llx\n", val); /* No need to check and wait for gpu resets, only libdrm auto-restarts * on ioctls on -EAGAIN. */ From 17601cbc93bd8ee07181ac3e4456c86e94336990 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 25 Nov 2013 09:54:38 -0800 Subject: [PATCH 062/595] drm/i915: Removed unused vm args i915_gem_execbuffer_relocate became defunct in: commit 27173f1f95db5e74ceb35fe9a2f2f348ea11bac9 Author: Ben Widawsky Date: Wed Aug 14 11:38:36 2013 +0200 drm/i915: Convert execbuf code to use vmas eb_create: never used? Signed-off-by: Ben Widawsky [danvet: The lingering vm parameter to eb_create might have been back from the days where we didn't yet keep both vmas and obj lists in the eb struct. But I didn't check really.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 885d595e0e02..740fc1da7f17 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -43,7 +43,7 @@ struct eb_vmas { }; static struct eb_vmas * -eb_create(struct drm_i915_gem_execbuffer2 *args, struct i915_address_space *vm) +eb_create(struct drm_i915_gem_execbuffer2 *args) { struct eb_vmas *eb = NULL; @@ -454,8 +454,7 @@ i915_gem_execbuffer_relocate_vma_slow(struct i915_vma *vma, } static int -i915_gem_execbuffer_relocate(struct eb_vmas *eb, - struct i915_address_space *vm) +i915_gem_execbuffer_relocate(struct eb_vmas *eb) { struct i915_vma *vma; int ret = 0; @@ -1102,7 +1101,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } - eb = eb_create(args, vm); + eb = eb_create(args); if (eb == NULL) { mutex_unlock(&dev->struct_mutex); ret = -ENOMEM; @@ -1125,7 +1124,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* The objects are in their final locations, apply the relocations. */ if (need_relocs) - ret = i915_gem_execbuffer_relocate(eb, vm); + ret = i915_gem_execbuffer_relocate(eb); if (ret) { if (ret == -EFAULT) { ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, From 2f88542607adcfe71e2d1fb6f134635e06f5d392 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 25 Nov 2013 09:54:39 -0800 Subject: [PATCH 063/595] drm/i915: Remove defunct ctx switch comments Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 2ec122a63406..41877045a1a0 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -492,8 +492,6 @@ static int do_switch(struct i915_hw_context *to) * @ring: ring for which we'll execute the context switch * @file_priv: file_priv associated with the context, may be NULL * @id: context id number - * @seqno: sequence number by which the new context will be switched to - * @flags: * * The context life cycle is simple. The context refcount is incremented and * decremented by 1 and create and destroy. If the context is in use by the GPU, From 5ce097254e71cd727687800bf15ca7af23a6bf08 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 25 Nov 2013 09:54:40 -0800 Subject: [PATCH 064/595] drm/i915: Missed dropped VMA conversion This belonged in commit 07fe0b12800d4752d729d4122c01f41f80a5ba5a Author: Ben Widawsky Date: Wed Jul 31 17:00:10 2013 -0700 drm/i915: plumb VM into bind/unbind code But it was somehow missed along the way. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 740fc1da7f17..b800fe449530 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -307,7 +307,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, target_i915_obj = target_vma->obj; target_obj = &target_vma->obj->base; - target_offset = i915_gem_obj_ggtt_offset(target_i915_obj); + target_offset = target_vma->node.start; /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and * pipe_control writes because the gpu doesn't properly redirect them From 5ed1678206a392ac509cd1f6415df74b9008aa9a Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 25 Nov 2013 09:54:43 -0800 Subject: [PATCH 065/595] drm/i915: Move the gtt mm takedown to cleanup Our VM code already has a cleanup function, and this is a nice place to put the drm_mm_takedown. This should have no functional impact, it just leaves the unload function a bit cleaer, and is more logical IMO Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 - drivers/gpu/drm/i915/i915_gem_gtt.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 25acbb5eca6e..5aeb103eae44 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1777,7 +1777,6 @@ int i915_driver_unload(struct drm_device *dev) list_del(&dev_priv->gtt.base.global_link); WARN_ON(!list_empty(&dev_priv->vm_list)); - drm_mm_takedown(&dev_priv->gtt.base.mm); drm_vblank_cleanup(dev); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index c1d04a36688f..056f1f0e2772 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1411,6 +1411,8 @@ static void gen6_gmch_remove(struct i915_address_space *vm) { struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base); + + drm_mm_takedown(&vm->mm); iounmap(gtt->gsm); teardown_scratch_page(vm->dev); } From 67e5871be82fec1451801d448b51d9a403d1ffac Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 22 Nov 2013 20:35:24 +0000 Subject: [PATCH 066/595] drm/i915: Drop forcewake w/a for missed interrupts/seqno on Sandybridge I believe, and an evening of i-g-t, that our original workaround for the missed interrupts on Sandybridge, that of holding forcewake whilst we wait for an interrupts, is no longer required. This leaves us dependent on the second workaround of forcing an UC read of the ACTHD before reading back the seqno from the snooped HWS. Dropping the forcewake should allow us to conserve a little power, not much as the GPU is meant to be busy whilst we wait for it! Cc: Jesse Barnes Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b65f4d77e3ed..69589e4f957f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1032,11 +1032,6 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring) if (!dev->irq_enabled) return false; - /* It looks like we need to prevent the gt from suspending while waiting - * for an notifiy irq, otherwise irqs seem to get lost on at least the - * blt/bsd rings on ivb. */ - gen6_gt_force_wake_get(dev_priv); - spin_lock_irqsave(&dev_priv->irq_lock, flags); if (ring->irq_refcount++ == 0) { if (HAS_L3_DPF(dev) && ring->id == RCS) @@ -1068,8 +1063,6 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) ilk_disable_gt_irq(dev_priv, ring->irq_enable_mask); } spin_unlock_irqrestore(&dev_priv->irq_lock, flags); - - gen6_gt_force_wake_put(dev_priv); } static bool From 8b4f49e03901e82898540bd1189333edf9588d74 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 25 Nov 2013 15:51:16 -0800 Subject: [PATCH 067/595] drm/i915: split fb allocation and initialization v2 If we use a stolen buffer, our probe callback shouldn't allocate a new buffer; we should re-use the one from the BIOS instead if possible. v2: fix locking (Jesse) Reviewed-by: Chris Wilson Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 62 ++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 895fcb4fbd94..fdb6dc92a7ab 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -57,18 +57,14 @@ static struct fb_ops intelfb_ops = { .fb_debug_leave = drm_fb_helper_debug_leave, }; -static int intelfb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) +static int intelfb_alloc(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) { struct intel_fbdev *ifbdev = container_of(helper, struct intel_fbdev, helper); struct drm_device *dev = helper->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct fb_info *info; - struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_i915_gem_object *obj; - struct device *device = &dev->pdev->dev; int size, ret; /* we don't do packed 24bpp */ @@ -94,8 +90,6 @@ static int intelfb_create(struct drm_fb_helper *helper, goto out; } - mutex_lock(&dev->struct_mutex); - /* Flush everything out, we'll be doing GTT only from now on */ ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); if (ret) { @@ -103,7 +97,49 @@ static int intelfb_create(struct drm_fb_helper *helper, goto out_unref; } - info = framebuffer_alloc(0, device); + ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); + if (ret) + goto out_unpin; + + return 0; + +out_unpin: + i915_gem_object_unpin(obj); +out_unref: + drm_gem_object_unreference(&obj->base); +out: + return ret; +} + +static int intelfb_create(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct intel_fbdev *ifbdev = + container_of(helper, struct intel_fbdev, helper); + struct intel_framebuffer *intel_fb = &ifbdev->ifb; + struct drm_device *dev = helper->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct fb_info *info; + struct drm_framebuffer *fb; + struct drm_i915_gem_object *obj; + int size, ret; + + mutex_lock(&dev->struct_mutex); + + if (!intel_fb->obj) { + DRM_ERROR("no BIOS fb, allocating a new one\n"); + ret = intelfb_alloc(helper, sizes); + if (ret) + goto out_unlock; + } else { + sizes->fb_width = intel_fb->base.width; + sizes->fb_height = intel_fb->base.height; + } + + obj = intel_fb->obj; + size = obj->base.size; + + info = framebuffer_alloc(0, &dev->pdev->dev); if (!info) { ret = -ENOMEM; goto out_unpin; @@ -111,10 +147,6 @@ static int intelfb_create(struct drm_fb_helper *helper, info->par = helper; - ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); - if (ret) - goto out_unpin; - fb = &ifbdev->ifb.base; ifbdev->helper.fb = fb; @@ -170,17 +202,15 @@ static int intelfb_create(struct drm_fb_helper *helper, fb->width, fb->height, i915_gem_obj_ggtt_offset(obj), obj); - mutex_unlock(&dev->struct_mutex); vga_switcheroo_client_fb_set(dev->pdev, info); return 0; out_unpin: i915_gem_object_unpin(obj); -out_unref: drm_gem_object_unreference(&obj->base); +out_unlock: mutex_unlock(&dev->struct_mutex); -out: return ret; } From fbeeaa2306fcff7614c8b41b420a400503b6d28e Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 25 Nov 2013 17:15:28 +0200 Subject: [PATCH 068/595] drm/i915: add audio power domain This way the code is simpler and can also be used for other platforms where the audio power domain->power well mapping is different. Signed-off-by: Imre Deak Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 10 ++-------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 18ff544670d8..4ef8e81f5393 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -113,6 +113,7 @@ enum intel_display_power_domain { POWER_DOMAIN_TRANSCODER_C, POWER_DOMAIN_TRANSCODER_EDP, POWER_DOMAIN_VGA, + POWER_DOMAIN_AUDIO, POWER_DOMAIN_INIT, POWER_DOMAIN_NUM, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index de4cf565ec4c..8f472daa2793 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5775,10 +5775,7 @@ void i915_request_power_well(void) dev_priv = container_of(hsw_pwr, struct drm_i915_private, power_domains); - - mutex_lock(&hsw_pwr->lock); - __intel_power_well_get(dev_priv->dev, &hsw_pwr->power_wells[0]); - mutex_unlock(&hsw_pwr->lock); + intel_display_power_get(dev_priv->dev, POWER_DOMAIN_AUDIO); } EXPORT_SYMBOL_GPL(i915_request_power_well); @@ -5792,10 +5789,7 @@ void i915_release_power_well(void) dev_priv = container_of(hsw_pwr, struct drm_i915_private, power_domains); - - mutex_lock(&hsw_pwr->lock); - __intel_power_well_put(dev_priv->dev, &hsw_pwr->power_wells[0]); - mutex_unlock(&hsw_pwr->lock); + intel_display_power_put(dev_priv->dev, POWER_DOMAIN_AUDIO); } EXPORT_SYMBOL_GPL(i915_release_power_well); From c1ca727f89450cbc560af93045d57a186b83b0dc Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 25 Nov 2013 17:15:29 +0200 Subject: [PATCH 069/595] drm/i915: support for multiple power wells HW generations so far had only one always-on power well and optionally one dynamic power well. Upcoming HW gens may have multiple dynamic power wells, so add some infrastructure to support them. The idea is to keep the existing power domain API used by the rest of the driver and create a mapping between these power domains and the underlying power wells. This mapping can differ from one HW to another but high level driver code doesn't need to know about this. Through the existing get/put API it would just ask for a given power domain and the power domain framework would make sure the relevant power wells get enabled in the right order. Signed-off-by: Imre Deak Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 12 +++- drivers/gpu/drm/i915/intel_pm.c | 116 +++++++++++++++++++++++++++----- 2 files changed, 108 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4ef8e81f5393..bb09dbf65fe8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -950,21 +950,27 @@ struct intel_ilk_power_mgmt { /* Power well structure for haswell */ struct i915_power_well { + const char *name; /* power well enable/disable usage count */ int count; + unsigned long domains; + void *data; + void (*set)(struct drm_device *dev, struct i915_power_well *power_well, + bool enable); + bool (*is_enabled)(struct drm_device *dev, + struct i915_power_well *power_well); }; -#define I915_MAX_POWER_WELLS 1 - struct i915_power_domains { /* * Power wells needed for initialization at driver init and suspend * time are on. They are kept on until after the first modeset. */ bool init_power_on; + int power_well_count; struct mutex lock; - struct i915_power_well power_wells[I915_MAX_POWER_WELLS]; + struct i915_power_well *power_wells; }; struct i915_dri1_state { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8f472daa2793..2b3173415212 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5627,15 +5627,41 @@ static bool is_always_on_power_domain(struct drm_device *dev, return BIT(domain) & always_on_domains; } +#define for_each_power_well(i, power_well, domain_mask, power_domains) \ + for (i = 0; \ + i < (power_domains)->power_well_count && \ + ((power_well) = &(power_domains)->power_wells[i]); \ + i++) \ + if ((power_well)->domains & (domain_mask)) + +#define for_each_power_well_rev(i, power_well, domain_mask, power_domains) \ + for (i = (power_domains)->power_well_count - 1; \ + i >= 0 && ((power_well) = &(power_domains)->power_wells[i]);\ + i--) \ + if ((power_well)->domains & (domain_mask)) + /** * We should only use the power well if we explicitly asked the hardware to * enable it, so check if it's enabled and also check if we've requested it to * be enabled. */ +static bool hsw_power_well_enabled(struct drm_device *dev, + struct i915_power_well *power_well) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(HSW_PWR_WELL_DRIVER) == + (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED); +} + bool intel_display_power_enabled(struct drm_device *dev, enum intel_display_power_domain domain) { struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_power_domains *power_domains; + struct i915_power_well *power_well; + bool is_enabled; + int i; if (!HAS_POWER_WELL(dev)) return true; @@ -5643,11 +5669,24 @@ bool intel_display_power_enabled(struct drm_device *dev, if (is_always_on_power_domain(dev, domain)) return true; - return I915_READ(HSW_PWR_WELL_DRIVER) == - (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED); + power_domains = &dev_priv->power_domains; + + is_enabled = true; + + mutex_lock(&power_domains->lock); + for_each_power_well_rev(i, power_well, BIT(domain), power_domains) { + if (!power_well->is_enabled(dev, power_well)) { + is_enabled = false; + break; + } + } + mutex_unlock(&power_domains->lock); + + return is_enabled; } -static void __intel_set_power_well(struct drm_device *dev, bool enable) +static void hsw_set_power_well(struct drm_device *dev, + struct i915_power_well *power_well, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; bool is_enabled, enable_requested; @@ -5713,16 +5752,17 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable) static void __intel_power_well_get(struct drm_device *dev, struct i915_power_well *power_well) { - if (!power_well->count++) - __intel_set_power_well(dev, true); + if (!power_well->count++ && power_well->set) + power_well->set(dev, power_well, true); } static void __intel_power_well_put(struct drm_device *dev, struct i915_power_well *power_well) { WARN_ON(!power_well->count); - if (!--power_well->count && i915_disable_power_well) - __intel_set_power_well(dev, false); + + if (!--power_well->count && power_well->set && i915_disable_power_well) + power_well->set(dev, power_well, false); } void intel_display_power_get(struct drm_device *dev, @@ -5730,6 +5770,8 @@ void intel_display_power_get(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains; + struct i915_power_well *power_well; + int i; if (!HAS_POWER_WELL(dev)) return; @@ -5740,7 +5782,8 @@ void intel_display_power_get(struct drm_device *dev, power_domains = &dev_priv->power_domains; mutex_lock(&power_domains->lock); - __intel_power_well_get(dev, &power_domains->power_wells[0]); + for_each_power_well(i, power_well, BIT(domain), power_domains) + __intel_power_well_get(dev, power_well); mutex_unlock(&power_domains->lock); } @@ -5749,6 +5792,8 @@ void intel_display_power_put(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains; + struct i915_power_well *power_well; + int i; if (!HAS_POWER_WELL(dev)) return; @@ -5759,7 +5804,8 @@ void intel_display_power_put(struct drm_device *dev, power_domains = &dev_priv->power_domains; mutex_lock(&power_domains->lock); - __intel_power_well_put(dev, &power_domains->power_wells[0]); + for_each_power_well_rev(i, power_well, BIT(domain), power_domains) + __intel_power_well_put(dev, power_well); mutex_unlock(&power_domains->lock); } @@ -5793,17 +5839,52 @@ void i915_release_power_well(void) } EXPORT_SYMBOL_GPL(i915_release_power_well); +static struct i915_power_well hsw_power_wells[] = { + { + .name = "display", + .domains = POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS, + .is_enabled = hsw_power_well_enabled, + .set = hsw_set_power_well, + }, +}; + +static struct i915_power_well bdw_power_wells[] = { + { + .name = "display", + .domains = POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS, + .is_enabled = hsw_power_well_enabled, + .set = hsw_set_power_well, + }, +}; + +#define set_power_wells(power_domains, __power_wells) ({ \ + (power_domains)->power_wells = (__power_wells); \ + (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \ +}) + int intel_power_domains_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains = &dev_priv->power_domains; - struct i915_power_well *power_well; + + if (!HAS_POWER_WELL(dev)) + return 0; mutex_init(&power_domains->lock); - hsw_pwr = power_domains; - power_well = &power_domains->power_wells[0]; - power_well->count = 0; + /* + * The enabling order will be from lower to higher indexed wells, + * the disabling order is reversed. + */ + if (IS_HASWELL(dev)) { + set_power_wells(power_domains, hsw_power_wells); + hsw_pwr = power_domains; + } else if (IS_BROADWELL(dev)) { + set_power_wells(power_domains, bdw_power_wells); + hsw_pwr = power_domains; + } else { + WARN_ON(1); + } return 0; } @@ -5818,15 +5899,16 @@ static void intel_power_domains_resume(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains = &dev_priv->power_domains; struct i915_power_well *power_well; + int i; if (!HAS_POWER_WELL(dev)) return; mutex_lock(&power_domains->lock); - - power_well = &power_domains->power_wells[0]; - __intel_set_power_well(dev, power_well->count > 0); - + for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) { + if (power_well->set) + power_well->set(dev, power_well, power_well->count > 0); + } mutex_unlock(&power_domains->lock); } From 6f3ef5ddabc0ad321678ee091c75b1f082a42707 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 25 Nov 2013 17:15:30 +0200 Subject: [PATCH 070/595] drm/i915: add always-on power wells instead of special casing them Instead of using a separate function to check whether a power domain is is always on, add an always-on power well covering all these power domains and do the usual get/put on these unconditionally. Since we don't assign a .set handler for these the get/put won't have any effect besides the adjusted refcount. This makes the code more readable and provides debug info also on the use of always-on power wells (once the relevant debugfs entry is added.) v3: make is_always_on to be bool instead of a bit field (Paulo) Signed-off-by: Imre Deak Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 41 +++++++++++---------------------- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bb09dbf65fe8..e3e732bd832c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -951,6 +951,7 @@ struct intel_ilk_power_mgmt { /* Power well structure for haswell */ struct i915_power_well { const char *name; + bool always_on; /* power well enable/disable usage count */ int count; unsigned long domains; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2b3173415212..9230781824e5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5608,25 +5608,6 @@ void intel_suspend_hw(struct drm_device *dev) lpt_suspend_hw(dev); } -static bool is_always_on_power_domain(struct drm_device *dev, - enum intel_display_power_domain domain) -{ - unsigned long always_on_domains; - - BUG_ON(BIT(domain) & ~POWER_DOMAIN_MASK); - - if (IS_BROADWELL(dev)) { - always_on_domains = BDW_ALWAYS_ON_POWER_DOMAINS; - } else if (IS_HASWELL(dev)) { - always_on_domains = HSW_ALWAYS_ON_POWER_DOMAINS; - } else { - WARN_ON(1); - return true; - } - - return BIT(domain) & always_on_domains; -} - #define for_each_power_well(i, power_well, domain_mask, power_domains) \ for (i = 0; \ i < (power_domains)->power_well_count && \ @@ -5666,15 +5647,15 @@ bool intel_display_power_enabled(struct drm_device *dev, if (!HAS_POWER_WELL(dev)) return true; - if (is_always_on_power_domain(dev, domain)) - return true; - power_domains = &dev_priv->power_domains; is_enabled = true; mutex_lock(&power_domains->lock); for_each_power_well_rev(i, power_well, BIT(domain), power_domains) { + if (power_well->always_on) + continue; + if (!power_well->is_enabled(dev, power_well)) { is_enabled = false; break; @@ -5776,9 +5757,6 @@ void intel_display_power_get(struct drm_device *dev, if (!HAS_POWER_WELL(dev)) return; - if (is_always_on_power_domain(dev, domain)) - return; - power_domains = &dev_priv->power_domains; mutex_lock(&power_domains->lock); @@ -5798,9 +5776,6 @@ void intel_display_power_put(struct drm_device *dev, if (!HAS_POWER_WELL(dev)) return; - if (is_always_on_power_domain(dev, domain)) - return; - power_domains = &dev_priv->power_domains; mutex_lock(&power_domains->lock); @@ -5840,6 +5815,11 @@ void i915_release_power_well(void) EXPORT_SYMBOL_GPL(i915_release_power_well); static struct i915_power_well hsw_power_wells[] = { + { + .name = "always-on", + .always_on = 1, + .domains = HSW_ALWAYS_ON_POWER_DOMAINS, + }, { .name = "display", .domains = POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS, @@ -5849,6 +5829,11 @@ static struct i915_power_well hsw_power_wells[] = { }; static struct i915_power_well bdw_power_wells[] = { + { + .name = "always-on", + .always_on = 1, + .domains = BDW_ALWAYS_ON_POWER_DOMAINS, + }, { .name = "display", .domains = POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS, From 190be112fc02f6efcf954a82bd49e2c19b3673e8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 25 Nov 2013 17:15:31 +0200 Subject: [PATCH 071/595] drm/i915: use IS_HASWELL/BROADWELL instead of HAS_POWER_WELL In intel_display_capture_error_state we use HAS_POWER_WELL to check if we are running on Haswell/Broadwell when accessing HSW_PWR_WELL_DRIVER which is specific to these platforms. Future platforms with power wells don't have this register, so HAS_POWER_WELL won't work there any more. Use IS_HASWELL/IS_BROADWELL instead. v3: fix using logical || instead of bitwise | (Paulo) Signed-off-by: Imre Deak Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 54e7fa6d9628..aa1a6c1e90ea 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11359,7 +11359,7 @@ intel_display_capture_error_state(struct drm_device *dev) if (error == NULL) return NULL; - if (HAS_POWER_WELL(dev)) + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER); for_each_pipe(i) { @@ -11430,7 +11430,7 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m, return; err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); - if (HAS_POWER_WELL(dev)) + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) err_printf(m, "PWR_WELL_CTL2: %08x\n", error->power_well_driver); for_each_pipe(i) { From f9e711e92825d4c71791794c944dd685c63c1a59 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 25 Nov 2013 17:15:32 +0200 Subject: [PATCH 072/595] drm/i915: protect HSW power well check with IS_HASWELL in redisable_vga This may need work if other platforms do the same thing, but in the meantime we should avoid looking at HSW specific bits in this generic function. Signed-off-by: Jesse Barnes Reviewed-by: Paulo Zanoni [added IS_BROADWELL too as that needs the same handling (Imre)] Signed-off-by: Imre Deak [danvet: Add Imre's missing sob.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aa1a6c1e90ea..22b7b141a22f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11032,7 +11032,7 @@ void i915_redisable_vga(struct drm_device *dev) * level, just check if the power well is enabled instead of trying to * follow the "don't touch the power well if we don't need it" policy * the rest of the driver uses. */ - if (HAS_POWER_WELL(dev) && + if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && (I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_STATE_ENABLED) == 0) return; From f7243ac9a25810140f5910c69821d5fa1e3e2387 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 25 Nov 2013 17:15:33 +0200 Subject: [PATCH 073/595] drm/i915: don't do BDW/HSW specific powerdomains init on other platforms Signed-off-by: Imre Deak Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9230781824e5..5331925e37fa 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5914,6 +5914,9 @@ void intel_power_domains_init_hw(struct drm_device *dev) intel_display_set_init_power(dev, true); intel_power_domains_resume(dev); + if (!(IS_HASWELL(dev) || IS_BROADWELL(dev))) + return; + /* We're taking over the BIOS, so clear any requests made by it since * the driver is in charge now. */ if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST) From 1c2256df26f697bcd20016c271ddc8fd44653919 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 25 Nov 2013 17:15:34 +0200 Subject: [PATCH 074/595] drm/i915: add a default always-on power well So far we distinguished platforms without a dynamic power well with the HAS_POWER_WELL macro and for such platforms we didn't call any power domain functions. Instead of doing this check we can add an always-on power well for these platforms and call the power domain functions unconditionally. For always-on power wells we only increase/decrease their refcounts, otherwise they are nop. This makes high level driver code more readable and as a bonus provides some idea of the current power domains state for all platforms (once the relevant debugfs entry is added). v3: rename intel_power_wells to i9xx_always_on_power_well (Paulo) Signed-off-by: Imre Deak Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 18 +++++++----------- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_pm.c | 28 +++++++++------------------- 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 5aeb103eae44..89e4cf1bb073 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1639,8 +1639,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_gem_unload; } - if (HAS_POWER_WELL(dev)) - intel_power_domains_init(dev); + intel_power_domains_init(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) { ret = i915_load_modeset_init(dev); @@ -1667,8 +1666,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) return 0; out_power_well: - if (HAS_POWER_WELL(dev)) - intel_power_domains_remove(dev); + intel_power_domains_remove(dev); drm_vblank_cleanup(dev); out_gem_unload: if (dev_priv->mm.inactive_shrinker.scan_objects) @@ -1706,13 +1704,11 @@ int i915_driver_unload(struct drm_device *dev) intel_gpu_ips_teardown(); - if (HAS_POWER_WELL(dev)) { - /* The i915.ko module is still not prepared to be loaded when - * the power well is not enabled, so just enable it in case - * we're going to unload/reload. */ - intel_display_set_init_power(dev, true); - intel_power_domains_remove(dev); - } + /* The i915.ko module is still not prepared to be loaded when + * the power well is not enabled, so just enable it in case + * we're going to unload/reload. */ + intel_display_set_init_power(dev, true); + intel_power_domains_remove(dev); i915_teardown_sysfs(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e3e732bd832c..0f7bc14208a3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1834,7 +1834,6 @@ struct drm_i915_file_private { #define HAS_IPS(dev) (IS_ULT(dev) || IS_BROADWELL(dev)) #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) -#define HAS_POWER_WELL(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev)) #define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) #define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev)) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5331925e37fa..6b4f91ee486c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5644,9 +5644,6 @@ bool intel_display_power_enabled(struct drm_device *dev, bool is_enabled; int i; - if (!HAS_POWER_WELL(dev)) - return true; - power_domains = &dev_priv->power_domains; is_enabled = true; @@ -5754,9 +5751,6 @@ void intel_display_power_get(struct drm_device *dev, struct i915_power_well *power_well; int i; - if (!HAS_POWER_WELL(dev)) - return; - power_domains = &dev_priv->power_domains; mutex_lock(&power_domains->lock); @@ -5773,9 +5767,6 @@ void intel_display_power_put(struct drm_device *dev, struct i915_power_well *power_well; int i; - if (!HAS_POWER_WELL(dev)) - return; - power_domains = &dev_priv->power_domains; mutex_lock(&power_domains->lock); @@ -5814,6 +5805,14 @@ void i915_release_power_well(void) } EXPORT_SYMBOL_GPL(i915_release_power_well); +static struct i915_power_well i9xx_always_on_power_well[] = { + { + .name = "always-on", + .always_on = 1, + .domains = POWER_DOMAIN_MASK, + }, +}; + static struct i915_power_well hsw_power_wells[] = { { .name = "always-on", @@ -5852,9 +5851,6 @@ int intel_power_domains_init(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains = &dev_priv->power_domains; - if (!HAS_POWER_WELL(dev)) - return 0; - mutex_init(&power_domains->lock); /* @@ -5868,7 +5864,7 @@ int intel_power_domains_init(struct drm_device *dev) set_power_wells(power_domains, bdw_power_wells); hsw_pwr = power_domains; } else { - WARN_ON(1); + set_power_wells(power_domains, i9xx_always_on_power_well); } return 0; @@ -5886,9 +5882,6 @@ static void intel_power_domains_resume(struct drm_device *dev) struct i915_power_well *power_well; int i; - if (!HAS_POWER_WELL(dev)) - return; - mutex_lock(&power_domains->lock); for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) { if (power_well->set) @@ -5907,9 +5900,6 @@ void intel_power_domains_init_hw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!HAS_POWER_WELL(dev)) - return; - /* For now, we need the power well to be always enabled. */ intel_display_set_init_power(dev, true); intel_power_domains_resume(dev); From 1da51581b00b3fc3ac72156e2a69c6bab71f7794 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 25 Nov 2013 17:15:35 +0200 Subject: [PATCH 075/595] drm/i915: add a debugfs entry for power domain info Add a debugfs entry showing the use-count for all power domains of each power well. v3: address comments from Paulo: - simplify power_domain_str() by using a switch table - move power_well::domain_count to power_domains - WARN_ON decrementing a 0 refcount Signed-off-by: Imre Deak Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 71 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 3 ++ drivers/gpu/drm/i915/intel_pm.c | 12 +++++ 3 files changed, 86 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ee4d46593aae..6600447ad0d5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1844,6 +1844,76 @@ static int i915_pc8_status(struct seq_file *m, void *unused) return 0; } +static const char *power_domain_str(enum intel_display_power_domain domain) +{ + switch (domain) { + case POWER_DOMAIN_PIPE_A: + return "PIPE_A"; + case POWER_DOMAIN_PIPE_B: + return "PIPE_B"; + case POWER_DOMAIN_PIPE_C: + return "PIPE_C"; + case POWER_DOMAIN_PIPE_A_PANEL_FITTER: + return "PIPE_A_PANEL_FITTER"; + case POWER_DOMAIN_PIPE_B_PANEL_FITTER: + return "PIPE_B_PANEL_FITTER"; + case POWER_DOMAIN_PIPE_C_PANEL_FITTER: + return "PIPE_C_PANEL_FITTER"; + case POWER_DOMAIN_TRANSCODER_A: + return "TRANSCODER_A"; + case POWER_DOMAIN_TRANSCODER_B: + return "TRANSCODER_B"; + case POWER_DOMAIN_TRANSCODER_C: + return "TRANSCODER_C"; + case POWER_DOMAIN_TRANSCODER_EDP: + return "TRANSCODER_EDP"; + case POWER_DOMAIN_VGA: + return "VGA"; + case POWER_DOMAIN_AUDIO: + return "AUDIO"; + case POWER_DOMAIN_INIT: + return "INIT"; + default: + WARN_ON(1); + return "?"; + } +} + +static int i915_power_domain_info(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_power_domains *power_domains = &dev_priv->power_domains; + int i; + + mutex_lock(&power_domains->lock); + + seq_printf(m, "%-25s %s\n", "Power well/domain", "Use count"); + for (i = 0; i < power_domains->power_well_count; i++) { + struct i915_power_well *power_well; + enum intel_display_power_domain power_domain; + + power_well = &power_domains->power_wells[i]; + seq_printf(m, "%-25s %d\n", power_well->name, + power_well->count); + + for (power_domain = 0; power_domain < POWER_DOMAIN_NUM; + power_domain++) { + if (!(BIT(power_domain) & power_well->domains)) + continue; + + seq_printf(m, " %-23s %d\n", + power_domain_str(power_domain), + power_domains->domain_use_count[power_domain]); + } + } + + mutex_unlock(&power_domains->lock); + + return 0; +} + struct pipe_crc_info { const char *name; struct drm_device *dev; @@ -3079,6 +3149,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_edp_psr_status", i915_edp_psr_status, 0}, {"i915_energy_uJ", i915_energy_uJ, 0}, {"i915_pc8_status", i915_pc8_status, 0}, + {"i915_power_domain_info", i915_power_domain_info, 0}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0f7bc14208a3..49dfac9028e3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -971,6 +971,9 @@ struct i915_power_domains { int power_well_count; struct mutex lock; +#if IS_ENABLED(CONFIG_DEBUG_FS) + int domain_use_count[POWER_DOMAIN_NUM]; +#endif struct i915_power_well *power_wells; }; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6b4f91ee486c..2f8399c347ee 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5754,8 +5754,13 @@ void intel_display_power_get(struct drm_device *dev, power_domains = &dev_priv->power_domains; mutex_lock(&power_domains->lock); + +#if IS_ENABLED(CONFIG_DEBUG_FS) + power_domains->domain_use_count[domain]++; +#endif for_each_power_well(i, power_well, BIT(domain), power_domains) __intel_power_well_get(dev, power_well); + mutex_unlock(&power_domains->lock); } @@ -5770,8 +5775,15 @@ void intel_display_power_put(struct drm_device *dev, power_domains = &dev_priv->power_domains; mutex_lock(&power_domains->lock); + for_each_power_well_rev(i, power_well, BIT(domain), power_domains) __intel_power_well_put(dev, power_well); + +#if IS_ENABLED(CONFIG_DEBUG_FS) + WARN_ON(!power_domains->domain_use_count[domain]); + power_domains->domain_use_count[domain]--; +#endif + mutex_unlock(&power_domains->lock); } From 947fdaadf05480e567d3cd58d456240655063d03 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Nov 2013 12:01:32 +0000 Subject: [PATCH 076/595] drm/i915: Do not attempt to re-enable an unconnected primary plane Due to user fudging (for instance using video=VGA-1:e with FBDEV=n) we can attempt to reset an inconsistent CRTC that is marked as active but has no assigned fb. It would be wise to fix this earlier, but the long term plan is to have primary and secondary planes associated with a CRTC, in which crtc->fb being NULL will be expected. So for a quick short term fix with pretensions of grandeur, just check for a NULL fb during GPU reset and ignore the plane restoration. This fixes a potential hard hang (a panic in the panic handler) following a GPU hang. Signed-off-by: Chris Wilson Cc: Daniel Vetter [danvet: Add a corresponding fixme comment.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 22b7b141a22f..784ff70a95eb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2241,7 +2241,12 @@ void intel_display_handle_reset(struct drm_device *dev) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); mutex_lock(&crtc->mutex); - if (intel_crtc->active) + /* + * FIXME: Once we have proper support for primary planes (and + * disabling them without disabling the entire crtc) allow again + * a NULL crtc->fb. + */ + if (intel_crtc->active && crtc->fb) dev_priv->display.update_plane(crtc, crtc->fb, crtc->x, crtc->y); mutex_unlock(&crtc->mutex); From c8d9a5905e45d856fb21cce2e20f186ce6719560 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Sat, 23 Nov 2013 14:55:42 +0530 Subject: [PATCH 077/595] drm/i915: Add power well arguments to force wake routines. Added power well arguments to all the force wake routines to help us individually control power well based on the scenario. Signed-off-by: Deepak S Reviewed-by: Jesse Barnes [danvet: Resolve conflict with the removed forcewake hack and drop one spurious hunk Jesse noticed.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 8 ++--- drivers/gpu/drm/i915/i915_drv.h | 15 ++++++--- drivers/gpu/drm/i915/intel_display.c | 4 +-- drivers/gpu/drm/i915/intel_pm.c | 19 ++++++----- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 +-- drivers/gpu/drm/i915/intel_uncore.c | 44 +++++++++++++++---------- 6 files changed, 56 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6600447ad0d5..1a4c559a9689 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -947,7 +947,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) if (ret) return ret; - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); reqf = I915_READ(GEN6_RPNSWREQ); reqf &= ~GEN6_TURBO_DISABLE; @@ -970,7 +970,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT; cagf *= GT_FREQUENCY_MULTIPLIER; - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); mutex_unlock(&dev->struct_mutex); seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); @@ -3053,7 +3053,7 @@ static int i915_forcewake_open(struct inode *inode, struct file *file) if (INTEL_INFO(dev)->gen < 6) return 0; - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); return 0; } @@ -3066,7 +3066,7 @@ static int i915_forcewake_release(struct inode *inode, struct file *file) if (INTEL_INFO(dev)->gen < 6) return 0; - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 49dfac9028e3..9b219d3bf233 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -437,8 +437,10 @@ struct drm_i915_display_funcs { }; struct intel_uncore_funcs { - void (*force_wake_get)(struct drm_i915_private *dev_priv); - void (*force_wake_put)(struct drm_i915_private *dev_priv); + void (*force_wake_get)(struct drm_i915_private *dev_priv, + int fw_engine); + void (*force_wake_put)(struct drm_i915_private *dev_priv, + int fw_engine); uint8_t (*mmio_readb)(struct drm_i915_private *dev_priv, off_t offset, bool trace); uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, off_t offset, bool trace); @@ -2438,8 +2440,8 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, * must be set to prevent GT core from power down and stale values being * returned. */ -void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); -void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); +void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine); +void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine); int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val); int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); @@ -2468,6 +2470,11 @@ void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val); int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val); +#define FORCEWAKE_RENDER (1 << 0) +#define FORCEWAKE_MEDIA (1 << 1) +#define FORCEWAKE_ALL (FORCEWAKE_RENDER | FORCEWAKE_MEDIA) + + #define I915_READ8(reg) dev_priv->uncore.funcs.mmio_readb(dev_priv, (reg), true) #define I915_WRITE8(reg, val) dev_priv->uncore.funcs.mmio_writeb(dev_priv, (reg), (val), true) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 784ff70a95eb..ca467cb3c1b4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6583,7 +6583,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) /* Make sure we're not on PC8 state before disabling PC8, otherwise * we'll hang the machine! */ - dev_priv->uncore.funcs.force_wake_get(dev_priv); + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); if (val & LCPLL_POWER_DOWN_ALLOW) { val &= ~LCPLL_POWER_DOWN_ALLOW; @@ -6617,7 +6617,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) DRM_ERROR("Switching back to LCPLL failed\n"); } - dev_priv->uncore.funcs.force_wake_put(dev_priv); + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); } void hsw_enable_pc8_work(struct work_struct *__work) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2f8399c347ee..fd2537d429f2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -191,7 +191,8 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) u32 blt_ecoskpd; /* Make sure blitter notifies FBC of writes */ - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); + blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << GEN6_BLITTER_LOCK_SHIFT; @@ -202,7 +203,8 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) GEN6_BLITTER_LOCK_SHIFT); I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); POSTING_READ(GEN6_BLITTER_ECOSKPD); - gen6_gt_force_wake_put(dev_priv); + + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); } static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) @@ -3739,7 +3741,7 @@ static void gen8_enable_rps(struct drm_device *dev) /* 1c & 1d: Get forcewake during program sequence. Although the driver * hasn't enabled a state yet where we need forcewake, BIOS may have.*/ - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); /* 2a: Disable RC states. */ I915_WRITE(GEN6_RC_CONTROL, 0); @@ -3796,7 +3798,7 @@ static void gen8_enable_rps(struct drm_device *dev) gen6_enable_rps_interrupts(dev); - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); } static void gen6_enable_rps(struct drm_device *dev) @@ -3826,7 +3828,7 @@ static void gen6_enable_rps(struct drm_device *dev) I915_WRITE(GTFIFODBG, gtfifodbg); } - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); @@ -3918,7 +3920,7 @@ static void gen6_enable_rps(struct drm_device *dev) DRM_ERROR("Couldn't fix incorrect rc6 voltage\n"); } - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); } void gen6_update_ring_freq(struct drm_device *dev) @@ -4080,7 +4082,8 @@ static void valleyview_enable_rps(struct drm_device *dev) valleyview_setup_pctx(dev); - gen6_gt_force_wake_get(dev_priv); + /* If VLV, Forcewake all wells, else re-direct to regular path */ + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400); I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000); @@ -4152,7 +4155,7 @@ static void valleyview_enable_rps(struct drm_device *dev) gen6_enable_rps_interrupts(dev); - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); } void ironlake_teardown_rc6(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 69589e4f957f..e05a0216cd9b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -438,7 +438,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) int ret = 0; u32 head; - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); if (I915_NEED_GFX_HWS(dev)) intel_ring_setup_status_page(ring); @@ -511,7 +511,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); out: - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); return ret; } diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 07c0ad0e1583..d7c3f5effc79 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -64,7 +64,8 @@ static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv) __raw_posting_read(dev_priv, ECOBUS); } -static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) +static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, + int fw_engine) { if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK) & 1) == 0, FORCEWAKE_ACK_TIMEOUT_MS)) @@ -89,7 +90,8 @@ static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv) __raw_posting_read(dev_priv, ECOBUS); } -static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) +static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv, + int fw_engine) { u32 forcewake_ack; @@ -126,7 +128,8 @@ static void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv) __raw_i915_write32(dev_priv, GTFIFODBG, GT_FIFO_CPU_ERROR_MASK); } -static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) +static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, + int fw_engine) { __raw_i915_write32(dev_priv, FORCEWAKE, 0); /* something from same cacheline, but !FORCEWAKE */ @@ -134,7 +137,8 @@ static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) gen6_gt_check_fifodbg(dev_priv); } -static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) +static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv, + int fw_engine) { __raw_i915_write32(dev_priv, FORCEWAKE_MT, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); @@ -171,7 +175,7 @@ static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) __raw_posting_read(dev_priv, FORCEWAKE_ACK_VLV); } -static void vlv_force_wake_get(struct drm_i915_private *dev_priv) +static void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) { if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0, FORCEWAKE_ACK_TIMEOUT_MS)) @@ -195,7 +199,7 @@ static void vlv_force_wake_get(struct drm_i915_private *dev_priv) __gen6_gt_wait_for_thread_c0(dev_priv); } -static void vlv_force_wake_put(struct drm_i915_private *dev_priv) +static void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) { __raw_i915_write32(dev_priv, FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); @@ -213,7 +217,7 @@ static void gen6_force_wake_work(struct work_struct *work) spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (--dev_priv->uncore.forcewake_count == 0) - dev_priv->uncore.funcs.force_wake_put(dev_priv); + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } @@ -279,7 +283,7 @@ void intel_uncore_sanitize(struct drm_device *dev) * be called at the beginning of the sequence followed by a call to * gen6_gt_force_wake_put() at the end of the sequence. */ -void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) +void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) { unsigned long irqflags; @@ -288,14 +292,14 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (dev_priv->uncore.forcewake_count++ == 0) - dev_priv->uncore.funcs.force_wake_get(dev_priv); + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } /* * see gen6_gt_force_wake_get() */ -void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) +void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) { unsigned long irqflags; @@ -377,10 +381,12 @@ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ REG_READ_HEADER(x); \ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ if (dev_priv->uncore.forcewake_count == 0) \ - dev_priv->uncore.funcs.force_wake_get(dev_priv); \ + dev_priv->uncore.funcs.force_wake_get(dev_priv, \ + FORCEWAKE_ALL); \ val = __raw_i915_read##x(dev_priv, reg); \ if (dev_priv->uncore.forcewake_count == 0) \ - dev_priv->uncore.funcs.force_wake_put(dev_priv); \ + dev_priv->uncore.funcs.force_wake_put(dev_priv, \ + FORCEWAKE_ALL); \ } else { \ val = __raw_i915_read##x(dev_priv, reg); \ } \ @@ -487,11 +493,13 @@ gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace bool __needs_put = !is_gen8_shadowed(dev_priv, reg); \ REG_WRITE_HEADER; \ if (__needs_put) { \ - dev_priv->uncore.funcs.force_wake_get(dev_priv); \ + dev_priv->uncore.funcs.force_wake_get(dev_priv, \ + FORCEWAKE_ALL); \ } \ __raw_i915_write##x(dev_priv, reg, val); \ if (__needs_put) { \ - dev_priv->uncore.funcs.force_wake_put(dev_priv); \ + dev_priv->uncore.funcs.force_wake_put(dev_priv, \ + FORCEWAKE_ALL); \ } \ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ } @@ -550,9 +558,9 @@ void intel_uncore_init(struct drm_device *dev) * forcewake being disabled. */ mutex_lock(&dev->struct_mutex); - __gen6_gt_force_wake_mt_get(dev_priv); + __gen6_gt_force_wake_mt_get(dev_priv, FORCEWAKE_ALL); ecobus = __raw_i915_read32(dev_priv, ECOBUS); - __gen6_gt_force_wake_mt_put(dev_priv); + __gen6_gt_force_wake_mt_put(dev_priv, FORCEWAKE_ALL); mutex_unlock(&dev->struct_mutex); if (ecobus & FORCEWAKE_MT_ENABLE) { @@ -805,9 +813,9 @@ static int gen6_do_reset(struct drm_device *dev) /* If reset with a user forcewake, try to restore, otherwise turn it off */ if (dev_priv->uncore.forcewake_count) - dev_priv->uncore.funcs.force_wake_get(dev_priv); + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); else - dev_priv->uncore.funcs.force_wake_put(dev_priv); + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); /* Restore fifo count */ dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES); From 940aece471bd6656b86f5d77132b6670a3b88dc8 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Sat, 23 Nov 2013 14:55:43 +0530 Subject: [PATCH 078/595] drm/i915/vlv: Valleyview support for forcewake Individual power wells. Split vlv force wake routines to help individually control Media/Render well based on the register access. We've seen power savings in the lower sub-1W range on workloads that only need on of the power wells, e.g. glbenchmark, media playback Note: The same split isn't there for the forcewake queue, only the forcwake domains are split. Signed-off-by: Deepak S Reviewed-by: Jesse Barnes [danvet: Rebase on top of the removed forcewake hack in the ring irq get/put code and add a note to add Deepak's answer to Chris question.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 17 +++ drivers/gpu/drm/i915/intel_pm.c | 7 +- drivers/gpu/drm/i915/intel_uncore.c | 177 ++++++++++++++++++++++++---- 3 files changed, 173 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9b219d3bf233..6b18b4714d7e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -465,6 +465,9 @@ struct intel_uncore { unsigned fifo_count; unsigned forcewake_count; + unsigned fw_rendercount; + unsigned fw_mediacount; + struct delayed_work force_wake_work; }; @@ -2470,6 +2473,20 @@ void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val); int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val); +void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine); +void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine); + +#define FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg) \ + (((reg) >= 0x2000 && (reg) < 0x4000) ||\ + ((reg) >= 0x5000 && (reg) < 0x8000) ||\ + ((reg) >= 0xB000 && (reg) < 0x12000) ||\ + ((reg) >= 0x2E000 && (reg) < 0x30000)) + +#define FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)\ + (((reg) >= 0x12000 && (reg) < 0x14000) ||\ + ((reg) >= 0x22000 && (reg) < 0x24000) ||\ + ((reg) >= 0x30000 && (reg) < 0x40000)) + #define FORCEWAKE_RENDER (1 << 0) #define FORCEWAKE_MEDIA (1 << 1) #define FORCEWAKE_ALL (FORCEWAKE_RENDER | FORCEWAKE_MEDIA) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fd2537d429f2..1659265a7f7a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -191,7 +191,10 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) u32 blt_ecoskpd; /* Make sure blitter notifies FBC of writes */ - gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); + + /* Blitter is part of Media powerwell on VLV. No impact of + * his param in other platforms for now */ + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_MEDIA); blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << @@ -204,7 +207,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); POSTING_READ(GEN6_BLITTER_ECOSKPD); - gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA); } static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index d7c3f5effc79..d002e30aaae0 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -175,38 +175,112 @@ static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) __raw_posting_read(dev_priv, FORCEWAKE_ACK_VLV); } -static void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) +static void __vlv_force_wake_get(struct drm_i915_private *dev_priv, + int fw_engine) { - if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0, - FORCEWAKE_ACK_TIMEOUT_MS)) - DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); + /* Check for Render Engine */ + if (FORCEWAKE_RENDER & fw_engine) { + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_VLV) & + FORCEWAKE_KERNEL) == 0, + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: Render forcewake old ack to clear.\n"); - __raw_i915_write32(dev_priv, FORCEWAKE_VLV, - _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); - __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV, - _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); + __raw_i915_write32(dev_priv, FORCEWAKE_VLV, + _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); - if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL), - FORCEWAKE_ACK_TIMEOUT_MS)) - DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n"); + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_VLV) & + FORCEWAKE_KERNEL), + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: waiting for Render to ack.\n"); + } - if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_MEDIA_VLV) & - FORCEWAKE_KERNEL), - FORCEWAKE_ACK_TIMEOUT_MS)) - DRM_ERROR("Timed out waiting for media to ack forcewake request.\n"); + /* Check for Media Engine */ + if (FORCEWAKE_MEDIA & fw_engine) { + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_MEDIA_VLV) & + FORCEWAKE_KERNEL) == 0, + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: Media forcewake old ack to clear.\n"); + + __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV, + _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); + + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_MEDIA_VLV) & + FORCEWAKE_KERNEL), + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: waiting for media to ack.\n"); + } /* WaRsForcewakeWaitTC0:vlv */ __gen6_gt_wait_for_thread_c0(dev_priv); + } -static void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) +static void __vlv_force_wake_put(struct drm_i915_private *dev_priv, + int fw_engine) { - __raw_i915_write32(dev_priv, FORCEWAKE_VLV, - _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); - __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV, - _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); + + /* Check for Render Engine */ + if (FORCEWAKE_RENDER & fw_engine) + __raw_i915_write32(dev_priv, FORCEWAKE_VLV, + _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); + + + /* Check for Media Engine */ + if (FORCEWAKE_MEDIA & fw_engine) + __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV, + _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); + /* The below doubles as a POSTING_READ */ gen6_gt_check_fifodbg(dev_priv); + +} + +void vlv_force_wake_get(struct drm_i915_private *dev_priv, + int fw_engine) +{ + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + if (FORCEWAKE_RENDER & fw_engine) { + if (dev_priv->uncore.fw_rendercount++ == 0) + dev_priv->uncore.funcs.force_wake_get(dev_priv, + FORCEWAKE_RENDER); + } + if (FORCEWAKE_MEDIA & fw_engine) { + if (dev_priv->uncore.fw_mediacount++ == 0) + dev_priv->uncore.funcs.force_wake_get(dev_priv, + FORCEWAKE_MEDIA); + } + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +void vlv_force_wake_put(struct drm_i915_private *dev_priv, + int fw_engine) +{ + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + if (FORCEWAKE_RENDER & fw_engine) { + WARN_ON(dev_priv->uncore.fw_rendercount == 0); + if (--dev_priv->uncore.fw_rendercount == 0) + dev_priv->uncore.funcs.force_wake_put(dev_priv, + FORCEWAKE_RENDER); + } + + if (FORCEWAKE_MEDIA & fw_engine) { + WARN_ON(dev_priv->uncore.fw_mediacount == 0); + if (--dev_priv->uncore.fw_mediacount == 0) + dev_priv->uncore.funcs.force_wake_put(dev_priv, + FORCEWAKE_MEDIA); + } + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void gen6_force_wake_work(struct work_struct *work) @@ -290,6 +364,10 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) if (!dev_priv->uncore.funcs.force_wake_get) return; + /* Redirect to VLV specific routine */ + if (IS_VALLEYVIEW(dev_priv->dev)) + return vlv_force_wake_get(dev_priv, fw_engine); + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (dev_priv->uncore.forcewake_count++ == 0) dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); @@ -306,6 +384,11 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) if (!dev_priv->uncore.funcs.force_wake_put) return; + /* Redirect to VLV specific routine */ + if (IS_VALLEYVIEW(dev_priv->dev)) + return vlv_force_wake_put(dev_priv, fw_engine); + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (--dev_priv->uncore.forcewake_count == 0) { dev_priv->uncore.forcewake_count++; @@ -393,6 +476,39 @@ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ REG_READ_FOOTER; \ } +#define __vlv_read(x) \ +static u##x \ +vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ + unsigned fwengine = 0; \ + unsigned *fwcount = 0; \ + REG_READ_HEADER(x); \ + if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) { \ + fwengine = FORCEWAKE_RENDER; \ + fwcount = &dev_priv->uncore.fw_rendercount; \ + } \ + else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) { \ + fwengine = FORCEWAKE_MEDIA; \ + fwcount = &dev_priv->uncore.fw_mediacount; \ + } \ + if (fwengine != 0) { \ + if ((*fwcount)++ == 0) \ + (dev_priv)->uncore.funcs.force_wake_get(dev_priv, \ + fwengine); \ + val = __raw_i915_read##x(dev_priv, reg); \ + if (--(*fwcount) == 0) \ + (dev_priv)->uncore.funcs.force_wake_put(dev_priv, \ + FORCEWAKE_ALL); \ + } else { \ + val = __raw_i915_read##x(dev_priv, reg); \ + } \ + REG_READ_FOOTER; \ +} + + +__vlv_read(8) +__vlv_read(16) +__vlv_read(32) +__vlv_read(64) __gen6_read(8) __gen6_read(16) __gen6_read(32) @@ -406,6 +522,7 @@ __gen4_read(16) __gen4_read(32) __gen4_read(64) +#undef __vlv_read #undef __gen6_read #undef __gen5_read #undef __gen4_read @@ -540,8 +657,8 @@ void intel_uncore_init(struct drm_device *dev) gen6_force_wake_work); if (IS_VALLEYVIEW(dev)) { - dev_priv->uncore.funcs.force_wake_get = vlv_force_wake_get; - dev_priv->uncore.funcs.force_wake_put = vlv_force_wake_put; + dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get; + dev_priv->uncore.funcs.force_wake_put = __vlv_force_wake_put; } else if (IS_HASWELL(dev) || IS_GEN8(dev)) { dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get; dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put; @@ -607,10 +724,18 @@ void intel_uncore_init(struct drm_device *dev) dev_priv->uncore.funcs.mmio_writel = gen6_write32; dev_priv->uncore.funcs.mmio_writeq = gen6_write64; } - dev_priv->uncore.funcs.mmio_readb = gen6_read8; - dev_priv->uncore.funcs.mmio_readw = gen6_read16; - dev_priv->uncore.funcs.mmio_readl = gen6_read32; - dev_priv->uncore.funcs.mmio_readq = gen6_read64; + + if (IS_VALLEYVIEW(dev)) { + dev_priv->uncore.funcs.mmio_readb = vlv_read8; + dev_priv->uncore.funcs.mmio_readw = vlv_read16; + dev_priv->uncore.funcs.mmio_readl = vlv_read32; + dev_priv->uncore.funcs.mmio_readq = vlv_read64; + } else { + dev_priv->uncore.funcs.mmio_readb = gen6_read8; + dev_priv->uncore.funcs.mmio_readw = gen6_read16; + dev_priv->uncore.funcs.mmio_readl = gen6_read32; + dev_priv->uncore.funcs.mmio_readq = gen6_read64; + } break; case 5: dev_priv->uncore.funcs.mmio_writeb = gen5_write8; From 43709ba0d828b3706ace6980d875b762f90ce472 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Sat, 23 Nov 2013 14:55:44 +0530 Subject: [PATCH 079/595] drm/i915: Enabling DebugFS for valleyview forcewake counts Forcewake counts for valleyview are not exposed throgh DebugFS. Exposing with this change. Signed-off-by: Deepak S Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 1a4c559a9689..13accf795548 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1564,13 +1564,21 @@ static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; - unsigned forcewake_count; + unsigned forcewake_count = 0, fw_rendercount = 0, fw_mediacount = 0; spin_lock_irq(&dev_priv->uncore.lock); - forcewake_count = dev_priv->uncore.forcewake_count; + if (IS_VALLEYVIEW(dev)) { + fw_rendercount = dev_priv->uncore.fw_rendercount; + fw_mediacount = dev_priv->uncore.fw_mediacount; + } else + forcewake_count = dev_priv->uncore.forcewake_count; spin_unlock_irq(&dev_priv->uncore.lock); - seq_printf(m, "forcewake count = %u\n", forcewake_count); + if (IS_VALLEYVIEW(dev)) { + seq_printf(m, "fw_rendercount = %u\n", fw_rendercount); + seq_printf(m, "fw_mediacount = %u\n", fw_mediacount); + } else + seq_printf(m, "forcewake count = %u\n", forcewake_count); return 0; } From 90f256b5bbdd5c69e5a7bbaec690bc4821bb2272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 14 Nov 2013 01:59:59 +0200 Subject: [PATCH 080/595] drm/i915: Report all GTFIFODBG errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On VLV GTFIFODBG has more bits. Just report them all. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 5 ++++- drivers/gpu/drm/i915/intel_uncore.c | 5 ++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f2104f5e3af7..4f84573c5ad6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4857,7 +4857,10 @@ #define FORCEWAKE_MT_ENABLE (1<<5) #define GTFIFODBG 0x120000 -#define GT_FIFO_CPU_ERROR_MASK 7 +#define GT_FIFO_SBDROPERR (1<<6) +#define GT_FIFO_BLOBDROPERR (1<<5) +#define GT_FIFO_SB_READ_ABORTERR (1<<4) +#define GT_FIFO_DROPERR (1<<3) #define GT_FIFO_OVFERR (1<<2) #define GT_FIFO_IAWRERR (1<<1) #define GT_FIFO_IARDERR (1<<0) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index d002e30aaae0..cff6610601f6 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -123,9 +123,8 @@ static void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv) u32 gtfifodbg; gtfifodbg = __raw_i915_read32(dev_priv, GTFIFODBG); - if (WARN(gtfifodbg & GT_FIFO_CPU_ERROR_MASK, - "MMIO read or write has been dropped %x\n", gtfifodbg)) - __raw_i915_write32(dev_priv, GTFIFODBG, GT_FIFO_CPU_ERROR_MASK); + if (WARN(gtfifodbg, "GT wake FIFO error 0x%x\n", gtfifodbg)) + __raw_i915_write32(dev_priv, GTFIFODBG, gtfifodbg); } static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, From 46520e2baa861a02c14d3d590d5897092950c62a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 14 Nov 2013 02:00:00 +0200 Subject: [PATCH 081/595] drm/i915: Fix GT wake FIFO free entries for VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On VLV the GTFIFOCTL register has other bits besides the number of free entries in the GT wake FIFO. Apply a mask when we read th register to make sure we don't misinterpret the number of free FIFO entries. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes [danvet: There's some unclarity about hsw, but brushed off as todays' Bspec just acting up a bit.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 ++- drivers/gpu/drm/i915/intel_uncore.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4f84573c5ad6..2658d975279b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4865,7 +4865,8 @@ #define GT_FIFO_IAWRERR (1<<1) #define GT_FIFO_IARDERR (1<<0) -#define GT_FIFO_FREE_ENTRIES 0x120008 +#define GTFIFOCTL 0x120008 +#define GT_FIFO_FREE_ENTRIES_MASK 0x7f #define GT_FIFO_NUM_RESERVED_ENTRIES 20 #define HSW_IDICR 0x9008 diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index cff6610601f6..97ae8bda7a1e 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -152,10 +152,10 @@ static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) if (dev_priv->uncore.fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) { int loop = 500; - u32 fifo = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES); + u32 fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) { udelay(10); - fifo = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES); + fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; } if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES)) ++ret; @@ -942,7 +942,7 @@ static int gen6_do_reset(struct drm_device *dev) dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); /* Restore fifo count */ - dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES); + dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); return ret; From 084054fc05c7798ff7cf61e25c246f222f41db5b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 27 Nov 2013 20:47:58 +0100 Subject: [PATCH 082/595] drm/i915: drop the right force-wake engine in the vlv mmio funcs This was fumbled in the conversion to per-engine forcewake. Cc: Deepak S Cc: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 97ae8bda7a1e..a7c6de7d6240 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -496,7 +496,7 @@ vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ val = __raw_i915_read##x(dev_priv, reg); \ if (--(*fwcount) == 0) \ (dev_priv)->uncore.funcs.force_wake_put(dev_priv, \ - FORCEWAKE_ALL); \ + fwengine); \ } else { \ val = __raw_i915_read##x(dev_priv, reg); \ } \ From 5bc0e85cc6207650535e579b0995aa9574a8ecba Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 27 Nov 2013 20:52:23 +0100 Subject: [PATCH 083/595] drm/i915: make sparse happy for the new vlv mmio read function It doesn't like that we assign 0 to a pointer, it wants the real NULL. On closer look that initialization is actually bogus, and the compiler can easily see that we never use it unitialized. So let's just drop this. Cc: Deepak S Cc: Jesse Barnes Reported-by: kbuild test robot Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index a7c6de7d6240..d511e00095ac 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -479,7 +479,7 @@ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ static u##x \ vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ unsigned fwengine = 0; \ - unsigned *fwcount = 0; \ + unsigned *fwcount; \ REG_READ_HEADER(x); \ if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) { \ fwengine = FORCEWAKE_RENDER; \ From 84fcb46977e57bafba40bde32067bacc1e510f9c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 27 Nov 2013 16:03:01 +0100 Subject: [PATCH 084/595] drm/i915/sdvo: Fix up debug output to not split lines It leads to a big mess when stuff interleaves. Especially with the new patch I've submitted for the drm core to no longer artificially split up debug messages. v2: The size parameter to snprintf includes the terminating 0, but the return value does not. Adjust the logic accordingly. Spotted by Mika. Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sdvo.c | 55 +++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index a583e8f718a7..e4f9918ab859 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -413,23 +413,34 @@ static const struct _sdvo_cmd_name { static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, const void *args, int args_len) { - int i; + int i, pos = 0; +#define BUF_LEN 256 + char buffer[BUF_LEN]; - DRM_DEBUG_KMS("%s: W: %02X ", - SDVO_NAME(intel_sdvo), cmd); - for (i = 0; i < args_len; i++) - DRM_LOG_KMS("%02X ", ((u8 *)args)[i]); - for (; i < 8; i++) - DRM_LOG_KMS(" "); +#define BUF_PRINT(args...) \ + pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args) + + + for (i = 0; i < args_len; i++) { + BUF_PRINT("%02X ", ((u8 *)args)[i]); + } + for (; i < 8; i++) { + BUF_PRINT(" "); + } for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name); + BUF_PRINT("(%s)", sdvo_cmd_names[i].name); break; } } - if (i == ARRAY_SIZE(sdvo_cmd_names)) - DRM_LOG_KMS("(%02X)", cmd); - DRM_LOG_KMS("\n"); + if (i == ARRAY_SIZE(sdvo_cmd_names)) { + BUF_PRINT("(%02X)", cmd); + } + BUG_ON(pos >= BUF_LEN - 1); +#undef BUF_PRINT +#undef BUF_LEN + + DRM_DEBUG_KMS("%s: W: %02X %s\n", SDVO_NAME(intel_sdvo), cmd, buffer); } static const char *cmd_status_names[] = { @@ -512,9 +523,10 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, { u8 retry = 15; /* 5 quick checks, followed by 10 long checks */ u8 status; - int i; + int i, pos = 0; +#define BUF_LEN 256 + char buffer[BUF_LEN]; - DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo)); /* * The documentation states that all commands will be @@ -551,10 +563,13 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, goto log_fail; } +#define BUF_PRINT(args...) \ + pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args) + if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - DRM_LOG_KMS("(%s)", cmd_status_names[status]); + BUF_PRINT("(%s)", cmd_status_names[status]); else - DRM_LOG_KMS("(??? %d)", status); + BUF_PRINT("(??? %d)", status); if (status != SDVO_CMD_STATUS_SUCCESS) goto log_fail; @@ -565,13 +580,17 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i])) goto log_fail; - DRM_LOG_KMS(" %02X", ((u8 *)response)[i]); + BUF_PRINT(" %02X", ((u8 *)response)[i]); } - DRM_LOG_KMS("\n"); + BUG_ON(pos >= BUF_LEN - 1); +#undef BUF_PRINT +#undef BUF_LEN + + DRM_DEBUG_KMS("%s: R: %s\n", SDVO_NAME(intel_sdvo), buffer); return true; log_fail: - DRM_LOG_KMS("... failed\n"); + DRM_DEBUG_KMS("%s: R: ... failed\n", SDVO_NAME(intel_sdvo)); return false; } From 2f0aa30425414f3105bc29dd39bfdb40cb684393 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 15 Nov 2013 09:32:11 -0800 Subject: [PATCH 085/595] drm/i915/vlv: use a lower RC6 timeout on VLV We use timeout mode, and we need to lower the timeout to get good RC6 residency when loads are running. This gets me from 0% residency during glxgears to 77%, which is a pretty good improvement. This value also matches the current BWG recommentations. Tested-by: "Meng, Mengmeng" Signed-off-by: Jesse Barnes Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1659265a7f7a..2d74ae83b175 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4110,7 +4110,7 @@ static void valleyview_enable_rps(struct drm_device *dev) for_each_ring(ring, dev_priv, i) I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10); - I915_WRITE(GEN6_RC6_THRESHOLD, 0xc350); + I915_WRITE(GEN6_RC6_THRESHOLD, 0x557); /* allows RC6 residency counter to work */ I915_WRITE(VLV_COUNTER_CONTROL, From 6b88f295690d3340fcbd01c1ff46991ea4f83c9f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 15 Nov 2013 09:32:12 -0800 Subject: [PATCH 086/595] drm/i915/vlv: use parallel context restore when coming out of RC6 Setting this bit restores all ring contexts in parallel rather than serially. Matches current BWG recommendations. Tested-by: "Meng, Mengmeng" Signed-off-by: Jesse Barnes Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2658d975279b..3be449d884a7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4900,6 +4900,7 @@ #define GEN6_RC_CTL_RC6_ENABLE (1<<18) #define GEN6_RC_CTL_RC1e_ENABLE (1<<20) #define GEN6_RC_CTL_RC7_ENABLE (1<<22) +#define VLV_RC_CTL_CTX_RST_PARALLEL (1<<24) #define GEN7_RC_CTL_TO_MODE (1<<28) #define GEN6_RC_CTL_EI_MODE(x) ((x)<<27) #define GEN6_RC_CTL_HW_ENABLE (1<<31) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2d74ae83b175..eac7c4eb345c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4118,7 +4118,7 @@ static void valleyview_enable_rps(struct drm_device *dev) VLV_MEDIA_RC6_COUNT_EN | VLV_RENDER_RC6_COUNT_EN)); if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE) - rc6_mode = GEN7_RC_CTL_TO_MODE; + rc6_mode = GEN7_RC_CTL_TO_MODE | VLV_RC_CTL_CTX_RST_PARALLEL; intel_print_rc6_info(dev, rc6_mode); From 48e9212021d920fe91046ad078e1070524844059 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 26 Nov 2013 11:25:54 -0800 Subject: [PATCH 087/595] drm/i915: drop DRM_ERROR in intel_fbdev init This should just be a debug. Add another debug msg to the inherit path while we're at it. Signed-off-by: Jesse Barnes Reviewed-by: Damien Lespiau Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=72098 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index fdb6dc92a7ab..284c3eb066f6 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -127,11 +127,12 @@ static int intelfb_create(struct drm_fb_helper *helper, mutex_lock(&dev->struct_mutex); if (!intel_fb->obj) { - DRM_ERROR("no BIOS fb, allocating a new one\n"); + DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); ret = intelfb_alloc(helper, sizes); if (ret) goto out_unlock; } else { + DRM_DEBUG_KMS("re-using BIOS fb\n"); sizes->fb_width = intel_fb->base.width; sizes->fb_height = intel_fb->base.height; } From ddf9c536295b9d7fcfd0bfc377593b41f2a4dc02 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 27 Nov 2013 22:02:02 +0200 Subject: [PATCH 088/595] drm/i915: add intel_display_power_enabled_sw() for use in atomic ctx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atm we call intel_display_power_enabled() from i915_capture_error_state() in IRQ context and then take a mutex. To fix this add a new intel_display_power_enabled_sw() which returns the domain state based on software tracking as opposed to reading the actual HW state. Since we use domain_use_count for this without locking on the reader side make sure we increase the counter only after enabling all required power wells and decrease it before disabling any of these power wells. Regression introduced in commit 1b02383464b4a915627ef3b8fd0ad7f07168c54c Author: Imre Deak Date:   Tue Sep 24 16:17:09 2013 +0300     drm/i915: support for multiple power wells Note that atm we depend on the value returned by intel_display_power_enabled_sw() in i915_capture_error_state() to avoid unclaimed register access reports. This was never guaranteed though, since another thread can disable the power concurrently. If this is a problem we need another explicit way to disable the reporting during error captures. v2: - remove barriers as the caller can't depend on the value returned from i915_capture_error_state_sw() anyway (Ville) - dump the state of pipe/transcoder power domain state (Daniel) Reported-by: Chris Wilson Signed-off-by: Imre Deak Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/intel_display.c | 15 ++++++++++++--- drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 24 ++++++++++++++++-------- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6b18b4714d7e..64ed8f4d991f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -976,9 +976,7 @@ struct i915_power_domains { int power_well_count; struct mutex lock; -#if IS_ENABLED(CONFIG_DEBUG_FS) int domain_use_count[POWER_DOMAIN_NUM]; -#endif struct i915_power_well *power_wells; }; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ca467cb3c1b4..5a79088e6da1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11317,6 +11317,7 @@ struct intel_display_error_state { } cursor[I915_MAX_PIPES]; struct intel_pipe_error_state { + bool power_domain_on; u32 source; } pipe[I915_MAX_PIPES]; @@ -11331,6 +11332,7 @@ struct intel_display_error_state { } plane[I915_MAX_PIPES]; struct intel_transcoder_error_state { + bool power_domain_on; enum transcoder cpu_transcoder; u32 conf; @@ -11368,7 +11370,9 @@ intel_display_capture_error_state(struct drm_device *dev) error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER); for_each_pipe(i) { - if (!intel_display_power_enabled(dev, POWER_DOMAIN_PIPE(i))) + error->pipe[i].power_domain_on = + intel_display_power_enabled_sw(dev, POWER_DOMAIN_PIPE(i)); + if (!error->pipe[i].power_domain_on) continue; if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) { @@ -11404,8 +11408,9 @@ intel_display_capture_error_state(struct drm_device *dev) for (i = 0; i < error->num_transcoders; i++) { enum transcoder cpu_transcoder = transcoders[i]; - if (!intel_display_power_enabled(dev, - POWER_DOMAIN_TRANSCODER(cpu_transcoder))) + error->transcoder[i].power_domain_on = + intel_display_power_enabled_sw(dev, POWER_DOMAIN_PIPE(i)); + if (!error->transcoder[i].power_domain_on) continue; error->transcoder[i].cpu_transcoder = cpu_transcoder; @@ -11440,6 +11445,8 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m, error->power_well_driver); for_each_pipe(i) { err_printf(m, "Pipe [%d]:\n", i); + err_printf(m, " Power: %s\n", + error->pipe[i].power_domain_on ? "on" : "off"); err_printf(m, " SRC: %08x\n", error->pipe[i].source); err_printf(m, "Plane [%d]:\n", i); @@ -11465,6 +11472,8 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m, for (i = 0; i < error->num_transcoders; i++) { err_printf(m, "CPU transcoder: %c\n", transcoder_name(error->transcoder[i].cpu_transcoder)); + err_printf(m, " Power: %s\n", + error->transcoder[i].power_domain_on ? "on" : "off"); err_printf(m, " CONF: %08x\n", error->transcoder[i].conf); err_printf(m, " HTOTAL: %08x\n", error->transcoder[i].htotal); err_printf(m, " HBLANK: %08x\n", error->transcoder[i].hblank); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 02312810374d..5dea38967523 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -842,6 +842,8 @@ int intel_power_domains_init(struct drm_device *dev); void intel_power_domains_remove(struct drm_device *dev); bool intel_display_power_enabled(struct drm_device *dev, enum intel_display_power_domain domain); +bool intel_display_power_enabled_sw(struct drm_device *dev, + enum intel_display_power_domain domain); void intel_display_power_get(struct drm_device *dev, enum intel_display_power_domain domain); void intel_display_power_put(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index eac7c4eb345c..ff47520f8d40 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5641,6 +5641,17 @@ static bool hsw_power_well_enabled(struct drm_device *dev, (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED); } +bool intel_display_power_enabled_sw(struct drm_device *dev, + enum intel_display_power_domain domain) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_power_domains *power_domains; + + power_domains = &dev_priv->power_domains; + + return power_domains->domain_use_count[domain]; +} + bool intel_display_power_enabled(struct drm_device *dev, enum intel_display_power_domain domain) { @@ -5761,12 +5772,11 @@ void intel_display_power_get(struct drm_device *dev, mutex_lock(&power_domains->lock); -#if IS_ENABLED(CONFIG_DEBUG_FS) - power_domains->domain_use_count[domain]++; -#endif for_each_power_well(i, power_well, BIT(domain), power_domains) __intel_power_well_get(dev, power_well); + power_domains->domain_use_count[domain]++; + mutex_unlock(&power_domains->lock); } @@ -5782,13 +5792,11 @@ void intel_display_power_put(struct drm_device *dev, mutex_lock(&power_domains->lock); - for_each_power_well_rev(i, power_well, BIT(domain), power_domains) - __intel_power_well_put(dev, power_well); - -#if IS_ENABLED(CONFIG_DEBUG_FS) WARN_ON(!power_domains->domain_use_count[domain]); power_domains->domain_use_count[domain]--; -#endif + + for_each_power_well_rev(i, power_well, BIT(domain), power_domains) + __intel_power_well_put(dev, power_well); mutex_unlock(&power_domains->lock); } From c19de8eb67f745a7b16a7587ed002e6916ab2a5d Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 28 Nov 2013 15:29:18 +0000 Subject: [PATCH 089/595] drm/i915: Return a drm_mode_status enum in the mode_valid vfuncs We had some mode_valid() vfuncs returning an int, others the enum. Let's use the latter everywhere. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 5 +++-- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_dsi.c | 5 +++-- drivers/gpu/drm/i915/intel_dvo.c | 5 +++-- drivers/gpu/drm/i915/intel_hdmi.c | 5 +++-- drivers/gpu/drm/i915/intel_lvds.c | 5 +++-- drivers/gpu/drm/i915/intel_sdvo.c | 5 +++-- 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index b5b1b9b23adf..e2e39e65f109 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -222,8 +222,9 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) intel_modeset_check_state(connector->dev); } -static int intel_crt_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_crt_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3b22e726585e..82de200efa05 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -142,7 +142,7 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes) return (max_link_clock * max_lanes * 8) / 10; } -static int +static enum drm_mode_status intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index d257b093ca68..7b9b350d29ae 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -251,8 +251,9 @@ static void intel_dsi_get_config(struct intel_encoder *encoder, /* XXX: read flags, set to adjusted_mode */ } -static int intel_dsi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_dsi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 3c7736546856..eeff998e52ef 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -234,8 +234,9 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) intel_modeset_check_state(connector->dev); } -static int intel_dvo_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_dvo_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct intel_dvo *intel_dvo = intel_attached_dvo(connector); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index d0c81b170149..6a6ad0c78dc7 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -853,8 +853,9 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi) return 225000; } -static int intel_hdmi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_hdmi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector))) return MODE_CLOCK_HIGH; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index c3b4da7895ed..3deb58e2f394 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -256,8 +256,9 @@ static void intel_disable_lvds(struct intel_encoder *encoder) POSTING_READ(lvds_encoder->reg); } -static int intel_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_lvds_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index e4f9918ab859..2abeab09e883 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1536,8 +1536,9 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) intel_modeset_check_state(connector->dev); } -static int intel_sdvo_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_sdvo_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); From be46ffd48ba34189336c6fe420ff3370dcd36c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 29 Nov 2013 13:21:49 +0200 Subject: [PATCH 090/595] drm/i915: Fix port name in vlv_wait_port_ready() timeout warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're currently misprinting the port name when vlv_wait_port_ready() times out. Fix it by using port_name(). Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5a79088e6da1..0332d7ca892d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1513,7 +1513,7 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv, if (wait_for((I915_READ(DPLL(0)) & port_mask) == 0, 1000)) WARN(1, "timed out waiting for port %c ready: 0x%08x\n", - 'B' + dport->port, I915_READ(DPLL(0))); + port_name(dport->port), I915_READ(DPLL(0))); } /** From c8ca9d6aa676b7a26ae9dce6e50222519380e483 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 23 Aug 2013 10:21:21 +0800 Subject: [PATCH 091/595] drm/rcar-du: fix return value check in rcar_du_lvdsenc_get_resources() In case of error, the function devm_ioremap_resource() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Also remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c index a0f6a1781925..fe1f6f59f539 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c @@ -144,18 +144,9 @@ static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds, sprintf(name, "lvds.%u", lvds->index); mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); - if (mem == NULL) { - dev_err(&pdev->dev, "failed to get memory resource for %s\n", - name); - return -EINVAL; - } - lvds->mmio = devm_ioremap_resource(&pdev->dev, mem); - if (lvds->mmio == NULL) { - dev_err(&pdev->dev, "failed to remap memory resource for %s\n", - name); - return -ENOMEM; - } + if (IS_ERR(lvds->mmio)) + return PTR_ERR(lvds->mmio); lvds->clock = devm_clk_get(&pdev->dev, name); if (IS_ERR(lvds->clock)) { From f5abcc4674c3aa9d745772bb3fd51db60c93161f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 13 Nov 2013 14:38:03 +0100 Subject: [PATCH 092/595] drm/rcar-du: Don't cast crtc to rcrtc twice in the same function Reuse the previously cast variable instead. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index a9d24e4bf792..d2af2bcf3eae 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -413,7 +413,7 @@ static int rcar_du_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, rcrtc->plane->src_x = x; rcrtc->plane->src_y = y; - rcar_du_crtc_update_base(to_rcar_crtc(crtc)); + rcar_du_crtc_update_base(rcrtc); return 0; } From eb86301f293da3c362db729a9f40ddb25755902b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 13 Nov 2013 14:26:01 +0100 Subject: [PATCH 093/595] drm/rcar-du: Update plane pitch in .mode_set_base() operation When setting a new frame buffer with the mode set base operation the pitch value might change. Set the hardware plane pitch register at the same time as the plane base address in the rcar_du_plane_update_base() function to make sure the pitch value always matches the frame buffer. Cc: stable@vger.kernel.org Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 1 - drivers/gpu/drm/rcar-du/rcar_du_plane.c | 21 +++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index d2af2bcf3eae..fbf4be316d0b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -371,7 +371,6 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc, goto error; rcrtc->plane->format = format; - rcrtc->plane->pitch = crtc->fb->pitches[0]; rcrtc->plane->src_x = x; rcrtc->plane->src_y = y; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 53000644733f..3fb69d9ae61b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -104,6 +104,15 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane) { struct rcar_du_group *rgrp = plane->group; unsigned int index = plane->hwindex; + u32 mwr; + + /* Memory pitch (expressed in pixels) */ + if (plane->format->planes == 2) + mwr = plane->pitch; + else + mwr = plane->pitch * 8 / plane->format->bpp; + + rcar_du_plane_write(rgrp, index, PnMWR, mwr); /* The Y position is expressed in raster line units and must be doubled * for 32bpp formats, according to the R8A7790 datasheet. No mention of @@ -133,6 +142,8 @@ void rcar_du_plane_compute_base(struct rcar_du_plane *plane, { struct drm_gem_cma_object *gem; + plane->pitch = fb->pitches[0]; + gem = drm_fb_cma_get_gem_obj(fb, 0); plane->dma[0] = gem->paddr + fb->offsets[0]; @@ -209,7 +220,6 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane, struct rcar_du_group *rgrp = plane->group; u32 ddcr2 = PnDDCR2_CODE; u32 ddcr4; - u32 mwr; /* Data format * @@ -240,14 +250,6 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane, rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2); rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4); - /* Memory pitch (expressed in pixels) */ - if (plane->format->planes == 2) - mwr = plane->pitch; - else - mwr = plane->pitch * 8 / plane->format->bpp; - - rcar_du_plane_write(rgrp, index, PnMWR, mwr); - /* Destination position and size */ rcar_du_plane_write(rgrp, index, PnDSXR, plane->width); rcar_du_plane_write(rgrp, index, PnDSYR, plane->height); @@ -309,7 +311,6 @@ rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, rplane->crtc = crtc; rplane->format = format; - rplane->pitch = fb->pitches[0]; rplane->src_x = src_x >> 16; rplane->src_y = src_y >> 16; From e8355e0dc48c966477e6b427e7043ea71698776a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 13 Nov 2013 13:33:45 +0100 Subject: [PATCH 094/595] drm/rcar-du: Split features and quirks 128-byte pitch alignement is not a hardware feature, it's a hardware bug. Split it from the features field into a new quirks field. New quirks will be added to support the R8A7791 SoC. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 4 ++-- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 13 +++++++++++-- drivers/gpu/drm/rcar-du/rcar_du_kms.c | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 0023f9719cf1..a0ffacb4b80b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -249,8 +249,8 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = { }; static const struct rcar_du_device_info rcar_du_r8a7790_info = { - .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_ALIGN_128B - | RCAR_DU_FEATURE_DEFR8, + .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8, + .quirks = RCAR_DU_QUIRK_ALIGN_128B, .num_crtcs = 3, .routes = { /* R8A7790 has one RGB output, two LVDS outputs and one diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 65d2d636b002..7ca98f352479 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -28,8 +28,9 @@ struct rcar_du_device; struct rcar_du_lvdsenc; #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */ -#define RCAR_DU_FEATURE_ALIGN_128B (1 << 1) /* Align pitches to 128 bytes */ -#define RCAR_DU_FEATURE_DEFR8 (1 << 2) /* Has DEFR8 register */ +#define RCAR_DU_FEATURE_DEFR8 (1 << 1) /* Has DEFR8 register */ + +#define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ /* * struct rcar_du_output_routing - Output routing specification @@ -48,12 +49,14 @@ struct rcar_du_output_routing { /* * struct rcar_du_device_info - DU model-specific information * @features: device features (RCAR_DU_FEATURE_*) + * @quirks: device quirks (RCAR_DU_QUIRK_*) * @num_crtcs: total number of CRTCs * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*) * @num_lvds: number of internal LVDS encoders */ struct rcar_du_device_info { unsigned int features; + unsigned int quirks; unsigned int num_crtcs; struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX]; unsigned int num_lvds; @@ -84,6 +87,12 @@ static inline bool rcar_du_has(struct rcar_du_device *rcdu, return rcdu->info->features & feature; } +static inline bool rcar_du_needs(struct rcar_du_device *rcdu, + unsigned int quirk) +{ + return rcdu->info->quirks & quirk; +} + static inline u32 rcar_du_read(struct rcar_du_device *rcdu, u32 reg) { return ioread32(rcdu->mmio + reg); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index b31ac080c4a7..fbeabd9a281f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -119,7 +119,7 @@ int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, /* The R8A7779 DU requires a 16 pixels pitch alignment as documented, * but the R8A7790 DU seems to require a 128 bytes pitch alignment. */ - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_ALIGN_128B)) + if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B)) align = 128; else align = 16 * args->bpp / 8; @@ -144,7 +144,7 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, return ERR_PTR(-EINVAL); } - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_ALIGN_128B)) + if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B)) align = 128; else align = 16 * format->bpp / 8; From 5cca30ebe089be23bc2588c4b76af69e89b3b639 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 13 Nov 2013 13:35:15 +0100 Subject: [PATCH 095/595] drm/rcar-du: Add LVDS_LANES quirk LVDS lanes 1 and 3 are switched in ES1 hardware (R8A7790). The problem has been fixed in newer revisions, add a quirk to make the workaround selectable. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 2 +- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 + drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c | 15 ++++++++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index a0ffacb4b80b..4eee02f89965 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -250,7 +250,7 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = { static const struct rcar_du_device_info rcar_du_r8a7790_info = { .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8, - .quirks = RCAR_DU_QUIRK_ALIGN_128B, + .quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES, .num_crtcs = 3, .routes = { /* R8A7790 has one RGB output, two LVDS outputs and one diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 7ca98f352479..e31b735d3f25 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -31,6 +31,7 @@ struct rcar_du_lvdsenc; #define RCAR_DU_FEATURE_DEFR8 (1 << 1) /* Has DEFR8 register */ #define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ +#define RCAR_DU_QUIRK_LVDS_LANES (1 << 1) /* LVDS lanes 1 and 3 inverted */ /* * struct rcar_du_output_routing - Output routing specification diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c index fe1f6f59f539..df30a075d793 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c @@ -44,6 +44,7 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, const struct drm_display_mode *mode = &rcrtc->crtc.mode; unsigned int freq = mode->clock; u32 lvdcr0; + u32 lvdhcr; u32 pllcr; int ret; @@ -72,15 +73,19 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, * VSYNC -> CTRL1 * DISP -> CTRL2 * 0 -> CTRL3 - * - * Channels 1 and 3 are switched on ES1. */ rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO | LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC | LVDCTRCR_CTR0SEL_HSYNC); - rcar_lvds_write(lvds, LVDCHCR, - LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3) | - LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1)); + + if (rcar_du_needs(lvds->dev, RCAR_DU_QUIRK_LVDS_LANES)) + lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3) + | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1); + else + lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1) + | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3); + + rcar_lvds_write(lvds, LVDCHCR, lvdhcr); /* Select the input, hardcode mode 0, enable LVDS operation and turn * bias circuitry on. From 29ee6469e6138115420236a71c6b89bf8af1788a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 11 Nov 2013 19:08:13 +0100 Subject: [PATCH 096/595] drm/rcar-du: Add support for the r8a7791 DU The r8a7791 DU is a stripped-down version of the r8a7790 DU with two CRTCs and a single LVDS output. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 4eee02f89965..5536811a8cbe 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -272,9 +272,29 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = { .num_lvds = 2, }; +static const struct rcar_du_device_info rcar_du_r8a7791_info = { + .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8, + .num_crtcs = 2, + .routes = { + /* R8A7791 has one RGB output, one LVDS output and one + * (currently unsupported) TCON output. + */ + [RCAR_DU_OUTPUT_DPAD0] = { + .possible_crtcs = BIT(1), + .encoder_type = DRM_MODE_ENCODER_NONE, + }, + [RCAR_DU_OUTPUT_LVDS0] = { + .possible_crtcs = BIT(0), + .encoder_type = DRM_MODE_ENCODER_LVDS, + }, + }, + .num_lvds = 1, +}; + static const struct platform_device_id rcar_du_id_table[] = { { "rcar-du-r8a7779", (kernel_ulong_t)&rcar_du_r8a7779_info }, { "rcar-du-r8a7790", (kernel_ulong_t)&rcar_du_r8a7790_info }, + { "rcar-du-r8a7791", (kernel_ulong_t)&rcar_du_r8a7791_info }, { } }; From 5be19d910b9fc40102af475b3d1e6f2e0e9770d5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 9 Oct 2013 10:47:12 +0200 Subject: [PATCH 097/595] drm/i915/lvds: don't restore hw state in the lid notifier for pch platforms It's a pain for two reasons: - The vga plane redisablign requires actual legacy vgao i/o to pull of. The hw engineers really botched this one here :( - There seem to be some BIOS out there which send out lid events when unplugging. Together with our broken DP code, which disables the port when the cable is lost, this results in an immediate modeset call, which can hang on the wait for outstanding flips. - Also we don't want to force a modeset on machines where it's not really needed, see the referenced bug. We might want to extend this in general to also all machines that support opregion, since there the BIOS supposedly should manage the gfx hardware more cooperatively. v2: Pimp commit message a bit. Cc: Roland Dreier References: https://bugs.freedesktop.org/show_bug.cgi?id=65486 Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lvds.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3deb58e2f394..4c8553ea82f7 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -447,9 +447,19 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, if (dev_priv->modeset_restore == MODESET_DONE) goto exit; - drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, true); - drm_modeset_unlock_all(dev); + /* + * Some old platform's BIOS love to wreak havoc while the lid is closed. + * We try to detect this here and undo any damage. The split for PCH + * platforms is rather conservative and a bit arbitrary expect that on + * those platforms VGA disabling requires actual legacy VGA I/O access, + * and as part of the cleanup in the hw state restore we also redisable + * the vga plane. + */ + if (!HAS_PCH_SPLIT(dev)) { + drm_modeset_lock_all(dev); + intel_modeset_setup_hw_state(dev, true); + drm_modeset_unlock_all(dev); + } dev_priv->modeset_restore = MODESET_DONE; From e1b22732485396dda9b8eab90cdd1c636efc0a3e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 3 Dec 2013 13:46:58 +0000 Subject: [PATCH 098/595] drm/i915: Fix copy/paste DP vs eDP error in comment It's all about tiny details. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e5eecfd5e47c..cc0a63349a9c 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -73,7 +73,7 @@ static const u32 hsw_ddi_translations_hdmi[] = { }; static const u32 bdw_ddi_translations_edp[] = { - 0x00FFFFFF, 0x00000012, /* DP parameters */ + 0x00FFFFFF, 0x00000012, /* eDP parameters */ 0x00EBAFFF, 0x00020011, 0x00C71FFF, 0x0006000F, 0x00FFFFFF, 0x00020011, From 7e11f9f4cacf71847716cec9d103b25d4c21e7a0 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 3 Dec 2013 13:47:00 +0000 Subject: [PATCH 099/595] drm/i915: Remove if 0'ed static arrays Sweeping some dead code away. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 82de200efa05..5f97be6f22ed 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1941,18 +1941,6 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ DP_LINK_STATUS_SIZE); } -#if 0 -static char *voltage_names[] = { - "0.4V", "0.6V", "0.8V", "1.2V" -}; -static char *pre_emph_names[] = { - "0dB", "3.5dB", "6dB", "9.5dB" -}; -static char *link_train_names[] = { - "pattern 1", "pattern 2", "idle", "off" -}; -#endif - /* * These are source-specific values; current Intel hardware supports * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB From ed5ca77ed7505cd389003a6d35ca1b7365429d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 2 Dec 2013 19:00:45 +0200 Subject: [PATCH 100/595] drm/i915: Avoid div-by-zero in clock calculation funcs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that the N and P dividers don't cause a divide by zero. This shouldn't happen under normal circumstances, but can happen eg. under simulation. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0332d7ca892d..66b39dbaf12c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -329,6 +329,8 @@ static void vlv_clock(int refclk, intel_clock_t *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n == 0 || clock->p == 0)) + return; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } @@ -430,6 +432,8 @@ static void pineview_clock(int refclk, intel_clock_t *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n == 0 || clock->p == 0)) + return; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } @@ -443,6 +447,8 @@ static void i9xx_clock(int refclk, intel_clock_t *clock) { clock->m = i9xx_dpll_compute_m(clock); clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n + 2 == 0 || clock->p == 0)) + return; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } From e445123975141a1f14b3c8f2aa96588f62a0c156 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 2 Dec 2013 11:26:09 -0200 Subject: [PATCH 101/595] drm/i915: use __packed instead of __attribute__((packed)) Checkpatch tells me WARNING: __packed is preferred over __attribute__((packed)) so switch over to __packed across the driver before adding new packed structs. Signed-off-by: Jani Nikula Signed-off-by: Rodrigo Vivi Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.h | 48 +++++++++++++------------- drivers/gpu/drm/i915/intel_opregion.c | 8 ++--- drivers/gpu/drm/i915/intel_sdvo_regs.h | 40 ++++++++++----------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index f580a2b0ddd3..81ed58cb7b31 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -39,7 +39,7 @@ struct vbt_header { u8 reserved0; u32 bdb_offset; /**< from beginning of VBT */ u32 aim_offset[4]; /**< from beginning of VBT */ -} __attribute__((packed)); +} __packed; struct bdb_header { u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ @@ -65,7 +65,7 @@ struct vbios_data { u8 rsvd4; /* popup memory size */ u8 resize_pci_bios; u8 rsvd5; /* is crt already on ddc2 */ -} __attribute__((packed)); +} __packed; /* * There are several types of BIOS data blocks (BDBs), each block has @@ -142,7 +142,7 @@ struct bdb_general_features { u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */ u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */ u8 rsvd11:3; /* finish byte */ -} __attribute__((packed)); +} __packed; /* pre-915 */ #define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ @@ -225,7 +225,7 @@ struct old_child_dev_config { u8 dvo2_wiring; u16 extended_type; u8 dvo_function; -} __attribute__((packed)); +} __packed; /* This one contains field offsets that are known to be common for all BDB * versions. Notice that the meaning of the contents contents may still change, @@ -238,7 +238,7 @@ struct common_child_dev_config { u8 not_common2[2]; u8 ddc_pin; u16 edid_ptr; -} __attribute__((packed)); +} __packed; /* This field changes depending on the BDB version, so the most reliable way to * read it is by checking the BDB version and reading the raw pointer. */ @@ -279,7 +279,7 @@ struct bdb_general_definitions { * sizeof(child_device_config); */ union child_device_config devices[0]; -} __attribute__((packed)); +} __packed; struct bdb_lvds_options { u8 panel_type; @@ -293,7 +293,7 @@ struct bdb_lvds_options { u8 lvds_edid:1; u8 rsvd2:1; u8 rsvd4; -} __attribute__((packed)); +} __packed; /* LFP pointer table contains entries to the struct below */ struct bdb_lvds_lfp_data_ptr { @@ -303,12 +303,12 @@ struct bdb_lvds_lfp_data_ptr { u8 dvo_table_size; u16 panel_pnp_id_offset; u8 pnp_table_size; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_ptrs { u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ struct bdb_lvds_lfp_data_ptr ptr[16]; -} __attribute__((packed)); +} __packed; /* LFP data has 3 blocks per entry */ struct lvds_fp_timing { @@ -325,7 +325,7 @@ struct lvds_fp_timing { u32 pfit_reg; u32 pfit_reg_val; u16 terminator; -} __attribute__((packed)); +} __packed; struct lvds_dvo_timing { u16 clock; /**< In 10khz */ @@ -353,7 +353,7 @@ struct lvds_dvo_timing { u8 vsync_positive:1; u8 hsync_positive:1; u8 rsvd2:1; -} __attribute__((packed)); +} __packed; struct lvds_pnp_id { u16 mfg_name; @@ -361,17 +361,17 @@ struct lvds_pnp_id { u32 serial; u8 mfg_week; u8 mfg_year; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_entry { struct lvds_fp_timing fp_timing; struct lvds_dvo_timing dvo_timing; struct lvds_pnp_id pnp_id; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data { struct bdb_lvds_lfp_data_entry data[16]; -} __attribute__((packed)); +} __packed; struct aimdb_header { char signature[16]; @@ -379,12 +379,12 @@ struct aimdb_header { u16 aimdb_version; u16 aimdb_header_size; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct aimdb_block { u8 aimdb_id; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct vch_panel_data { u16 fp_timing_offset; @@ -395,12 +395,12 @@ struct vch_panel_data { u8 text_fitting_size; u16 graphics_fitting_offset; u8 graphics_fitting_size; -} __attribute__((packed)); +} __packed; struct vch_bdb_22 { struct aimdb_block aimdb_block; struct vch_panel_data panels[16]; -} __attribute__((packed)); +} __packed; struct bdb_sdvo_lvds_options { u8 panel_backlight; @@ -416,7 +416,7 @@ struct bdb_sdvo_lvds_options { u8 panel_misc_bits_2; u8 panel_misc_bits_3; u8 panel_misc_bits_4; -} __attribute__((packed)); +} __packed; #define BDB_DRIVER_FEATURE_NO_LVDS 0 @@ -462,7 +462,7 @@ struct bdb_driver_features { u8 hdmi_termination; u8 custom_vbt_version; -} __attribute__((packed)); +} __packed; #define EDP_18BPP 0 #define EDP_24BPP 1 @@ -487,14 +487,14 @@ struct edp_power_seq { u16 t9; u16 t10; u16 t11_t12; -} __attribute__ ((packed)); +} __packed; struct edp_link_params { u8 rate:4; u8 lanes:4; u8 preemphasis:4; u8 vswing:4; -} __attribute__ ((packed)); +} __packed; struct bdb_edp { struct edp_power_seq power_seqs[16]; @@ -505,7 +505,7 @@ struct bdb_edp { /* ith bit indicates enabled/disabled for (i+1)th panel */ u16 edp_s3d_feature; u16 edp_t3_optimization; -} __attribute__ ((packed)); +} __packed; void intel_setup_bios(struct drm_device *dev); int intel_parse_bios(struct drm_device *dev); @@ -733,6 +733,6 @@ struct bdb_mipi { u32 hl_switch_cnt; u32 lp_byte_clk; u32 clk_lane_switch_cnt; -} __attribute__((packed)); +} __packed; #endif /* _I830_BIOS_H_ */ diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 6506df26ac9e..853d13ea055f 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -64,7 +64,7 @@ struct opregion_header { u8 driver_ver[16]; u32 mboxes; u8 reserved[164]; -} __attribute__((packed)); +} __packed; /* OpRegion mailbox #1: public ACPI methods */ struct opregion_acpi { @@ -86,7 +86,7 @@ struct opregion_acpi { u32 cnot; /* current OS notification */ u32 nrdy; /* driver status */ u8 rsvd2[60]; -} __attribute__((packed)); +} __packed; /* OpRegion mailbox #2: SWSCI */ struct opregion_swsci { @@ -94,7 +94,7 @@ struct opregion_swsci { u32 parm; /* command parameters */ u32 dslp; /* driver sleep time-out */ u8 rsvd[244]; -} __attribute__((packed)); +} __packed; /* OpRegion mailbox #3: ASLE */ struct opregion_asle { @@ -115,7 +115,7 @@ struct opregion_asle { u32 srot; /* supported rotation angles */ u32 iuer; /* IUER events */ u8 rsvd[86]; -} __attribute__((packed)); +} __packed; /* Driver readiness indicator */ #define ASLE_ARDY_READY (1 << 0) diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 770bdd6ecd9f..2e2d4eb4a00d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -59,7 +59,7 @@ struct intel_sdvo_caps { unsigned int stall_support:1; unsigned int pad:1; u16 output_flags; -} __attribute__((packed)); +} __packed; /* Note: SDVO detailed timing flags match EDID misc flags. */ #define DTD_FLAG_HSYNC_POSITIVE (1 << 1) @@ -94,12 +94,12 @@ struct intel_sdvo_dtd { u8 v_sync_off_high; u8 reserved; } part2; -} __attribute__((packed)); +} __packed; struct intel_sdvo_pixel_clock_range { u16 min; /**< pixel clock, in 10kHz units */ u16 max; /**< pixel clock, in 10kHz units */ -} __attribute__((packed)); +} __packed; struct intel_sdvo_preferred_input_timing_args { u16 clock; @@ -108,7 +108,7 @@ struct intel_sdvo_preferred_input_timing_args { u8 interlace:1; u8 scaled:1; u8 pad:6; -} __attribute__((packed)); +} __packed; /* I2C registers for SDVO */ #define SDVO_I2C_ARG_0 0x07 @@ -162,7 +162,7 @@ struct intel_sdvo_get_trained_inputs_response { unsigned int input0_trained:1; unsigned int input1_trained:1; unsigned int pad:6; -} __attribute__((packed)); +} __packed; /** Returns a struct intel_sdvo_output_flags of active outputs. */ #define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04 @@ -219,7 +219,7 @@ struct intel_sdvo_get_interrupt_event_source_response { unsigned int ambient_light_interrupt:1; unsigned int hdmi_audio_encrypt_change:1; unsigned int pad:6; -} __attribute__((packed)); +} __packed; /** * Selects which input is affected by future input commands. @@ -232,7 +232,7 @@ struct intel_sdvo_get_interrupt_event_source_response { struct intel_sdvo_set_target_input_args { unsigned int target_1:1; unsigned int pad:7; -} __attribute__((packed)); +} __packed; /** * Takes a struct intel_sdvo_output_flags of which outputs are targeted by @@ -370,7 +370,7 @@ struct intel_sdvo_tv_format { unsigned int hdtv_std_eia_7702a_480i_60:1; unsigned int hdtv_std_eia_7702a_480p_60:1; unsigned int pad:3; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_TV_FORMAT 0x28 @@ -401,7 +401,7 @@ struct intel_sdvo_sdtv_resolution_request { unsigned int secam_l:1; unsigned int secam_60:1; unsigned int pad:5; -} __attribute__((packed)); +} __packed; struct intel_sdvo_sdtv_resolution_reply { unsigned int res_320x200:1; @@ -426,7 +426,7 @@ struct intel_sdvo_sdtv_resolution_reply { unsigned int res_1024x768:1; unsigned int res_1280x1024:1; unsigned int pad:5; -} __attribute__((packed)); +} __packed; /* Get supported resolution with squire pixel aspect ratio that can be scaled for the requested HDTV format */ @@ -463,7 +463,7 @@ struct intel_sdvo_hdtv_resolution_request { unsigned int hdtv_std_eia_7702a_480i_60:1; unsigned int hdtv_std_eia_7702a_480p_60:1; unsigned int pad:6; -} __attribute__((packed)); +} __packed; struct intel_sdvo_hdtv_resolution_reply { unsigned int res_640x480:1; @@ -517,7 +517,7 @@ struct intel_sdvo_hdtv_resolution_reply { unsigned int res_1280x768:1; unsigned int pad5:7; -} __attribute__((packed)); +} __packed; /* Get supported power state returns info for encoder and monitor, rely on last SetTargetInput and SetTargetOutput calls */ @@ -557,13 +557,13 @@ struct sdvo_panel_power_sequencing { unsigned int t4_high:2; unsigned int pad:6; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_MAX_BACKLIGHT_LEVEL 0x30 struct sdvo_max_backlight_reply { u8 max_value; u8 default_value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_BACKLIGHT_LEVEL 0x31 #define SDVO_CMD_SET_BACKLIGHT_LEVEL 0x32 @@ -573,14 +573,14 @@ struct sdvo_get_ambient_light_reply { u16 trip_low; u16 trip_high; u16 value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_SET_AMBIENT_LIGHT 0x34 struct sdvo_set_ambient_light_reply { u16 trip_low; u16 trip_high; unsigned int enable:1; unsigned int pad:7; -} __attribute__((packed)); +} __packed; /* Set display power state */ #define SDVO_CMD_SET_DISPLAY_POWER_STATE 0x7d @@ -608,7 +608,7 @@ struct intel_sdvo_enhancements_reply { unsigned int dither:1; unsigned int tv_chroma_filter:1; unsigned int tv_luma_filter:1; -} __attribute__((packed)); +} __packed; /* Picture enhancement limits below are dependent on the current TV format, * and thus need to be queried and set after it. @@ -630,7 +630,7 @@ struct intel_sdvo_enhancements_reply { struct intel_sdvo_enhancement_limits_reply { u16 max_value; u16 default_value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_LVDS_PANEL_INFORMATION 0x7f #define SDVO_CMD_SET_LVDS_PANEL_INFORMATION 0x80 @@ -671,7 +671,7 @@ struct intel_sdvo_enhancement_limits_reply { #define SDVO_CMD_SET_TV_LUMA_FILTER 0x79 struct intel_sdvo_enhancements_arg { u16 value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_DOT_CRAWL 0x70 #define SDVO_CMD_SET_DOT_CRAWL 0x71 @@ -727,4 +727,4 @@ struct intel_sdvo_enhancements_arg { struct intel_sdvo_encode { u8 dvi_rev; u8 hdmi_rev; -} __attribute__ ((packed)); +} __packed; From 54c136d4e525684a3310e3dd76de8ae81d7dbbf7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 2 Dec 2013 09:57:16 +0000 Subject: [PATCH 102/595] drm/i915: Add a timing breadcrumb to panel waits When inspecting reports that boot/suspend/resume times are unusual it would be useful to clearly identify the time we must spend waiting for the hardware to complete its task. In this case we have a notification before we start waiting for the panel to change state, but none afterwards - which would be useful. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5f97be6f22ed..d45b311c1ab6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1037,6 +1037,8 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp, I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); } + + DRM_DEBUG_KMS("Wait complete\n"); } static void ironlake_wait_panel_on(struct intel_dp *intel_dp) From 0d9653014f081eacdeb82b0a8ad0e0d4ce87e3da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 2 Dec 2013 14:23:02 +0200 Subject: [PATCH 103/595] drm/i915: Add REG_WRITE_FOOTER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a REG_WRITE_FOOTER macro as a counterpart to the REG_WRITE_HEADER. The current code has the spin_lock() in the HEADER, but the spin_unlock() is open coded, which looks rather confusing on the first glance. A bit of additional symmetry might help. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index d511e00095ac..ffb6edebd887 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -533,12 +533,15 @@ __gen4_read(64) trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags) +#define REG_WRITE_FOOTER \ + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags) + #define __gen4_write(x) \ static void \ gen4_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ REG_WRITE_HEADER; \ __raw_i915_write##x(dev_priv, reg, val); \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } #define __gen5_write(x) \ @@ -547,7 +550,7 @@ gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace REG_WRITE_HEADER; \ ilk_dummy_write(dev_priv); \ __raw_i915_write##x(dev_priv, reg, val); \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } #define __gen6_write(x) \ @@ -562,7 +565,7 @@ gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } #define __hsw_write(x) \ @@ -579,7 +582,7 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) gen6_gt_check_fifodbg(dev_priv); \ } \ hsw_unclaimed_reg_check(dev_priv, reg); \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } static const u32 gen8_shadowed_regs[] = { @@ -617,7 +620,7 @@ gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace dev_priv->uncore.funcs.force_wake_put(dev_priv, \ FORCEWAKE_ALL); \ } \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } __gen8_write(8) @@ -646,6 +649,7 @@ __gen4_write(64) #undef __gen6_write #undef __gen5_write #undef __gen4_write +#undef REG_WRITE_FOOTER #undef REG_WRITE_HEADER void intel_uncore_init(struct drm_device *dev) From 82f344967cca4d4d0bd3cbcdeddfc6bf00a46fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:29:55 +0200 Subject: [PATCH 104/595] drm/i915: Fix bogus FBC1 defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilons Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3be449d884a7..2d203905bd70 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1028,14 +1028,14 @@ #define FBC_CTL_UNCOMPRESSIBLE (1<<14) #define FBC_CTL_C3_IDLE (1<<13) #define FBC_CTL_STRIDE_SHIFT (5) -#define FBC_CTL_FENCENO (1<<0) +#define FBC_CTL_FENCENO_SHIFT (0) #define FBC_COMMAND 0x0320c #define FBC_CMD_COMPRESS (1<<0) #define FBC_STATUS 0x03210 #define FBC_STAT_COMPRESSING (1<<31) #define FBC_STAT_COMPRESSED (1<<30) #define FBC_STAT_MODIFIED (1<<29) -#define FBC_STAT_CURRENT_LINE (1<<0) +#define FBC_STAT_CURRENT_LINE_SHIFT (0) #define FBC_CONTROL2 0x03214 #define FBC_CTL_FENCE_DBL (0<<4) #define FBC_CTL_IDLE_IMM (0<<2) From c5a44aa012ee86b3dfd0c6050ba34cd6eb412875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:29:58 +0200 Subject: [PATCH 105/595] drm/i915: Fix FBC1 plane checks for gen2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On gen2 and gen3 chipsets FBC is supported only on plane A. Fix (and simplify) the plane checks in intel_update_fbc() accordingly. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ff47520f8d40..d389078f0fe1 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -537,10 +537,10 @@ void intel_update_fbc(struct drm_device *dev) DRM_DEBUG_KMS("mode too large for compression, disabling\n"); goto out_disable; } - if ((IS_I915GM(dev) || IS_I945GM(dev) || IS_HASWELL(dev)) && - intel_crtc->plane != 0) { + if ((INTEL_INFO(dev)->gen < 4 || IS_HASWELL(dev)) && + intel_crtc->plane != PLANE_A) { if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE)) - DRM_DEBUG_KMS("plane not 0, disabling compression\n"); + DRM_DEBUG_KMS("plane not A, disabling compression\n"); goto out_disable; } From 40045465a91cad4e4bcd2691f0bece5f8b2910e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:29:59 +0200 Subject: [PATCH 106/595] drm/i915: Reorganize FBC function pointer initializaition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize the FBC vfuncs on gen2 and gen3 chipsets. Also make a clean split for gen7+ vs. gen5+ vfunc initialization. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d389078f0fe1..ac4a74a41344 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5956,25 +5956,23 @@ void intel_init_pm(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; if (I915_HAS_FBC(dev)) { - if (HAS_PCH_SPLIT(dev)) { + if (INTEL_INFO(dev)->gen >= 7) { dev_priv->display.fbc_enabled = ironlake_fbc_enabled; - if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) - dev_priv->display.enable_fbc = - gen7_enable_fbc; - else - dev_priv->display.enable_fbc = - ironlake_enable_fbc; + dev_priv->display.enable_fbc = gen7_enable_fbc; + dev_priv->display.disable_fbc = ironlake_disable_fbc; + } else if (INTEL_INFO(dev)->gen >= 5) { + dev_priv->display.fbc_enabled = ironlake_fbc_enabled; + dev_priv->display.enable_fbc = ironlake_enable_fbc; dev_priv->display.disable_fbc = ironlake_disable_fbc; } else if (IS_GM45(dev)) { dev_priv->display.fbc_enabled = g4x_fbc_enabled; dev_priv->display.enable_fbc = g4x_enable_fbc; dev_priv->display.disable_fbc = g4x_disable_fbc; - } else if (IS_CRESTLINE(dev)) { + } else { dev_priv->display.fbc_enabled = i8xx_fbc_enabled; dev_priv->display.enable_fbc = i8xx_enable_fbc; dev_priv->display.disable_fbc = i8xx_disable_fbc; } - /* 855GM needs testing */ } /* For cxsr */ From 1f1c2e2468f937cefd6bcb645c959c7b5d9821df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:30:01 +0200 Subject: [PATCH 107/595] drm/i915: Swap primary planes on gen2 for FBC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only plane A is FBC capable on gen2 (like gen3), but the panel fitter is hooked up to pipe B, so we want to prefer pipe B + plane A. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson [danvet: Add the code comment Chris requested in his review.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 14 +++++++++----- drivers/gpu/drm/i915/intel_display.c | 7 +++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 271560080ad5..74918e7afeb5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3139,10 +3139,10 @@ static int i8xx_irq_postinstall(struct drm_device *dev) * Returns true when a page flip has completed. */ static bool i8xx_handle_vblank(struct drm_device *dev, - int pipe, u16 iir) + int plane, int pipe, u32 iir) { drm_i915_private_t *dev_priv = dev->dev_private; - u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe); + u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); if (!drm_handle_vblank(dev, pipe)) return false; @@ -3150,7 +3150,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev, if ((iir & flip_pending) == 0) return false; - intel_prepare_page_flip(dev, pipe); + intel_prepare_page_flip(dev, plane); /* We detect FlipDone by looking for the change in PendingFlip from '1' * to '0' on the following vblank, i.e. IIR has the Pendingflip @@ -3219,9 +3219,13 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) notify_ring(dev, &dev_priv->ring[RCS]); for_each_pipe(pipe) { + int plane = pipe; + if (IS_MOBILE(dev)) + plane = !plane; + if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && - i8xx_handle_vblank(dev, pipe, iir)) - flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe); + i8xx_handle_vblank(dev, plane, pipe, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) i9xx_pipe_crc_irq_handler(dev, pipe); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 66b39dbaf12c..2eaf7e7e5a40 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10109,10 +10109,13 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->lut_b[i] = i; } - /* Swap pipes & planes for FBC on pre-965 */ + /* + * On gen2/3 only plane A can do fbc, but the panel fitter and lvds port + * is hooked to plane B. Hence we want plane A feeding pipe B. + */ intel_crtc->pipe = pipe; intel_crtc->plane = pipe; - if (IS_MOBILE(dev) && IS_GEN3(dev)) { + if (IS_MOBILE(dev) && INTEL_INFO(dev)->gen < 4) { DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); intel_crtc->plane = !pipe; } From 5135d64b7f0c91c69af3147e5c93eec05f80b820 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Fri, 29 Nov 2013 15:56:30 +0530 Subject: [PATCH 108/595] drm/i915/vlv: Update Wait for FIFO and wait for 20 free entries. v3 On VLV, FIFO will be shared by both SW and HW. So, we read the free entries through register and update dev_priv variable and wait for only 20 entries to be free From Deepak's follow-up mail explaining why vlv is special: "On SB, Out of 64 FIFO Entries, 20 Entries will be used by HW and remaining 44 will be used by the SW,. I think due to this reason, we have a threshold of 20 Entries." "On VLV, HW and SW can access all 64 fifo entries, I don't think having a threshold of 20 Entries is mandatory on VLV. Also, since both SW and HW can access all 64 Entries. I think on VLV, we need to update the fifo_count before waiting for the FIFO." v2: Apply mask when we read the number of free FIFO entries (Ville). v3: Mask applied after reading the register (Deepak). Signed-off-by: Deepak S [danvet: Add further explanation from Deepak to commit message.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index ffb6edebd887..b737a32dd399 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -150,6 +150,13 @@ static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) { int ret = 0; + /* On VLV, FIFO will be shared by both SW and HW. + * So, we need to read the FREE_ENTRIES everytime */ + if (IS_VALLEYVIEW(dev_priv->dev)) + dev_priv->uncore.fifo_count = + __raw_i915_read32(dev_priv, GTFIFOCTL) & + GT_FIFO_FREE_ENTRIES_MASK; + if (dev_priv->uncore.fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) { int loop = 500; u32 fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; From 70903c3ba8fa5ad391d1519c60666a389e4be597 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Dec 2013 09:59:09 +0000 Subject: [PATCH 109/595] drm/i915: Fix ordering of unbind vs unpin pages It is useful to assert that if the object is bound, then it must have its pages pinned to prevent the shrinker from reaping its backing store. This is even more useful with the introduction of real-ppgtt whereupon we may have the object bound into several vma, with each instance pinning the backing store. This assertion breaks down during unbind where we unpinned the backing store before decoupling the vma binding. This can be fixed with a trivial reording of the unbind sequence, which reinforces the pin pages bind to vma ... unbind from vma unpin pages concept. v2: Bonus comment Signed-off-by: Chris Wilson Cc: Ben Widawsky Reviewed-by: Ben Widawsky Tested-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 40d9dcf858bf..92149bcabe98 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2746,7 +2746,6 @@ int i915_vma_unbind(struct i915_vma *vma) obj->has_aliasing_ppgtt_mapping = 0; } i915_gem_gtt_finish_object(obj); - i915_gem_object_unpin_pages(obj); list_del(&vma->mm_list); /* Avoid an unnecessary call to unbind on rebind. */ @@ -2754,7 +2753,6 @@ int i915_vma_unbind(struct i915_vma *vma) obj->map_and_fenceable = true; drm_mm_remove_node(&vma->node); - i915_gem_vma_destroy(vma); /* Since the unbound list is global, only move to that list if @@ -2762,6 +2760,12 @@ int i915_vma_unbind(struct i915_vma *vma) if (list_empty(&obj->vma_list)) list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list); + /* And finally now the object is completely decoupled from this vma, + * we can drop its hold on the backing storage and allow it to be + * reaped by the shrinker. + */ + i915_gem_object_unpin_pages(obj); + return 0; } From d299cce76e001406df40c4ff712b33fccbce1222 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 26 Nov 2013 16:14:33 +0200 Subject: [PATCH 110/595] drm/i915: check context reset stats before relocations Doing it early prevents moving and relocating objects in vain for contexts that won't get any GPU time. Reported-by: Chris Wilson Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 38 ++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index b800fe449530..9282b4c411f6 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -884,6 +884,24 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, return 0; } +static int +i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, + const u32 ctx_id) +{ + struct i915_ctx_hang_stats *hs; + + hs = i915_gem_context_get_hang_stats(dev, file, ctx_id); + if (IS_ERR(hs)) + return PTR_ERR(hs); + + if (hs->banned) { + DRM_DEBUG("Context %u tried to submit while banned\n", ctx_id); + return -EIO; + } + + return 0; +} + static void i915_gem_execbuffer_move_to_active(struct list_head *vmas, struct intel_ring_buffer *ring) @@ -963,8 +981,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; struct intel_ring_buffer *ring; - struct i915_ctx_hang_stats *hs; - u32 ctx_id = i915_execbuffer2_get_context_id(*args); + const u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 exec_start, exec_len; u32 mask, flags; int ret, mode, i; @@ -1101,6 +1118,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } + ret = i915_gem_validate_context(dev, file, ctx_id); + if (ret) { + mutex_unlock(&dev->struct_mutex); + goto pre_mutex_err; + } + eb = eb_create(args); if (eb == NULL) { mutex_unlock(&dev->struct_mutex); @@ -1153,17 +1176,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; - hs = i915_gem_context_get_hang_stats(dev, file, ctx_id); - if (IS_ERR(hs)) { - ret = PTR_ERR(hs); - goto err; - } - - if (hs->banned) { - ret = -EIO; - goto err; - } - ret = i915_switch_context(ring, file, ctx_id); if (ret) goto err; From ce58c32b106efbe228b33b65f1ef6ab505fb7840 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 2 Dec 2013 11:26:07 -0200 Subject: [PATCH 111/595] drm/i915: Do hw quiescing first during unload If we force the hw to idle as our first step during unload, we can abort the unload upon failure. Later we can probe whether the hardware remain active even after we try to shut it down. Signed-off-by: Chris Wilson Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 89e4cf1bb073..a5d010c86368 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1702,6 +1702,12 @@ int i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + ret = i915_gem_suspend(dev); + if (ret) { + DRM_ERROR("failed to idle hardware: %d\n", ret); + return ret; + } + intel_gpu_ips_teardown(); /* The i915.ko module is still not prepared to be loaded when @@ -1715,10 +1721,6 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->mm.inactive_shrinker.scan_objects) unregister_shrinker(&dev_priv->mm.inactive_shrinker); - ret = i915_gem_suspend(dev); - if (ret) - DRM_ERROR("failed to idle hardware: %d\n", ret); - io_mapping_free(dev_priv->gtt.mappable); arch_phys_wc_del(dev_priv->gtt.mtrr); From 798183c54799fbe1e5a5bfabb3a8c0505ffd2149 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 6 Dec 2013 20:29:01 -0200 Subject: [PATCH 112/595] drm/i915: change CRTC assertion on LCPLL disable Currently, PC8 is enabled at modeset_global_resources, which is called after intel_modeset_update_state. Due to this, there's a small race condition on the case where we start enabling PC8, then do a modeset while PC8 is still being enabled. The racing condition triggers a WARN because intel_modeset_update_state will mark the CRTC as enabled, then the thread that's still enabling PC8 might look at the data structure and think that PC8 is being enabled while a pipe is enabled. Despite the WARN, this is not really a bug since we'll wait for the PC8-enabling thread to finish when we call modeset_global_resources. The spec says the CRTC cannot be enabled when we disable LCPLL, so we had a check for crtc->base.enabled. If we change to crtc->active we will still prevent disabling LCPLL while the CRTC is enabled, and we will also prevent the WARN above. This is a replacement for the previous patch named "drm/i915: get/put PC8 when we get/put a CRTC" Testcase: igt/pm_pc8/modeset-lpsp-stress-no-wait Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2eaf7e7e5a40..1f7af63b31df 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6490,7 +6490,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) uint32_t val; list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) - WARN(crtc->base.enabled, "CRTC for pipe %c enabled\n", + WARN(crtc->active, "CRTC for pipe %c enabled\n", pipe_name(crtc->pipe)); WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n"); From c461562e84d180fb691af57f93a42bd9cc7eb69c Mon Sep 17 00:00:00 2001 From: Deepak S Date: Sun, 8 Dec 2013 13:52:59 +0530 Subject: [PATCH 113/595] drm/i915: Remove duplicate intel_uncore_forcewake_reset. Since early sanitize and uncore sanitize are called one after the other, I think, we can remove second forcewake reset which was are calling twice in both the functions. Note that this is merge fallout between commit ef46e0d247da0a7a408573aa15870e231bbd4af2 Author: Daniel Vetter Date: Sat Nov 16 16:00:09 2013 +0100 drm/i915: restore the early forcewake cleanup and commit 521198a2e7095c8c7daa8d7d3a76a110c346be6f Author: Mika Kuoppala Date: Fri Aug 23 16:52:30 2013 +0300 drm/i915: sanitize forcewake registers on reset Signed-off-by: Deepak S [danvet: Explain how this came to be.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index feb2d6692544..e63658e0cfd3 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -340,8 +340,6 @@ void intel_uncore_sanitize(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 reg_val; - intel_uncore_forcewake_reset(dev); - /* BIOS often leaves RC6 enabled, but disable it for hw init */ intel_disable_gt_powersave(dev); From ec9ed1976c256333567932b4acced34c072b57a7 Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Tue, 10 Dec 2013 13:37:36 +0530 Subject: [PATCH 114/595] drm/i915: Make downclock deduction common for all panels If one mode of a internal panel has more than one refresh rate, then a reduced clock is found for the LFP (LVDS/eDP). This enables switching between low and high frequency dynamically. Moving downclock calculation to intel_panel so that it is common for LVDS and eDP. Signed-off-by: Vandana Kannan Signed-off-by: Pradeep Bhat Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 6 ++- drivers/gpu/drm/i915/intel_lvds.c | 69 +++++++----------------------- drivers/gpu/drm/i915/intel_panel.c | 57 ++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5dea38967523..9f8b46574956 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -155,6 +155,7 @@ struct intel_encoder { struct intel_panel { struct drm_display_mode *fixed_mode; + struct drm_display_mode *downclock_mode; int fitting_mode; /* backlight */ @@ -823,7 +824,10 @@ void intel_panel_disable_backlight(struct intel_connector *connector); void intel_panel_destroy_backlight(struct drm_connector *connector); void intel_panel_init_backlight_funcs(struct drm_device *dev); enum drm_connector_status intel_panel_detect(struct drm_device *dev); - +extern struct drm_display_mode *intel_find_panel_downclock( + struct drm_device *dev, + struct drm_display_mode *fixed_mode, + struct drm_connector *connector); /* intel_pm.c */ void intel_init_clock_gating(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 4c8553ea82f7..8bcb93a2a9f6 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -755,57 +755,6 @@ static const struct dmi_system_id intel_no_lvds[] = { { } /* terminating entry */ }; -/** - * intel_find_lvds_downclock - find the reduced downclock for LVDS in EDID - * @dev: drm device - * @connector: LVDS connector - * - * Find the reduced downclock for LVDS in EDID. - */ -static void intel_find_lvds_downclock(struct drm_device *dev, - struct drm_display_mode *fixed_mode, - struct drm_connector *connector) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *scan; - int temp_downclock; - - temp_downclock = fixed_mode->clock; - list_for_each_entry(scan, &connector->probed_modes, head) { - /* - * If one mode has the same resolution with the fixed_panel - * mode while they have the different refresh rate, it means - * that the reduced downclock is found for the LVDS. In such - * case we can set the different FPx0/1 to dynamically select - * between low and high frequency. - */ - if (scan->hdisplay == fixed_mode->hdisplay && - scan->hsync_start == fixed_mode->hsync_start && - scan->hsync_end == fixed_mode->hsync_end && - scan->htotal == fixed_mode->htotal && - scan->vdisplay == fixed_mode->vdisplay && - scan->vsync_start == fixed_mode->vsync_start && - scan->vsync_end == fixed_mode->vsync_end && - scan->vtotal == fixed_mode->vtotal) { - if (scan->clock < temp_downclock) { - /* - * The downclock is already found. But we - * expect to find the lower downclock. - */ - temp_downclock = scan->clock; - } - } - } - if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) { - /* We found the downclock for LVDS. */ - dev_priv->lvds_downclock_avail = 1; - dev_priv->lvds_downclock = temp_downclock; - DRM_DEBUG_KMS("LVDS downclock is found in EDID. " - "Normal clock %dKhz, downclock %dKhz\n", - fixed_mode->clock, temp_downclock); - } -} - /* * Enumerate the child dev array parsed from VBT to check whether * the LVDS is present. @@ -1083,8 +1032,22 @@ void intel_lvds_init(struct drm_device *dev) fixed_mode = drm_mode_duplicate(dev, scan); if (fixed_mode) { - intel_find_lvds_downclock(dev, fixed_mode, - connector); + intel_connector->panel.downclock_mode = + intel_find_panel_downclock(dev, + fixed_mode, connector); + if (intel_connector->panel.downclock_mode != + NULL && i915_lvds_downclock) { + /* We found the downclock for LVDS. */ + dev_priv->lvds_downclock_avail = true; + dev_priv->lvds_downclock = + intel_connector->panel. + downclock_mode->clock; + DRM_DEBUG_KMS("LVDS downclock is found" + " in EDID. Normal clock %dKhz, " + "downclock %dKhz\n", + fixed_mode->clock, + dev_priv->lvds_downclock); + } goto out; } } diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e480cf41c536..b0f6e6cc4354 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -1104,6 +1104,59 @@ void intel_panel_destroy_backlight(struct drm_connector *connector) intel_backlight_device_unregister(intel_connector); } +/** + * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID + * @dev: drm device + * @fixed_mode : panel native mode + * @connector: LVDS/eDP connector + * + * Return downclock_avail + * Find the reduced downclock for LVDS/eDP in EDID. + */ +struct drm_display_mode * +intel_find_panel_downclock(struct drm_device *dev, + struct drm_display_mode *fixed_mode, + struct drm_connector *connector) +{ + struct drm_display_mode *scan, *tmp_mode; + int temp_downclock; + + temp_downclock = fixed_mode->clock; + tmp_mode = NULL; + + list_for_each_entry(scan, &connector->probed_modes, head) { + /* + * If one mode has the same resolution with the fixed_panel + * mode while they have the different refresh rate, it means + * that the reduced downclock is found. In such + * case we can set the different FPx0/1 to dynamically select + * between low and high frequency. + */ + if (scan->hdisplay == fixed_mode->hdisplay && + scan->hsync_start == fixed_mode->hsync_start && + scan->hsync_end == fixed_mode->hsync_end && + scan->htotal == fixed_mode->htotal && + scan->vdisplay == fixed_mode->vdisplay && + scan->vsync_start == fixed_mode->vsync_start && + scan->vsync_end == fixed_mode->vsync_end && + scan->vtotal == fixed_mode->vtotal) { + if (scan->clock < temp_downclock) { + /* + * The downclock is already found. But we + * expect to find the lower downclock. + */ + temp_downclock = scan->clock; + tmp_mode = scan; + } + } + } + + if (temp_downclock < fixed_mode->clock) + return drm_mode_duplicate(dev, tmp_mode); + else + return NULL; +} + /* Set up chip specific backlight functions */ void intel_panel_init_backlight_funcs(struct drm_device *dev) { @@ -1157,4 +1210,8 @@ void intel_panel_fini(struct intel_panel *panel) if (panel->fixed_mode) drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); + + if (panel->downclock_mode) + drm_mode_destroy(intel_connector->base.dev, + panel->downclock_mode); } From fff6386766fc846f19d5628878a4638fa7ece0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 10 Dec 2013 15:19:08 +0200 Subject: [PATCH 115/595] drm/i915: Don't cast away const from infoframe buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't modify the packed infoframe data, so we should keep the const qualifier in place. Just pass the buffer as 'const void *' instead of 'const uint8_t *' and we can drop the cast entirely. v2: Do intel_sdvo_write_infoframe() as well Reviewed-by: Damien Lespiau Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_hdmi.c | 20 ++++++++++---------- drivers/gpu/drm/i915/intel_sdvo.c | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9f8b46574956..79585cddc2cd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -455,7 +455,7 @@ struct intel_hdmi { bool rgb_quant_range_selectable; void (*write_infoframe)(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len); + const void *frame, ssize_t len); void (*set_infoframes)(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode); }; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 6a6ad0c78dc7..6db0d9d17f47 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -130,9 +130,9 @@ static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type, static void g4x_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 val = I915_READ(VIDEO_DIP_CTL); @@ -167,9 +167,9 @@ static void g4x_write_infoframe(struct drm_encoder *encoder, static void ibx_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -205,9 +205,9 @@ static void ibx_write_infoframe(struct drm_encoder *encoder, static void cpt_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -246,9 +246,9 @@ static void cpt_write_infoframe(struct drm_encoder *encoder, static void vlv_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -284,9 +284,9 @@ static void vlv_write_infoframe(struct drm_encoder *encoder, static void hsw_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2abeab09e883..95bdfb3c431c 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -952,7 +952,7 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, unsigned if_index, uint8_t tx_rate, - uint8_t *data, unsigned length) + const uint8_t *data, unsigned length) { uint8_t set_buf_index[2] = { if_index, 0 }; uint8_t hbuf_size, tmp[8]; From 8212d56329b223a106d3d4f7dda95f571b1fa044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 10 Dec 2013 14:06:45 +0200 Subject: [PATCH 116/595] drm/i915: Move VLV PHY CRI clock enable into intel_init_dpio() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CRI clock is related to the display PHY, so the setup belongs in intel_init_dpio(). Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 596ad09f0e51..10a803f69360 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1367,6 +1367,10 @@ static void intel_init_dpio(struct drm_device *dev) if (!IS_VALLEYVIEW(dev)) return; + /* Enable the CRI clock source so we can get at the display */ + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + DPLL_INTEGRATED_CRI_CLK_VLV); + DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO; /* * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx - @@ -10788,17 +10792,10 @@ static void i915_disable_vga(struct drm_device *dev) void intel_modeset_init_hw(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - intel_prepare_ddi(dev); intel_init_clock_gating(dev); - /* Enable the CRI clock source so we can get at the display */ - if (IS_VALLEYVIEW(dev)) - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | - DPLL_INTEGRATED_CRI_CLK_VLV); - intel_init_dpio(dev); mutex_lock(&dev->struct_mutex); From 7125ecb8297a122d60b2b4be9490f49bfadff8e0 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 21 Nov 2013 13:47:15 -0200 Subject: [PATCH 117/595] drm/i915: WARN if !HAS_PC8 when enabling/disabling PC8 We already have some checks and shouldn't be reaching these places on !HAS_PC8 platforms, but add a WARN, just in case. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 10a803f69360..895759b5569f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6638,6 +6638,8 @@ void hsw_enable_pc8_work(struct work_struct *__work) struct drm_device *dev = dev_priv->dev; uint32_t val; + WARN_ON(!HAS_PC8(dev)); + if (dev_priv->pc8.enabled) return; @@ -6683,6 +6685,8 @@ static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv) if (dev_priv->pc8.disable_count != 1) return; + WARN_ON(!HAS_PC8(dev)); + cancel_delayed_work_sync(&dev_priv->pc8.enable_work); if (!dev_priv->pc8.enabled) return; From d62292c8f778772d1b6ec125d461c8c16fdc0417 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 27 Nov 2013 17:59:22 -0200 Subject: [PATCH 118/595] drm/i915: get a PC8 reference when enabling the power well In the current code, at haswell_modeset_global_resources, first we decide if we want to enable/disable the power well, then we decide if we want to enable/disable PC8. On the case where we're enabling PC8 this works fine, but on the case where we disable PC8 due to a non-eDP monitor being enabled, we first enable the power well and then disable PC8. Although wrong, this doesn't seem to be causing any problems now, and we don't even see anything in dmesg. But the patches for runtime D3 turn this problem into a real bug, so we need to fix it. This fixes the "modeset-non-lpsp" subtest from the "pm_pc8" test from intel-gpu-tools. v2: - Rebase (i915_disable_power_well). v3: - More reabase. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 41b6e080e362..cd3f511847ec 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5688,6 +5688,8 @@ static void hsw_set_power_well(struct drm_device *dev, unsigned long irqflags; uint32_t tmp; + WARN_ON(dev_priv->pc8.enabled); + tmp = I915_READ(HSW_PWR_WELL_DRIVER); is_enabled = tmp & HSW_PWR_WELL_STATE_ENABLED; enable_requested = tmp & HSW_PWR_WELL_ENABLE_REQUEST; @@ -5747,17 +5749,26 @@ static void hsw_set_power_well(struct drm_device *dev, static void __intel_power_well_get(struct drm_device *dev, struct i915_power_well *power_well) { - if (!power_well->count++ && power_well->set) + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!power_well->count++ && power_well->set) { + hsw_disable_package_c8(dev_priv); power_well->set(dev, power_well, true); + } } static void __intel_power_well_put(struct drm_device *dev, struct i915_power_well *power_well) { + struct drm_i915_private *dev_priv = dev->dev_private; + WARN_ON(!power_well->count); - if (!--power_well->count && power_well->set && i915_disable_power_well) + if (!--power_well->count && power_well->set && + i915_disable_power_well) { power_well->set(dev, power_well, false); + hsw_enable_package_c8(dev_priv); + } } void intel_display_power_get(struct drm_device *dev, From 8a1874559f222efcae0c0c41b180f6e1af6b9d2e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 6 Dec 2013 20:32:13 -0200 Subject: [PATCH 119/595] drm/i915: add initial Runtime PM functions This patch adds the initial infrastructure to allow a Runtime PM implementation that sets the device to its D3 state. The patch just adds the necessary callbacks and the initial infrastructure. We still don't have any platform that actually uses this infrastructure, we still don't call get/put in all the places we need to, and we don't have any function to save/restore the state of the registers. This is not a problem since no platform uses the code added by this patch. We have a few people simultaneously working on runtime PM, so this initial code could help everybody make their plans. V2: - Move some functions to intel_pm.c - Remove useless pm_runtime_allow() call at init - Remove useless pm_runtime_mark_last_busy() call at get - Use pm_runtime_get_sync() instead of 2 calls - Add a WARN to check if we're really awake V3: - Rebase. V4: - Don't need to call pci_{save,restore}_state and pci_set_power_sate, since they're already called by the PCI layer - Remove wrong pm_runtime_enable() call at init_runtime_pm Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 6 ++++ drivers/gpu/drm/i915/i915_drv.c | 36 +++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 7 ++++ drivers/gpu/drm/i915/intel_drv.h | 4 +++ drivers/gpu/drm/i915/intel_pm.c | 55 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_uncore.c | 9 +++++ 6 files changed, 117 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a5d010c86368..b49571df555f 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include #define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS]) @@ -1663,6 +1665,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (IS_GEN5(dev)) intel_gpu_ips_init(dev_priv); + intel_init_runtime_pm(dev_priv); + return 0; out_power_well: @@ -1708,6 +1712,8 @@ int i915_driver_unload(struct drm_device *dev) return ret; } + intel_fini_runtime_pm(dev_priv); + intel_gpu_ips_teardown(); /* The i915.ko module is still not prepared to be loaded when diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 13076db65eb9..7d2136170293 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -502,6 +502,8 @@ static int i915_drm_freeze(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; + intel_runtime_pm_get(dev_priv); + /* ignore lid events during suspend */ mutex_lock(&dev_priv->modeset_restore_lock); dev_priv->modeset_restore = MODESET_SUSPENDED; @@ -686,6 +688,8 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) mutex_lock(&dev_priv->modeset_restore_lock); dev_priv->modeset_restore = MODESET_DONE; mutex_unlock(&dev_priv->modeset_restore_lock); + + intel_runtime_pm_put(dev_priv); return error; } @@ -900,6 +904,36 @@ static int i915_pm_poweroff(struct device *dev) return i915_drm_freeze(drm_dev); } +static int i915_runtime_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_i915_private *dev_priv = dev->dev_private; + + WARN_ON(!HAS_RUNTIME_PM(dev)); + + DRM_DEBUG_KMS("Suspending device\n"); + + dev_priv->pm.suspended = true; + + return 0; +} + +static int i915_runtime_resume(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_i915_private *dev_priv = dev->dev_private; + + WARN_ON(!HAS_RUNTIME_PM(dev)); + + DRM_DEBUG_KMS("Resuming device\n"); + + dev_priv->pm.suspended = false; + + return 0; +} + static const struct dev_pm_ops i915_pm_ops = { .suspend = i915_pm_suspend, .resume = i915_pm_resume, @@ -907,6 +941,8 @@ static const struct dev_pm_ops i915_pm_ops = { .thaw = i915_pm_thaw, .poweroff = i915_pm_poweroff, .restore = i915_pm_resume, + .runtime_suspend = i915_runtime_suspend, + .runtime_resume = i915_runtime_resume, }; static const struct vm_operations_struct i915_gem_vm_ops = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 780f815b6c9f..98fd1c043777 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1289,6 +1289,10 @@ struct i915_package_c8 { } regsave; }; +struct i915_runtime_pm { + bool suspended; +}; + enum intel_pipe_crc_source { INTEL_PIPE_CRC_SOURCE_NONE, INTEL_PIPE_CRC_SOURCE_PLANE1, @@ -1519,6 +1523,8 @@ typedef struct drm_i915_private { struct i915_package_c8 pc8; + struct i915_runtime_pm pm; + /* Old dri1 support infrastructure, beware the dragons ya fools entering * here! */ struct i915_dri1_state dri1; @@ -1843,6 +1849,7 @@ struct drm_i915_file_private { #define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) #define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev)) #define HAS_PC8(dev) (IS_HASWELL(dev)) /* XXX HSW:ULX */ +#define HAS_RUNTIME_PM(dev) false #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 79585cddc2cd..4a4effba134b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -862,6 +862,10 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv); void gen6_rps_boost(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv); +void intel_runtime_pm_get(struct drm_i915_private *dev_priv); +void intel_runtime_pm_put(struct drm_i915_private *dev_priv); +void intel_init_runtime_pm(struct drm_i915_private *dev_priv); +void intel_fini_runtime_pm(struct drm_i915_private *dev_priv); void ilk_wm_get_hw_state(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cd3f511847ec..2590a5c90725 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -31,6 +31,7 @@ #include "../../../platform/x86/intel_ips.h" #include #include +#include /** * RC6 is a special power stage which allows the GPU to enter an very @@ -5961,6 +5962,60 @@ void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv) hsw_enable_package_c8(dev_priv); } +void intel_runtime_pm_get(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + if (!HAS_RUNTIME_PM(dev)) + return; + + pm_runtime_get_sync(device); + WARN(dev_priv->pm.suspended, "Device still suspended.\n"); +} + +void intel_runtime_pm_put(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + if (!HAS_RUNTIME_PM(dev)) + return; + + pm_runtime_mark_last_busy(device); + pm_runtime_put_autosuspend(device); +} + +void intel_init_runtime_pm(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + dev_priv->pm.suspended = false; + + if (!HAS_RUNTIME_PM(dev)) + return; + + pm_runtime_set_active(device); + + pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */ + pm_runtime_mark_last_busy(device); + pm_runtime_use_autosuspend(device); +} + +void intel_fini_runtime_pm(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + if (!HAS_RUNTIME_PM(dev)) + return; + + /* Make sure we're not suspended first. */ + pm_runtime_get_sync(device); + pm_runtime_disable(device); +} + /* Set up chip specific power management-related functions */ void intel_init_pm(struct drm_device *dev) { diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index e63658e0cfd3..0c4c302aa38c 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -437,6 +437,13 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) } } +static void +assert_device_not_suspended(struct drm_i915_private *dev_priv) +{ + WARN(HAS_RUNTIME_PM(dev_priv->dev) && dev_priv->pm.suspended, + "Device suspended\n"); +} + #define REG_READ_HEADER(x) \ unsigned long irqflags; \ u##x val = 0; \ @@ -568,6 +575,7 @@ gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ + assert_device_not_suspended(dev_priv); \ __raw_i915_write##x(dev_priv, reg, val); \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ @@ -583,6 +591,7 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ + assert_device_not_suspended(dev_priv); \ hsw_unclaimed_reg_clear(dev_priv, reg); \ __raw_i915_write##x(dev_priv, reg, val); \ if (unlikely(__fifo_ret)) { \ From cd2e9e908a86c44c83026acd95520a2761f0d64c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 6 Dec 2013 20:34:21 -0200 Subject: [PATCH 120/595] drm/i915: do adapter power state notification at runtime PM Now that we are actually setting the device to the D3 state, we should issue the notification. The opregion spec says we should send the message before the adapter is about to be placed in a lower power state, and after the adapter is placed in a higher power state. Jani originally wrote a similar patch for PC8, but then we discovered that we were not really changing the PCI D states when enabling/disabling PC8, so we had to postpone his patch. v2: - Improve commit message, explaining the expected state. v3: - Rebase. Cc: Jani Nikula Credits-to: Jani Nikula Reviewed-by: Rodrigo Vivi (v2) Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 7d2136170293..2137a33d5bb2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -915,6 +915,7 @@ static int i915_runtime_suspend(struct device *device) DRM_DEBUG_KMS("Suspending device\n"); dev_priv->pm.suspended = true; + intel_opregion_notify_adapter(dev, PCI_D3cold); return 0; } @@ -929,6 +930,7 @@ static int i915_runtime_resume(struct device *device) DRM_DEBUG_KMS("Resuming device\n"); + intel_opregion_notify_adapter(dev, PCI_D0); dev_priv->pm.suspended = false; return 0; From f65c9168983926962b25ae19073474d60dea0442 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 27 Nov 2013 18:20:34 -0200 Subject: [PATCH 121/595] drm/i915: add runtime put/get calls at the basic places If I add code to enable runtime PM on my Haswell machine, start a desktop environment, then enable runtime PM, these functions will complain that they're trying to read/write registers while the graphics card is suspended. v2: - Simplify i915_gem_fault changes. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi [danvet: Drop the hunk in i915_hangcheck_elapsed, it's the wrong thing to do.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 27 +++++++++++++++++----- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 +++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 92149bcabe98..df83fec174e9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1380,6 +1380,8 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) int ret = 0; bool write = !!(vmf->flags & FAULT_FLAG_WRITE); + intel_runtime_pm_get(dev_priv); + /* We don't use vmf->pgoff since that has the fake offset */ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; @@ -1427,8 +1429,10 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* If this -EIO is due to a gpu hang, give the reset code a * chance to clean up the mess. Otherwise return the proper * SIGBUS. */ - if (i915_terminally_wedged(&dev_priv->gpu_error)) - return VM_FAULT_SIGBUS; + if (i915_terminally_wedged(&dev_priv->gpu_error)) { + ret = VM_FAULT_SIGBUS; + break; + } case -EAGAIN: /* * EAGAIN means the gpu is hung and we'll wait for the error @@ -1443,15 +1447,22 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) * EBUSY is ok: this just means that another thread * already did the job. */ - return VM_FAULT_NOPAGE; + ret = VM_FAULT_NOPAGE; + break; case -ENOMEM: - return VM_FAULT_OOM; + ret = VM_FAULT_OOM; + break; case -ENOSPC: - return VM_FAULT_SIGBUS; + ret = VM_FAULT_SIGBUS; + break; default: WARN_ONCE(ret, "unhandled error in i915_gem_fault: %i\n", ret); - return VM_FAULT_SIGBUS; + ret = VM_FAULT_SIGBUS; + break; } + + intel_runtime_pm_put(dev_priv); + return ret; } /** @@ -4169,6 +4180,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) drm_i915_private_t *dev_priv = dev->dev_private; struct i915_vma *vma, *next; + intel_runtime_pm_get(dev_priv); + trace_i915_gem_object_destroy(obj); if (obj->phys_obj) @@ -4213,6 +4226,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) kfree(obj->bit_17); i915_gem_object_free(obj); + + intel_runtime_pm_put(dev_priv); } struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9282b4c411f6..bceddf5a04bc 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1108,6 +1108,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } } + intel_runtime_pm_get(dev_priv); + ret = i915_mutex_lock_interruptible(dev); if (ret) goto pre_mutex_err; @@ -1237,6 +1239,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, pre_mutex_err: kfree(cliprects); + + /* intel_gpu_busy should also get a ref, so it will free when the device + * is really idle. */ + intel_runtime_pm_put(dev_priv); return ret; } From c8c8fb33b37766acf6474784b0d5245dab9a1690 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 27 Nov 2013 18:21:54 -0200 Subject: [PATCH 122/595] drm/i915: add some runtime PM get/put calls These are needed when we cat the debugfs and sysfs files. V2: - Rebase V3: - Rebase V4: - Rebase Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 45 +++++++++++++++++++++++++++-- drivers/gpu/drm/i915/i915_sysfs.c | 14 +++++++-- drivers/gpu/drm/i915/intel_dp.c | 11 +++++-- drivers/gpu/drm/i915/intel_panel.c | 3 ++ drivers/gpu/drm/i915/intel_uncore.c | 4 +++ 5 files changed, 70 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 13accf795548..6badc1596ceb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -564,10 +564,12 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); for_each_ring(ring, dev_priv, i) i915_ring_seqno_info(m, ring); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -585,6 +587,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); if (INTEL_INFO(dev)->gen >= 8) { int i; @@ -711,6 +714,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) } i915_ring_seqno_info(m, ring); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -904,9 +908,11 @@ static int i915_rstdby_delays(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); crstanddelay = I915_READ16(CRSTANDVID); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f)); @@ -919,7 +925,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - int ret; + int ret = 0; + + intel_runtime_pm_get(dev_priv); flush_delayed_work(&dev_priv->rps.delayed_resume_work); @@ -945,7 +953,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) /* RPSTAT1 is in the GT power well */ ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) - return ret; + goto out; gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); @@ -1033,7 +1041,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) seq_puts(m, "no P-state info available\n"); } - return 0; +out: + intel_runtime_pm_put(dev_priv); + return ret; } static int i915_delayfreq_table(struct seq_file *m, void *unused) @@ -1047,6 +1057,7 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); for (i = 0; i < 16; i++) { delayfreq = I915_READ(PXVFREQ_BASE + i * 4); @@ -1054,6 +1065,8 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT); } + intel_runtime_pm_put(dev_priv); + mutex_unlock(&dev->struct_mutex); return 0; @@ -1075,12 +1088,14 @@ static int i915_inttoext_table(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); for (i = 1; i <= 32; i++) { inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4); seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -1098,11 +1113,13 @@ static int ironlake_drpc_info(struct seq_file *m) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); rgvmodectl = I915_READ(MEMMODECTL); rstdbyctl = I915_READ(RSTDBYCTL); crstandvid = I915_READ16(CRSTANDVID); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? @@ -1166,6 +1183,7 @@ static int gen6_drpc_info(struct seq_file *m) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); spin_lock_irq(&dev_priv->uncore.lock); forcewake_count = dev_priv->uncore.forcewake_count; @@ -1191,6 +1209,8 @@ static int gen6_drpc_info(struct seq_file *m) sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids); mutex_unlock(&dev_priv->rps.hw_lock); + intel_runtime_pm_put(dev_priv); + seq_printf(m, "Video Turbo Mode: %s\n", yesno(rpmodectl1 & GEN6_RP_MEDIA_TURBO)); seq_printf(m, "HW control enabled: %s\n", @@ -1405,6 +1425,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; + intel_runtime_pm_get(dev_priv); seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); @@ -1421,6 +1442,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) ((ia_freq >> 8) & 0xff) * 100); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev_priv->rps.hw_lock); return 0; @@ -1436,8 +1458,10 @@ static int i915_gfxec(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); seq_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4)); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); @@ -1617,6 +1641,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); seq_printf(m, "bit6 swizzle for X-tiling = %s\n", swizzle_string(dev_priv->mm.bit_6_swizzle_x)); @@ -1648,6 +1673,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data) seq_printf(m, "DISP_ARB_CTL = 0x%08x\n", I915_READ(DISP_ARB_CTL)); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -1708,16 +1734,19 @@ static int i915_ppgtt_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); if (INTEL_INFO(dev)->gen >= 8) gen8_ppgtt_info(m, dev); else if (INTEL_INFO(dev)->gen >= 6) gen6_ppgtt_info(m, dev); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -1791,6 +1820,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) u32 psrperf = 0; bool enabled = false; + intel_runtime_pm_get(dev_priv); + seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support)); seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok)); @@ -1803,6 +1834,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) EDP_PSR_PERF_CNT_MASK; seq_printf(m, "Performance_Counter: %u\n", psrperf); + intel_runtime_pm_put(dev_priv); return 0; } @@ -3016,8 +3048,11 @@ i915_cache_sharing_get(void *data, u64 *val) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); + + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev_priv->dev->struct_mutex); *val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT; @@ -3038,6 +3073,7 @@ i915_cache_sharing_set(void *data, u64 val) if (val > 3) return -EINVAL; + intel_runtime_pm_get(dev_priv); DRM_DEBUG_DRIVER("Manually setting uncore sharing to %llu\n", val); /* Update the cache sharing policy here as well */ @@ -3046,6 +3082,7 @@ i915_cache_sharing_set(void *data, u64 val) snpcr |= (val << GEN6_MBC_SNPCR_SHIFT); I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); + intel_runtime_pm_put(dev_priv); return 0; } @@ -3061,6 +3098,7 @@ static int i915_forcewake_open(struct inode *inode, struct file *file) if (INTEL_INFO(dev)->gen < 6) return 0; + intel_runtime_pm_get(dev_priv); gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); return 0; @@ -3075,6 +3113,7 @@ static int i915_forcewake_release(struct inode *inode, struct file *file) return 0; gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); + intel_runtime_pm_put(dev_priv); return 0; } diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 05d8b1680c22..33bcae314bf8 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -40,10 +40,13 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) struct drm_i915_private *dev_priv = dev->dev_private; u64 raw_time; /* 32b value may overflow during fixed point math */ u64 units = 128ULL, div = 100000ULL, bias = 100ULL; + u32 ret; if (!intel_enable_rc6(dev)) return 0; + intel_runtime_pm_get(dev_priv); + /* On VLV, residency time is in CZ units rather than 1.28us */ if (IS_VALLEYVIEW(dev)) { u32 clkctl2; @@ -52,7 +55,8 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) CLK_CTL2_CZCOUNT_30NS_SHIFT; if (!clkctl2) { WARN(!clkctl2, "bogus CZ count value"); - return 0; + ret = 0; + goto out; } units = DIV_ROUND_UP_ULL(30ULL * bias, (u64)clkctl2); if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH) @@ -62,7 +66,11 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) } raw_time = I915_READ(reg) * units; - return DIV_ROUND_UP_ULL(raw_time, div); + ret = DIV_ROUND_UP_ULL(raw_time, div); + +out: + intel_runtime_pm_put(dev_priv); + return ret; } static ssize_t @@ -448,7 +456,9 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); if (attr == &dev_attr_gt_RP0_freq_mhz) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f3b17b11b270..a01264234bf0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3072,9 +3072,12 @@ intel_dp_detect(struct drm_connector *connector, bool force) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; enum drm_connector_status status; struct edid *edid = NULL; + intel_runtime_pm_get(dev_priv); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, drm_get_connector_name(connector)); @@ -3086,7 +3089,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) status = g4x_dp_detect(intel_dp); if (status != connector_status_connected) - return status; + goto out; intel_dp_probe_oui(intel_dp); @@ -3102,7 +3105,11 @@ intel_dp_detect(struct drm_connector *connector, bool force) if (intel_encoder->type != INTEL_OUTPUT_EDP) intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; - return connector_status_connected; + status = connector_status_connected; + +out: + intel_runtime_pm_put(dev_priv); + return status; } static int intel_dp_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index b0f6e6cc4354..20ebc3e83d39 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -845,11 +845,14 @@ static int intel_backlight_device_get_brightness(struct backlight_device *bd) { struct intel_connector *connector = bl_get_data(bd); struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; + intel_runtime_pm_get(dev_priv); mutex_lock(&dev->mode_config.mutex); ret = intel_panel_get_backlight(connector); mutex_unlock(&dev->mode_config.mutex); + intel_runtime_pm_put(dev_priv); return ret; } diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 0c4c302aa38c..8102af9a178d 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -370,6 +370,8 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) if (!dev_priv->uncore.funcs.force_wake_get) return; + intel_runtime_pm_get(dev_priv); + /* Redirect to VLV specific routine */ if (IS_VALLEYVIEW(dev_priv->dev)) return vlv_force_wake_get(dev_priv, fw_engine); @@ -403,6 +405,8 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) 1); } spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + + intel_runtime_pm_put(dev_priv); } /* We give fast paths for the really cool registers */ From e9cb81a22841908b1c075156b409a538d09c8466 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 21 Nov 2013 13:47:23 -0200 Subject: [PATCH 123/595] drm/i915: get a runtime PM reference when the panel VDD is on And put it when it's off. Otherwise, when you run pm_pc8 from intel-gpu-tools, and the delayed function that disables VDD runs, we'll get some messages saying we're touching registers while the HW is suspended. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a01264234bf0..ba5a59c9129f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1094,6 +1094,8 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) if (ironlake_edp_have_panel_vdd(intel_dp)) return; + intel_runtime_pm_get(dev_priv); + DRM_DEBUG_KMS("Turning eDP VDD on\n"); if (!ironlake_edp_have_panel_power(intel_dp)) @@ -1143,6 +1145,8 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n", I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); msleep(intel_dp->panel_power_down_delay); + + intel_runtime_pm_put(dev_priv); } } @@ -1250,6 +1254,9 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) intel_dp->want_panel_vdd = false; ironlake_wait_panel_off(intel_dp); + + /* We got a reference when we enabled the VDD. */ + intel_runtime_pm_put(dev_priv); } void ironlake_edp_backlight_on(struct intel_dp *intel_dp) From 6806e63f48f819754f39e1f796e790b377fb6a89 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 21 Nov 2013 13:47:24 -0200 Subject: [PATCH 124/595] drm/i915: do not assert DE_PCH_EVENT_IVB enabled The current code was checking if all bits of "val" were enabled and DE_PCH_EVENT_IVB was disabled. The new code doesn't care about the state of DE_PCH_EVENT_IVB: it just checks if everything else is 1. The goal is that future patches may completely disable interrupts, and the LCPLL-disabling code shouldn't care about the state of DE_PCH_EVENT_IVB. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi [danvet: I think the commit message is actually wrong in it's description of what the old test checked, but the new one seems sane. So meh.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 895759b5569f..d3a3fba64361 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6514,7 +6514,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) spin_lock_irqsave(&dev_priv->irq_lock, irqflags); val = I915_READ(DEIMR); - WARN((val & ~DE_PCH_EVENT_IVB) != val, + WARN((val | DE_PCH_EVENT_IVB) != 0xffffffff, "Unexpected DEIMR bits enabled: 0x%x\n", val); val = I915_READ(SDEIMR); WARN((val | SDE_HOTPLUG_MASK_CPT) != 0xffffffff, From 1f2d45319922cdcf1f2a6f1f32f3afb206fdaaf7 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 21 Nov 2013 13:47:25 -0200 Subject: [PATCH 125/595] drm/i915: disable interrupts when enabling PC8 The plan is to merge PC8 and D3 into a single feature, and when we're in D3 we won't get any hotplug interrupt anyway, so leaving them enable doesn't make sense, and it also brings us a problem. The problem is that we get a hotplug interrupt right when we we wake up from D3, when we're still waking up everything. If we fully disable interrupts we won't get this hotplug interrupt, so we won't have problems. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 74918e7afeb5..1d44c793bdf4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3900,8 +3900,8 @@ void hsw_pc8_disable_interrupts(struct drm_device *dev) dev_priv->pc8.regsave.gtier = I915_READ(GTIER); dev_priv->pc8.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR); - ironlake_disable_display_irq(dev_priv, ~DE_PCH_EVENT_IVB); - ibx_disable_display_interrupt(dev_priv, ~SDE_HOTPLUG_MASK_CPT); + ironlake_disable_display_irq(dev_priv, 0xffffffff); + ibx_disable_display_interrupt(dev_priv, 0xffffffff); ilk_disable_gt_irq(dev_priv, 0xffffffff); snb_disable_pm_irq(dev_priv, 0xffffffff); @@ -3915,34 +3915,26 @@ void hsw_pc8_restore_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; - uint32_t val, expected; + uint32_t val; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); val = I915_READ(DEIMR); - expected = ~DE_PCH_EVENT_IVB; - WARN(val != expected, "DEIMR is 0x%08x, not 0x%08x\n", val, expected); + WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val); - val = I915_READ(SDEIMR) & ~SDE_HOTPLUG_MASK_CPT; - expected = ~SDE_HOTPLUG_MASK_CPT; - WARN(val != expected, "SDEIMR non-HPD bits are 0x%08x, not 0x%08x\n", - val, expected); + val = I915_READ(SDEIMR); + WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val); val = I915_READ(GTIMR); - expected = 0xffffffff; - WARN(val != expected, "GTIMR is 0x%08x, not 0x%08x\n", val, expected); + WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val); val = I915_READ(GEN6_PMIMR); - expected = 0xffffffff; - WARN(val != expected, "GEN6_PMIMR is 0x%08x, not 0x%08x\n", val, - expected); + WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val); dev_priv->pc8.irqs_disabled = false; ironlake_enable_display_irq(dev_priv, ~dev_priv->pc8.regsave.deimr); - ibx_enable_display_interrupt(dev_priv, - ~dev_priv->pc8.regsave.sdeimr & - ~SDE_HOTPLUG_MASK_CPT); + ibx_enable_display_interrupt(dev_priv, ~dev_priv->pc8.regsave.sdeimr); ilk_enable_gt_irq(dev_priv, ~dev_priv->pc8.regsave.gtimr); snb_enable_pm_irq(dev_priv, ~dev_priv->pc8.regsave.gen6_pmimr); I915_WRITE(GTIER, dev_priv->pc8.regsave.gtier); From 8771a7f80289bc08eac12c7d4f72627ff6552295 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 21 Nov 2013 13:47:28 -0200 Subject: [PATCH 126/595] drm/i915: add runtime PM support on Haswell The code to enable/disable PC8 already takes care of saving and restoring all the registers we need to save/restore, so do a put() call when we enable PC8 and a get() call when we disable it. Ideally, in order to make it easier to add runtime PM support to other platforms, we should move some things from the PC8 code to the runtime PM code, but let's do this later, since we can make Haswell work right now. V2: - Rebase Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi [danvet: Don't actually enable runtime pm since I didn't merge all patches.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d3a3fba64361..7b1b18d8f45c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6656,6 +6656,8 @@ void hsw_enable_pc8_work(struct work_struct *__work) lpt_disable_clkout_dp(dev); hsw_pc8_disable_interrupts(dev); hsw_disable_lcpll(dev_priv, true, true); + + intel_runtime_pm_put(dev_priv); } static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv) @@ -6693,6 +6695,8 @@ static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv) DRM_DEBUG_KMS("Disabling package C8+\n"); + intel_runtime_pm_get(dev_priv); + hsw_restore_lcpll(dev_priv); hsw_pc8_restore_interrupts(dev); lpt_init_pch_refclk(dev); From 9b33600d52fab54df1aa82ea0d70c113060c293a Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 6 Dec 2013 17:32:40 -0200 Subject: [PATCH 127/595] drm/i915: don't enable VDD just to enable the panel We just don't need this. This saves 250ms from every modeset on my machine. Reviewed-by: Rodrigo Vivi Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 86dc6ecd357f..a75ceb5132ed 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1122,9 +1122,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_panel_on(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp, true); } WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE); From dff392dbd258381a6c3164f38420593f2d291e3b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 6 Dec 2013 17:32:41 -0200 Subject: [PATCH 128/595] drm/i915: don't touch the VDD when disabling the panel I don't see a reason to touch VDD when we're disabling the panel: since the panel is enabled, we don't need VDD. This saves a few sleep calls from the vdd_on and vdd_off functions at every modeset. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=69693 Reviewed-by: Rodrigo Vivi Signed-off-by: Paulo Zanoni [danvet: Fix the patch mangle wiggle has done ... Spotted by Paulo. Also drop the runtime_pm_put call which now has to go due to different patch ordering. Also from Paul.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index a75ceb5132ed..8b0e96ff76c9 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1165,7 +1165,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - ironlake_edp_panel_vdd_on(intel_dp); + ironlake_edp_panel_off(intel_dp); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ba5a59c9129f..948892d18ff7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1239,24 +1239,17 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); - WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); - pp = ironlake_get_pp_control(intel_dp); /* We need to switch off panel power _and_ force vdd, for otherwise some * panels get very unhappy and cease to work. */ - pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); + pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE); pp_ctrl_reg = _pp_ctrl_reg(intel_dp); I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); - intel_dp->want_panel_vdd = false; - ironlake_wait_panel_off(intel_dp); - - /* We got a reference when we enabled the VDD. */ - intel_runtime_pm_put(dev_priv); } void ironlake_edp_backlight_on(struct intel_dp *intel_dp) @@ -1781,7 +1774,6 @@ static void intel_disable_dp(struct intel_encoder *encoder) /* Make sure the panel is off before trying to change the mode. But also * ensure that we have vdd while we switch off the panel. */ - ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_backlight_off(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); ironlake_edp_panel_off(intel_dp); From 90791a5c644e2e06cadfe4f37de8ca81483e3a72 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 6 Dec 2013 17:32:42 -0200 Subject: [PATCH 129/595] drm/i915: fix VDD override off wait If we're disabling the VDD override bit and the panel is enabled, we don't need to wait for anything. If the panel is disabled, then we need to actually wait for panel_power_cycle_delay, not panel_power_down_delay, because the power down delay was already respected when we disabled the panel. Signed-off-by: Paulo Zanoni Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 948892d18ff7..8f17f8fbd0b1 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1144,7 +1144,9 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) /* Make sure sequencer is idle before allowing subsequent activity */ DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n", I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); - msleep(intel_dp->panel_power_down_delay); + + if ((pp & POWER_TARGET_ON) == 0) + msleep(intel_dp->panel_power_cycle_delay); intel_runtime_pm_put(dev_priv); } From 0476190e107f398cfe0b50101bee4f8bd8e0fe30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 10 Dec 2013 20:47:44 +0200 Subject: [PATCH 130/595] drm/i915: Use 32bit read for BB_ADDR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BB_ADDR register is documented to be 32bits at least since SNB. Prior to that the high 32bits were listed as MBZ, so using a 64bit read doesn't seem worth anything. Also the simulator doesn't like the 64bit read. So just switch to using a 32bit read instead. Signed-off-by: Ville Syrjälä Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 79dcb8f896c6..9a642921182b 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -726,7 +726,7 @@ static void i915_record_ring_state(struct drm_device *dev, error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base)); error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base)); if (ring->id == RCS) - error->bbaddr = I915_READ64(BB_ADDR); + error->bbaddr = I915_READ(BB_ADDR); error->bbstate[ring->id] = I915_READ(RING_BBSTATE(ring->mmio_base)); } else { error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX); From 3dda20a974e013a4985560904c0e491a70a25251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 10 Dec 2013 21:44:43 +0200 Subject: [PATCH 131/595] drm/i915: Record BB_ADDR for every ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every ring seems to have a BB_ADDR registers, so include them all in the error state. v2: Also include the _UDW on BDW Signed-off-by: Ville Syrjälä Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gpu_error.c | 12 ++++++------ drivers/gpu/drm/i915/i915_reg.h | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 98fd1c043777..a3804b29ef90 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -323,7 +323,7 @@ struct drm_i915_error_state { u32 instps[I915_NUM_RINGS]; u32 extra_instdone[I915_NUM_INSTDONE_REG]; u32 seqno[I915_NUM_RINGS]; - u64 bbaddr; + u64 bbaddr[I915_NUM_RINGS]; u32 fault_reg[I915_NUM_RINGS]; u32 done_reg; u32 faddr[I915_NUM_RINGS]; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 9a642921182b..a707cca692e4 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -247,12 +247,11 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m, err_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); err_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); err_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]); - if (ring == RCS && INTEL_INFO(dev)->gen >= 4) - err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr); - if (INTEL_INFO(dev)->gen >= 4) + if (INTEL_INFO(dev)->gen >= 4) { + err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr[ring]); err_printf(m, " BB_STATE: 0x%08x\n", error->bbstate[ring]); - if (INTEL_INFO(dev)->gen >= 4) err_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]); + } err_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]); err_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); if (INTEL_INFO(dev)->gen >= 6) { @@ -725,8 +724,9 @@ static void i915_record_ring_state(struct drm_device *dev, error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base)); error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base)); error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base)); - if (ring->id == RCS) - error->bbaddr = I915_READ(BB_ADDR); + error->bbaddr[ring->id] = I915_READ(RING_BBADDR(ring->mmio_base)); + if (INTEL_INFO(dev)->gen >= 8) + error->bbaddr[ring->id] |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32; error->bbstate[ring->id] = I915_READ(RING_BBSTATE(ring->mmio_base)); } else { error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2d203905bd70..8828ee4eabec 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -734,6 +734,8 @@ #define HWSTAM 0x02098 #define DMA_FADD_I8XX 0x020d0 #define RING_BBSTATE(base) ((base)+0x110) +#define RING_BBADDR(base) ((base)+0x140) +#define RING_BBADDR_UDW(base) ((base)+0x168) /* gen8+ */ #define ERROR_GEN6 0x040a0 #define GEN7_ERR_INT 0x44040 @@ -924,7 +926,6 @@ #define CM0_COLOR_EVICT_DISABLE (1<<3) #define CM0_DEPTH_WRITE_DISABLE (1<<1) #define CM0_RC_OP_FLUSH_DISABLE (1<<0) -#define BB_ADDR 0x02140 /* 8 bytes */ #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ #define GFX_FLSH_CNTL_GEN6 0x101008 #define GFX_FLSH_CNTL_EN (1<<0) From b1c560d13d1aab194b467ca33d0be6ca6e829ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 9 Dec 2013 18:54:13 +0200 Subject: [PATCH 132/595] drm/i915: Extract p2 divider correctly for gen2 LVDS dual channel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to determine the correct p2 divider for LVDS on gen2, we need to check the CLKB mode from the LVDS port register to determine if we're dealing with single or dual channel LVDS. Cc: Bruno Prémont Signed-off-by: Ville Syrjälä Tested-by: Bruno Prémont Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7b1b18d8f45c..8c4e384b8ae1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7951,12 +7951,17 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, else i9xx_clock(refclk, &clock); } else { - bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN); + u32 lvds = I915_READ(LVDS); + bool is_lvds = (pipe == 1) && (lvds & LVDS_PORT_EN); if (is_lvds) { clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> DPLL_FPA01_P1_POST_DIV_SHIFT); - clock.p2 = 14; + + if (lvds & LVDS_CLKB_POWER_UP) + clock.p2 = 7; + else + clock.p2 = 14; } else { if (dpll & PLL_P1_DIVIDE_BY_TWO) clock.p1 = 2; From 91dbe5fb77a2afea04a52b432cfb4529d72096d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 9 Dec 2013 18:54:14 +0200 Subject: [PATCH 133/595] drm/i915: Change N divider minimum from 3 to 2 for gen2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bruno Prémont has a 855 machine with a 1400x1050 LVDS screen. The VBT mode is as follows: 0:"1400x1050" 0 108000 1400 1416 1528 1688 1050 1051 1054 1066 0x8 0xa The BIOS uses the following DPLL settings: DPLL = 0x90020000 FP0 = 0x2140e FP1 = 0x21207 We can't generate that pixel clock currently as we're limiting the N divider to at least 3, whereas the BIOS uses a value of 2. Let's reduce the N minimum to 2 and see what happens. Cc: Bruno Prémont Signed-off-by: Ville Syrjälä Tested-by: Bruno Prémont Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8c4e384b8ae1..efc3391dfac5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -91,7 +91,7 @@ intel_fdi_link_freq(struct drm_device *dev) static const intel_limit_t intel_limits_i8xx_dac = { .dot = { .min = 25000, .max = 350000 }, .vco = { .min = 930000, .max = 1400000 }, - .n = { .min = 3, .max = 16 }, + .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, .m2 = { .min = 6, .max = 16 }, @@ -104,7 +104,7 @@ static const intel_limit_t intel_limits_i8xx_dac = { static const intel_limit_t intel_limits_i8xx_dvo = { .dot = { .min = 25000, .max = 350000 }, .vco = { .min = 930000, .max = 1400000 }, - .n = { .min = 3, .max = 16 }, + .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, .m2 = { .min = 6, .max = 16 }, @@ -117,7 +117,7 @@ static const intel_limit_t intel_limits_i8xx_dvo = { static const intel_limit_t intel_limits_i8xx_lvds = { .dot = { .min = 25000, .max = 350000 }, .vco = { .min = 930000, .max = 1400000 }, - .n = { .min = 3, .max = 16 }, + .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, .m2 = { .min = 6, .max = 16 }, From c7721d3266c71b122f7a6c2b40b0800985b53ce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 9 Dec 2013 18:54:15 +0200 Subject: [PATCH 134/595] drm/i915: Increase gen2 vco frequency limit to 1512 MHz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bruno Prémont has a 855 machine with a 1400x1050 LVDS screen. The VBT mode is as follows: 0:"1400x1050" 0 108000 1400 1416 1528 1688 1050 1051 1054 1066 0x8 0xa The BIOS uses the following DPLL settings: DPLL = 0x90020000 FP0 = 0x2140e FP1 = 0x21207 That puts the BIOS generated VCO frequency at 1512 MHz, which is higher than the 1400 MHz limit we have currently. Let's bump the VCO limit to 1512 MHz and see what happens. Cc: Bruno Prémont Signed-off-by: Ville Syrjälä Tested-by: Bruno Prémont Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index efc3391dfac5..14e0b80c5641 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -90,7 +90,7 @@ intel_fdi_link_freq(struct drm_device *dev) static const intel_limit_t intel_limits_i8xx_dac = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1400000 }, + .vco = { .min = 930000, .max = 1512000 }, .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, @@ -103,7 +103,7 @@ static const intel_limit_t intel_limits_i8xx_dac = { static const intel_limit_t intel_limits_i8xx_dvo = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1400000 }, + .vco = { .min = 930000, .max = 1512000 }, .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, @@ -116,7 +116,7 @@ static const intel_limit_t intel_limits_i8xx_dvo = { static const intel_limit_t intel_limits_i8xx_lvds = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1400000 }, + .vco = { .min = 930000, .max = 1512000 }, .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, From e91e941bd566ae94ed576424c9e8b31bdfc55512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 9 Dec 2013 18:54:16 +0200 Subject: [PATCH 135/595] drm/i915: Fix 66 MHz LVDS SSC freq for gen2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store the SSC refclock frequency in kHz to get more accuracy. Currently we're pretending that 66 MHz is ~66000 kHz, when in fact it is actually ~66667 kHz. By storing the less rounded kHz value we get a much better accuracy for out pixel clock calculations. Cc: Bruno Prémont Signed-off-by: Ville Syrjälä Tested-by: Bruno Prémont Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.c | 8 ++++---- drivers/gpu/drm/i915/intel_display.c | 13 ++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index e4fba39631a5..f88e5079a3f5 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -327,12 +327,12 @@ static int intel_bios_ssc_frequency(struct drm_device *dev, { switch (INTEL_INFO(dev)->gen) { case 2: - return alternate ? 66 : 48; + return alternate ? 66667 : 48000; case 3: case 4: - return alternate ? 100 : 96; + return alternate ? 100000 : 96000; default: - return alternate ? 100 : 120; + return alternate ? 100000 : 120000; } } @@ -796,7 +796,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) */ dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, !HAS_PCH_SPLIT(dev)); - DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq); + DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); for (port = PORT_A; port < I915_MAX_PORTS; port++) { struct ddi_vbt_port_info *info = diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 14e0b80c5641..9404b50ee8c4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4761,9 +4761,8 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) refclk = 100000; } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { - refclk = dev_priv->vbt.lvds_ssc_freq * 1000; - DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", - refclk / 1000); + refclk = dev_priv->vbt.lvds_ssc_freq; + DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk); } else if (!IS_GEN2(dev)) { refclk = 96000; } else { @@ -5909,9 +5908,9 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) } if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { - DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", + DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", dev_priv->vbt.lvds_ssc_freq); - return dev_priv->vbt.lvds_ssc_freq * 1000; + return dev_priv->vbt.lvds_ssc_freq; } return 120000; @@ -6173,7 +6172,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, factor = 21; if (is_lvds) { if ((intel_panel_use_ssc(dev_priv) && - dev_priv->vbt.lvds_ssc_freq == 100) || + dev_priv->vbt.lvds_ssc_freq == 100000) || (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) factor = 25; } else if (intel_crtc->config.sdvo_tv_clock) @@ -7888,7 +7887,7 @@ static int i9xx_pll_refclk(struct drm_device *dev, u32 dpll = pipe_config->dpll_hw_state.dpll; if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) - return dev_priv->vbt.lvds_ssc_freq * 1000; + return dev_priv->vbt.lvds_ssc_freq; else if (HAS_PCH_SPLIT(dev)) return 120000; else if (!IS_GEN2(dev)) From 9c333719ae95b7c974aa15c6dcc618918b7479c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 9 Dec 2013 18:54:17 +0200 Subject: [PATCH 136/595] drm/i915: Decrease gen2 vco frequency minimum to 908 MHz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On my 855 machine the BIOS uses the following DPLL settings: DPLL 0x90016000 FP0 = 0x61207 FP1 = 0x21207 With the 66MHz SSC refclock, that puts the BIOS generated VCO frequency at ~908 MHz, which is lower than the 930 MHz limit we have currently. This also results in the pixel clock coming out significantly higher than the requested 65 MHz when we try to recompute it. Reduce the the VCO limit to 908 MHz. Combined with the earlier SSC reference clock accuracy fix, this results in the pixel clock coming out as 65.08 MHz which is quite close to the target. For some reason the BIOS uses 64.881 MHz, which isn't quite as close. This makes kms_flip wf_vblank-ts-check pass for the first time on this machine \o/ Cc: Bruno Prémont Signed-off-by: Ville Syrjälä Tested-by: Bruno Prémont Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9404b50ee8c4..c01aff8a36bb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -90,7 +90,7 @@ intel_fdi_link_freq(struct drm_device *dev) static const intel_limit_t intel_limits_i8xx_dac = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1512000 }, + .vco = { .min = 908000, .max = 1512000 }, .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, @@ -103,7 +103,7 @@ static const intel_limit_t intel_limits_i8xx_dac = { static const intel_limit_t intel_limits_i8xx_dvo = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1512000 }, + .vco = { .min = 908000, .max = 1512000 }, .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, @@ -116,7 +116,7 @@ static const intel_limit_t intel_limits_i8xx_dvo = { static const intel_limit_t intel_limits_i8xx_lvds = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1512000 }, + .vco = { .min = 908000, .max = 1512000 }, .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, From b9f5e07d0245ff0ddaca453d146fcad056ac12c3 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Tue, 10 Dec 2013 12:14:54 +0530 Subject: [PATCH 137/595] drm/i915: Add more dev ops for MIPI sub encoder Some panels require one time programming if they do not contain their own eeprom for basic register initialization. The sequence is Panel Reset --> Send OTP --> Enable Pixel Stream --> Enable the panel v2: Based on review comments from Jani and Ville - Updated the commit message with more details - Move the new parameters out of this patch Signed-off-by: Yogesh Mohan Marimuthu Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi.c | 9 ++++++++- drivers/gpu/drm/i915/intel_dsi.h | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 7b9b350d29ae..42ed28a309f5 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -147,6 +147,9 @@ static void intel_dsi_enable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); + if (intel_dsi->dev.dev_ops->panel_reset) + intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev); + temp = I915_READ(MIPI_DEVICE_READY(pipe)); if ((temp & DEVICE_READY) == 0) { temp &= ~ULPS_STATE_MASK; @@ -162,6 +165,9 @@ static void intel_dsi_enable(struct intel_encoder *encoder) I915_WRITE(MIPI_DEVICE_READY(pipe), temp); } + if (intel_dsi->dev.dev_ops->send_otp_cmds) + intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev); + if (is_cmd_mode(intel_dsi)) I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); @@ -176,7 +182,8 @@ static void intel_dsi_enable(struct intel_encoder *encoder) POSTING_READ(MIPI_PORT_CTRL(pipe)); } - intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); + if (intel_dsi->dev.dev_ops->enable) + intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); } static void intel_dsi_disable(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index c7765f33d524..14509d65f78d 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -39,6 +39,11 @@ struct intel_dsi_device { struct intel_dsi_dev_ops { bool (*init)(struct intel_dsi_device *dsi); + void (*panel_reset)(struct intel_dsi_device *dsi); + + /* one time programmable commands if needed */ + void (*send_otp_cmds)(struct intel_dsi_device *dsi); + /* This callback must be able to assume DSI commands can be sent */ void (*enable)(struct intel_dsi_device *dsi); From e9fe51c6656f7fd4fad38869cb70a42e65ec0ba9 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Tue, 10 Dec 2013 12:14:55 +0530 Subject: [PATCH 138/595] drm/i915: Use FLISDSI interface for band gap reset v2: Rebased on latest code Signed-off-by: Shobhit Kumar Signed-off-by: Yogesh Mohan Marimuthu Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_dsi.c | 47 +++++---------------------- drivers/gpu/drm/i915/intel_sideband.c | 14 ++++++++ 4 files changed, 25 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a3804b29ef90..709b20e0e3f0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2475,6 +2475,8 @@ u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, enum intel_sbi_destination destination); void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, enum intel_sbi_destination destination); +u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg); +void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val); int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8828ee4eabec..e8cc27cd9494 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -362,6 +362,7 @@ #define IOSF_PORT_CCK 0x14 #define IOSF_PORT_CCU 0xA9 #define IOSF_PORT_GPS_CORE 0x48 +#define IOSF_PORT_FLISDSI 0x1B #define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104) #define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 42ed28a309f5..1016e7b0337e 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -37,49 +37,18 @@ static const struct intel_dsi_device intel_dsi_devices[] = { }; - -static void vlv_cck_modify(struct drm_i915_private *dev_priv, u32 reg, u32 val, - u32 mask) -{ - u32 tmp = vlv_cck_read(dev_priv, reg); - tmp &= ~mask; - tmp |= val; - vlv_cck_write(dev_priv, reg, tmp); -} - -static void band_gap_wa(struct drm_i915_private *dev_priv) +static void band_gap_reset(struct drm_i915_private *dev_priv) { mutex_lock(&dev_priv->dpio_lock); - /* Enable bandgap fix in GOP driver */ - vlv_cck_modify(dev_priv, 0x6D, 0x00010000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6E, 0x00010000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6F, 0x00010000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x00, 0x00008000, 0x00008000); - msleep(20); - vlv_cck_modify(dev_priv, 0x00, 0x00000000, 0x00008000); - msleep(20); - - /* Turn Display Trunk on */ - vlv_cck_modify(dev_priv, 0x6B, 0x00020000, 0x00030000); - msleep(20); - - vlv_cck_modify(dev_priv, 0x6C, 0x00020000, 0x00030000); - msleep(20); - - vlv_cck_modify(dev_priv, 0x6D, 0x00020000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6E, 0x00020000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6F, 0x00020000, 0x00030000); + vlv_flisdsi_write(dev_priv, 0x08, 0x0001); + vlv_flisdsi_write(dev_priv, 0x0F, 0x0005); + vlv_flisdsi_write(dev_priv, 0x0F, 0x0025); + udelay(150); + vlv_flisdsi_write(dev_priv, 0x0F, 0x0000); + vlv_flisdsi_write(dev_priv, 0x08, 0x0000); mutex_unlock(&dev_priv->dpio_lock); - - /* Need huge delay, otherwise clock is not stable */ - msleep(100); } static struct intel_dsi *intel_attached_dsi(struct drm_connector *connector) @@ -364,7 +333,7 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) vlv_enable_dsi_pll(intel_encoder); /* XXX: Location of the call */ - band_gap_wa(dev_priv); + band_gap_reset(dev_priv); /* escape clock divider, 20MHz, shared for A and C. device ready must be * off when doing this! txclkesc? */ diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index cc6fbcde7d3d..0954f132726e 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -249,3 +249,17 @@ void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, return; } } + +u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI, + DPIO_OPCODE_REG_READ, reg, &val); + return val; +} + +void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI, + DPIO_OPCODE_REG_WRITE, reg, &val); +} From 44d4c6eebb2ef04f698c292bb6eda5f2e80c663b Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Tue, 10 Dec 2013 12:14:56 +0530 Subject: [PATCH 139/595] drm/i915: Compute dsi_clk from pixel clock Pixel clock based calculation is recommended in the MIPI host controller documentation v2: Based on review comments from Jani and Ville - Use dsi_clk in KHz rather than converting in Hz and back to MHz - RR formula is retained though not used but return dsi_clk in KHz now - Moved the m-n-p changes into a separate patch - Removed the parameter check for intel_dsi->dsi_clock_freq. This will be bought back in if needed when appropriate panel drivers are done v3: Removed the unused mnp calculation from static table Signed-off-by: Vijayakumar Balakrishnan Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi_pll.c | 89 ++++++++++------------------ 1 file changed, 31 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 44279b2ade88..0d1b17fee018 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -50,6 +50,8 @@ static const u32 lfsr_converts[] = { 71, 35 /* 91 - 92 */ }; +#ifdef DSI_CLK_FROM_RR + static u32 dsi_rr_formula(const struct drm_display_mode *mode, int pixel_format, int video_mode_format, int lane_count, bool eotp) @@ -121,7 +123,7 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, /* the dsi clock is divided by 2 in the hardware to get dsi ddr clock */ dsi_bit_clock_hz = bytes_per_x_frames_x_lanes * 8; - dsi_clk = dsi_bit_clock_hz / (1000 * 1000); + dsi_clk = dsi_bit_clock_hz / 1000; if (eotp && video_mode_format == VIDEO_MODE_BURST) dsi_clk *= 2; @@ -129,64 +131,37 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, return dsi_clk; } -#ifdef MNP_FROM_TABLE +#else -struct dsi_clock_table { - u32 freq; - u8 m; - u8 p; -}; - -static const struct dsi_clock_table dsi_clk_tbl[] = { - {300, 72, 6}, {313, 75, 6}, {323, 78, 6}, {333, 80, 6}, - {343, 82, 6}, {353, 85, 6}, {363, 87, 6}, {373, 90, 6}, - {383, 92, 6}, {390, 78, 5}, {393, 79, 5}, {400, 80, 5}, - {401, 80, 5}, {402, 80, 5}, {403, 81, 5}, {404, 81, 5}, - {405, 81, 5}, {406, 81, 5}, {407, 81, 5}, {408, 82, 5}, - {409, 82, 5}, {410, 82, 5}, {411, 82, 5}, {412, 82, 5}, - {413, 83, 5}, {414, 83, 5}, {415, 83, 5}, {416, 83, 5}, - {417, 83, 5}, {418, 84, 5}, {419, 84, 5}, {420, 84, 5}, - {430, 86, 5}, {440, 88, 5}, {450, 90, 5}, {460, 92, 5}, - {470, 75, 4}, {480, 77, 4}, {490, 78, 4}, {500, 80, 4}, - {510, 82, 4}, {520, 83, 4}, {530, 85, 4}, {540, 86, 4}, - {550, 88, 4}, {560, 90, 4}, {570, 91, 4}, {580, 70, 3}, - {590, 71, 3}, {600, 72, 3}, {610, 73, 3}, {620, 74, 3}, - {630, 76, 3}, {640, 77, 3}, {650, 78, 3}, {660, 79, 3}, - {670, 80, 3}, {680, 82, 3}, {690, 83, 3}, {700, 84, 3}, - {710, 85, 3}, {720, 86, 3}, {730, 88, 3}, {740, 89, 3}, - {750, 90, 3}, {760, 91, 3}, {770, 92, 3}, {780, 62, 2}, - {790, 63, 2}, {800, 64, 2}, {880, 70, 2}, {900, 72, 2}, - {1000, 80, 2}, /* dsi clock frequency in Mhz*/ -}; - -static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) +/* Get DSI clock from pixel clock */ +static u32 dsi_clk_from_pclk(const struct drm_display_mode *mode, + int pixel_format, int lane_count) { - unsigned int i; - u8 m; - u8 n; - u8 p; - u32 m_seed; + u32 dsi_clk_khz; + u32 bpp; - if (dsi_clk < 300 || dsi_clk > 1000) - return -ECHRNG; - - for (i = 0; i <= ARRAY_SIZE(dsi_clk_tbl); i++) { - if (dsi_clk_tbl[i].freq > dsi_clk) - break; + switch (pixel_format) { + default: + case VID_MODE_FORMAT_RGB888: + case VID_MODE_FORMAT_RGB666_LOOSE: + bpp = 24; + break; + case VID_MODE_FORMAT_RGB666: + bpp = 18; + break; + case VID_MODE_FORMAT_RGB565: + bpp = 16; + break; } - m = dsi_clk_tbl[i].m; - p = dsi_clk_tbl[i].p; - m_seed = lfsr_converts[m - 62]; - n = 1; - dsi_mnp->dsi_pll_ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + p - 2); - dsi_mnp->dsi_pll_div = (n - 1) << DSI_PLL_N1_DIV_SHIFT | - m_seed << DSI_PLL_M1_DIV_SHIFT; + /* DSI data rate = pixel clock * bits per pixel / lane count + pixel clock is converted from KHz to Hz */ + dsi_clk_khz = DIV_ROUND_CLOSEST(mode->clock * bpp, lane_count); - return 0; + return dsi_clk_khz; } -#else +#endif static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) { @@ -200,13 +175,14 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) u32 calc_p; u32 m_seed; - if (dsi_clk < 300 || dsi_clk > 1150) { + /* dsi_clk is expected in KHZ */ + if (dsi_clk < 300000 || dsi_clk > 1150000) { DRM_ERROR("DSI CLK Out of Range\n"); return -ECHRNG; } ref_clk = 25000; - target_dsi_clk = dsi_clk * 1000; + target_dsi_clk = dsi_clk; error = 0xFFFFFFFF; calc_m = 0; calc_p = 0; @@ -235,8 +211,6 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) return 0; } -#endif - /* * XXX: The muxing and gating is hard coded for now. Need to add support for * sharing PLLs with two DSI outputs. @@ -251,9 +225,8 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder) struct dsi_mnp dsi_mnp; u32 dsi_clk; - dsi_clk = dsi_rr_formula(mode, intel_dsi->pixel_format, - intel_dsi->video_mode_format, - intel_dsi->lane_count, !intel_dsi->eot_disable); + dsi_clk = dsi_clk_from_pclk(mode, intel_dsi->pixel_format, + intel_dsi->lane_count); ret = dsi_calc_mnp(dsi_clk, &dsi_mnp); if (ret) { From 8e1eed5aa8fe6cdd2c445b7aded42498523ad4dd Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Tue, 10 Dec 2013 12:14:57 +0530 Subject: [PATCH 140/595] drm/i915: Try harder to get best m, n, p values with minimal error Basically check for both +ive and -ive deviation from target clock and pick the one with minimal error. If we get a direct match, break from loop to acheive some optimization. v2: Use signed variable for target and calculated dsi clock values Signed-off-by: Vijayakumar Balakrishnan Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi_pll.c | 30 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 0d1b17fee018..ba79ec19da3b 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -169,8 +169,8 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) u32 ref_clk; u32 error; u32 tmp_error; - u32 target_dsi_clk; - u32 calc_dsi_clk; + int target_dsi_clk; + int calc_dsi_clk; u32 calc_m; u32 calc_p; u32 m_seed; @@ -184,22 +184,32 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) ref_clk = 25000; target_dsi_clk = dsi_clk; error = 0xFFFFFFFF; + tmp_error = 0xFFFFFFFF; calc_m = 0; calc_p = 0; for (m = 62; m <= 92; m++) { for (p = 2; p <= 6; p++) { - + /* Find the optimal m and p divisors + with minimal error +/- the required clock */ calc_dsi_clk = (m * ref_clk) / p; - if (calc_dsi_clk >= target_dsi_clk) { - tmp_error = calc_dsi_clk - target_dsi_clk; - if (tmp_error < error) { - error = tmp_error; - calc_m = m; - calc_p = p; - } + if (calc_dsi_clk == target_dsi_clk) { + calc_m = m; + calc_p = p; + error = 0; + break; + } else + tmp_error = abs(target_dsi_clk - calc_dsi_clk); + + if (tmp_error < error) { + error = tmp_error; + calc_m = m; + calc_p = p; } } + + if (error == 0) + break; } m_seed = lfsr_converts[calc_m - 62]; From 1dbd7cb256913e5b8d6a4837185b45e3467dff42 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Wed, 11 Dec 2013 17:52:05 +0530 Subject: [PATCH 141/595] drm/i915: Reorganize the DSI enable/disable sequence Basically ULPS handling during enable/disable has been moved to pre_enable and post_disable phases. PLL and panel power disable also has been moved to post_disable phase. The ULPS entry/exit sequneces as suggested by HW team is as follows - During enable time - set DEVICE_READY --> Clear DEVICE_READY --> set DEVICE_READY And during disable time to flush all FIFOs - set ENTER_SLEEP --> EXIT_SLEEP --> ENTER_SLEEP Also during disbale sequnece sub-encoder disable is moved to the end after port is disabled. v2: Based on comments from Ville - Detailed epxlaination in the commit messgae - Moved parameter changes out into another patch - Backlight enabling will be a new patch v3: Updated as per Jani's comments - Removed the I915_WRITE_BITS as it is not needed - Moved panel_reset and send_otp_cmds hooks to dsi_pre_enable - Moved disable_panel_power hook to dsi_post_disable - Replace hardcoding with AFE_LATCHOUT v4: Make intel_dsi_device_ready and intel_dsi_clear_device_ready static Signed-off-by: Yogesh Mohan Marimuthu Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi.c | 112 +++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_dsi.h | 2 + 2 files changed, 80 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 1016e7b0337e..e9bcb46dba5f 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -101,14 +101,47 @@ static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder) vlv_enable_dsi_pll(encoder); } +static void intel_dsi_device_ready(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + int pipe = intel_crtc->pipe; + u32 val; + + DRM_DEBUG_KMS("\n"); + + val = I915_READ(MIPI_PORT_CTRL(pipe)); + I915_WRITE(MIPI_PORT_CTRL(pipe), val | LP_OUTPUT_HOLD); + usleep_range(1000, 1500); + I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_EXIT); + usleep_range(2000, 2500); + I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY); + usleep_range(2000, 2500); + I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00); + usleep_range(2000, 2500); + I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY); + usleep_range(2000, 2500); +} static void intel_dsi_pre_enable(struct intel_encoder *encoder) { + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + DRM_DEBUG_KMS("\n"); + + if (intel_dsi->dev.dev_ops->panel_reset) + intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev); + + /* put device in ready state */ + intel_dsi_device_ready(encoder); + + if (intel_dsi->dev.dev_ops->send_otp_cmds) + intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev); } static void intel_dsi_enable(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; @@ -116,31 +149,9 @@ static void intel_dsi_enable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); - if (intel_dsi->dev.dev_ops->panel_reset) - intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev); - - temp = I915_READ(MIPI_DEVICE_READY(pipe)); - if ((temp & DEVICE_READY) == 0) { - temp &= ~ULPS_STATE_MASK; - I915_WRITE(MIPI_DEVICE_READY(pipe), temp | DEVICE_READY); - } else if (temp & ULPS_STATE_MASK) { - temp &= ~ULPS_STATE_MASK; - I915_WRITE(MIPI_DEVICE_READY(pipe), temp | ULPS_STATE_EXIT); - /* - * We need to ensure that there is a minimum of 1 ms time - * available before clearing the UPLS exit state. - */ - msleep(2); - I915_WRITE(MIPI_DEVICE_READY(pipe), temp); - } - - if (intel_dsi->dev.dev_ops->send_otp_cmds) - intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev); - if (is_cmd_mode(intel_dsi)) I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); - - if (is_vid_mode(intel_dsi)) { + else { msleep(20); /* XXX */ dpi_send_cmd(intel_dsi, TURN_ON); msleep(100); @@ -157,7 +168,8 @@ static void intel_dsi_enable(struct intel_encoder *encoder) static void intel_dsi_disable(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; @@ -165,8 +177,6 @@ static void intel_dsi_disable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); - intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); - if (is_vid_mode(intel_dsi)) { dpi_send_cmd(intel_dsi, SHUTDOWN); msleep(10); @@ -179,20 +189,54 @@ static void intel_dsi_disable(struct intel_encoder *encoder) msleep(2); } - temp = I915_READ(MIPI_DEVICE_READY(pipe)); - if (temp & DEVICE_READY) { - temp &= ~DEVICE_READY; - temp &= ~ULPS_STATE_MASK; - I915_WRITE(MIPI_DEVICE_READY(pipe), temp); - } + /* if disable packets are sent before sending shutdown packet then in + * some next enable sequence send turn on packet error is observed */ + if (intel_dsi->dev.dev_ops->disable) + intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); } -static void intel_dsi_post_disable(struct intel_encoder *encoder) +static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + int pipe = intel_crtc->pipe; + u32 val; + DRM_DEBUG_KMS("\n"); + I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER); + usleep_range(2000, 2500); + + I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_EXIT); + usleep_range(2000, 2500); + + I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER); + usleep_range(2000, 2500); + + val = I915_READ(MIPI_PORT_CTRL(pipe)); + I915_WRITE(MIPI_PORT_CTRL(pipe), val & ~LP_OUTPUT_HOLD); + usleep_range(1000, 1500); + + if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & AFE_LATCHOUT) + == 0x00000), 30)) + DRM_ERROR("DSI LP not going Low\n"); + + I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00); + usleep_range(2000, 2500); + vlv_disable_dsi_pll(encoder); } +static void intel_dsi_post_disable(struct intel_encoder *encoder) +{ + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + + DRM_DEBUG_KMS("\n"); + + intel_dsi_clear_device_ready(encoder); + + if (intel_dsi->dev.dev_ops->disable_panel_power) + intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev); +} static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 14509d65f78d..387dfe13cd9b 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -41,6 +41,8 @@ struct intel_dsi_dev_ops { void (*panel_reset)(struct intel_dsi_device *dsi); + void (*disable_panel_power)(struct intel_dsi_device *dsi); + /* one time programmable commands if needed */ void (*send_otp_cmds)(struct intel_dsi_device *dsi); From a4a593be5dcb39ac565fd2dd5a359456070328ac Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Tue, 10 Dec 2013 12:14:59 +0530 Subject: [PATCH 142/595] drm/i915: Remove redundant DSI PLL enabling DSI PLL will get configured during crtc_enable using ->pre_pll_enable and no need to do in ->mode_set Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index e9bcb46dba5f..604fa6cee289 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -373,9 +373,6 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); - /* Update the DSI PLL */ - vlv_enable_dsi_pll(intel_encoder); - /* XXX: Location of the call */ band_gap_reset(dev_priv); From f6da28429a90c87c8329425297a36b85345a3f75 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Tue, 10 Dec 2013 12:15:00 +0530 Subject: [PATCH 143/595] drm/i915: Parametrize the dphy and other spec specific parameters The values of these parameters will be different for differnet panel based on dsi rate, lane count, etc. Remove the hardcodings and make these as parameters whch will be initialized in panel specific sub-encoder implementaion. This will also form groundwork for planned generic panel sub-encoder implemntation based on VBT design enhancments to support multiple panels v2: Mask away the port_bits before use Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi.c | 29 ++++++++++++++--------------- drivers/gpu/drm/i915/intel_dsi.h | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 604fa6cee289..fabbf0d895cf 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -157,7 +157,8 @@ static void intel_dsi_enable(struct intel_encoder *encoder) msleep(100); /* assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(pipe)); + temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK; + temp = temp | intel_dsi->port_bits; I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(pipe)); } @@ -391,11 +392,7 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) I915_WRITE(MIPI_INTR_STAT(pipe), 0xffffffff); I915_WRITE(MIPI_INTR_EN(pipe), 0xffffffff); - I915_WRITE(MIPI_DPHY_PARAM(pipe), - 0x3c << EXIT_ZERO_COUNT_SHIFT | - 0x1f << TRAIL_COUNT_SHIFT | - 0xc5 << CLK_ZERO_COUNT_SHIFT | - 0x1f << PREPARE_COUNT_SHIFT); + I915_WRITE(MIPI_DPHY_PARAM(pipe), intel_dsi->dphy_reg); I915_WRITE(MIPI_DPI_RESOLUTION(pipe), adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT | @@ -443,9 +440,9 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) adjusted_mode->htotal, bpp, intel_dsi->lane_count) + 1); } - I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), 8309); /* max */ - I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), 0x14); /* max */ - I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), 0xffff); /* max */ + I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout); + I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val); + I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), intel_dsi->rst_timer_val); /* dphy stuff */ @@ -460,29 +457,31 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) * * XXX: write MIPI_STOP_STATE_STALL? */ - I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), 0x46); + I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), + intel_dsi->hs_to_lp_count); /* XXX: low power clock equivalence in terms of byte clock. the number * of byte clocks occupied in one low power clock. based on txbyteclkhs * and txclkesc. txclkesc time / txbyteclk time * (105 + * MIPI_STOP_STATE_STALL) / 105.??? */ - I915_WRITE(MIPI_LP_BYTECLK(pipe), 4); + I915_WRITE(MIPI_LP_BYTECLK(pipe), intel_dsi->lp_byte_clk); /* the bw essential for transmitting 16 long packets containing 252 * bytes meant for dcs write memory command is programmed in this * register in terms of byte clocks. based on dsi transfer rate and the * number of lanes configured the time taken to transmit 16 long packets * in a dsi stream varies. */ - I915_WRITE(MIPI_DBI_BW_CTRL(pipe), 0x820); + I915_WRITE(MIPI_DBI_BW_CTRL(pipe), intel_dsi->bw_timer); I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe), - 0xa << LP_HS_SSW_CNT_SHIFT | - 0x14 << HS_LP_PWR_SW_CNT_SHIFT); + intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT | + intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT); if (is_vid_mode(intel_dsi)) I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe), - intel_dsi->video_mode_format); + intel_dsi->video_frmt_cfg_bits | + intel_dsi->video_mode_format); } static enum drm_connector_status diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 387dfe13cd9b..b4a27cec882f 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -96,6 +96,20 @@ struct intel_dsi { /* eot for MIPI_EOT_DISABLE register */ u32 eot_disable; + + u32 port_bits; + u32 bw_timer; + u32 dphy_reg; + u32 video_frmt_cfg_bits; + u16 lp_byte_clk; + + /* timeouts in byte clocks */ + u16 lp_rx_timeout; + u16 turn_arnd_val; + u16 rst_timer_val; + u16 hs_to_lp_count; + u16 clk_lp_to_hs_count; + u16 clk_hs_to_lp_count; }; static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) From b664607480ace4c13c946dee6a1c0e72a2d0d48e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 11 Dec 2013 18:50:08 -0200 Subject: [PATCH 144/595] drm/i915: remove i915_disable_vga_mem declaration It was supposed to have been killed on the same commit that killed the function, e1264ebe9ff48e1b3e1dd11805eec9f5b143ab7c, but I guess the intel_drv.h reorganization accidentally brought it back. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4a4effba134b..a829ab5516f4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -703,7 +703,6 @@ void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config, int dotclock); bool intel_crtc_active(struct drm_crtc *crtc); -void i915_disable_vga_mem(struct drm_device *dev); void hsw_enable_ips(struct intel_crtc *crtc); void hsw_disable_ips(struct intel_crtc *crtc); void intel_display_set_init_power(struct drm_device *dev, bool enable); From d5e8fdc8c10bdff9b8af9cc8b25607ae71e26d3b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 11 Dec 2013 18:50:09 -0200 Subject: [PATCH 145/595] drm/i915: extract hsw_power_well_post_{enable, disable} I want to add more code to the post_enable function. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 75 +++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2590a5c90725..d8fb00a2b565 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5681,12 +5681,53 @@ bool intel_display_power_enabled(struct drm_device *dev, return is_enabled; } +static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + unsigned long irqflags; + + if (IS_BROADWELL(dev)) { + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B), + dev_priv->de_irq_mask[PIPE_B]); + I915_WRITE(GEN8_DE_PIPE_IER(PIPE_B), + ~dev_priv->de_irq_mask[PIPE_B] | + GEN8_PIPE_VBLANK); + I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_C), + dev_priv->de_irq_mask[PIPE_C]); + I915_WRITE(GEN8_DE_PIPE_IER(PIPE_C), + ~dev_priv->de_irq_mask[PIPE_C] | + GEN8_PIPE_VBLANK); + POSTING_READ(GEN8_DE_PIPE_IER(PIPE_C)); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } +} + +static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + enum pipe p; + unsigned long irqflags; + + /* + * After this, the registers on the pipes that are part of the power + * well will become zero, so we have to adjust our counters according to + * that. + * + * FIXME: Should we do this in general in drm_vblank_post_modeset? + */ + spin_lock_irqsave(&dev->vbl_lock, irqflags); + for_each_pipe(p) + if (p != PIPE_A) + dev->vblank[p].last = 0; + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); +} + static void hsw_set_power_well(struct drm_device *dev, struct i915_power_well *power_well, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; bool is_enabled, enable_requested; - unsigned long irqflags; uint32_t tmp; WARN_ON(dev_priv->pc8.enabled); @@ -5707,42 +5748,14 @@ static void hsw_set_power_well(struct drm_device *dev, DRM_ERROR("Timeout enabling power well\n"); } - if (IS_BROADWELL(dev)) { - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B), - dev_priv->de_irq_mask[PIPE_B]); - I915_WRITE(GEN8_DE_PIPE_IER(PIPE_B), - ~dev_priv->de_irq_mask[PIPE_B] | - GEN8_PIPE_VBLANK); - I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_C), - dev_priv->de_irq_mask[PIPE_C]); - I915_WRITE(GEN8_DE_PIPE_IER(PIPE_C), - ~dev_priv->de_irq_mask[PIPE_C] | - GEN8_PIPE_VBLANK); - POSTING_READ(GEN8_DE_PIPE_IER(PIPE_C)); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - } + hsw_power_well_post_enable(dev_priv); } else { if (enable_requested) { - enum pipe p; - I915_WRITE(HSW_PWR_WELL_DRIVER, 0); POSTING_READ(HSW_PWR_WELL_DRIVER); DRM_DEBUG_KMS("Requesting to disable the power well\n"); - /* - * After this, the registers on the pipes that are part - * of the power well will become zero, so we have to - * adjust our counters according to that. - * - * FIXME: Should we do this in general in - * drm_vblank_post_modeset? - */ - spin_lock_irqsave(&dev->vbl_lock, irqflags); - for_each_pipe(p) - if (p != PIPE_A) - dev->vblank[p].last = 0; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + hsw_power_well_post_disable(dev_priv); } } } From f9dcb0dfee98406c9c64e1aad10af427d644b78f Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 11 Dec 2013 18:50:10 -0200 Subject: [PATCH 146/595] drm/i915: touch VGA MSR after we enable the power well Fixes regression introduced by: commit bf51d5e2cda5d36d98e4b46ac7fca9461e512c41 Author: Paulo Zanoni Date: Wed Jul 3 17:12:13 2013 -0300 drm/i915: switch disable_power_well default value to 1 The bug I'm seeing can be reproduced with: - Have vgacon configured/enabled - Make sure the power well gets disabled, then enabled. You can check this by seeing the messages print by hsw_set_power_well - Stop your display manager - echo 0 > /sys/class/vtconsole/vtcon1/bind I can easily reproduce this by blacklising snd_hda_intel and booting with eDP+HDMI. If you do this and then look at dmesg, you'll see we're printing infinite "Unclaimed register" messages. This is happening because we're stuck on an infinite loop inside console_unlock(), which is calling many functions from vgacon.c. And the code that's triggering the error messages is from vgacon_set_cursor_size(). After we re-enable the power well, every time we read/write the VGA address 0x3d5 we get an "unclaimed register" interrupt (ERR_INT) and print error messages. If we write anything to the VGA MSR register (it doesn't really matter which value you write to bit 0), any reads/writes to 0x3d5 _don't_ trigger the "unclaimed register" errors anymore (even if MSR bit 0 is zero). So what happens with the current code is that when we unbind i915 and bind vgacon, we call console_unlock(). Function console_unlock() is responsible for printing any messages that were supposed to be print when the console was locked, so it calls the TTY layer, which calls the console layer, which calls vgacon to print the messages. At this point, vgacon eventually calls vgacon_set_cursor_size(), which touches 0x3d5, which triggers unclaimed register interrupts. The problem is that when we get these interrupts, we print the error messages, so we add more work to console_unlock(), which will try to print it again, and then call vgacon again, trigger a new interrupt, which will put more stuff to the buffer, and then we'll be stuck at console_unlock() forever. If you patch intel_uncore.c to not print anything when we detect unclaimed registers, we won't get into the console_unlock() infinite loop and the driver unbind will work just fine. We will still be getting interrupts every time vgacon touches those registers, but we will survive. This is a valid experiment, but IMHO it's not the real fix: if we don't print any error messages we will still keep getting the interrupts, and if we disable ERR_INT we won't get the interrupt anymore, but we will also stop getting all the other error interrupts. I talked about this problem with the HW engineer and his recommendation is "So don't do any VGA I/O or memory access while the power well is disabled, and make to re-program MSR after enabling the power well and before using VGA I/O or memory accesses.". Notice that this is just a partial fix to fd.o #67813. This fixes the case where the power well is already enabled when we unbind, not when it's disabled when we unbind. V2: - Rebase (first version was sent in September). V3: - Complete rewrite of the same fix: smaller implementation, improved commit message. Testcase: igt/drv_module_reload Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=67813 Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d8fb00a2b565..3cd521f3823b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -30,6 +30,7 @@ #include "intel_drv.h" #include "../../../platform/x86/intel_ips.h" #include +#include #include #include @@ -5686,6 +5687,20 @@ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv) struct drm_device *dev = dev_priv->dev; unsigned long irqflags; + /* + * After we re-enable the power well, if we touch VGA register 0x3d5 + * we'll get unclaimed register interrupts. This stops after we write + * anything to the VGA MSR register. The vgacon module uses this + * register all the time, so if we unbind our driver and, as a + * consequence, bind vgacon, we'll get stuck in an infinite loop at + * console_unlock(). So make here we touch the VGA MSR register, making + * sure vgacon can keep working normally without triggering interrupts + * and error messages. + */ + vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); + outb(inb(VGA_MSR_READ), VGA_MSR_WRITE); + vga_put(dev->pdev, VGA_RSRC_LEGACY_IO); + if (IS_BROADWELL(dev)) { spin_lock_irqsave(&dev_priv->irq_lock, irqflags); I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B), From 47e9766df0298739aab87c9874a21feb71560953 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 10 Dec 2013 17:02:43 +0200 Subject: [PATCH 147/595] drm/i915: Fix timeout with missed interrupts in __wait_seqno MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 094f9a54e355 ("drm/i915: Fix __wait_seqno to use true infinite timeouts") added support for __wait_seqno to detect missing interrupts and go around them by polling. As there is also timeout detection in __wait_seqno, the polling and timeout detection were done with the same timer. When there has been missed interrupts and polling is needed, the timer is set to trigger in (now + 1) jiffies in future, instead of the caller specified timeout. Now when io_schedule() returns, we calculate the jiffies left to timeout using the timer expiration value. As the current jiffies is now bound to be always equal or greater than the expiration value, the timeout_jiffies will become zero or negative and we return -ETIME to caller even tho the timeout was never reached. Fix this by decoupling timeout calculation from timer expiration. v2: Commit message with some sense in it (Chris Wilson) v3: add parenthesis on timeout_expire calculation v4: don't read jiffies without timeout (Chris Wilson) Signed-off-by: Mika Kuoppala Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index df83fec174e9..279387a2fef5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1017,7 +1017,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, drm_i915_private_t *dev_priv = ring->dev->dev_private; struct timespec before, now; DEFINE_WAIT(wait); - long timeout_jiffies; + unsigned long timeout_expire; int ret; WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n"); @@ -1025,7 +1025,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, if (i915_seqno_passed(ring->get_seqno(ring, true), seqno)) return 0; - timeout_jiffies = timeout ? timespec_to_jiffies_timeout(timeout) : 1; + timeout_expire = timeout ? jiffies + timespec_to_jiffies_timeout(timeout) : 0; if (dev_priv->info->gen >= 6 && can_wait_boost(file_priv)) { gen6_rps_boost(dev_priv); @@ -1044,7 +1044,6 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, getrawmonotonic(&before); for (;;) { struct timer_list timer; - unsigned long expire; prepare_to_wait(&ring->irq_queue, &wait, interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); @@ -1070,23 +1069,22 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, break; } - if (timeout_jiffies <= 0) { + if (timeout && time_after_eq(jiffies, timeout_expire)) { ret = -ETIME; break; } timer.function = NULL; if (timeout || missed_irq(dev_priv, ring)) { + unsigned long expire; + setup_timer_on_stack(&timer, fake_irq, (unsigned long)current); - expire = jiffies + (missed_irq(dev_priv, ring) ? 1: timeout_jiffies); + expire = missed_irq(dev_priv, ring) ? jiffies + 1 : timeout_expire; mod_timer(&timer, expire); } io_schedule(); - if (timeout) - timeout_jiffies = expire - jiffies; - if (timer.function) { del_singleshot_timer_sync(&timer); destroy_timer_on_stack(&timer); From 566b734a190766f25f21c8c44633c14a122e61fa Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 25 Nov 2013 15:27:08 -0200 Subject: [PATCH 148/595] drm/i915: split intel_ddi_pll_mode_set in 2 pieces The first piece, intel_ddi_pll_select, finds a PLL and assigns it to the CRTC, but doesn't write any register. It can also fail in case it doesn't find a PLL. The second piece, intel_ddi_pll_enable, uses the information stored by intel_ddi_pll_select to actually enable the PLL by writing to its register. This function can't fail. We also have some refcount sanity checks here. The idea is that one day we'll remove all the functions that touch registers from haswell_crtc_mode_set to haswell_crtc_enable, so we'll call intel_ddi_pll_select at haswell_crtc_mode_set and then call intel_ddi_pll_enable at haswell_crtc_enable. Since I'm already touching this code, let's take care of this particular split today. v2: - Clock on the debug message is in KHz - Add missing POSTING_READ Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau [danvet: Bikeshed comments.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 108 ++++++++++++++++++++++----- drivers/gpu/drm/i915/intel_display.c | 3 +- drivers/gpu/drm/i915/intel_drv.h | 3 +- 3 files changed, 94 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 8b0e96ff76c9..cec06a5453cc 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -696,21 +696,23 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */, *n2_out = best.n2; *p_out = best.p; *r2_out = best.r2; - - DRM_DEBUG_KMS("WRPLL: %dHz refresh rate with p=%d, n2=%d r2=%d\n", - clock, *p_out, *n2_out, *r2_out); } -bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) +/* + * Tries to find a PLL for the CRTC. If it finds, it increases the refcount and + * stores it in intel_crtc->ddi_pll_sel, so other mode sets won't be able to + * steal the selected PLL. You need to call intel_ddi_pll_enable to actually + * enable the PLL. + */ +bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_crtc *crtc = &intel_crtc->base; struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); struct drm_encoder *encoder = &intel_encoder->base; struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_ddi_plls *plls = &dev_priv->ddi_plls; int type = intel_encoder->type; enum pipe pipe = intel_crtc->pipe; - uint32_t reg, val; int clock = intel_crtc->config.port_clock; intel_ddi_put_crtc_pll(crtc); @@ -734,10 +736,8 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) return false; } - /* We don't need to turn any PLL on because we'll use LCPLL. */ - return true; - } else if (type == INTEL_OUTPUT_HDMI) { + uint32_t reg, val; unsigned p, n2, r2; intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); @@ -767,6 +767,9 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) return false; } + DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", + clock, p, n2, r2); + if (reg == WRPLL_CTL1) { plls->wrpll1_refcount++; intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1; @@ -780,29 +783,98 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) DRM_DEBUG_KMS("Using SPLL on pipe %c\n", pipe_name(pipe)); plls->spll_refcount++; - reg = SPLL_CTL; intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL; } else { DRM_ERROR("SPLL already in use\n"); return false; } - WARN(I915_READ(reg) & SPLL_PLL_ENABLE, - "SPLL already enabled\n"); - - val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC; - } else { WARN(1, "Invalid DDI encoder type %d\n", type); return false; } - I915_WRITE(reg, val); - udelay(20); - return true; } +/* + * To be called after intel_ddi_pll_select(). That one selects the PLL to be + * used, this one actually enables the PLL. + */ +void intel_ddi_pll_enable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + int clock = crtc->config.port_clock; + uint32_t reg, cur_val, new_val; + int refcount; + const char *pll_name; + uint32_t enable_bit = (1 << 31); + unsigned int p, n2, r2; + + BUILD_BUG_ON(enable_bit != SPLL_PLL_ENABLE); + BUILD_BUG_ON(enable_bit != WRPLL_PLL_ENABLE); + + switch (crtc->ddi_pll_sel) { + case PORT_CLK_SEL_LCPLL_2700: + case PORT_CLK_SEL_LCPLL_1350: + case PORT_CLK_SEL_LCPLL_810: + /* + * LCPLL should always be enabled at this point of the mode set + * sequence, so nothing to do. + */ + return; + + case PORT_CLK_SEL_SPLL: + pll_name = "SPLL"; + reg = SPLL_CTL; + refcount = plls->spll_refcount; + new_val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | + SPLL_PLL_SSC; + break; + + case PORT_CLK_SEL_WRPLL1: + case PORT_CLK_SEL_WRPLL2: + if (crtc->ddi_pll_sel == PORT_CLK_SEL_WRPLL1) { + pll_name = "WRPLL1"; + reg = WRPLL_CTL1; + refcount = plls->wrpll1_refcount; + } else { + pll_name = "WRPLL2"; + reg = WRPLL_CTL2; + refcount = plls->wrpll2_refcount; + } + + intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); + + new_val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | + WRPLL_DIVIDER_REFERENCE(r2) | + WRPLL_DIVIDER_FEEDBACK(n2) | WRPLL_DIVIDER_POST(p); + + break; + + case PORT_CLK_SEL_NONE: + WARN(1, "Bad selected pll: PORT_CLK_SEL_NONE\n"); + return; + default: + WARN(1, "Bad selected pll: 0x%08x\n", crtc->ddi_pll_sel); + return; + } + + cur_val = I915_READ(reg); + + WARN(refcount < 1, "Bad %s refcount: %d\n", pll_name, refcount); + if (refcount == 1) { + WARN(cur_val & enable_bit, "%s already enabled\n", pll_name); + I915_WRITE(reg, new_val); + POSTING_READ(reg); + udelay(20); + } else { + WARN((cur_val & enable_bit) == 0, "%s disabled\n", pll_name); + } +} + void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c01aff8a36bb..a40651ef525c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6902,8 +6902,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, int plane = intel_crtc->plane; int ret; - if (!intel_ddi_pll_mode_set(crtc)) + if (!intel_ddi_pll_select(intel_crtc)) return -EINVAL; + intel_ddi_pll_enable(intel_crtc); if (intel_crtc->config.has_dp_encoder) intel_dp_set_m_n(intel_crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a829ab5516f4..e903432c7c37 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -613,7 +613,8 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc); void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc); void intel_ddi_setup_hw_pll_state(struct drm_device *dev); -bool intel_ddi_pll_mode_set(struct drm_crtc *crtc); +bool intel_ddi_pll_select(struct intel_crtc *crtc); +void intel_ddi_pll_enable(struct intel_crtc *crtc); void intel_ddi_put_crtc_pll(struct drm_crtc *crtc); void intel_ddi_set_pipe_settings(struct drm_crtc *crtc); void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); From 42a430f51c7500be41ca4cbd5b3de930853bd5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:29:56 +0200 Subject: [PATCH 149/595] drm/i915: Gen2 FBC1 CFB pitch wants 32B units MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On gen2 the compressed frame buffer pitch is specified in 32B units rather than the 64B units used on gen3+. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3cd521f3823b..599d445f7ce9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -104,8 +104,11 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) if (fb->pitches[0] < cfb_pitch) cfb_pitch = fb->pitches[0]; - /* FBC_CTL wants 64B units */ - cfb_pitch = (cfb_pitch / 64) - 1; + /* FBC_CTL wants 32B or 64B units */ + if (IS_GEN2(dev)) + cfb_pitch = (cfb_pitch / 32) - 1; + else + cfb_pitch = (cfb_pitch / 64) - 1; plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB; /* Clear old tags */ From 159f98750e413f5d6e63d1131417c5310ea175fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:29:57 +0200 Subject: [PATCH 150/595] drm/i915: FBC_CONTROL2 is gen4 only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gen2 and gen3 don't have the FBC_CONTROL2 register, so don't touch it. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 599d445f7ce9..d7cb6bf5712d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -98,7 +98,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int cfb_pitch; int plane, i; - u32 fbc_ctl, fbc_ctl2; + u32 fbc_ctl; cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE; if (fb->pitches[0] < cfb_pitch) @@ -115,11 +115,15 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) I915_WRITE(FBC_TAG + (i * 4), 0); - /* Set it up... */ - fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; - fbc_ctl2 |= plane; - I915_WRITE(FBC_CONTROL2, fbc_ctl2); - I915_WRITE(FBC_FENCE_OFF, crtc->y); + if (IS_GEN4(dev)) { + u32 fbc_ctl2; + + /* Set it up... */ + fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; + fbc_ctl2 |= plane; + I915_WRITE(FBC_CONTROL2, fbc_ctl2); + I915_WRITE(FBC_FENCE_OFF, crtc->y); + } /* enable it... */ fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; From fd70d52acc7abef6402e21e3e11950773af3d769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:30:02 +0200 Subject: [PATCH 151/595] drm/i915: Enable FBC for all mobile gen2 and gen3 platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All mobile gen2 and gen3 chipsets should have FBC1, and the code should now handle them all. So just set has_fbc=true for all such chipsets. Note that fbc is still disabled by default for now. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2137a33d5bb2..c2c9a93861ae 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -172,6 +172,7 @@ static const struct intel_device_info intel_i85x_info = { .gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, + .has_fbc = 1, .ring_mask = RENDER_RING, }; @@ -191,6 +192,7 @@ static const struct intel_device_info intel_i915gm_info = { .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, + .has_fbc = 1, .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i945g_info = { @@ -203,6 +205,7 @@ static const struct intel_device_info intel_i945gm_info = { .has_hotplug = 1, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, + .has_fbc = 1, .ring_mask = RENDER_RING, }; From 993495ae992c91e98ade8fbe977c57bfd81910c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 12 Dec 2013 17:27:40 +0200 Subject: [PATCH 152/595] drm/i915: Rework the FBC interval/stall stuff a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't touch DPFC_RECOMP_CTL on FBC2, use RMW to update the FBC_CONTROL on FBC1 to make it easier for people to experiment with different numbers. Also fix the interval mask for FBC1. v2: Rebased Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +-- drivers/gpu/drm/i915/intel_pm.c | 34 ++++++++++++++------------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 709b20e0e3f0..ae2c80c1981b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -372,7 +372,7 @@ struct dpll; struct drm_i915_display_funcs { bool (*fbc_enabled)(struct drm_device *dev); - void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); + void (*enable_fbc)(struct drm_crtc *crtc); void (*disable_fbc)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); @@ -695,7 +695,6 @@ struct i915_fbc { struct delayed_work work; struct drm_crtc *crtc; struct drm_framebuffer *fb; - int interval; } *fbc_work; enum no_fbc_reason { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d7cb6bf5712d..c68abf718825 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -88,7 +88,7 @@ static void i8xx_disable_fbc(struct drm_device *dev) DRM_DEBUG_KMS("disabled FBC\n"); } -static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void i8xx_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -126,11 +126,12 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) } /* enable it... */ - fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; + fbc_ctl = I915_READ(FBC_CONTROL); + fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT; + fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC; if (IS_I945GM(dev)) fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; - fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; fbc_ctl |= obj->fence_reg; I915_WRITE(FBC_CONTROL, fbc_ctl); @@ -145,7 +146,7 @@ static bool i8xx_fbc_enabled(struct drm_device *dev) return I915_READ(FBC_CONTROL) & FBC_CTL_EN; } -static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void g4x_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -154,16 +155,12 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; - unsigned long stall_watermark = 200; u32 dpfc_ctl; dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY); - I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | - (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | - (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); I915_WRITE(DPFC_FENCE_YOFF, crtc->y); /* enable it... */ @@ -219,7 +216,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA); } -static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void ironlake_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -228,7 +225,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; - unsigned long stall_watermark = 200; u32 dpfc_ctl; dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); @@ -241,9 +237,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) dpfc_ctl |= obj->fence_reg; I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); - I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | - (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | - (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID); /* enable it... */ @@ -281,7 +274,7 @@ static bool ironlake_fbc_enabled(struct drm_device *dev) return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; } -static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void gen7_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -338,8 +331,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) * the prior work. */ if (work->crtc->fb == work->fb) { - dev_priv->display.enable_fbc(work->crtc, - work->interval); + dev_priv->display.enable_fbc(work->crtc); dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane; dev_priv->fbc.fb_id = work->crtc->fb->base.id; @@ -376,7 +368,7 @@ static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) dev_priv->fbc.fbc_work = NULL; } -static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void intel_enable_fbc(struct drm_crtc *crtc) { struct intel_fbc_work *work; struct drm_device *dev = crtc->dev; @@ -390,13 +382,12 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) work = kzalloc(sizeof(*work), GFP_KERNEL); if (work == NULL) { DRM_ERROR("Failed to allocate FBC work structure\n"); - dev_priv->display.enable_fbc(crtc, interval); + dev_priv->display.enable_fbc(crtc); return; } work->crtc = crtc; work->fb = crtc->fb; - work->interval = interval; INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); dev_priv->fbc.fbc_work = work; @@ -611,7 +602,7 @@ void intel_update_fbc(struct drm_device *dev) intel_disable_fbc(dev); } - intel_enable_fbc(crtc, 500); + intel_enable_fbc(crtc); dev_priv->fbc.no_fbc_reason = FBC_OK; return; @@ -6073,6 +6064,9 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.fbc_enabled = i8xx_fbc_enabled; dev_priv->display.enable_fbc = i8xx_enable_fbc; dev_priv->display.disable_fbc = i8xx_disable_fbc; + + /* This value was pulled out of someone's hat */ + I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); } } From 168c3f2151a7de906b060a335d19b0ba483a6718 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 12 Dec 2013 17:54:42 +0200 Subject: [PATCH 153/595] drm/i915: dont call irq_put when irq test is on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If test is running, irq_get was not called so we should gain balance by not doing irq_put "So the rule is: if you access unlocked values, you use ACCESS_ONCE(). You don't say "but it can't matter". Because you simply don't know." -- Linus v2: use local variable so it can't change during test (Chris) v3: update commit msg and use ACCESS_ONCE (Ville) Signed-off-by: Mika Kuoppala Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 279387a2fef5..e34b48e862e7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1015,6 +1015,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, struct drm_i915_file_private *file_priv) { drm_i915_private_t *dev_priv = ring->dev->dev_private; + const bool irq_test_in_progress = + ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring); struct timespec before, now; DEFINE_WAIT(wait); unsigned long timeout_expire; @@ -1035,8 +1037,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, msecs_to_jiffies(100)); } - if (!(dev_priv->gpu_error.test_irq_rings & intel_ring_flag(ring)) && - WARN_ON(!ring->irq_get(ring))) + if (!irq_test_in_progress && WARN_ON(!ring->irq_get(ring))) return -ENODEV; /* Record current time in case interrupted by signal, or wedged */ @@ -1093,7 +1094,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, getrawmonotonic(&now); trace_i915_gem_request_wait_end(ring, seqno); - ring->irq_put(ring); + if (!irq_test_in_progress) + ring->irq_put(ring); finish_wait(&ring->irq_queue, &wait); From 97058870e616631a80721e08d5797d7da4b23b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 3 Dec 2013 11:30:09 +0200 Subject: [PATCH 154/595] drm/i915: Clear out old GT FIFO errors in intel_uncore_early_sanitize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BIOS or someone else might have done something bad and there might be old GT FIFO erros reported in GTFIFODBG. Clear those out in intel_uncore_early_sanitize() to make sure we don't mistake them for our problems. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 8102af9a178d..32527a74dc46 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -332,6 +332,11 @@ void intel_uncore_early_sanitize(struct drm_device *dev) DRM_INFO("Found %zuMB of eLLC\n", dev_priv->ellc_size); } + /* clear out old GT FIFO errors */ + if (IS_GEN6(dev) || IS_GEN7(dev)) + __raw_i915_write32(dev_priv, GTFIFODBG, + __raw_i915_read32(dev_priv, GTFIFODBG)); + intel_uncore_forcewake_reset(dev); } From a3564d2b5236b73bceb271f482965d38cd9d8d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 Dec 2013 13:26:20 +0200 Subject: [PATCH 155/595] drm/i915/bdw: Don't use forcewake needlessly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not all registers need forcewake even if they're not shadowed. Add the missing check to gen8_writeX() to avoid needless forcewake usage when writing eg. display registers. v2: Use straight up <0x40000 check instead of NEEDS_FORCE_WAKE() Reviewed-by: Ben Widawsky Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 32527a74dc46..2c8143c37de3 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -634,7 +634,7 @@ static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg) #define __gen8_write(x) \ static void \ gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ - bool __needs_put = !is_gen8_shadowed(dev_priv, reg); \ + bool __needs_put = reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg); \ REG_WRITE_HEADER; \ if (__needs_put) { \ dev_priv->uncore.funcs.force_wake_get(dev_priv, \ From 63801f211c6eeb6def635ceee39d165e00fd6e09 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 12 Dec 2013 17:26:03 -0800 Subject: [PATCH 156/595] drm/i915/bdw: Force all Data Cache Data Port access to be Non-Coherent I stumbled on to some unimplemented errata. To be honest, I am not really sure of the impact, just that the docs say to do. No w/a name for this one. v2: v1 was a stale thing which should have never seen the light of day. (Haihao) Cc: Kenneth Graunke Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_pm.c | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e8cc27cd9494..3259e83eb2c6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4167,6 +4167,10 @@ #define GEN7_L3SQCREG4 0xb034 #define L3SQ_URB_READ_CAM_MATCH_DISABLE (1<<27) +/* GEN8 chicken */ +#define HDC_CHICKEN0 0x7300 +#define HDC_FORCE_NON_COHERENT (1<<4) + /* WaCatErrorRejectionIssue */ #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG 0x9030 #define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c68abf718825..791fbe386b7c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5269,6 +5269,14 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_READ(CHICKEN_PIPESL_1(i) | DPRS_MASK_VBLANK_SRD)); } + + /* Use Force Non-Coherent whenever executing a 3D context. This is a + * workaround for for a possible hang in the unlikely event a TLB + * invalidation occurs during a PSD flush. + */ + I915_WRITE(HDC_CHICKEN0, + I915_READ(HDC_CHICKEN0) | + _MASKED_BIT_ENABLE(HDC_FORCE_NON_COHERENT)); } static void haswell_init_clock_gating(struct drm_device *dev) From ab57fff1302c485d74992d34df24ccb5efda244e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 12 Dec 2013 15:28:04 -0800 Subject: [PATCH 157/595] drm/i915/bdw: Implement ff workarounds WaVSRefCountFullforceMissDisable and WaDSRefCountFullforceMissDisable VS is a carry-over from HSW, and DS is likely not used by anyone yet. Cc: Kenneth Graunke Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau [danvet: Line of 106 chars is too long. Really.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3259e83eb2c6..f1eece4a63d5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1003,6 +1003,7 @@ #define GEN7_FF_THREAD_MODE 0x20a0 #define GEN7_FF_SCHED_MASK 0x0077070 +#define GEN8_FF_DS_REF_CNT_FFME (1 << 19) #define GEN7_FF_TS_SCHED_HS1 (0x5<<16) #define GEN7_FF_TS_SCHED_HS0 (0x3<<16) #define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 791fbe386b7c..b35f65ed6c5e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5256,14 +5256,14 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, _MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE)); - /* WaSwitchSolVfFArbitrationPriority */ + /* WaSwitchSolVfFArbitrationPriority:bdw */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); - /* WaPsrDPAMaskVBlankInSRD */ + /* WaPsrDPAMaskVBlankInSRD:bdw */ I915_WRITE(CHICKEN_PAR1_1, I915_READ(CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD); - /* WaPsrDPRSUnmaskVBlankInSRD */ + /* WaPsrDPRSUnmaskVBlankInSRD:bdw */ for_each_pipe(i) { I915_WRITE(CHICKEN_PIPESL_1(i), I915_READ(CHICKEN_PIPESL_1(i) | @@ -5277,6 +5277,12 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_WRITE(HDC_CHICKEN0, I915_READ(HDC_CHICKEN0) | _MASKED_BIT_ENABLE(HDC_FORCE_NON_COHERENT)); + + /* WaVSRefCountFullforceMissDisable:bdw */ + /* WaDSRefCountFullforceMissDisable:bdw */ + I915_WRITE(GEN7_FF_THREAD_MODE, + I915_READ(GEN7_FF_THREAD_MODE) & + ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME)); } static void haswell_init_clock_gating(struct drm_device *dev) From 16a3d6ef9f9db6b0e54e6bb756a6b6165166cf44 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 13 Dec 2013 15:22:30 -0200 Subject: [PATCH 158/595] drm/i915: cancel the hangcheck before runtime suspend The hangcheck function requires the hardware to be working, and if we're suspending we're going to put the HW in D3 state. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c2c9a93861ae..df634a42cc0c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -917,6 +917,7 @@ static int i915_runtime_suspend(struct device *device) DRM_DEBUG_KMS("Suspending device\n"); + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); dev_priv->pm.suspended = true; intel_opregion_notify_adapter(dev, PCI_D3cold); From 48018a57a8f5900e7e53ffaa0adeb784095accfb Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 13 Dec 2013 15:22:31 -0200 Subject: [PATCH 159/595] drm/i915: release the GTT mmaps when going into D3 So we'll get a fault when someone tries to access the mmap, then we'll wake up from D3. v2: - Rebase v3: - Use gtt active/inactive Testcase: igt/pm_pc8/gem-mmap-gtt Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi [danvet: Add comment + WARN as discussed with Paulo on irc.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 16 ++++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index df634a42cc0c..aea909b2f22e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -917,6 +917,8 @@ static int i915_runtime_suspend(struct device *device) DRM_DEBUG_KMS("Suspending device\n"); + i915_gem_release_all_mmaps(dev_priv); + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); dev_priv->pm.suspended = true; intel_opregion_notify_adapter(dev, PCI_D3cold); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ae2c80c1981b..9e4b5ca6ee72 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2015,6 +2015,7 @@ void i915_gem_object_unpin(struct drm_i915_gem_object *obj); int __must_check i915_vma_unbind(struct i915_vma *vma); int __must_check i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj); int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); +void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e34b48e862e7..c5a99c46ca9c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1465,6 +1465,22 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return ret; } +void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv) +{ + struct i915_vma *vma; + + /* + * Only the global gtt is relevant for gtt memory mappings, so restrict + * list traversal to objects bound into the global address space. Note + * that the active list should be empty, but better safe than sorry. + */ + WARN_ON(!list_empty(&dev_priv->gtt.base.active_list)); + list_for_each_entry(vma, &dev_priv->gtt.base.active_list, mm_list) + i915_gem_release_mmap(vma->obj); + list_for_each_entry(vma, &dev_priv->gtt.base.inactive_list, mm_list) + i915_gem_release_mmap(vma->obj); +} + /** * i915_gem_release_mmap - remove physical page mappings * @obj: obj in question From df4547d82589714f1b0cecd93569130a452cbf46 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 13 Dec 2013 15:22:32 -0200 Subject: [PATCH 160/595] drm/i915: add runtime PM support on Haswell Now that all the infrastructure is in place and all the tests from pm_pc8 pass, we can finally enable the feature. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9e4b5ca6ee72..67f2ca1e50e0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1848,7 +1848,7 @@ struct drm_i915_file_private { #define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) #define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev)) #define HAS_PC8(dev) (IS_HASWELL(dev)) /* XXX HSW:ULX */ -#define HAS_RUNTIME_PM(dev) false +#define HAS_RUNTIME_PM(dev) (IS_HASWELL(dev)) #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 From f00076d2fd3fe25b2e8c83921818914dee37ffef Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Sat, 14 Dec 2013 20:38:29 -0200 Subject: [PATCH 161/595] drm/i915: parse backlight modulation frequency from the BIOS VBT We don't actually do anything with the information yet, but parse and log what's in the VBT. Signed-off-by: Jani Nikula Signed-off-by: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +++++ drivers/gpu/drm/i915/intel_bios.c | 29 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_bios.h | 16 ++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 67f2ca1e50e0..b0a6e767951c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1184,6 +1184,11 @@ struct intel_vbt_data { int edp_bpp; struct edp_power_seq edp_pps; + struct { + u16 pwm_freq_hz; + bool active_low_pwm; + } backlight; + /* MIPI DSI */ struct { u16 panel_id; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index f88e5079a3f5..f22041973f3a 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -281,6 +281,34 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, } } +static void +parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) +{ + const struct bdb_lfp_backlight_data *backlight_data; + const struct bdb_lfp_backlight_data_entry *entry; + + backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); + if (!backlight_data) + return; + + if (backlight_data->entry_size != sizeof(backlight_data->data[0])) { + DRM_DEBUG_KMS("Unsupported backlight data entry size %u\n", + backlight_data->entry_size); + return; + } + + entry = &backlight_data->data[panel_type]; + + dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; + dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; + DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " + "active %s, min brightness %u, level %u\n", + dev_priv->vbt.backlight.pwm_freq_hz, + dev_priv->vbt.backlight.active_low_pwm ? "low" : "high", + entry->min_brightness, + backlight_data->level[panel_type]); +} + /* Try to find sdvo panel data */ static void parse_sdvo_panel_data(struct drm_i915_private *dev_priv, @@ -894,6 +922,7 @@ intel_parse_bios(struct drm_device *dev) parse_general_features(dev_priv, bdb); parse_general_definitions(dev_priv, bdb); parse_lfp_panel_data(dev_priv, bdb); + parse_lfp_backlight(dev_priv, bdb); parse_sdvo_panel_data(dev_priv, bdb); parse_sdvo_device_mapping(dev_priv, bdb); parse_device_mapping(dev_priv, bdb); diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 81ed58cb7b31..282de5e9f39d 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -373,6 +373,22 @@ struct bdb_lvds_lfp_data { struct bdb_lvds_lfp_data_entry data[16]; } __packed; +struct bdb_lfp_backlight_data_entry { + u8 type:2; + u8 active_low_pwm:1; + u8 obsolete1:5; + u16 pwm_freq_hz; + u8 min_brightness; + u8 obsolete2; + u8 obsolete3; +} __packed; + +struct bdb_lfp_backlight_data { + u8 entry_size; + struct bdb_lfp_backlight_data_entry data[16]; + u8 level[16]; +} __packed; + struct aimdb_header { char signature[16]; char oem_device[20]; From f3c5fe979117908fb642ed130ae2cd78cb005931 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 16 Dec 2013 14:13:25 +0800 Subject: [PATCH 162/595] drm/i915: fix return value check of debugfs_create_file() In case of error, the function debugfs_create_file() returns NULL pointer not ERR_PTR() if debugfs is enabled. The IS_ERR() test in the return value check should be replaced with NULL test. Signed-off-by: Wei Yongjun Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6badc1596ceb..242189ee3607 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2117,8 +2117,8 @@ static int i915_pipe_crc_create(struct dentry *root, struct drm_minor *minor, info->dev = dev; ent = debugfs_create_file(info->name, S_IRUGO, root, info, &i915_pipe_crc_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); + if (!ent) + return -ENOMEM; return drm_add_fake_info_node(minor, ent, info); } @@ -3133,8 +3133,8 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor) S_IRUSR, root, dev, &i915_forcewake_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); + if (!ent) + return -ENOMEM; return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops); } @@ -3151,8 +3151,8 @@ static int i915_debugfs_create(struct dentry *root, S_IRUGO | S_IWUSR, root, dev, fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); + if (!ent) + return -ENOMEM; return drm_add_fake_info_node(minor, ent, fops); } From a57750f210ef4dcf271cd24d9b3e2ee0d267ad03 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 16 Dec 2013 13:10:36 +0200 Subject: [PATCH 163/595] drm/i915: only build i915_debugfs.c when CONFIG_DEBUG_FS is enabled The whole file is wrapped around in #if defined(CONFIG_DEBUG_FS) anyway, so skip the file at the build level already. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 3 ++- drivers/gpu/drm/i915/i915_debugfs.c | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 41838eaa799c..da682cbcb806 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -4,7 +4,6 @@ ccflags-y := -Iinclude/drm i915-y := i915_drv.o i915_dma.o i915_irq.o \ - i915_debugfs.o \ i915_gpu_error.o \ i915_suspend.o \ i915_gem.o \ @@ -55,6 +54,8 @@ i915-$(CONFIG_ACPI) += intel_acpi.o i915-$(CONFIG_DRM_I915_FBDEV) += intel_fbdev.o +i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o + obj-$(CONFIG_DRM_I915) += i915.o CFLAGS_i915_trace_points.o := -I$(src) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 242189ee3607..6294ffdcc0ac 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -40,8 +40,6 @@ #include #include "i915_drv.h" -#if defined(CONFIG_DEBUG_FS) - enum { ACTIVE_LIST, INACTIVE_LIST, @@ -3282,5 +3280,3 @@ void i915_debugfs_cleanup(struct drm_minor *minor) drm_debugfs_remove_files(info_list, 1, minor); } } - -#endif /* CONFIG_DEBUG_FS */ From f42bb70d4ff976b134fcbfb50301a87e7523f042 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 16 Dec 2013 16:34:23 -0800 Subject: [PATCH 164/595] drm/i915/vlv: add early DPIO init v3 Just add an early init since we may need to access DPIO regs early on. The init call in modeset_init_hw is also needed for the resume case, when we need to reset DPIO to keep things happy. v2: split reset and reg init v3: split patches (Daniel) Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a40651ef525c..9405340369d1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10871,6 +10871,8 @@ void intel_modeset_init(struct drm_device *dev) } } + intel_init_dpio(dev); + intel_cpu_pll_init(dev); intel_shared_dpll_init(dev); From 5382f5f35e73e5c7ac486824d1e26a2f44de0eec Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 16 Dec 2013 16:34:24 -0800 Subject: [PATCH 165/595] drm/i915/vlv: split DPIO init and reset We only need to init the reg offset for DPIO once, but we need to reset DPIO at resume time and at init time. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9405340369d1..066fc9ddbd28 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1372,6 +1372,15 @@ static void intel_init_dpio(struct drm_device *dev) DPLL_INTEGRATED_CRI_CLK_VLV); DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO; +} + +static void intel_reset_dpio(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_VALLEYVIEW(dev)) + return; + /* * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx - * 6. De-assert cmn_reset/side_reset. Same as VLV X0. @@ -10809,7 +10818,7 @@ void intel_modeset_init_hw(struct drm_device *dev) intel_init_clock_gating(dev); - intel_init_dpio(dev); + intel_reset_dpio(dev); mutex_lock(&dev->struct_mutex); intel_enable_gt_powersave(dev); @@ -10872,6 +10881,7 @@ void intel_modeset_init(struct drm_device *dev) } intel_init_dpio(dev); + intel_reset_dpio(dev); intel_cpu_pll_init(dev); intel_shared_dpll_init(dev); From 0e79284d138d01a794cb860af5c4d2c0eb8f6fda Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 16 Dec 2013 20:50:37 -0800 Subject: [PATCH 166/595] drm/i915: Reorder/respace MI instruction definition A few command were out of numerical order and had different spacing. Put them back in numerical order, with proper spacing. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 52 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f1eece4a63d5..ac87ab883ff7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -193,10 +193,13 @@ #define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ #define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ #define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */ +#define MI_REPORT_HEAD MI_INSTR(0x07, 0) +#define MI_ARB_ON_OFF MI_INSTR(0x08, 0) +#define MI_ARB_ENABLE (1<<0) +#define MI_ARB_DISABLE (0<<0) #define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) #define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0) #define MI_SUSPEND_FLUSH_EN (1<<0) -#define MI_REPORT_HEAD MI_INSTR(0x07, 0) #define MI_OVERLAY_FLIP MI_INSTR(0x11, 0) #define MI_OVERLAY_CONTINUE (0x0<<21) #define MI_OVERLAY_ON (0x1<<21) @@ -212,10 +215,24 @@ #define MI_DISPLAY_FLIP_IVB_SPRITE_B (3 << 19) #define MI_DISPLAY_FLIP_IVB_PLANE_C (4 << 19) #define MI_DISPLAY_FLIP_IVB_SPRITE_C (5 << 19) -#define MI_ARB_ON_OFF MI_INSTR(0x08, 0) -#define MI_ARB_ENABLE (1<<0) -#define MI_ARB_DISABLE (0<<0) - +#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */ +#define MI_SEMAPHORE_GLOBAL_GTT (1<<22) +#define MI_SEMAPHORE_UPDATE (1<<21) +#define MI_SEMAPHORE_COMPARE (1<<20) +#define MI_SEMAPHORE_REGISTER (1<<18) +#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */ +#define MI_SEMAPHORE_SYNC_VER (1<<16) /* RCS wait for VECS (RVESYNC) */ +#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */ +#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */ +#define MI_SEMAPHORE_SYNC_VEV (1<<16) /* VCS wait for VECS (VVESYNC) */ +#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */ +#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */ +#define MI_SEMAPHORE_SYNC_VEB (1<<16) /* BCS wait for VECS (BVESYNC) */ +#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */ +#define MI_SEMAPHORE_SYNC_BVE (0<<16) /* VECS wait for BCS (VEBSYNC) */ +#define MI_SEMAPHORE_SYNC_VVE (1<<16) /* VECS wait for VCS (VEVSYNC) */ +#define MI_SEMAPHORE_SYNC_RVE (2<<16) /* VECS wait for RCS (VERSYNC) */ +#define MI_SEMAPHORE_SYNC_INVALID (3<<16) #define MI_SET_CONTEXT MI_INSTR(0x18, 0) #define MI_MM_SPACE_GTT (1<<8) #define MI_MM_SPACE_PHYSICAL (0<<8) @@ -235,7 +252,7 @@ */ #define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*x-1) #define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*x-1) -#define MI_SRM_LRM_GLOBAL_GTT (1<<22) +#define MI_SRM_LRM_GLOBAL_GTT (1<<22) #define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ #define MI_FLUSH_DW_STORE_INDEX (1<<21) #define MI_INVALIDATE_TLB (1<<18) @@ -246,30 +263,13 @@ #define MI_BATCH_BUFFER MI_INSTR(0x30, 1) #define MI_BATCH_NON_SECURE (1) /* for snb/ivb/vlv this also means "batch in ppgtt" when ppgtt is enabled. */ -#define MI_BATCH_NON_SECURE_I965 (1<<8) +#define MI_BATCH_NON_SECURE_I965 (1<<8) #define MI_BATCH_PPGTT_HSW (1<<8) -#define MI_BATCH_NON_SECURE_HSW (1<<13) +#define MI_BATCH_NON_SECURE_HSW (1<<13) #define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) #define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */ #define MI_BATCH_BUFFER_START_GEN8 MI_INSTR(0x31, 1) -#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */ -#define MI_SEMAPHORE_GLOBAL_GTT (1<<22) -#define MI_SEMAPHORE_UPDATE (1<<21) -#define MI_SEMAPHORE_COMPARE (1<<20) -#define MI_SEMAPHORE_REGISTER (1<<18) -#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */ -#define MI_SEMAPHORE_SYNC_VER (1<<16) /* RCS wait for VECS (RVESYNC) */ -#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */ -#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */ -#define MI_SEMAPHORE_SYNC_VEV (1<<16) /* VCS wait for VECS (VVESYNC) */ -#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */ -#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */ -#define MI_SEMAPHORE_SYNC_VEB (1<<16) /* BCS wait for VECS (BVESYNC) */ -#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */ -#define MI_SEMAPHORE_SYNC_BVE (0<<16) /* VECS wait for BCS (VEBSYNC) */ -#define MI_SEMAPHORE_SYNC_VVE (1<<16) /* VECS wait for VCS (VEVSYNC) */ -#define MI_SEMAPHORE_SYNC_RVE (2<<16) /* VECS wait for RCS (VERSYNC) */ -#define MI_SEMAPHORE_SYNC_INVALID (3<<16) + #define MI_PREDICATE_RESULT_2 (0x2214) #define LOWER_SLICE_ENABLED (1<<0) From 52ed23253b68e1cf154b03d91bed619504cf955b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 16 Dec 2013 20:50:38 -0800 Subject: [PATCH 167/595] drm/i915: Don't emit mbox updates without semaphores Aside from the fact that it leaves confusing dumps on error capture, it is entirely unnecessary, and potentially harmful in cases like BDW, where the instruction has changed. In reality (seemingly), this will have no behavioral impact. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e05a0216cd9b..b106984c722a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -663,14 +663,15 @@ gen6_add_request(struct intel_ring_buffer *ring) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *useless; - int i, ret; + int i, ret, num_dwords = 4; - ret = intel_ring_begin(ring, ((I915_NUM_RINGS-1) * - MBOX_UPDATE_DWORDS) + - 4); + if (i915_semaphore_is_enabled(dev)) + num_dwords += ((I915_NUM_RINGS-1) * MBOX_UPDATE_DWORDS); +#undef MBOX_UPDATE_DWORDS + + ret = intel_ring_begin(ring, num_dwords); if (ret) return ret; -#undef MBOX_UPDATE_DWORDS for_each_ring(useless, dev_priv, i) { u32 mbox_reg = ring->signal_mbox[i]; From a08acaf2f6c278f7b3c090d9d7c6cbbe4f02f003 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 17 Dec 2013 09:56:53 +0100 Subject: [PATCH 168/595] drm/i915: Use symbolic names for booleans in i915_semaphore_is_enabled Noticed while reviewing a patch and couldn't resist the OCD. Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index aea909b2f22e..31ffe39d2b79 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -480,12 +480,12 @@ void intel_detect_pch(struct drm_device *dev) bool i915_semaphore_is_enabled(struct drm_device *dev) { if (INTEL_INFO(dev)->gen < 6) - return 0; + return false; /* Until we get further testing... */ if (IS_GEN8(dev)) { WARN_ON(!i915_preliminary_hw_support); - return 0; + return false; } if (i915_semaphores >= 0) @@ -497,7 +497,7 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) return false; #endif - return 1; + return true; } static int i915_drm_freeze(struct drm_device *dev) From 691bb717544f3c1241f5a4e5fb884a0215a2dc9e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 12 Dec 2013 14:36:36 +0000 Subject: [PATCH 169/595] drm/i915: Use IS_VALLEYVIEW() to test the is_valleyview flag Signed-off-by: Damien Lespiau Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b35f65ed6c5e..7fd3e67244ec 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3582,9 +3582,11 @@ void gen6_set_rps(struct drm_device *dev, u8 val) void gen6_rps_idle(struct drm_i915_private *dev_priv) { + struct drm_device *dev = dev_priv->dev; + mutex_lock(&dev_priv->rps.hw_lock); if (dev_priv->rps.enabled) { - if (dev_priv->info->is_valleyview) + if (IS_VALLEYVIEW(dev)) valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_delay); else gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay); @@ -3595,9 +3597,11 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv) void gen6_rps_boost(struct drm_i915_private *dev_priv) { + struct drm_device *dev = dev_priv->dev; + mutex_lock(&dev_priv->rps.hw_lock); if (dev_priv->rps.enabled) { - if (dev_priv->info->is_valleyview) + if (IS_VALLEYVIEW(dev)) valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_delay); else gen6_set_rps(dev_priv->dev, dev_priv->rps.max_delay); From 243eaf381d1a851f53c9f3cbd26849731da17c48 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 17 Dec 2013 10:00:54 +0100 Subject: [PATCH 170/595] drm/i915: kick firmware fbs even when i915 fbdev is disabled Otherwise we don't kick out firmware framebuffers like vesafb and efifb when CONFIG_DRM_I915_FBDEV=n but CONFIG_FB=y. There's still the pesky issue with vgacon which we should somehow replace with the dummy console at least. We have a similar issue at module un/reload, since vgacon state is terminally botched after i915.ko has loaded in modeset mode. But this gets us a step further at least. v2: Use IS_ENABLED - I always get this wrong for tristates. Spotted by Jani. Reported-by: Chris Wilson Cc: Chris Wilson Cc: Jani Nikula Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index b49571df555f..1a25f9eaca59 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1405,7 +1405,7 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) master->driver_priv = NULL; } -#ifdef CONFIG_DRM_I915_FBDEV +#if IS_ENABLED(CONFIG_FB) static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) { struct apertures_struct *ap; From ac9545fda6ed13c3a1205de138fa25c076cf4473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:28 +0200 Subject: [PATCH 171/595] drm/i915: Add IVB DDB partitioning control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On IVB the display data buffer partitioning control lives in the DISP_ARB_CTL2 register. Add the relevant defines/code for it. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 30 ++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ac87ab883ff7..e9548b185f66 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4148,6 +4148,8 @@ #define DISP_ARB_CTL 0x45000 #define DISP_TILE_SURFACE_SWIZZLING (1<<13) #define DISP_FBC_WM_DIS (1<<15) +#define DISP_ARB_CTL2 0x45004 +#define DISP_DATA_PARTITION_5_6 (1<<6) #define GEN7_MSG_CTL 0x45010 #define WAIT_FOR_PCH_RESET_ACK (1<<1) #define WAIT_FOR_PCH_FLR_ACK (1<<0) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7fd3e67244ec..be8244282742 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2864,6 +2864,7 @@ static unsigned int ilk_compute_wm_dirty(struct drm_device *dev, static void hsw_write_wm_values(struct drm_i915_private *dev_priv, struct hsw_wm_values *results) { + struct drm_device *dev = dev_priv->dev; struct hsw_wm_values *previous = &dev_priv->wm.hw; unsigned int dirty; uint32_t val; @@ -2894,12 +2895,21 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(PIPE_WM_LINETIME(PIPE_C), results->wm_linetime[2]); if (dirty & WM_DIRTY_DDB) { - val = I915_READ(WM_MISC); - if (results->partitioning == INTEL_DDB_PART_1_2) - val &= ~WM_MISC_DATA_PARTITION_5_6; - else - val |= WM_MISC_DATA_PARTITION_5_6; - I915_WRITE(WM_MISC, val); + if (IS_HASWELL(dev)) { + val = I915_READ(WM_MISC); + if (results->partitioning == INTEL_DDB_PART_1_2) + val &= ~WM_MISC_DATA_PARTITION_5_6; + else + val |= WM_MISC_DATA_PARTITION_5_6; + I915_WRITE(WM_MISC, val); + } else { + val = I915_READ(DISP_ARB_CTL2); + if (results->partitioning == INTEL_DDB_PART_1_2) + val &= ~DISP_DATA_PARTITION_5_6; + else + val |= DISP_DATA_PARTITION_5_6; + I915_WRITE(DISP_ARB_CTL2, val); + } } if (dirty & WM_DIRTY_FBC) { @@ -3210,8 +3220,12 @@ void ilk_wm_get_hw_state(struct drm_device *dev) hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB); hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB); - hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? - INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2; + if (IS_HASWELL(dev)) + hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? + INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2; + else if (IS_IVYBRIDGE(dev)) + hw->partitioning = (I915_READ(DISP_ARB_CTL2) & DISP_DATA_PARTITION_5_6) ? + INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2; hw->enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS); From a68d68eebc9820212186b6d02f2dce09deef0e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:29 +0200 Subject: [PATCH 172/595] drm/i915: Add ILK/SNB/IVB WM latency field support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new function ilk_wm_lp_latency() which will tell us what to write into the WM_LPx register latency field. HSW is different from erlier gens in this regard. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index be8244282742..dbd025a4f22f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2715,6 +2715,17 @@ static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm) return wm_lp + (wm_lp >= 2 && pipe_wm->wm[4].enable); } +/* The value we need to program into the WM_LPx latency field */ +static unsigned int ilk_wm_lp_latency(struct drm_device *dev, int level) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_HASWELL(dev)) + return 2 * level; + else + return dev_priv->wm.pri_latency[level]; +} + static void hsw_compute_wm_results(struct drm_device *dev, const struct intel_pipe_wm *merged, enum intel_ddb_partitioning partitioning, @@ -2737,7 +2748,7 @@ static void hsw_compute_wm_results(struct drm_device *dev, break; results->wm_lp[wm_lp - 1] = WM3_LP_EN | - ((level * 2) << WM1_LP_LATENCY_SHIFT) | + (ilk_wm_lp_latency(dev, level) << WM1_LP_LATENCY_SHIFT) | (r->pri_val << WM1_LP_SR_SHIFT) | r->cur_val; From 7b39a0b791a356d09dd2517ec04b1bf9cdced4ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:30 +0200 Subject: [PATCH 173/595] drm/i915: Avoid computing invalid WM levels when sprites/scaling is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ILK/SNB only LP0/1 watermarks can be enabled when sprites are enabled, and on ILK/SNB/IVB sprite scaling is limited to LP0 only. So we can avoid computing the extra levels we're never going to use. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index dbd025a4f22f..b06076d8f386 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2643,6 +2643,14 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, /* LP0 watermarks always use 1/2 DDB partitioning */ ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max); + /* ILK/SNB: LP2+ watermarks only w/o sprites */ + if (INTEL_INFO(dev)->gen <= 6 && params->spr.enabled) + max_level = 1; + + /* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */ + if (params->spr.scaled) + max_level = 0; + for (level = 0; level <= max_level; level++) ilk_compute_wm_level(dev_priv, level, params, &pipe_wm->wm[level]); From 6cef2b8a5671dc6abbc0414a94be843590f93ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:32 +0200 Subject: [PATCH 174/595] drm/i915: Fix LP1 sprite watermarks for ILK/SNB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ILK/SNB don't have LP2+ watermarks for sprites. Also the LP1 sprite watermark register has its own enable bit. Take these differences into account when programming the LP1+ registers. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b06076d8f386..232d8c3b1f10 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2767,7 +2767,11 @@ static void hsw_compute_wm_results(struct drm_device *dev, results->wm_lp[wm_lp - 1] |= r->fbc_val << WM1_LP_FBC_SHIFT; - results->wm_lp_spr[wm_lp - 1] = r->spr_val; + if (INTEL_INFO(dev)->gen <= 6 && r->spr_val) { + WARN_ON(wm_lp != 1); + results->wm_lp_spr[wm_lp - 1] = WM1S_LP_EN | r->spr_val; + } else + results->wm_lp_spr[wm_lp - 1] = r->spr_val; } /* LP0 register values */ @@ -2899,6 +2903,10 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != 0) I915_WRITE(WM1_LP_ILK, 0); + if (INTEL_INFO(dev)->gen <= 6 && + dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != 0) + I915_WRITE(WM1S_LP_ILK, 0); + if (dirty & WM_DIRTY_PIPE(PIPE_A)) I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]); if (dirty & WM_DIRTY_PIPE(PIPE_B)) @@ -2940,12 +2948,17 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(DISP_ARB_CTL, val); } - if (dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != results->wm_lp_spr[0]) - I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]); - if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1]) - I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]); - if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2]) - I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]); + if (INTEL_INFO(dev)->gen <= 6) { + if (dirty & WM_DIRTY_LP(1) && results->wm_lp_spr[0] != 0) + I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]); + } else { + if (dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != results->wm_lp_spr[0]) + I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]); + if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1]) + I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]); + if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2]) + I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]); + } if (dirty & WM_DIRTY_LP(1) && results->wm_lp[0] != 0) I915_WRITE(WM1_LP_ILK, results->wm_lp[0]); From facd619b8869b308e02104a200abf6f9d7cddcab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:33 +0200 Subject: [PATCH 175/595] drm/i915: Fix LP1+ watermark disabling ILK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ILK disabling LP1+ watermarks must be done carefully to avoid underruns. If we just write 0 to the register in the middle of the scan cycle we often get an underrun. So instead we have to leave the actual watermark levels in the register intact, and just toggle the enable bit. Presumably the hardware takes a while to get out of low power mode, and so the watermark level need to stay valid until that time. We also have to be careful with the WM1S_LP_EN bit. It seems the hardware more or less treats it like the actual watermarks numbers, and so we must not toggle it too soon. Just leave it alone when disabling the LP1+ watermarks. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 232d8c3b1f10..c43cf138c871 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2896,16 +2896,23 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, if (!dirty) return; - if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != 0) - I915_WRITE(WM3_LP_ILK, 0); - if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != 0) - I915_WRITE(WM2_LP_ILK, 0); - if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != 0) - I915_WRITE(WM1_LP_ILK, 0); + if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] & WM1_LP_SR_EN) { + previous->wm_lp[2] &= ~WM1_LP_SR_EN; + I915_WRITE(WM3_LP_ILK, previous->wm_lp[2]); + } + if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] & WM1_LP_SR_EN) { + previous->wm_lp[1] &= ~WM1_LP_SR_EN; + I915_WRITE(WM2_LP_ILK, previous->wm_lp[1]); + } + if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] & WM1_LP_SR_EN) { + previous->wm_lp[0] &= ~WM1_LP_SR_EN; + I915_WRITE(WM1_LP_ILK, previous->wm_lp[0]); + } - if (INTEL_INFO(dev)->gen <= 6 && - dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != 0) - I915_WRITE(WM1S_LP_ILK, 0); + /* + * Don't touch WM1S_LP_EN here. + * Doing so could cause underruns. + */ if (dirty & WM_DIRTY_PIPE(PIPE_A)) I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]); @@ -2949,7 +2956,7 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, } if (INTEL_INFO(dev)->gen <= 6) { - if (dirty & WM_DIRTY_LP(1) && results->wm_lp_spr[0] != 0) + if (dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != results->wm_lp_spr[0]) I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]); } else { if (dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != results->wm_lp_spr[0]) @@ -2960,11 +2967,11 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]); } - if (dirty & WM_DIRTY_LP(1) && results->wm_lp[0] != 0) + if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != results->wm_lp[0]) I915_WRITE(WM1_LP_ILK, results->wm_lp[0]); - if (dirty & WM_DIRTY_LP(2) && results->wm_lp[1] != 0) + if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != results->wm_lp[1]) I915_WRITE(WM2_LP_ILK, results->wm_lp[1]); - if (dirty & WM_DIRTY_LP(3) && results->wm_lp[2] != 0) + if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != results->wm_lp[2]) I915_WRITE(WM3_LP_ILK, results->wm_lp[2]); dev_priv->wm.hw = *results; From 0ba22e26fe47b2a216e5438292aeeb8e015e9d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:34 +0200 Subject: [PATCH 176/595] drm/i915: Don't merge LP1+ watermarks on ILK/SNB/IVB when multiple pipes are enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Multi-pipe LP1+ watermarks are a HSW+ feature, so let's not do it on earlier generations. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c43cf138c871..a65d8816c1e6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2690,11 +2690,17 @@ static void ilk_merge_wm_level(struct drm_device *dev, * Merge all low power watermarks for all active pipes. */ static void ilk_wm_merge(struct drm_device *dev, + const struct intel_wm_config *config, const struct hsw_wm_maximums *max, struct intel_pipe_wm *merged) { int level, max_level = ilk_wm_max_level(dev); + /* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */ + if ((INTEL_INFO(dev)->gen <= 6 || IS_IVYBRIDGE(dev)) && + config->num_pipes_active > 1) + return; + merged->fbc_wm_enabled = true; /* merge each WM1+ level */ @@ -3000,13 +3006,13 @@ static void haswell_update_wm(struct drm_crtc *crtc) intel_crtc->wm.active = pipe_wm; ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max); - ilk_wm_merge(dev, &max, &lp_wm_1_2); + ilk_wm_merge(dev, &config, &max, &lp_wm_1_2); /* 5/6 split only in single pipe config on IVB+ */ if (INTEL_INFO(dev)->gen >= 7 && config.num_pipes_active == 1 && config.sprites_enabled) { ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max); - ilk_wm_merge(dev, &max, &lp_wm_5_6); + ilk_wm_merge(dev, &config, &max, &lp_wm_5_6); best_lp_wm = hsw_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6); } else { From 6c8b6c288783b05733de31fb61fc8ebfa8ae0229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:35 +0200 Subject: [PATCH 177/595] drm/i915: Disable FBC WM on ILK, and disable LP2+ when FBC is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ILK has a bunch of issues with FBC. First of all, BSpec tells us that FBC WM should never be enabled. Secondly when FBC is enabled with FBC WM disabled, LP2+ watermarks must be disabled. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a65d8816c1e6..3d4daa1fc3be 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2701,7 +2701,8 @@ static void ilk_wm_merge(struct drm_device *dev, config->num_pipes_active > 1) return; - merged->fbc_wm_enabled = true; + /* ILK: FBC WM must be disabled always */ + merged->fbc_wm_enabled = INTEL_INFO(dev)->gen >= 6; /* merge each WM1+ level */ for (level = 1; level <= max_level; level++) { @@ -2721,6 +2722,20 @@ static void ilk_wm_merge(struct drm_device *dev, wm->fbc_val = 0; } } + + /* ILK: LP2+ must be disabled when FBC WM is disabled but FBC enabled */ + /* + * FIXME this is racy. FBC might get enabled later. + * What we should check here is whether FBC can be + * enabled sometime later. + */ + if (IS_GEN5(dev) && !merged->fbc_wm_enabled && intel_fbc_enabled(dev)) { + for (level = 2; level <= max_level; level++) { + struct intel_wm_level *wm = &merged->wm[level]; + + wm->enable = false; + } + } } static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm) From ce0e0713a6b21ec611d4a2eb5c60d18dbb4bf479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:36 +0200 Subject: [PATCH 178/595] drm/i915: Linetime watermarks are a HSW feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Linetime watermarks don't exist on ILK/SNB/IVB, so don't compute them except on HSW. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3d4daa1fc3be..276e98df1c0d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2655,7 +2655,8 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, ilk_compute_wm_level(dev_priv, level, params, &pipe_wm->wm[level]); - pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); + if (IS_HASWELL(dev)) + pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); /* At least LP0 must be valid */ return ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]); @@ -3234,7 +3235,8 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) }; hw->wm_pipe[pipe] = I915_READ(wm0_pipe_reg[pipe]); - hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe)); + if (IS_HASWELL(dev)) + hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe)); if (intel_crtc_active(crtc)) { u32 tmp = hw->wm_pipe[pipe]; From 017636cc09e2c58bc493cc1fe74d858f50d173af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:37 +0200 Subject: [PATCH 179/595] drm/i915: Disable LP1+ watermarks safely in init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ILK doesn't like if we just write the LP1+ watermarks registers with 0. We need to just disable the watermarks by clearing the enable bit. Use that method also when disabling LP1+ watermarks in init_clock_gating. It looks like disabling the sprite LP1 watermarks can cause underruns even if we just toggle the WM1S_LP_EN bit. So treat that bit like the actual watermark numbers and avoid setting it to 0 immediately. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 276e98df1c0d..e321fbc28a0b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5051,6 +5051,20 @@ static void g4x_disable_trickle_feed(struct drm_device *dev) } } +static void ilk_init_lp_watermarks(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(WM3_LP_ILK, I915_READ(WM3_LP_ILK) & ~WM1_LP_SR_EN); + I915_WRITE(WM2_LP_ILK, I915_READ(WM2_LP_ILK) & ~WM1_LP_SR_EN); + I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN); + + /* + * Don't touch WM1S_LP_EN here. + * Doing so could cause underruns. + */ +} + static void ironlake_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5084,9 +5098,8 @@ static void ironlake_init_clock_gating(struct drm_device *dev) I915_WRITE(DISP_ARB_CTL, (I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS)); - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); + + ilk_init_lp_watermarks(dev); /* * Based on the document from hardware guys the following bits @@ -5193,9 +5206,7 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE)); - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); + ilk_init_lp_watermarks(dev); I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB)); @@ -5369,9 +5380,7 @@ static void haswell_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); + ilk_init_lp_watermarks(dev); /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. * This implements the WaDisableRCZUnitClockGating:hsw workaround. @@ -5420,9 +5429,7 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t snpcr; - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); + ilk_init_lp_watermarks(dev); I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); From 96f90c5421aaaba35ffd931728fabeb8f6cd8471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:38 +0200 Subject: [PATCH 180/595] drm/i915: Move ILK/SNB/IVB over to the HSW WM code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new HSW watermark code can now handle ILK/SNB/IVB as well, so switch them over. Kill the old code. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 656 +-------------------------- 2 files changed, 12 insertions(+), 646 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 066fc9ddbd28..de5bbd791be5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11230,7 +11230,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, pll->on = false; } - if (IS_HASWELL(dev)) + if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); if (force_restore) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e321fbc28a0b..7e028341b2f5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -965,65 +965,6 @@ static const struct intel_watermark_params i830_wm_info = { I830_FIFO_LINE_SIZE }; -static const struct intel_watermark_params ironlake_display_wm_info = { - ILK_DISPLAY_FIFO, - ILK_DISPLAY_MAXWM, - ILK_DISPLAY_DFTWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_cursor_wm_info = { - ILK_CURSOR_FIFO, - ILK_CURSOR_MAXWM, - ILK_CURSOR_DFTWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_display_srwm_info = { - ILK_DISPLAY_SR_FIFO, - ILK_DISPLAY_MAX_SRWM, - ILK_DISPLAY_DFT_SRWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_cursor_srwm_info = { - ILK_CURSOR_SR_FIFO, - ILK_CURSOR_MAX_SRWM, - ILK_CURSOR_DFT_SRWM, - 2, - ILK_FIFO_LINE_SIZE -}; - -static const struct intel_watermark_params sandybridge_display_wm_info = { - SNB_DISPLAY_FIFO, - SNB_DISPLAY_MAXWM, - SNB_DISPLAY_DFTWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_cursor_wm_info = { - SNB_CURSOR_FIFO, - SNB_CURSOR_MAXWM, - SNB_CURSOR_DFTWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_display_srwm_info = { - SNB_DISPLAY_SR_FIFO, - SNB_DISPLAY_MAX_SRWM, - SNB_DISPLAY_DFT_SRWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_cursor_srwm_info = { - SNB_CURSOR_SR_FIFO, - SNB_CURSOR_MAX_SRWM, - SNB_CURSOR_DFT_SRWM, - 2, - SNB_FIFO_LINE_SIZE -}; - - /** * intel_calculate_wm - calculate watermark level * @clock_in_khz: pixel clock @@ -1707,423 +1648,6 @@ static void i830_update_wm(struct drm_crtc *unused_crtc) I915_WRITE(FW_BLC, fwater_lo); } -/* - * Check the wm result. - * - * If any calculated watermark values is larger than the maximum value that - * can be programmed into the associated watermark register, that watermark - * must be disabled. - */ -static bool ironlake_check_srwm(struct drm_device *dev, int level, - int fbc_wm, int display_wm, int cursor_wm, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d," - " cursor %d\n", level, display_wm, fbc_wm, cursor_wm); - - if (fbc_wm > SNB_FBC_MAX_SRWM) { - DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n", - fbc_wm, SNB_FBC_MAX_SRWM, level); - - /* fbc has it's own way to disable FBC WM */ - I915_WRITE(DISP_ARB_CTL, - I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS); - return false; - } else if (INTEL_INFO(dev)->gen >= 6) { - /* enable FBC WM (except on ILK, where it must remain off) */ - I915_WRITE(DISP_ARB_CTL, - I915_READ(DISP_ARB_CTL) & ~DISP_FBC_WM_DIS); - } - - if (display_wm > display->max_wm) { - DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n", - display_wm, SNB_DISPLAY_MAX_SRWM, level); - return false; - } - - if (cursor_wm > cursor->max_wm) { - DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n", - cursor_wm, SNB_CURSOR_MAX_SRWM, level); - return false; - } - - if (!(fbc_wm || display_wm || cursor_wm)) { - DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level); - return false; - } - - return true; -} - -/* - * Compute watermark values of WM[1-3], - */ -static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane, - int latency_ns, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor, - int *fbc_wm, int *display_wm, int *cursor_wm) -{ - struct drm_crtc *crtc; - const struct drm_display_mode *adjusted_mode; - unsigned long line_time_us; - int hdisplay, htotal, pixel_size, clock; - int line_count, line_size; - int small, large; - int entries; - - if (!latency_ns) { - *fbc_wm = *display_wm = *cursor_wm = 0; - return false; - } - - crtc = intel_get_crtc_for_plane(dev, plane); - adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; - clock = adjusted_mode->crtc_clock; - htotal = adjusted_mode->htotal; - hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; - pixel_size = crtc->fb->bits_per_pixel / 8; - - line_time_us = (htotal * 1000) / clock; - line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = hdisplay * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; - large = line_count * line_size; - - entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); - *display_wm = entries + display->guard_size; - - /* - * Spec says: - * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2 - */ - *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2; - - /* calculate the self-refresh watermark for display cursor */ - entries = line_count * pixel_size * 64; - entries = DIV_ROUND_UP(entries, cursor->cacheline_size); - *cursor_wm = entries + cursor->guard_size; - - return ironlake_check_srwm(dev, level, - *fbc_wm, *display_wm, *cursor_wm, - display, cursor); -} - -static void ironlake_update_wm(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int fbc_wm, plane_wm, cursor_wm; - unsigned int enabled; - - enabled = 0; - if (g4x_compute_wm0(dev, PIPE_A, - &ironlake_display_wm_info, - dev_priv->wm.pri_latency[0] * 100, - &ironlake_cursor_wm_info, - dev_priv->wm.cur_latency[0] * 100, - &plane_wm, &cursor_wm)) { - I915_WRITE(WM0_PIPEA_ILK, - (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); - enabled |= 1 << PIPE_A; - } - - if (g4x_compute_wm0(dev, PIPE_B, - &ironlake_display_wm_info, - dev_priv->wm.pri_latency[0] * 100, - &ironlake_cursor_wm_info, - dev_priv->wm.cur_latency[0] * 100, - &plane_wm, &cursor_wm)) { - I915_WRITE(WM0_PIPEB_ILK, - (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); - enabled |= 1 << PIPE_B; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - if (!single_plane_enabled(enabled)) - return; - enabled = ffs(enabled) - 1; - - /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, enabled, - dev_priv->wm.pri_latency[1] * 500, - &ironlake_display_srwm_info, - &ironlake_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM1_LP_ILK, - WM1_LP_SR_EN | - (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, enabled, - dev_priv->wm.pri_latency[2] * 500, - &ironlake_display_srwm_info, - &ironlake_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM2_LP_ILK, - WM2_LP_EN | - (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* - * WM3 is unsupported on ILK, probably because we don't have latency - * data for that power state - */ -} - -static void sandybridge_update_wm(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int latency = dev_priv->wm.pri_latency[0] * 100; /* In unit 0.1us */ - u32 val; - int fbc_wm, plane_wm, cursor_wm; - unsigned int enabled; - - enabled = 0; - if (g4x_compute_wm0(dev, PIPE_A, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &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); - enabled |= 1 << PIPE_A; - } - - if (g4x_compute_wm0(dev, PIPE_B, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &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); - enabled |= 1 << PIPE_B; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - * - * SNB support 3 levels of watermark. - * - * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, - * and disabled in the descending order - * - */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - if (!single_plane_enabled(enabled) || - dev_priv->sprite_scaling_enabled) - return; - enabled = ffs(enabled) - 1; - - /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, enabled, - dev_priv->wm.pri_latency[1] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM1_LP_ILK, - WM1_LP_SR_EN | - (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, enabled, - dev_priv->wm.pri_latency[2] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM2_LP_ILK, - WM2_LP_EN | - (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM3 */ - if (!ironlake_compute_srwm(dev, 3, enabled, - dev_priv->wm.pri_latency[3] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM3_LP_ILK, - WM3_LP_EN | - (dev_priv->wm.pri_latency[3] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); -} - -static void ivybridge_update_wm(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int latency = dev_priv->wm.pri_latency[0] * 100; /* In unit 0.1us */ - u32 val; - int fbc_wm, plane_wm, cursor_wm; - int ignore_fbc_wm, ignore_plane_wm, ignore_cursor_wm; - unsigned int enabled; - - enabled = 0; - if (g4x_compute_wm0(dev, PIPE_A, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &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); - enabled |= 1 << PIPE_A; - } - - if (g4x_compute_wm0(dev, PIPE_B, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &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); - enabled |= 1 << PIPE_B; - } - - if (g4x_compute_wm0(dev, PIPE_C, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &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); - enabled |= 1 << PIPE_C; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - * - * SNB support 3 levels of watermark. - * - * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, - * and disabled in the descending order - * - */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - if (!single_plane_enabled(enabled) || - dev_priv->sprite_scaling_enabled) - return; - enabled = ffs(enabled) - 1; - - /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, enabled, - dev_priv->wm.pri_latency[1] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM1_LP_ILK, - WM1_LP_SR_EN | - (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, enabled, - dev_priv->wm.pri_latency[2] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM2_LP_ILK, - WM2_LP_EN | - (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM3, note we have to correct the cursor latency */ - if (!ironlake_compute_srwm(dev, 3, enabled, - dev_priv->wm.pri_latency[3] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &ignore_cursor_wm) || - !ironlake_compute_srwm(dev, 3, enabled, - dev_priv->wm.cur_latency[3] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &ignore_fbc_wm, &ignore_plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM3_LP_ILK, - WM3_LP_EN | - (dev_priv->wm.pri_latency[3] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); -} - static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev, struct drm_crtc *crtc) { @@ -3058,168 +2582,6 @@ static void haswell_update_sprite_wm(struct drm_plane *plane, haswell_update_wm(crtc); } -static bool -sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, - uint32_t sprite_width, int pixel_size, - const struct intel_watermark_params *display, - int display_latency_ns, int *sprite_wm) -{ - struct drm_crtc *crtc; - int clock; - int entries, tlb_miss; - - crtc = intel_get_crtc_for_plane(dev, plane); - if (!intel_crtc_active(crtc)) { - *sprite_wm = display->guard_size; - return false; - } - - clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; - - /* Use the small buffer method to calculate the sprite watermark */ - entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; - tlb_miss = display->fifo_size*display->cacheline_size - - sprite_width * 8; - if (tlb_miss > 0) - entries += tlb_miss; - entries = DIV_ROUND_UP(entries, display->cacheline_size); - *sprite_wm = entries + display->guard_size; - if (*sprite_wm > (int)display->max_wm) - *sprite_wm = display->max_wm; - - return true; -} - -static bool -sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane, - uint32_t sprite_width, int pixel_size, - const struct intel_watermark_params *display, - int latency_ns, int *sprite_wm) -{ - struct drm_crtc *crtc; - unsigned long line_time_us; - int clock; - int line_count, line_size; - int small, large; - int entries; - - if (!latency_ns) { - *sprite_wm = 0; - return false; - } - - crtc = intel_get_crtc_for_plane(dev, plane); - clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; - if (!clock) { - *sprite_wm = 0; - return false; - } - - line_time_us = (sprite_width * 1000) / clock; - if (!line_time_us) { - *sprite_wm = 0; - return false; - } - - line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = sprite_width * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; - large = line_count * line_size; - - entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); - *sprite_wm = entries + display->guard_size; - - return *sprite_wm > 0x3ff ? false : true; -} - -static void sandybridge_update_sprite_wm(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, int pixel_size, - bool enabled, bool scaled) -{ - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe = to_intel_plane(plane)->pipe; - int latency = dev_priv->wm.spr_latency[0] * 100; /* In unit 0.1us */ - u32 val; - int sprite_wm, reg; - int ret; - - if (!enabled) - return; - - switch (pipe) { - case 0: - reg = WM0_PIPEA_ILK; - break; - case 1: - reg = WM0_PIPEB_ILK; - break; - case 2: - reg = WM0_PIPEC_IVB; - break; - default: - return; /* bad pipe */ - } - - ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size, - &sandybridge_display_wm_info, - latency, &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite wm for pipe %c\n", - pipe_name(pipe)); - return; - } - - 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 %c - %d\n", pipe_name(pipe), sprite_wm); - - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - dev_priv->wm.spr_latency[1] * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %c\n", - pipe_name(pipe)); - return; - } - I915_WRITE(WM1S_LP_ILK, sprite_wm); - - /* Only IVB has two more LP watermarks for sprite */ - if (!IS_IVYBRIDGE(dev)) - return; - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - dev_priv->wm.spr_latency[2] * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %c\n", - pipe_name(pipe)); - return; - } - I915_WRITE(WM2S_LP_IVB, sprite_wm); - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - dev_priv->wm.spr_latency[3] * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %c\n", - pipe_name(pipe)); - return; - } - I915_WRITE(WM3S_LP_IVB, sprite_wm); -} - static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -6184,9 +5546,11 @@ void intel_init_pm(struct drm_device *dev) if (IS_GEN5(dev)) { if (dev_priv->wm.pri_latency[1] && dev_priv->wm.spr_latency[1] && - dev_priv->wm.cur_latency[1]) - dev_priv->display.update_wm = ironlake_update_wm; - else { + dev_priv->wm.cur_latency[1]) { + dev_priv->display.update_wm = haswell_update_wm; + dev_priv->display.update_sprite_wm = + haswell_update_sprite_wm; + } else { DRM_DEBUG_KMS("Failed to get proper latency. " "Disable CxSR\n"); dev_priv->display.update_wm = NULL; @@ -6196,8 +5560,9 @@ void intel_init_pm(struct drm_device *dev) if (dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0]) { - dev_priv->display.update_wm = sandybridge_update_wm; - dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; + dev_priv->display.update_wm = haswell_update_wm; + dev_priv->display.update_sprite_wm = + haswell_update_sprite_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); @@ -6208,8 +5573,9 @@ void intel_init_pm(struct drm_device *dev) if (dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0]) { - dev_priv->display.update_wm = ivybridge_update_wm; - dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; + dev_priv->display.update_wm = haswell_update_wm; + dev_priv->display.update_sprite_wm = + haswell_update_sprite_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); From 8553c18ea696827f26d3ba5652d3a2fa9ce8e874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:39 +0200 Subject: [PATCH 181/595] drm/i915: Try to fix the messy IVB sprite scaling workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now have a very clear method of disabling LP1+ wartermarks, and we can actually detect if we actually did disable them, or if they were already disabled. Use that to clean up the WaCxSRDisabledForSpriteScaling:ivb handling. I was hoping to apply the workaround in a way that wouldn't require a blocking wait, but sadly IVB really does appear to require LP1+ watermarks to be off for an entire frame before enabling sprite scaling. Simply disabling LP1+ watermarks during the previous frame is not enough, no matter how early in the frame we do it :( Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_pm.c | 68 +++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_sprite.c | 27 +----------- 3 files changed, 51 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b0a6e767951c..50da8a5a6500 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1401,7 +1401,6 @@ typedef struct drm_i915_private { /* overlay */ struct intel_overlay *overlay; - unsigned int sprite_scaling_enabled; /* backlight registers and fields in struct intel_panel */ spinlock_t backlight_lock; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7e028341b2f5..ecdb64e44e2a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2426,6 +2426,36 @@ static unsigned int ilk_compute_wm_dirty(struct drm_device *dev, return dirty; } +static bool _ilk_disable_lp_wm(struct drm_i915_private *dev_priv, + unsigned int dirty) +{ + struct hsw_wm_values *previous = &dev_priv->wm.hw; + bool changed = false; + + if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] & WM1_LP_SR_EN) { + previous->wm_lp[2] &= ~WM1_LP_SR_EN; + I915_WRITE(WM3_LP_ILK, previous->wm_lp[2]); + changed = true; + } + if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] & WM1_LP_SR_EN) { + previous->wm_lp[1] &= ~WM1_LP_SR_EN; + I915_WRITE(WM2_LP_ILK, previous->wm_lp[1]); + changed = true; + } + if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] & WM1_LP_SR_EN) { + previous->wm_lp[0] &= ~WM1_LP_SR_EN; + I915_WRITE(WM1_LP_ILK, previous->wm_lp[0]); + changed = true; + } + + /* + * Don't touch WM1S_LP_EN here. + * Doing so could cause underruns. + */ + + return changed; +} + /* * The spec says we shouldn't write when we don't need, because every write * causes WMs to be re-evaluated, expending some power. @@ -2438,27 +2468,11 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, unsigned int dirty; uint32_t val; - dirty = ilk_compute_wm_dirty(dev_priv->dev, previous, results); + dirty = ilk_compute_wm_dirty(dev, previous, results); if (!dirty) return; - if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] & WM1_LP_SR_EN) { - previous->wm_lp[2] &= ~WM1_LP_SR_EN; - I915_WRITE(WM3_LP_ILK, previous->wm_lp[2]); - } - if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] & WM1_LP_SR_EN) { - previous->wm_lp[1] &= ~WM1_LP_SR_EN; - I915_WRITE(WM2_LP_ILK, previous->wm_lp[1]); - } - if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] & WM1_LP_SR_EN) { - previous->wm_lp[0] &= ~WM1_LP_SR_EN; - I915_WRITE(WM1_LP_ILK, previous->wm_lp[0]); - } - - /* - * Don't touch WM1S_LP_EN here. - * Doing so could cause underruns. - */ + _ilk_disable_lp_wm(dev_priv, dirty); if (dirty & WM_DIRTY_PIPE(PIPE_A)) I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]); @@ -2523,6 +2537,13 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, dev_priv->wm.hw = *results; } +static bool ilk_disable_lp_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL); +} + static void haswell_update_wm(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -2572,6 +2593,7 @@ static void haswell_update_sprite_wm(struct drm_plane *plane, uint32_t sprite_width, int pixel_size, bool enabled, bool scaled) { + struct drm_device *dev = plane->dev; struct intel_plane *intel_plane = to_intel_plane(plane); intel_plane->wm.enabled = enabled; @@ -2579,6 +2601,16 @@ static void haswell_update_sprite_wm(struct drm_plane *plane, intel_plane->wm.horiz_pixels = sprite_width; intel_plane->wm.bytes_per_pixel = pixel_size; + /* + * IVB workaround: must disable low power watermarks for at least + * one frame before enabling scaling. LP watermarks can be re-enabled + * when scaling is disabled. + * + * WaCxSRDisabledForSpriteScaling:ivb + */ + if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev)) + intel_wait_for_vblank(dev, intel_plane->pipe); + haswell_update_wm(crtc); } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 90a3f6db8288..0bba103b00ee 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -230,7 +230,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; sprctl = I915_READ(SPRCTL(pipe)); @@ -291,21 +290,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, crtc_w--; crtc_h--; - /* - * IVB workaround: must disable low power watermarks for at least - * one frame before enabling scaling. LP watermarks can be re-enabled - * when scaling is disabled. - */ - if (crtc_w != src_w || crtc_h != src_h) { - dev_priv->sprite_scaling_enabled |= 1 << pipe; - - if (!scaling_was_enabled) { - intel_update_watermarks(crtc); - intel_wait_for_vblank(dev, pipe); - } + if (crtc_w != src_w || crtc_h != src_h) sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; - } else - dev_priv->sprite_scaling_enabled &= ~(1 << pipe); I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); @@ -332,10 +318,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, I915_MODIFY_DISPBASE(SPRSURF(pipe), i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); POSTING_READ(SPRSURF(pipe)); - - /* potentially re-enable LP watermarks */ - if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) - intel_update_watermarks(crtc); } static void @@ -345,7 +327,6 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; - bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); /* Can't leave the scaler enabled... */ @@ -355,13 +336,7 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); POSTING_READ(SPRSURF(pipe)); - dev_priv->sprite_scaling_enabled &= ~(1 << pipe); - intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false); - - /* potentially re-enable LP watermarks */ - if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) - intel_update_watermarks(crtc); } static int From efb31d15dc16150a7a41947d712822e703c3e923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:40 +0200 Subject: [PATCH 182/595] drm/i915: Don't disable primary when color keying is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When color keying is used, the primary may not be invisible even though the sprite fully covers it. So check for color keying before deciding to disable the primary plane. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 0bba103b00ee..050ec29e3150 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -636,6 +636,15 @@ format_is_yuv(uint32_t format) } } +static bool colorkey_enabled(struct intel_plane *intel_plane) +{ + struct drm_intel_sprite_colorkey key; + + intel_plane->get_colorkey(&intel_plane->base, &key); + + return key.flags != I915_SET_COLORKEY_NONE; +} + static int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -821,7 +830,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, * If the sprite is completely covering the primary plane, * we can disable the primary and save power. */ - disable_primary = drm_rect_equals(&dst, &clip); + disable_primary = drm_rect_equals(&dst, &clip) && !colorkey_enabled(intel_plane); WARN_ON(disable_primary && !visible && intel_crtc->active); mutex_lock(&dev->struct_mutex); From 1bd09ec7ad314313f15db733c7e9cb2225d95453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:41 +0200 Subject: [PATCH 183/595] drm/i915: Avoid underruns when disabling sprites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the watermark registers aren't double bufferd, clearing the watermarks immediately after writing the sprite registers can be hazardous. Until we have something better, add a wait for vblank between the two steps to make sure the sprite no longer needs the watermark levels before we clear them. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 050ec29e3150..606c27b7ae8f 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -336,6 +336,12 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); POSTING_READ(SPRSURF(pipe)); + /* + * Avoid underruns when disabling the sprite. + * FIXME remove once watermark updates are done properly. + */ + intel_wait_for_vblank(dev, pipe); + intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false); } @@ -503,6 +509,12 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) I915_MODIFY_DISPBASE(DVSSURF(pipe), 0); POSTING_READ(DVSSURF(pipe)); + /* + * Avoid underruns when disabling the sprite. + * FIXME remove once watermark updates are done properly. + */ + intel_wait_for_vblank(dev, pipe); + intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false); } From 8368f0148fa95fb5720e0fbeb4a91d738f06a4b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 5 Dec 2013 15:51:31 +0200 Subject: [PATCH 184/595] Revert "drm/i915/sprite: Always enable the scaler on IronLake" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently always enabling the sprite scaler magically made sprites work on ILK in the past. I think the real reason for the failure was missing sprite watermark programming, and enabling the scaler effectively disabled LP1+ watermarks, which was enough to keep things going. Or it might be that the hardware more or less ignores watermarks for scaled sprites since things seem to work even if I leave sprite watermarks at 0 and disable all other planes except the sprite. In any case, we left the scaler always on but then failed to check whether we might be exceeding the scaler's source size limits. That caused the sprite to fail when a sufficiently large unscaled image was being displayed. Now that we're getting proper watermark programming for ILK, we can keep the scaler disabled unless we need to do actual scaling. This reverts commit 8aaa81a166d80ac9bf2813984e5b4c2503d0fe08. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 606c27b7ae8f..fe4de89c374c 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -469,7 +469,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, crtc_h--; dvsscale = 0; - if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h) + if (crtc_w != src_w || crtc_h != src_h) dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); From 43394d2fc8f6776c8971ab09544a93359acbe88b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 2 Dec 2013 16:22:49 +0100 Subject: [PATCH 185/595] of: Add MIPI DSI bus device tree bindings Document the device tree bindings for the MIPI DSI bus. The MIPI Display Serial Interface specifies a serial bus and a protocol for communication between a host and up to four peripherals. Signed-off-by: Thierry Reding --- .../bindings/mipi/dsi/mipi-dsi-bus.txt | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt diff --git a/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt new file mode 100644 index 000000000000..973c27273772 --- /dev/null +++ b/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt @@ -0,0 +1,98 @@ +MIPI DSI (Display Serial Interface) busses +========================================== + +The MIPI Display Serial Interface specifies a serial bus and a protocol for +communication between a host and up to four peripherals. This document will +define the syntax used to represent a DSI bus in a device tree. + +This document describes DSI bus-specific properties only or defines existing +standard properties in the context of the DSI bus. + +Each DSI host provides a DSI bus. The DSI host controller's node contains a +set of properties that characterize the bus. Child nodes describe individual +peripherals on that bus. + +The following assumes that only a single peripheral is connected to a DSI +host. Experience shows that this is true for the large majority of setups. + +DSI host +-------- + +In addition to the standard properties and those defined by the parent bus of +a DSI host, the following properties apply to a node representing a DSI host. + +Required properties: +- #address-cells: The number of cells required to represent an address on the + bus. DSI peripherals are addressed using a 2-bit virtual channel number, so + a maximum of 4 devices can be addressed on a single bus. Hence the value of + this property should be 1. +- #size-cells: Should be 0. There are cases where it makes sense to use a + different value here. See below. + +DSI peripheral +-------------- + +Peripherals are represented as child nodes of the DSI host's node. Properties +described here apply to all DSI peripherals, but individual bindings may want +to define additional, device-specific properties. + +Required properties: +- reg: The virtual channel number of a DSI peripheral. Must be in the range + from 0 to 3. + +Some DSI peripherals respond to more than a single virtual channel. In that +case two alternative representations can be chosen: +- The reg property can take multiple entries, one for each virtual channel + that the peripheral responds to. +- If the virtual channels that a peripheral responds to are consecutive, the + #size-cells can be set to 1. The first cell of each entry in the reg + property is the number of the first virtual channel and the second cell is + the number of consecutive virtual channels. + +Example +------- + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <0>; + + /* peripheral responds to virtual channel 0 */ + peripheral@0 { + compatible = "..."; + reg = <0>; + }; + + ... + }; + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <0>; + + /* peripheral responds to virtual channels 0 and 2 */ + peripheral@0 { + compatible = "..."; + reg = <0, 2>; + }; + + ... + }; + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <1>; + + /* peripheral responds to virtual channels 1, 2 and 3 */ + peripheral@1 { + compatible = "..."; + reg = <1 3>; + }; + + ... + }; From d95f95eb96c511b39bf9c854217d7dddb6d06755 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 22 Nov 2013 19:19:55 +0100 Subject: [PATCH 186/595] of: Add simple panel device tree binding This binding specifies a set of common properties for display panels. It can be used as a basis by bindings for specific panels. Bindings for three specific panels are provided to show how the simple panel binding can be used. Acked-by: Rob Herring Signed-off-by: Thierry Reding --- .../bindings/panel/auo,b101aw03.txt | 7 +++++++ .../bindings/panel/chunghwa,claa101wb03.txt | 7 +++++++ .../bindings/panel/panasonic,vvx10f004b00.txt | 7 +++++++ .../bindings/panel/simple-panel.txt | 21 +++++++++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 Documentation/devicetree/bindings/panel/auo,b101aw03.txt create mode 100644 Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt create mode 100644 Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt create mode 100644 Documentation/devicetree/bindings/panel/simple-panel.txt diff --git a/Documentation/devicetree/bindings/panel/auo,b101aw03.txt b/Documentation/devicetree/bindings/panel/auo,b101aw03.txt new file mode 100644 index 000000000000..72e088a4fb3a --- /dev/null +++ b/Documentation/devicetree/bindings/panel/auo,b101aw03.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 10.1" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "auo,b101aw03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt b/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt new file mode 100644 index 000000000000..0ab2c05a4c22 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt @@ -0,0 +1,7 @@ +Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel + +Required properties: +- compatible: should be "chunghwa,claa101wb03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt b/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt new file mode 100644 index 000000000000..d328b0341bf4 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt @@ -0,0 +1,7 @@ +Panasonic Corporation 10.1" WUXGA TFT LCD panel + +Required properties: +- compatible: should be "panasonic,vvx10f004b00" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/simple-panel.txt b/Documentation/devicetree/bindings/panel/simple-panel.txt new file mode 100644 index 000000000000..1341bbf4aa3d --- /dev/null +++ b/Documentation/devicetree/bindings/panel/simple-panel.txt @@ -0,0 +1,21 @@ +Simple display panel + +Required properties: +- power-supply: regulator to provide the supply voltage + +Optional properties: +- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing +- enable-gpios: GPIO pin to enable or disable the panel +- backlight: phandle of the backlight device attached to the panel + +Example: + + panel: panel { + compatible = "cptt,claa101wb01"; + ddc-i2c-bus = <&panelddc>; + + power-supply = <&vdd_pnl_reg>; + enable-gpios = <&gpio 90 0>; + + backlight = <&backlight>; + }; From 068a00233969833f1ba925e7627797489efd6041 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 4 Dec 2013 16:35:12 +0100 Subject: [PATCH 187/595] drm: Add MIPI DSI bus support MIPI DSI bus allows to model DSI hosts and DSI peripherals using the Linux driver model. DSI hosts are registered by the DSI host drivers. During registration DSI peripherals will be created from the children of the DSI host's device tree node. Support for registration from board-setup code will be added later when needed. DSI hosts expose operations which can be used by DSI peripheral drivers to access associated devices. Signed-off-by: Andrzej Hajda Signed-off-by: Kyungmin Park Signed-off-by: Thierry Reding --- drivers/gpu/drm/Kconfig | 4 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_mipi_dsi.c | 315 +++++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 158 +++++++++++++++++ 4 files changed, 478 insertions(+) create mode 100644 drivers/gpu/drm/drm_mipi_dsi.c create mode 100644 include/drm/drm_mipi_dsi.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index f86427591167..0b8f8fdfdea9 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -20,6 +20,10 @@ menuconfig DRM details. You should also select and configure AGP (/dev/agpgart) support if it is available for your platform. +config DRM_MIPI_DSI + bool + depends on DRM + config DRM_USB tristate depends on DRM diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index cc08b845f965..b46239a619cf 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o CFLAGS_drm_trace_points.o := -I$(src) obj-$(CONFIG_DRM) += drm.o +obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o obj-$(CONFIG_DRM_USB) += drm_usb.o obj-$(CONFIG_DRM_TTM) += ttm/ obj-$(CONFIG_DRM_TDFX) += tdfx/ diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c new file mode 100644 index 000000000000..b155ee2ffa17 --- /dev/null +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -0,0 +1,315 @@ +/* + * MIPI DSI Bus + * + * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. + * Andrzej Hajda + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +#include