|
6 | 6 | #include <drm/drm_atomic_state_helper.h> |
7 | 7 |
|
8 | 8 | #include "intel_bw.h" |
| 9 | +#include "intel_pm.h" |
9 | 10 | #include "intel_display_types.h" |
10 | 11 | #include "intel_sideband.h" |
11 | 12 | #include "intel_atomic.h" |
12 | 13 | #include "intel_pm.h" |
13 | | - |
| 14 | +#include "intel_cdclk.h" |
14 | 15 |
|
15 | 16 | /* Parameters for Qclk Geyserville (QGV) */ |
16 | 17 | struct intel_qgv_point { |
@@ -351,7 +352,6 @@ static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_ |
351 | 352 |
|
352 | 353 | return data_rate; |
353 | 354 | } |
354 | | - |
355 | 355 | void intel_bw_crtc_update(struct intel_bw_state *bw_state, |
356 | 356 | const struct intel_crtc_state *crtc_state) |
357 | 357 | { |
@@ -428,6 +428,123 @@ intel_atomic_get_bw_state(struct intel_atomic_state *state) |
428 | 428 | return to_intel_bw_state(bw_state); |
429 | 429 | } |
430 | 430 |
|
| 431 | +int skl_bw_calc_min_cdclk(struct intel_atomic_state *state) |
| 432 | +{ |
| 433 | + struct drm_i915_private *dev_priv = to_i915(state->base.dev); |
| 434 | + int i; |
| 435 | + const struct intel_crtc_state *crtc_state; |
| 436 | + struct intel_crtc *crtc; |
| 437 | + int max_bw = 0; |
| 438 | + int slice_id; |
| 439 | + struct intel_bw_state *new_bw_state = NULL; |
| 440 | + struct intel_bw_state *old_bw_state = NULL; |
| 441 | + |
| 442 | + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { |
| 443 | + enum plane_id plane_id; |
| 444 | + struct intel_dbuf_bw *crtc_bw; |
| 445 | + |
| 446 | + new_bw_state = intel_atomic_get_bw_state(state); |
| 447 | + if (IS_ERR(new_bw_state)) |
| 448 | + return PTR_ERR(new_bw_state); |
| 449 | + |
| 450 | + crtc_bw = &new_bw_state->dbuf_bw[crtc->pipe]; |
| 451 | + |
| 452 | + memset(&crtc_bw->used_bw, 0, sizeof(crtc_bw->used_bw)); |
| 453 | + |
| 454 | + for_each_plane_id_on_crtc(crtc, plane_id) { |
| 455 | + const struct skl_ddb_entry *plane_alloc = |
| 456 | + &crtc_state->wm.skl.plane_ddb_y[plane_id]; |
| 457 | + const struct skl_ddb_entry *uv_plane_alloc = |
| 458 | + &crtc_state->wm.skl.plane_ddb_uv[plane_id]; |
| 459 | + unsigned int data_rate = crtc_state->data_rate[plane_id]; |
| 460 | + unsigned int dbuf_mask = 0; |
| 461 | + |
| 462 | + dbuf_mask |= skl_ddb_dbuf_slice_mask(dev_priv, plane_alloc); |
| 463 | + dbuf_mask |= skl_ddb_dbuf_slice_mask(dev_priv, uv_plane_alloc); |
| 464 | + |
| 465 | + /* |
| 466 | + * FIXME: To calculate that more properly we probably need to |
| 467 | + * to split per plane data_rate into data_rate_y and data_rate_uv |
| 468 | + * for multiplanar formats in order not to get accounted those twice |
| 469 | + * if they happen to reside on different slices. |
| 470 | + * However for pre-icl this would work anyway because we have only single |
| 471 | + * slice and for icl+ uv plane has non-zero data rate. |
| 472 | + * So in worst case those calculation are a bit pessimistic, which |
| 473 | + * shouldn't pose any significant problem anyway. |
| 474 | + */ |
| 475 | + for_each_dbuf_slice_in_mask(slice_id, dbuf_mask) |
| 476 | + crtc_bw->used_bw[slice_id] += data_rate; |
| 477 | + } |
| 478 | + |
| 479 | + for_each_dbuf_slice(slice_id) { |
| 480 | + /* |
| 481 | + * Current experimental observations show that contrary to BSpec |
| 482 | + * we get underruns once we exceed 64 * CDCLK for slices in total. |
| 483 | + * As a temporary measure in order not to keep CDCLK bumped up all the |
| 484 | + * time we calculate CDCLK according to this formula for overall bw |
| 485 | + * consumed by slices. |
| 486 | + */ |
| 487 | + max_bw += crtc_bw->used_bw[slice_id]; |
| 488 | + } |
| 489 | + |
| 490 | + new_bw_state->min_cdclk = max_bw / 64; |
| 491 | + |
| 492 | + old_bw_state = intel_atomic_get_old_bw_state(state); |
| 493 | + } |
| 494 | + |
| 495 | + if (!old_bw_state) |
| 496 | + return 0; |
| 497 | + |
| 498 | + if (new_bw_state->min_cdclk != old_bw_state->min_cdclk) { |
| 499 | + int ret = intel_atomic_lock_global_state(&new_bw_state->base); |
| 500 | + |
| 501 | + if (ret) |
| 502 | + return ret; |
| 503 | + } |
| 504 | + |
| 505 | + return 0; |
| 506 | +} |
| 507 | + |
| 508 | +int intel_bw_calc_min_cdclk(struct intel_atomic_state *state) |
| 509 | +{ |
| 510 | + int i; |
| 511 | + const struct intel_crtc_state *crtc_state; |
| 512 | + struct intel_crtc *crtc; |
| 513 | + int min_cdclk = 0; |
| 514 | + struct intel_bw_state *new_bw_state = NULL; |
| 515 | + struct intel_bw_state *old_bw_state = NULL; |
| 516 | + |
| 517 | + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { |
| 518 | + struct intel_cdclk_state *cdclk_state; |
| 519 | + |
| 520 | + new_bw_state = intel_atomic_get_bw_state(state); |
| 521 | + if (IS_ERR(new_bw_state)) |
| 522 | + return PTR_ERR(new_bw_state); |
| 523 | + |
| 524 | + cdclk_state = intel_atomic_get_cdclk_state(state); |
| 525 | + if (IS_ERR(cdclk_state)) |
| 526 | + return PTR_ERR(cdclk_state); |
| 527 | + |
| 528 | + min_cdclk = max(cdclk_state->min_cdclk[crtc->pipe], min_cdclk); |
| 529 | + |
| 530 | + new_bw_state->min_cdclk = min_cdclk; |
| 531 | + |
| 532 | + old_bw_state = intel_atomic_get_old_bw_state(state); |
| 533 | + } |
| 534 | + |
| 535 | + if (!old_bw_state) |
| 536 | + return 0; |
| 537 | + |
| 538 | + if (new_bw_state->min_cdclk != old_bw_state->min_cdclk) { |
| 539 | + int ret = intel_atomic_lock_global_state(&new_bw_state->base); |
| 540 | + |
| 541 | + if (ret) |
| 542 | + return ret; |
| 543 | + } |
| 544 | + |
| 545 | + return 0; |
| 546 | +} |
| 547 | + |
431 | 548 | int intel_bw_atomic_check(struct intel_atomic_state *state) |
432 | 549 | { |
433 | 550 | struct drm_i915_private *dev_priv = to_i915(state->base.dev); |
|
0 commit comments