drm/i915: Rework DPLL calculation parameters for Ironlake

Got Ironlake DPLL parameter table, which reflects the hardware
optimized values. So this one trys to list DPLL parameters for
different output types, should potential fix clock issue seen
on new Arrandale CPUs.

This fixes DPLL setting failure on one 1920x1080 dual channel
LVDS for Ironlake. Test has also been made on LVDS panels with
smaller size and CRT/HDMI/DP ports for different monitors on
their all supported modes.

Update:
- Change name of double LVDS to dual LVDS.
- Fix SSC 120M reference clock to use the right range.

Cc: CSJ <changsijay@gmail.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>

authored by Zhenyu Wang and committed by Eric Anholt b91ad0ec e28cab42

+167 -50
+167 -50
drivers/gpu/drm/i915/intel_display.c
··· 240 #define IRONLAKE_DOT_MAX 350000 241 #define IRONLAKE_VCO_MIN 1760000 242 #define IRONLAKE_VCO_MAX 3510000 243 - #define IRONLAKE_N_MIN 1 244 - #define IRONLAKE_N_MAX 6 245 - #define IRONLAKE_M_MIN 79 246 - #define IRONLAKE_M_MAX 127 247 #define IRONLAKE_M1_MIN 12 248 #define IRONLAKE_M1_MAX 22 249 #define IRONLAKE_M2_MIN 5 250 #define IRONLAKE_M2_MAX 9 251 - #define IRONLAKE_P_SDVO_DAC_MIN 5 252 - #define IRONLAKE_P_SDVO_DAC_MAX 80 253 - #define IRONLAKE_P_LVDS_MIN 28 254 - #define IRONLAKE_P_LVDS_MAX 112 255 - #define IRONLAKE_P1_MIN 1 256 - #define IRONLAKE_P1_MAX 8 257 - #define IRONLAKE_P2_SDVO_DAC_SLOW 10 258 - #define IRONLAKE_P2_SDVO_DAC_FAST 5 259 - #define IRONLAKE_P2_LVDS_SLOW 14 /* single channel */ 260 - #define IRONLAKE_P2_LVDS_FAST 7 /* double channel */ 261 #define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */ 262 263 - #define IRONLAKE_P_DISPLAY_PORT_MIN 10 264 - #define IRONLAKE_P_DISPLAY_PORT_MAX 20 265 - #define IRONLAKE_P2_DISPLAY_PORT_FAST 10 266 - #define IRONLAKE_P2_DISPLAY_PORT_SLOW 10 267 - #define IRONLAKE_P2_DISPLAY_PORT_LIMIT 0 268 - #define IRONLAKE_P1_DISPLAY_PORT_MIN 1 269 - #define IRONLAKE_P1_DISPLAY_PORT_MAX 2 270 271 static bool 272 intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, ··· 527 .find_pll = intel_find_best_PLL, 528 }; 529 530 - static const intel_limit_t intel_limits_ironlake_sdvo = { 531 .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, 532 .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, 533 - .n = { .min = IRONLAKE_N_MIN, .max = IRONLAKE_N_MAX }, 534 - .m = { .min = IRONLAKE_M_MIN, .max = IRONLAKE_M_MAX }, 535 .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, 536 .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, 537 - .p = { .min = IRONLAKE_P_SDVO_DAC_MIN, .max = IRONLAKE_P_SDVO_DAC_MAX }, 538 - .p1 = { .min = IRONLAKE_P1_MIN, .max = IRONLAKE_P1_MAX }, 539 .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, 540 - .p2_slow = IRONLAKE_P2_SDVO_DAC_SLOW, 541 - .p2_fast = IRONLAKE_P2_SDVO_DAC_FAST }, 542 .find_pll = intel_g4x_find_best_PLL, 543 }; 544 545 - static const intel_limit_t intel_limits_ironlake_lvds = { 546 .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, 547 .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, 548 - .n = { .min = IRONLAKE_N_MIN, .max = IRONLAKE_N_MAX }, 549 - .m = { .min = IRONLAKE_M_MIN, .max = IRONLAKE_M_MAX }, 550 .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, 551 .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, 552 - .p = { .min = IRONLAKE_P_LVDS_MIN, .max = IRONLAKE_P_LVDS_MAX }, 553 - .p1 = { .min = IRONLAKE_P1_MIN, .max = IRONLAKE_P1_MAX }, 554 .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, 555 - .p2_slow = IRONLAKE_P2_LVDS_SLOW, 556 - .p2_fast = IRONLAKE_P2_LVDS_FAST }, 557 .find_pll = intel_g4x_find_best_PLL, 558 }; 559 ··· 607 .max = IRONLAKE_DOT_MAX }, 608 .vco = { .min = IRONLAKE_VCO_MIN, 609 .max = IRONLAKE_VCO_MAX}, 610 - .n = { .min = IRONLAKE_N_MIN, 611 - .max = IRONLAKE_N_MAX }, 612 - .m = { .min = IRONLAKE_M_MIN, 613 - .max = IRONLAKE_M_MAX }, 614 .m1 = { .min = IRONLAKE_M1_MIN, 615 .max = IRONLAKE_M1_MAX }, 616 .m2 = { .min = IRONLAKE_M2_MIN, 617 .max = IRONLAKE_M2_MAX }, 618 - .p = { .min = IRONLAKE_P_DISPLAY_PORT_MIN, 619 - .max = IRONLAKE_P_DISPLAY_PORT_MAX }, 620 - .p1 = { .min = IRONLAKE_P1_DISPLAY_PORT_MIN, 621 - .max = IRONLAKE_P1_DISPLAY_PORT_MAX}, 622 - .p2 = { .dot_limit = IRONLAKE_P2_DISPLAY_PORT_LIMIT, 623 - .p2_slow = IRONLAKE_P2_DISPLAY_PORT_SLOW, 624 - .p2_fast = IRONLAKE_P2_DISPLAY_PORT_FAST }, 625 .find_pll = intel_find_pll_ironlake_dp, 626 }; 627 628 static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc) 629 { 630 const intel_limit_t *limit; 631 - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) 632 - limit = &intel_limits_ironlake_lvds; 633 - else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || 634 HAS_eDP) 635 limit = &intel_limits_ironlake_display_port; 636 else 637 - limit = &intel_limits_ironlake_sdvo; 638 639 return limit; 640 }
··· 240 #define IRONLAKE_DOT_MAX 350000 241 #define IRONLAKE_VCO_MIN 1760000 242 #define IRONLAKE_VCO_MAX 3510000 243 #define IRONLAKE_M1_MIN 12 244 #define IRONLAKE_M1_MAX 22 245 #define IRONLAKE_M2_MIN 5 246 #define IRONLAKE_M2_MAX 9 247 #define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */ 248 249 + /* We have parameter ranges for different type of outputs. */ 250 + 251 + /* DAC & HDMI Refclk 120Mhz */ 252 + #define IRONLAKE_DAC_N_MIN 1 253 + #define IRONLAKE_DAC_N_MAX 5 254 + #define IRONLAKE_DAC_M_MIN 79 255 + #define IRONLAKE_DAC_M_MAX 127 256 + #define IRONLAKE_DAC_P_MIN 5 257 + #define IRONLAKE_DAC_P_MAX 80 258 + #define IRONLAKE_DAC_P1_MIN 1 259 + #define IRONLAKE_DAC_P1_MAX 8 260 + #define IRONLAKE_DAC_P2_SLOW 10 261 + #define IRONLAKE_DAC_P2_FAST 5 262 + 263 + /* LVDS single-channel 120Mhz refclk */ 264 + #define IRONLAKE_LVDS_S_N_MIN 1 265 + #define IRONLAKE_LVDS_S_N_MAX 3 266 + #define IRONLAKE_LVDS_S_M_MIN 79 267 + #define IRONLAKE_LVDS_S_M_MAX 118 268 + #define IRONLAKE_LVDS_S_P_MIN 28 269 + #define IRONLAKE_LVDS_S_P_MAX 112 270 + #define IRONLAKE_LVDS_S_P1_MIN 2 271 + #define IRONLAKE_LVDS_S_P1_MAX 8 272 + #define IRONLAKE_LVDS_S_P2_SLOW 14 273 + #define IRONLAKE_LVDS_S_P2_FAST 14 274 + 275 + /* LVDS dual-channel 120Mhz refclk */ 276 + #define IRONLAKE_LVDS_D_N_MIN 1 277 + #define IRONLAKE_LVDS_D_N_MAX 3 278 + #define IRONLAKE_LVDS_D_M_MIN 79 279 + #define IRONLAKE_LVDS_D_M_MAX 127 280 + #define IRONLAKE_LVDS_D_P_MIN 14 281 + #define IRONLAKE_LVDS_D_P_MAX 56 282 + #define IRONLAKE_LVDS_D_P1_MIN 2 283 + #define IRONLAKE_LVDS_D_P1_MAX 8 284 + #define IRONLAKE_LVDS_D_P2_SLOW 7 285 + #define IRONLAKE_LVDS_D_P2_FAST 7 286 + 287 + /* LVDS single-channel 100Mhz refclk */ 288 + #define IRONLAKE_LVDS_S_SSC_N_MIN 1 289 + #define IRONLAKE_LVDS_S_SSC_N_MAX 2 290 + #define IRONLAKE_LVDS_S_SSC_M_MIN 79 291 + #define IRONLAKE_LVDS_S_SSC_M_MAX 126 292 + #define IRONLAKE_LVDS_S_SSC_P_MIN 28 293 + #define IRONLAKE_LVDS_S_SSC_P_MAX 112 294 + #define IRONLAKE_LVDS_S_SSC_P1_MIN 2 295 + #define IRONLAKE_LVDS_S_SSC_P1_MAX 8 296 + #define IRONLAKE_LVDS_S_SSC_P2_SLOW 14 297 + #define IRONLAKE_LVDS_S_SSC_P2_FAST 14 298 + 299 + /* LVDS dual-channel 100Mhz refclk */ 300 + #define IRONLAKE_LVDS_D_SSC_N_MIN 1 301 + #define IRONLAKE_LVDS_D_SSC_N_MAX 3 302 + #define IRONLAKE_LVDS_D_SSC_M_MIN 79 303 + #define IRONLAKE_LVDS_D_SSC_M_MAX 126 304 + #define IRONLAKE_LVDS_D_SSC_P_MIN 14 305 + #define IRONLAKE_LVDS_D_SSC_P_MAX 42 306 + #define IRONLAKE_LVDS_D_SSC_P1_MIN 2 307 + #define IRONLAKE_LVDS_D_SSC_P1_MAX 6 308 + #define IRONLAKE_LVDS_D_SSC_P2_SLOW 7 309 + #define IRONLAKE_LVDS_D_SSC_P2_FAST 7 310 + 311 + /* DisplayPort */ 312 + #define IRONLAKE_DP_N_MIN 1 313 + #define IRONLAKE_DP_N_MAX 2 314 + #define IRONLAKE_DP_M_MIN 81 315 + #define IRONLAKE_DP_M_MAX 90 316 + #define IRONLAKE_DP_P_MIN 10 317 + #define IRONLAKE_DP_P_MAX 20 318 + #define IRONLAKE_DP_P2_FAST 10 319 + #define IRONLAKE_DP_P2_SLOW 10 320 + #define IRONLAKE_DP_P2_LIMIT 0 321 + #define IRONLAKE_DP_P1_MIN 1 322 + #define IRONLAKE_DP_P1_MAX 2 323 324 static bool 325 intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, ··· 474 .find_pll = intel_find_best_PLL, 475 }; 476 477 + static const intel_limit_t intel_limits_ironlake_dac = { 478 .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, 479 .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, 480 + .n = { .min = IRONLAKE_DAC_N_MIN, .max = IRONLAKE_DAC_N_MAX }, 481 + .m = { .min = IRONLAKE_DAC_M_MIN, .max = IRONLAKE_DAC_M_MAX }, 482 .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, 483 .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, 484 + .p = { .min = IRONLAKE_DAC_P_MIN, .max = IRONLAKE_DAC_P_MAX }, 485 + .p1 = { .min = IRONLAKE_DAC_P1_MIN, .max = IRONLAKE_DAC_P1_MAX }, 486 .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, 487 + .p2_slow = IRONLAKE_DAC_P2_SLOW, 488 + .p2_fast = IRONLAKE_DAC_P2_FAST }, 489 .find_pll = intel_g4x_find_best_PLL, 490 }; 491 492 + static const intel_limit_t intel_limits_ironlake_single_lvds = { 493 .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, 494 .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, 495 + .n = { .min = IRONLAKE_LVDS_S_N_MIN, .max = IRONLAKE_LVDS_S_N_MAX }, 496 + .m = { .min = IRONLAKE_LVDS_S_M_MIN, .max = IRONLAKE_LVDS_S_M_MAX }, 497 .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, 498 .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, 499 + .p = { .min = IRONLAKE_LVDS_S_P_MIN, .max = IRONLAKE_LVDS_S_P_MAX }, 500 + .p1 = { .min = IRONLAKE_LVDS_S_P1_MIN, .max = IRONLAKE_LVDS_S_P1_MAX }, 501 .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, 502 + .p2_slow = IRONLAKE_LVDS_S_P2_SLOW, 503 + .p2_fast = IRONLAKE_LVDS_S_P2_FAST }, 504 + .find_pll = intel_g4x_find_best_PLL, 505 + }; 506 + 507 + static const intel_limit_t intel_limits_ironlake_dual_lvds = { 508 + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, 509 + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, 510 + .n = { .min = IRONLAKE_LVDS_D_N_MIN, .max = IRONLAKE_LVDS_D_N_MAX }, 511 + .m = { .min = IRONLAKE_LVDS_D_M_MIN, .max = IRONLAKE_LVDS_D_M_MAX }, 512 + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, 513 + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, 514 + .p = { .min = IRONLAKE_LVDS_D_P_MIN, .max = IRONLAKE_LVDS_D_P_MAX }, 515 + .p1 = { .min = IRONLAKE_LVDS_D_P1_MIN, .max = IRONLAKE_LVDS_D_P1_MAX }, 516 + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, 517 + .p2_slow = IRONLAKE_LVDS_D_P2_SLOW, 518 + .p2_fast = IRONLAKE_LVDS_D_P2_FAST }, 519 + .find_pll = intel_g4x_find_best_PLL, 520 + }; 521 + 522 + static const intel_limit_t intel_limits_ironlake_single_lvds_100m = { 523 + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, 524 + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, 525 + .n = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX }, 526 + .m = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX }, 527 + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, 528 + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, 529 + .p = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX }, 530 + .p1 = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX }, 531 + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, 532 + .p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW, 533 + .p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST }, 534 + .find_pll = intel_g4x_find_best_PLL, 535 + }; 536 + 537 + static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { 538 + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, 539 + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, 540 + .n = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX }, 541 + .m = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX }, 542 + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, 543 + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, 544 + .p = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX }, 545 + .p1 = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX }, 546 + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, 547 + .p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW, 548 + .p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST }, 549 .find_pll = intel_g4x_find_best_PLL, 550 }; 551 ··· 509 .max = IRONLAKE_DOT_MAX }, 510 .vco = { .min = IRONLAKE_VCO_MIN, 511 .max = IRONLAKE_VCO_MAX}, 512 + .n = { .min = IRONLAKE_DP_N_MIN, 513 + .max = IRONLAKE_DP_N_MAX }, 514 + .m = { .min = IRONLAKE_DP_M_MIN, 515 + .max = IRONLAKE_DP_M_MAX }, 516 .m1 = { .min = IRONLAKE_M1_MIN, 517 .max = IRONLAKE_M1_MAX }, 518 .m2 = { .min = IRONLAKE_M2_MIN, 519 .max = IRONLAKE_M2_MAX }, 520 + .p = { .min = IRONLAKE_DP_P_MIN, 521 + .max = IRONLAKE_DP_P_MAX }, 522 + .p1 = { .min = IRONLAKE_DP_P1_MIN, 523 + .max = IRONLAKE_DP_P1_MAX}, 524 + .p2 = { .dot_limit = IRONLAKE_DP_P2_LIMIT, 525 + .p2_slow = IRONLAKE_DP_P2_SLOW, 526 + .p2_fast = IRONLAKE_DP_P2_FAST }, 527 .find_pll = intel_find_pll_ironlake_dp, 528 }; 529 530 static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc) 531 { 532 + struct drm_device *dev = crtc->dev; 533 + struct drm_i915_private *dev_priv = dev->dev_private; 534 const intel_limit_t *limit; 535 + int refclk = 120; 536 + 537 + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { 538 + if (dev_priv->lvds_use_ssc && dev_priv->lvds_ssc_freq == 100) 539 + refclk = 100; 540 + 541 + if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == 542 + LVDS_CLKB_POWER_UP) { 543 + /* LVDS dual channel */ 544 + if (refclk == 100) 545 + limit = &intel_limits_ironlake_dual_lvds_100m; 546 + else 547 + limit = &intel_limits_ironlake_dual_lvds; 548 + } else { 549 + if (refclk == 100) 550 + limit = &intel_limits_ironlake_single_lvds_100m; 551 + else 552 + limit = &intel_limits_ironlake_single_lvds; 553 + } 554 + } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || 555 HAS_eDP) 556 limit = &intel_limits_ironlake_display_port; 557 else 558 + limit = &intel_limits_ironlake_dac; 559 560 return limit; 561 }