diff options
author | Chon Ming Lee <chon.ming.lee@intel.com> | 2013-09-27 03:31:00 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-10-01 01:45:41 -0400 |
commit | 24eb2d599b6a2bf7761c00e1959898d1d9240cb5 (patch) | |
tree | aa1dde4aac8985152c7c588457f5148862b071e0 /drivers/gpu/drm | |
parent | afc85b9d9e617e602006d8766d04e0b8ac9c1b74 (diff) |
drm/i915: Program GMBUS Frequency based on the CDCLK for VLV.
CDCLK is used to generate the gmbus clock. This is normally done by
BIOS. Program the value if the BIOS-less system doesn't do it.
v2: Move this to intel_i2c_reset to allow reprogram the gmbus frequency
during resume. (Daniel)
v3: Change GMBUS_FREQ to GMBUSFREQ_VLV, and use VLV_DISPLAY_BASE.
(Ville).
Remove cdclk_ratio[] table, and calculate the cdclk ratio instead.
(Ville).
Change the shift then mask for reg read, to mask first, then shift.
(Ville).
Remove the gmbus frequency calculation = cdclk/1.01. Based on BIOS
programming, gmbus frequency = cdclk frequency. (Ville)
Add get_disp_clk_div, which can use to get cdclk/czclk divide.
v4: Fix the mmio_offset base for CZCLK_CDCLK_FREQ_RATIO, gmbus_freq
calculation, and duplicate check for gmbus_freq. (Ville)
In VLV, the spec is wrong about 4Mhz reference frequency for GMBUS. It
should be 1Mhz.
Signed-off-by: Chon Ming Lee <chon.ming.lee@intel.com>
[danvet: Add the comment Ville suggested. Also appease checkpatch a
bit.]
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_i2c.c | 64 |
2 files changed, 72 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 00fda45728d7..33bb4750516a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -382,6 +382,8 @@ | |||
382 | #define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000 | 382 | #define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000 |
383 | 383 | ||
384 | /* vlv2 north clock has */ | 384 | /* vlv2 north clock has */ |
385 | #define CCK_FUSE_REG 0x8 | ||
386 | #define CCK_FUSE_HPLL_FREQ_MASK 0x3 | ||
385 | #define CCK_REG_DSI_PLL_FUSE 0x44 | 387 | #define CCK_REG_DSI_PLL_FUSE 0x44 |
386 | #define CCK_REG_DSI_PLL_CONTROL 0x48 | 388 | #define CCK_REG_DSI_PLL_CONTROL 0x48 |
387 | #define DSI_PLL_VCO_EN (1 << 31) | 389 | #define DSI_PLL_VCO_EN (1 << 31) |
@@ -1429,6 +1431,12 @@ | |||
1429 | 1431 | ||
1430 | #define MI_ARB_VLV (VLV_DISPLAY_BASE + 0x6504) | 1432 | #define MI_ARB_VLV (VLV_DISPLAY_BASE + 0x6504) |
1431 | 1433 | ||
1434 | #define CZCLK_CDCLK_FREQ_RATIO (VLV_DISPLAY_BASE + 0x6508) | ||
1435 | #define CDCLK_FREQ_SHIFT 4 | ||
1436 | #define CDCLK_FREQ_MASK (0x1f << CDCLK_FREQ_SHIFT) | ||
1437 | #define CZCLK_FREQ_MASK 0xf | ||
1438 | #define GMBUSFREQ_VLV (VLV_DISPLAY_BASE + 0x6510) | ||
1439 | |||
1432 | /* | 1440 | /* |
1433 | * Palette regs | 1441 | * Palette regs |
1434 | */ | 1442 | */ |
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index d1c1e0f7f262..2ca17b14b6c1 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c | |||
@@ -34,6 +34,11 @@ | |||
34 | #include <drm/i915_drm.h> | 34 | #include <drm/i915_drm.h> |
35 | #include "i915_drv.h" | 35 | #include "i915_drv.h" |
36 | 36 | ||
37 | enum disp_clk { | ||
38 | CDCLK, | ||
39 | CZCLK | ||
40 | }; | ||
41 | |||
37 | struct gmbus_port { | 42 | struct gmbus_port { |
38 | const char *name; | 43 | const char *name; |
39 | int reg; | 44 | int reg; |
@@ -58,10 +63,69 @@ to_intel_gmbus(struct i2c_adapter *i2c) | |||
58 | return container_of(i2c, struct intel_gmbus, adapter); | 63 | return container_of(i2c, struct intel_gmbus, adapter); |
59 | } | 64 | } |
60 | 65 | ||
66 | static int get_disp_clk_div(struct drm_i915_private *dev_priv, | ||
67 | enum disp_clk clk) | ||
68 | { | ||
69 | u32 reg_val; | ||
70 | int clk_ratio; | ||
71 | |||
72 | reg_val = I915_READ(CZCLK_CDCLK_FREQ_RATIO); | ||
73 | |||
74 | if (clk == CDCLK) | ||
75 | clk_ratio = | ||
76 | ((reg_val & CDCLK_FREQ_MASK) >> CDCLK_FREQ_SHIFT) + 1; | ||
77 | else | ||
78 | clk_ratio = (reg_val & CZCLK_FREQ_MASK) + 1; | ||
79 | |||
80 | return clk_ratio; | ||
81 | } | ||
82 | |||
83 | static void gmbus_set_freq(struct drm_i915_private *dev_priv) | ||
84 | { | ||
85 | int vco_freq[] = { 800, 1600, 2000, 2400 }; | ||
86 | int gmbus_freq = 0, cdclk_div, hpll_freq; | ||
87 | |||
88 | BUG_ON(!IS_VALLEYVIEW(dev_priv->dev)); | ||
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 */ | ||
95 | mutex_lock(&dev_priv->dpio_lock); | ||
96 | hpll_freq = | ||
97 | vlv_cck_read(dev_priv, CCK_FUSE_REG) & CCK_FUSE_HPLL_FREQ_MASK; | ||
98 | mutex_unlock(&dev_priv->dpio_lock); | ||
99 | |||
100 | /* Get the CDCLK divide ratio */ | ||
101 | cdclk_div = get_disp_clk_div(dev_priv, CDCLK); | ||
102 | |||
103 | /* | ||
104 | * Program the gmbus_freq based on the cdclk frequency. | ||
105 | * BSpec erroneously claims we should aim for 4MHz, but | ||
106 | * in fact 1MHz is the correct frequency. | ||
107 | */ | ||
108 | if (cdclk_div) | ||
109 | gmbus_freq = (vco_freq[hpll_freq] << 1) / cdclk_div; | ||
110 | |||
111 | if (WARN_ON(gmbus_freq == 0)) | ||
112 | return; | ||
113 | |||
114 | I915_WRITE(GMBUSFREQ_VLV, gmbus_freq); | ||
115 | } | ||
116 | |||
61 | void | 117 | void |
62 | intel_i2c_reset(struct drm_device *dev) | 118 | intel_i2c_reset(struct drm_device *dev) |
63 | { | 119 | { |
64 | struct drm_i915_private *dev_priv = dev->dev_private; | 120 | struct drm_i915_private *dev_priv = dev->dev_private; |
121 | |||
122 | /* | ||
123 | * In BIOS-less system, program the correct gmbus frequency | ||
124 | * before reading edid. | ||
125 | */ | ||
126 | if (IS_VALLEYVIEW(dev)) | ||
127 | gmbus_set_freq(dev_priv); | ||
128 | |||
65 | I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0); | 129 | I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0); |
66 | I915_WRITE(dev_priv->gpio_mmio_base + GMBUS4, 0); | 130 | I915_WRITE(dev_priv->gpio_mmio_base + GMBUS4, 0); |
67 | } | 131 | } |