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