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