diff options
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 61 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 299 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_combios.c | 108 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 38 |
4 files changed, 506 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index df21edc..d73d37d 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -150,6 +150,8 @@ struct radeon_clock { */ int radeon_pm_init(struct radeon_device *rdev); void radeon_pm_compute_clocks(struct radeon_device *rdev); +void radeon_combios_get_power_modes(struct radeon_device *rdev); +void radeon_atombios_get_power_modes(struct radeon_device *rdev); /* * Fences. @@ -583,6 +585,59 @@ enum radeon_pm_action { PM_ACTION_DOWNCLOCK, PM_ACTION_UPCLOCK }; + +enum radeon_voltage_type { + VOLTAGE_NONE = 0, + VOLTAGE_GPIO, + VOLTAGE_VDDC, + VOLTAGE_SW +}; + +struct radeon_voltage { + enum radeon_voltage_type type; + /* gpio voltage */ + struct radeon_gpio_rec gpio; + u32 delay; /* delay in usec from voltage drop to sclk change */ + bool active_high; /* voltage drop is active when bit is high */ + /* VDDC voltage */ + u8 vddc_id; /* index into vddc voltage table */ + u8 vddci_id; /* index into vddci voltage table */ + bool vddci_enabled; + /* r6xx+ sw */ + u32 voltage; +}; + +struct radeon_pm_non_clock_info { + /* pcie lanes */ + int pcie_lanes; + /* standardized non-clock flags */ + u32 flags; +}; + +struct radeon_pm_clock_info { + /* memory clock */ + u32 mclk; + /* engine clock */ + u32 sclk; + /* voltage info */ + struct radeon_voltage voltage; + /* standardized clock flags - not sure we'll need these */ + u32 flags; +}; + +struct radeon_power_state { + /* XXX: use a define for num clock modes */ + struct radeon_pm_clock_info clock_info[8]; + /* number of valid clock modes in this power state */ + int num_clock_modes; + /* currently selected clock mode */ + struct radeon_pm_clock_info *current_clock_mode; + struct radeon_pm_clock_info *default_clock_mode; + /* non clock info about this state */ + struct radeon_pm_non_clock_info non_clock_info; + bool voltage_drop_active; +}; + struct radeon_pm { struct mutex mutex; struct work_struct reclock_work; @@ -609,6 +664,12 @@ struct radeon_pm { fixed20_12 core_bandwidth; fixed20_12 sclk; fixed20_12 needed_bandwidth; + /* XXX: use a define for num power modes */ + struct radeon_power_state power_state[8]; + /* number of valid power states */ + int num_power_states; + struct radeon_power_state *current_power_state; + struct radeon_power_state *default_power_state; }; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index d33fb41..adf900e 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) return tv_dac; } +union power_info { + struct _ATOM_POWERPLAY_INFO info; + struct _ATOM_POWERPLAY_INFO_V2 info_2; + struct _ATOM_POWERPLAY_INFO_V3 info_3; + struct _ATOM_PPLIB_POWERPLAYTABLE info_4; +}; + +void radeon_atombios_get_power_modes(struct radeon_device *rdev) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); + u16 data_offset; + u8 frev, crev; + u32 misc, misc2 = 0, sclk, mclk; + union power_info *power_info; + struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; + struct _ATOM_PPLIB_STATE *power_state; + int num_modes = 0, i, j; + int state_index = 0, mode_index = 0; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); + + power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); + + rdev->pm.default_power_state = NULL; + rdev->pm.current_power_state = NULL; + + if (power_info) { + if (frev < 4) { + num_modes = power_info->info.ucNumOfPowerModeEntries; + if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) + num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; + for (i = 0; i < num_modes; i++) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; + switch (frev) { + case 1: + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = + le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock); + rdev->pm.power_state[state_index].clock_info[0].sclk = + le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock); + /* skip invalid modes */ + if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || + (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) + continue; + /* skip overclock modes for now */ + if ((rdev->pm.power_state[state_index].clock_info[0].mclk > + rdev->clock.default_mclk) || + (rdev->pm.power_state[state_index].clock_info[0].sclk > + rdev->clock.default_sclk)) + continue; + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + power_info->info.asPowerPlayInfo[i].ucNumPciELanes; + misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); + if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_GPIO; + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = + radeon_lookup_gpio(rdev, + power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex); + if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + true; + else + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + false; + } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_VDDC; + rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = + power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; + } + if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { + rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.power_state[state_index].default_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].current_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + } + state_index++; + break; + case 2: + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = + le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock); + rdev->pm.power_state[state_index].clock_info[0].sclk = + le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock); + /* skip invalid modes */ + if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || + (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) + continue; + /* skip overclock modes for now */ + if ((rdev->pm.power_state[state_index].clock_info[0].mclk > + rdev->clock.default_mclk) || + (rdev->pm.power_state[state_index].clock_info[0].sclk > + rdev->clock.default_sclk)) + continue; + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; + misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); + misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); + if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_GPIO; + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = + radeon_lookup_gpio(rdev, + power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex); + if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + true; + else + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + false; + } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_VDDC; + rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = + power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; + } + if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { + rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.power_state[state_index].default_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].current_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + } + state_index++; + break; + case 3: + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = + le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock); + rdev->pm.power_state[state_index].clock_info[0].sclk = + le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock); + /* skip invalid modes */ + if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || + (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) + continue; + /* skip overclock modes for now */ + if ((rdev->pm.power_state[state_index].clock_info[0].mclk > + rdev->clock.default_mclk) || + (rdev->pm.power_state[state_index].clock_info[0].sclk > + rdev->clock.default_sclk)) + continue; + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; + misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); + misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); + if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_GPIO; + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = + radeon_lookup_gpio(rdev, + power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex); + if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + true; + else + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + false; + } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_VDDC; + rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = + power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex; + if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) { + rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled = + true; + rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id = + power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; + } + } + if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { + rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.power_state[state_index].default_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].current_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + } + state_index++; + break; + } + } + } else if (frev == 4) { + for (i = 0; i < power_info->info_4.ucNumStates; i++) { + mode_index = 0; + power_state = (struct _ATOM_PPLIB_STATE *) + (mode_info->atom_context->bios + + data_offset + + le16_to_cpu(power_info->info_4.usStateArrayOffset) + + i * power_info->info_4.ucStateEntrySize); + non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) + (mode_info->atom_context->bios + + data_offset + + le16_to_cpu(power_info->info_4.usNonClockInfoArrayOffset) + + (power_state->ucNonClockStateIndex * + power_info->info_4.ucNonClockSize)); + misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> + ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; + for (j = 0; j < (power_info->info_4.ucStateEntrySize - 1); j++) { + if (rdev->flags & RADEON_IS_IGP) { + struct _ATOM_PPLIB_RS780_CLOCK_INFO *clock_info = + (struct _ATOM_PPLIB_RS780_CLOCK_INFO *) + (mode_info->atom_context->bios + + data_offset + + le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + + (power_state->ucClockStateIndices[j] * + power_info->info_4.ucClockInfoSize)); + sclk = le16_to_cpu(clock_info->usLowEngineClockLow); + sclk |= clock_info->ucLowEngineClockHigh << 16; + rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; + /* skip invalid modes */ + if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) + continue; + /* skip overclock modes for now */ + if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > + rdev->clock.default_sclk) + continue; + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = + VOLTAGE_SW; + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = + clock_info->usVDDC; + mode_index++; + } else { + struct _ATOM_PPLIB_R600_CLOCK_INFO *clock_info = + (struct _ATOM_PPLIB_R600_CLOCK_INFO *) + (mode_info->atom_context->bios + + data_offset + + le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + + (power_state->ucClockStateIndices[j] * + power_info->info_4.ucClockInfoSize)); + sclk = le16_to_cpu(clock_info->usEngineClockLow); + sclk |= clock_info->ucEngineClockHigh << 16; + mclk = le16_to_cpu(clock_info->usMemoryClockLow); + mclk |= clock_info->ucMemoryClockHigh << 16; + rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; + rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; + /* skip invalid modes */ + if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || + (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) + continue; + /* skip overclock modes for now */ + if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk > + rdev->clock.default_mclk) || + (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > + rdev->clock.default_sclk)) + continue; + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = + VOLTAGE_SW; + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = + clock_info->usVDDC; + mode_index++; + } + } + rdev->pm.power_state[state_index].num_clock_modes = mode_index; + if (mode_index) { + misc2 = le16_to_cpu(non_clock_info->usClassification); + if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { + rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.power_state[state_index].default_clock_mode = + &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; + rdev->pm.power_state[state_index].current_clock_mode = + &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; + } + state_index++; + } + } + } + } else { + /* XXX figure out some good default low power mode for cards w/out power tables */ + } + + if (rdev->pm.default_power_state == NULL) { + /* add the default mode */ + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk; + rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; + rdev->pm.power_state[state_index].default_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].current_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; + if (rdev->asic->get_pcie_lanes) + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); + else + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; + rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; + state_index++; + } + rdev->pm.num_power_states = state_index; +} + void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) { DYNAMIC_CLOCK_GATING_PS_ALLOCATION args; diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 257ce17..eac2174 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2374,6 +2374,114 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) return true; } +void radeon_combios_get_power_modes(struct radeon_device *rdev) +{ + struct drm_device *dev = rdev->ddev; + u16 offset, misc, misc2 = 0; + u8 rev, blocks, tmp; + int state_index = 0; + + rdev->pm.default_power_state = NULL; + rdev->pm.current_power_state = NULL; + + /* XXX mac/sparc cards */ + if (rdev->bios == NULL) + goto default_mode; + + if (rdev->flags & RADEON_IS_MOBILITY) { + offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE); + if (offset) { + rev = RBIOS8(offset); + blocks = RBIOS8(offset + 0x2); + /* power mode 0 tends to be the only valid one */ + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = RBIOS32(offset + 0x5 + 0x2); + rdev->pm.power_state[state_index].clock_info[0].sclk = RBIOS32(offset + 0x5 + 0x6); + if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || + (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) + goto default_mode; + /* skip overclock modes for now */ + if ((rdev->pm.power_state[state_index].clock_info[0].mclk > + rdev->clock.default_mclk) || + (rdev->pm.power_state[state_index].clock_info[0].sclk > + rdev->clock.default_sclk)) + goto default_mode; + misc = RBIOS16(offset + 0x5 + 0x0); + if (rev > 4) + misc2 = RBIOS16(offset + 0x5 + 0xe); + if (misc & 0x4) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; + if (misc & 0x8) + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + true; + else + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + false; + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.valid = true; + if (rev < 6) { + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.reg = + RBIOS16(offset + 0x5 + 0xb) * 4; + tmp = RBIOS8(offset + 0x5 + 0xd); + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.mask = (1 << tmp); + } else { + u8 entries = RBIOS8(offset + 0x5 + 0xb); + u16 voltage_table_offset = RBIOS16(offset + 0x5 + 0xc); + if (entries && voltage_table_offset) { + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.reg = + RBIOS16(voltage_table_offset) * 4; + tmp = RBIOS8(voltage_table_offset + 0x2); + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.mask = (1 << tmp); + } else + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.valid = false; + } + switch ((misc2 & 0x700) >> 8) { + case 0: + default: + rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 0; + break; + case 1: + rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 33; + break; + case 2: + rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 66; + break; + case 3: + rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 99; + break; + case 4: + rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 132; + break; + } + } else + rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; + if (rev > 6) + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + RBIOS8(offset + 0x5 + 0x10); + state_index++; + } else { + /* XXX figure out some good default low power mode for mobility cards w/out power tables */ + } + } else { + /* XXX figure out some good default low power mode for desktop cards */ + } + +default_mode: + /* add the default mode */ + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk; + rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; + rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].current_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; + if (rdev->asic->get_pcie_lanes) + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); + else + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; + rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.current_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.num_power_states = state_index + 1; +} + void radeon_external_tmds_setup(struct drm_encoder *encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a9c61f4..6eb0e0b 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -18,6 +18,7 @@ * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Rafał Miłecki <zajec5@gmail.com> + * Alex Deucher <alexdeucher@gmail.com> */ #include "drmP.h" #include "radeon.h" @@ -39,6 +40,35 @@ static const char *pm_state_names[4] = { "PM_STATE_ACTIVE" }; +static void radeon_print_power_mode_info(struct radeon_device *rdev) +{ + int i, j; + bool is_default; + + DRM_INFO("%d Power State(s)\n", rdev->pm.num_power_states); + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.default_power_state == &rdev->pm.power_state[i]) + is_default = true; + else + is_default = false; + DRM_INFO("State %d %s\n", i, is_default ? "(default)" : ""); + if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) + DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].non_clock_info.pcie_lanes); + DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); + for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) { + if (rdev->flags & RADEON_IS_IGP) + DRM_INFO("\t\t%d engine: %d\n", + j, + rdev->pm.power_state[i].clock_info[j].sclk * 10); + else + DRM_INFO("\t\t%d engine/memory: %d/%d\n", + j, + rdev->pm.power_state[i].clock_info[j].sclk * 10, + rdev->pm.power_state[i].clock_info[j].mclk * 10); + } + } +} + int radeon_pm_init(struct radeon_device *rdev) { rdev->pm.state = PM_STATE_DISABLED; @@ -46,6 +76,14 @@ int radeon_pm_init(struct radeon_device *rdev) rdev->pm.downclocked = false; rdev->pm.vblank_callback = false; + if (rdev->bios) { + if (rdev->is_atom_bios) + radeon_atombios_get_power_modes(rdev); + else + radeon_combios_get_power_modes(rdev); + radeon_print_power_mode_info(rdev); + } + radeon_pm_check_limits(rdev); if (radeon_debugfs_pm_init(rdev)) { |