diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-08-07 06:01:28 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2010-08-09 14:24:34 -0400 |
commit | 1d8e1c75ffa84400758aef9cc59298920b8801f9 (patch) | |
tree | c1faa4ad7c8754330edd959d0726b19376cf4f9c | |
parent | 2e88e40bed136a7b7cb1c77d8dc6bd181d0d2732 (diff) |
drm/i915: Enable aspect/centering panel fitting for Ironlake.
v2: Hook in DP paths to keep FULLSCREEN panel fitting on eDP.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r-- | drivers/gpu/drm/i915/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 32 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 111 |
7 files changed, 143 insertions, 46 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 384fd4535796..5c8e53458edb 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile | |||
@@ -19,6 +19,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ | |||
19 | intel_hdmi.o \ | 19 | intel_hdmi.o \ |
20 | intel_sdvo.o \ | 20 | intel_sdvo.o \ |
21 | intel_modes.o \ | 21 | intel_modes.o \ |
22 | intel_panel.o \ | ||
22 | intel_i2c.o \ | 23 | intel_i2c.o \ |
23 | intel_fb.o \ | 24 | intel_fb.o \ |
24 | intel_tv.o \ | 25 | intel_tv.o \ |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6221f239fa5e..4b0ffb6c5561 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -614,6 +614,8 @@ typedef struct drm_i915_private { | |||
614 | struct sdvo_device_mapping sdvo_mappings[2]; | 614 | struct sdvo_device_mapping sdvo_mappings[2]; |
615 | /* indicate whether the LVDS_BORDER should be enabled or not */ | 615 | /* indicate whether the LVDS_BORDER should be enabled or not */ |
616 | unsigned int lvds_border_bits; | 616 | unsigned int lvds_border_bits; |
617 | /* Panel fitter placement and size for Ironlake+ */ | ||
618 | u32 pch_pf_pos, pch_pf_size; | ||
617 | 619 | ||
618 | struct drm_crtc *plane_to_crtc_mapping[2]; | 620 | struct drm_crtc *plane_to_crtc_mapping[2]; |
619 | struct drm_crtc *pipe_to_crtc_mapping[2]; | 621 | struct drm_crtc *pipe_to_crtc_mapping[2]; |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 24fbd0f24507..25e3866f9159 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -2005,15 +2005,13 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
2005 | /* Enable panel fitting for LVDS */ | 2005 | /* Enable panel fitting for LVDS */ |
2006 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) | 2006 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) |
2007 | || HAS_eDP || intel_pch_has_edp(crtc)) { | 2007 | || HAS_eDP || intel_pch_has_edp(crtc)) { |
2008 | temp = I915_READ(pf_ctl_reg); | 2008 | if (dev_priv->pch_pf_size) { |
2009 | I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3); | 2009 | temp = I915_READ(pf_ctl_reg); |
2010 | 2010 | I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3); | |
2011 | /* currently full aspect */ | 2011 | I915_WRITE(pf_win_pos, dev_priv->pch_pf_pos); |
2012 | I915_WRITE(pf_win_pos, 0); | 2012 | I915_WRITE(pf_win_size, dev_priv->pch_pf_size); |
2013 | 2013 | } else | |
2014 | I915_WRITE(pf_win_size, | 2014 | I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); |
2015 | (dev_priv->panel_fixed_mode->hdisplay << 16) | | ||
2016 | (dev_priv->panel_fixed_mode->vdisplay)); | ||
2017 | } | 2015 | } |
2018 | 2016 | ||
2019 | /* Enable CPU pipe */ | 2017 | /* Enable CPU pipe */ |
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c4c5868a8aa0..cee5d9ceb3b8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -523,21 +523,9 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, | |||
523 | 523 | ||
524 | if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && | 524 | if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && |
525 | dev_priv->panel_fixed_mode) { | 525 | dev_priv->panel_fixed_mode) { |
526 | struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; | 526 | intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode); |
527 | 527 | intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN, | |
528 | adjusted_mode->hdisplay = fixed_mode->hdisplay; | 528 | mode, adjusted_mode); |
529 | adjusted_mode->hsync_start = fixed_mode->hsync_start; | ||
530 | adjusted_mode->hsync_end = fixed_mode->hsync_end; | ||
531 | adjusted_mode->htotal = fixed_mode->htotal; | ||
532 | |||
533 | adjusted_mode->vdisplay = fixed_mode->vdisplay; | ||
534 | adjusted_mode->vsync_start = fixed_mode->vsync_start; | ||
535 | adjusted_mode->vsync_end = fixed_mode->vsync_end; | ||
536 | adjusted_mode->vtotal = fixed_mode->vtotal; | ||
537 | |||
538 | adjusted_mode->clock = fixed_mode->clock; | ||
539 | drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | ||
540 | |||
541 | /* | 529 | /* |
542 | * the mode->clock is used to calculate the Data&Link M/N | 530 | * the mode->clock is used to calculate the Data&Link M/N |
543 | * of the pipe. For the eDP the fixed clock should be used. | 531 | * of the pipe. For the eDP the fixed clock should be used. |
@@ -572,8 +560,10 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, | |||
572 | "count %d clock %d\n", | 560 | "count %d clock %d\n", |
573 | intel_dp->link_bw, intel_dp->lane_count, | 561 | intel_dp->link_bw, intel_dp->lane_count, |
574 | adjusted_mode->clock); | 562 | adjusted_mode->clock); |
563 | |||
575 | return true; | 564 | return true; |
576 | } | 565 | } |
566 | |||
577 | return false; | 567 | return false; |
578 | } | 568 | } |
579 | 569 | ||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a44b8cb4d2cc..c552b06e5d21 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -186,6 +186,13 @@ extern bool intel_dpd_is_edp(struct drm_device *dev); | |||
186 | extern void intel_edp_link_config (struct intel_encoder *, int *, int *); | 186 | extern void intel_edp_link_config (struct intel_encoder *, int *, int *); |
187 | 187 | ||
188 | 188 | ||
189 | extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, | ||
190 | struct drm_display_mode *adjusted_mode); | ||
191 | extern void intel_pch_panel_fitting(struct drm_device *dev, | ||
192 | int fitting_mode, | ||
193 | struct drm_display_mode *mode, | ||
194 | struct drm_display_mode *adjusted_mode); | ||
195 | |||
189 | extern int intel_panel_fitter_pipe (struct drm_device *dev); | 196 | extern int intel_panel_fitter_pipe (struct drm_device *dev); |
190 | extern void intel_crtc_load_lut(struct drm_crtc *crtc); | 197 | extern void intel_crtc_load_lut(struct drm_crtc *crtc); |
191 | extern void intel_encoder_prepare (struct drm_encoder *encoder); | 198 | extern void intel_encoder_prepare (struct drm_encoder *encoder); |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 312ac306469a..cb5821eb59b6 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -246,26 +246,20 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | |||
246 | /* If we don't have a panel mode, there is nothing we can do */ | 246 | /* If we don't have a panel mode, there is nothing we can do */ |
247 | if (dev_priv->panel_fixed_mode == NULL) | 247 | if (dev_priv->panel_fixed_mode == NULL) |
248 | return true; | 248 | return true; |
249 | |||
249 | /* | 250 | /* |
250 | * We have timings from the BIOS for the panel, put them in | 251 | * We have timings from the BIOS for the panel, put them in |
251 | * to the adjusted mode. The CRTC will be set up for this mode, | 252 | * to the adjusted mode. The CRTC will be set up for this mode, |
252 | * with the panel scaling set up to source from the H/VDisplay | 253 | * with the panel scaling set up to source from the H/VDisplay |
253 | * of the original mode. | 254 | * of the original mode. |
254 | */ | 255 | */ |
255 | adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay; | 256 | intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode); |
256 | adjusted_mode->hsync_start = | 257 | |
257 | dev_priv->panel_fixed_mode->hsync_start; | 258 | if (HAS_PCH_SPLIT(dev)) { |
258 | adjusted_mode->hsync_end = | 259 | intel_pch_panel_fitting(dev, intel_lvds->fitting_mode, |
259 | dev_priv->panel_fixed_mode->hsync_end; | 260 | mode, adjusted_mode); |
260 | adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal; | 261 | return true; |
261 | adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay; | 262 | } |
262 | adjusted_mode->vsync_start = | ||
263 | dev_priv->panel_fixed_mode->vsync_start; | ||
264 | adjusted_mode->vsync_end = | ||
265 | dev_priv->panel_fixed_mode->vsync_end; | ||
266 | adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal; | ||
267 | adjusted_mode->clock = dev_priv->panel_fixed_mode->clock; | ||
268 | drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | ||
269 | 263 | ||
270 | /* Make sure pre-965s set dither correctly */ | 264 | /* Make sure pre-965s set dither correctly */ |
271 | if (!IS_I965G(dev)) { | 265 | if (!IS_I965G(dev)) { |
@@ -278,10 +272,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | |||
278 | adjusted_mode->vdisplay == mode->vdisplay) | 272 | adjusted_mode->vdisplay == mode->vdisplay) |
279 | goto out; | 273 | goto out; |
280 | 274 | ||
281 | /* full screen scale for now */ | ||
282 | if (HAS_PCH_SPLIT(dev)) | ||
283 | goto out; | ||
284 | |||
285 | /* 965+ wants fuzzy fitting */ | 275 | /* 965+ wants fuzzy fitting */ |
286 | if (IS_I965G(dev)) | 276 | if (IS_I965G(dev)) |
287 | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | | 277 | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | |
@@ -293,10 +283,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | |||
293 | * to register description and PRM. | 283 | * to register description and PRM. |
294 | * Change the value here to see the borders for debugging | 284 | * Change the value here to see the borders for debugging |
295 | */ | 285 | */ |
296 | if (!HAS_PCH_SPLIT(dev)) { | 286 | I915_WRITE(BCLRPAT_A, 0); |
297 | I915_WRITE(BCLRPAT_A, 0); | 287 | I915_WRITE(BCLRPAT_B, 0); |
298 | I915_WRITE(BCLRPAT_B, 0); | ||
299 | } | ||
300 | 288 | ||
301 | switch (intel_lvds->fitting_mode) { | 289 | switch (intel_lvds->fitting_mode) { |
302 | case DRM_MODE_SCALE_CENTER: | 290 | case DRM_MODE_SCALE_CENTER: |
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c new file mode 100644 index 000000000000..e7f5299d9d57 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2010 Intel Corporation | ||
3 | * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
10 | * Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice (including the next | ||
13 | * paragraph) shall be included in all copies or substantial portions of the | ||
14 | * Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
22 | * DEALINGS IN THE SOFTWARE. | ||
23 | * | ||
24 | * Authors: | ||
25 | * Eric Anholt <eric@anholt.net> | ||
26 | * Dave Airlie <airlied@linux.ie> | ||
27 | * Jesse Barnes <jesse.barnes@intel.com> | ||
28 | * Chris Wilson <chris@chris-wilson.co.uk> | ||
29 | */ | ||
30 | |||
31 | #include "intel_drv.h" | ||
32 | |||
33 | void | ||
34 | intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, | ||
35 | struct drm_display_mode *adjusted_mode) | ||
36 | { | ||
37 | adjusted_mode->hdisplay = fixed_mode->hdisplay; | ||
38 | adjusted_mode->hsync_start = fixed_mode->hsync_start; | ||
39 | adjusted_mode->hsync_end = fixed_mode->hsync_end; | ||
40 | adjusted_mode->htotal = fixed_mode->htotal; | ||
41 | |||
42 | adjusted_mode->vdisplay = fixed_mode->vdisplay; | ||
43 | adjusted_mode->vsync_start = fixed_mode->vsync_start; | ||
44 | adjusted_mode->vsync_end = fixed_mode->vsync_end; | ||
45 | adjusted_mode->vtotal = fixed_mode->vtotal; | ||
46 | |||
47 | adjusted_mode->clock = fixed_mode->clock; | ||
48 | |||
49 | drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | ||
50 | } | ||
51 | |||
52 | /* adjusted_mode has been preset to be the panel's fixed mode */ | ||
53 | void | ||
54 | intel_pch_panel_fitting(struct drm_device *dev, | ||
55 | int fitting_mode, | ||
56 | struct drm_display_mode *mode, | ||
57 | struct drm_display_mode *adjusted_mode) | ||
58 | { | ||
59 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
60 | int x, y, width, height; | ||
61 | |||
62 | x = y = width = height = 0; | ||
63 | |||
64 | /* Native modes don't need fitting */ | ||
65 | if (adjusted_mode->hdisplay == mode->hdisplay && | ||
66 | adjusted_mode->vdisplay == mode->vdisplay) | ||
67 | goto done; | ||
68 | |||
69 | switch (fitting_mode) { | ||
70 | case DRM_MODE_SCALE_CENTER: | ||
71 | width = mode->hdisplay; | ||
72 | height = mode->vdisplay; | ||
73 | x = (adjusted_mode->hdisplay - width + 1)/2; | ||
74 | y = (adjusted_mode->vdisplay - height + 1)/2; | ||
75 | break; | ||
76 | |||
77 | case DRM_MODE_SCALE_ASPECT: | ||
78 | /* Scale but preserve the aspect ratio */ | ||
79 | { | ||
80 | u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; | ||
81 | u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; | ||
82 | if (scaled_width > scaled_height) { /* pillar */ | ||
83 | width = scaled_height / mode->vdisplay; | ||
84 | x = (adjusted_mode->hdisplay - width + 1) / 2; | ||
85 | y = 0; | ||
86 | height = adjusted_mode->vdisplay; | ||
87 | } else if (scaled_width < scaled_height) { /* letter */ | ||
88 | height = scaled_width / mode->hdisplay; | ||
89 | y = (adjusted_mode->vdisplay - height + 1) / 2; | ||
90 | x = 0; | ||
91 | width = adjusted_mode->hdisplay; | ||
92 | } else { | ||
93 | x = y = 0; | ||
94 | width = adjusted_mode->hdisplay; | ||
95 | height = adjusted_mode->vdisplay; | ||
96 | } | ||
97 | } | ||
98 | break; | ||
99 | |||
100 | default: | ||
101 | case DRM_MODE_SCALE_FULLSCREEN: | ||
102 | x = y = 0; | ||
103 | width = adjusted_mode->hdisplay; | ||
104 | height = adjusted_mode->vdisplay; | ||
105 | break; | ||
106 | } | ||
107 | |||
108 | done: | ||
109 | dev_priv->pch_pf_pos = (x << 16) | y; | ||
110 | dev_priv->pch_pf_size = (width << 16) | height; | ||
111 | } | ||