aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/intel_panel.c')
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c207
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
175static 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
195static 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
174void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, 252void 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
444static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level) 468static 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 */
638static 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
610static void intel_panel_init_backlight(struct drm_device *dev) 649static 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)
641static int intel_panel_update_status(struct backlight_device *bd) 682static 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;