diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_panel.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 346 |
1 files changed, 233 insertions, 113 deletions
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 293564a2896a..f161ac02c4f6 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
@@ -50,23 +50,22 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc, | |||
50 | struct intel_crtc_config *pipe_config, | 50 | struct intel_crtc_config *pipe_config, |
51 | int fitting_mode) | 51 | int fitting_mode) |
52 | { | 52 | { |
53 | struct drm_display_mode *mode, *adjusted_mode; | 53 | struct drm_display_mode *adjusted_mode; |
54 | int x, y, width, height; | 54 | int x, y, width, height; |
55 | 55 | ||
56 | mode = &pipe_config->requested_mode; | ||
57 | adjusted_mode = &pipe_config->adjusted_mode; | 56 | adjusted_mode = &pipe_config->adjusted_mode; |
58 | 57 | ||
59 | x = y = width = height = 0; | 58 | x = y = width = height = 0; |
60 | 59 | ||
61 | /* Native modes don't need fitting */ | 60 | /* Native modes don't need fitting */ |
62 | if (adjusted_mode->hdisplay == mode->hdisplay && | 61 | if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && |
63 | adjusted_mode->vdisplay == mode->vdisplay) | 62 | adjusted_mode->vdisplay == pipe_config->pipe_src_h) |
64 | goto done; | 63 | goto done; |
65 | 64 | ||
66 | switch (fitting_mode) { | 65 | switch (fitting_mode) { |
67 | case DRM_MODE_SCALE_CENTER: | 66 | case DRM_MODE_SCALE_CENTER: |
68 | width = mode->hdisplay; | 67 | width = pipe_config->pipe_src_w; |
69 | height = mode->vdisplay; | 68 | height = pipe_config->pipe_src_h; |
70 | x = (adjusted_mode->hdisplay - width + 1)/2; | 69 | x = (adjusted_mode->hdisplay - width + 1)/2; |
71 | y = (adjusted_mode->vdisplay - height + 1)/2; | 70 | y = (adjusted_mode->vdisplay - height + 1)/2; |
72 | break; | 71 | break; |
@@ -74,17 +73,19 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc, | |||
74 | case DRM_MODE_SCALE_ASPECT: | 73 | case DRM_MODE_SCALE_ASPECT: |
75 | /* Scale but preserve the aspect ratio */ | 74 | /* Scale but preserve the aspect ratio */ |
76 | { | 75 | { |
77 | u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; | 76 | u32 scaled_width = adjusted_mode->hdisplay |
78 | u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; | 77 | * pipe_config->pipe_src_h; |
78 | u32 scaled_height = pipe_config->pipe_src_w | ||
79 | * adjusted_mode->vdisplay; | ||
79 | if (scaled_width > scaled_height) { /* pillar */ | 80 | if (scaled_width > scaled_height) { /* pillar */ |
80 | width = scaled_height / mode->vdisplay; | 81 | width = scaled_height / pipe_config->pipe_src_h; |
81 | if (width & 1) | 82 | if (width & 1) |
82 | width++; | 83 | width++; |
83 | x = (adjusted_mode->hdisplay - width + 1) / 2; | 84 | x = (adjusted_mode->hdisplay - width + 1) / 2; |
84 | y = 0; | 85 | y = 0; |
85 | height = adjusted_mode->vdisplay; | 86 | height = adjusted_mode->vdisplay; |
86 | } else if (scaled_width < scaled_height) { /* letter */ | 87 | } else if (scaled_width < scaled_height) { /* letter */ |
87 | height = scaled_width / mode->hdisplay; | 88 | height = scaled_width / pipe_config->pipe_src_w; |
88 | if (height & 1) | 89 | if (height & 1) |
89 | height++; | 90 | height++; |
90 | y = (adjusted_mode->vdisplay - height + 1) / 2; | 91 | y = (adjusted_mode->vdisplay - height + 1) / 2; |
@@ -171,20 +172,96 @@ static inline u32 panel_fitter_scaling(u32 source, u32 target) | |||
171 | return (FACTOR * ratio + FACTOR/2) / FACTOR; | 172 | return (FACTOR * ratio + FACTOR/2) / FACTOR; |
172 | } | 173 | } |
173 | 174 | ||
175 | static void i965_scale_aspect(struct intel_crtc_config *pipe_config, | ||
176 | u32 *pfit_control) | ||
177 | { | ||
178 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | ||
179 | u32 scaled_width = adjusted_mode->hdisplay * | ||
180 | pipe_config->pipe_src_h; | ||
181 | u32 scaled_height = pipe_config->pipe_src_w * | ||
182 | adjusted_mode->vdisplay; | ||
183 | |||
184 | /* 965+ is easy, it does everything in hw */ | ||
185 | if (scaled_width > scaled_height) | ||
186 | *pfit_control |= PFIT_ENABLE | | ||
187 | PFIT_SCALING_PILLAR; | ||
188 | else if (scaled_width < scaled_height) | ||
189 | *pfit_control |= PFIT_ENABLE | | ||
190 | PFIT_SCALING_LETTER; | ||
191 | else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w) | ||
192 | *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; | ||
193 | } | ||
194 | |||
195 | static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config, | ||
196 | u32 *pfit_control, u32 *pfit_pgm_ratios, | ||
197 | u32 *border) | ||
198 | { | ||
199 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | ||
200 | u32 scaled_width = adjusted_mode->hdisplay * | ||
201 | pipe_config->pipe_src_h; | ||
202 | u32 scaled_height = pipe_config->pipe_src_w * | ||
203 | adjusted_mode->vdisplay; | ||
204 | u32 bits; | ||
205 | |||
206 | /* | ||
207 | * For earlier chips we have to calculate the scaling | ||
208 | * ratio by hand and program it into the | ||
209 | * PFIT_PGM_RATIO register | ||
210 | */ | ||
211 | if (scaled_width > scaled_height) { /* pillar */ | ||
212 | centre_horizontally(adjusted_mode, | ||
213 | scaled_height / | ||
214 | pipe_config->pipe_src_h); | ||
215 | |||
216 | *border = LVDS_BORDER_ENABLE; | ||
217 | if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) { | ||
218 | bits = panel_fitter_scaling(pipe_config->pipe_src_h, | ||
219 | adjusted_mode->vdisplay); | ||
220 | |||
221 | *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | | ||
222 | bits << PFIT_VERT_SCALE_SHIFT); | ||
223 | *pfit_control |= (PFIT_ENABLE | | ||
224 | VERT_INTERP_BILINEAR | | ||
225 | HORIZ_INTERP_BILINEAR); | ||
226 | } | ||
227 | } else if (scaled_width < scaled_height) { /* letter */ | ||
228 | centre_vertically(adjusted_mode, | ||
229 | scaled_width / | ||
230 | pipe_config->pipe_src_w); | ||
231 | |||
232 | *border = LVDS_BORDER_ENABLE; | ||
233 | if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) { | ||
234 | bits = panel_fitter_scaling(pipe_config->pipe_src_w, | ||
235 | adjusted_mode->hdisplay); | ||
236 | |||
237 | *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | | ||
238 | bits << PFIT_VERT_SCALE_SHIFT); | ||
239 | *pfit_control |= (PFIT_ENABLE | | ||
240 | VERT_INTERP_BILINEAR | | ||
241 | HORIZ_INTERP_BILINEAR); | ||
242 | } | ||
243 | } else { | ||
244 | /* Aspects match, Let hw scale both directions */ | ||
245 | *pfit_control |= (PFIT_ENABLE | | ||
246 | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | | ||
247 | VERT_INTERP_BILINEAR | | ||
248 | HORIZ_INTERP_BILINEAR); | ||
249 | } | ||
250 | } | ||
251 | |||
174 | void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, | 252 | void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, |
175 | struct intel_crtc_config *pipe_config, | 253 | struct intel_crtc_config *pipe_config, |
176 | int fitting_mode) | 254 | int fitting_mode) |
177 | { | 255 | { |
178 | struct drm_device *dev = intel_crtc->base.dev; | 256 | struct drm_device *dev = intel_crtc->base.dev; |
179 | u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; | 257 | u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; |
180 | struct drm_display_mode *mode, *adjusted_mode; | 258 | struct drm_display_mode *adjusted_mode; |
181 | 259 | ||
182 | mode = &pipe_config->requested_mode; | ||
183 | adjusted_mode = &pipe_config->adjusted_mode; | 260 | adjusted_mode = &pipe_config->adjusted_mode; |
184 | 261 | ||
185 | /* Native modes don't need fitting */ | 262 | /* Native modes don't need fitting */ |
186 | if (adjusted_mode->hdisplay == mode->hdisplay && | 263 | if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && |
187 | adjusted_mode->vdisplay == mode->vdisplay) | 264 | adjusted_mode->vdisplay == pipe_config->pipe_src_h) |
188 | goto out; | 265 | goto out; |
189 | 266 | ||
190 | switch (fitting_mode) { | 267 | switch (fitting_mode) { |
@@ -193,81 +270,25 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, | |||
193 | * For centered modes, we have to calculate border widths & | 270 | * For centered modes, we have to calculate border widths & |
194 | * heights and modify the values programmed into the CRTC. | 271 | * heights and modify the values programmed into the CRTC. |
195 | */ | 272 | */ |
196 | centre_horizontally(adjusted_mode, mode->hdisplay); | 273 | centre_horizontally(adjusted_mode, pipe_config->pipe_src_w); |
197 | centre_vertically(adjusted_mode, mode->vdisplay); | 274 | centre_vertically(adjusted_mode, pipe_config->pipe_src_h); |
198 | border = LVDS_BORDER_ENABLE; | 275 | border = LVDS_BORDER_ENABLE; |
199 | break; | 276 | break; |
200 | case DRM_MODE_SCALE_ASPECT: | 277 | case DRM_MODE_SCALE_ASPECT: |
201 | /* Scale but preserve the aspect ratio */ | 278 | /* Scale but preserve the aspect ratio */ |
202 | if (INTEL_INFO(dev)->gen >= 4) { | 279 | if (INTEL_INFO(dev)->gen >= 4) |
203 | u32 scaled_width = adjusted_mode->hdisplay * | 280 | i965_scale_aspect(pipe_config, &pfit_control); |
204 | mode->vdisplay; | 281 | else |
205 | u32 scaled_height = mode->hdisplay * | 282 | i9xx_scale_aspect(pipe_config, &pfit_control, |
206 | adjusted_mode->vdisplay; | 283 | &pfit_pgm_ratios, &border); |
207 | |||
208 | /* 965+ is easy, it does everything in hw */ | ||
209 | if (scaled_width > scaled_height) | ||
210 | pfit_control |= PFIT_ENABLE | | ||
211 | PFIT_SCALING_PILLAR; | ||
212 | else if (scaled_width < scaled_height) | ||
213 | pfit_control |= PFIT_ENABLE | | ||
214 | PFIT_SCALING_LETTER; | ||
215 | else if (adjusted_mode->hdisplay != mode->hdisplay) | ||
216 | pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; | ||
217 | } else { | ||
218 | u32 scaled_width = adjusted_mode->hdisplay * | ||
219 | mode->vdisplay; | ||
220 | u32 scaled_height = mode->hdisplay * | ||
221 | adjusted_mode->vdisplay; | ||
222 | /* | ||
223 | * For earlier chips we have to calculate the scaling | ||
224 | * ratio by hand and program it into the | ||
225 | * PFIT_PGM_RATIO register | ||
226 | */ | ||
227 | if (scaled_width > scaled_height) { /* pillar */ | ||
228 | centre_horizontally(adjusted_mode, | ||
229 | scaled_height / | ||
230 | mode->vdisplay); | ||
231 | |||
232 | border = LVDS_BORDER_ENABLE; | ||
233 | if (mode->vdisplay != adjusted_mode->vdisplay) { | ||
234 | u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); | ||
235 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | | ||
236 | bits << PFIT_VERT_SCALE_SHIFT); | ||
237 | pfit_control |= (PFIT_ENABLE | | ||
238 | VERT_INTERP_BILINEAR | | ||
239 | HORIZ_INTERP_BILINEAR); | ||
240 | } | ||
241 | } else if (scaled_width < scaled_height) { /* letter */ | ||
242 | centre_vertically(adjusted_mode, | ||
243 | scaled_width / | ||
244 | mode->hdisplay); | ||
245 | |||
246 | border = LVDS_BORDER_ENABLE; | ||
247 | if (mode->hdisplay != adjusted_mode->hdisplay) { | ||
248 | u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); | ||
249 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | | ||
250 | bits << PFIT_VERT_SCALE_SHIFT); | ||
251 | pfit_control |= (PFIT_ENABLE | | ||
252 | VERT_INTERP_BILINEAR | | ||
253 | HORIZ_INTERP_BILINEAR); | ||
254 | } | ||
255 | } else { | ||
256 | /* Aspects match, Let hw scale both directions */ | ||
257 | pfit_control |= (PFIT_ENABLE | | ||
258 | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | | ||
259 | VERT_INTERP_BILINEAR | | ||
260 | HORIZ_INTERP_BILINEAR); | ||
261 | } | ||
262 | } | ||
263 | break; | 284 | break; |
264 | case DRM_MODE_SCALE_FULLSCREEN: | 285 | case DRM_MODE_SCALE_FULLSCREEN: |
265 | /* | 286 | /* |
266 | * Full scaling, even if it changes the aspect ratio. | 287 | * Full scaling, even if it changes the aspect ratio. |
267 | * Fortunately this is all done for us in hw. | 288 | * Fortunately this is all done for us in hw. |
268 | */ | 289 | */ |
269 | if (mode->vdisplay != adjusted_mode->vdisplay || | 290 | if (pipe_config->pipe_src_h != adjusted_mode->vdisplay || |
270 | mode->hdisplay != adjusted_mode->hdisplay) { | 291 | pipe_config->pipe_src_w != adjusted_mode->hdisplay) { |
271 | pfit_control |= PFIT_ENABLE; | 292 | pfit_control |= PFIT_ENABLE; |
272 | if (INTEL_INFO(dev)->gen >= 4) | 293 | if (INTEL_INFO(dev)->gen >= 4) |
273 | pfit_control |= PFIT_SCALING_AUTO; | 294 | pfit_control |= PFIT_SCALING_AUTO; |
@@ -308,7 +329,7 @@ static int is_backlight_combination_mode(struct drm_device *dev) | |||
308 | { | 329 | { |
309 | struct drm_i915_private *dev_priv = dev->dev_private; | 330 | struct drm_i915_private *dev_priv = dev->dev_private; |
310 | 331 | ||
311 | if (INTEL_INFO(dev)->gen >= 4) | 332 | if (IS_GEN4(dev)) |
312 | return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; | 333 | return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; |
313 | 334 | ||
314 | if (IS_GEN2(dev)) | 335 | if (IS_GEN2(dev)) |
@@ -320,7 +341,7 @@ static int is_backlight_combination_mode(struct drm_device *dev) | |||
320 | /* XXX: query mode clock or hardware clock and program max PWM appropriately | 341 | /* XXX: query mode clock or hardware clock and program max PWM appropriately |
321 | * when it's 0. | 342 | * when it's 0. |
322 | */ | 343 | */ |
323 | static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) | 344 | static u32 i915_read_blc_pwm_ctl(struct drm_device *dev, enum pipe pipe) |
324 | { | 345 | { |
325 | struct drm_i915_private *dev_priv = dev->dev_private; | 346 | struct drm_i915_private *dev_priv = dev->dev_private; |
326 | u32 val; | 347 | u32 val; |
@@ -337,6 +358,21 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) | |||
337 | val = dev_priv->regfile.saveBLC_PWM_CTL2; | 358 | val = dev_priv->regfile.saveBLC_PWM_CTL2; |
338 | I915_WRITE(BLC_PWM_PCH_CTL2, val); | 359 | I915_WRITE(BLC_PWM_PCH_CTL2, val); |
339 | } | 360 | } |
361 | } else if (IS_VALLEYVIEW(dev)) { | ||
362 | val = I915_READ(VLV_BLC_PWM_CTL(pipe)); | ||
363 | if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { | ||
364 | dev_priv->regfile.saveBLC_PWM_CTL = val; | ||
365 | dev_priv->regfile.saveBLC_PWM_CTL2 = | ||
366 | I915_READ(VLV_BLC_PWM_CTL2(pipe)); | ||
367 | } else if (val == 0) { | ||
368 | val = dev_priv->regfile.saveBLC_PWM_CTL; | ||
369 | I915_WRITE(VLV_BLC_PWM_CTL(pipe), val); | ||
370 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), | ||
371 | dev_priv->regfile.saveBLC_PWM_CTL2); | ||
372 | } | ||
373 | |||
374 | if (!val) | ||
375 | val = 0x0f42ffff; | ||
340 | } else { | 376 | } else { |
341 | val = I915_READ(BLC_PWM_CTL); | 377 | val = I915_READ(BLC_PWM_CTL); |
342 | if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { | 378 | if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { |
@@ -356,11 +392,12 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) | |||
356 | return val; | 392 | return val; |
357 | } | 393 | } |
358 | 394 | ||
359 | static u32 intel_panel_get_max_backlight(struct drm_device *dev) | 395 | static u32 intel_panel_get_max_backlight(struct drm_device *dev, |
396 | enum pipe pipe) | ||
360 | { | 397 | { |
361 | u32 max; | 398 | u32 max; |
362 | 399 | ||
363 | max = i915_read_blc_pwm_ctl(dev); | 400 | max = i915_read_blc_pwm_ctl(dev, pipe); |
364 | 401 | ||
365 | if (HAS_PCH_SPLIT(dev)) { | 402 | if (HAS_PCH_SPLIT(dev)) { |
366 | max >>= 16; | 403 | max >>= 16; |
@@ -386,7 +423,8 @@ MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " | |||
386 | "to dri-devel@lists.freedesktop.org, if your machine needs it. " | 423 | "to dri-devel@lists.freedesktop.org, if your machine needs it. " |
387 | "It will then be included in an upcoming module version."); | 424 | "It will then be included in an upcoming module version."); |
388 | module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); | 425 | module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); |
389 | static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) | 426 | static u32 intel_panel_compute_brightness(struct drm_device *dev, |
427 | enum pipe pipe, u32 val) | ||
390 | { | 428 | { |
391 | struct drm_i915_private *dev_priv = dev->dev_private; | 429 | struct drm_i915_private *dev_priv = dev->dev_private; |
392 | 430 | ||
@@ -395,7 +433,7 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) | |||
395 | 433 | ||
396 | if (i915_panel_invert_brightness > 0 || | 434 | if (i915_panel_invert_brightness > 0 || |
397 | dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { | 435 | dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { |
398 | u32 max = intel_panel_get_max_backlight(dev); | 436 | u32 max = intel_panel_get_max_backlight(dev, pipe); |
399 | if (max) | 437 | if (max) |
400 | return max - val; | 438 | return max - val; |
401 | } | 439 | } |
@@ -403,18 +441,25 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) | |||
403 | return val; | 441 | return val; |
404 | } | 442 | } |
405 | 443 | ||
406 | static u32 intel_panel_get_backlight(struct drm_device *dev) | 444 | static u32 intel_panel_get_backlight(struct drm_device *dev, |
445 | enum pipe pipe) | ||
407 | { | 446 | { |
408 | struct drm_i915_private *dev_priv = dev->dev_private; | 447 | struct drm_i915_private *dev_priv = dev->dev_private; |
409 | u32 val; | 448 | u32 val; |
410 | unsigned long flags; | 449 | unsigned long flags; |
450 | int reg; | ||
411 | 451 | ||
412 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | 452 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
413 | 453 | ||
414 | if (HAS_PCH_SPLIT(dev)) { | 454 | if (HAS_PCH_SPLIT(dev)) { |
415 | val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; | 455 | val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
416 | } else { | 456 | } else { |
417 | val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; | 457 | if (IS_VALLEYVIEW(dev)) |
458 | reg = VLV_BLC_PWM_CTL(pipe); | ||
459 | else | ||
460 | reg = BLC_PWM_CTL; | ||
461 | |||
462 | val = I915_READ(reg) & BACKLIGHT_DUTY_CYCLE_MASK; | ||
418 | if (INTEL_INFO(dev)->gen < 4) | 463 | if (INTEL_INFO(dev)->gen < 4) |
419 | val >>= 1; | 464 | val >>= 1; |
420 | 465 | ||
@@ -426,7 +471,7 @@ static u32 intel_panel_get_backlight(struct drm_device *dev) | |||
426 | } | 471 | } |
427 | } | 472 | } |
428 | 473 | ||
429 | val = intel_panel_compute_brightness(dev, val); | 474 | val = intel_panel_compute_brightness(dev, pipe, val); |
430 | 475 | ||
431 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | 476 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
432 | 477 | ||
@@ -441,19 +486,21 @@ static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) | |||
441 | I915_WRITE(BLC_PWM_CPU_CTL, val | level); | 486 | I915_WRITE(BLC_PWM_CPU_CTL, val | level); |
442 | } | 487 | } |
443 | 488 | ||
444 | static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level) | 489 | static void intel_panel_actually_set_backlight(struct drm_device *dev, |
490 | enum pipe pipe, u32 level) | ||
445 | { | 491 | { |
446 | struct drm_i915_private *dev_priv = dev->dev_private; | 492 | struct drm_i915_private *dev_priv = dev->dev_private; |
447 | u32 tmp; | 493 | u32 tmp; |
494 | int reg; | ||
448 | 495 | ||
449 | DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); | 496 | DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); |
450 | level = intel_panel_compute_brightness(dev, level); | 497 | level = intel_panel_compute_brightness(dev, pipe, level); |
451 | 498 | ||
452 | if (HAS_PCH_SPLIT(dev)) | 499 | if (HAS_PCH_SPLIT(dev)) |
453 | return intel_pch_panel_set_backlight(dev, level); | 500 | return intel_pch_panel_set_backlight(dev, level); |
454 | 501 | ||
455 | if (is_backlight_combination_mode(dev)) { | 502 | if (is_backlight_combination_mode(dev)) { |
456 | u32 max = intel_panel_get_max_backlight(dev); | 503 | u32 max = intel_panel_get_max_backlight(dev, pipe); |
457 | u8 lbpc; | 504 | u8 lbpc; |
458 | 505 | ||
459 | /* we're screwed, but keep behaviour backwards compatible */ | 506 | /* we're screwed, but keep behaviour backwards compatible */ |
@@ -465,23 +512,34 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level | |||
465 | pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); | 512 | pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); |
466 | } | 513 | } |
467 | 514 | ||
468 | tmp = I915_READ(BLC_PWM_CTL); | 515 | if (IS_VALLEYVIEW(dev)) |
516 | reg = VLV_BLC_PWM_CTL(pipe); | ||
517 | else | ||
518 | reg = BLC_PWM_CTL; | ||
519 | |||
520 | tmp = I915_READ(reg); | ||
469 | if (INTEL_INFO(dev)->gen < 4) | 521 | if (INTEL_INFO(dev)->gen < 4) |
470 | level <<= 1; | 522 | level <<= 1; |
471 | tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; | 523 | tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; |
472 | I915_WRITE(BLC_PWM_CTL, tmp | level); | 524 | I915_WRITE(reg, tmp | level); |
473 | } | 525 | } |
474 | 526 | ||
475 | /* set backlight brightness to level in range [0..max] */ | 527 | /* set backlight brightness to level in range [0..max] */ |
476 | void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) | 528 | void intel_panel_set_backlight(struct intel_connector *connector, u32 level, |
529 | u32 max) | ||
477 | { | 530 | { |
531 | struct drm_device *dev = connector->base.dev; | ||
478 | struct drm_i915_private *dev_priv = dev->dev_private; | 532 | struct drm_i915_private *dev_priv = dev->dev_private; |
533 | enum pipe pipe = intel_get_pipe_from_connector(connector); | ||
479 | u32 freq; | 534 | u32 freq; |
480 | unsigned long flags; | 535 | unsigned long flags; |
481 | 536 | ||
537 | if (pipe == INVALID_PIPE) | ||
538 | return; | ||
539 | |||
482 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | 540 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
483 | 541 | ||
484 | freq = intel_panel_get_max_backlight(dev); | 542 | freq = intel_panel_get_max_backlight(dev, pipe); |
485 | if (!freq) { | 543 | if (!freq) { |
486 | /* we are screwed, bail out */ | 544 | /* we are screwed, bail out */ |
487 | goto out; | 545 | goto out; |
@@ -498,16 +556,21 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) | |||
498 | dev_priv->backlight.device->props.brightness = level; | 556 | dev_priv->backlight.device->props.brightness = level; |
499 | 557 | ||
500 | if (dev_priv->backlight.enabled) | 558 | if (dev_priv->backlight.enabled) |
501 | intel_panel_actually_set_backlight(dev, level); | 559 | intel_panel_actually_set_backlight(dev, pipe, level); |
502 | out: | 560 | out: |
503 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | 561 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
504 | } | 562 | } |
505 | 563 | ||
506 | void intel_panel_disable_backlight(struct drm_device *dev) | 564 | void intel_panel_disable_backlight(struct intel_connector *connector) |
507 | { | 565 | { |
566 | struct drm_device *dev = connector->base.dev; | ||
508 | struct drm_i915_private *dev_priv = dev->dev_private; | 567 | struct drm_i915_private *dev_priv = dev->dev_private; |
568 | enum pipe pipe = intel_get_pipe_from_connector(connector); | ||
509 | unsigned long flags; | 569 | unsigned long flags; |
510 | 570 | ||
571 | if (pipe == INVALID_PIPE) | ||
572 | return; | ||
573 | |||
511 | /* | 574 | /* |
512 | * Do not disable backlight on the vgaswitcheroo path. When switching | 575 | * Do not disable backlight on the vgaswitcheroo path. When switching |
513 | * away from i915, the other client may depend on i915 to handle the | 576 | * away from i915, the other client may depend on i915 to handle the |
@@ -522,12 +585,17 @@ void intel_panel_disable_backlight(struct drm_device *dev) | |||
522 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | 585 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
523 | 586 | ||
524 | dev_priv->backlight.enabled = false; | 587 | dev_priv->backlight.enabled = false; |
525 | intel_panel_actually_set_backlight(dev, 0); | 588 | intel_panel_actually_set_backlight(dev, pipe, 0); |
526 | 589 | ||
527 | if (INTEL_INFO(dev)->gen >= 4) { | 590 | if (INTEL_INFO(dev)->gen >= 4) { |
528 | uint32_t reg, tmp; | 591 | uint32_t reg, tmp; |
529 | 592 | ||
530 | reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2; | 593 | if (HAS_PCH_SPLIT(dev)) |
594 | reg = BLC_PWM_CPU_CTL2; | ||
595 | else if (IS_VALLEYVIEW(dev)) | ||
596 | reg = VLV_BLC_PWM_CTL2(pipe); | ||
597 | else | ||
598 | reg = BLC_PWM_CTL2; | ||
531 | 599 | ||
532 | I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE); | 600 | I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE); |
533 | 601 | ||
@@ -541,18 +609,25 @@ void intel_panel_disable_backlight(struct drm_device *dev) | |||
541 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | 609 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
542 | } | 610 | } |
543 | 611 | ||
544 | void intel_panel_enable_backlight(struct drm_device *dev, | 612 | void intel_panel_enable_backlight(struct intel_connector *connector) |
545 | enum pipe pipe) | ||
546 | { | 613 | { |
614 | struct drm_device *dev = connector->base.dev; | ||
547 | struct drm_i915_private *dev_priv = dev->dev_private; | 615 | struct drm_i915_private *dev_priv = dev->dev_private; |
616 | enum pipe pipe = intel_get_pipe_from_connector(connector); | ||
548 | enum transcoder cpu_transcoder = | 617 | enum transcoder cpu_transcoder = |
549 | intel_pipe_to_cpu_transcoder(dev_priv, pipe); | 618 | intel_pipe_to_cpu_transcoder(dev_priv, pipe); |
550 | unsigned long flags; | 619 | unsigned long flags; |
551 | 620 | ||
621 | if (pipe == INVALID_PIPE) | ||
622 | return; | ||
623 | |||
624 | DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); | ||
625 | |||
552 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | 626 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
553 | 627 | ||
554 | if (dev_priv->backlight.level == 0) { | 628 | if (dev_priv->backlight.level == 0) { |
555 | dev_priv->backlight.level = intel_panel_get_max_backlight(dev); | 629 | dev_priv->backlight.level = intel_panel_get_max_backlight(dev, |
630 | pipe); | ||
556 | if (dev_priv->backlight.device) | 631 | if (dev_priv->backlight.device) |
557 | dev_priv->backlight.device->props.brightness = | 632 | dev_priv->backlight.device->props.brightness = |
558 | dev_priv->backlight.level; | 633 | dev_priv->backlight.level; |
@@ -561,8 +636,12 @@ void intel_panel_enable_backlight(struct drm_device *dev, | |||
561 | if (INTEL_INFO(dev)->gen >= 4) { | 636 | if (INTEL_INFO(dev)->gen >= 4) { |
562 | uint32_t reg, tmp; | 637 | uint32_t reg, tmp; |
563 | 638 | ||
564 | reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2; | 639 | if (HAS_PCH_SPLIT(dev)) |
565 | 640 | reg = BLC_PWM_CPU_CTL2; | |
641 | else if (IS_VALLEYVIEW(dev)) | ||
642 | reg = VLV_BLC_PWM_CTL2(pipe); | ||
643 | else | ||
644 | reg = BLC_PWM_CTL2; | ||
566 | 645 | ||
567 | tmp = I915_READ(reg); | 646 | tmp = I915_READ(reg); |
568 | 647 | ||
@@ -602,16 +681,41 @@ set_level: | |||
602 | * registers are set. | 681 | * registers are set. |
603 | */ | 682 | */ |
604 | dev_priv->backlight.enabled = true; | 683 | dev_priv->backlight.enabled = true; |
605 | intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); | 684 | intel_panel_actually_set_backlight(dev, pipe, |
685 | dev_priv->backlight.level); | ||
606 | 686 | ||
607 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | 687 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
608 | } | 688 | } |
609 | 689 | ||
690 | /* FIXME: use VBT vals to init PWM_CTL and PWM_CTL2 correctly */ | ||
691 | static void intel_panel_init_backlight_regs(struct drm_device *dev) | ||
692 | { | ||
693 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
694 | |||
695 | if (IS_VALLEYVIEW(dev)) { | ||
696 | enum pipe pipe; | ||
697 | |||
698 | for_each_pipe(pipe) { | ||
699 | u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe)); | ||
700 | |||
701 | /* Skip if the modulation freq is already set */ | ||
702 | if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK) | ||
703 | continue; | ||
704 | |||
705 | cur_val &= BACKLIGHT_DUTY_CYCLE_MASK; | ||
706 | I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) | | ||
707 | cur_val); | ||
708 | } | ||
709 | } | ||
710 | } | ||
711 | |||
610 | static void intel_panel_init_backlight(struct drm_device *dev) | 712 | static void intel_panel_init_backlight(struct drm_device *dev) |
611 | { | 713 | { |
612 | struct drm_i915_private *dev_priv = dev->dev_private; | 714 | struct drm_i915_private *dev_priv = dev->dev_private; |
613 | 715 | ||
614 | dev_priv->backlight.level = intel_panel_get_backlight(dev); | 716 | intel_panel_init_backlight_regs(dev); |
717 | |||
718 | dev_priv->backlight.level = intel_panel_get_backlight(dev, 0); | ||
615 | dev_priv->backlight.enabled = dev_priv->backlight.level != 0; | 719 | dev_priv->backlight.enabled = dev_priv->backlight.level != 0; |
616 | } | 720 | } |
617 | 721 | ||
@@ -637,19 +741,34 @@ intel_panel_detect(struct drm_device *dev) | |||
637 | } | 741 | } |
638 | } | 742 | } |
639 | 743 | ||
640 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | 744 | #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) |
641 | static int intel_panel_update_status(struct backlight_device *bd) | 745 | static int intel_panel_update_status(struct backlight_device *bd) |
642 | { | 746 | { |
643 | struct drm_device *dev = bl_get_data(bd); | 747 | struct intel_connector *connector = bl_get_data(bd); |
644 | intel_panel_set_backlight(dev, bd->props.brightness, | 748 | struct drm_device *dev = connector->base.dev; |
749 | |||
750 | mutex_lock(&dev->mode_config.mutex); | ||
751 | DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", | ||
752 | bd->props.brightness, bd->props.max_brightness); | ||
753 | intel_panel_set_backlight(connector, bd->props.brightness, | ||
645 | bd->props.max_brightness); | 754 | bd->props.max_brightness); |
755 | mutex_unlock(&dev->mode_config.mutex); | ||
646 | return 0; | 756 | return 0; |
647 | } | 757 | } |
648 | 758 | ||
649 | static int intel_panel_get_brightness(struct backlight_device *bd) | 759 | static int intel_panel_get_brightness(struct backlight_device *bd) |
650 | { | 760 | { |
651 | struct drm_device *dev = bl_get_data(bd); | 761 | struct intel_connector *connector = bl_get_data(bd); |
652 | return intel_panel_get_backlight(dev); | 762 | struct drm_device *dev = connector->base.dev; |
763 | enum pipe pipe; | ||
764 | |||
765 | mutex_lock(&dev->mode_config.mutex); | ||
766 | pipe = intel_get_pipe_from_connector(connector); | ||
767 | mutex_unlock(&dev->mode_config.mutex); | ||
768 | if (pipe == INVALID_PIPE) | ||
769 | return 0; | ||
770 | |||
771 | return intel_panel_get_backlight(connector->base.dev, pipe); | ||
653 | } | 772 | } |
654 | 773 | ||
655 | static const struct backlight_ops intel_panel_bl_ops = { | 774 | static const struct backlight_ops intel_panel_bl_ops = { |
@@ -674,7 +793,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector) | |||
674 | props.brightness = dev_priv->backlight.level; | 793 | props.brightness = dev_priv->backlight.level; |
675 | 794 | ||
676 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | 795 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
677 | props.max_brightness = intel_panel_get_max_backlight(dev); | 796 | props.max_brightness = intel_panel_get_max_backlight(dev, 0); |
678 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | 797 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
679 | 798 | ||
680 | if (props.max_brightness == 0) { | 799 | if (props.max_brightness == 0) { |
@@ -683,7 +802,8 @@ int intel_panel_setup_backlight(struct drm_connector *connector) | |||
683 | } | 802 | } |
684 | dev_priv->backlight.device = | 803 | dev_priv->backlight.device = |
685 | backlight_device_register("intel_backlight", | 804 | backlight_device_register("intel_backlight", |
686 | &connector->kdev, dev, | 805 | connector->kdev, |
806 | to_intel_connector(connector), | ||
687 | &intel_panel_bl_ops, &props); | 807 | &intel_panel_bl_ops, &props); |
688 | 808 | ||
689 | if (IS_ERR(dev_priv->backlight.device)) { | 809 | if (IS_ERR(dev_priv->backlight.device)) { |