aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2013-11-04 16:48:12 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-11-05 13:28:18 -0500
commit30a970c6a6ff734eda7cefe7e88f030157a6c939 (patch)
tree1fa4673e734c5e3f57288b97002de82a3ab9f39f /drivers
parent85b1d7b3f475c6425707b2e064f9c0f54058019d (diff)
drm/i915/vlv: modeset_global_* for VLV v7
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 <jbarnes@virtuousgeek.org> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h9
-rw-r--r--drivers/gpu/drm/i915/intel_display.c189
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c4
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 @@
360#define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104) 360#define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104)
361#define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108) 361#define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108)
362 362
363/* See configdb bunit SB addr map */
364#define BUNIT_REG_BISOC 0x11
365
363#define PUNIT_OPCODE_REG_READ 6 366#define PUNIT_OPCODE_REG_READ 6
364#define PUNIT_OPCODE_REG_WRITE 7 367#define PUNIT_OPCODE_REG_WRITE 7
365 368
369#define PUNIT_REG_DSPFREQ 0x36
370#define DSPFREQSTAT_SHIFT 30
371#define DSPFREQSTAT_MASK (0x3 << DSPFREQSTAT_SHIFT)
372#define DSPFREQGUAR_SHIFT 14
373#define DSPFREQGUAR_MASK (0x3 << DSPFREQGUAR_SHIFT)
366#define PUNIT_REG_PWRGT_CTRL 0x60 374#define PUNIT_REG_PWRGT_CTRL 0x60
367#define PUNIT_REG_PWRGT_STATUS 0x61 375#define PUNIT_REG_PWRGT_STATUS 0x61
368#define PUNIT_CLK_GATE 1 376#define PUNIT_CLK_GATE 1
@@ -425,6 +433,7 @@
425#define DSI_PLL_N1_DIV_MASK (3 << 16) 433#define DSI_PLL_N1_DIV_MASK (3 << 16)
426#define DSI_PLL_M1_DIV_SHIFT 0 434#define DSI_PLL_M1_DIV_SHIFT 0
427#define DSI_PLL_M1_DIV_MASK (0x1ff << 0) 435#define DSI_PLL_M1_DIV_MASK (0x1ff << 0)
436#define CCK_DISPLAY_CLOCK_CONTROL 0x6b
428 437
429/* 438/*
430 * DPIO - a special bus for various display related registers to hide behind 439 * 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)
3894 I915_WRITE(BCLRPAT(crtc->pipe), 0); 3894 I915_WRITE(BCLRPAT(crtc->pipe), 0);
3895} 3895}
3896 3896
3897static int valleyview_get_vco(struct drm_i915_private *dev_priv)
3898{
3899 int vco;
3900
3901 switch (dev_priv->mem_freq) {
3902 default:
3903 case 800:
3904 vco = 800;
3905 break;
3906 case 1066:
3907 vco = 1600;
3908 break;
3909 case 1333:
3910 vco = 2000;
3911 break;
3912 }
3913
3914 return vco;
3915}
3916
3917/* Adjust CDclk dividers to allow high res or save power if possible */
3918static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
3919{
3920 struct drm_i915_private *dev_priv = dev->dev_private;
3921 u32 val, cmd;
3922
3923 if (cdclk >= 320) /* jump to highest voltage for 400MHz too */
3924 cmd = 2;
3925 else if (cdclk == 266)
3926 cmd = 1;
3927 else
3928 cmd = 0;
3929
3930 mutex_lock(&dev_priv->rps.hw_lock);
3931 val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
3932 val &= ~DSPFREQGUAR_MASK;
3933 val |= (cmd << DSPFREQGUAR_SHIFT);
3934 vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val);
3935 if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) &
3936 DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT),
3937 50)) {
3938 DRM_ERROR("timed out waiting for CDclk change\n");
3939 }
3940 mutex_unlock(&dev_priv->rps.hw_lock);
3941
3942 if (cdclk == 400) {
3943 u32 divider, vco;
3944
3945 vco = valleyview_get_vco(dev_priv);
3946 divider = ((vco << 1) / cdclk) - 1;
3947
3948 mutex_lock(&dev_priv->dpio_lock);
3949 /* adjust cdclk divider */
3950 val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
3951 val &= ~0xf;
3952 val |= divider;
3953 vlv_cck_write(dev_priv, CCK_DISPLAY_CLOCK_CONTROL, val);
3954 mutex_unlock(&dev_priv->dpio_lock);
3955 }
3956
3957 mutex_lock(&dev_priv->dpio_lock);
3958 /* adjust self-refresh exit latency value */
3959 val = vlv_bunit_read(dev_priv, BUNIT_REG_BISOC);
3960 val &= ~0x7f;
3961
3962 /*
3963 * For high bandwidth configs, we set a higher latency in the bunit
3964 * so that the core display fetch happens in time to avoid underruns.
3965 */
3966 if (cdclk == 400)
3967 val |= 4500 / 250; /* 4.5 usec */
3968 else
3969 val |= 3000 / 250; /* 3.0 usec */
3970 vlv_bunit_write(dev_priv, BUNIT_REG_BISOC, val);
3971 mutex_unlock(&dev_priv->dpio_lock);
3972
3973 /* Since we changed the CDclk, we need to update the GMBUSFREQ too */
3974 intel_i2c_reset(dev);
3975}
3976
3977static int valleyview_cur_cdclk(struct drm_i915_private *dev_priv)
3978{
3979 int cur_cdclk, vco;
3980 int divider;
3981
3982 vco = valleyview_get_vco(dev_priv);
3983
3984 mutex_lock(&dev_priv->dpio_lock);
3985 divider = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
3986 mutex_unlock(&dev_priv->dpio_lock);
3987
3988 divider &= 0xf;
3989
3990 cur_cdclk = (vco << 1) / (divider + 1);
3991
3992 return cur_cdclk;
3993}
3994
3995static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv,
3996 int max_pixclk)
3997{
3998 int cur_cdclk;
3999
4000 cur_cdclk = valleyview_cur_cdclk(dev_priv);
4001
4002 /*
4003 * Really only a few cases to deal with, as only 4 CDclks are supported:
4004 * 200MHz
4005 * 267MHz
4006 * 320MHz
4007 * 400MHz
4008 * So we check to see whether we're above 90% of the lower bin and
4009 * adjust if needed.
4010 */
4011 if (max_pixclk > 288000) {
4012 return 400;
4013 } else if (max_pixclk > 240000) {
4014 return 320;
4015 } else
4016 return 266;
4017 /* Looks like the 200MHz CDclk freq doesn't work on some configs */
4018}
4019
4020static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv,
4021 unsigned modeset_pipes,
4022 struct intel_crtc_config *pipe_config)
4023{
4024 struct drm_device *dev = dev_priv->dev;
4025 struct intel_crtc *intel_crtc;
4026 int max_pixclk = 0;
4027
4028 list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
4029 base.head) {
4030 if (modeset_pipes & (1 << intel_crtc->pipe))
4031 max_pixclk = max(max_pixclk,
4032 pipe_config->adjusted_mode.crtc_clock);
4033 else if (intel_crtc->base.enabled)
4034 max_pixclk = max(max_pixclk,
4035 intel_crtc->config.adjusted_mode.crtc_clock);
4036 }
4037
4038 return max_pixclk;
4039}
4040
4041static void valleyview_modeset_global_pipes(struct drm_device *dev,
4042 unsigned *prepare_pipes,
4043 unsigned modeset_pipes,
4044 struct intel_crtc_config *pipe_config)
4045{
4046 struct drm_i915_private *dev_priv = dev->dev_private;
4047 struct intel_crtc *intel_crtc;
4048 int max_pixclk = intel_mode_max_pixclk(dev_priv, modeset_pipes,
4049 pipe_config);
4050 int cur_cdclk = valleyview_cur_cdclk(dev_priv);
4051
4052 if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk)
4053 return;
4054
4055 list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
4056 base.head)
4057 if (intel_crtc->base.enabled)
4058 *prepare_pipes |= (1 << intel_crtc->pipe);
4059}
4060
4061static void valleyview_modeset_global_resources(struct drm_device *dev)
4062{
4063 struct drm_i915_private *dev_priv = dev->dev_private;
4064 int max_pixclk = intel_mode_max_pixclk(dev_priv, 0, NULL);
4065 int cur_cdclk = valleyview_cur_cdclk(dev_priv);
4066 int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
4067
4068 if (req_cdclk != cur_cdclk)
4069 valleyview_set_cdclk(dev, req_cdclk);
4070}
4071
3897static void valleyview_crtc_enable(struct drm_crtc *crtc) 4072static void valleyview_crtc_enable(struct drm_crtc *crtc)
3898{ 4073{
3899 struct drm_device *dev = crtc->dev; 4074 struct drm_device *dev = crtc->dev;
@@ -9318,6 +9493,17 @@ static int __intel_set_mode(struct drm_crtc *crtc,
9318 "[modeset]"); 9493 "[modeset]");
9319 } 9494 }
9320 9495
9496 /*
9497 * See if the config requires any additional preparation, e.g.
9498 * to adjust global state with pipes off. We need to do this
9499 * here so we can get the modeset_pipe updated config for the new
9500 * mode set on this crtc. For other crtcs we need to use the
9501 * adjusted_mode bits in the crtc directly.
9502 */
9503 if (IS_VALLEYVIEW(dev))
9504 valleyview_modeset_global_pipes(dev, &prepare_pipes,
9505 modeset_pipes, pipe_config);
9506
9321 for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) 9507 for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
9322 intel_crtc_disable(&intel_crtc->base); 9508 intel_crtc_disable(&intel_crtc->base);
9323 9509
@@ -10317,6 +10503,9 @@ static void intel_init_display(struct drm_device *dev)
10317 } 10503 }
10318 } else if (IS_G4X(dev)) { 10504 } else if (IS_G4X(dev)) {
10319 dev_priv->display.write_eld = g4x_write_eld; 10505 dev_priv->display.write_eld = g4x_write_eld;
10506 } else if (IS_VALLEYVIEW(dev)) {
10507 dev_priv->display.modeset_global_resources =
10508 valleyview_modeset_global_resources;
10320 } 10509 }
10321 10510
10322 /* Default just returns -ENODEV to indicate unsupported */ 10511 /* 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)
87 87
88 BUG_ON(!IS_VALLEYVIEW(dev_priv->dev)); 88 BUG_ON(!IS_VALLEYVIEW(dev_priv->dev));
89 89
90 /* Skip setting the gmbus freq if BIOS has already programmed it */
91 if (I915_READ(GMBUSFREQ_VLV) != 0xA0)
92 return;
93
94 /* Obtain SKU information */ 90 /* Obtain SKU information */
95 mutex_lock(&dev_priv->dpio_lock); 91 mutex_lock(&dev_priv->dpio_lock);
96 hpll_freq = 92 hpll_freq =