xref: /linux/drivers/gpu/drm/i915/display/intel_pfit.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2024 Intel Corporation
4  */
5 
6 #include "i915_drv.h"
7 #include "i915_reg.h"
8 #include "intel_display_core.h"
9 #include "intel_display_driver.h"
10 #include "intel_display_types.h"
11 #include "intel_lvds_regs.h"
12 #include "intel_pfit.h"
13 
14 static int intel_pch_pfit_check_dst_window(const struct intel_crtc_state *crtc_state)
15 {
16 	struct intel_display *display = to_intel_display(crtc_state);
17 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
18 	const struct drm_display_mode *adjusted_mode =
19 		&crtc_state->hw.adjusted_mode;
20 	const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
21 	int width = drm_rect_width(dst);
22 	int height = drm_rect_height(dst);
23 	int x = dst->x1;
24 	int y = dst->y1;
25 
26 	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE &&
27 	    (y & 1 || height & 1)) {
28 		drm_dbg_kms(display->drm,
29 			    "[CRTC:%d:%s] pfit window (" DRM_RECT_FMT ") misaligned for interlaced output\n",
30 			    crtc->base.base.id, crtc->base.name, DRM_RECT_ARG(dst));
31 		return -EINVAL;
32 	}
33 
34 	/*
35 	 * "Restriction : When pipe scaling is enabled, the scaled
36 	 *  output must equal the pipe active area, so Pipe active
37 	 *  size = (2 * PF window position) + PF window size."
38 	 *
39 	 * The vertical direction seems more forgiving than the
40 	 * horizontal direction, but still has some issues so
41 	 * let's follow the same hard rule for both.
42 	 */
43 	if (adjusted_mode->crtc_hdisplay != 2 * x + width ||
44 	    adjusted_mode->crtc_vdisplay != 2 * y + height) {
45 		drm_dbg_kms(display->drm,
46 			    "[CRTC:%d:%s] pfit window (" DRM_RECT_FMT ") not centered\n",
47 			    crtc->base.base.id, crtc->base.name, DRM_RECT_ARG(dst));
48 		return -EINVAL;
49 	}
50 
51 	/*
52 	 * "Restriction : The X position must not be programmed
53 	 *  to be 1 (28:16=0 0000 0000 0001b)."
54 	 */
55 	if (x == 1) {
56 		drm_dbg_kms(display->drm,
57 			    "[CRTC:%d:%s] pfit window (" DRM_RECT_FMT ") badly positioned\n",
58 			    crtc->base.base.id, crtc->base.name, DRM_RECT_ARG(dst));
59 		return -EINVAL;
60 	}
61 
62 	return 0;
63 }
64 
65 static int intel_pch_pfit_check_src_size(const struct intel_crtc_state *crtc_state)
66 {
67 	struct intel_display *display = to_intel_display(crtc_state);
68 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
69 	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
70 	int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
71 	int max_src_w, max_src_h;
72 
73 	if (DISPLAY_VER(display) >= 8) {
74 		max_src_w = 4096;
75 		max_src_h = 4096;
76 	} else if (DISPLAY_VER(display) >= 7) {
77 		/*
78 		 * PF0 7x5 capable
79 		 * PF1 3x3 capable (could be switched to 7x5
80 		 *                  mode on HSW when PF2 unused)
81 		 * PF2 3x3 capable
82 		 *
83 		 * This assumes we use a 1:1 mapping between pipe and PF.
84 		 */
85 		max_src_w = crtc->pipe == PIPE_A ? 4096 : 2048;
86 		max_src_h = 4096;
87 	} else {
88 		max_src_w = 4096;
89 		max_src_h = 4096;
90 	}
91 
92 	if (pipe_src_w > max_src_w || pipe_src_h > max_src_h) {
93 		drm_dbg_kms(display->drm,
94 			    "[CRTC:%d:%s] source size (%dx%d) exceeds pfit max (%dx%d)\n",
95 			    crtc->base.base.id, crtc->base.name,
96 			    pipe_src_w, pipe_src_h, max_src_w, max_src_h);
97 		return -EINVAL;
98 	}
99 
100 	return 0;
101 }
102 
103 static int intel_pch_pfit_check_scaling(const struct intel_crtc_state *crtc_state)
104 {
105 	struct intel_display *display = to_intel_display(crtc_state);
106 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
107 	const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
108 	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
109 	int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
110 	int hscale, vscale, max_scale = 0x12000; /* 1.125 */
111 	struct drm_rect src;
112 
113 	drm_rect_init(&src, 0, 0, pipe_src_w << 16, pipe_src_h << 16);
114 
115 	hscale = drm_rect_calc_hscale(&src, dst, 0, max_scale);
116 	if (hscale < 0) {
117 		drm_dbg_kms(display->drm,
118 			    "[CRTC:%d:%s] pfit horizontal downscaling (%d->%d) exceeds max (0x%x)\n",
119 			    crtc->base.base.id, crtc->base.name,
120 			    pipe_src_w, drm_rect_width(dst),
121 			    max_scale);
122 		return hscale;
123 	}
124 
125 	vscale = drm_rect_calc_vscale(&src, dst, 0, max_scale);
126 	if (vscale < 0) {
127 		drm_dbg_kms(display->drm,
128 			    "[CRTC:%d:%s] pfit vertical downscaling (%d->%d) exceeds max (0x%x)\n",
129 			    crtc->base.base.id, crtc->base.name,
130 			    pipe_src_h, drm_rect_height(dst),
131 			    max_scale);
132 		return vscale;
133 	}
134 
135 	return 0;
136 }
137 
138 static int intel_pch_pfit_check_timings(const struct intel_crtc_state *crtc_state)
139 {
140 	struct intel_display *display = to_intel_display(crtc_state);
141 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
142 	const struct drm_display_mode *adjusted_mode =
143 		&crtc_state->hw.adjusted_mode;
144 
145 	if (adjusted_mode->crtc_vdisplay < 7) {
146 		drm_dbg_kms(display->drm,
147 			    "[CRTC:%d:%s] vertical active (%d) below minimum (%d) for pfit\n",
148 			    crtc->base.base.id, crtc->base.name,
149 			    adjusted_mode->crtc_vdisplay, 7);
150 		return -EINVAL;
151 	}
152 
153 	return 0;
154 }
155 
156 static int intel_pch_pfit_check_cloning(const struct intel_crtc_state *crtc_state)
157 {
158 	struct intel_display *display = to_intel_display(crtc_state);
159 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
160 
161 	/*
162 	 * The panel fitter is in the pipe and thus would affect every
163 	 * cloned output. The relevant properties (scaling mode, TV
164 	 * margins) are per-connector so we'd have to make sure each
165 	 * output sets them up identically. Seems like a very niche use
166 	 * case so let's just reject cloning entirely when pfit is used.
167 	 */
168 	if (crtc_state->uapi.encoder_mask &&
169 	    !is_power_of_2(crtc_state->uapi.encoder_mask)) {
170 		drm_dbg_kms(display->drm,
171 			    "[CRTC:%d:%s] no pfit when cloning\n",
172 			    crtc->base.base.id, crtc->base.name);
173 		return -EINVAL;
174 	}
175 
176 	return 0;
177 }
178 
179 /* adjusted_mode has been preset to be the panel's fixed mode */
180 static int pch_panel_fitting(struct intel_crtc_state *crtc_state,
181 			     const struct drm_connector_state *conn_state)
182 {
183 	struct intel_display *display = to_intel_display(crtc_state);
184 	const struct drm_display_mode *adjusted_mode =
185 		&crtc_state->hw.adjusted_mode;
186 	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
187 	int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
188 	int ret, x, y, width, height;
189 
190 	/* Native modes don't need fitting */
191 	if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
192 	    adjusted_mode->crtc_vdisplay == pipe_src_h &&
193 	    crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
194 		return 0;
195 
196 	switch (conn_state->scaling_mode) {
197 	case DRM_MODE_SCALE_CENTER:
198 		width = pipe_src_w;
199 		height = pipe_src_h;
200 		x = (adjusted_mode->crtc_hdisplay - width + 1)/2;
201 		y = (adjusted_mode->crtc_vdisplay - height + 1)/2;
202 		break;
203 
204 	case DRM_MODE_SCALE_ASPECT:
205 		/* Scale but preserve the aspect ratio */
206 		{
207 			u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
208 			u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
209 
210 			if (scaled_width > scaled_height) { /* pillar */
211 				width = scaled_height / pipe_src_h;
212 				if (width & 1)
213 					width++;
214 				x = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
215 				y = 0;
216 				height = adjusted_mode->crtc_vdisplay;
217 			} else if (scaled_width < scaled_height) { /* letter */
218 				height = scaled_width / pipe_src_w;
219 				if (height & 1)
220 					height++;
221 				y = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
222 				x = 0;
223 				width = adjusted_mode->crtc_hdisplay;
224 			} else {
225 				x = y = 0;
226 				width = adjusted_mode->crtc_hdisplay;
227 				height = adjusted_mode->crtc_vdisplay;
228 			}
229 		}
230 		break;
231 
232 	case DRM_MODE_SCALE_NONE:
233 		WARN_ON(adjusted_mode->crtc_hdisplay != pipe_src_w);
234 		WARN_ON(adjusted_mode->crtc_vdisplay != pipe_src_h);
235 		fallthrough;
236 	case DRM_MODE_SCALE_FULLSCREEN:
237 		x = y = 0;
238 		width = adjusted_mode->crtc_hdisplay;
239 		height = adjusted_mode->crtc_vdisplay;
240 		break;
241 
242 	default:
243 		MISSING_CASE(conn_state->scaling_mode);
244 		return -EINVAL;
245 	}
246 
247 	drm_rect_init(&crtc_state->pch_pfit.dst,
248 		      x, y, width, height);
249 	crtc_state->pch_pfit.enabled = true;
250 
251 	/*
252 	 * SKL+ have unified scalers for pipes/planes so the
253 	 * checks are done in a single place for all scalers.
254 	 */
255 	if (DISPLAY_VER(display) >= 9)
256 		return 0;
257 
258 	ret = intel_pch_pfit_check_dst_window(crtc_state);
259 	if (ret)
260 		return ret;
261 
262 	ret = intel_pch_pfit_check_src_size(crtc_state);
263 	if (ret)
264 		return ret;
265 
266 	ret = intel_pch_pfit_check_scaling(crtc_state);
267 	if (ret)
268 		return ret;
269 
270 	ret = intel_pch_pfit_check_timings(crtc_state);
271 	if (ret)
272 		return ret;
273 
274 	ret = intel_pch_pfit_check_cloning(crtc_state);
275 	if (ret)
276 		return ret;
277 
278 	return 0;
279 }
280 
281 static void
282 centre_horizontally(struct drm_display_mode *adjusted_mode,
283 		    int width)
284 {
285 	u32 border, sync_pos, blank_width, sync_width;
286 
287 	/* keep the hsync and hblank widths constant */
288 	sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
289 	blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
290 	sync_pos = (blank_width - sync_width + 1) / 2;
291 
292 	border = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
293 	border += border & 1; /* make the border even */
294 
295 	adjusted_mode->crtc_hdisplay = width;
296 	adjusted_mode->crtc_hblank_start = width + border;
297 	adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width;
298 
299 	adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos;
300 	adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width;
301 }
302 
303 static void
304 centre_vertically(struct drm_display_mode *adjusted_mode,
305 		  int height)
306 {
307 	u32 border, sync_pos, blank_width, sync_width;
308 
309 	/* keep the vsync and vblank widths constant */
310 	sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
311 	blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start;
312 	sync_pos = (blank_width - sync_width + 1) / 2;
313 
314 	border = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
315 
316 	adjusted_mode->crtc_vdisplay = height;
317 	adjusted_mode->crtc_vblank_start = height + border;
318 	adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width;
319 
320 	adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos;
321 	adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width;
322 }
323 
324 static u32 panel_fitter_scaling(u32 source, u32 target)
325 {
326 	/*
327 	 * Floating point operation is not supported. So the FACTOR
328 	 * is defined, which can avoid the floating point computation
329 	 * when calculating the panel ratio.
330 	 */
331 #define ACCURACY 12
332 #define FACTOR (1 << ACCURACY)
333 	u32 ratio = source * FACTOR / target;
334 	return (FACTOR * ratio + FACTOR/2) / FACTOR;
335 }
336 
337 static void i965_scale_aspect(struct intel_crtc_state *crtc_state,
338 			      u32 *pfit_control)
339 {
340 	const struct drm_display_mode *adjusted_mode =
341 		&crtc_state->hw.adjusted_mode;
342 	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
343 	int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
344 	u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
345 	u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
346 
347 	/* 965+ is easy, it does everything in hw */
348 	if (scaled_width > scaled_height)
349 		*pfit_control |= PFIT_ENABLE |
350 			PFIT_SCALING_PILLAR;
351 	else if (scaled_width < scaled_height)
352 		*pfit_control |= PFIT_ENABLE |
353 			PFIT_SCALING_LETTER;
354 	else if (adjusted_mode->crtc_hdisplay != pipe_src_w)
355 		*pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
356 }
357 
358 static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state,
359 			      u32 *pfit_control, u32 *pfit_pgm_ratios,
360 			      u32 *border)
361 {
362 	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
363 	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
364 	int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
365 	u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h;
366 	u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay;
367 	u32 bits;
368 
369 	/*
370 	 * For earlier chips we have to calculate the scaling
371 	 * ratio by hand and program it into the
372 	 * PFIT_PGM_RATIO register
373 	 */
374 	if (scaled_width > scaled_height) { /* pillar */
375 		centre_horizontally(adjusted_mode,
376 				    scaled_height / pipe_src_h);
377 
378 		*border = LVDS_BORDER_ENABLE;
379 		if (pipe_src_h != adjusted_mode->crtc_vdisplay) {
380 			bits = panel_fitter_scaling(pipe_src_h,
381 						    adjusted_mode->crtc_vdisplay);
382 
383 			*pfit_pgm_ratios |= (PFIT_HORIZ_SCALE(bits) |
384 					     PFIT_VERT_SCALE(bits));
385 			*pfit_control |= (PFIT_ENABLE |
386 					  PFIT_VERT_INTERP_BILINEAR |
387 					  PFIT_HORIZ_INTERP_BILINEAR);
388 		}
389 	} else if (scaled_width < scaled_height) { /* letter */
390 		centre_vertically(adjusted_mode,
391 				  scaled_width / pipe_src_w);
392 
393 		*border = LVDS_BORDER_ENABLE;
394 		if (pipe_src_w != adjusted_mode->crtc_hdisplay) {
395 			bits = panel_fitter_scaling(pipe_src_w,
396 						    adjusted_mode->crtc_hdisplay);
397 
398 			*pfit_pgm_ratios |= (PFIT_HORIZ_SCALE(bits) |
399 					     PFIT_VERT_SCALE(bits));
400 			*pfit_control |= (PFIT_ENABLE |
401 					  PFIT_VERT_INTERP_BILINEAR |
402 					  PFIT_HORIZ_INTERP_BILINEAR);
403 		}
404 	} else {
405 		/* Aspects match, Let hw scale both directions */
406 		*pfit_control |= (PFIT_ENABLE |
407 				  PFIT_VERT_AUTO_SCALE |
408 				  PFIT_HORIZ_AUTO_SCALE |
409 				  PFIT_VERT_INTERP_BILINEAR |
410 				  PFIT_HORIZ_INTERP_BILINEAR);
411 	}
412 }
413 
414 static int intel_gmch_pfit_check_timings(const struct intel_crtc_state *crtc_state)
415 {
416 	struct intel_display *display = to_intel_display(crtc_state);
417 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
418 	const struct drm_display_mode *adjusted_mode =
419 		&crtc_state->hw.adjusted_mode;
420 	int min;
421 
422 	if (DISPLAY_VER(display) >= 4)
423 		min = 3;
424 	else
425 		min = 2;
426 
427 	if (adjusted_mode->crtc_hdisplay < min) {
428 		drm_dbg_kms(display->drm,
429 			    "[CRTC:%d:%s] horizontal active (%d) below minimum (%d) for pfit\n",
430 			    crtc->base.base.id, crtc->base.name,
431 			    adjusted_mode->crtc_hdisplay, min);
432 		return -EINVAL;
433 	}
434 
435 	if (adjusted_mode->crtc_vdisplay < min) {
436 		drm_dbg_kms(display->drm,
437 			    "[CRTC:%d:%s] vertical active (%d) below minimum (%d) for pfit\n",
438 			    crtc->base.base.id, crtc->base.name,
439 			    adjusted_mode->crtc_vdisplay, min);
440 		return -EINVAL;
441 	}
442 
443 	return 0;
444 }
445 
446 static int gmch_panel_fitting(struct intel_crtc_state *crtc_state,
447 			      const struct drm_connector_state *conn_state)
448 {
449 	struct intel_display *display = to_intel_display(crtc_state);
450 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
451 	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
452 	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
453 	int pipe_src_w = drm_rect_width(&crtc_state->pipe_src);
454 	int pipe_src_h = drm_rect_height(&crtc_state->pipe_src);
455 
456 	/* Native modes don't need fitting */
457 	if (adjusted_mode->crtc_hdisplay == pipe_src_w &&
458 	    adjusted_mode->crtc_vdisplay == pipe_src_h)
459 		goto out;
460 
461 	/*
462 	 * TODO: implement downscaling for i965+. Need to account
463 	 * for downscaling in intel_crtc_compute_pixel_rate().
464 	 */
465 	if (adjusted_mode->crtc_hdisplay < pipe_src_w) {
466 		drm_dbg_kms(display->drm,
467 			    "[CRTC:%d:%s] pfit horizontal downscaling (%d->%d) not supported\n",
468 			    crtc->base.base.id, crtc->base.name,
469 			    pipe_src_w, adjusted_mode->crtc_hdisplay);
470 		return -EINVAL;
471 	}
472 	if (adjusted_mode->crtc_vdisplay < pipe_src_h) {
473 		drm_dbg_kms(display->drm,
474 			    "[CRTC:%d:%s] pfit vertical downscaling (%d->%d) not supported\n",
475 			    crtc->base.base.id, crtc->base.name,
476 			    pipe_src_h, adjusted_mode->crtc_vdisplay);
477 		return -EINVAL;
478 	}
479 
480 	switch (conn_state->scaling_mode) {
481 	case DRM_MODE_SCALE_CENTER:
482 		/*
483 		 * For centered modes, we have to calculate border widths &
484 		 * heights and modify the values programmed into the CRTC.
485 		 */
486 		centre_horizontally(adjusted_mode, pipe_src_w);
487 		centre_vertically(adjusted_mode, pipe_src_h);
488 		border = LVDS_BORDER_ENABLE;
489 		break;
490 	case DRM_MODE_SCALE_ASPECT:
491 		/* Scale but preserve the aspect ratio */
492 		if (DISPLAY_VER(display) >= 4)
493 			i965_scale_aspect(crtc_state, &pfit_control);
494 		else
495 			i9xx_scale_aspect(crtc_state, &pfit_control,
496 					  &pfit_pgm_ratios, &border);
497 		break;
498 	case DRM_MODE_SCALE_FULLSCREEN:
499 		/*
500 		 * Full scaling, even if it changes the aspect ratio.
501 		 * Fortunately this is all done for us in hw.
502 		 */
503 		if (pipe_src_h != adjusted_mode->crtc_vdisplay ||
504 		    pipe_src_w != adjusted_mode->crtc_hdisplay) {
505 			pfit_control |= PFIT_ENABLE;
506 			if (DISPLAY_VER(display) >= 4)
507 				pfit_control |= PFIT_SCALING_AUTO;
508 			else
509 				pfit_control |= (PFIT_VERT_AUTO_SCALE |
510 						 PFIT_VERT_INTERP_BILINEAR |
511 						 PFIT_HORIZ_AUTO_SCALE |
512 						 PFIT_HORIZ_INTERP_BILINEAR);
513 		}
514 		break;
515 	default:
516 		MISSING_CASE(conn_state->scaling_mode);
517 		return -EINVAL;
518 	}
519 
520 	/* 965+ wants fuzzy fitting */
521 	/* FIXME: handle multiple panels by failing gracefully */
522 	if (DISPLAY_VER(display) >= 4)
523 		pfit_control |= PFIT_PIPE(crtc->pipe) | PFIT_FILTER_FUZZY;
524 
525 out:
526 	if ((pfit_control & PFIT_ENABLE) == 0) {
527 		pfit_control = 0;
528 		pfit_pgm_ratios = 0;
529 	}
530 
531 	/* Make sure pre-965 set dither correctly for 18bpp panels. */
532 	if (DISPLAY_VER(display) < 4 && crtc_state->pipe_bpp == 18)
533 		pfit_control |= PFIT_PANEL_8TO6_DITHER_ENABLE;
534 
535 	crtc_state->gmch_pfit.control = pfit_control;
536 	crtc_state->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
537 	crtc_state->gmch_pfit.lvds_border_bits = border;
538 
539 	if ((pfit_control & PFIT_ENABLE) == 0)
540 		return 0;
541 
542 	return intel_gmch_pfit_check_timings(crtc_state);
543 }
544 
545 int intel_panel_fitting(struct intel_crtc_state *crtc_state,
546 			const struct drm_connector_state *conn_state)
547 {
548 	struct intel_display *display = to_intel_display(crtc_state);
549 
550 	if (HAS_GMCH(display))
551 		return gmch_panel_fitting(crtc_state, conn_state);
552 	else
553 		return pch_panel_fitting(crtc_state, conn_state);
554 }
555