diff options
| author | 2016-05-23 11:48:48 -0700 | |
|---|---|---|
| committer | 2016-05-23 11:48:48 -0700 | |
| commit | 1d6da87a3241deb13d073c4125d19ed0e5a0c62c (patch) | |
| tree | 42b7a9842618dad2afe7db9709cc6217ced03120 /drivers/gpu/drm/i915/intel_runtime_pm.c | |
| parent | Merge tag 'libnvdimm-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm (diff) | |
| parent | drm/edid: add displayid detailed 1 timings to the modelist. (v1.1) (diff) | |
| download | wireguard-linux-1d6da87a3241deb13d073c4125d19ed0e5a0c62c.tar.xz wireguard-linux-1d6da87a3241deb13d073c4125d19ed0e5a0c62c.zip | |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"Here's the main drm pull request for 4.7, it's been a busy one, and
I've been a bit more distracted in real life this merge window. Lots
more ARM drivers, not sure if it'll ever end. I think I've at least
one more coming the next merge window.
But changes are all over the place, support for AMD Polaris GPUs is in
here, some missing GM108 support for nouveau (found in some Lenovos),
a bunch of MST and skylake fixes.
I've also noticed a few fixes from Arnd in my inbox, that I'll try and
get in asap, but I didn't think they should hold this up.
New drivers:
- Hisilicon kirin display driver
- Mediatek MT8173 display driver
- ARC PGU - bitstreamer on Synopsys ARC SDP boards
- Allwinner A13 initial RGB output driver
- Analogix driver for DisplayPort IP found in exynos and rockchip
DRM Core:
- UAPI headers fixes and C++ safety
- DRM connector reference counting
- DisplayID mode parsing for Dell 5K monitors
- Removal of struct_mutex from drivers
- Connector registration cleanups
- MST robustness fixes
- MAINTAINERS updates
- Lockless GEM object freeing
- Generic fbdev deferred IO support
panel:
- Support for a bunch of new panels
i915:
- VBT refactoring
- PLL computation cleanups
- DSI support for BXT
- Color manager support
- More atomic patches
- GEM improvements
- GuC fw loading fixes
- DP detection fixes
- SKL GPU hang fixes
- Lots of BXT fixes
radeon/amdgpu:
- Initial Polaris support
- GPUVM/Scheduler/Clock/Power improvements
- ASYNC pageflip support
- New mesa feature support
nouveau:
- GM108 support
- Power sensor support improvements
- GR init + ucode fixes.
- Use GPU provided topology information
vmwgfx:
- Add host messaging support
gma500:
- Some cleanups and fixes
atmel:
- Bridge support
- Async atomic commit support
fsl-dcu:
- Timing controller for LCD support
- Pixel clock polarity support
rcar-du:
- Misc fixes
exynos:
- Pipeline clock support
- Exynoss4533 SoC support
- HW trigger mode support
- export HDMI_PHY clock
- DECON5433 fixes
- Use generic prime functions
- use DMA mapping APIs
rockchip:
- Lots of little fixes
vc4:
- Render node support
- Gamma ramp support
- DPI output support
msm:
- Mostly cleanups and fixes
- Conversion to generic struct fence
etnaviv:
- Fix for prime buffer handling
- Allow hangcheck to be coalesced with other wakeups
tegra:
- Gamme table size fix"
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (1050 commits)
drm/edid: add displayid detailed 1 timings to the modelist. (v1.1)
drm/edid: move displayid validation to it's own function.
drm/displayid: Iterate over all DisplayID blocks
drm/edid: move displayid tiled block parsing into separate function.
drm: Nuke ->vblank_disable_allowed
drm/vmwgfx: Report vmwgfx version to vmware.log
drm/vmwgfx: Add VMWare host messaging capability
drm/vmwgfx: Kill some lockdep warnings
drm/nouveau/gr/gf100-: fix race condition in fecs/gpccs ucode
drm/nouveau/core: recognise GM108 chipsets
drm/nouveau/gr/gm107-: fix touching non-existent ppcs in attrib cb setup
drm/nouveau/gr/gk104-: share implementation of ppc exception init
drm/nouveau/gr/gk104-: move rop_active_fbps init to nonctx
drm/nouveau/bios/pll: check BIT table version before trying to parse it
drm/nouveau/bios/pll: prevent oops when limits table can't be parsed
drm/nouveau/volt/gk104: round up in gk104_volt_set
drm/nouveau/fb/gm200: setup mmu debug buffer registers at init()
drm/nouveau/fb/gk20a,gm20b: setup mmu debug buffer registers at init()
drm/nouveau/fb/gf100-: allocate mmu debug buffers
drm/nouveau/fb: allow chipset-specific actions for oneinit()
...
Diffstat (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_runtime_pm.c | 519 |
1 files changed, 324 insertions, 195 deletions
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 6e54d978d9d4..7fb1da4e7fc3 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -89,6 +89,10 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) return "TRANSCODER_C"; case POWER_DOMAIN_TRANSCODER_EDP: return "TRANSCODER_EDP"; + case POWER_DOMAIN_TRANSCODER_DSI_A: + return "TRANSCODER_DSI_A"; + case POWER_DOMAIN_TRANSCODER_DSI_C: + return "TRANSCODER_DSI_C"; case POWER_DOMAIN_PORT_DDI_A_LANES: return "PORT_DDI_A_LANES"; case POWER_DOMAIN_PORT_DDI_B_LANES: @@ -393,11 +397,6 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_MODESET) | \ BIT(POWER_DOMAIN_AUX_A) | \ BIT(POWER_DOMAIN_INIT)) -#define SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS ( \ - (POWER_DOMAIN_MASK & ~( \ - SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ - SKL_DISPLAY_DC_OFF_POWER_DOMAINS)) | \ - BIT(POWER_DOMAIN_INIT)) #define BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_TRANSCODER_A) | \ @@ -415,36 +414,21 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_VGA) | \ BIT(POWER_DOMAIN_GMBUS) | \ BIT(POWER_DOMAIN_INIT)) -#define BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS ( \ - BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ - BIT(POWER_DOMAIN_PIPE_A) | \ - BIT(POWER_DOMAIN_TRANSCODER_EDP) | \ - BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \ - BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \ - BIT(POWER_DOMAIN_AUX_A) | \ - BIT(POWER_DOMAIN_PLLS) | \ - BIT(POWER_DOMAIN_INIT)) #define BXT_DISPLAY_DC_OFF_POWER_DOMAINS ( \ BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ BIT(POWER_DOMAIN_MODESET) | \ BIT(POWER_DOMAIN_AUX_A) | \ BIT(POWER_DOMAIN_INIT)) -#define BXT_DISPLAY_ALWAYS_ON_POWER_DOMAINS ( \ - (POWER_DOMAIN_MASK & ~(BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS | \ - BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS)) | \ - BIT(POWER_DOMAIN_INIT)) static void assert_can_enable_dc9(struct drm_i915_private *dev_priv) { - struct drm_device *dev = dev_priv->dev; - - WARN(!IS_BROXTON(dev), "Platform doesn't support DC9.\n"); - WARN((I915_READ(DC_STATE_EN) & DC_STATE_EN_DC9), - "DC9 already programmed to be enabled.\n"); - WARN(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5, - "DC5 still not disabled to enable DC9.\n"); - WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on.\n"); - WARN(intel_irqs_enabled(dev_priv), "Interrupts not disabled yet.\n"); + WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_DC9), + "DC9 already programmed to be enabled.\n"); + WARN_ONCE(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5, + "DC5 still not disabled to enable DC9.\n"); + WARN_ONCE(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on.\n"); + WARN_ONCE(intel_irqs_enabled(dev_priv), + "Interrupts not disabled yet.\n"); /* * TODO: check for the following to verify the conditions to enter DC9 @@ -457,11 +441,10 @@ static void assert_can_enable_dc9(struct drm_i915_private *dev_priv) static void assert_can_disable_dc9(struct drm_i915_private *dev_priv) { - WARN(intel_irqs_enabled(dev_priv), "Interrupts not disabled yet.\n"); - WARN(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_DC9), - "DC9 already programmed to be disabled.\n"); - WARN(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5, - "DC5 still not disabled.\n"); + WARN_ONCE(intel_irqs_enabled(dev_priv), + "Interrupts not disabled yet.\n"); + WARN_ONCE(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5, + "DC5 still not disabled.\n"); /* * TODO: check for the following to verify DC9 state was indeed @@ -472,24 +455,6 @@ static void assert_can_disable_dc9(struct drm_i915_private *dev_priv) */ } -static void gen9_set_dc_state_debugmask(struct drm_i915_private *dev_priv) -{ - uint32_t val, mask; - - mask = DC_STATE_DEBUG_MASK_MEMORY_UP; - - if (IS_BROXTON(dev_priv)) - mask |= DC_STATE_DEBUG_MASK_CORES; - - /* The below bit doesn't need to be cleared ever afterwards */ - val = I915_READ(DC_STATE_DEBUG); - if ((val & mask) != mask) { - val |= mask; - I915_WRITE(DC_STATE_DEBUG, val); - POSTING_READ(DC_STATE_DEBUG); - } -} - static void gen9_write_dc_state(struct drm_i915_private *dev_priv, u32 state) { @@ -527,10 +492,9 @@ static void gen9_write_dc_state(struct drm_i915_private *dev_priv, state, rewrites); } -static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state) +static u32 gen9_dc_mask(struct drm_i915_private *dev_priv) { - uint32_t val; - uint32_t mask; + u32 mask; mask = DC_STATE_EN_UPTO_DC5; if (IS_BROXTON(dev_priv)) @@ -538,14 +502,30 @@ static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state) else mask |= DC_STATE_EN_UPTO_DC6; - WARN_ON_ONCE(state & ~mask); + return mask; +} + +void gen9_sanitize_dc_state(struct drm_i915_private *dev_priv) +{ + u32 val; - if (i915.enable_dc == 0) - state = DC_STATE_DISABLE; - else if (i915.enable_dc == 1 && state > DC_STATE_EN_UPTO_DC5) - state = DC_STATE_EN_UPTO_DC5; + val = I915_READ(DC_STATE_EN) & gen9_dc_mask(dev_priv); + + DRM_DEBUG_KMS("Resetting DC state tracking from %02x to %02x\n", + dev_priv->csr.dc_state, val); + dev_priv->csr.dc_state = val; +} + +static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state) +{ + uint32_t val; + uint32_t mask; + + if (WARN_ON_ONCE(state & ~dev_priv->csr.allowed_dc_mask)) + state &= dev_priv->csr.allowed_dc_mask; val = I915_READ(DC_STATE_EN); + mask = gen9_dc_mask(dev_priv); DRM_DEBUG_KMS("Setting DC state from %02x to %02x\n", val & mask, state); @@ -590,13 +570,9 @@ static void assert_csr_loaded(struct drm_i915_private *dev_priv) static void assert_can_enable_dc5(struct drm_i915_private *dev_priv) { - struct drm_device *dev = dev_priv->dev; bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv, SKL_DISP_PW_2); - WARN_ONCE(!IS_SKYLAKE(dev) && !IS_KABYLAKE(dev), - "Platform doesn't support DC5.\n"); - WARN_ONCE(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n"); WARN_ONCE(pg2_enabled, "PG2 not disabled to enable DC5.\n"); WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5), @@ -606,19 +582,7 @@ static void assert_can_enable_dc5(struct drm_i915_private *dev_priv) assert_csr_loaded(dev_priv); } -static void assert_can_disable_dc5(struct drm_i915_private *dev_priv) -{ - /* - * During initialization, the firmware may not be loaded yet. - * We still want to make sure that the DC enabling flag is cleared. - */ - if (dev_priv->power_domains.initializing) - return; - - assert_rpm_wakelock_held(dev_priv); -} - -static void gen9_enable_dc5(struct drm_i915_private *dev_priv) +void gen9_enable_dc5(struct drm_i915_private *dev_priv) { assert_can_enable_dc5(dev_priv); @@ -629,11 +593,6 @@ static void gen9_enable_dc5(struct drm_i915_private *dev_priv) static void assert_can_enable_dc6(struct drm_i915_private *dev_priv) { - struct drm_device *dev = dev_priv->dev; - - WARN_ONCE(!IS_SKYLAKE(dev) && !IS_KABYLAKE(dev), - "Platform doesn't support DC6.\n"); - WARN_ONCE(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n"); WARN_ONCE(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE, "Backlight is not disabled.\n"); WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), @@ -642,47 +601,60 @@ static void assert_can_enable_dc6(struct drm_i915_private *dev_priv) assert_csr_loaded(dev_priv); } -static void assert_can_disable_dc6(struct drm_i915_private *dev_priv) +void skl_enable_dc6(struct drm_i915_private *dev_priv) { - /* - * During initialization, the firmware may not be loaded yet. - * We still want to make sure that the DC enabling flag is cleared. - */ - if (dev_priv->power_domains.initializing) - return; + assert_can_enable_dc6(dev_priv); + + DRM_DEBUG_KMS("Enabling DC6\n"); + + gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); - WARN_ONCE(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), - "DC6 already programmed to be disabled.\n"); } -static void gen9_disable_dc5_dc6(struct drm_i915_private *dev_priv) +void skl_disable_dc6(struct drm_i915_private *dev_priv) { - assert_can_disable_dc5(dev_priv); - - if ((IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) && - i915.enable_dc != 0 && i915.enable_dc != 1) - assert_can_disable_dc6(dev_priv); + DRM_DEBUG_KMS("Disabling DC6\n"); gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); } -void skl_enable_dc6(struct drm_i915_private *dev_priv) +static void +gen9_sanitize_power_well_requests(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) { - assert_can_enable_dc6(dev_priv); + enum skl_disp_power_wells power_well_id = power_well->data; + u32 val; + u32 mask; - DRM_DEBUG_KMS("Enabling DC6\n"); + mask = SKL_POWER_WELL_REQ(power_well_id); - gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); + val = I915_READ(HSW_PWR_WELL_KVMR); + if (WARN_ONCE(val & mask, "Clearing unexpected KVMR request for %s\n", + power_well->name)) + I915_WRITE(HSW_PWR_WELL_KVMR, val & ~mask); -} + val = I915_READ(HSW_PWR_WELL_BIOS); + val |= I915_READ(HSW_PWR_WELL_DEBUG); -void skl_disable_dc6(struct drm_i915_private *dev_priv) -{ - assert_can_disable_dc6(dev_priv); + if (!(val & mask)) + return; - DRM_DEBUG_KMS("Disabling DC6\n"); + /* + * DMC is known to force on the request bits for power well 1 on SKL + * and BXT and the misc IO power well on SKL but we don't expect any + * other request bits to be set, so WARN for those. + */ + if (power_well_id == SKL_DISP_PW_1 || + ((IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) && + power_well_id == SKL_DISP_PW_MISC_IO)) + DRM_DEBUG_DRIVER("Clearing auxiliary requests for %s forced on " + "by DMC\n", power_well->name); + else + WARN_ONCE(1, "Clearing unexpected auxiliary requests for %s\n", + power_well->name); - gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); + I915_WRITE(HSW_PWR_WELL_BIOS, val & ~mask); + I915_WRITE(HSW_PWR_WELL_DEBUG, val & ~mask); } static void skl_set_power_well(struct drm_i915_private *dev_priv, @@ -739,10 +711,6 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, if (!is_enabled) { DRM_DEBUG_KMS("Enabling %s\n", power_well->name); - if (wait_for((I915_READ(HSW_PWR_WELL_DRIVER) & - state_mask), 1)) - DRM_ERROR("%s enable timeout\n", - power_well->name); check_fuse_status = true; } } else { @@ -751,8 +719,16 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, POSTING_READ(HSW_PWR_WELL_DRIVER); DRM_DEBUG_KMS("Disabling %s\n", power_well->name); } + + if (IS_GEN9(dev_priv)) + gen9_sanitize_power_well_requests(dev_priv, power_well); } + if (wait_for(!!(I915_READ(HSW_PWR_WELL_DRIVER) & state_mask) == enable, + 1)) + DRM_ERROR("%s %s timeout\n", + power_well->name, enable ? "enable" : "disable"); + if (check_fuse_status) { if (power_well->data == SKL_DISP_PW_1) { if (wait_for((I915_READ(SKL_FUSE_STATUS) & @@ -833,32 +809,33 @@ static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv, static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - gen9_disable_dc5_dc6(dev_priv); + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); + + if (IS_BROXTON(dev_priv)) { + broxton_cdclk_verify_state(dev_priv); + broxton_ddi_phy_verify_state(dev_priv); + } } static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - if ((IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) && - i915.enable_dc != 0 && i915.enable_dc != 1) + if (!dev_priv->csr.dmc_payload) + return; + + if (dev_priv->csr.allowed_dc_mask & DC_STATE_EN_UPTO_DC6) skl_enable_dc6(dev_priv); - else + else if (dev_priv->csr.allowed_dc_mask & DC_STATE_EN_UPTO_DC5) gen9_enable_dc5(dev_priv); } static void gen9_dc_off_power_well_sync_hw(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - if (power_well->count > 0) { - gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); - } else { - if ((IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) && - i915.enable_dc != 0 && - i915.enable_dc != 1) - gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); - else - gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5); - } + if (power_well->count > 0) + gen9_dc_off_power_well_enable(dev_priv, power_well); + else + gen9_dc_off_power_well_disable(dev_priv, power_well); } static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv, @@ -962,6 +939,17 @@ static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv, return enabled; } +static void vlv_init_display_clock_gating(struct drm_i915_private *dev_priv) +{ + I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE); + + /* + * Disable trickle feed and enable pnd deadline calculation + */ + I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE); + I915_WRITE(CBR1_VLV, 0); +} + static void vlv_display_power_well_init(struct drm_i915_private *dev_priv) { enum pipe pipe; @@ -984,6 +972,8 @@ static void vlv_display_power_well_init(struct drm_i915_private *dev_priv) I915_WRITE(DPLL(pipe), val); } + vlv_init_display_clock_gating(dev_priv); + spin_lock_irq(&dev_priv->irq_lock); valleyview_enable_display_irqs(dev_priv); spin_unlock_irq(&dev_priv->irq_lock); @@ -1622,34 +1612,56 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, intel_runtime_pm_put(dev_priv); } -#define HSW_ALWAYS_ON_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PIPE_A) | \ - BIT(POWER_DOMAIN_TRANSCODER_EDP) | \ - BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \ +#define HSW_DISPLAY_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PIPE_B) | \ + BIT(POWER_DOMAIN_PIPE_C) | \ + BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \ + BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \ + BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) | \ + BIT(POWER_DOMAIN_TRANSCODER_A) | \ + BIT(POWER_DOMAIN_TRANSCODER_B) | \ + BIT(POWER_DOMAIN_TRANSCODER_C) | \ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \ - BIT(POWER_DOMAIN_PORT_CRT) | \ - BIT(POWER_DOMAIN_PLLS) | \ - BIT(POWER_DOMAIN_AUX_A) | \ - BIT(POWER_DOMAIN_AUX_B) | \ - BIT(POWER_DOMAIN_AUX_C) | \ - BIT(POWER_DOMAIN_AUX_D) | \ - BIT(POWER_DOMAIN_GMBUS) | \ - BIT(POWER_DOMAIN_INIT)) -#define HSW_DISPLAY_POWER_DOMAINS ( \ - (POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) | \ + BIT(POWER_DOMAIN_PORT_CRT) | /* DDI E */ \ + BIT(POWER_DOMAIN_VGA) | \ + BIT(POWER_DOMAIN_AUDIO) | \ BIT(POWER_DOMAIN_INIT)) -#define BDW_ALWAYS_ON_POWER_DOMAINS ( \ - HSW_ALWAYS_ON_POWER_DOMAINS | \ - BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER)) -#define BDW_DISPLAY_POWER_DOMAINS ( \ - (POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) | \ +#define BDW_DISPLAY_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PIPE_B) | \ + BIT(POWER_DOMAIN_PIPE_C) | \ + BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \ + BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) | \ + BIT(POWER_DOMAIN_TRANSCODER_A) | \ + BIT(POWER_DOMAIN_TRANSCODER_B) | \ + BIT(POWER_DOMAIN_TRANSCODER_C) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \ + BIT(POWER_DOMAIN_PORT_CRT) | /* DDI E */ \ + BIT(POWER_DOMAIN_VGA) | \ + BIT(POWER_DOMAIN_AUDIO) | \ BIT(POWER_DOMAIN_INIT)) -#define VLV_ALWAYS_ON_POWER_DOMAINS BIT(POWER_DOMAIN_INIT) -#define VLV_DISPLAY_POWER_DOMAINS POWER_DOMAIN_MASK +#define VLV_DISPLAY_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PIPE_A) | \ + BIT(POWER_DOMAIN_PIPE_B) | \ + BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \ + BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \ + BIT(POWER_DOMAIN_TRANSCODER_A) | \ + BIT(POWER_DOMAIN_TRANSCODER_B) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ + BIT(POWER_DOMAIN_PORT_DSI) | \ + BIT(POWER_DOMAIN_PORT_CRT) | \ + BIT(POWER_DOMAIN_VGA) | \ + BIT(POWER_DOMAIN_AUDIO) | \ + BIT(POWER_DOMAIN_AUX_B) | \ + BIT(POWER_DOMAIN_AUX_C) | \ + BIT(POWER_DOMAIN_GMBUS) | \ + BIT(POWER_DOMAIN_INIT)) #define VLV_DPIO_CMN_BC_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ @@ -1679,6 +1691,28 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_INIT)) +#define CHV_DISPLAY_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PIPE_A) | \ + BIT(POWER_DOMAIN_PIPE_B) | \ + BIT(POWER_DOMAIN_PIPE_C) | \ + BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \ + BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \ + BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) | \ + BIT(POWER_DOMAIN_TRANSCODER_A) | \ + BIT(POWER_DOMAIN_TRANSCODER_B) | \ + BIT(POWER_DOMAIN_TRANSCODER_C) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \ + BIT(POWER_DOMAIN_PORT_DSI) | \ + BIT(POWER_DOMAIN_VGA) | \ + BIT(POWER_DOMAIN_AUDIO) | \ + BIT(POWER_DOMAIN_AUX_B) | \ + BIT(POWER_DOMAIN_AUX_C) | \ + BIT(POWER_DOMAIN_AUX_D) | \ + BIT(POWER_DOMAIN_GMBUS) | \ + BIT(POWER_DOMAIN_INIT)) + #define CHV_DPIO_CMN_BC_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ @@ -1746,7 +1780,7 @@ static struct i915_power_well hsw_power_wells[] = { { .name = "always-on", .always_on = 1, - .domains = HSW_ALWAYS_ON_POWER_DOMAINS, + .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, }, { @@ -1760,7 +1794,7 @@ static struct i915_power_well bdw_power_wells[] = { { .name = "always-on", .always_on = 1, - .domains = BDW_ALWAYS_ON_POWER_DOMAINS, + .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, }, { @@ -1795,7 +1829,7 @@ static struct i915_power_well vlv_power_wells[] = { { .name = "always-on", .always_on = 1, - .domains = VLV_ALWAYS_ON_POWER_DOMAINS, + .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, .data = PUNIT_POWER_WELL_ALWAYS_ON, }, @@ -1853,7 +1887,7 @@ static struct i915_power_well chv_power_wells[] = { { .name = "always-on", .always_on = 1, - .domains = VLV_ALWAYS_ON_POWER_DOMAINS, + .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, }, { @@ -1863,7 +1897,7 @@ static struct i915_power_well chv_power_wells[] = { * power wells don't actually exist. Pipe A power well is * required for any pipe to work. */ - .domains = VLV_DISPLAY_POWER_DOMAINS, + .domains = CHV_DISPLAY_POWER_DOMAINS, .data = PIPE_A, .ops = &chv_pipe_power_well_ops, }, @@ -1897,7 +1931,7 @@ static struct i915_power_well skl_power_wells[] = { { .name = "always-on", .always_on = 1, - .domains = SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS, + .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, .data = SKL_DISP_PW_ALWAYS_ON, }, @@ -1953,44 +1987,16 @@ static struct i915_power_well skl_power_wells[] = { }, }; -void skl_pw1_misc_io_init(struct drm_i915_private *dev_priv) -{ - struct i915_power_well *well; - - if (!(IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))) - return; - - well = lookup_power_well(dev_priv, SKL_DISP_PW_1); - intel_power_well_enable(dev_priv, well); - - well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO); - intel_power_well_enable(dev_priv, well); -} - -void skl_pw1_misc_io_fini(struct drm_i915_private *dev_priv) -{ - struct i915_power_well *well; - - if (!(IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))) - return; - - well = lookup_power_well(dev_priv, SKL_DISP_PW_1); - intel_power_well_disable(dev_priv, well); - - well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO); - intel_power_well_disable(dev_priv, well); -} - static struct i915_power_well bxt_power_wells[] = { { .name = "always-on", .always_on = 1, - .domains = BXT_DISPLAY_ALWAYS_ON_POWER_DOMAINS, + .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, }, { .name = "power well 1", - .domains = BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS, + .domains = 0, .ops = &skl_power_well_ops, .data = SKL_DISP_PW_1, }, @@ -2015,12 +2021,56 @@ sanitize_disable_power_well_option(const struct drm_i915_private *dev_priv, if (disable_power_well >= 0) return !!disable_power_well; - if (IS_BROXTON(dev_priv)) { - DRM_DEBUG_KMS("Disabling display power well support\n"); - return 0; + return 1; +} + +static uint32_t get_allowed_dc_mask(const struct drm_i915_private *dev_priv, + int enable_dc) +{ + uint32_t mask; + int requested_dc; + int max_dc; + + if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + max_dc = 2; + mask = 0; + } else if (IS_BROXTON(dev_priv)) { + max_dc = 1; + /* + * DC9 has a separate HW flow from the rest of the DC states, + * not depending on the DMC firmware. It's needed by system + * suspend/resume, so allow it unconditionally. + */ + mask = DC_STATE_EN_DC9; + } else { + max_dc = 0; + mask = 0; } - return 1; + if (!i915.disable_power_well) + max_dc = 0; + + if (enable_dc >= 0 && enable_dc <= max_dc) { + requested_dc = enable_dc; + } else if (enable_dc == -1) { + requested_dc = max_dc; + } else if (enable_dc > max_dc && enable_dc <= 2) { + DRM_DEBUG_KMS("Adjusting requested max DC state (%d->%d)\n", + enable_dc, max_dc); + requested_dc = max_dc; + } else { + DRM_ERROR("Unexpected value for enable_dc (%d)\n", enable_dc); + requested_dc = max_dc; + } + + if (requested_dc > 1) + mask |= DC_STATE_EN_UPTO_DC6; + if (requested_dc > 0) + mask |= DC_STATE_EN_UPTO_DC5; + + DRM_DEBUG_KMS("Allowed DC state mask %02x\n", mask); + + return mask; } #define set_power_wells(power_domains, __power_wells) ({ \ @@ -2041,6 +2091,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) i915.disable_power_well = sanitize_disable_power_well_option(dev_priv, i915.disable_power_well); + dev_priv->csr.allowed_dc_mask = get_allowed_dc_mask(dev_priv, + i915.enable_dc); BUILD_BUG_ON(POWER_DOMAIN_NUM > 31); @@ -2050,17 +2102,17 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) * The enabling order will be from lower to higher indexed wells, * the disabling order is reversed. */ - if (IS_HASWELL(dev_priv->dev)) { + if (IS_HASWELL(dev_priv)) { set_power_wells(power_domains, hsw_power_wells); - } else if (IS_BROADWELL(dev_priv->dev)) { + } else if (IS_BROADWELL(dev_priv)) { set_power_wells(power_domains, bdw_power_wells); - } else if (IS_SKYLAKE(dev_priv->dev) || IS_KABYLAKE(dev_priv->dev)) { + } else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { set_power_wells(power_domains, skl_power_wells); - } else if (IS_BROXTON(dev_priv->dev)) { + } else if (IS_BROXTON(dev_priv)) { set_power_wells(power_domains, bxt_power_wells); - } else if (IS_CHERRYVIEW(dev_priv->dev)) { + } else if (IS_CHERRYVIEW(dev_priv)) { set_power_wells(power_domains, chv_power_wells); - } else if (IS_VALLEYVIEW(dev_priv->dev)) { + } else if (IS_VALLEYVIEW(dev_priv)) { set_power_wells(power_domains, vlv_power_wells); } else { set_power_wells(power_domains, i9xx_always_on_power_well); @@ -2120,9 +2172,10 @@ static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv) } static void skl_display_core_init(struct drm_i915_private *dev_priv, - bool resume) + bool resume) { struct i915_power_domains *power_domains = &dev_priv->power_domains; + struct i915_power_well *well; uint32_t val; gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); @@ -2133,7 +2186,13 @@ static void skl_display_core_init(struct drm_i915_private *dev_priv, /* enable PG1 and Misc I/O */ mutex_lock(&power_domains->lock); - skl_pw1_misc_io_init(dev_priv); + + well = lookup_power_well(dev_priv, SKL_DISP_PW_1); + intel_power_well_enable(dev_priv, well); + + well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO); + intel_power_well_enable(dev_priv, well); + mutex_unlock(&power_domains->lock); if (!resume) @@ -2141,13 +2200,14 @@ static void skl_display_core_init(struct drm_i915_private *dev_priv, skl_init_cdclk(dev_priv); - if (dev_priv->csr.dmc_payload && intel_csr_load_program(dev_priv)) - gen9_set_dc_state_debugmask(dev_priv); + if (dev_priv->csr.dmc_payload) + intel_csr_load_program(dev_priv); } static void skl_display_core_uninit(struct drm_i915_private *dev_priv) { struct i915_power_domains *power_domains = &dev_priv->power_domains; + struct i915_power_well *well; gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); @@ -2155,8 +2215,73 @@ static void skl_display_core_uninit(struct drm_i915_private *dev_priv) /* The spec doesn't call for removing the reset handshake flag */ /* disable PG1 and Misc I/O */ + + mutex_lock(&power_domains->lock); + + well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO); + intel_power_well_disable(dev_priv, well); + + well = lookup_power_well(dev_priv, SKL_DISP_PW_1); + intel_power_well_disable(dev_priv, well); + + mutex_unlock(&power_domains->lock); +} + +void bxt_display_core_init(struct drm_i915_private *dev_priv, + bool resume) +{ + struct i915_power_domains *power_domains = &dev_priv->power_domains; + struct i915_power_well *well; + uint32_t val; + + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); + + /* + * NDE_RSTWRN_OPT RST PCH Handshake En must always be 0b on BXT + * or else the reset will hang because there is no PCH to respond. + * Move the handshake programming to initialization sequence. + * Previously was left up to BIOS. + */ + val = I915_READ(HSW_NDE_RSTWRN_OPT); + val &= ~RESET_PCH_HANDSHAKE_ENABLE; + I915_WRITE(HSW_NDE_RSTWRN_OPT, val); + + /* Enable PG1 */ + mutex_lock(&power_domains->lock); + + well = lookup_power_well(dev_priv, SKL_DISP_PW_1); + intel_power_well_enable(dev_priv, well); + + mutex_unlock(&power_domains->lock); + + broxton_init_cdclk(dev_priv); + broxton_ddi_phy_init(dev_priv); + + broxton_cdclk_verify_state(dev_priv); + broxton_ddi_phy_verify_state(dev_priv); + + if (resume && dev_priv->csr.dmc_payload) + intel_csr_load_program(dev_priv); +} + +void bxt_display_core_uninit(struct drm_i915_private *dev_priv) +{ + struct i915_power_domains *power_domains = &dev_priv->power_domains; + struct i915_power_well *well; + + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); + + broxton_ddi_phy_uninit(dev_priv); + broxton_uninit_cdclk(dev_priv); + + /* The spec doesn't call for removing the reset handshake flag */ + + /* Disable PG1 */ mutex_lock(&power_domains->lock); - skl_pw1_misc_io_fini(dev_priv); + + well = lookup_power_well(dev_priv, SKL_DISP_PW_1); + intel_power_well_disable(dev_priv, well); + mutex_unlock(&power_domains->lock); } @@ -2291,6 +2416,8 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume) if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { skl_display_core_init(dev_priv, resume); + } else if (IS_BROXTON(dev)) { + bxt_display_core_init(dev_priv, resume); } else if (IS_CHERRYVIEW(dev)) { mutex_lock(&power_domains->lock); chv_phy_control_init(dev_priv); @@ -2328,6 +2455,8 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv) if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) skl_display_core_uninit(dev_priv); + else if (IS_BROXTON(dev_priv)) + bxt_display_core_uninit(dev_priv); } /** |
