1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2024 Intel Corporation
4 */
5
6 #include <drm/drm_print.h>
7
8 #include "i915_reg.h"
9 #include "i915_utils.h"
10 #include "intel_de.h"
11 #include "intel_display_core.h"
12 #include "intel_display_driver.h"
13 #include "intel_display_types.h"
14 #include "intel_lvds_regs.h"
15 #include "intel_pfit.h"
16 #include "intel_pfit_regs.h"
17
intel_pch_pfit_check_dst_window(const struct intel_crtc_state * crtc_state)18 static int intel_pch_pfit_check_dst_window(const struct intel_crtc_state *crtc_state)
19 {
20 struct intel_display *display = to_intel_display(crtc_state);
21 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
22 const struct drm_display_mode *adjusted_mode =
23 &crtc_state->hw.adjusted_mode;
24 const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
25 int width = drm_rect_width(dst);
26 int height = drm_rect_height(dst);
27 int x = dst->x1;
28 int y = dst->y1;
29
30 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE &&
31 (y & 1 || height & 1)) {
32 drm_dbg_kms(display->drm,
33 "[CRTC:%d:%s] pfit window (" DRM_RECT_FMT ") misaligned for interlaced output\n",
34 crtc->base.base.id, crtc->base.name, DRM_RECT_ARG(dst));
35 return -EINVAL;
36 }
37
38 /*
39 * "Restriction : When pipe scaling is enabled, the scaled
40 * output must equal the pipe active area, so Pipe active
41 * size = (2 * PF window position) + PF window size."
42 *
43 * The vertical direction seems more forgiving than the
44 * horizontal direction, but still has some issues so
45 * let's follow the same hard rule for both.
46 */
47 if (adjusted_mode->crtc_hdisplay != 2 * x + width ||
48 adjusted_mode->crtc_vdisplay != 2 * y + height) {
49 drm_dbg_kms(display->drm,
50 "[CRTC:%d:%s] pfit window (" DRM_RECT_FMT ") not centered\n",
51 crtc->base.base.id, crtc->base.name, DRM_RECT_ARG(dst));
52 return -EINVAL;
53 }
54
55 /*
56 * "Restriction : The X position must not be programmed
57 * to be 1 (28:16=0 0000 0000 0001b)."
58 */
59 if (x == 1) {
60 drm_dbg_kms(display->drm,
61 "[CRTC:%d:%s] pfit window (" DRM_RECT_FMT ") badly positioned\n",
62 crtc->base.base.id, crtc->base.name, DRM_RECT_ARG(dst));
63 return -EINVAL;
64 }
65
66 return 0;
67 }
68
intel_pch_pfit_check_src_size(const struct intel_crtc_state * crtc_state)69 static int intel_pch_pfit_check_src_size(const struct intel_crtc_state *crtc_state)
70 {
71 struct intel_display *display = to_intel_display(crtc_state);
72 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
73 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
74 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
75 int max_src_w, max_src_h;
76
77 if (DISPLAY_VER(display) >= 8) {
78 max_src_w = 4096;
79 max_src_h = 4096;
80 } else if (DISPLAY_VER(display) >= 7) {
81 /*
82 * PF0 7x5 capable
83 * PF1 3x3 capable (could be switched to 7x5
84 * mode on HSW when PF2 unused)
85 * PF2 3x3 capable
86 *
87 * This assumes we use a 1:1 mapping between pipe and PF.
88 */
89 max_src_w = crtc->pipe == PIPE_A ? 4096 : 2048;
90 max_src_h = 4096;
91 } else {
92 max_src_w = 4096;
93 max_src_h = 4096;
94 }
95
96 if (pipe_src_w > max_src_w || pipe_src_h > max_src_h) {
97 drm_dbg_kms(display->drm,
98 "[CRTC:%d:%s] source size (%dx%d) exceeds pfit max (%dx%d)\n",
99 crtc->base.base.id, crtc->base.name,
100 pipe_src_w, pipe_src_h, max_src_w, max_src_h);
101 return -EINVAL;
102 }
103
104 return 0;
105 }
106
intel_pch_pfit_check_scaling(const struct intel_crtc_state * crtc_state)107 static int intel_pch_pfit_check_scaling(const struct intel_crtc_state *crtc_state)
108 {
109 struct intel_display *display = to_intel_display(crtc_state);
110 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
111 const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
112 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
113 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
114 int hscale, vscale, max_scale = 0x12000; /* 1.125 */
115 struct drm_rect src;
116
117 drm_rect_init(&src, 0, 0, pipe_src_w << 16, pipe_src_h << 16);
118
119 hscale = drm_rect_calc_hscale(&src, dst, 0, max_scale);
120 if (hscale < 0) {
121 drm_dbg_kms(display->drm,
122 "[CRTC:%d:%s] pfit horizontal downscaling (%d->%d) exceeds max (0x%x)\n",
123 crtc->base.base.id, crtc->base.name,
124 pipe_src_w, drm_rect_width(dst),
125 max_scale);
126 return hscale;
127 }
128
129 vscale = drm_rect_calc_vscale(&src, dst, 0, max_scale);
130 if (vscale < 0) {
131 drm_dbg_kms(display->drm,
132 "[CRTC:%d:%s] pfit vertical downscaling (%d->%d) exceeds max (0x%x)\n",
133 crtc->base.base.id, crtc->base.name,
134 pipe_src_h, drm_rect_height(dst),
135 max_scale);
136 return vscale;
137 }
138
139 return 0;
140 }
141
intel_pch_pfit_check_timings(const struct intel_crtc_state * crtc_state)142 static int intel_pch_pfit_check_timings(const struct intel_crtc_state *crtc_state)
143 {
144 struct intel_display *display = to_intel_display(crtc_state);
145 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
146 const struct drm_display_mode *adjusted_mode =
147 &crtc_state->hw.adjusted_mode;
148
149 if (adjusted_mode->crtc_vdisplay < 7) {
150 drm_dbg_kms(display->drm,
151 "[CRTC:%d:%s] vertical active (%d) below minimum (%d) for pfit\n",
152 crtc->base.base.id, crtc->base.name,
153 adjusted_mode->crtc_vdisplay, 7);
154 return -EINVAL;
155 }
156
157 return 0;
158 }
159
intel_pch_pfit_check_cloning(const struct intel_crtc_state * crtc_state)160 static int intel_pch_pfit_check_cloning(const struct intel_crtc_state *crtc_state)
161 {
162 struct intel_display *display = to_intel_display(crtc_state);
163 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
164
165 /*
166 * The panel fitter is in the pipe and thus would affect every
167 * cloned output. The relevant properties (scaling mode, TV
168 * margins) are per-connector so we'd have to make sure each
169 * output sets them up identically. Seems like a very niche use
170 * case so let's just reject cloning entirely when pfit is used.
171 */
172 if (crtc_state->uapi.encoder_mask &&
173 !is_power_of_2(crtc_state->uapi.encoder_mask)) {
174 drm_dbg_kms(display->drm,
175 "[CRTC:%d:%s] no pfit when cloning\n",
176 crtc->base.base.id, crtc->base.name);
177 return -EINVAL;
178 }
179
180 return 0;
181 }
182
183 /* adjusted_mode has been preset to be the panel's fixed mode */
pch_panel_fitting(struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)184 static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
185 const struct drm_connector_state *conn_state)
186 {
187 struct intel_display *display = to_intel_display(crtc_state);
188 const struct drm_display_mode *adjusted_mode =
189 &crtc_state->hw.adjusted_mode;
190 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
191 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
192 int ret, x, y, width, height;
193
194 /* Native modes don't need fitting */
195 if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
196 adjusted_mode->crtc_vdisplay == pipe_src_h &&
197 crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
198 return 0;
199
200 switch (conn_state->scaling_mode) {
201 case DRM_MODE_SCALE_CENTER:
202 width = pipe_src_w;
203 height = pipe_src_h;
204 x = (adjusted_mode->crtc_hdisplay - width + 1)/2;
205 y = (adjusted_mode->crtc_vdisplay - height + 1)/2;
206 break;
207
208 case DRM_MODE_SCALE_ASPECT:
209 /* Scale but preserve the aspect ratio */
210 {
211 u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
212 u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
213
214 if (scaled_width > scaled_height) { /* pillar */
215 width = scaled_height / pipe_src_h;
216 if (width & 1)
217 width++;
218 x = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
219 y = 0;
220 height = adjusted_mode->crtc_vdisplay;
221 } else if (scaled_width < scaled_height) { /* letter */
222 height = scaled_width / pipe_src_w;
223 if (height & 1)
224 height++;
225 y = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
226 x = 0;
227 width = adjusted_mode->crtc_hdisplay;
228 } else {
229 x = y = 0;
230 width = adjusted_mode->crtc_hdisplay;
231 height = adjusted_mode->crtc_vdisplay;
232 }
233 }
234 break;
235
236 case DRM_MODE_SCALE_NONE:
237 WARN_ON(adjusted_mode->crtc_hdisplay != pipe_src_w);
238 WARN_ON(adjusted_mode->crtc_vdisplay != pipe_src_h);
239 fallthrough;
240 case DRM_MODE_SCALE_FULLSCREEN:
241 x = y = 0;
242 width = adjusted_mode->crtc_hdisplay;
243 height = adjusted_mode->crtc_vdisplay;
244 break;
245
246 default:
247 MISSING_CASE(conn_state->scaling_mode);
248 return -EINVAL;
249 }
250
251 drm_rect_init(&crtc_state->pch_pfit.dst,
252 x, y, width, height);
253 crtc_state->pch_pfit.enabled = true;
254
255 /*
256 * SKL+ have unified scalers for pipes/planes so the
257 * checks are done in a single place for all scalers.
258 */
259 if (DISPLAY_VER(display) >= 9)
260 return 0;
261
262 ret = intel_pch_pfit_check_dst_window(crtc_state);
263 if (ret)
264 return ret;
265
266 ret = intel_pch_pfit_check_src_size(crtc_state);
267 if (ret)
268 return ret;
269
270 ret = intel_pch_pfit_check_scaling(crtc_state);
271 if (ret)
272 return ret;
273
274 ret = intel_pch_pfit_check_timings(crtc_state);
275 if (ret)
276 return ret;
277
278 ret = intel_pch_pfit_check_cloning(crtc_state);
279 if (ret)
280 return ret;
281
282 return 0;
283 }
284
285 static void
centre_horizontally(struct drm_display_mode * adjusted_mode,int width)286 centre_horizontally(struct drm_display_mode *adjusted_mode,
287 int width)
288 {
289 u32 border, sync_pos, blank_width, sync_width;
290
291 /* keep the hsync and hblank widths constant */
292 sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
293 blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
294 sync_pos = (blank_width - sync_width + 1) / 2;
295
296 border = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
297 border += border & 1; /* make the border even */
298
299 adjusted_mode->crtc_hdisplay = width;
300 adjusted_mode->crtc_hblank_start = width + border;
301 adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width;
302
303 adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos;
304 adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width;
305 }
306
307 static void
centre_vertically(struct drm_display_mode * adjusted_mode,int height)308 centre_vertically(struct drm_display_mode *adjusted_mode,
309 int height)
310 {
311 u32 border, sync_pos, blank_width, sync_width;
312
313 /* keep the vsync and vblank widths constant */
314 sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
315 blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start;
316 sync_pos = (blank_width - sync_width + 1) / 2;
317
318 border = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
319
320 adjusted_mode->crtc_vdisplay = height;
321 adjusted_mode->crtc_vblank_start = height + border;
322 adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width;
323
324 adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos;
325 adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width;
326 }
327
panel_fitter_scaling(u32 source,u32 target)328 static u32 panel_fitter_scaling(u32 source, u32 target)
329 {
330 /*
331 * Floating point operation is not supported. So the FACTOR
332 * is defined, which can avoid the floating point computation
333 * when calculating the panel ratio.
334 */
335 #define ACCURACY 12
336 #define FACTOR (1 << ACCURACY)
337 u32 ratio = source * FACTOR / target;
338 return (FACTOR * ratio + FACTOR/2) / FACTOR;
339 }
340
i965_scale_aspect(struct intel_crtc_state * crtc_state,u32 * pfit_control)341 static void i965_scale_aspect(struct intel_crtc_state *crtc_state,
342 u32 *pfit_control)
343 {
344 const struct drm_display_mode *adjusted_mode =
345 &crtc_state->hw.adjusted_mode;
346 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
347 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
348 u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
349 u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
350
351 /* 965+ is easy, it does everything in hw */
352 if (scaled_width > scaled_height)
353 *pfit_control |= PFIT_ENABLE |
354 PFIT_SCALING_PILLAR;
355 else if (scaled_width < scaled_height)
356 *pfit_control |= PFIT_ENABLE |
357 PFIT_SCALING_LETTER;
358 else if (adjusted_mode->crtc_hdisplay != pipe_src_w)
359 *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
360 }
361
i9xx_scale_aspect(struct intel_crtc_state * crtc_state,u32 * pfit_control,u32 * pfit_pgm_ratios,u32 * border)362 static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
363 u32 *pfit_control, u32 *pfit_pgm_ratios,
364 u32 *border)
365 {
366 struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
367 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
368 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
369 u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
370 u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
371 u32 bits;
372
373 /*
374 * For earlier chips we have to calculate the scaling
375 * ratio by hand and program it into the
376 * PFIT_PGM_RATIO register
377 */
378 if (scaled_width > scaled_height) { /* pillar */
379 centre_horizontally(adjusted_mode,
380 scaled_height / pipe_src_h);
381
382 *border = LVDS_BORDER_ENABLE;
383 if (pipe_src_h != adjusted_mode->crtc_vdisplay) {
384 bits = panel_fitter_scaling(pipe_src_h,
385 adjusted_mode->crtc_vdisplay);
386
387 *pfit_pgm_ratios |= (PFIT_HORIZ_SCALE(bits) |
388 PFIT_VERT_SCALE(bits));
389 *pfit_control |= (PFIT_ENABLE |
390 PFIT_VERT_INTERP_BILINEAR |
391 PFIT_HORIZ_INTERP_BILINEAR);
392 }
393 } else if (scaled_width < scaled_height) { /* letter */
394 centre_vertically(adjusted_mode,
395 scaled_width / pipe_src_w);
396
397 *border = LVDS_BORDER_ENABLE;
398 if (pipe_src_w != adjusted_mode->crtc_hdisplay) {
399 bits = panel_fitter_scaling(pipe_src_w,
400 adjusted_mode->crtc_hdisplay);
401
402 *pfit_pgm_ratios |= (PFIT_HORIZ_SCALE(bits) |
403 PFIT_VERT_SCALE(bits));
404 *pfit_control |= (PFIT_ENABLE |
405 PFIT_VERT_INTERP_BILINEAR |
406 PFIT_HORIZ_INTERP_BILINEAR);
407 }
408 } else {
409 /* Aspects match, Let hw scale both directions */
410 *pfit_control |= (PFIT_ENABLE |
411 PFIT_VERT_AUTO_SCALE |
412 PFIT_HORIZ_AUTO_SCALE |
413 PFIT_VERT_INTERP_BILINEAR |
414 PFIT_HORIZ_INTERP_BILINEAR);
415 }
416 }
417
intel_gmch_pfit_check_timings(const struct intel_crtc_state * crtc_state)418 static int intel_gmch_pfit_check_timings(const struct intel_crtc_state *crtc_state)
419 {
420 struct intel_display *display = to_intel_display(crtc_state);
421 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
422 const struct drm_display_mode *adjusted_mode =
423 &crtc_state->hw.adjusted_mode;
424 int min;
425
426 if (DISPLAY_VER(display) >= 4)
427 min = 3;
428 else
429 min = 2;
430
431 if (adjusted_mode->crtc_hdisplay < min) {
432 drm_dbg_kms(display->drm,
433 "[CRTC:%d:%s] horizontal active (%d) below minimum (%d) for pfit\n",
434 crtc->base.base.id, crtc->base.name,
435 adjusted_mode->crtc_hdisplay, min);
436 return -EINVAL;
437 }
438
439 if (adjusted_mode->crtc_vdisplay < min) {
440 drm_dbg_kms(display->drm,
441 "[CRTC:%d:%s] vertical active (%d) below minimum (%d) for pfit\n",
442 crtc->base.base.id, crtc->base.name,
443 adjusted_mode->crtc_vdisplay, min);
444 return -EINVAL;
445 }
446
447 return 0;
448 }
449
gmch_panel_fitting(struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)450 static int gmch_panel_fitting(struct intel_crtc_state *crtc_state,
451 const struct drm_connector_state *conn_state)
452 {
453 struct intel_display *display = to_intel_display(crtc_state);
454 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
455 u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
456 struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
457 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
458 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
459
460 /* Native modes don't need fitting */
461 if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
462 adjusted_mode->crtc_vdisplay == pipe_src_h)
463 goto out;
464
465 /*
466 * TODO: implement downscaling for i965+. Need to account
467 * for downscaling in intel_crtc_compute_pixel_rate().
468 */
469 if (adjusted_mode->crtc_hdisplay < pipe_src_w) {
470 drm_dbg_kms(display->drm,
471 "[CRTC:%d:%s] pfit horizontal downscaling (%d->%d) not supported\n",
472 crtc->base.base.id, crtc->base.name,
473 pipe_src_w, adjusted_mode->crtc_hdisplay);
474 return -EINVAL;
475 }
476 if (adjusted_mode->crtc_vdisplay < pipe_src_h) {
477 drm_dbg_kms(display->drm,
478 "[CRTC:%d:%s] pfit vertical downscaling (%d->%d) not supported\n",
479 crtc->base.base.id, crtc->base.name,
480 pipe_src_h, adjusted_mode->crtc_vdisplay);
481 return -EINVAL;
482 }
483
484 switch (conn_state->scaling_mode) {
485 case DRM_MODE_SCALE_CENTER:
486 /*
487 * For centered modes, we have to calculate border widths &
488 * heights and modify the values programmed into the CRTC.
489 */
490 centre_horizontally(adjusted_mode, pipe_src_w);
491 centre_vertically(adjusted_mode, pipe_src_h);
492 border = LVDS_BORDER_ENABLE;
493 break;
494 case DRM_MODE_SCALE_ASPECT:
495 /* Scale but preserve the aspect ratio */
496 if (DISPLAY_VER(display) >= 4)
497 i965_scale_aspect(crtc_state, &pfit_control);
498 else
499 i9xx_scale_aspect(crtc_state, &pfit_control,
500 &pfit_pgm_ratios, &border);
501 break;
502 case DRM_MODE_SCALE_FULLSCREEN:
503 /*
504 * Full scaling, even if it changes the aspect ratio.
505 * Fortunately this is all done for us in hw.
506 */
507 if (pipe_src_h != adjusted_mode->crtc_vdisplay ||
508 pipe_src_w != adjusted_mode->crtc_hdisplay) {
509 pfit_control |= PFIT_ENABLE;
510 if (DISPLAY_VER(display) >= 4)
511 pfit_control |= PFIT_SCALING_AUTO;
512 else
513 pfit_control |= (PFIT_VERT_AUTO_SCALE |
514 PFIT_VERT_INTERP_BILINEAR |
515 PFIT_HORIZ_AUTO_SCALE |
516 PFIT_HORIZ_INTERP_BILINEAR);
517 }
518 break;
519 default:
520 MISSING_CASE(conn_state->scaling_mode);
521 return -EINVAL;
522 }
523
524 /* 965+ wants fuzzy fitting */
525 /* FIXME: handle multiple panels by failing gracefully */
526 if (DISPLAY_VER(display) >= 4)
527 pfit_control |= PFIT_PIPE(crtc->pipe) | PFIT_FILTER_FUZZY;
528
529 out:
530 if ((pfit_control & PFIT_ENABLE) == 0) {
531 pfit_control = 0;
532 pfit_pgm_ratios = 0;
533 }
534
535 /* Make sure pre-965 set dither correctly for 18bpp panels. */
536 if (DISPLAY_VER(display) < 4 && crtc_state->pipe_bpp == 18)
537 pfit_control |= PFIT_PANEL_8TO6_DITHER_ENABLE;
538
539 crtc_state->gmch_pfit.control = pfit_control;
540 crtc_state->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
541 crtc_state->gmch_pfit.lvds_border_bits = border;
542
543 if ((pfit_control & PFIT_ENABLE) == 0)
544 return 0;
545
546 return intel_gmch_pfit_check_timings(crtc_state);
547 }
548
intel_pfit_compute_config(struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)549 int intel_pfit_compute_config(struct intel_crtc_state *crtc_state,
550 const struct drm_connector_state *conn_state)
551 {
552 struct intel_display *display = to_intel_display(crtc_state);
553
554 if (HAS_GMCH(display))
555 return gmch_panel_fitting(crtc_state, conn_state);
556 else
557 return pch_panel_fitting(crtc_state, conn_state);
558 }
559
ilk_pfit_enable(const struct intel_crtc_state * crtc_state)560 void ilk_pfit_enable(const struct intel_crtc_state *crtc_state)
561 {
562 struct intel_display *display = to_intel_display(crtc_state);
563 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
564 const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
565 enum pipe pipe = crtc->pipe;
566 int width = drm_rect_width(dst);
567 int height = drm_rect_height(dst);
568 int x = dst->x1;
569 int y = dst->y1;
570
571 if (!crtc_state->pch_pfit.enabled)
572 return;
573
574 /*
575 * Force use of hard-coded filter coefficients as some pre-programmed
576 * values are broken, e.g. x201.
577 */
578 if (display->platform.ivybridge || display->platform.haswell)
579 intel_de_write_fw(display, PF_CTL(pipe), PF_ENABLE |
580 PF_FILTER_MED_3x3 | PF_PIPE_SEL_IVB(pipe));
581 else
582 intel_de_write_fw(display, PF_CTL(pipe), PF_ENABLE |
583 PF_FILTER_MED_3x3);
584 intel_de_write_fw(display, PF_WIN_POS(pipe),
585 PF_WIN_XPOS(x) | PF_WIN_YPOS(y));
586 intel_de_write_fw(display, PF_WIN_SZ(pipe),
587 PF_WIN_XSIZE(width) | PF_WIN_YSIZE(height));
588 }
589
ilk_pfit_disable(const struct intel_crtc_state * old_crtc_state)590 void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state)
591 {
592 struct intel_display *display = to_intel_display(old_crtc_state);
593 struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
594 enum pipe pipe = crtc->pipe;
595
596 /*
597 * To avoid upsetting the power well on haswell only disable the pfit if
598 * it's in use. The hw state code will make sure we get this right.
599 */
600 if (!old_crtc_state->pch_pfit.enabled)
601 return;
602
603 intel_de_write_fw(display, PF_CTL(pipe), 0);
604 intel_de_write_fw(display, PF_WIN_POS(pipe), 0);
605 intel_de_write_fw(display, PF_WIN_SZ(pipe), 0);
606 }
607
ilk_pfit_get_config(struct intel_crtc_state * crtc_state)608 void ilk_pfit_get_config(struct intel_crtc_state *crtc_state)
609 {
610 struct intel_display *display = to_intel_display(crtc_state);
611 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
612 u32 ctl, pos, size;
613 enum pipe pipe;
614
615 ctl = intel_de_read(display, PF_CTL(crtc->pipe));
616 if ((ctl & PF_ENABLE) == 0)
617 return;
618
619 if (display->platform.ivybridge || display->platform.haswell)
620 pipe = REG_FIELD_GET(PF_PIPE_SEL_MASK_IVB, ctl);
621 else
622 pipe = crtc->pipe;
623
624 crtc_state->pch_pfit.enabled = true;
625
626 pos = intel_de_read(display, PF_WIN_POS(crtc->pipe));
627 size = intel_de_read(display, PF_WIN_SZ(crtc->pipe));
628
629 drm_rect_init(&crtc_state->pch_pfit.dst,
630 REG_FIELD_GET(PF_WIN_XPOS_MASK, pos),
631 REG_FIELD_GET(PF_WIN_YPOS_MASK, pos),
632 REG_FIELD_GET(PF_WIN_XSIZE_MASK, size),
633 REG_FIELD_GET(PF_WIN_YSIZE_MASK, size));
634
635 /*
636 * We currently do not free assignments of panel fitters on
637 * ivb/hsw (since we don't use the higher upscaling modes which
638 * differentiates them) so just WARN about this case for now.
639 */
640 drm_WARN_ON(display->drm, pipe != crtc->pipe);
641 }
642
i9xx_pfit_enable(const struct intel_crtc_state * crtc_state)643 void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state)
644 {
645 struct intel_display *display = to_intel_display(crtc_state);
646 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
647
648 if (!crtc_state->gmch_pfit.control)
649 return;
650
651 /*
652 * The panel fitter should only be adjusted whilst the pipe is disabled,
653 * according to register description and PRM.
654 */
655 drm_WARN_ON(display->drm,
656 intel_de_read(display, PFIT_CONTROL(display)) & PFIT_ENABLE);
657 assert_transcoder_disabled(display, crtc_state->cpu_transcoder);
658
659 intel_de_write(display, PFIT_PGM_RATIOS(display),
660 crtc_state->gmch_pfit.pgm_ratios);
661 intel_de_write(display, PFIT_CONTROL(display),
662 crtc_state->gmch_pfit.control);
663
664 /*
665 * Border color in case we don't scale up to the full screen. Black by
666 * default, change to something else for debugging.
667 */
668 intel_de_write(display, BCLRPAT(display, crtc->pipe), 0);
669 }
670
i9xx_pfit_disable(const struct intel_crtc_state * old_crtc_state)671 void i9xx_pfit_disable(const struct intel_crtc_state *old_crtc_state)
672 {
673 struct intel_display *display = to_intel_display(old_crtc_state);
674
675 if (!old_crtc_state->gmch_pfit.control)
676 return;
677
678 assert_transcoder_disabled(display, old_crtc_state->cpu_transcoder);
679
680 drm_dbg_kms(display->drm, "disabling pfit, current: 0x%08x\n",
681 intel_de_read(display, PFIT_CONTROL(display)));
682 intel_de_write(display, PFIT_CONTROL(display), 0);
683 }
684
i9xx_has_pfit(struct intel_display * display)685 static bool i9xx_has_pfit(struct intel_display *display)
686 {
687 if (display->platform.i830)
688 return false;
689
690 return DISPLAY_VER(display) >= 4 ||
691 display->platform.pineview || display->platform.mobile;
692 }
693
i9xx_pfit_get_config(struct intel_crtc_state * crtc_state)694 void i9xx_pfit_get_config(struct intel_crtc_state *crtc_state)
695 {
696 struct intel_display *display = to_intel_display(crtc_state);
697 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
698 enum pipe pipe;
699 u32 tmp;
700
701 if (!i9xx_has_pfit(display))
702 return;
703
704 tmp = intel_de_read(display, PFIT_CONTROL(display));
705 if (!(tmp & PFIT_ENABLE))
706 return;
707
708 /* Check whether the pfit is attached to our pipe. */
709 if (DISPLAY_VER(display) >= 4)
710 pipe = REG_FIELD_GET(PFIT_PIPE_MASK, tmp);
711 else
712 pipe = PIPE_B;
713
714 if (pipe != crtc->pipe)
715 return;
716
717 crtc_state->gmch_pfit.control = tmp;
718 crtc_state->gmch_pfit.pgm_ratios =
719 intel_de_read(display, PFIT_PGM_RATIOS(display));
720 }
721