diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2012-09-12 18:54:14 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2012-09-20 13:10:44 -0400 |
commit | 2f454cf1261ba913e2f660b7555864b340502c60 (patch) | |
tree | 3582704f7e9e07c0036e597dca80394d10bcca18 /drivers | |
parent | 9dbbcfc6894957fdbb311ba92c85c026659878b5 (diff) |
drm/radeon: allow PPLL sharing on non-DP displays
If several non-DP displays use the same pixel clock
we can use the same PPLL for all of them. If all
relevant displays have the same pixel clock, this
allows the driver to:
- use fewer PPLLs which saves power
- support more than two non-DP displays on DCE4+
The current drm modesetting infrastructure doesn't
really provide a good framework for validating combinations
that work or won't work, so it's possible you could go from
a working configuration to a non-working one by changing the
mode a one of the displays. However, there this is better
than what was there before.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_crtc.c | 71 |
1 files changed, 65 insertions, 6 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index c5a040677d48..2f7cc9e3b175 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
@@ -1536,6 +1536,49 @@ static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) | |||
1536 | } | 1536 | } |
1537 | 1537 | ||
1538 | /** | 1538 | /** |
1539 | * radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc | ||
1540 | * | ||
1541 | * @crtc: drm crtc | ||
1542 | * @encoder: drm encoder | ||
1543 | * | ||
1544 | * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can | ||
1545 | * be shared (i.e., same clock). | ||
1546 | */ | ||
1547 | static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc, | ||
1548 | struct drm_encoder *encoder) | ||
1549 | { | ||
1550 | struct drm_device *dev = crtc->dev; | ||
1551 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
1552 | struct drm_encoder *test_encoder; | ||
1553 | struct radeon_crtc *radeon_test_crtc; | ||
1554 | struct radeon_encoder *test_radeon_encoder; | ||
1555 | u32 target_clock, test_clock; | ||
1556 | |||
1557 | if (radeon_encoder->native_mode.clock) | ||
1558 | target_clock = radeon_encoder->native_mode.clock; | ||
1559 | else | ||
1560 | target_clock = crtc->mode.clock; | ||
1561 | |||
1562 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { | ||
1563 | if (test_encoder->crtc && (test_encoder->crtc != crtc)) { | ||
1564 | if (!ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { | ||
1565 | test_radeon_encoder = to_radeon_encoder(test_encoder); | ||
1566 | radeon_test_crtc = to_radeon_crtc(test_encoder->crtc); | ||
1567 | /* for non-DP check the clock */ | ||
1568 | if (test_radeon_encoder->native_mode.clock) | ||
1569 | test_clock = test_radeon_encoder->native_mode.clock; | ||
1570 | else | ||
1571 | test_clock = test_encoder->crtc->mode.clock; | ||
1572 | if ((target_clock == test_clock) && | ||
1573 | (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID)) | ||
1574 | return radeon_test_crtc->pll_id; | ||
1575 | } | ||
1576 | } | ||
1577 | } | ||
1578 | return ATOM_PPLL_INVALID; | ||
1579 | } | ||
1580 | |||
1581 | /** | ||
1539 | * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. | 1582 | * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. |
1540 | * | 1583 | * |
1541 | * @crtc: drm crtc | 1584 | * @crtc: drm crtc |
@@ -1568,7 +1611,6 @@ static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) | |||
1568 | */ | 1611 | */ |
1569 | static int radeon_atom_pick_pll(struct drm_crtc *crtc) | 1612 | static int radeon_atom_pick_pll(struct drm_crtc *crtc) |
1570 | { | 1613 | { |
1571 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
1572 | struct drm_device *dev = crtc->dev; | 1614 | struct drm_device *dev = crtc->dev; |
1573 | struct radeon_device *rdev = dev->dev_private; | 1615 | struct radeon_device *rdev = dev->dev_private; |
1574 | struct drm_encoder *test_encoder; | 1616 | struct drm_encoder *test_encoder; |
@@ -1599,6 +1641,11 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) | |||
1599 | if (pll != ATOM_PPLL_INVALID) | 1641 | if (pll != ATOM_PPLL_INVALID) |
1600 | return pll; | 1642 | return pll; |
1601 | } | 1643 | } |
1644 | } else { | ||
1645 | /* use the same PPLL for all monitors with the same clock */ | ||
1646 | pll = radeon_get_shared_nondp_ppll(crtc, test_encoder); | ||
1647 | if (pll != ATOM_PPLL_INVALID) | ||
1648 | return pll; | ||
1602 | } | 1649 | } |
1603 | break; | 1650 | break; |
1604 | } | 1651 | } |
@@ -1640,6 +1687,11 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) | |||
1640 | if (pll != ATOM_PPLL_INVALID) | 1687 | if (pll != ATOM_PPLL_INVALID) |
1641 | return pll; | 1688 | return pll; |
1642 | } | 1689 | } |
1690 | } else { | ||
1691 | /* use the same PPLL for all monitors with the same clock */ | ||
1692 | pll = radeon_get_shared_nondp_ppll(crtc, test_encoder); | ||
1693 | if (pll != ATOM_PPLL_INVALID) | ||
1694 | return pll; | ||
1643 | } | 1695 | } |
1644 | break; | 1696 | break; |
1645 | } | 1697 | } |
@@ -1652,7 +1704,12 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) | |||
1652 | return ATOM_PPLL1; | 1704 | return ATOM_PPLL1; |
1653 | DRM_ERROR("unable to allocate a PPLL\n"); | 1705 | DRM_ERROR("unable to allocate a PPLL\n"); |
1654 | return ATOM_PPLL_INVALID; | 1706 | return ATOM_PPLL_INVALID; |
1655 | } else if (ASIC_IS_DCE3(rdev)) { | 1707 | } else { |
1708 | /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ | ||
1709 | if (!ASIC_IS_AVIVO(rdev)) { | ||
1710 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
1711 | return radeon_crtc->crtc_id; | ||
1712 | } | ||
1656 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { | 1713 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { |
1657 | if (test_encoder->crtc && (test_encoder->crtc == crtc)) { | 1714 | if (test_encoder->crtc && (test_encoder->crtc == crtc)) { |
1658 | /* in DP mode, the DP ref clock can come from either PPLL | 1715 | /* in DP mode, the DP ref clock can come from either PPLL |
@@ -1664,6 +1721,11 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) | |||
1664 | pll = radeon_get_shared_dp_ppll(crtc); | 1721 | pll = radeon_get_shared_dp_ppll(crtc); |
1665 | if (pll != ATOM_PPLL_INVALID) | 1722 | if (pll != ATOM_PPLL_INVALID) |
1666 | return pll; | 1723 | return pll; |
1724 | } else { | ||
1725 | /* use the same PPLL for all monitors with the same clock */ | ||
1726 | pll = radeon_get_shared_nondp_ppll(crtc, test_encoder); | ||
1727 | if (pll != ATOM_PPLL_INVALID) | ||
1728 | return pll; | ||
1667 | } | 1729 | } |
1668 | break; | 1730 | break; |
1669 | } | 1731 | } |
@@ -1676,10 +1738,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) | |||
1676 | return ATOM_PPLL1; | 1738 | return ATOM_PPLL1; |
1677 | DRM_ERROR("unable to allocate a PPLL\n"); | 1739 | DRM_ERROR("unable to allocate a PPLL\n"); |
1678 | return ATOM_PPLL_INVALID; | 1740 | return ATOM_PPLL_INVALID; |
1679 | } else | 1741 | } |
1680 | /* use PPLL1 or PPLL2 */ | ||
1681 | return radeon_crtc->crtc_id; | ||
1682 | |||
1683 | } | 1742 | } |
1684 | 1743 | ||
1685 | void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev) | 1744 | void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev) |