diff options
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 209 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 191 |
5 files changed, 241 insertions, 209 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e83dbe5ecc0..fc6f76837437 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -3601,6 +3601,33 @@ g4x_fixup_plane(struct drm_i915_private *dev_priv, enum pipe pipe) | |||
3601 | } | 3601 | } |
3602 | } | 3602 | } |
3603 | 3603 | ||
3604 | static void i9xx_pfit_enable(struct intel_crtc *crtc) | ||
3605 | { | ||
3606 | struct drm_device *dev = crtc->base.dev; | ||
3607 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
3608 | struct intel_crtc_config *pipe_config = &crtc->config; | ||
3609 | |||
3610 | if (!(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || | ||
3611 | intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS))) | ||
3612 | return; | ||
3613 | |||
3614 | WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); | ||
3615 | assert_pipe_disabled(dev_priv, crtc->pipe); | ||
3616 | |||
3617 | /* | ||
3618 | * Enable automatic panel scaling so that non-native modes | ||
3619 | * fill the screen. The panel fitter should only be | ||
3620 | * adjusted whilst the pipe is disabled, according to | ||
3621 | * register description and PRM. | ||
3622 | */ | ||
3623 | DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", | ||
3624 | pipe_config->pfit_control, | ||
3625 | pipe_config->pfit_pgm_ratios); | ||
3626 | |||
3627 | I915_WRITE(PFIT_PGM_RATIOS, pipe_config->pfit_pgm_ratios); | ||
3628 | I915_WRITE(PFIT_CONTROL, pipe_config->pfit_control); | ||
3629 | } | ||
3630 | |||
3604 | static void valleyview_crtc_enable(struct drm_crtc *crtc) | 3631 | static void valleyview_crtc_enable(struct drm_crtc *crtc) |
3605 | { | 3632 | { |
3606 | struct drm_device *dev = crtc->dev; | 3633 | struct drm_device *dev = crtc->dev; |
@@ -3634,6 +3661,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) | |||
3634 | for_each_encoder_on_crtc(dev, crtc, encoder) | 3661 | for_each_encoder_on_crtc(dev, crtc, encoder) |
3635 | encoder->enable(encoder); | 3662 | encoder->enable(encoder); |
3636 | 3663 | ||
3664 | /* Enable panel fitting for eDP */ | ||
3665 | i9xx_pfit_enable(intel_crtc); | ||
3666 | |||
3637 | intel_enable_pipe(dev_priv, pipe, false); | 3667 | intel_enable_pipe(dev_priv, pipe, false); |
3638 | intel_enable_plane(dev_priv, plane, pipe); | 3668 | intel_enable_plane(dev_priv, plane, pipe); |
3639 | 3669 | ||
@@ -3670,6 +3700,9 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) | |||
3670 | if (encoder->pre_enable) | 3700 | if (encoder->pre_enable) |
3671 | encoder->pre_enable(encoder); | 3701 | encoder->pre_enable(encoder); |
3672 | 3702 | ||
3703 | /* Enable panel fitting for LVDS */ | ||
3704 | i9xx_pfit_enable(intel_crtc); | ||
3705 | |||
3673 | intel_enable_pipe(dev_priv, pipe, false); | 3706 | intel_enable_pipe(dev_priv, pipe, false); |
3674 | intel_enable_plane(dev_priv, plane, pipe); | 3707 | intel_enable_plane(dev_priv, plane, pipe); |
3675 | if (IS_G4X(dev)) | 3708 | if (IS_G4X(dev)) |
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f63973ad33cb..9c834bc15ab7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -712,6 +712,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, | |||
712 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | 712 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
713 | struct drm_display_mode *mode = &pipe_config->requested_mode; | 713 | struct drm_display_mode *mode = &pipe_config->requested_mode; |
714 | struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); | 714 | struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); |
715 | struct intel_crtc *intel_crtc = encoder->new_crtc; | ||
715 | struct intel_connector *intel_connector = intel_dp->attached_connector; | 716 | struct intel_connector *intel_connector = intel_dp->attached_connector; |
716 | int lane_count, clock; | 717 | int lane_count, clock; |
717 | int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); | 718 | int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); |
@@ -728,9 +729,13 @@ intel_dp_compute_config(struct intel_encoder *encoder, | |||
728 | if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { | 729 | if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { |
729 | intel_fixed_panel_mode(intel_connector->panel.fixed_mode, | 730 | intel_fixed_panel_mode(intel_connector->panel.fixed_mode, |
730 | adjusted_mode); | 731 | adjusted_mode); |
731 | intel_pch_panel_fitting(dev, | 732 | if (!HAS_PCH_SPLIT(dev)) |
732 | intel_connector->panel.fitting_mode, | 733 | intel_gmch_panel_fitting(intel_crtc, pipe_config, |
733 | mode, adjusted_mode); | 734 | intel_connector->panel.fitting_mode); |
735 | else | ||
736 | intel_pch_panel_fitting(dev, | ||
737 | intel_connector->panel.fitting_mode, | ||
738 | mode, adjusted_mode); | ||
734 | } | 739 | } |
735 | /* We need to take the panel's fixed mode into account. */ | 740 | /* We need to take the panel's fixed mode into account. */ |
736 | target_clock = adjusted_mode->clock; | 741 | target_clock = adjusted_mode->clock; |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a5fe976364e1..9f3f71bc2f22 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -237,6 +237,9 @@ struct intel_crtc_config { | |||
237 | int pixel_target_clock; | 237 | int pixel_target_clock; |
238 | /* Used by SDVO (and if we ever fix it, HDMI). */ | 238 | /* Used by SDVO (and if we ever fix it, HDMI). */ |
239 | unsigned pixel_multiplier; | 239 | unsigned pixel_multiplier; |
240 | |||
241 | /* Panel fitter controls for gen2-gen4 + VLV */ | ||
242 | u32 pfit_control, pfit_pgm_ratios; | ||
240 | }; | 243 | }; |
241 | 244 | ||
242 | struct intel_crtc { | 245 | struct intel_crtc { |
@@ -558,6 +561,9 @@ extern void intel_pch_panel_fitting(struct drm_device *dev, | |||
558 | int fitting_mode, | 561 | int fitting_mode, |
559 | const struct drm_display_mode *mode, | 562 | const struct drm_display_mode *mode, |
560 | struct drm_display_mode *adjusted_mode); | 563 | struct drm_display_mode *adjusted_mode); |
564 | extern void intel_gmch_panel_fitting(struct intel_crtc *crtc, | ||
565 | struct intel_crtc_config *pipe_config, | ||
566 | int fitting_mode); | ||
561 | extern void intel_panel_set_backlight(struct drm_device *dev, | 567 | extern void intel_panel_set_backlight(struct drm_device *dev, |
562 | u32 level, u32 max); | 568 | u32 level, u32 max); |
563 | extern int intel_panel_setup_backlight(struct drm_connector *connector); | 569 | extern int intel_panel_setup_backlight(struct drm_connector *connector); |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 84085454b104..7d418818c7a8 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -49,8 +49,6 @@ struct intel_lvds_connector { | |||
49 | struct intel_lvds_encoder { | 49 | struct intel_lvds_encoder { |
50 | struct intel_encoder base; | 50 | struct intel_encoder base; |
51 | 51 | ||
52 | u32 pfit_control; | ||
53 | u32 pfit_pgm_ratios; | ||
54 | bool is_dual_link; | 52 | bool is_dual_link; |
55 | u32 reg; | 53 | u32 reg; |
56 | 54 | ||
@@ -153,32 +151,6 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) | |||
153 | I915_WRITE(lvds_encoder->reg, temp); | 151 | I915_WRITE(lvds_encoder->reg, temp); |
154 | } | 152 | } |
155 | 153 | ||
156 | static void intel_pre_enable_lvds(struct intel_encoder *encoder) | ||
157 | { | ||
158 | struct drm_device *dev = encoder->base.dev; | ||
159 | struct intel_lvds_encoder *enc = to_lvds_encoder(&encoder->base); | ||
160 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
161 | |||
162 | if (HAS_PCH_SPLIT(dev) || !enc->pfit_control) | ||
163 | return; | ||
164 | |||
165 | WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); | ||
166 | assert_pipe_disabled(dev_priv, to_intel_crtc(encoder->base.crtc)->pipe); | ||
167 | |||
168 | /* | ||
169 | * Enable automatic panel scaling so that non-native modes | ||
170 | * fill the screen. The panel fitter should only be | ||
171 | * adjusted whilst the pipe is disabled, according to | ||
172 | * register description and PRM. | ||
173 | */ | ||
174 | DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", | ||
175 | enc->pfit_control, | ||
176 | enc->pfit_pgm_ratios); | ||
177 | |||
178 | I915_WRITE(PFIT_PGM_RATIOS, enc->pfit_pgm_ratios); | ||
179 | I915_WRITE(PFIT_CONTROL, enc->pfit_control); | ||
180 | } | ||
181 | |||
182 | /** | 154 | /** |
183 | * Sets the power state for the panel. | 155 | * Sets the power state for the panel. |
184 | */ | 156 | */ |
@@ -247,62 +219,6 @@ static int intel_lvds_mode_valid(struct drm_connector *connector, | |||
247 | return MODE_OK; | 219 | return MODE_OK; |
248 | } | 220 | } |
249 | 221 | ||
250 | static void | ||
251 | centre_horizontally(struct drm_display_mode *mode, | ||
252 | int width) | ||
253 | { | ||
254 | u32 border, sync_pos, blank_width, sync_width; | ||
255 | |||
256 | /* keep the hsync and hblank widths constant */ | ||
257 | sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; | ||
258 | blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; | ||
259 | sync_pos = (blank_width - sync_width + 1) / 2; | ||
260 | |||
261 | border = (mode->hdisplay - width + 1) / 2; | ||
262 | border += border & 1; /* make the border even */ | ||
263 | |||
264 | mode->crtc_hdisplay = width; | ||
265 | mode->crtc_hblank_start = width + border; | ||
266 | mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; | ||
267 | |||
268 | mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; | ||
269 | mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; | ||
270 | } | ||
271 | |||
272 | static void | ||
273 | centre_vertically(struct drm_display_mode *mode, | ||
274 | int height) | ||
275 | { | ||
276 | u32 border, sync_pos, blank_width, sync_width; | ||
277 | |||
278 | /* keep the vsync and vblank widths constant */ | ||
279 | sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; | ||
280 | blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; | ||
281 | sync_pos = (blank_width - sync_width + 1) / 2; | ||
282 | |||
283 | border = (mode->vdisplay - height + 1) / 2; | ||
284 | |||
285 | mode->crtc_vdisplay = height; | ||
286 | mode->crtc_vblank_start = height + border; | ||
287 | mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; | ||
288 | |||
289 | mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; | ||
290 | mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; | ||
291 | } | ||
292 | |||
293 | static inline u32 panel_fitter_scaling(u32 source, u32 target) | ||
294 | { | ||
295 | /* | ||
296 | * Floating point operation is not supported. So the FACTOR | ||
297 | * is defined, which can avoid the floating point computation | ||
298 | * when calculating the panel ratio. | ||
299 | */ | ||
300 | #define ACCURACY 12 | ||
301 | #define FACTOR (1 << ACCURACY) | ||
302 | u32 ratio = source * FACTOR / target; | ||
303 | return (FACTOR * ratio + FACTOR/2) / FACTOR; | ||
304 | } | ||
305 | |||
306 | static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | 222 | static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, |
307 | struct intel_crtc_config *pipe_config) | 223 | struct intel_crtc_config *pipe_config) |
308 | { | 224 | { |
@@ -315,7 +231,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | |||
315 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | 231 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
316 | struct drm_display_mode *mode = &pipe_config->requested_mode; | 232 | struct drm_display_mode *mode = &pipe_config->requested_mode; |
317 | struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; | 233 | struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; |
318 | u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; | ||
319 | unsigned int lvds_bpp; | 234 | unsigned int lvds_bpp; |
320 | int pipe; | 235 | int pipe; |
321 | 236 | ||
@@ -338,11 +253,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | |||
338 | DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", | 253 | DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", |
339 | pipe_config->pipe_bpp, lvds_bpp); | 254 | pipe_config->pipe_bpp, lvds_bpp); |
340 | pipe_config->pipe_bpp = lvds_bpp; | 255 | pipe_config->pipe_bpp = lvds_bpp; |
341 | |||
342 | /* Make sure pre-965 set dither correctly for 18bpp panels. */ | ||
343 | if (INTEL_INFO(dev)->gen < 4 && lvds_bpp == 18) | ||
344 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; | ||
345 | |||
346 | } | 256 | } |
347 | 257 | ||
348 | /* | 258 | /* |
@@ -361,18 +271,11 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | |||
361 | intel_connector->panel.fitting_mode, | 271 | intel_connector->panel.fitting_mode, |
362 | mode, adjusted_mode); | 272 | mode, adjusted_mode); |
363 | return true; | 273 | return true; |
274 | } else { | ||
275 | intel_gmch_panel_fitting(intel_crtc, pipe_config, | ||
276 | intel_connector->panel.fitting_mode); | ||
364 | } | 277 | } |
365 | 278 | ||
366 | /* Native modes don't need fitting */ | ||
367 | if (adjusted_mode->hdisplay == mode->hdisplay && | ||
368 | adjusted_mode->vdisplay == mode->vdisplay) | ||
369 | goto out; | ||
370 | |||
371 | /* 965+ wants fuzzy fitting */ | ||
372 | if (INTEL_INFO(dev)->gen >= 4) | ||
373 | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | | ||
374 | PFIT_FILTER_FUZZY); | ||
375 | |||
376 | /* | 279 | /* |
377 | * Enable automatic panel scaling for non-native modes so that they fill | 280 | * Enable automatic panel scaling for non-native modes so that they fill |
378 | * the screen. Should be enabled before the pipe is enabled, according | 281 | * the screen. Should be enabled before the pipe is enabled, according |
@@ -385,107 +288,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | |||
385 | drm_mode_set_crtcinfo(adjusted_mode, 0); | 288 | drm_mode_set_crtcinfo(adjusted_mode, 0); |
386 | pipe_config->timings_set = true; | 289 | pipe_config->timings_set = true; |
387 | 290 | ||
388 | switch (intel_connector->panel.fitting_mode) { | ||
389 | case DRM_MODE_SCALE_CENTER: | ||
390 | /* | ||
391 | * For centered modes, we have to calculate border widths & | ||
392 | * heights and modify the values programmed into the CRTC. | ||
393 | */ | ||
394 | centre_horizontally(adjusted_mode, mode->hdisplay); | ||
395 | centre_vertically(adjusted_mode, mode->vdisplay); | ||
396 | border = LVDS_BORDER_ENABLE; | ||
397 | break; | ||
398 | |||
399 | case DRM_MODE_SCALE_ASPECT: | ||
400 | /* Scale but preserve the aspect ratio */ | ||
401 | if (INTEL_INFO(dev)->gen >= 4) { | ||
402 | u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; | ||
403 | u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; | ||
404 | |||
405 | /* 965+ is easy, it does everything in hw */ | ||
406 | if (scaled_width > scaled_height) | ||
407 | pfit_control |= PFIT_ENABLE | PFIT_SCALING_PILLAR; | ||
408 | else if (scaled_width < scaled_height) | ||
409 | pfit_control |= PFIT_ENABLE | PFIT_SCALING_LETTER; | ||
410 | else if (adjusted_mode->hdisplay != mode->hdisplay) | ||
411 | pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; | ||
412 | } else { | ||
413 | u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; | ||
414 | u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; | ||
415 | /* | ||
416 | * For earlier chips we have to calculate the scaling | ||
417 | * ratio by hand and program it into the | ||
418 | * PFIT_PGM_RATIO register | ||
419 | */ | ||
420 | if (scaled_width > scaled_height) { /* pillar */ | ||
421 | centre_horizontally(adjusted_mode, scaled_height / mode->vdisplay); | ||
422 | |||
423 | border = LVDS_BORDER_ENABLE; | ||
424 | if (mode->vdisplay != adjusted_mode->vdisplay) { | ||
425 | u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); | ||
426 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | | ||
427 | bits << PFIT_VERT_SCALE_SHIFT); | ||
428 | pfit_control |= (PFIT_ENABLE | | ||
429 | VERT_INTERP_BILINEAR | | ||
430 | HORIZ_INTERP_BILINEAR); | ||
431 | } | ||
432 | } else if (scaled_width < scaled_height) { /* letter */ | ||
433 | centre_vertically(adjusted_mode, scaled_width / mode->hdisplay); | ||
434 | |||
435 | border = LVDS_BORDER_ENABLE; | ||
436 | if (mode->hdisplay != adjusted_mode->hdisplay) { | ||
437 | u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); | ||
438 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | | ||
439 | bits << PFIT_VERT_SCALE_SHIFT); | ||
440 | pfit_control |= (PFIT_ENABLE | | ||
441 | VERT_INTERP_BILINEAR | | ||
442 | HORIZ_INTERP_BILINEAR); | ||
443 | } | ||
444 | } else | ||
445 | /* Aspects match, Let hw scale both directions */ | ||
446 | pfit_control |= (PFIT_ENABLE | | ||
447 | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | | ||
448 | VERT_INTERP_BILINEAR | | ||
449 | HORIZ_INTERP_BILINEAR); | ||
450 | } | ||
451 | break; | ||
452 | |||
453 | case DRM_MODE_SCALE_FULLSCREEN: | ||
454 | /* | ||
455 | * Full scaling, even if it changes the aspect ratio. | ||
456 | * Fortunately this is all done for us in hw. | ||
457 | */ | ||
458 | if (mode->vdisplay != adjusted_mode->vdisplay || | ||
459 | mode->hdisplay != adjusted_mode->hdisplay) { | ||
460 | pfit_control |= PFIT_ENABLE; | ||
461 | if (INTEL_INFO(dev)->gen >= 4) | ||
462 | pfit_control |= PFIT_SCALING_AUTO; | ||
463 | else | ||
464 | pfit_control |= (VERT_AUTO_SCALE | | ||
465 | VERT_INTERP_BILINEAR | | ||
466 | HORIZ_AUTO_SCALE | | ||
467 | HORIZ_INTERP_BILINEAR); | ||
468 | } | ||
469 | break; | ||
470 | |||
471 | default: | ||
472 | break; | ||
473 | } | ||
474 | |||
475 | out: | ||
476 | /* If not enabling scaling, be consistent and always use 0. */ | ||
477 | if ((pfit_control & PFIT_ENABLE) == 0) { | ||
478 | pfit_control = 0; | ||
479 | pfit_pgm_ratios = 0; | ||
480 | } | ||
481 | |||
482 | if (pfit_control != lvds_encoder->pfit_control || | ||
483 | pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) { | ||
484 | lvds_encoder->pfit_control = pfit_control; | ||
485 | lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios; | ||
486 | } | ||
487 | dev_priv->lvds_border_bits = border; | ||
488 | |||
489 | /* | 291 | /* |
490 | * XXX: It would be nice to support lower refresh rates on the | 292 | * XXX: It would be nice to support lower refresh rates on the |
491 | * panels to reduce power consumption, and perhaps match the | 293 | * panels to reduce power consumption, and perhaps match the |
@@ -1115,10 +917,6 @@ bool intel_lvds_init(struct drm_device *dev) | |||
1115 | 917 | ||
1116 | lvds_encoder->attached_connector = lvds_connector; | 918 | lvds_encoder->attached_connector = lvds_connector; |
1117 | 919 | ||
1118 | if (!HAS_PCH_SPLIT(dev)) { | ||
1119 | lvds_encoder->pfit_control = I915_READ(PFIT_CONTROL); | ||
1120 | } | ||
1121 | |||
1122 | intel_encoder = &lvds_encoder->base; | 920 | intel_encoder = &lvds_encoder->base; |
1123 | encoder = &intel_encoder->base; | 921 | encoder = &intel_encoder->base; |
1124 | intel_connector = &lvds_connector->base; | 922 | intel_connector = &lvds_connector->base; |
@@ -1130,7 +928,6 @@ bool intel_lvds_init(struct drm_device *dev) | |||
1130 | DRM_MODE_ENCODER_LVDS); | 928 | DRM_MODE_ENCODER_LVDS); |
1131 | 929 | ||
1132 | intel_encoder->enable = intel_enable_lvds; | 930 | intel_encoder->enable = intel_enable_lvds; |
1133 | intel_encoder->pre_enable = intel_pre_enable_lvds; | ||
1134 | intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; | 931 | intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; |
1135 | intel_encoder->compute_config = intel_lvds_compute_config; | 932 | intel_encoder->compute_config = intel_lvds_compute_config; |
1136 | intel_encoder->disable = intel_disable_lvds; | 933 | intel_encoder->disable = intel_disable_lvds; |
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 7f6141d9a06d..0f32f6498ad3 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
@@ -117,6 +117,197 @@ done: | |||
117 | dev_priv->pch_pf_size = (width << 16) | height; | 117 | dev_priv->pch_pf_size = (width << 16) | height; |
118 | } | 118 | } |
119 | 119 | ||
120 | static void | ||
121 | centre_horizontally(struct drm_display_mode *mode, | ||
122 | int width) | ||
123 | { | ||
124 | u32 border, sync_pos, blank_width, sync_width; | ||
125 | |||
126 | /* keep the hsync and hblank widths constant */ | ||
127 | sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; | ||
128 | blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; | ||
129 | sync_pos = (blank_width - sync_width + 1) / 2; | ||
130 | |||
131 | border = (mode->hdisplay - width + 1) / 2; | ||
132 | border += border & 1; /* make the border even */ | ||
133 | |||
134 | mode->crtc_hdisplay = width; | ||
135 | mode->crtc_hblank_start = width + border; | ||
136 | mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; | ||
137 | |||
138 | mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; | ||
139 | mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; | ||
140 | } | ||
141 | |||
142 | static void | ||
143 | centre_vertically(struct drm_display_mode *mode, | ||
144 | int height) | ||
145 | { | ||
146 | u32 border, sync_pos, blank_width, sync_width; | ||
147 | |||
148 | /* keep the vsync and vblank widths constant */ | ||
149 | sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; | ||
150 | blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; | ||
151 | sync_pos = (blank_width - sync_width + 1) / 2; | ||
152 | |||
153 | border = (mode->vdisplay - height + 1) / 2; | ||
154 | |||
155 | mode->crtc_vdisplay = height; | ||
156 | mode->crtc_vblank_start = height + border; | ||
157 | mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; | ||
158 | |||
159 | mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; | ||
160 | mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; | ||
161 | } | ||
162 | |||
163 | static inline u32 panel_fitter_scaling(u32 source, u32 target) | ||
164 | { | ||
165 | /* | ||
166 | * Floating point operation is not supported. So the FACTOR | ||
167 | * is defined, which can avoid the floating point computation | ||
168 | * when calculating the panel ratio. | ||
169 | */ | ||
170 | #define ACCURACY 12 | ||
171 | #define FACTOR (1 << ACCURACY) | ||
172 | u32 ratio = source * FACTOR / target; | ||
173 | return (FACTOR * ratio + FACTOR/2) / FACTOR; | ||
174 | } | ||
175 | |||
176 | void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, | ||
177 | struct intel_crtc_config *pipe_config, | ||
178 | int fitting_mode) | ||
179 | { | ||
180 | struct drm_device *dev = intel_crtc->base.dev; | ||
181 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
182 | u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; | ||
183 | struct drm_display_mode *mode, *adjusted_mode; | ||
184 | |||
185 | mode = &pipe_config->requested_mode; | ||
186 | adjusted_mode = &pipe_config->adjusted_mode; | ||
187 | |||
188 | /* Native modes don't need fitting */ | ||
189 | if (adjusted_mode->hdisplay == mode->hdisplay && | ||
190 | adjusted_mode->vdisplay == mode->vdisplay) | ||
191 | goto out; | ||
192 | |||
193 | switch (fitting_mode) { | ||
194 | case DRM_MODE_SCALE_CENTER: | ||
195 | /* | ||
196 | * For centered modes, we have to calculate border widths & | ||
197 | * heights and modify the values programmed into the CRTC. | ||
198 | */ | ||
199 | centre_horizontally(adjusted_mode, mode->hdisplay); | ||
200 | centre_vertically(adjusted_mode, mode->vdisplay); | ||
201 | border = LVDS_BORDER_ENABLE; | ||
202 | break; | ||
203 | case DRM_MODE_SCALE_ASPECT: | ||
204 | /* Scale but preserve the aspect ratio */ | ||
205 | if (INTEL_INFO(dev)->gen >= 4) { | ||
206 | u32 scaled_width = adjusted_mode->hdisplay * | ||
207 | mode->vdisplay; | ||
208 | u32 scaled_height = mode->hdisplay * | ||
209 | adjusted_mode->vdisplay; | ||
210 | |||
211 | /* 965+ is easy, it does everything in hw */ | ||
212 | if (scaled_width > scaled_height) | ||
213 | pfit_control |= PFIT_ENABLE | | ||
214 | PFIT_SCALING_PILLAR; | ||
215 | else if (scaled_width < scaled_height) | ||
216 | pfit_control |= PFIT_ENABLE | | ||
217 | PFIT_SCALING_LETTER; | ||
218 | else if (adjusted_mode->hdisplay != mode->hdisplay) | ||
219 | pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; | ||
220 | } else { | ||
221 | u32 scaled_width = adjusted_mode->hdisplay * | ||
222 | mode->vdisplay; | ||
223 | u32 scaled_height = mode->hdisplay * | ||
224 | adjusted_mode->vdisplay; | ||
225 | /* | ||
226 | * For earlier chips we have to calculate the scaling | ||
227 | * ratio by hand and program it into the | ||
228 | * PFIT_PGM_RATIO register | ||
229 | */ | ||
230 | if (scaled_width > scaled_height) { /* pillar */ | ||
231 | centre_horizontally(adjusted_mode, | ||
232 | scaled_height / | ||
233 | mode->vdisplay); | ||
234 | |||
235 | border = LVDS_BORDER_ENABLE; | ||
236 | if (mode->vdisplay != adjusted_mode->vdisplay) { | ||
237 | u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); | ||
238 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | | ||
239 | bits << PFIT_VERT_SCALE_SHIFT); | ||
240 | pfit_control |= (PFIT_ENABLE | | ||
241 | VERT_INTERP_BILINEAR | | ||
242 | HORIZ_INTERP_BILINEAR); | ||
243 | } | ||
244 | } else if (scaled_width < scaled_height) { /* letter */ | ||
245 | centre_vertically(adjusted_mode, | ||
246 | scaled_width / | ||
247 | mode->hdisplay); | ||
248 | |||
249 | border = LVDS_BORDER_ENABLE; | ||
250 | if (mode->hdisplay != adjusted_mode->hdisplay) { | ||
251 | u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); | ||
252 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | | ||
253 | bits << PFIT_VERT_SCALE_SHIFT); | ||
254 | pfit_control |= (PFIT_ENABLE | | ||
255 | VERT_INTERP_BILINEAR | | ||
256 | HORIZ_INTERP_BILINEAR); | ||
257 | } | ||
258 | } else { | ||
259 | /* Aspects match, Let hw scale both directions */ | ||
260 | pfit_control |= (PFIT_ENABLE | | ||
261 | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | | ||
262 | VERT_INTERP_BILINEAR | | ||
263 | HORIZ_INTERP_BILINEAR); | ||
264 | } | ||
265 | } | ||
266 | break; | ||
267 | default: | ||
268 | case DRM_MODE_SCALE_FULLSCREEN: | ||
269 | /* | ||
270 | * Full scaling, even if it changes the aspect ratio. | ||
271 | * Fortunately this is all done for us in hw. | ||
272 | */ | ||
273 | if (mode->vdisplay != adjusted_mode->vdisplay || | ||
274 | mode->hdisplay != adjusted_mode->hdisplay) { | ||
275 | pfit_control |= PFIT_ENABLE; | ||
276 | if (INTEL_INFO(dev)->gen >= 4) | ||
277 | pfit_control |= PFIT_SCALING_AUTO; | ||
278 | else | ||
279 | pfit_control |= (VERT_AUTO_SCALE | | ||
280 | VERT_INTERP_BILINEAR | | ||
281 | HORIZ_AUTO_SCALE | | ||
282 | HORIZ_INTERP_BILINEAR); | ||
283 | } | ||
284 | break; | ||
285 | } | ||
286 | |||
287 | /* 965+ wants fuzzy fitting */ | ||
288 | /* FIXME: handle multiple panels by failing gracefully */ | ||
289 | if (INTEL_INFO(dev)->gen >= 4) | ||
290 | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | | ||
291 | PFIT_FILTER_FUZZY); | ||
292 | |||
293 | out: | ||
294 | if ((pfit_control & PFIT_ENABLE) == 0) { | ||
295 | pfit_control = 0; | ||
296 | pfit_pgm_ratios = 0; | ||
297 | } | ||
298 | |||
299 | /* Make sure pre-965 set dither correctly for 18bpp panels. */ | ||
300 | if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) | ||
301 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; | ||
302 | |||
303 | if (pfit_control != pipe_config->pfit_control || | ||
304 | pfit_pgm_ratios != pipe_config->pfit_pgm_ratios) { | ||
305 | pipe_config->pfit_control = pfit_control; | ||
306 | pipe_config->pfit_pgm_ratios = pfit_pgm_ratios; | ||
307 | } | ||
308 | dev_priv->lvds_border_bits = border; | ||
309 | } | ||
310 | |||
120 | static int is_backlight_combination_mode(struct drm_device *dev) | 311 | static int is_backlight_combination_mode(struct drm_device *dev) |
121 | { | 312 | { |
122 | struct drm_i915_private *dev_priv = dev->dev_private; | 313 | struct drm_i915_private *dev_priv = dev->dev_private; |