diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 434 |
1 files changed, 248 insertions, 186 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0abe79fb6385..25d96889d7d2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -3418,15 +3418,16 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused, | |||
3418 | static bool ironlake_compute_wm0(struct drm_device *dev, | 3418 | static bool ironlake_compute_wm0(struct drm_device *dev, |
3419 | int pipe, | 3419 | int pipe, |
3420 | const struct intel_watermark_params *display, | 3420 | const struct intel_watermark_params *display, |
3421 | int display_latency, | 3421 | int display_latency_ns, |
3422 | const struct intel_watermark_params *cursor, | 3422 | const struct intel_watermark_params *cursor, |
3423 | int cursor_latency, | 3423 | int cursor_latency_ns, |
3424 | int *plane_wm, | 3424 | int *plane_wm, |
3425 | int *cursor_wm) | 3425 | int *cursor_wm) |
3426 | { | 3426 | { |
3427 | struct drm_crtc *crtc; | 3427 | struct drm_crtc *crtc; |
3428 | int htotal, hdisplay, clock, pixel_size = 0; | 3428 | int htotal, hdisplay, clock, pixel_size; |
3429 | int line_time_us, line_count, entries; | 3429 | int line_time_us, line_count; |
3430 | int entries, tlb_miss; | ||
3430 | 3431 | ||
3431 | crtc = intel_get_crtc_for_pipe(dev, pipe); | 3432 | crtc = intel_get_crtc_for_pipe(dev, pipe); |
3432 | if (crtc->fb == NULL || !crtc->enabled) | 3433 | if (crtc->fb == NULL || !crtc->enabled) |
@@ -3438,7 +3439,10 @@ static bool ironlake_compute_wm0(struct drm_device *dev, | |||
3438 | pixel_size = crtc->fb->bits_per_pixel / 8; | 3439 | pixel_size = crtc->fb->bits_per_pixel / 8; |
3439 | 3440 | ||
3440 | /* Use the small buffer method to calculate plane watermark */ | 3441 | /* Use the small buffer method to calculate plane watermark */ |
3441 | entries = ((clock * pixel_size / 1000) * display_latency * 100) / 1000; | 3442 | entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; |
3443 | tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8; | ||
3444 | if (tlb_miss > 0) | ||
3445 | entries += tlb_miss; | ||
3442 | entries = DIV_ROUND_UP(entries, display->cacheline_size); | 3446 | entries = DIV_ROUND_UP(entries, display->cacheline_size); |
3443 | *plane_wm = entries + display->guard_size; | 3447 | *plane_wm = entries + display->guard_size; |
3444 | if (*plane_wm > (int)display->max_wm) | 3448 | if (*plane_wm > (int)display->max_wm) |
@@ -3446,8 +3450,11 @@ static bool ironlake_compute_wm0(struct drm_device *dev, | |||
3446 | 3450 | ||
3447 | /* Use the large buffer method to calculate cursor watermark */ | 3451 | /* Use the large buffer method to calculate cursor watermark */ |
3448 | line_time_us = ((htotal * 1000) / clock); | 3452 | line_time_us = ((htotal * 1000) / clock); |
3449 | line_count = (cursor_latency * 100 / line_time_us + 1000) / 1000; | 3453 | line_count = (cursor_latency_ns / line_time_us + 1000) / 1000; |
3450 | entries = line_count * 64 * pixel_size; | 3454 | entries = line_count * 64 * pixel_size; |
3455 | tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8; | ||
3456 | if (tlb_miss > 0) | ||
3457 | entries += tlb_miss; | ||
3451 | entries = DIV_ROUND_UP(entries, cursor->cacheline_size); | 3458 | entries = DIV_ROUND_UP(entries, cursor->cacheline_size); |
3452 | *cursor_wm = entries + cursor->guard_size; | 3459 | *cursor_wm = entries + cursor->guard_size; |
3453 | if (*cursor_wm > (int)cursor->max_wm) | 3460 | if (*cursor_wm > (int)cursor->max_wm) |
@@ -3456,113 +3463,17 @@ static bool ironlake_compute_wm0(struct drm_device *dev, | |||
3456 | return true; | 3463 | return true; |
3457 | } | 3464 | } |
3458 | 3465 | ||
3459 | static void ironlake_update_wm(struct drm_device *dev, | ||
3460 | int planea_clock, int planeb_clock, | ||
3461 | int sr_hdisplay, int sr_htotal, | ||
3462 | int pixel_size) | ||
3463 | { | ||
3464 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
3465 | int plane_wm, cursor_wm, enabled; | ||
3466 | int tmp; | ||
3467 | |||
3468 | enabled = 0; | ||
3469 | if (ironlake_compute_wm0(dev, 0, | ||
3470 | &ironlake_display_wm_info, | ||
3471 | ILK_LP0_PLANE_LATENCY, | ||
3472 | &ironlake_cursor_wm_info, | ||
3473 | ILK_LP0_CURSOR_LATENCY, | ||
3474 | &plane_wm, &cursor_wm)) { | ||
3475 | I915_WRITE(WM0_PIPEA_ILK, | ||
3476 | (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); | ||
3477 | DRM_DEBUG_KMS("FIFO watermarks For pipe A -" | ||
3478 | " plane %d, " "cursor: %d\n", | ||
3479 | plane_wm, cursor_wm); | ||
3480 | enabled++; | ||
3481 | } | ||
3482 | |||
3483 | if (ironlake_compute_wm0(dev, 1, | ||
3484 | &ironlake_display_wm_info, | ||
3485 | ILK_LP0_PLANE_LATENCY, | ||
3486 | &ironlake_cursor_wm_info, | ||
3487 | ILK_LP0_CURSOR_LATENCY, | ||
3488 | &plane_wm, &cursor_wm)) { | ||
3489 | I915_WRITE(WM0_PIPEB_ILK, | ||
3490 | (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); | ||
3491 | DRM_DEBUG_KMS("FIFO watermarks For pipe B -" | ||
3492 | " plane %d, cursor: %d\n", | ||
3493 | plane_wm, cursor_wm); | ||
3494 | enabled++; | ||
3495 | } | ||
3496 | |||
3497 | /* | ||
3498 | * Calculate and update the self-refresh watermark only when one | ||
3499 | * display plane is used. | ||
3500 | */ | ||
3501 | tmp = 0; | ||
3502 | if (enabled == 1) { | ||
3503 | unsigned long line_time_us; | ||
3504 | int small, large, plane_fbc; | ||
3505 | int sr_clock, entries; | ||
3506 | int line_count, line_size; | ||
3507 | /* Read the self-refresh latency. The unit is 0.5us */ | ||
3508 | int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK; | ||
3509 | |||
3510 | sr_clock = planea_clock ? planea_clock : planeb_clock; | ||
3511 | line_time_us = (sr_htotal * 1000) / sr_clock; | ||
3512 | |||
3513 | /* Use ns/us then divide to preserve precision */ | ||
3514 | line_count = ((ilk_sr_latency * 500) / line_time_us + 1000) | ||
3515 | / 1000; | ||
3516 | line_size = sr_hdisplay * pixel_size; | ||
3517 | |||
3518 | /* Use the minimum of the small and large buffer method for primary */ | ||
3519 | small = ((sr_clock * pixel_size / 1000) * (ilk_sr_latency * 500)) / 1000; | ||
3520 | large = line_count * line_size; | ||
3521 | |||
3522 | entries = DIV_ROUND_UP(min(small, large), | ||
3523 | ironlake_display_srwm_info.cacheline_size); | ||
3524 | |||
3525 | plane_fbc = entries * 64; | ||
3526 | plane_fbc = DIV_ROUND_UP(plane_fbc, line_size); | ||
3527 | |||
3528 | plane_wm = entries + ironlake_display_srwm_info.guard_size; | ||
3529 | if (plane_wm > (int)ironlake_display_srwm_info.max_wm) | ||
3530 | plane_wm = ironlake_display_srwm_info.max_wm; | ||
3531 | |||
3532 | /* calculate the self-refresh watermark for display cursor */ | ||
3533 | entries = line_count * pixel_size * 64; | ||
3534 | entries = DIV_ROUND_UP(entries, | ||
3535 | ironlake_cursor_srwm_info.cacheline_size); | ||
3536 | |||
3537 | cursor_wm = entries + ironlake_cursor_srwm_info.guard_size; | ||
3538 | if (cursor_wm > (int)ironlake_cursor_srwm_info.max_wm) | ||
3539 | cursor_wm = ironlake_cursor_srwm_info.max_wm; | ||
3540 | |||
3541 | /* configure watermark and enable self-refresh */ | ||
3542 | tmp = (WM1_LP_SR_EN | | ||
3543 | (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) | | ||
3544 | (plane_fbc << WM1_LP_FBC_SHIFT) | | ||
3545 | (plane_wm << WM1_LP_SR_SHIFT) | | ||
3546 | cursor_wm); | ||
3547 | DRM_DEBUG_KMS("self-refresh watermark: display plane %d, fbc lines %d," | ||
3548 | " cursor %d\n", plane_wm, plane_fbc, cursor_wm); | ||
3549 | } | ||
3550 | I915_WRITE(WM1_LP_ILK, tmp); | ||
3551 | /* XXX setup WM2 and WM3 */ | ||
3552 | } | ||
3553 | |||
3554 | /* | 3466 | /* |
3555 | * Check the wm result. | 3467 | * Check the wm result. |
3556 | * | 3468 | * |
3557 | * If any calculated watermark values is larger than the maximum value that | 3469 | * If any calculated watermark values is larger than the maximum value that |
3558 | * can be programmed into the associated watermark register, that watermark | 3470 | * can be programmed into the associated watermark register, that watermark |
3559 | * must be disabled. | 3471 | * must be disabled. |
3560 | * | ||
3561 | * Also return true if all of those watermark values is 0, which is set by | ||
3562 | * sandybridge_compute_srwm, to indicate the latency is ZERO. | ||
3563 | */ | 3472 | */ |
3564 | static bool sandybridge_check_srwm(struct drm_device *dev, int level, | 3473 | static bool ironlake_check_srwm(struct drm_device *dev, int level, |
3565 | int fbc_wm, int display_wm, int cursor_wm) | 3474 | int fbc_wm, int display_wm, int cursor_wm, |
3475 | const struct intel_watermark_params *display, | ||
3476 | const struct intel_watermark_params *cursor) | ||
3566 | { | 3477 | { |
3567 | struct drm_i915_private *dev_priv = dev->dev_private; | 3478 | struct drm_i915_private *dev_priv = dev->dev_private; |
3568 | 3479 | ||
@@ -3571,7 +3482,7 @@ static bool sandybridge_check_srwm(struct drm_device *dev, int level, | |||
3571 | 3482 | ||
3572 | if (fbc_wm > SNB_FBC_MAX_SRWM) { | 3483 | if (fbc_wm > SNB_FBC_MAX_SRWM) { |
3573 | DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n", | 3484 | DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n", |
3574 | fbc_wm, SNB_FBC_MAX_SRWM, level); | 3485 | fbc_wm, SNB_FBC_MAX_SRWM, level); |
3575 | 3486 | ||
3576 | /* fbc has it's own way to disable FBC WM */ | 3487 | /* fbc has it's own way to disable FBC WM */ |
3577 | I915_WRITE(DISP_ARB_CTL, | 3488 | I915_WRITE(DISP_ARB_CTL, |
@@ -3579,15 +3490,15 @@ static bool sandybridge_check_srwm(struct drm_device *dev, int level, | |||
3579 | return false; | 3490 | return false; |
3580 | } | 3491 | } |
3581 | 3492 | ||
3582 | if (display_wm > SNB_DISPLAY_MAX_SRWM) { | 3493 | if (display_wm > display->max_wm) { |
3583 | DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n", | 3494 | DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n", |
3584 | display_wm, SNB_DISPLAY_MAX_SRWM, level); | 3495 | display_wm, SNB_DISPLAY_MAX_SRWM, level); |
3585 | return false; | 3496 | return false; |
3586 | } | 3497 | } |
3587 | 3498 | ||
3588 | if (cursor_wm > SNB_CURSOR_MAX_SRWM) { | 3499 | if (cursor_wm > cursor->max_wm) { |
3589 | DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n", | 3500 | DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n", |
3590 | cursor_wm, SNB_CURSOR_MAX_SRWM, level); | 3501 | cursor_wm, SNB_CURSOR_MAX_SRWM, level); |
3591 | return false; | 3502 | return false; |
3592 | } | 3503 | } |
3593 | 3504 | ||
@@ -3602,16 +3513,18 @@ static bool sandybridge_check_srwm(struct drm_device *dev, int level, | |||
3602 | /* | 3513 | /* |
3603 | * Compute watermark values of WM[1-3], | 3514 | * Compute watermark values of WM[1-3], |
3604 | */ | 3515 | */ |
3605 | static bool sandybridge_compute_srwm(struct drm_device *dev, int level, | 3516 | static bool ironlake_compute_srwm(struct drm_device *dev, int level, |
3606 | int hdisplay, int htotal, int pixel_size, | 3517 | int hdisplay, int htotal, |
3607 | int clock, int latency_ns, int *fbc_wm, | 3518 | int pixel_size, int clock, int latency_ns, |
3608 | int *display_wm, int *cursor_wm) | 3519 | const struct intel_watermark_params *display, |
3520 | const struct intel_watermark_params *cursor, | ||
3521 | int *fbc_wm, int *display_wm, int *cursor_wm) | ||
3609 | { | 3522 | { |
3610 | 3523 | ||
3611 | unsigned long line_time_us; | 3524 | unsigned long line_time_us; |
3525 | int line_count, line_size; | ||
3612 | int small, large; | 3526 | int small, large; |
3613 | int entries; | 3527 | int entries; |
3614 | int line_count, line_size; | ||
3615 | 3528 | ||
3616 | if (!latency_ns) { | 3529 | if (!latency_ns) { |
3617 | *fbc_wm = *display_wm = *cursor_wm = 0; | 3530 | *fbc_wm = *display_wm = *cursor_wm = 0; |
@@ -3626,24 +3539,110 @@ static bool sandybridge_compute_srwm(struct drm_device *dev, int level, | |||
3626 | small = ((clock * pixel_size / 1000) * latency_ns) / 1000; | 3539 | small = ((clock * pixel_size / 1000) * latency_ns) / 1000; |
3627 | large = line_count * line_size; | 3540 | large = line_count * line_size; |
3628 | 3541 | ||
3629 | entries = DIV_ROUND_UP(min(small, large), | 3542 | entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); |
3630 | sandybridge_display_srwm_info.cacheline_size); | 3543 | *display_wm = entries + display->guard_size; |
3631 | *display_wm = entries + sandybridge_display_srwm_info.guard_size; | ||
3632 | 3544 | ||
3633 | /* | 3545 | /* |
3634 | * Spec said: | 3546 | * Spec says: |
3635 | * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2 | 3547 | * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2 |
3636 | */ | 3548 | */ |
3637 | *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2; | 3549 | *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2; |
3638 | 3550 | ||
3639 | /* calculate the self-refresh watermark for display cursor */ | 3551 | /* calculate the self-refresh watermark for display cursor */ |
3640 | entries = line_count * pixel_size * 64; | 3552 | entries = line_count * pixel_size * 64; |
3641 | entries = DIV_ROUND_UP(entries, | 3553 | entries = DIV_ROUND_UP(entries, cursor->cacheline_size); |
3642 | sandybridge_cursor_srwm_info.cacheline_size); | 3554 | *cursor_wm = entries + cursor->guard_size; |
3643 | *cursor_wm = entries + sandybridge_cursor_srwm_info.guard_size; | ||
3644 | 3555 | ||
3645 | return sandybridge_check_srwm(dev, level, | 3556 | return ironlake_check_srwm(dev, level, |
3646 | *fbc_wm, *display_wm, *cursor_wm); | 3557 | *fbc_wm, *display_wm, *cursor_wm, |
3558 | display, cursor); | ||
3559 | } | ||
3560 | |||
3561 | static void ironlake_update_wm(struct drm_device *dev, | ||
3562 | int planea_clock, int planeb_clock, | ||
3563 | int hdisplay, int htotal, | ||
3564 | int pixel_size) | ||
3565 | { | ||
3566 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
3567 | int fbc_wm, plane_wm, cursor_wm, enabled; | ||
3568 | int clock; | ||
3569 | |||
3570 | enabled = 0; | ||
3571 | if (ironlake_compute_wm0(dev, 0, | ||
3572 | &ironlake_display_wm_info, | ||
3573 | ILK_LP0_PLANE_LATENCY, | ||
3574 | &ironlake_cursor_wm_info, | ||
3575 | ILK_LP0_CURSOR_LATENCY, | ||
3576 | &plane_wm, &cursor_wm)) { | ||
3577 | I915_WRITE(WM0_PIPEA_ILK, | ||
3578 | (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); | ||
3579 | DRM_DEBUG_KMS("FIFO watermarks For pipe A -" | ||
3580 | " plane %d, " "cursor: %d\n", | ||
3581 | plane_wm, cursor_wm); | ||
3582 | enabled++; | ||
3583 | } | ||
3584 | |||
3585 | if (ironlake_compute_wm0(dev, 1, | ||
3586 | &ironlake_display_wm_info, | ||
3587 | ILK_LP0_PLANE_LATENCY, | ||
3588 | &ironlake_cursor_wm_info, | ||
3589 | ILK_LP0_CURSOR_LATENCY, | ||
3590 | &plane_wm, &cursor_wm)) { | ||
3591 | I915_WRITE(WM0_PIPEB_ILK, | ||
3592 | (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); | ||
3593 | DRM_DEBUG_KMS("FIFO watermarks For pipe B -" | ||
3594 | " plane %d, cursor: %d\n", | ||
3595 | plane_wm, cursor_wm); | ||
3596 | enabled++; | ||
3597 | } | ||
3598 | |||
3599 | /* | ||
3600 | * Calculate and update the self-refresh watermark only when one | ||
3601 | * display plane is used. | ||
3602 | */ | ||
3603 | I915_WRITE(WM3_LP_ILK, 0); | ||
3604 | I915_WRITE(WM2_LP_ILK, 0); | ||
3605 | I915_WRITE(WM1_LP_ILK, 0); | ||
3606 | |||
3607 | if (enabled != 1) | ||
3608 | return; | ||
3609 | |||
3610 | clock = planea_clock ? planea_clock : planeb_clock; | ||
3611 | |||
3612 | /* WM1 */ | ||
3613 | if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, | ||
3614 | clock, ILK_READ_WM1_LATENCY() * 500, | ||
3615 | &ironlake_display_srwm_info, | ||
3616 | &ironlake_cursor_srwm_info, | ||
3617 | &fbc_wm, &plane_wm, &cursor_wm)) | ||
3618 | return; | ||
3619 | |||
3620 | I915_WRITE(WM1_LP_ILK, | ||
3621 | WM1_LP_SR_EN | | ||
3622 | (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | | ||
3623 | (fbc_wm << WM1_LP_FBC_SHIFT) | | ||
3624 | (plane_wm << WM1_LP_SR_SHIFT) | | ||
3625 | cursor_wm); | ||
3626 | |||
3627 | /* WM2 */ | ||
3628 | if (!ironlake_compute_srwm(dev, 2, hdisplay, htotal, pixel_size, | ||
3629 | clock, ILK_READ_WM2_LATENCY() * 500, | ||
3630 | &ironlake_display_srwm_info, | ||
3631 | &ironlake_cursor_srwm_info, | ||
3632 | &fbc_wm, &plane_wm, &cursor_wm)) | ||
3633 | return; | ||
3634 | |||
3635 | I915_WRITE(WM2_LP_ILK, | ||
3636 | WM2_LP_EN | | ||
3637 | (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | | ||
3638 | (fbc_wm << WM1_LP_FBC_SHIFT) | | ||
3639 | (plane_wm << WM1_LP_SR_SHIFT) | | ||
3640 | cursor_wm); | ||
3641 | |||
3642 | /* | ||
3643 | * WM3 is unsupported on ILK, probably because we don't have latency | ||
3644 | * data for that power state | ||
3645 | */ | ||
3647 | } | 3646 | } |
3648 | 3647 | ||
3649 | static void sandybridge_update_wm(struct drm_device *dev, | 3648 | static void sandybridge_update_wm(struct drm_device *dev, |
@@ -3652,7 +3651,7 @@ static void sandybridge_update_wm(struct drm_device *dev, | |||
3652 | int pixel_size) | 3651 | int pixel_size) |
3653 | { | 3652 | { |
3654 | struct drm_i915_private *dev_priv = dev->dev_private; | 3653 | struct drm_i915_private *dev_priv = dev->dev_private; |
3655 | int latency = SNB_READ_WM0_LATENCY(); | 3654 | int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ |
3656 | int fbc_wm, plane_wm, cursor_wm, enabled; | 3655 | int fbc_wm, plane_wm, cursor_wm, enabled; |
3657 | int clock; | 3656 | int clock; |
3658 | 3657 | ||
@@ -3701,9 +3700,11 @@ static void sandybridge_update_wm(struct drm_device *dev, | |||
3701 | clock = planea_clock ? planea_clock : planeb_clock; | 3700 | clock = planea_clock ? planea_clock : planeb_clock; |
3702 | 3701 | ||
3703 | /* WM1 */ | 3702 | /* WM1 */ |
3704 | if (!sandybridge_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, | 3703 | if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, |
3705 | clock, SNB_READ_WM1_LATENCY() * 500, | 3704 | clock, SNB_READ_WM1_LATENCY() * 500, |
3706 | &fbc_wm, &plane_wm, &cursor_wm)) | 3705 | &sandybridge_display_srwm_info, |
3706 | &sandybridge_cursor_srwm_info, | ||
3707 | &fbc_wm, &plane_wm, &cursor_wm)) | ||
3707 | return; | 3708 | return; |
3708 | 3709 | ||
3709 | I915_WRITE(WM1_LP_ILK, | 3710 | I915_WRITE(WM1_LP_ILK, |
@@ -3714,10 +3715,12 @@ static void sandybridge_update_wm(struct drm_device *dev, | |||
3714 | cursor_wm); | 3715 | cursor_wm); |
3715 | 3716 | ||
3716 | /* WM2 */ | 3717 | /* WM2 */ |
3717 | if (!sandybridge_compute_srwm(dev, 2, | 3718 | if (!ironlake_compute_srwm(dev, 2, |
3718 | hdisplay, htotal, pixel_size, | 3719 | hdisplay, htotal, pixel_size, |
3719 | clock, SNB_READ_WM2_LATENCY() * 500, | 3720 | clock, SNB_READ_WM2_LATENCY() * 500, |
3720 | &fbc_wm, &plane_wm, &cursor_wm)) | 3721 | &sandybridge_display_srwm_info, |
3722 | &sandybridge_cursor_srwm_info, | ||
3723 | &fbc_wm, &plane_wm, &cursor_wm)) | ||
3721 | return; | 3724 | return; |
3722 | 3725 | ||
3723 | I915_WRITE(WM2_LP_ILK, | 3726 | I915_WRITE(WM2_LP_ILK, |
@@ -3728,10 +3731,12 @@ static void sandybridge_update_wm(struct drm_device *dev, | |||
3728 | cursor_wm); | 3731 | cursor_wm); |
3729 | 3732 | ||
3730 | /* WM3 */ | 3733 | /* WM3 */ |
3731 | if (!sandybridge_compute_srwm(dev, 3, | 3734 | if (!ironlake_compute_srwm(dev, 3, |
3732 | hdisplay, htotal, pixel_size, | 3735 | hdisplay, htotal, pixel_size, |
3733 | clock, SNB_READ_WM3_LATENCY() * 500, | 3736 | clock, SNB_READ_WM3_LATENCY() * 500, |
3734 | &fbc_wm, &plane_wm, &cursor_wm)) | 3737 | &sandybridge_display_srwm_info, |
3738 | &sandybridge_cursor_srwm_info, | ||
3739 | &fbc_wm, &plane_wm, &cursor_wm)) | ||
3735 | return; | 3740 | return; |
3736 | 3741 | ||
3737 | I915_WRITE(WM3_LP_ILK, | 3742 | I915_WRITE(WM3_LP_ILK, |
@@ -3951,7 +3956,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, | |||
3951 | int lane = 0, link_bw, bpp; | 3956 | int lane = 0, link_bw, bpp; |
3952 | /* CPU eDP doesn't require FDI link, so just set DP M/N | 3957 | /* CPU eDP doesn't require FDI link, so just set DP M/N |
3953 | according to current link config */ | 3958 | according to current link config */ |
3954 | if (has_edp_encoder && !intel_encoder_is_pch_edp(&encoder->base)) { | 3959 | if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) { |
3955 | target_clock = mode->clock; | 3960 | target_clock = mode->clock; |
3956 | intel_edp_link_config(has_edp_encoder, | 3961 | intel_edp_link_config(has_edp_encoder, |
3957 | &lane, &link_bw); | 3962 | &lane, &link_bw); |
@@ -5038,8 +5043,8 @@ static void intel_increase_pllclock(struct drm_crtc *crtc) | |||
5038 | drm_i915_private_t *dev_priv = dev->dev_private; | 5043 | drm_i915_private_t *dev_priv = dev->dev_private; |
5039 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | 5044 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
5040 | int pipe = intel_crtc->pipe; | 5045 | int pipe = intel_crtc->pipe; |
5041 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | 5046 | int dpll_reg = DPLL(pipe); |
5042 | int dpll = I915_READ(dpll_reg); | 5047 | int dpll; |
5043 | 5048 | ||
5044 | if (HAS_PCH_SPLIT(dev)) | 5049 | if (HAS_PCH_SPLIT(dev)) |
5045 | return; | 5050 | return; |
@@ -5047,17 +5052,19 @@ static void intel_increase_pllclock(struct drm_crtc *crtc) | |||
5047 | if (!dev_priv->lvds_downclock_avail) | 5052 | if (!dev_priv->lvds_downclock_avail) |
5048 | return; | 5053 | return; |
5049 | 5054 | ||
5055 | dpll = I915_READ(dpll_reg); | ||
5050 | if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) { | 5056 | if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) { |
5051 | DRM_DEBUG_DRIVER("upclocking LVDS\n"); | 5057 | DRM_DEBUG_DRIVER("upclocking LVDS\n"); |
5052 | 5058 | ||
5053 | /* Unlock panel regs */ | 5059 | /* Unlock panel regs */ |
5054 | I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | | 5060 | I915_WRITE(PP_CONTROL, |
5055 | PANEL_UNLOCK_REGS); | 5061 | I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); |
5056 | 5062 | ||
5057 | dpll &= ~DISPLAY_RATE_SELECT_FPA1; | 5063 | dpll &= ~DISPLAY_RATE_SELECT_FPA1; |
5058 | I915_WRITE(dpll_reg, dpll); | 5064 | I915_WRITE(dpll_reg, dpll); |
5059 | dpll = I915_READ(dpll_reg); | 5065 | POSTING_READ(dpll_reg); |
5060 | intel_wait_for_vblank(dev, pipe); | 5066 | intel_wait_for_vblank(dev, pipe); |
5067 | |||
5061 | dpll = I915_READ(dpll_reg); | 5068 | dpll = I915_READ(dpll_reg); |
5062 | if (dpll & DISPLAY_RATE_SELECT_FPA1) | 5069 | if (dpll & DISPLAY_RATE_SELECT_FPA1) |
5063 | DRM_DEBUG_DRIVER("failed to upclock LVDS!\n"); | 5070 | DRM_DEBUG_DRIVER("failed to upclock LVDS!\n"); |
@@ -5802,6 +5809,8 @@ static void intel_setup_outputs(struct drm_device *dev) | |||
5802 | encoder->base.possible_clones = | 5809 | encoder->base.possible_clones = |
5803 | intel_encoder_clones(dev, encoder->clone_mask); | 5810 | intel_encoder_clones(dev, encoder->clone_mask); |
5804 | } | 5811 | } |
5812 | |||
5813 | intel_panel_setup_backlight(dev); | ||
5805 | } | 5814 | } |
5806 | 5815 | ||
5807 | static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) | 5816 | static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) |
@@ -6145,6 +6154,10 @@ void intel_init_emon(struct drm_device *dev) | |||
6145 | 6154 | ||
6146 | void gen6_enable_rps(struct drm_i915_private *dev_priv) | 6155 | void gen6_enable_rps(struct drm_i915_private *dev_priv) |
6147 | { | 6156 | { |
6157 | u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); | ||
6158 | u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); | ||
6159 | u32 pcu_mbox; | ||
6160 | int cur_freq, min_freq, max_freq; | ||
6148 | int i; | 6161 | int i; |
6149 | 6162 | ||
6150 | /* Here begins a magic sequence of register writes to enable | 6163 | /* Here begins a magic sequence of register writes to enable |
@@ -6216,6 +6229,29 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) | |||
6216 | 500)) | 6229 | 500)) |
6217 | DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); | 6230 | DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); |
6218 | 6231 | ||
6232 | min_freq = (rp_state_cap & 0xff0000) >> 16; | ||
6233 | max_freq = rp_state_cap & 0xff; | ||
6234 | cur_freq = (gt_perf_status & 0xff00) >> 8; | ||
6235 | |||
6236 | /* Check for overclock support */ | ||
6237 | if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, | ||
6238 | 500)) | ||
6239 | DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); | ||
6240 | I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS); | ||
6241 | pcu_mbox = I915_READ(GEN6_PCODE_DATA); | ||
6242 | if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, | ||
6243 | 500)) | ||
6244 | DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); | ||
6245 | if (pcu_mbox & (1<<31)) { /* OC supported */ | ||
6246 | max_freq = pcu_mbox & 0xff; | ||
6247 | DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 100); | ||
6248 | } | ||
6249 | |||
6250 | /* In units of 100MHz */ | ||
6251 | dev_priv->max_delay = max_freq; | ||
6252 | dev_priv->min_delay = min_freq; | ||
6253 | dev_priv->cur_delay = cur_freq; | ||
6254 | |||
6219 | /* requires MSI enabled */ | 6255 | /* requires MSI enabled */ |
6220 | I915_WRITE(GEN6_PMIER, | 6256 | I915_WRITE(GEN6_PMIER, |
6221 | GEN6_PM_MBOX_EVENT | | 6257 | GEN6_PM_MBOX_EVENT | |
@@ -6386,42 +6422,6 @@ void intel_enable_clock_gating(struct drm_device *dev) | |||
6386 | } else if (IS_I830(dev)) { | 6422 | } else if (IS_I830(dev)) { |
6387 | I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); | 6423 | I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); |
6388 | } | 6424 | } |
6389 | |||
6390 | /* | ||
6391 | * GPU can automatically power down the render unit if given a page | ||
6392 | * to save state. | ||
6393 | */ | ||
6394 | if (IS_IRONLAKE_M(dev) && 0) { /* XXX causes a failure during suspend */ | ||
6395 | if (dev_priv->renderctx == NULL) | ||
6396 | dev_priv->renderctx = intel_alloc_context_page(dev); | ||
6397 | if (dev_priv->renderctx) { | ||
6398 | struct drm_i915_gem_object *obj = dev_priv->renderctx; | ||
6399 | if (BEGIN_LP_RING(4) == 0) { | ||
6400 | OUT_RING(MI_SET_CONTEXT); | ||
6401 | OUT_RING(obj->gtt_offset | | ||
6402 | MI_MM_SPACE_GTT | | ||
6403 | MI_SAVE_EXT_STATE_EN | | ||
6404 | MI_RESTORE_EXT_STATE_EN | | ||
6405 | MI_RESTORE_INHIBIT); | ||
6406 | OUT_RING(MI_NOOP); | ||
6407 | OUT_RING(MI_FLUSH); | ||
6408 | ADVANCE_LP_RING(); | ||
6409 | } | ||
6410 | } else | ||
6411 | DRM_DEBUG_KMS("Failed to allocate render context." | ||
6412 | "Disable RC6\n"); | ||
6413 | } | ||
6414 | |||
6415 | if (IS_GEN4(dev) && IS_MOBILE(dev)) { | ||
6416 | if (dev_priv->pwrctx == NULL) | ||
6417 | dev_priv->pwrctx = intel_alloc_context_page(dev); | ||
6418 | if (dev_priv->pwrctx) { | ||
6419 | struct drm_i915_gem_object *obj = dev_priv->pwrctx; | ||
6420 | I915_WRITE(PWRCTXA, obj->gtt_offset | PWRCTX_EN); | ||
6421 | I915_WRITE(MCHBAR_RENDER_STANDBY, | ||
6422 | I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT); | ||
6423 | } | ||
6424 | } | ||
6425 | } | 6425 | } |
6426 | 6426 | ||
6427 | void intel_disable_clock_gating(struct drm_device *dev) | 6427 | void intel_disable_clock_gating(struct drm_device *dev) |
@@ -6451,6 +6451,57 @@ void intel_disable_clock_gating(struct drm_device *dev) | |||
6451 | } | 6451 | } |
6452 | } | 6452 | } |
6453 | 6453 | ||
6454 | static void ironlake_disable_rc6(struct drm_device *dev) | ||
6455 | { | ||
6456 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
6457 | |||
6458 | /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ | ||
6459 | I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); | ||
6460 | wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), | ||
6461 | 10); | ||
6462 | POSTING_READ(CCID); | ||
6463 | I915_WRITE(PWRCTXA, 0); | ||
6464 | POSTING_READ(PWRCTXA); | ||
6465 | I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); | ||
6466 | POSTING_READ(RSTDBYCTL); | ||
6467 | i915_gem_object_unpin(dev_priv->renderctx); | ||
6468 | drm_gem_object_unreference(&dev_priv->renderctx->base); | ||
6469 | dev_priv->renderctx = NULL; | ||
6470 | i915_gem_object_unpin(dev_priv->pwrctx); | ||
6471 | drm_gem_object_unreference(&dev_priv->pwrctx->base); | ||
6472 | dev_priv->pwrctx = NULL; | ||
6473 | } | ||
6474 | |||
6475 | void ironlake_enable_rc6(struct drm_device *dev) | ||
6476 | { | ||
6477 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
6478 | int ret; | ||
6479 | |||
6480 | /* | ||
6481 | * GPU can automatically power down the render unit if given a page | ||
6482 | * to save state. | ||
6483 | */ | ||
6484 | ret = BEGIN_LP_RING(6); | ||
6485 | if (ret) { | ||
6486 | ironlake_disable_rc6(dev); | ||
6487 | return; | ||
6488 | } | ||
6489 | OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); | ||
6490 | OUT_RING(MI_SET_CONTEXT); | ||
6491 | OUT_RING(dev_priv->renderctx->gtt_offset | | ||
6492 | MI_MM_SPACE_GTT | | ||
6493 | MI_SAVE_EXT_STATE_EN | | ||
6494 | MI_RESTORE_EXT_STATE_EN | | ||
6495 | MI_RESTORE_INHIBIT); | ||
6496 | OUT_RING(MI_SUSPEND_FLUSH); | ||
6497 | OUT_RING(MI_NOOP); | ||
6498 | OUT_RING(MI_FLUSH); | ||
6499 | ADVANCE_LP_RING(); | ||
6500 | |||
6501 | I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN); | ||
6502 | I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); | ||
6503 | } | ||
6504 | |||
6454 | /* Set up chip specific display functions */ | 6505 | /* Set up chip specific display functions */ |
6455 | static void intel_init_display(struct drm_device *dev) | 6506 | static void intel_init_display(struct drm_device *dev) |
6456 | { | 6507 | { |
@@ -6665,12 +6716,7 @@ void intel_modeset_init(struct drm_device *dev) | |||
6665 | dev->mode_config.max_width = 8192; | 6716 | dev->mode_config.max_width = 8192; |
6666 | dev->mode_config.max_height = 8192; | 6717 | dev->mode_config.max_height = 8192; |
6667 | } | 6718 | } |
6668 | 6719 | dev->mode_config.fb_base = dev->agp->base; | |
6669 | /* set memory base */ | ||
6670 | if (IS_GEN2(dev)) | ||
6671 | dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); | ||
6672 | else | ||
6673 | dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2); | ||
6674 | 6720 | ||
6675 | if (IS_MOBILE(dev) || !IS_GEN2(dev)) | 6721 | if (IS_MOBILE(dev) || !IS_GEN2(dev)) |
6676 | dev_priv->num_pipe = 2; | 6722 | dev_priv->num_pipe = 2; |
@@ -6698,6 +6744,21 @@ void intel_modeset_init(struct drm_device *dev) | |||
6698 | if (IS_GEN6(dev)) | 6744 | if (IS_GEN6(dev)) |
6699 | gen6_enable_rps(dev_priv); | 6745 | gen6_enable_rps(dev_priv); |
6700 | 6746 | ||
6747 | if (IS_IRONLAKE_M(dev)) { | ||
6748 | dev_priv->renderctx = intel_alloc_context_page(dev); | ||
6749 | if (!dev_priv->renderctx) | ||
6750 | goto skip_rc6; | ||
6751 | dev_priv->pwrctx = intel_alloc_context_page(dev); | ||
6752 | if (!dev_priv->pwrctx) { | ||
6753 | i915_gem_object_unpin(dev_priv->renderctx); | ||
6754 | drm_gem_object_unreference(&dev_priv->renderctx->base); | ||
6755 | dev_priv->renderctx = NULL; | ||
6756 | goto skip_rc6; | ||
6757 | } | ||
6758 | ironlake_enable_rc6(dev); | ||
6759 | } | ||
6760 | |||
6761 | skip_rc6: | ||
6701 | INIT_WORK(&dev_priv->idle_work, intel_idle_update); | 6762 | INIT_WORK(&dev_priv->idle_work, intel_idle_update); |
6702 | setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, | 6763 | setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, |
6703 | (unsigned long)dev); | 6764 | (unsigned long)dev); |
@@ -6734,7 +6795,8 @@ void intel_modeset_cleanup(struct drm_device *dev) | |||
6734 | if (IS_GEN6(dev)) | 6795 | if (IS_GEN6(dev)) |
6735 | gen6_disable_rps(dev); | 6796 | gen6_disable_rps(dev); |
6736 | 6797 | ||
6737 | intel_disable_clock_gating(dev); | 6798 | if (IS_IRONLAKE_M(dev)) |
6799 | ironlake_disable_rc6(dev); | ||
6738 | 6800 | ||
6739 | mutex_unlock(&dev->struct_mutex); | 6801 | mutex_unlock(&dev->struct_mutex); |
6740 | 6802 | ||