diff options
author | Paulo Zanoni <paulo.r.zanoni@intel.com> | 2013-07-23 10:19:26 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-07-24 04:37:10 -0400 |
commit | be256dc70284c028d0dd828b18b8f804e310507b (patch) | |
tree | 8c7958e44305ce17af999b08de41584b94e096cd /drivers/gpu/drm/i915 | |
parent | 47701c3ba26cb33ebe8a5e899ec922ab0de621a3 (diff) |
drm/i915: add functions to disable and restore LCPLL
For now there are no callers, but these functions are going to be
needed for the code that allows Package C8+. Other future features may
also require this code.
Also merge the commit which introduced assert_can_disable_lcpll and
had the following commit message:
Most of the hardware needs to be disabled before LCPLL is disabled, so
let's add a function to assert some of items listed in the "Display
Sequences for LCPLL disabling" documentation.
The idea is that hsw_disable_lcpll should not disable the hardware,
the callers need to take care of calling hsw_disable_lcpll only once
everything is already disabled.
v2: - Rebase.
- Fix D_COMP wait timeout.
v3: - Use wait_for_atomic_use (Ben)
- Remove/add a useless/needed POSTING_READ (Ben)
- Early return in case LCPLL is already restored (Ben)
- Add ndelay(100) (Ben)
v4: - Merge the commit that added assert_can_disable_lcpll (Ben)
- Add interrupt assertions (Ben)
Reviewed-by: Ben Widawsky <ben@bwidawsk.net>
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
[danvet: Fix compile fail since there's no HAS_LP_PCH yet.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 136 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 3 |
3 files changed, 154 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0dfcbad4eb7b..6caa748fa00f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -2261,6 +2261,8 @@ | |||
2261 | #define BLC_PWM_CPU_CTL2 0x48250 | 2261 | #define BLC_PWM_CPU_CTL2 0x48250 |
2262 | #define BLC_PWM_CPU_CTL 0x48254 | 2262 | #define BLC_PWM_CPU_CTL 0x48254 |
2263 | 2263 | ||
2264 | #define HSW_BLC_PWM2_CTL 0x48350 | ||
2265 | |||
2264 | /* PCH CTL1 is totally different, all but the below bits are reserved. CTL2 is | 2266 | /* PCH CTL1 is totally different, all but the below bits are reserved. CTL2 is |
2265 | * like the normal CTL from gen4 and earlier. Hooray for confusing naming. */ | 2267 | * like the normal CTL from gen4 and earlier. Hooray for confusing naming. */ |
2266 | #define BLC_PWM_PCH_CTL1 0xc8250 | 2268 | #define BLC_PWM_PCH_CTL1 0xc8250 |
@@ -2269,6 +2271,12 @@ | |||
2269 | #define BLM_PCH_POLARITY (1 << 29) | 2271 | #define BLM_PCH_POLARITY (1 << 29) |
2270 | #define BLC_PWM_PCH_CTL2 0xc8254 | 2272 | #define BLC_PWM_PCH_CTL2 0xc8254 |
2271 | 2273 | ||
2274 | #define UTIL_PIN_CTL 0x48400 | ||
2275 | #define UTIL_PIN_ENABLE (1 << 31) | ||
2276 | |||
2277 | #define PCH_GTC_CTL 0xe7000 | ||
2278 | #define PCH_GTC_ENABLE (1 << 31) | ||
2279 | |||
2272 | /* TV port control */ | 2280 | /* TV port control */ |
2273 | #define TV_CTL 0x68000 | 2281 | #define TV_CTL 0x68000 |
2274 | /** Enables the TV encoder */ | 2282 | /** Enables the TV encoder */ |
@@ -5009,7 +5017,14 @@ | |||
5009 | #define LCPLL_CLK_FREQ_450 (0<<26) | 5017 | #define LCPLL_CLK_FREQ_450 (0<<26) |
5010 | #define LCPLL_CD_CLOCK_DISABLE (1<<25) | 5018 | #define LCPLL_CD_CLOCK_DISABLE (1<<25) |
5011 | #define LCPLL_CD2X_CLOCK_DISABLE (1<<23) | 5019 | #define LCPLL_CD2X_CLOCK_DISABLE (1<<23) |
5020 | #define LCPLL_POWER_DOWN_ALLOW (1<<22) | ||
5012 | #define LCPLL_CD_SOURCE_FCLK (1<<21) | 5021 | #define LCPLL_CD_SOURCE_FCLK (1<<21) |
5022 | #define LCPLL_CD_SOURCE_FCLK_DONE (1<<19) | ||
5023 | |||
5024 | #define D_COMP (MCHBAR_MIRROR_BASE_SNB + 0x5F0C) | ||
5025 | #define D_COMP_RCOMP_IN_PROGRESS (1<<9) | ||
5026 | #define D_COMP_COMP_FORCE (1<<8) | ||
5027 | #define D_COMP_COMP_DISABLE (1<<0) | ||
5013 | 5028 | ||
5014 | /* Pipe WM_LINETIME - watermark line time */ | 5029 | /* Pipe WM_LINETIME - watermark line time */ |
5015 | #define PIPE_WM_LINETIME_A 0x45270 | 5030 | #define PIPE_WM_LINETIME_A 0x45270 |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 26b49d8d781c..32024dadccee 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -5925,6 +5925,142 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, | |||
5925 | return true; | 5925 | return true; |
5926 | } | 5926 | } |
5927 | 5927 | ||
5928 | static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) | ||
5929 | { | ||
5930 | struct drm_device *dev = dev_priv->dev; | ||
5931 | struct intel_ddi_plls *plls = &dev_priv->ddi_plls; | ||
5932 | struct intel_crtc *crtc; | ||
5933 | unsigned long irqflags; | ||
5934 | uint32_t val, pch_hpd_mask; | ||
5935 | |||
5936 | pch_hpd_mask = SDE_PORTB_HOTPLUG_CPT | SDE_PORTC_HOTPLUG_CPT; | ||
5937 | if (!(dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE)) | ||
5938 | pch_hpd_mask |= SDE_PORTD_HOTPLUG_CPT | SDE_CRT_HOTPLUG_CPT; | ||
5939 | |||
5940 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) | ||
5941 | WARN(crtc->base.enabled, "CRTC for pipe %c enabled\n", | ||
5942 | pipe_name(crtc->pipe)); | ||
5943 | |||
5944 | WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n"); | ||
5945 | WARN(plls->spll_refcount, "SPLL enabled\n"); | ||
5946 | WARN(plls->wrpll1_refcount, "WRPLL1 enabled\n"); | ||
5947 | WARN(plls->wrpll2_refcount, "WRPLL2 enabled\n"); | ||
5948 | WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n"); | ||
5949 | WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE, | ||
5950 | "CPU PWM1 enabled\n"); | ||
5951 | WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE, | ||
5952 | "CPU PWM2 enabled\n"); | ||
5953 | WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE, | ||
5954 | "PCH PWM1 enabled\n"); | ||
5955 | WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE, | ||
5956 | "Utility pin enabled\n"); | ||
5957 | WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n"); | ||
5958 | |||
5959 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); | ||
5960 | val = I915_READ(DEIMR); | ||
5961 | WARN((val & ~DE_PCH_EVENT_IVB) != val, | ||
5962 | "Unexpected DEIMR bits enabled: 0x%x\n", val); | ||
5963 | val = I915_READ(SDEIMR); | ||
5964 | WARN((val & ~pch_hpd_mask) != val, | ||
5965 | "Unexpected SDEIMR bits enabled: 0x%x\n", val); | ||
5966 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); | ||
5967 | } | ||
5968 | |||
5969 | /* | ||
5970 | * This function implements pieces of two sequences from BSpec: | ||
5971 | * - Sequence for display software to disable LCPLL | ||
5972 | * - Sequence for display software to allow package C8+ | ||
5973 | * The steps implemented here are just the steps that actually touch the LCPLL | ||
5974 | * register. Callers should take care of disabling all the display engine | ||
5975 | * functions, doing the mode unset, fixing interrupts, etc. | ||
5976 | */ | ||
5977 | void hsw_disable_lcpll(struct drm_i915_private *dev_priv, | ||
5978 | bool switch_to_fclk, bool allow_power_down) | ||
5979 | { | ||
5980 | uint32_t val; | ||
5981 | |||
5982 | assert_can_disable_lcpll(dev_priv); | ||
5983 | |||
5984 | val = I915_READ(LCPLL_CTL); | ||
5985 | |||
5986 | if (switch_to_fclk) { | ||
5987 | val |= LCPLL_CD_SOURCE_FCLK; | ||
5988 | I915_WRITE(LCPLL_CTL, val); | ||
5989 | |||
5990 | if (wait_for_atomic_us(I915_READ(LCPLL_CTL) & | ||
5991 | LCPLL_CD_SOURCE_FCLK_DONE, 1)) | ||
5992 | DRM_ERROR("Switching to FCLK failed\n"); | ||
5993 | |||
5994 | val = I915_READ(LCPLL_CTL); | ||
5995 | } | ||
5996 | |||
5997 | val |= LCPLL_PLL_DISABLE; | ||
5998 | I915_WRITE(LCPLL_CTL, val); | ||
5999 | POSTING_READ(LCPLL_CTL); | ||
6000 | |||
6001 | if (wait_for((I915_READ(LCPLL_CTL) & LCPLL_PLL_LOCK) == 0, 1)) | ||
6002 | DRM_ERROR("LCPLL still locked\n"); | ||
6003 | |||
6004 | val = I915_READ(D_COMP); | ||
6005 | val |= D_COMP_COMP_DISABLE; | ||
6006 | I915_WRITE(D_COMP, val); | ||
6007 | POSTING_READ(D_COMP); | ||
6008 | ndelay(100); | ||
6009 | |||
6010 | if (wait_for((I915_READ(D_COMP) & D_COMP_RCOMP_IN_PROGRESS) == 0, 1)) | ||
6011 | DRM_ERROR("D_COMP RCOMP still in progress\n"); | ||
6012 | |||
6013 | if (allow_power_down) { | ||
6014 | val = I915_READ(LCPLL_CTL); | ||
6015 | val |= LCPLL_POWER_DOWN_ALLOW; | ||
6016 | I915_WRITE(LCPLL_CTL, val); | ||
6017 | POSTING_READ(LCPLL_CTL); | ||
6018 | } | ||
6019 | } | ||
6020 | |||
6021 | /* | ||
6022 | * Fully restores LCPLL, disallowing power down and switching back to LCPLL | ||
6023 | * source. | ||
6024 | */ | ||
6025 | void hsw_restore_lcpll(struct drm_i915_private *dev_priv) | ||
6026 | { | ||
6027 | uint32_t val; | ||
6028 | |||
6029 | val = I915_READ(LCPLL_CTL); | ||
6030 | |||
6031 | if ((val & (LCPLL_PLL_LOCK | LCPLL_PLL_DISABLE | LCPLL_CD_SOURCE_FCLK | | ||
6032 | LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK) | ||
6033 | return; | ||
6034 | |||
6035 | if (val & LCPLL_POWER_DOWN_ALLOW) { | ||
6036 | val &= ~LCPLL_POWER_DOWN_ALLOW; | ||
6037 | I915_WRITE(LCPLL_CTL, val); | ||
6038 | } | ||
6039 | |||
6040 | val = I915_READ(D_COMP); | ||
6041 | val |= D_COMP_COMP_FORCE; | ||
6042 | val &= ~D_COMP_COMP_DISABLE; | ||
6043 | I915_WRITE(D_COMP, val); | ||
6044 | I915_READ(D_COMP); | ||
6045 | |||
6046 | val = I915_READ(LCPLL_CTL); | ||
6047 | val &= ~LCPLL_PLL_DISABLE; | ||
6048 | I915_WRITE(LCPLL_CTL, val); | ||
6049 | |||
6050 | if (wait_for(I915_READ(LCPLL_CTL) & LCPLL_PLL_LOCK, 5)) | ||
6051 | DRM_ERROR("LCPLL not locked yet\n"); | ||
6052 | |||
6053 | if (val & LCPLL_CD_SOURCE_FCLK) { | ||
6054 | val = I915_READ(LCPLL_CTL); | ||
6055 | val &= ~LCPLL_CD_SOURCE_FCLK; | ||
6056 | I915_WRITE(LCPLL_CTL, val); | ||
6057 | |||
6058 | if (wait_for_atomic_us((I915_READ(LCPLL_CTL) & | ||
6059 | LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1)) | ||
6060 | DRM_ERROR("Switching back to LCPLL failed\n"); | ||
6061 | } | ||
6062 | } | ||
6063 | |||
5928 | static void haswell_modeset_global_resources(struct drm_device *dev) | 6064 | static void haswell_modeset_global_resources(struct drm_device *dev) |
5929 | { | 6065 | { |
5930 | bool enable = false; | 6066 | bool enable = false; |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 40e955d00b2b..253fc1e9dbe2 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -838,5 +838,8 @@ extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, | |||
838 | extern void intel_edp_psr_enable(struct intel_dp *intel_dp); | 838 | extern void intel_edp_psr_enable(struct intel_dp *intel_dp); |
839 | extern void intel_edp_psr_disable(struct intel_dp *intel_dp); | 839 | extern void intel_edp_psr_disable(struct intel_dp *intel_dp); |
840 | extern void intel_edp_psr_update(struct drm_device *dev); | 840 | extern void intel_edp_psr_update(struct drm_device *dev); |
841 | extern void hsw_disable_lcpll(struct drm_i915_private *dev_priv, | ||
842 | bool switch_to_fclk, bool allow_power_down); | ||
843 | extern void hsw_restore_lcpll(struct drm_i915_private *dev_priv); | ||
841 | 844 | ||
842 | #endif /* __INTEL_DRV_H__ */ | 845 | #endif /* __INTEL_DRV_H__ */ |