diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2012-08-31 11:56:50 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2012-09-20 13:10:43 -0400 |
commit | f3dd8508d459a2d0d0bc426144b92f1696d4fe86 (patch) | |
tree | 000ca4a5d664dca3837cc5c11d59c332bea8c046 | |
parent | a59fbb8e18566a346a2736000d979576ab7525fe (diff) |
drm/radeon: rework pll selection (v4)
For DP we can use the same PPLL for all active DP
encoders. Take advantage of that to prevent cases
where we may end up sharing a PPLL between DP and
non-DP which won't work. Also clean up the code
a bit.
v2: - fix missing pll_id assignment in crtc init
v3: - fix DP PPLL check
- document functions
- break in main encoder search loop after matching.
no need to keep checking additional encoders.
v4: - same as v3, but re-apply to drm-next as the corner
cases are fixed properly in subsequent patches.
fixes:
https://bugs.freedesktop.org/show_bug.cgi?id=54471
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_crtc.c | 163 |
1 files changed, 129 insertions, 34 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index cc1b2444a5e5..8e73d53b769e 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
@@ -1482,14 +1482,98 @@ static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) | |||
1482 | } | 1482 | } |
1483 | } | 1483 | } |
1484 | 1484 | ||
1485 | /** | ||
1486 | * radeon_get_pll_use_mask - look up a mask of which pplls are in use | ||
1487 | * | ||
1488 | * @crtc: drm crtc | ||
1489 | * | ||
1490 | * Returns the mask of which PPLLs (Pixel PLLs) are in use. | ||
1491 | */ | ||
1492 | static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) | ||
1493 | { | ||
1494 | struct drm_device *dev = crtc->dev; | ||
1495 | struct drm_crtc *test_crtc; | ||
1496 | struct radeon_crtc *radeon_test_crtc; | ||
1497 | u32 pll_in_use = 0; | ||
1498 | |||
1499 | list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { | ||
1500 | if (crtc == test_crtc) | ||
1501 | continue; | ||
1502 | |||
1503 | radeon_test_crtc = to_radeon_crtc(test_crtc); | ||
1504 | if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) | ||
1505 | pll_in_use |= (1 << radeon_test_crtc->pll_id); | ||
1506 | } | ||
1507 | return pll_in_use; | ||
1508 | } | ||
1509 | |||
1510 | /** | ||
1511 | * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP | ||
1512 | * | ||
1513 | * @crtc: drm crtc | ||
1514 | * | ||
1515 | * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is | ||
1516 | * also in DP mode. For DP, a single PPLL can be used for all DP | ||
1517 | * crtcs/encoders. | ||
1518 | */ | ||
1519 | static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) | ||
1520 | { | ||
1521 | struct drm_device *dev = crtc->dev; | ||
1522 | struct drm_encoder *test_encoder; | ||
1523 | struct radeon_crtc *radeon_test_crtc; | ||
1524 | |||
1525 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { | ||
1526 | if (test_encoder->crtc && (test_encoder->crtc != crtc)) { | ||
1527 | if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { | ||
1528 | /* for DP use the same PLL for all */ | ||
1529 | radeon_test_crtc = to_radeon_crtc(test_encoder->crtc); | ||
1530 | if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) | ||
1531 | return radeon_test_crtc->pll_id; | ||
1532 | } | ||
1533 | } | ||
1534 | } | ||
1535 | return ATOM_PPLL_INVALID; | ||
1536 | } | ||
1537 | |||
1538 | /** | ||
1539 | * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. | ||
1540 | * | ||
1541 | * @crtc: drm crtc | ||
1542 | * | ||
1543 | * Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors | ||
1544 | * a single PPLL can be used for all DP crtcs/encoders. For non-DP | ||
1545 | * monitors a dedicated PPLL must be used. If a particular board has | ||
1546 | * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming | ||
1547 | * as there is no need to program the PLL itself. If we are not able to | ||
1548 | * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to | ||
1549 | * avoid messing up an existing monitor. | ||
1550 | * | ||
1551 | * Asic specific PLL information | ||
1552 | * | ||
1553 | * DCE 6.1 | ||
1554 | * - PPLL2 is only available to UNIPHYA (both DP and non-DP) | ||
1555 | * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) | ||
1556 | * | ||
1557 | * DCE 6.0 | ||
1558 | * - PPLL0 is available to all UNIPHY (DP only) | ||
1559 | * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC | ||
1560 | * | ||
1561 | * DCE 5.0 | ||
1562 | * - DCPLL is available to all UNIPHY (DP only) | ||
1563 | * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC | ||
1564 | * | ||
1565 | * DCE 3.0/4.0/4.1 | ||
1566 | * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC | ||
1567 | * | ||
1568 | */ | ||
1485 | static int radeon_atom_pick_pll(struct drm_crtc *crtc) | 1569 | static int radeon_atom_pick_pll(struct drm_crtc *crtc) |
1486 | { | 1570 | { |
1487 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | 1571 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
1488 | struct drm_device *dev = crtc->dev; | 1572 | struct drm_device *dev = crtc->dev; |
1489 | struct radeon_device *rdev = dev->dev_private; | 1573 | struct radeon_device *rdev = dev->dev_private; |
1490 | struct drm_encoder *test_encoder; | 1574 | struct drm_encoder *test_encoder; |
1491 | struct drm_crtc *test_crtc; | 1575 | u32 pll_in_use; |
1492 | uint32_t pll_in_use = 0; | 1576 | int pll; |
1493 | 1577 | ||
1494 | if (ASIC_IS_DCE61(rdev)) { | 1578 | if (ASIC_IS_DCE61(rdev)) { |
1495 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { | 1579 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { |
@@ -1501,32 +1585,40 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) | |||
1501 | 1585 | ||
1502 | if ((test_radeon_encoder->encoder_id == | 1586 | if ((test_radeon_encoder->encoder_id == |
1503 | ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && | 1587 | ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && |
1504 | (dig->linkb == false)) /* UNIPHY A uses PPLL2 */ | 1588 | (dig->linkb == false)) |
1589 | /* UNIPHY A uses PPLL2 */ | ||
1505 | return ATOM_PPLL2; | 1590 | return ATOM_PPLL2; |
1591 | else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { | ||
1592 | /* UNIPHY B/C/D/E/F */ | ||
1593 | if (rdev->clock.dp_extclk) | ||
1594 | /* skip PPLL programming if using ext clock */ | ||
1595 | return ATOM_PPLL_INVALID; | ||
1596 | else { | ||
1597 | /* use the same PPLL for all DP monitors */ | ||
1598 | pll = radeon_get_shared_dp_ppll(crtc); | ||
1599 | if (pll != ATOM_PPLL_INVALID) | ||
1600 | return pll; | ||
1601 | } | ||
1602 | } | ||
1603 | break; | ||
1506 | } | 1604 | } |
1507 | } | 1605 | } |
1508 | /* UNIPHY B/C/D/E/F */ | 1606 | /* UNIPHY B/C/D/E/F */ |
1509 | list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { | 1607 | pll_in_use = radeon_get_pll_use_mask(crtc); |
1510 | struct radeon_crtc *radeon_test_crtc; | 1608 | if (!(pll_in_use & (1 << ATOM_PPLL0))) |
1511 | |||
1512 | if (crtc == test_crtc) | ||
1513 | continue; | ||
1514 | |||
1515 | radeon_test_crtc = to_radeon_crtc(test_crtc); | ||
1516 | if ((radeon_test_crtc->pll_id == ATOM_PPLL0) || | ||
1517 | (radeon_test_crtc->pll_id == ATOM_PPLL1)) | ||
1518 | pll_in_use |= (1 << radeon_test_crtc->pll_id); | ||
1519 | } | ||
1520 | if (!(pll_in_use & 4)) | ||
1521 | return ATOM_PPLL0; | 1609 | return ATOM_PPLL0; |
1522 | return ATOM_PPLL1; | 1610 | if (!(pll_in_use & (1 << ATOM_PPLL1))) |
1611 | return ATOM_PPLL1; | ||
1612 | DRM_ERROR("unable to allocate a PPLL\n"); | ||
1613 | return ATOM_PPLL_INVALID; | ||
1523 | } else if (ASIC_IS_DCE4(rdev)) { | 1614 | } else if (ASIC_IS_DCE4(rdev)) { |
1524 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { | 1615 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { |
1525 | if (test_encoder->crtc && (test_encoder->crtc == crtc)) { | 1616 | if (test_encoder->crtc && (test_encoder->crtc == crtc)) { |
1526 | /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, | 1617 | /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, |
1527 | * depending on the asic: | 1618 | * depending on the asic: |
1528 | * DCE4: PPLL or ext clock | 1619 | * DCE4: PPLL or ext clock |
1529 | * DCE5: DCPLL or ext clock | 1620 | * DCE5: PPLL, DCPLL, or ext clock |
1621 | * DCE6: PPLL, PPLL0, or ext clock | ||
1530 | * | 1622 | * |
1531 | * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip | 1623 | * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip |
1532 | * PPLL/DCPLL programming and only program the DP DTO for the | 1624 | * PPLL/DCPLL programming and only program the DP DTO for the |
@@ -1534,31 +1626,34 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) | |||
1534 | */ | 1626 | */ |
1535 | if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { | 1627 | if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { |
1536 | if (rdev->clock.dp_extclk) | 1628 | if (rdev->clock.dp_extclk) |
1629 | /* skip PPLL programming if using ext clock */ | ||
1537 | return ATOM_PPLL_INVALID; | 1630 | return ATOM_PPLL_INVALID; |
1538 | else if (ASIC_IS_DCE6(rdev)) | 1631 | else if (ASIC_IS_DCE6(rdev)) |
1632 | /* use PPLL0 for all DP */ | ||
1539 | return ATOM_PPLL0; | 1633 | return ATOM_PPLL0; |
1540 | else if (ASIC_IS_DCE5(rdev)) | 1634 | else if (ASIC_IS_DCE5(rdev)) |
1635 | /* use DCPLL for all DP */ | ||
1541 | return ATOM_DCPLL; | 1636 | return ATOM_DCPLL; |
1637 | else { | ||
1638 | /* use the same PPLL for all DP monitors */ | ||
1639 | pll = radeon_get_shared_dp_ppll(crtc); | ||
1640 | if (pll != ATOM_PPLL_INVALID) | ||
1641 | return pll; | ||
1642 | } | ||
1542 | } | 1643 | } |
1644 | break; | ||
1543 | } | 1645 | } |
1544 | } | 1646 | } |
1545 | 1647 | /* all other cases */ | |
1546 | /* otherwise, pick one of the plls */ | 1648 | pll_in_use = radeon_get_pll_use_mask(crtc); |
1547 | list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { | 1649 | if (!(pll_in_use & (1 << ATOM_PPLL2))) |
1548 | struct radeon_crtc *radeon_test_crtc; | 1650 | return ATOM_PPLL2; |
1549 | 1651 | if (!(pll_in_use & (1 << ATOM_PPLL1))) | |
1550 | if (crtc == test_crtc) | ||
1551 | continue; | ||
1552 | |||
1553 | radeon_test_crtc = to_radeon_crtc(test_crtc); | ||
1554 | if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && | ||
1555 | (radeon_test_crtc->pll_id <= ATOM_PPLL2)) | ||
1556 | pll_in_use |= (1 << radeon_test_crtc->pll_id); | ||
1557 | } | ||
1558 | if (!(pll_in_use & 1)) | ||
1559 | return ATOM_PPLL1; | 1652 | return ATOM_PPLL1; |
1560 | return ATOM_PPLL2; | 1653 | DRM_ERROR("unable to allocate a PPLL\n"); |
1654 | return ATOM_PPLL_INVALID; | ||
1561 | } else | 1655 | } else |
1656 | /* use PPLL1 or PPLL2 */ | ||
1562 | return radeon_crtc->crtc_id; | 1657 | return radeon_crtc->crtc_id; |
1563 | 1658 | ||
1564 | } | 1659 | } |
@@ -1700,7 +1795,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) | |||
1700 | break; | 1795 | break; |
1701 | } | 1796 | } |
1702 | done: | 1797 | done: |
1703 | radeon_crtc->pll_id = -1; | 1798 | radeon_crtc->pll_id = ATOM_PPLL_INVALID; |
1704 | } | 1799 | } |
1705 | 1800 | ||
1706 | static const struct drm_crtc_helper_funcs atombios_helper_funcs = { | 1801 | static const struct drm_crtc_helper_funcs atombios_helper_funcs = { |
@@ -1749,6 +1844,6 @@ void radeon_atombios_init_crtc(struct drm_device *dev, | |||
1749 | else | 1844 | else |
1750 | radeon_crtc->crtc_offset = 0; | 1845 | radeon_crtc->crtc_offset = 0; |
1751 | } | 1846 | } |
1752 | radeon_crtc->pll_id = -1; | 1847 | radeon_crtc->pll_id = ATOM_PPLL_INVALID; |
1753 | drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); | 1848 | drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); |
1754 | } | 1849 | } |