aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/atombios_crtc.c
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2012-09-17 17:34:45 -0400
committerAlex Deucher <alexander.deucher@amd.com>2012-09-27 10:22:40 -0400
commit57b35e29cf4e45eb163631c4ece10dbc259ddf30 (patch)
treeadd8d0761eb25bd74bb0ee1e94fd77f93f77e8e0 /drivers/gpu/drm/radeon/atombios_crtc.c
parent9642ac0e645198b62f99279704e829a286f58d96 (diff)
drm/radeon: work around KMS modeset limitations in PLL allocation (v2)
Since the current KMS API sets the mode independantly on each crtc, we may end up with resource conflicts. The PLL allocation is one of those cases. In the following example we have 3 crtcs in use driving 2 DVI connectors and 1 DP connector. On the initial kernel modeset for fbdev, the display topology ends up as follows: crtc0 -> DP-0 crtc1 -> DVI-0 crtc2 -> DVI-1 Because this is the first modeset, all of the PLLs are available as none have been assigned. So we end up with the following: crtc0 uses DCPLL crtc1 uses PPLL2 crtc2 uses PPLL1 When X starts, it assigns a different topology: crtc0 -> DVI-0 crtc1 -> DP-0 crtc2 -> DVI-1 However, since the KMS API is per crtc, we set the mode on each crtc independantly. When it comes time to set the mode on crtc0, the topology for crtc1 and crtc2 are still intact. crtc1 and crtc2 are already assigned PPLL2 and PPLL1 so when it comes time to set the mode on crtc0, crtc1 and crtc2 have not been torn down yet, so there appears to be no PLLs available. In reality, we are reconfiguring the entire display topology, however, since each crtc is handled independantly, we don't know that in the driver at each crtc mode set time. This patch checks to see if the same connector is being driven by another crtc, and if so, uses the PLL already associated with it. v2: store connector in the radeon crtc struct, simplify checking. Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/atombios_crtc.c')
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c66
1 files changed, 38 insertions, 28 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 721f80e9568d..8e32c5891be1 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1492,16 +1492,16 @@ static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc)
1492{ 1492{
1493 struct drm_device *dev = crtc->dev; 1493 struct drm_device *dev = crtc->dev;
1494 struct drm_crtc *test_crtc; 1494 struct drm_crtc *test_crtc;
1495 struct radeon_crtc *radeon_test_crtc; 1495 struct radeon_crtc *test_radeon_crtc;
1496 u32 pll_in_use = 0; 1496 u32 pll_in_use = 0;
1497 1497
1498 list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1498 list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
1499 if (crtc == test_crtc) 1499 if (crtc == test_crtc)
1500 continue; 1500 continue;
1501 1501
1502 radeon_test_crtc = to_radeon_crtc(test_crtc); 1502 test_radeon_crtc = to_radeon_crtc(test_crtc);
1503 if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) 1503 if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)
1504 pll_in_use |= (1 << radeon_test_crtc->pll_id); 1504 pll_in_use |= (1 << test_radeon_crtc->pll_id);
1505 } 1505 }
1506 return pll_in_use; 1506 return pll_in_use;
1507} 1507}
@@ -1518,17 +1518,18 @@ static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc)
1518static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) 1518static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc)
1519{ 1519{
1520 struct drm_device *dev = crtc->dev; 1520 struct drm_device *dev = crtc->dev;
1521 struct drm_encoder *test_encoder; 1521 struct drm_crtc *test_crtc;
1522 struct radeon_crtc *test_radeon_crtc; 1522 struct radeon_crtc *test_radeon_crtc;
1523 1523
1524 list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 1524 list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
1525 if (test_encoder->crtc && (test_encoder->crtc != crtc)) { 1525 if (crtc == test_crtc)
1526 if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { 1526 continue;
1527 /* for DP use the same PLL for all */ 1527 test_radeon_crtc = to_radeon_crtc(test_crtc);
1528 test_radeon_crtc = to_radeon_crtc(test_encoder->crtc); 1528 if (test_radeon_crtc->encoder &&
1529 if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 1529 ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) {
1530 return test_radeon_crtc->pll_id; 1530 /* for DP use the same PLL for all */
1531 } 1531 if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)
1532 return test_radeon_crtc->pll_id;
1532 } 1533 }
1533 } 1534 }
1534 return ATOM_PPLL_INVALID; 1535 return ATOM_PPLL_INVALID;
@@ -1547,10 +1548,8 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc)
1547{ 1548{
1548 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1549 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1549 struct drm_device *dev = crtc->dev; 1550 struct drm_device *dev = crtc->dev;
1550 struct drm_encoder *test_encoder;
1551 struct drm_crtc *test_crtc; 1551 struct drm_crtc *test_crtc;
1552 struct radeon_crtc *test_radeon_crtc; 1552 struct radeon_crtc *test_radeon_crtc;
1553 struct radeon_encoder *test_radeon_encoder;
1554 u32 adjusted_clock, test_adjusted_clock; 1553 u32 adjusted_clock, test_adjusted_clock;
1555 1554
1556 adjusted_clock = radeon_crtc->adjusted_clock; 1555 adjusted_clock = radeon_crtc->adjusted_clock;
@@ -1558,20 +1557,25 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc)
1558 if (adjusted_clock == 0) 1557 if (adjusted_clock == 0)
1559 return ATOM_PPLL_INVALID; 1558 return ATOM_PPLL_INVALID;
1560 1559
1561 list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 1560 list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
1562 if (test_encoder->crtc && (test_encoder->crtc != crtc)) { 1561 if (crtc == test_crtc)
1563 if (!ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { 1562 continue;
1564 test_radeon_encoder = to_radeon_encoder(test_encoder); 1563 test_radeon_crtc = to_radeon_crtc(test_crtc);
1565 test_crtc = test_encoder->crtc; 1564 if (test_radeon_crtc->encoder &&
1566 test_radeon_crtc = to_radeon_crtc(test_crtc); 1565 !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) {
1567 /* for non-DP check the clock */ 1566 /* check if we are already driving this connector with another crtc */
1568 test_adjusted_clock = test_radeon_crtc->adjusted_clock; 1567 if (test_radeon_crtc->connector == radeon_crtc->connector) {
1569 if ((crtc->mode.clock == test_crtc->mode.clock) && 1568 /* if we are, return that pll */
1570 (adjusted_clock == test_adjusted_clock) && 1569 if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)
1571 (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) &&
1572 (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID))
1573 return test_radeon_crtc->pll_id; 1570 return test_radeon_crtc->pll_id;
1574 } 1571 }
1572 /* for non-DP check the clock */
1573 test_adjusted_clock = test_radeon_crtc->adjusted_clock;
1574 if ((crtc->mode.clock == test_crtc->mode.clock) &&
1575 (adjusted_clock == test_adjusted_clock) &&
1576 (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) &&
1577 (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID))
1578 return test_radeon_crtc->pll_id;
1575 } 1579 }
1576 } 1580 }
1577 return ATOM_PPLL_INVALID; 1581 return ATOM_PPLL_INVALID;
@@ -1793,11 +1797,15 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
1793 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 1797 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1794 if (encoder->crtc == crtc) { 1798 if (encoder->crtc == crtc) {
1795 radeon_crtc->encoder = encoder; 1799 radeon_crtc->encoder = encoder;
1800 radeon_crtc->connector = radeon_get_connector_for_encoder(encoder);
1796 break; 1801 break;
1797 } 1802 }
1798 } 1803 }
1799 if (radeon_crtc->encoder == NULL) 1804 if ((radeon_crtc->encoder == NULL) || (radeon_crtc->connector == NULL)) {
1805 radeon_crtc->encoder = NULL;
1806 radeon_crtc->connector = NULL;
1800 return false; 1807 return false;
1808 }
1801 if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 1809 if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
1802 return false; 1810 return false;
1803 if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) 1811 if (!atombios_crtc_prepare_pll(crtc, adjusted_mode))
@@ -1874,6 +1882,7 @@ done:
1874 radeon_crtc->pll_id = ATOM_PPLL_INVALID; 1882 radeon_crtc->pll_id = ATOM_PPLL_INVALID;
1875 radeon_crtc->adjusted_clock = 0; 1883 radeon_crtc->adjusted_clock = 0;
1876 radeon_crtc->encoder = NULL; 1884 radeon_crtc->encoder = NULL;
1885 radeon_crtc->connector = NULL;
1877} 1886}
1878 1887
1879static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 1888static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
@@ -1925,5 +1934,6 @@ void radeon_atombios_init_crtc(struct drm_device *dev,
1925 radeon_crtc->pll_id = ATOM_PPLL_INVALID; 1934 radeon_crtc->pll_id = ATOM_PPLL_INVALID;
1926 radeon_crtc->adjusted_clock = 0; 1935 radeon_crtc->adjusted_clock = 0;
1927 radeon_crtc->encoder = NULL; 1936 radeon_crtc->encoder = NULL;
1937 radeon_crtc->connector = NULL;
1928 drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 1938 drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
1929} 1939}