1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2024 Intel Corporation 4 */ 5 6 #include <drm/drm_print.h> 7 8 #include "intel_de.h" 9 #include "intel_display_core.h" 10 #include "intel_display_driver.h" 11 #include "intel_display_regs.h" 12 #include "intel_display_types.h" 13 #include "intel_display_utils.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 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 190 const struct drm_display_mode *adjusted_mode = 191 &crtc_state->hw.adjusted_mode; 192 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); 193 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); 194 int ret, x, y, width, height; 195 196 /* Native modes don't need fitting */ 197 if (adjusted_mode->crtc_hdisplay == pipe_src_w && 198 adjusted_mode->crtc_vdisplay == pipe_src_h && 199 crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420 && 200 crtc_state->hw.sharpness_strength == 0) 201 return 0; 202 203 switch (conn_state->scaling_mode) { 204 case DRM_MODE_SCALE_CENTER: 205 if (adjusted_mode->crtc_hdisplay < pipe_src_w || 206 adjusted_mode->crtc_vdisplay < pipe_src_h) { 207 drm_dbg_kms(display->drm, 208 "[CRTC:%d:%s] pfit center mode source (%dx%d) exceeds display (%dx%d)\n", 209 crtc->base.base.id, crtc->base.name, 210 pipe_src_w, pipe_src_h, 211 adjusted_mode->crtc_hdisplay, 212 adjusted_mode->crtc_vdisplay); 213 return -EINVAL; 214 } 215 width = pipe_src_w; 216 height = pipe_src_h; 217 x = (adjusted_mode->crtc_hdisplay - width + 1)/2; 218 y = (adjusted_mode->crtc_vdisplay - height + 1)/2; 219 break; 220 221 case DRM_MODE_SCALE_ASPECT: 222 /* Scale but preserve the aspect ratio */ 223 { 224 u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h; 225 u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay; 226 227 if (scaled_width > scaled_height) { /* pillar */ 228 width = scaled_height / pipe_src_h; 229 if (width & 1) 230 width++; 231 x = (adjusted_mode->crtc_hdisplay - width + 1) / 2; 232 y = 0; 233 height = adjusted_mode->crtc_vdisplay; 234 } else if (scaled_width < scaled_height) { /* letter */ 235 height = scaled_width / pipe_src_w; 236 if (height & 1) 237 height++; 238 y = (adjusted_mode->crtc_vdisplay - height + 1) / 2; 239 x = 0; 240 width = adjusted_mode->crtc_hdisplay; 241 } else { 242 x = y = 0; 243 width = adjusted_mode->crtc_hdisplay; 244 height = adjusted_mode->crtc_vdisplay; 245 } 246 } 247 break; 248 249 case DRM_MODE_SCALE_NONE: 250 WARN_ON(adjusted_mode->crtc_hdisplay != pipe_src_w); 251 WARN_ON(adjusted_mode->crtc_vdisplay != pipe_src_h); 252 fallthrough; 253 case DRM_MODE_SCALE_FULLSCREEN: 254 x = y = 0; 255 width = adjusted_mode->crtc_hdisplay; 256 height = adjusted_mode->crtc_vdisplay; 257 break; 258 259 default: 260 MISSING_CASE(conn_state->scaling_mode); 261 return -EINVAL; 262 } 263 264 if (crtc_state->hw.sharpness_strength && 265 (width != pipe_src_w || height != pipe_src_h || 266 crtc_state->hw.scaling_filter != DRM_SCALING_FILTER_DEFAULT || 267 crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB)) { 268 drm_dbg_kms(display->drm, 269 "[CRTC:%d:%s] no scaling/YCbCr output with sharpness filter\n", 270 crtc->base.base.id, crtc->base.name); 271 return -EINVAL; 272 } 273 274 drm_rect_init(&crtc_state->pch_pfit.dst, 275 x, y, width, height); 276 crtc_state->pch_pfit.enabled = true; 277 278 /* 279 * SKL+ have unified scalers for pipes/planes so the 280 * checks are done in a single place for all scalers. 281 */ 282 if (DISPLAY_VER(display) >= 9) 283 return 0; 284 285 ret = intel_pch_pfit_check_dst_window(crtc_state); 286 if (ret) 287 return ret; 288 289 ret = intel_pch_pfit_check_src_size(crtc_state); 290 if (ret) 291 return ret; 292 293 ret = intel_pch_pfit_check_scaling(crtc_state); 294 if (ret) 295 return ret; 296 297 ret = intel_pch_pfit_check_timings(crtc_state); 298 if (ret) 299 return ret; 300 301 ret = intel_pch_pfit_check_cloning(crtc_state); 302 if (ret) 303 return ret; 304 305 return 0; 306 } 307 308 static void 309 centre_horizontally(struct drm_display_mode *adjusted_mode, 310 int width) 311 { 312 u32 border, sync_pos, blank_width, sync_width; 313 314 /* keep the hsync and hblank widths constant */ 315 sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; 316 blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start; 317 sync_pos = (blank_width - sync_width + 1) / 2; 318 319 border = (adjusted_mode->crtc_hdisplay - width + 1) / 2; 320 border += border & 1; /* make the border even */ 321 322 adjusted_mode->crtc_hdisplay = width; 323 adjusted_mode->crtc_hblank_start = width + border; 324 adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width; 325 326 adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos; 327 adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width; 328 } 329 330 static void 331 centre_vertically(struct drm_display_mode *adjusted_mode, 332 int height) 333 { 334 u32 border, sync_pos, blank_width, sync_width; 335 336 /* keep the vsync and vblank widths constant */ 337 sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; 338 blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start; 339 sync_pos = (blank_width - sync_width + 1) / 2; 340 341 border = (adjusted_mode->crtc_vdisplay - height + 1) / 2; 342 343 adjusted_mode->crtc_vdisplay = height; 344 adjusted_mode->crtc_vblank_start = height + border; 345 adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width; 346 347 adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos; 348 adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width; 349 } 350 351 static u32 panel_fitter_scaling(u32 source, u32 target) 352 { 353 /* 354 * Floating point operation is not supported. So the FACTOR 355 * is defined, which can avoid the floating point computation 356 * when calculating the panel ratio. 357 */ 358 #define ACCURACY 12 359 #define FACTOR (1 << ACCURACY) 360 u32 ratio = source * FACTOR / target; 361 return (FACTOR * ratio + FACTOR/2) / FACTOR; 362 } 363 364 static void i965_scale_aspect(struct intel_crtc_state *crtc_state, 365 u32 *pfit_control) 366 { 367 const struct drm_display_mode *adjusted_mode = 368 &crtc_state->hw.adjusted_mode; 369 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); 370 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); 371 u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h; 372 u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay; 373 374 /* 965+ is easy, it does everything in hw */ 375 if (scaled_width > scaled_height) 376 *pfit_control |= PFIT_ENABLE | 377 PFIT_SCALING_PILLAR; 378 else if (scaled_width < scaled_height) 379 *pfit_control |= PFIT_ENABLE | 380 PFIT_SCALING_LETTER; 381 else if (adjusted_mode->crtc_hdisplay != pipe_src_w) 382 *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; 383 } 384 385 static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state, 386 u32 *pfit_control, u32 *pfit_pgm_ratios, 387 u32 *border) 388 { 389 struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; 390 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); 391 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); 392 u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h; 393 u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay; 394 u32 bits; 395 396 /* 397 * For earlier chips we have to calculate the scaling 398 * ratio by hand and program it into the 399 * PFIT_PGM_RATIO register 400 */ 401 if (scaled_width > scaled_height) { /* pillar */ 402 centre_horizontally(adjusted_mode, 403 scaled_height / pipe_src_h); 404 405 *border = LVDS_BORDER_ENABLE; 406 if (pipe_src_h != adjusted_mode->crtc_vdisplay) { 407 bits = panel_fitter_scaling(pipe_src_h, 408 adjusted_mode->crtc_vdisplay); 409 410 *pfit_pgm_ratios |= (PFIT_HORIZ_SCALE(bits) | 411 PFIT_VERT_SCALE(bits)); 412 *pfit_control |= (PFIT_ENABLE | 413 PFIT_VERT_INTERP_BILINEAR | 414 PFIT_HORIZ_INTERP_BILINEAR); 415 } 416 } else if (scaled_width < scaled_height) { /* letter */ 417 centre_vertically(adjusted_mode, 418 scaled_width / pipe_src_w); 419 420 *border = LVDS_BORDER_ENABLE; 421 if (pipe_src_w != adjusted_mode->crtc_hdisplay) { 422 bits = panel_fitter_scaling(pipe_src_w, 423 adjusted_mode->crtc_hdisplay); 424 425 *pfit_pgm_ratios |= (PFIT_HORIZ_SCALE(bits) | 426 PFIT_VERT_SCALE(bits)); 427 *pfit_control |= (PFIT_ENABLE | 428 PFIT_VERT_INTERP_BILINEAR | 429 PFIT_HORIZ_INTERP_BILINEAR); 430 } 431 } else { 432 /* Aspects match, Let hw scale both directions */ 433 *pfit_control |= (PFIT_ENABLE | 434 PFIT_VERT_AUTO_SCALE | 435 PFIT_HORIZ_AUTO_SCALE | 436 PFIT_VERT_INTERP_BILINEAR | 437 PFIT_HORIZ_INTERP_BILINEAR); 438 } 439 } 440 441 static int intel_gmch_pfit_check_timings(const struct intel_crtc_state *crtc_state) 442 { 443 struct intel_display *display = to_intel_display(crtc_state); 444 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 445 const struct drm_display_mode *adjusted_mode = 446 &crtc_state->hw.adjusted_mode; 447 int min; 448 449 if (DISPLAY_VER(display) >= 4) 450 min = 3; 451 else 452 min = 2; 453 454 if (adjusted_mode->crtc_hdisplay < min) { 455 drm_dbg_kms(display->drm, 456 "[CRTC:%d:%s] horizontal active (%d) below minimum (%d) for pfit\n", 457 crtc->base.base.id, crtc->base.name, 458 adjusted_mode->crtc_hdisplay, min); 459 return -EINVAL; 460 } 461 462 if (adjusted_mode->crtc_vdisplay < min) { 463 drm_dbg_kms(display->drm, 464 "[CRTC:%d:%s] vertical active (%d) below minimum (%d) for pfit\n", 465 crtc->base.base.id, crtc->base.name, 466 adjusted_mode->crtc_vdisplay, min); 467 return -EINVAL; 468 } 469 470 return 0; 471 } 472 473 static int gmch_panel_fitting(struct intel_crtc_state *crtc_state, 474 const struct drm_connector_state *conn_state) 475 { 476 struct intel_display *display = to_intel_display(crtc_state); 477 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 478 u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; 479 struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; 480 int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); 481 int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); 482 483 /* Native modes don't need fitting */ 484 if (adjusted_mode->crtc_hdisplay == pipe_src_w && 485 adjusted_mode->crtc_vdisplay == pipe_src_h) 486 goto out; 487 488 /* 489 * TODO: implement downscaling for i965+. Need to account 490 * for downscaling in intel_crtc_compute_pixel_rate(). 491 */ 492 if (adjusted_mode->crtc_hdisplay < pipe_src_w) { 493 drm_dbg_kms(display->drm, 494 "[CRTC:%d:%s] pfit horizontal downscaling (%d->%d) not supported\n", 495 crtc->base.base.id, crtc->base.name, 496 pipe_src_w, adjusted_mode->crtc_hdisplay); 497 return -EINVAL; 498 } 499 if (adjusted_mode->crtc_vdisplay < pipe_src_h) { 500 drm_dbg_kms(display->drm, 501 "[CRTC:%d:%s] pfit vertical downscaling (%d->%d) not supported\n", 502 crtc->base.base.id, crtc->base.name, 503 pipe_src_h, adjusted_mode->crtc_vdisplay); 504 return -EINVAL; 505 } 506 507 switch (conn_state->scaling_mode) { 508 case DRM_MODE_SCALE_CENTER: 509 /* 510 * For centered modes, we have to calculate border widths & 511 * heights and modify the values programmed into the CRTC. 512 */ 513 centre_horizontally(adjusted_mode, pipe_src_w); 514 centre_vertically(adjusted_mode, pipe_src_h); 515 border = LVDS_BORDER_ENABLE; 516 break; 517 case DRM_MODE_SCALE_ASPECT: 518 /* Scale but preserve the aspect ratio */ 519 if (DISPLAY_VER(display) >= 4) 520 i965_scale_aspect(crtc_state, &pfit_control); 521 else 522 i9xx_scale_aspect(crtc_state, &pfit_control, 523 &pfit_pgm_ratios, &border); 524 break; 525 case DRM_MODE_SCALE_FULLSCREEN: 526 /* 527 * Full scaling, even if it changes the aspect ratio. 528 * Fortunately this is all done for us in hw. 529 */ 530 if (pipe_src_h != adjusted_mode->crtc_vdisplay || 531 pipe_src_w != adjusted_mode->crtc_hdisplay) { 532 pfit_control |= PFIT_ENABLE; 533 if (DISPLAY_VER(display) >= 4) 534 pfit_control |= PFIT_SCALING_AUTO; 535 else 536 pfit_control |= (PFIT_VERT_AUTO_SCALE | 537 PFIT_VERT_INTERP_BILINEAR | 538 PFIT_HORIZ_AUTO_SCALE | 539 PFIT_HORIZ_INTERP_BILINEAR); 540 } 541 break; 542 default: 543 MISSING_CASE(conn_state->scaling_mode); 544 return -EINVAL; 545 } 546 547 /* 965+ wants fuzzy fitting */ 548 /* FIXME: handle multiple panels by failing gracefully */ 549 if (DISPLAY_VER(display) >= 4) 550 pfit_control |= PFIT_PIPE(crtc->pipe) | PFIT_FILTER_FUZZY; 551 552 out: 553 if ((pfit_control & PFIT_ENABLE) == 0) { 554 pfit_control = 0; 555 pfit_pgm_ratios = 0; 556 } 557 558 /* Make sure pre-965 set dither correctly for 18bpp panels. */ 559 if (DISPLAY_VER(display) < 4 && crtc_state->pipe_bpp == 18) 560 pfit_control |= PFIT_PANEL_8TO6_DITHER_ENABLE; 561 562 crtc_state->gmch_pfit.control = pfit_control; 563 crtc_state->gmch_pfit.pgm_ratios = pfit_pgm_ratios; 564 crtc_state->gmch_pfit.lvds_border_bits = border; 565 566 if ((pfit_control & PFIT_ENABLE) == 0) 567 return 0; 568 569 return intel_gmch_pfit_check_timings(crtc_state); 570 } 571 572 enum drm_mode_status 573 intel_pfit_mode_valid(struct intel_display *display, 574 const struct drm_display_mode *mode, 575 enum intel_output_format output_format, 576 int num_joined_pipes) 577 { 578 return skl_scaler_mode_valid(display, mode, output_format, 579 num_joined_pipes); 580 } 581 582 int intel_pfit_compute_config(struct intel_crtc_state *crtc_state, 583 const struct drm_connector_state *conn_state) 584 { 585 struct intel_display *display = to_intel_display(crtc_state); 586 587 if (HAS_GMCH(display)) 588 return gmch_panel_fitting(crtc_state, conn_state); 589 else 590 return pch_panel_fitting(crtc_state, conn_state); 591 } 592 593 void ilk_pfit_enable(const struct intel_crtc_state *crtc_state) 594 { 595 struct intel_display *display = to_intel_display(crtc_state); 596 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 597 const struct drm_rect *dst = &crtc_state->pch_pfit.dst; 598 enum pipe pipe = crtc->pipe; 599 int width = drm_rect_width(dst); 600 int height = drm_rect_height(dst); 601 int x = dst->x1; 602 int y = dst->y1; 603 604 if (!crtc_state->pch_pfit.enabled) 605 return; 606 607 /* 608 * Force use of hard-coded filter coefficients as some pre-programmed 609 * values are broken, e.g. x201. 610 */ 611 if (display->platform.ivybridge || display->platform.haswell) 612 intel_de_write_fw(display, PF_CTL(pipe), PF_ENABLE | 613 PF_FILTER_MED_3x3 | PF_PIPE_SEL_IVB(pipe)); 614 else 615 intel_de_write_fw(display, PF_CTL(pipe), PF_ENABLE | 616 PF_FILTER_MED_3x3); 617 intel_de_write_fw(display, PF_WIN_POS(pipe), 618 PF_WIN_XPOS(x) | PF_WIN_YPOS(y)); 619 intel_de_write_fw(display, PF_WIN_SZ(pipe), 620 PF_WIN_XSIZE(width) | PF_WIN_YSIZE(height)); 621 } 622 623 void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state) 624 { 625 struct intel_display *display = to_intel_display(old_crtc_state); 626 struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); 627 enum pipe pipe = crtc->pipe; 628 629 /* 630 * To avoid upsetting the power well on haswell only disable the pfit if 631 * it's in use. The hw state code will make sure we get this right. 632 */ 633 if (!old_crtc_state->pch_pfit.enabled) 634 return; 635 636 intel_de_write_fw(display, PF_CTL(pipe), 0); 637 intel_de_write_fw(display, PF_WIN_POS(pipe), 0); 638 intel_de_write_fw(display, PF_WIN_SZ(pipe), 0); 639 } 640 641 void ilk_pfit_get_config(struct intel_crtc_state *crtc_state) 642 { 643 struct intel_display *display = to_intel_display(crtc_state); 644 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 645 u32 ctl, pos, size; 646 enum pipe pipe; 647 648 ctl = intel_de_read(display, PF_CTL(crtc->pipe)); 649 if ((ctl & PF_ENABLE) == 0) 650 return; 651 652 if (display->platform.ivybridge || display->platform.haswell) 653 pipe = REG_FIELD_GET(PF_PIPE_SEL_MASK_IVB, ctl); 654 else 655 pipe = crtc->pipe; 656 657 crtc_state->pch_pfit.enabled = true; 658 659 pos = intel_de_read(display, PF_WIN_POS(crtc->pipe)); 660 size = intel_de_read(display, PF_WIN_SZ(crtc->pipe)); 661 662 drm_rect_init(&crtc_state->pch_pfit.dst, 663 REG_FIELD_GET(PF_WIN_XPOS_MASK, pos), 664 REG_FIELD_GET(PF_WIN_YPOS_MASK, pos), 665 REG_FIELD_GET(PF_WIN_XSIZE_MASK, size), 666 REG_FIELD_GET(PF_WIN_YSIZE_MASK, size)); 667 668 /* 669 * We currently do not free assignments of panel fitters on 670 * ivb/hsw (since we don't use the higher upscaling modes which 671 * differentiates them) so just WARN about this case for now. 672 */ 673 drm_WARN_ON(display->drm, pipe != crtc->pipe); 674 } 675 676 void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state) 677 { 678 struct intel_display *display = to_intel_display(crtc_state); 679 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 680 681 if (!crtc_state->gmch_pfit.control) 682 return; 683 684 /* 685 * The panel fitter should only be adjusted whilst the pipe is disabled, 686 * according to register description and PRM. 687 */ 688 drm_WARN_ON(display->drm, 689 intel_de_read(display, PFIT_CONTROL(display)) & PFIT_ENABLE); 690 assert_transcoder_disabled(display, crtc_state->cpu_transcoder); 691 692 intel_de_write(display, PFIT_PGM_RATIOS(display), 693 crtc_state->gmch_pfit.pgm_ratios); 694 intel_de_write(display, PFIT_CONTROL(display), 695 crtc_state->gmch_pfit.control); 696 697 /* 698 * Border color in case we don't scale up to the full screen. Black by 699 * default, change to something else for debugging. 700 */ 701 intel_de_write(display, BCLRPAT(display, crtc->pipe), 0); 702 } 703 704 void i9xx_pfit_disable(const struct intel_crtc_state *old_crtc_state) 705 { 706 struct intel_display *display = to_intel_display(old_crtc_state); 707 708 if (!old_crtc_state->gmch_pfit.control) 709 return; 710 711 assert_transcoder_disabled(display, old_crtc_state->cpu_transcoder); 712 713 drm_dbg_kms(display->drm, "disabling pfit, current: 0x%08x\n", 714 intel_de_read(display, PFIT_CONTROL(display))); 715 intel_de_write(display, PFIT_CONTROL(display), 0); 716 } 717 718 static bool i9xx_has_pfit(struct intel_display *display) 719 { 720 if (display->platform.i830) 721 return false; 722 723 return DISPLAY_VER(display) >= 4 || 724 display->platform.pineview || display->platform.mobile; 725 } 726 727 void i9xx_pfit_get_config(struct intel_crtc_state *crtc_state) 728 { 729 struct intel_display *display = to_intel_display(crtc_state); 730 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 731 enum pipe pipe; 732 u32 tmp; 733 734 if (!i9xx_has_pfit(display)) 735 return; 736 737 tmp = intel_de_read(display, PFIT_CONTROL(display)); 738 if (!(tmp & PFIT_ENABLE)) 739 return; 740 741 /* Check whether the pfit is attached to our pipe. */ 742 if (DISPLAY_VER(display) >= 4) 743 pipe = REG_FIELD_GET(PFIT_PIPE_MASK, tmp); 744 else 745 pipe = PIPE_B; 746 747 if (pipe != crtc->pipe) 748 return; 749 750 crtc_state->gmch_pfit.control = tmp; 751 crtc_state->gmch_pfit.pgm_ratios = 752 intel_de_read(display, PFIT_PGM_RATIOS(display)); 753 } 754