diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/atombios_crtc.c')
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_crtc.c | 199 |
1 files changed, 145 insertions, 54 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index f4d4505fe831..e721e3087b99 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
@@ -258,7 +258,6 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
258 | radeon_crtc->enabled = true; | 258 | radeon_crtc->enabled = true; |
259 | /* adjust pm to dpms changes BEFORE enabling crtcs */ | 259 | /* adjust pm to dpms changes BEFORE enabling crtcs */ |
260 | radeon_pm_compute_clocks(rdev); | 260 | radeon_pm_compute_clocks(rdev); |
261 | /* disable crtc pair power gating before programming */ | ||
262 | if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) | 261 | if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) |
263 | atombios_powergate_crtc(crtc, ATOM_DISABLE); | 262 | atombios_powergate_crtc(crtc, ATOM_DISABLE); |
264 | atombios_enable_crtc(crtc, ATOM_ENABLE); | 263 | atombios_enable_crtc(crtc, ATOM_ENABLE); |
@@ -278,25 +277,8 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
278 | atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); | 277 | atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); |
279 | atombios_enable_crtc(crtc, ATOM_DISABLE); | 278 | atombios_enable_crtc(crtc, ATOM_DISABLE); |
280 | radeon_crtc->enabled = false; | 279 | radeon_crtc->enabled = false; |
281 | /* power gating is per-pair */ | 280 | if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) |
282 | if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) { | 281 | atombios_powergate_crtc(crtc, ATOM_ENABLE); |
283 | struct drm_crtc *other_crtc; | ||
284 | struct radeon_crtc *other_radeon_crtc; | ||
285 | list_for_each_entry(other_crtc, &rdev->ddev->mode_config.crtc_list, head) { | ||
286 | other_radeon_crtc = to_radeon_crtc(other_crtc); | ||
287 | if (((radeon_crtc->crtc_id == 0) && (other_radeon_crtc->crtc_id == 1)) || | ||
288 | ((radeon_crtc->crtc_id == 1) && (other_radeon_crtc->crtc_id == 0)) || | ||
289 | ((radeon_crtc->crtc_id == 2) && (other_radeon_crtc->crtc_id == 3)) || | ||
290 | ((radeon_crtc->crtc_id == 3) && (other_radeon_crtc->crtc_id == 2)) || | ||
291 | ((radeon_crtc->crtc_id == 4) && (other_radeon_crtc->crtc_id == 5)) || | ||
292 | ((radeon_crtc->crtc_id == 5) && (other_radeon_crtc->crtc_id == 4))) { | ||
293 | /* if both crtcs in the pair are off, enable power gating */ | ||
294 | if (other_radeon_crtc->enabled == false) | ||
295 | atombios_powergate_crtc(crtc, ATOM_ENABLE); | ||
296 | break; | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | /* adjust pm to dpms changes AFTER disabling crtcs */ | 282 | /* adjust pm to dpms changes AFTER disabling crtcs */ |
301 | radeon_pm_compute_clocks(rdev); | 283 | radeon_pm_compute_clocks(rdev); |
302 | break; | 284 | break; |
@@ -1497,14 +1479,98 @@ static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) | |||
1497 | } | 1479 | } |
1498 | } | 1480 | } |
1499 | 1481 | ||
1482 | /** | ||
1483 | * radeon_get_pll_use_mask - look up a mask of which pplls are in use | ||
1484 | * | ||
1485 | * @crtc: drm crtc | ||
1486 | * | ||
1487 | * Returns the mask of which PPLLs (Pixel PLLs) are in use. | ||
1488 | */ | ||
1489 | static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) | ||
1490 | { | ||
1491 | struct drm_device *dev = crtc->dev; | ||
1492 | struct drm_crtc *test_crtc; | ||
1493 | struct radeon_crtc *radeon_test_crtc; | ||
1494 | u32 pll_in_use = 0; | ||
1495 | |||
1496 | list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { | ||
1497 | if (crtc == test_crtc) | ||
1498 | continue; | ||
1499 | |||
1500 | radeon_test_crtc = to_radeon_crtc(test_crtc); | ||
1501 | if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) | ||
1502 | pll_in_use |= (1 << radeon_test_crtc->pll_id); | ||
1503 | } | ||
1504 | return pll_in_use; | ||
1505 | } | ||
1506 | |||
1507 | /** | ||
1508 | * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP | ||
1509 | * | ||
1510 | * @crtc: drm crtc | ||
1511 | * | ||
1512 | * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is | ||
1513 | * also in DP mode. For DP, a single PPLL can be used for all DP | ||
1514 | * crtcs/encoders. | ||
1515 | */ | ||
1516 | static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) | ||
1517 | { | ||
1518 | struct drm_device *dev = crtc->dev; | ||
1519 | struct drm_encoder *test_encoder; | ||
1520 | struct radeon_crtc *radeon_test_crtc; | ||
1521 | |||
1522 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { | ||
1523 | if (test_encoder->crtc && (test_encoder->crtc != crtc)) { | ||
1524 | if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { | ||
1525 | /* for DP use the same PLL for all */ | ||
1526 | radeon_test_crtc = to_radeon_crtc(test_encoder->crtc); | ||
1527 | if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) | ||
1528 | return radeon_test_crtc->pll_id; | ||
1529 | } | ||
1530 | } | ||
1531 | } | ||
1532 | return ATOM_PPLL_INVALID; | ||
1533 | } | ||
1534 | |||
1535 | /** | ||
1536 | * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. | ||
1537 | * | ||
1538 | * @crtc: drm crtc | ||
1539 | * | ||
1540 | * Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors | ||
1541 | * a single PPLL can be used for all DP crtcs/encoders. For non-DP | ||
1542 | * monitors a dedicated PPLL must be used. If a particular board has | ||
1543 | * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming | ||
1544 | * as there is no need to program the PLL itself. If we are not able to | ||
1545 | * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to | ||
1546 | * avoid messing up an existing monitor. | ||
1547 | * | ||
1548 | * Asic specific PLL information | ||
1549 | * | ||
1550 | * DCE 6.1 | ||
1551 | * - PPLL2 is only available to UNIPHYA (both DP and non-DP) | ||
1552 | * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) | ||
1553 | * | ||
1554 | * DCE 6.0 | ||
1555 | * - PPLL0 is available to all UNIPHY (DP only) | ||
1556 | * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC | ||
1557 | * | ||
1558 | * DCE 5.0 | ||
1559 | * - DCPLL is available to all UNIPHY (DP only) | ||
1560 | * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC | ||
1561 | * | ||
1562 | * DCE 3.0/4.0/4.1 | ||
1563 | * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC | ||
1564 | * | ||
1565 | */ | ||
1500 | static int radeon_atom_pick_pll(struct drm_crtc *crtc) | 1566 | static int radeon_atom_pick_pll(struct drm_crtc *crtc) |
1501 | { | 1567 | { |
1502 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | 1568 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
1503 | struct drm_device *dev = crtc->dev; | 1569 | struct drm_device *dev = crtc->dev; |
1504 | struct radeon_device *rdev = dev->dev_private; | 1570 | struct radeon_device *rdev = dev->dev_private; |
1505 | struct drm_encoder *test_encoder; | 1571 | struct drm_encoder *test_encoder; |
1506 | struct drm_crtc *test_crtc; | 1572 | u32 pll_in_use; |
1507 | uint32_t pll_in_use = 0; | 1573 | int pll; |
1508 | 1574 | ||
1509 | if (ASIC_IS_DCE61(rdev)) { | 1575 | if (ASIC_IS_DCE61(rdev)) { |
1510 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { | 1576 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { |
@@ -1516,32 +1582,40 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) | |||
1516 | 1582 | ||
1517 | if ((test_radeon_encoder->encoder_id == | 1583 | if ((test_radeon_encoder->encoder_id == |
1518 | ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && | 1584 | ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && |
1519 | (dig->linkb == false)) /* UNIPHY A uses PPLL2 */ | 1585 | (dig->linkb == false)) |
1586 | /* UNIPHY A uses PPLL2 */ | ||
1520 | return ATOM_PPLL2; | 1587 | return ATOM_PPLL2; |
1588 | else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { | ||
1589 | /* UNIPHY B/C/D/E/F */ | ||
1590 | if (rdev->clock.dp_extclk) | ||
1591 | /* skip PPLL programming if using ext clock */ | ||
1592 | return ATOM_PPLL_INVALID; | ||
1593 | else { | ||
1594 | /* use the same PPLL for all DP monitors */ | ||
1595 | pll = radeon_get_shared_dp_ppll(crtc); | ||
1596 | if (pll != ATOM_PPLL_INVALID) | ||
1597 | return pll; | ||
1598 | } | ||
1599 | } | ||
1600 | break; | ||
1521 | } | 1601 | } |
1522 | } | 1602 | } |
1523 | /* UNIPHY B/C/D/E/F */ | 1603 | /* UNIPHY B/C/D/E/F */ |
1524 | list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { | 1604 | pll_in_use = radeon_get_pll_use_mask(crtc); |
1525 | struct radeon_crtc *radeon_test_crtc; | 1605 | if (!(pll_in_use & (1 << ATOM_PPLL0))) |
1526 | |||
1527 | if (crtc == test_crtc) | ||
1528 | continue; | ||
1529 | |||
1530 | radeon_test_crtc = to_radeon_crtc(test_crtc); | ||
1531 | if ((radeon_test_crtc->pll_id == ATOM_PPLL0) || | ||
1532 | (radeon_test_crtc->pll_id == ATOM_PPLL1)) | ||
1533 | pll_in_use |= (1 << radeon_test_crtc->pll_id); | ||
1534 | } | ||
1535 | if (!(pll_in_use & 4)) | ||
1536 | return ATOM_PPLL0; | 1606 | return ATOM_PPLL0; |
1537 | return ATOM_PPLL1; | 1607 | if (!(pll_in_use & (1 << ATOM_PPLL1))) |
1608 | return ATOM_PPLL1; | ||
1609 | DRM_ERROR("unable to allocate a PPLL\n"); | ||
1610 | return ATOM_PPLL_INVALID; | ||
1538 | } else if (ASIC_IS_DCE4(rdev)) { | 1611 | } else if (ASIC_IS_DCE4(rdev)) { |
1539 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { | 1612 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { |
1540 | if (test_encoder->crtc && (test_encoder->crtc == crtc)) { | 1613 | if (test_encoder->crtc && (test_encoder->crtc == crtc)) { |
1541 | /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, | 1614 | /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, |
1542 | * depending on the asic: | 1615 | * depending on the asic: |
1543 | * DCE4: PPLL or ext clock | 1616 | * DCE4: PPLL or ext clock |
1544 | * DCE5: DCPLL or ext clock | 1617 | * DCE5: PPLL, DCPLL, or ext clock |
1618 | * DCE6: PPLL, PPLL0, or ext clock | ||
1545 | * | 1619 | * |
1546 | * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip | 1620 | * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip |
1547 | * PPLL/DCPLL programming and only program the DP DTO for the | 1621 | * PPLL/DCPLL programming and only program the DP DTO for the |
@@ -1549,31 +1623,34 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) | |||
1549 | */ | 1623 | */ |
1550 | if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { | 1624 | if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { |
1551 | if (rdev->clock.dp_extclk) | 1625 | if (rdev->clock.dp_extclk) |
1626 | /* skip PPLL programming if using ext clock */ | ||
1552 | return ATOM_PPLL_INVALID; | 1627 | return ATOM_PPLL_INVALID; |
1553 | else if (ASIC_IS_DCE6(rdev)) | 1628 | else if (ASIC_IS_DCE6(rdev)) |
1629 | /* use PPLL0 for all DP */ | ||
1554 | return ATOM_PPLL0; | 1630 | return ATOM_PPLL0; |
1555 | else if (ASIC_IS_DCE5(rdev)) | 1631 | else if (ASIC_IS_DCE5(rdev)) |
1632 | /* use DCPLL for all DP */ | ||
1556 | return ATOM_DCPLL; | 1633 | return ATOM_DCPLL; |
1634 | else { | ||
1635 | /* use the same PPLL for all DP monitors */ | ||
1636 | pll = radeon_get_shared_dp_ppll(crtc); | ||
1637 | if (pll != ATOM_PPLL_INVALID) | ||
1638 | return pll; | ||
1639 | } | ||
1557 | } | 1640 | } |
1641 | break; | ||
1558 | } | 1642 | } |
1559 | } | 1643 | } |
1560 | 1644 | /* all other cases */ | |
1561 | /* otherwise, pick one of the plls */ | 1645 | pll_in_use = radeon_get_pll_use_mask(crtc); |
1562 | list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { | 1646 | if (!(pll_in_use & (1 << ATOM_PPLL2))) |
1563 | struct radeon_crtc *radeon_test_crtc; | 1647 | return ATOM_PPLL2; |
1564 | 1648 | if (!(pll_in_use & (1 << ATOM_PPLL1))) | |
1565 | if (crtc == test_crtc) | ||
1566 | continue; | ||
1567 | |||
1568 | radeon_test_crtc = to_radeon_crtc(test_crtc); | ||
1569 | if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && | ||
1570 | (radeon_test_crtc->pll_id <= ATOM_PPLL2)) | ||
1571 | pll_in_use |= (1 << radeon_test_crtc->pll_id); | ||
1572 | } | ||
1573 | if (!(pll_in_use & 1)) | ||
1574 | return ATOM_PPLL1; | 1649 | return ATOM_PPLL1; |
1575 | return ATOM_PPLL2; | 1650 | DRM_ERROR("unable to allocate a PPLL\n"); |
1651 | return ATOM_PPLL_INVALID; | ||
1576 | } else | 1652 | } else |
1653 | /* use PPLL1 or PPLL2 */ | ||
1577 | return radeon_crtc->crtc_id; | 1654 | return radeon_crtc->crtc_id; |
1578 | 1655 | ||
1579 | } | 1656 | } |
@@ -1682,9 +1759,22 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) | |||
1682 | struct drm_device *dev = crtc->dev; | 1759 | struct drm_device *dev = crtc->dev; |
1683 | struct radeon_device *rdev = dev->dev_private; | 1760 | struct radeon_device *rdev = dev->dev_private; |
1684 | struct radeon_atom_ss ss; | 1761 | struct radeon_atom_ss ss; |
1762 | int i; | ||
1685 | 1763 | ||
1686 | atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | 1764 | atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
1687 | 1765 | ||
1766 | for (i = 0; i < rdev->num_crtc; i++) { | ||
1767 | if (rdev->mode_info.crtcs[i] && | ||
1768 | rdev->mode_info.crtcs[i]->enabled && | ||
1769 | i != radeon_crtc->crtc_id && | ||
1770 | radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) { | ||
1771 | /* one other crtc is using this pll don't turn | ||
1772 | * off the pll | ||
1773 | */ | ||
1774 | goto done; | ||
1775 | } | ||
1776 | } | ||
1777 | |||
1688 | switch (radeon_crtc->pll_id) { | 1778 | switch (radeon_crtc->pll_id) { |
1689 | case ATOM_PPLL1: | 1779 | case ATOM_PPLL1: |
1690 | case ATOM_PPLL2: | 1780 | case ATOM_PPLL2: |
@@ -1701,7 +1791,8 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) | |||
1701 | default: | 1791 | default: |
1702 | break; | 1792 | break; |
1703 | } | 1793 | } |
1704 | radeon_crtc->pll_id = -1; | 1794 | done: |
1795 | radeon_crtc->pll_id = ATOM_PPLL_INVALID; | ||
1705 | } | 1796 | } |
1706 | 1797 | ||
1707 | static const struct drm_crtc_helper_funcs atombios_helper_funcs = { | 1798 | static const struct drm_crtc_helper_funcs atombios_helper_funcs = { |
@@ -1750,6 +1841,6 @@ void radeon_atombios_init_crtc(struct drm_device *dev, | |||
1750 | else | 1841 | else |
1751 | radeon_crtc->crtc_offset = 0; | 1842 | radeon_crtc->crtc_offset = 0; |
1752 | } | 1843 | } |
1753 | radeon_crtc->pll_id = -1; | 1844 | radeon_crtc->pll_id = ATOM_PPLL_INVALID; |
1754 | drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); | 1845 | drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); |
1755 | } | 1846 | } |