aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_panel.c
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2013-04-25 15:55:01 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-04-25 16:16:22 -0400
commit2dd24552cab40ea829ba3fda890eeafd2c4816d8 (patch)
treefee957bf6e4c7824ffbd82125930f316634884b0 /drivers/gpu/drm/i915/intel_panel.c
parent198a037f02666eeaab5ba07974fa37467b1f6bd8 (diff)
drm/i915: factor out GMCH panel fitting code and use for eDP v3
This gets the panel fitter working on eDP on VLV, and should also apply to eDP panels on G4x chipsets (if we ever detect and mark an all-in-one panel as eDP anyway). A few cleanups are still possible on top of this, for example the LVDS border control could be placed in the LVDS encoder structure and updated based on the result of the panel fitter calculation. Multi-pipe fitting isn't handled correctly either if we ever get a config that wants to try the panel fitter on more than one output at a time. v2: use pipe_config for storing pfit values (Daniel) add i9xx_pfit_enable function for use by 9xx and VLV (Daniel) v3: fixup conflicts and lvds_dither check Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> [danvet: fix up botched conflict resolution from Jesse: - border = LVDS_BORDER_ENABLE was lost for CENTER scaling - comment about gen2/3 panel fitter scaling was lost - dev_priv->lvds_dither reintroduced.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_panel.c')
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c191
1 files changed, 191 insertions, 0 deletions
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
120static void
121centre_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
142static void
143centre_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
163static 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
176void 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
293out:
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
120static int is_backlight_combination_mode(struct drm_device *dev) 311static 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;