diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_panel.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 207 |
1 files changed, 125 insertions, 82 deletions
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 293564a2896a..de1518614827 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)) |
@@ -351,6 +372,9 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) | |||
351 | I915_WRITE(BLC_PWM_CTL2, | 372 | I915_WRITE(BLC_PWM_CTL2, |
352 | dev_priv->regfile.saveBLC_PWM_CTL2); | 373 | dev_priv->regfile.saveBLC_PWM_CTL2); |
353 | } | 374 | } |
375 | |||
376 | if (IS_VALLEYVIEW(dev) && !val) | ||
377 | val = 0x0f42ffff; | ||
354 | } | 378 | } |
355 | 379 | ||
356 | return val; | 380 | return val; |
@@ -441,7 +465,8 @@ static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) | |||
441 | I915_WRITE(BLC_PWM_CPU_CTL, val | level); | 465 | I915_WRITE(BLC_PWM_CPU_CTL, val | level); |
442 | } | 466 | } |
443 | 467 | ||
444 | static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level) | 468 | static void intel_panel_actually_set_backlight(struct drm_device *dev, |
469 | u32 level) | ||
445 | { | 470 | { |
446 | struct drm_i915_private *dev_priv = dev->dev_private; | 471 | struct drm_i915_private *dev_priv = dev->dev_private; |
447 | u32 tmp; | 472 | u32 tmp; |
@@ -549,6 +574,8 @@ void intel_panel_enable_backlight(struct drm_device *dev, | |||
549 | intel_pipe_to_cpu_transcoder(dev_priv, pipe); | 574 | intel_pipe_to_cpu_transcoder(dev_priv, pipe); |
550 | unsigned long flags; | 575 | unsigned long flags; |
551 | 576 | ||
577 | DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); | ||
578 | |||
552 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | 579 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
553 | 580 | ||
554 | if (dev_priv->backlight.level == 0) { | 581 | if (dev_priv->backlight.level == 0) { |
@@ -607,10 +634,24 @@ set_level: | |||
607 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | 634 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
608 | } | 635 | } |
609 | 636 | ||
637 | /* FIXME: use VBT vals to init PWM_CTL and PWM_CTL2 correctly */ | ||
638 | static void intel_panel_init_backlight_regs(struct drm_device *dev) | ||
639 | { | ||
640 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
641 | |||
642 | if (IS_VALLEYVIEW(dev)) { | ||
643 | u32 cur_val = I915_READ(BLC_PWM_CTL) & | ||
644 | BACKLIGHT_DUTY_CYCLE_MASK; | ||
645 | I915_WRITE(BLC_PWM_CTL, (0xf42 << 16) | cur_val); | ||
646 | } | ||
647 | } | ||
648 | |||
610 | static void intel_panel_init_backlight(struct drm_device *dev) | 649 | static void intel_panel_init_backlight(struct drm_device *dev) |
611 | { | 650 | { |
612 | struct drm_i915_private *dev_priv = dev->dev_private; | 651 | struct drm_i915_private *dev_priv = dev->dev_private; |
613 | 652 | ||
653 | intel_panel_init_backlight_regs(dev); | ||
654 | |||
614 | dev_priv->backlight.level = intel_panel_get_backlight(dev); | 655 | dev_priv->backlight.level = intel_panel_get_backlight(dev); |
615 | dev_priv->backlight.enabled = dev_priv->backlight.level != 0; | 656 | dev_priv->backlight.enabled = dev_priv->backlight.level != 0; |
616 | } | 657 | } |
@@ -637,10 +678,12 @@ intel_panel_detect(struct drm_device *dev) | |||
637 | } | 678 | } |
638 | } | 679 | } |
639 | 680 | ||
640 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | 681 | #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) |
641 | static int intel_panel_update_status(struct backlight_device *bd) | 682 | static int intel_panel_update_status(struct backlight_device *bd) |
642 | { | 683 | { |
643 | struct drm_device *dev = bl_get_data(bd); | 684 | struct drm_device *dev = bl_get_data(bd); |
685 | DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", | ||
686 | bd->props.brightness, bd->props.max_brightness); | ||
644 | intel_panel_set_backlight(dev, bd->props.brightness, | 687 | intel_panel_set_backlight(dev, bd->props.brightness, |
645 | bd->props.max_brightness); | 688 | bd->props.max_brightness); |
646 | return 0; | 689 | return 0; |