diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-08-22 08:18:16 -0400 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-09-08 05:23:58 -0400 |
commit | a95735569312f2ab0c80425e2cd1e5cb0b4e1870 (patch) | |
tree | 9daf28afa9b797b7f51486f4f759de9359b1e1e9 /drivers/gpu/drm/i915/intel_panel.c | |
parent | 5d607f9b038ea03f5e5b3064d2f3993f9ea67e1e (diff) |
drm/i915: Refactor panel backlight controls
There were two instances of code to control the panel backlight and
neither handled the complete set of device variations.
Fixes:
Bug 29716 - [GM965] Regression: Backlight resets to minimum when changing resolution
https://bugs.freedesktop.org/show_bug.cgi?id=29716
And a bug on one of my PineView boxes which overflowed the backlight
value.
Incorporates part of a similar patch by Matthew Garrett that exposes a
native Intel backlight controller.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_panel.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e7f5299d9d57..30abe7afc942 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
@@ -30,6 +30,8 @@ | |||
30 | 30 | ||
31 | #include "intel_drv.h" | 31 | #include "intel_drv.h" |
32 | 32 | ||
33 | #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ | ||
34 | |||
33 | void | 35 | void |
34 | intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, | 36 | intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, |
35 | struct drm_display_mode *adjusted_mode) | 37 | struct drm_display_mode *adjusted_mode) |
@@ -109,3 +111,110 @@ done: | |||
109 | dev_priv->pch_pf_pos = (x << 16) | y; | 111 | dev_priv->pch_pf_pos = (x << 16) | y; |
110 | dev_priv->pch_pf_size = (width << 16) | height; | 112 | dev_priv->pch_pf_size = (width << 16) | height; |
111 | } | 113 | } |
114 | |||
115 | static int is_backlight_combination_mode(struct drm_device *dev) | ||
116 | { | ||
117 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
118 | |||
119 | if (IS_I965G(dev)) | ||
120 | return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; | ||
121 | |||
122 | if (IS_GEN2(dev)) | ||
123 | return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | u32 intel_panel_get_max_backlight(struct drm_device *dev) | ||
129 | { | ||
130 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
131 | u32 max; | ||
132 | |||
133 | if (HAS_PCH_SPLIT(dev)) { | ||
134 | max = I915_READ(BLC_PWM_PCH_CTL2) >> 16; | ||
135 | } else { | ||
136 | max = I915_READ(BLC_PWM_CTL); | ||
137 | if (IS_PINEVIEW(dev)) { | ||
138 | max >>= 17; | ||
139 | } else { | ||
140 | max >>= 16; | ||
141 | if (!IS_I965G(dev)) | ||
142 | max &= ~1; | ||
143 | } | ||
144 | |||
145 | if (is_backlight_combination_mode(dev)) | ||
146 | max *= 0xff; | ||
147 | } | ||
148 | |||
149 | if (max == 0) { | ||
150 | /* XXX add code here to query mode clock or hardware clock | ||
151 | * and program max PWM appropriately. | ||
152 | */ | ||
153 | DRM_ERROR("fixme: max PWM is zero.\n"); | ||
154 | max = 1; | ||
155 | } | ||
156 | |||
157 | DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); | ||
158 | return max; | ||
159 | } | ||
160 | |||
161 | u32 intel_panel_get_backlight(struct drm_device *dev) | ||
162 | { | ||
163 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
164 | u32 val; | ||
165 | |||
166 | if (HAS_PCH_SPLIT(dev)) { | ||
167 | val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; | ||
168 | } else { | ||
169 | val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; | ||
170 | if (IS_PINEVIEW(dev)) | ||
171 | val >>= 1; | ||
172 | |||
173 | if (is_backlight_combination_mode(dev)){ | ||
174 | u8 lbpc; | ||
175 | |||
176 | val &= ~1; | ||
177 | pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); | ||
178 | val *= lbpc; | ||
179 | val >>= 1; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); | ||
184 | return val; | ||
185 | } | ||
186 | |||
187 | static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) | ||
188 | { | ||
189 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
190 | u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; | ||
191 | I915_WRITE(BLC_PWM_CPU_CTL, val | level); | ||
192 | } | ||
193 | |||
194 | void intel_panel_set_backlight(struct drm_device *dev, u32 level) | ||
195 | { | ||
196 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
197 | u32 tmp; | ||
198 | |||
199 | DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); | ||
200 | |||
201 | if (HAS_PCH_SPLIT(dev)) | ||
202 | return intel_pch_panel_set_backlight(dev, level); | ||
203 | |||
204 | if (is_backlight_combination_mode(dev)){ | ||
205 | u32 max = intel_panel_get_max_backlight(dev); | ||
206 | u8 lpbc; | ||
207 | |||
208 | lpbc = level * 0xfe / max + 1; | ||
209 | level /= lpbc; | ||
210 | pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc); | ||
211 | } | ||
212 | |||
213 | tmp = I915_READ(BLC_PWM_CTL); | ||
214 | if (IS_PINEVIEW(dev)) { | ||
215 | tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1); | ||
216 | level <<= 1; | ||
217 | } else | ||
218 | tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; | ||
219 | I915_WRITE(BLC_PWM_CTL, tmp | level); | ||
220 | } | ||