Commit 560154e9 authored by Alex Deucher's avatar Alex Deucher Committed by Dave Airlie

drm/radeon/kms: refactor atombios power state fetching

The function was getting too large.  Rework it to share
more state better handle new power table formats.
Signed-off-by: default avatarAlex Deucher <alexdeucher@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent e719ebd9
...@@ -1763,495 +1763,504 @@ static const char *pp_lib_thermal_controller_names[] = { ...@@ -1763,495 +1763,504 @@ static const char *pp_lib_thermal_controller_names[] = {
"RV6xx", "RV6xx",
"RV770", "RV770",
"adt7473", "adt7473",
"NONE",
"External GPIO", "External GPIO",
"Evergreen", "Evergreen",
"adt7473 with internal", "adt7473 with internal",
}; };
union power_info { union power_info {
struct _ATOM_POWERPLAY_INFO info; struct _ATOM_POWERPLAY_INFO info;
struct _ATOM_POWERPLAY_INFO_V2 info_2; struct _ATOM_POWERPLAY_INFO_V2 info_2;
struct _ATOM_POWERPLAY_INFO_V3 info_3; struct _ATOM_POWERPLAY_INFO_V3 info_3;
struct _ATOM_PPLIB_POWERPLAYTABLE info_4; struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
}; };
void radeon_atombios_get_power_modes(struct radeon_device *rdev) union pplib_clock_info {
struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
};
union pplib_power_state {
struct _ATOM_PPLIB_STATE v1;
struct _ATOM_PPLIB_STATE_V2 v2;
};
static void radeon_atombios_parse_misc_flags_1_3(struct radeon_device *rdev,
int state_index,
u32 misc, u32 misc2)
{
rdev->pm.power_state[state_index].misc = misc;
rdev->pm.power_state[state_index].misc2 = misc2;
/* order matters! */
if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_POWERSAVE;
if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
rdev->pm.power_state[state_index].flags &=
~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
}
if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.default_power_state_index = state_index;
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[0];
} else if (state_index == 0) {
rdev->pm.power_state[state_index].clock_info[0].flags |=
RADEON_PM_MODE_NO_DISPLAY;
}
}
static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
{ {
struct radeon_mode_info *mode_info = &rdev->mode_info; struct radeon_mode_info *mode_info = &rdev->mode_info;
u32 misc, misc2 = 0;
int num_modes = 0, i;
int state_index = 0;
struct radeon_i2c_bus_rec i2c_bus;
union power_info *power_info;
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
u16 data_offset; u16 data_offset;
u8 frev, crev; 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;
struct radeon_i2c_bus_rec i2c_bus;
rdev->pm.default_power_state_index = -1;
if (atom_parse_data_header(mode_info->atom_context, index, NULL, if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
&frev, &crev, &data_offset)) { &frev, &crev, &data_offset))
power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); return state_index;
if (frev < 4) { power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
/* add the i2c bus for thermal/fan chip */
if (power_info->info.ucOverdriveThermalController > 0) { /* add the i2c bus for thermal/fan chip */
DRM_INFO("Possible %s thermal controller at 0x%02x\n", if (power_info->info.ucOverdriveThermalController > 0) {
thermal_controller_names[power_info->info.ucOverdriveThermalController], DRM_INFO("Possible %s thermal controller at 0x%02x\n",
power_info->info.ucOverdriveControllerAddress >> 1); thermal_controller_names[power_info->info.ucOverdriveThermalController],
i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine); power_info->info.ucOverdriveControllerAddress >> 1);
rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine);
if (rdev->pm.i2c_bus) { rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
struct i2c_board_info info = { }; if (rdev->pm.i2c_bus) {
const char *name = thermal_controller_names[power_info->info. struct i2c_board_info info = { };
ucOverdriveThermalController]; const char *name = thermal_controller_names[power_info->info.
info.addr = power_info->info.ucOverdriveControllerAddress >> 1; ucOverdriveThermalController];
strlcpy(info.type, name, sizeof(info.type)); info.addr = power_info->info.ucOverdriveControllerAddress >> 1;
i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); strlcpy(info.type, name, sizeof(info.type));
} i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
}
}
num_modes = power_info->info.ucNumOfPowerModeEntries;
if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
/* last mode is usually default, array is low to high */
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;
rdev->pm.power_state[state_index].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) ||
(misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
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;
} }
num_modes = power_info->info.ucNumOfPowerModeEntries; rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0);
num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; state_index++;
/* last mode is usually default, array is low to high */ break;
for (i = 0; i < num_modes; i++) { case 2:
rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; rdev->pm.power_state[state_index].num_clock_modes = 1;
switch (frev) { rdev->pm.power_state[state_index].clock_info[0].mclk =
case 1: le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock);
rdev->pm.power_state[state_index].num_clock_modes = 1; rdev->pm.power_state[state_index].clock_info[0].sclk =
rdev->pm.power_state[state_index].clock_info[0].mclk = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock);
le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock); /* skip invalid modes */
rdev->pm.power_state[state_index].clock_info[0].sclk = if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock); (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
/* skip invalid modes */ continue;
if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || rdev->pm.power_state[state_index].pcie_lanes =
(rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
continue; misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
rdev->pm.power_state[state_index].pcie_lanes = misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2);
power_info->info.asPowerPlayInfo[i].ucNumPciELanes; if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || rdev->pm.power_state[state_index].clock_info[0].voltage.type =
(misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { VOLTAGE_GPIO;
rdev->pm.power_state[state_index].clock_info[0].voltage.type = rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
VOLTAGE_GPIO; radeon_lookup_gpio(rdev,
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
radeon_lookup_gpio(rdev, if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex); rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) true;
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = else
true; rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
else false;
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
false; rdev->pm.power_state[state_index].clock_info[0].voltage.type =
} else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { VOLTAGE_VDDC;
rdev->pm.power_state[state_index].clock_info[0].voltage.type = rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
VOLTAGE_VDDC; power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
}
rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
rdev->pm.power_state[state_index].misc = misc;
/* order matters! */
if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_POWERSAVE;
if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
rdev->pm.power_state[state_index].flags &=
~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
}
if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.default_power_state_index = 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].flags &=
~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
} else if (state_index == 0) {
rdev->pm.power_state[state_index].clock_info[0].flags |=
RADEON_PM_MODE_NO_DISPLAY;
}
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;
rdev->pm.power_state[state_index].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) ||
(misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
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;
}
rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
rdev->pm.power_state[state_index].misc = misc;
rdev->pm.power_state[state_index].misc2 = misc2;
/* order matters! */
if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_POWERSAVE;
if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
rdev->pm.power_state[state_index].flags &=
~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
}
if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc2 & ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT)
rdev->pm.power_state[state_index].flags &=
~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.default_power_state_index = 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].flags &=
~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
} else if (state_index == 0) {
rdev->pm.power_state[state_index].clock_info[0].flags |=
RADEON_PM_MODE_NO_DISPLAY;
}
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;
rdev->pm.power_state[state_index].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) ||
(misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
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;
}
}
rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
rdev->pm.power_state[state_index].misc = misc;
rdev->pm.power_state[state_index].misc2 = misc2;
/* order matters! */
if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_POWERSAVE;
if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
rdev->pm.power_state[state_index].flags &=
~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
}
if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.default_power_state_index = state_index;
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[0];
} else if (state_index == 0) {
rdev->pm.power_state[state_index].clock_info[0].flags |=
RADEON_PM_MODE_NO_DISPLAY;
}
state_index++;
break;
}
} }
/* last mode is usually default */ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
if (rdev->pm.default_power_state_index == -1) { radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
rdev->pm.power_state[state_index - 1].type = state_index++;
POWER_STATE_TYPE_DEFAULT; break;
rdev->pm.default_power_state_index = state_index - 1; case 3:
rdev->pm.power_state[state_index - 1].default_clock_mode = rdev->pm.power_state[state_index].num_clock_modes = 1;
&rdev->pm.power_state[state_index - 1].clock_info[0]; rdev->pm.power_state[state_index].clock_info[0].mclk =
rdev->pm.power_state[state_index].flags &= le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock);
~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; rdev->pm.power_state[state_index].clock_info[0].sclk =
rdev->pm.power_state[state_index].misc = 0; le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock);
rdev->pm.power_state[state_index].misc2 = 0; /* 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;
rdev->pm.power_state[state_index].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) ||
(misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
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;
}
} }
rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
state_index++;
break;
}
}
/* last mode is usually default */
if (rdev->pm.default_power_state_index == -1) {
rdev->pm.power_state[state_index - 1].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.default_power_state_index = state_index - 1;
rdev->pm.power_state[state_index - 1].default_clock_mode =
&rdev->pm.power_state[state_index - 1].clock_info[0];
rdev->pm.power_state[state_index].flags &=
~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
rdev->pm.power_state[state_index].misc = 0;
rdev->pm.power_state[state_index].misc2 = 0;
}
return state_index;
}
static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *rdev,
ATOM_PPLIB_THERMALCONTROLLER *controller)
{
struct radeon_i2c_bus_rec i2c_bus;
/* add the i2c bus for thermal/fan chip */
if (controller->ucType > 0) {
if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
DRM_INFO("Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
DRM_INFO("Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
rdev->pm.int_thermal_type = THERMAL_TYPE_RV770;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
DRM_INFO("Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
} else if ((controller->ucType ==
ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
(controller->ucType ==
ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL)) {
DRM_INFO("Special thermal controller config\n");
} else { } else {
int fw_index = GetIndexIntoMasterTable(DATA, FirmwareInfo); DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
uint8_t fw_frev, fw_crev; pp_lib_thermal_controller_names[controller->ucType],
uint16_t fw_data_offset, vddc = 0; controller->ucI2cAddress >> 1,
union firmware_info *firmware_info; (controller->ucFanParameters &
ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController; ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
if (atom_parse_data_header(mode_info->atom_context, fw_index, NULL, rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
&fw_frev, &fw_crev, &fw_data_offset)) { if (rdev->pm.i2c_bus) {
firmware_info = struct i2c_board_info info = { };
(union firmware_info *)(mode_info->atom_context->bios + const char *name = pp_lib_thermal_controller_names[controller->ucType];
fw_data_offset); info.addr = controller->ucI2cAddress >> 1;
vddc = firmware_info->info_14.usBootUpVDDCVoltage; strlcpy(info.type, name, sizeof(info.type));
i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
} }
}
}
}
/* add the i2c bus for thermal/fan chip */ static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev)
if (controller->ucType > 0) { {
if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { struct radeon_mode_info *mode_info = &rdev->mode_info;
DRM_INFO("Internal thermal controller %s fan control\n", int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
(controller->ucFanParameters & u8 frev, crev;
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); u16 data_offset;
rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX; union firmware_info *firmware_info;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) { u16 vddc = 0;
DRM_INFO("Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
rdev->pm.int_thermal_type = THERMAL_TYPE_RV770;
} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
DRM_INFO("Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
} else if ((controller->ucType ==
ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
(controller->ucType ==
ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL)) {
DRM_INFO("Special thermal controller config\n");
} else {
DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
pp_lib_thermal_controller_names[controller->ucType],
controller->ucI2cAddress >> 1,
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
if (rdev->pm.i2c_bus) {
struct i2c_board_info info = { };
const char *name = pp_lib_thermal_controller_names[controller->ucType];
info.addr = controller->ucI2cAddress >> 1;
strlcpy(info.type, name, sizeof(info.type));
i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
}
} if (atom_parse_data_header(mode_info->atom_context, index, NULL,
} &frev, &crev, &data_offset)) {
/* first mode is usually default, followed by low to high */ firmware_info =
for (i = 0; i < power_info->info_4.ucNumStates; i++) { (union firmware_info *)(mode_info->atom_context->bios +
mode_index = 0; data_offset);
power_state = (struct _ATOM_PPLIB_STATE *) vddc = firmware_info->info_14.usBootUpVDDCVoltage;
(mode_info->atom_context->bios + }
data_offset +
le16_to_cpu(power_info->info_4.usStateArrayOffset) + return vddc;
i * power_info->info_4.ucStateEntrySize); }
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
(mode_info->atom_context->bios + static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev,
data_offset + int state_index, int mode_index,
le16_to_cpu(power_info->info_4.usNonClockInfoArrayOffset) + struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info)
(power_state->ucNonClockStateIndex * {
power_info->info_4.ucNonClockSize)); int j;
for (j = 0; j < (power_info->info_4.ucStateEntrySize - 1); j++) { u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
if (rdev->flags & RADEON_IS_IGP) { u32 misc2 = le16_to_cpu(non_clock_info->usClassification);
struct _ATOM_PPLIB_RS780_CLOCK_INFO *clock_info = u16 vddc = radeon_atombios_get_default_vddc(rdev);
(struct _ATOM_PPLIB_RS780_CLOCK_INFO *)
(mode_info->atom_context->bios + rdev->pm.power_state[state_index].misc = misc;
data_offset + rdev->pm.power_state[state_index].misc2 = misc2;
le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + rdev->pm.power_state[state_index].pcie_lanes =
(power_state->ucClockStateIndices[j] * ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
power_info->info_4.ucClockInfoSize)); ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
sclk = le16_to_cpu(clock_info->usLowEngineClockLow); switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
sclk |= clock_info->ucLowEngineClockHigh << 16; case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; rdev->pm.power_state[state_index].type =
/* skip invalid modes */ POWER_STATE_TYPE_BATTERY;
if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) break;
continue; case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
/* voltage works differently on IGPs */ rdev->pm.power_state[state_index].type =
mode_index++; POWER_STATE_TYPE_BALANCED;
} else if (ASIC_IS_DCE4(rdev)) { break;
struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *clock_info = case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
(struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *) rdev->pm.power_state[state_index].type =
(mode_info->atom_context->bios + POWER_STATE_TYPE_PERFORMANCE;
data_offset + break;
le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
(power_state->ucClockStateIndices[j] * if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
power_info->info_4.ucClockInfoSize)); rdev->pm.power_state[state_index].type =
sclk = le16_to_cpu(clock_info->usEngineClockLow); POWER_STATE_TYPE_PERFORMANCE;
sclk |= clock_info->ucEngineClockHigh << 16; break;
mclk = le16_to_cpu(clock_info->usMemoryClockLow); }
mclk |= clock_info->ucMemoryClockHigh << 16; rdev->pm.power_state[state_index].flags = 0;
rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; rdev->pm.power_state[state_index].flags |=
/* skip invalid modes */ RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
(rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) rdev->pm.power_state[state_index].type =
continue; POWER_STATE_TYPE_DEFAULT;
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = rdev->pm.default_power_state_index = state_index;
VOLTAGE_SW; rdev->pm.power_state[state_index].default_clock_mode =
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = &rdev->pm.power_state[state_index].clock_info[mode_index - 1];
clock_info->usVDDC; /* patch the table values with the default slck/mclk from firmware info */
/* XXX usVDDCI */ for (j = 0; j < mode_index; j++) {
mode_index++; rdev->pm.power_state[state_index].clock_info[j].mclk =
} else { rdev->clock.default_mclk;
struct _ATOM_PPLIB_R600_CLOCK_INFO *clock_info = rdev->pm.power_state[state_index].clock_info[j].sclk =
(struct _ATOM_PPLIB_R600_CLOCK_INFO *) rdev->clock.default_sclk;
(mode_info->atom_context->bios + if (vddc)
data_offset + rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + vddc;
(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); static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
mclk |= clock_info->ucMemoryClockHigh << 16; int state_index, int mode_index,
rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; union pplib_clock_info *clock_info)
rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; {
/* skip invalid modes */ u32 sclk, mclk;
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)) if (rdev->flags & RADEON_IS_IGP) {
continue; sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = } else if (ASIC_IS_DCE4(rdev)) {
clock_info->usVDDC; sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
mode_index++; sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
} mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
} mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
rdev->pm.power_state[state_index].num_clock_modes = mode_index; rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
if (mode_index) { rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
misc2 = le16_to_cpu(non_clock_info->usClassification); VOLTAGE_SW;
rdev->pm.power_state[state_index].misc = misc; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
rdev->pm.power_state[state_index].misc2 = misc2; clock_info->evergreen.usVDDC;
rdev->pm.power_state[state_index].pcie_lanes = } else {
((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; sclk |= clock_info->r600.ucEngineClockHigh << 16;
switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY: mclk |= clock_info->r600.ucMemoryClockHigh << 16;
rdev->pm.power_state[state_index].type = rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
POWER_STATE_TYPE_BATTERY; rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
break; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED: VOLTAGE_SW;
rdev->pm.power_state[state_index].type = rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
POWER_STATE_TYPE_BALANCED; clock_info->r600.usVDDC;
break; }
case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
rdev->pm.power_state[state_index].type = if (rdev->flags & RADEON_IS_IGP) {
POWER_STATE_TYPE_PERFORMANCE; /* skip invalid modes */
break; if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
case ATOM_PPLIB_CLASSIFICATION_UI_NONE: return false;
if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) } else {
rdev->pm.power_state[state_index].type = /* skip invalid modes */
POWER_STATE_TYPE_PERFORMANCE; if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
break; (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
} return false;
rdev->pm.power_state[state_index].flags = 0; }
if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) return true;
rdev->pm.power_state[state_index].flags |= }
RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev)
rdev->pm.power_state[state_index].type = {
POWER_STATE_TYPE_DEFAULT; struct radeon_mode_info *mode_info = &rdev->mode_info;
rdev->pm.default_power_state_index = state_index; struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
rdev->pm.power_state[state_index].default_clock_mode = union pplib_power_state *power_state;
&rdev->pm.power_state[state_index].clock_info[mode_index - 1]; int i, j;
/* patch the table values with the default slck/mclk from firmware info */ int state_index = 0, mode_index = 0;
for (j = 0; j < mode_index; j++) { union pplib_clock_info *clock_info;
rdev->pm.power_state[state_index].clock_info[j].mclk = bool valid;
rdev->clock.default_mclk; union power_info *power_info;
rdev->pm.power_state[state_index].clock_info[j].sclk = int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
rdev->clock.default_sclk; u16 data_offset;
if (vddc) u8 frev, crev;
rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
vddc; if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
} &frev, &crev, &data_offset))
} return state_index;
state_index++; power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
}
} radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
/* if multiple clock modes, mark the lowest as no display */ /* first mode is usually default, followed by low to high */
for (i = 0; i < state_index; i++) { for (i = 0; i < power_info->pplib.ucNumStates; i++) {
if (rdev->pm.power_state[i].num_clock_modes > 1) mode_index = 0;
rdev->pm.power_state[i].clock_info[0].flags |= power_state = (union pplib_power_state *)
RADEON_PM_MODE_NO_DISPLAY; (mode_info->atom_context->bios + data_offset +
} le16_to_cpu(power_info->pplib.usStateArrayOffset) +
/* first mode is usually default */ i * power_info->pplib.ucStateEntrySize);
if (rdev->pm.default_power_state_index == -1) { non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
rdev->pm.power_state[0].type = (mode_info->atom_context->bios + data_offset +
POWER_STATE_TYPE_DEFAULT; le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
rdev->pm.default_power_state_index = 0; (power_state->v1.ucNonClockStateIndex *
rdev->pm.power_state[0].default_clock_mode = power_info->pplib.ucNonClockSize));
&rdev->pm.power_state[0].clock_info[0]; for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
} clock_info = (union pplib_clock_info *)
(mode_info->atom_context->bios + data_offset +
le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
(power_state->v1.ucClockStateIndices[j] *
power_info->pplib.ucClockInfoSize));
valid = radeon_atombios_parse_pplib_clock_info(rdev,
state_index, mode_index,
clock_info);
if (valid)
mode_index++;
}
rdev->pm.power_state[state_index].num_clock_modes = mode_index;
if (mode_index) {
radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
non_clock_info);
state_index++;
}
}
/* if multiple clock modes, mark the lowest as no display */
for (i = 0; i < state_index; i++) {
if (rdev->pm.power_state[i].num_clock_modes > 1)
rdev->pm.power_state[i].clock_info[0].flags |=
RADEON_PM_MODE_NO_DISPLAY;
}
/* first mode is usually default */
if (rdev->pm.default_power_state_index == -1) {
rdev->pm.power_state[0].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.default_power_state_index = 0;
rdev->pm.power_state[0].default_clock_mode =
&rdev->pm.power_state[0].clock_info[0];
}
return state_index;
}
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;
int state_index = 0;
rdev->pm.default_power_state_index = -1;
if (atom_parse_data_header(mode_info->atom_context, index, NULL,
&frev, &crev, &data_offset)) {
switch (frev) {
case 1:
case 2:
case 3:
state_index = radeon_atombios_parse_power_table_1_3(rdev);
break;
case 4:
case 5:
state_index = radeon_atombios_parse_power_table_4_5(rdev);
break;
default:
break;
} }
} else { } else {
/* add the default mode */ /* add the default mode */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment