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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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