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