diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2009-12-28 13:58:44 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-02-08 18:32:27 -0500 |
commit | 56278a8edacee9ae9e3bc9d8c8e2d37e9969f3eb (patch) | |
tree | 2aea5e4707e5caffb30abacc78230bd6f7295c32 /drivers/gpu/drm/radeon/radeon_atombios.c | |
parent | c836a4126768cd76af9ee33b3c11f57695d5fda6 (diff) |
drm/radeon/kms: pull power mode info from bios tables (v3)
The general idea is to validate the current hw state
against the set of power states and select a power
state based on that. This patch just pulls the power
states from the bios and prints the information. It
is not currently hooked up in the actual power management
code. Hooking it up will require reworking the the current
power state selection code and will be handled in a future
patch.
Additionally, we'd need to decide on some default lower
power states for cards without power tables.
v2 - increment state_index after checking for default state
v3 - fix typo in pm init on pre-atom cards, handle pre-atom
cards without x86 bioses
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_atombios.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index d33fb4174b13..adf900e368ac 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
@@ -1393,6 +1393,305 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) | |||
1393 | return tv_dac; | 1393 | return tv_dac; |
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | union power_info { | ||
1397 | struct _ATOM_POWERPLAY_INFO info; | ||
1398 | struct _ATOM_POWERPLAY_INFO_V2 info_2; | ||
1399 | struct _ATOM_POWERPLAY_INFO_V3 info_3; | ||
1400 | struct _ATOM_PPLIB_POWERPLAYTABLE info_4; | ||
1401 | }; | ||
1402 | |||
1403 | void radeon_atombios_get_power_modes(struct radeon_device *rdev) | ||
1404 | { | ||
1405 | struct radeon_mode_info *mode_info = &rdev->mode_info; | ||
1406 | int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); | ||
1407 | u16 data_offset; | ||
1408 | u8 frev, crev; | ||
1409 | u32 misc, misc2 = 0, sclk, mclk; | ||
1410 | union power_info *power_info; | ||
1411 | struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; | ||
1412 | struct _ATOM_PPLIB_STATE *power_state; | ||
1413 | int num_modes = 0, i, j; | ||
1414 | int state_index = 0, mode_index = 0; | ||
1415 | |||
1416 | atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); | ||
1417 | |||
1418 | power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); | ||
1419 | |||
1420 | rdev->pm.default_power_state = NULL; | ||
1421 | rdev->pm.current_power_state = NULL; | ||
1422 | |||
1423 | if (power_info) { | ||
1424 | if (frev < 4) { | ||
1425 | num_modes = power_info->info.ucNumOfPowerModeEntries; | ||
1426 | if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) | ||
1427 | num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; | ||
1428 | for (i = 0; i < num_modes; i++) { | ||
1429 | rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; | ||
1430 | switch (frev) { | ||
1431 | case 1: | ||
1432 | rdev->pm.power_state[state_index].num_clock_modes = 1; | ||
1433 | rdev->pm.power_state[state_index].clock_info[0].mclk = | ||
1434 | le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock); | ||
1435 | rdev->pm.power_state[state_index].clock_info[0].sclk = | ||
1436 | le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock); | ||
1437 | /* skip invalid modes */ | ||
1438 | if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || | ||
1439 | (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) | ||
1440 | continue; | ||
1441 | /* skip overclock modes for now */ | ||
1442 | if ((rdev->pm.power_state[state_index].clock_info[0].mclk > | ||
1443 | rdev->clock.default_mclk) || | ||
1444 | (rdev->pm.power_state[state_index].clock_info[0].sclk > | ||
1445 | rdev->clock.default_sclk)) | ||
1446 | continue; | ||
1447 | rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = | ||
1448 | power_info->info.asPowerPlayInfo[i].ucNumPciELanes; | ||
1449 | misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); | ||
1450 | if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { | ||
1451 | rdev->pm.power_state[state_index].clock_info[0].voltage.type = | ||
1452 | VOLTAGE_GPIO; | ||
1453 | rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = | ||
1454 | radeon_lookup_gpio(rdev, | ||
1455 | power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex); | ||
1456 | if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) | ||
1457 | rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = | ||
1458 | true; | ||
1459 | else | ||
1460 | rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = | ||
1461 | false; | ||
1462 | } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { | ||
1463 | rdev->pm.power_state[state_index].clock_info[0].voltage.type = | ||
1464 | VOLTAGE_VDDC; | ||
1465 | rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = | ||
1466 | power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; | ||
1467 | } | ||
1468 | if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { | ||
1469 | rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; | ||
1470 | rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; | ||
1471 | rdev->pm.power_state[state_index].default_clock_mode = | ||
1472 | &rdev->pm.power_state[state_index].clock_info[0]; | ||
1473 | rdev->pm.power_state[state_index].current_clock_mode = | ||
1474 | &rdev->pm.power_state[state_index].clock_info[0]; | ||
1475 | } | ||
1476 | state_index++; | ||
1477 | break; | ||
1478 | case 2: | ||
1479 | rdev->pm.power_state[state_index].num_clock_modes = 1; | ||
1480 | rdev->pm.power_state[state_index].clock_info[0].mclk = | ||
1481 | le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock); | ||
1482 | rdev->pm.power_state[state_index].clock_info[0].sclk = | ||
1483 | le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock); | ||
1484 | /* skip invalid modes */ | ||
1485 | if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || | ||
1486 | (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) | ||
1487 | continue; | ||
1488 | /* skip overclock modes for now */ | ||
1489 | if ((rdev->pm.power_state[state_index].clock_info[0].mclk > | ||
1490 | rdev->clock.default_mclk) || | ||
1491 | (rdev->pm.power_state[state_index].clock_info[0].sclk > | ||
1492 | rdev->clock.default_sclk)) | ||
1493 | continue; | ||
1494 | rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = | ||
1495 | power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; | ||
1496 | misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); | ||
1497 | misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); | ||
1498 | if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { | ||
1499 | rdev->pm.power_state[state_index].clock_info[0].voltage.type = | ||
1500 | VOLTAGE_GPIO; | ||
1501 | rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = | ||
1502 | radeon_lookup_gpio(rdev, | ||
1503 | power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex); | ||
1504 | if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) | ||
1505 | rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = | ||
1506 | true; | ||
1507 | else | ||
1508 | rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = | ||
1509 | false; | ||
1510 | } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { | ||
1511 | rdev->pm.power_state[state_index].clock_info[0].voltage.type = | ||
1512 | VOLTAGE_VDDC; | ||
1513 | rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = | ||
1514 | power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; | ||
1515 | } | ||
1516 | if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { | ||
1517 | rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; | ||
1518 | rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; | ||
1519 | rdev->pm.power_state[state_index].default_clock_mode = | ||
1520 | &rdev->pm.power_state[state_index].clock_info[0]; | ||
1521 | rdev->pm.power_state[state_index].current_clock_mode = | ||
1522 | &rdev->pm.power_state[state_index].clock_info[0]; | ||
1523 | } | ||
1524 | state_index++; | ||
1525 | break; | ||
1526 | case 3: | ||
1527 | rdev->pm.power_state[state_index].num_clock_modes = 1; | ||
1528 | rdev->pm.power_state[state_index].clock_info[0].mclk = | ||
1529 | le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock); | ||
1530 | rdev->pm.power_state[state_index].clock_info[0].sclk = | ||
1531 | le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock); | ||
1532 | /* skip invalid modes */ | ||
1533 | if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || | ||
1534 | (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) | ||
1535 | continue; | ||
1536 | /* skip overclock modes for now */ | ||
1537 | if ((rdev->pm.power_state[state_index].clock_info[0].mclk > | ||
1538 | rdev->clock.default_mclk) || | ||
1539 | (rdev->pm.power_state[state_index].clock_info[0].sclk > | ||
1540 | rdev->clock.default_sclk)) | ||
1541 | continue; | ||
1542 | rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = | ||
1543 | power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; | ||
1544 | misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); | ||
1545 | misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); | ||
1546 | if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { | ||
1547 | rdev->pm.power_state[state_index].clock_info[0].voltage.type = | ||
1548 | VOLTAGE_GPIO; | ||
1549 | rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = | ||
1550 | radeon_lookup_gpio(rdev, | ||
1551 | power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex); | ||
1552 | if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) | ||
1553 | rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = | ||
1554 | true; | ||
1555 | else | ||
1556 | rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = | ||
1557 | false; | ||
1558 | } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { | ||
1559 | rdev->pm.power_state[state_index].clock_info[0].voltage.type = | ||
1560 | VOLTAGE_VDDC; | ||
1561 | rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = | ||
1562 | power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex; | ||
1563 | if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) { | ||
1564 | rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled = | ||
1565 | true; | ||
1566 | rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id = | ||
1567 | power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; | ||
1568 | } | ||
1569 | } | ||
1570 | if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { | ||
1571 | rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; | ||
1572 | rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; | ||
1573 | rdev->pm.power_state[state_index].default_clock_mode = | ||
1574 | &rdev->pm.power_state[state_index].clock_info[0]; | ||
1575 | rdev->pm.power_state[state_index].current_clock_mode = | ||
1576 | &rdev->pm.power_state[state_index].clock_info[0]; | ||
1577 | } | ||
1578 | state_index++; | ||
1579 | break; | ||
1580 | } | ||
1581 | } | ||
1582 | } else if (frev == 4) { | ||
1583 | for (i = 0; i < power_info->info_4.ucNumStates; i++) { | ||
1584 | mode_index = 0; | ||
1585 | power_state = (struct _ATOM_PPLIB_STATE *) | ||
1586 | (mode_info->atom_context->bios + | ||
1587 | data_offset + | ||
1588 | le16_to_cpu(power_info->info_4.usStateArrayOffset) + | ||
1589 | i * power_info->info_4.ucStateEntrySize); | ||
1590 | non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) | ||
1591 | (mode_info->atom_context->bios + | ||
1592 | data_offset + | ||
1593 | le16_to_cpu(power_info->info_4.usNonClockInfoArrayOffset) + | ||
1594 | (power_state->ucNonClockStateIndex * | ||
1595 | power_info->info_4.ucNonClockSize)); | ||
1596 | misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); | ||
1597 | rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = | ||
1598 | ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> | ||
1599 | ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; | ||
1600 | for (j = 0; j < (power_info->info_4.ucStateEntrySize - 1); j++) { | ||
1601 | if (rdev->flags & RADEON_IS_IGP) { | ||
1602 | struct _ATOM_PPLIB_RS780_CLOCK_INFO *clock_info = | ||
1603 | (struct _ATOM_PPLIB_RS780_CLOCK_INFO *) | ||
1604 | (mode_info->atom_context->bios + | ||
1605 | data_offset + | ||
1606 | le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + | ||
1607 | (power_state->ucClockStateIndices[j] * | ||
1608 | power_info->info_4.ucClockInfoSize)); | ||
1609 | sclk = le16_to_cpu(clock_info->usLowEngineClockLow); | ||
1610 | sclk |= clock_info->ucLowEngineClockHigh << 16; | ||
1611 | rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; | ||
1612 | /* skip invalid modes */ | ||
1613 | if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) | ||
1614 | continue; | ||
1615 | /* skip overclock modes for now */ | ||
1616 | if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > | ||
1617 | rdev->clock.default_sclk) | ||
1618 | continue; | ||
1619 | rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = | ||
1620 | VOLTAGE_SW; | ||
1621 | rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = | ||
1622 | clock_info->usVDDC; | ||
1623 | mode_index++; | ||
1624 | } else { | ||
1625 | struct _ATOM_PPLIB_R600_CLOCK_INFO *clock_info = | ||
1626 | (struct _ATOM_PPLIB_R600_CLOCK_INFO *) | ||
1627 | (mode_info->atom_context->bios + | ||
1628 | data_offset + | ||
1629 | le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + | ||
1630 | (power_state->ucClockStateIndices[j] * | ||
1631 | power_info->info_4.ucClockInfoSize)); | ||
1632 | sclk = le16_to_cpu(clock_info->usEngineClockLow); | ||
1633 | sclk |= clock_info->ucEngineClockHigh << 16; | ||
1634 | mclk = le16_to_cpu(clock_info->usMemoryClockLow); | ||
1635 | mclk |= clock_info->ucMemoryClockHigh << 16; | ||
1636 | rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; | ||
1637 | rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; | ||
1638 | /* skip invalid modes */ | ||
1639 | if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || | ||
1640 | (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) | ||
1641 | continue; | ||
1642 | /* skip overclock modes for now */ | ||
1643 | if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk > | ||
1644 | rdev->clock.default_mclk) || | ||
1645 | (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > | ||
1646 | rdev->clock.default_sclk)) | ||
1647 | continue; | ||
1648 | rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = | ||
1649 | VOLTAGE_SW; | ||
1650 | rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = | ||
1651 | clock_info->usVDDC; | ||
1652 | mode_index++; | ||
1653 | } | ||
1654 | } | ||
1655 | rdev->pm.power_state[state_index].num_clock_modes = mode_index; | ||
1656 | if (mode_index) { | ||
1657 | misc2 = le16_to_cpu(non_clock_info->usClassification); | ||
1658 | if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { | ||
1659 | rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; | ||
1660 | rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; | ||
1661 | rdev->pm.power_state[state_index].default_clock_mode = | ||
1662 | &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; | ||
1663 | rdev->pm.power_state[state_index].current_clock_mode = | ||
1664 | &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; | ||
1665 | } | ||
1666 | state_index++; | ||
1667 | } | ||
1668 | } | ||
1669 | } | ||
1670 | } else { | ||
1671 | /* XXX figure out some good default low power mode for cards w/out power tables */ | ||
1672 | } | ||
1673 | |||
1674 | if (rdev->pm.default_power_state == NULL) { | ||
1675 | /* add the default mode */ | ||
1676 | rdev->pm.power_state[state_index].num_clock_modes = 1; | ||
1677 | rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk; | ||
1678 | rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; | ||
1679 | rdev->pm.power_state[state_index].default_clock_mode = | ||
1680 | &rdev->pm.power_state[state_index].clock_info[0]; | ||
1681 | rdev->pm.power_state[state_index].current_clock_mode = | ||
1682 | &rdev->pm.power_state[state_index].clock_info[0]; | ||
1683 | rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; | ||
1684 | if (rdev->asic->get_pcie_lanes) | ||
1685 | rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); | ||
1686 | else | ||
1687 | rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; | ||
1688 | rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; | ||
1689 | rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; | ||
1690 | state_index++; | ||
1691 | } | ||
1692 | rdev->pm.num_power_states = state_index; | ||
1693 | } | ||
1694 | |||
1396 | void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) | 1695 | void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) |
1397 | { | 1696 | { |
1398 | DYNAMIC_CLOCK_GATING_PS_ALLOCATION args; | 1697 | DYNAMIC_CLOCK_GATING_PS_ALLOCATION args; |