Loading drivers/gpu/drm/radeon/radeon_atombios.c +475 −466 Original line number Diff line number Diff line Loading @@ -1763,39 +1763,87 @@ static const char *pp_lib_thermal_controller_names[] = { "RV6xx", "RV770", "adt7473", "NONE", "External GPIO", "Evergreen", "adt7473 with internal", }; 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; 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; 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); 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; 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, &frev, &crev, &data_offset)) { if (!atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) return state_index; power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); if (frev < 4) { /* add the i2c bus for thermal/fan chip */ if (power_info->info.ucOverdriveThermalController > 0) { DRM_INFO("Possible %s thermal controller at 0x%02x\n", Loading Loading @@ -1852,38 +1900,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) 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; } radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0); state_index++; break; case 2: Loading Loading @@ -1920,45 +1937,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) 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; } radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2); state_index++; break; case 3: Loading Loading @@ -2001,40 +1980,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } } 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; } radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2); state_index++; break; } Loading @@ -2051,21 +1997,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].misc = 0; rdev->pm.power_state[state_index].misc2 = 0; } } else { int fw_index = GetIndexIntoMasterTable(DATA, FirmwareInfo); uint8_t fw_frev, fw_crev; uint16_t fw_data_offset, vddc = 0; union firmware_info *firmware_info; ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController; if (atom_parse_data_header(mode_info->atom_context, fw_index, NULL, &fw_frev, &fw_crev, &fw_data_offset)) { firmware_info = (union firmware_info *)(mode_info->atom_context->bios + fw_data_offset); vddc = firmware_info->info_14.usBootUpVDDCVoltage; 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) { Loading Loading @@ -2103,93 +2042,39 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) strlcpy(info.type, name, sizeof(info.type)); i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); } } } /* first mode is usually default, followed by low to high */ 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)); 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; /* voltage works differently on IGPs */ mode_index++; } else if (ASIC_IS_DCE4(rdev)) { struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *clock_info = (struct _ATOM_PPLIB_EVERGREEN_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; 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; /* XXX usVDDCI */ 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; 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++; } static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev) { struct radeon_mode_info *mode_info = &rdev->mode_info; int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); u8 frev, crev; u16 data_offset; union firmware_info *firmware_info; u16 vddc = 0; if (atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) { firmware_info = (union firmware_info *)(mode_info->atom_context->bios + data_offset); vddc = firmware_info->info_14.usBootUpVDDCVoltage; } rdev->pm.power_state[state_index].num_clock_modes = mode_index; if (mode_index) { misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); misc2 = le16_to_cpu(non_clock_info->usClassification); return vddc; } static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev, int state_index, int mode_index, struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info) { int j; u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); u32 misc2 = le16_to_cpu(non_clock_info->usClassification); u16 vddc = radeon_atombios_get_default_vddc(rdev); rdev->pm.power_state[state_index].misc = misc; rdev->pm.power_state[state_index].misc2 = misc2; rdev->pm.power_state[state_index].pcie_lanes = Loading Loading @@ -2235,6 +2120,103 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) vddc; } } } static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, int state_index, int mode_index, union pplib_clock_info *clock_info) { u32 sclk, mclk; if (rdev->flags & RADEON_IS_IGP) { sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow); sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; } else if (ASIC_IS_DCE4(rdev)) { sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); 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].clock_info[mode_index].mclk = mclk; rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; 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->evergreen.usVDDC; } else { sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); sclk |= clock_info->r600.ucEngineClockHigh << 16; mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); mclk |= clock_info->r600.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; 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->r600.usVDDC; } if (rdev->flags & RADEON_IS_IGP) { /* skip invalid modes */ if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) return false; } else { /* 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)) return false; } return true; } static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) { struct radeon_mode_info *mode_info = &rdev->mode_info; struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; union pplib_power_state *power_state; int i, j; int state_index = 0, mode_index = 0; union pplib_clock_info *clock_info; bool valid; union power_info *power_info; int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); u16 data_offset; u8 frev, crev; if (!atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) return 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); /* first mode is usually default, followed by low to high */ for (i = 0; i < power_info->pplib.ucNumStates; i++) { mode_index = 0; power_state = (union pplib_power_state *) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usStateArrayOffset) + i * power_info->pplib.ucStateEntrySize); non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + (power_state->v1.ucNonClockStateIndex * power_info->pplib.ucNonClockSize)); 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++; } } Loading @@ -2252,6 +2234,33 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) 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 { /* add the default mode */ Loading Loading
drivers/gpu/drm/radeon/radeon_atombios.c +475 −466 Original line number Diff line number Diff line Loading @@ -1763,39 +1763,87 @@ static const char *pp_lib_thermal_controller_names[] = { "RV6xx", "RV770", "adt7473", "NONE", "External GPIO", "Evergreen", "adt7473 with internal", }; 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; 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; 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); 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; 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, &frev, &crev, &data_offset)) { if (!atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) return state_index; power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); if (frev < 4) { /* add the i2c bus for thermal/fan chip */ if (power_info->info.ucOverdriveThermalController > 0) { DRM_INFO("Possible %s thermal controller at 0x%02x\n", Loading Loading @@ -1852,38 +1900,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) 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; } radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0); state_index++; break; case 2: Loading Loading @@ -1920,45 +1937,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) 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; } radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2); state_index++; break; case 3: Loading Loading @@ -2001,40 +1980,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } } 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; } radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2); state_index++; break; } Loading @@ -2051,21 +1997,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].misc = 0; rdev->pm.power_state[state_index].misc2 = 0; } } else { int fw_index = GetIndexIntoMasterTable(DATA, FirmwareInfo); uint8_t fw_frev, fw_crev; uint16_t fw_data_offset, vddc = 0; union firmware_info *firmware_info; ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController; if (atom_parse_data_header(mode_info->atom_context, fw_index, NULL, &fw_frev, &fw_crev, &fw_data_offset)) { firmware_info = (union firmware_info *)(mode_info->atom_context->bios + fw_data_offset); vddc = firmware_info->info_14.usBootUpVDDCVoltage; 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) { Loading Loading @@ -2103,93 +2042,39 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) strlcpy(info.type, name, sizeof(info.type)); i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); } } } /* first mode is usually default, followed by low to high */ 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)); 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; /* voltage works differently on IGPs */ mode_index++; } else if (ASIC_IS_DCE4(rdev)) { struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *clock_info = (struct _ATOM_PPLIB_EVERGREEN_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; 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; /* XXX usVDDCI */ 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; 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++; } static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev) { struct radeon_mode_info *mode_info = &rdev->mode_info; int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); u8 frev, crev; u16 data_offset; union firmware_info *firmware_info; u16 vddc = 0; if (atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) { firmware_info = (union firmware_info *)(mode_info->atom_context->bios + data_offset); vddc = firmware_info->info_14.usBootUpVDDCVoltage; } rdev->pm.power_state[state_index].num_clock_modes = mode_index; if (mode_index) { misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); misc2 = le16_to_cpu(non_clock_info->usClassification); return vddc; } static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev, int state_index, int mode_index, struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info) { int j; u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); u32 misc2 = le16_to_cpu(non_clock_info->usClassification); u16 vddc = radeon_atombios_get_default_vddc(rdev); rdev->pm.power_state[state_index].misc = misc; rdev->pm.power_state[state_index].misc2 = misc2; rdev->pm.power_state[state_index].pcie_lanes = Loading Loading @@ -2235,6 +2120,103 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) vddc; } } } static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, int state_index, int mode_index, union pplib_clock_info *clock_info) { u32 sclk, mclk; if (rdev->flags & RADEON_IS_IGP) { sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow); sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; } else if (ASIC_IS_DCE4(rdev)) { sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); 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].clock_info[mode_index].mclk = mclk; rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; 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->evergreen.usVDDC; } else { sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); sclk |= clock_info->r600.ucEngineClockHigh << 16; mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); mclk |= clock_info->r600.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; 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->r600.usVDDC; } if (rdev->flags & RADEON_IS_IGP) { /* skip invalid modes */ if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) return false; } else { /* 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)) return false; } return true; } static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) { struct radeon_mode_info *mode_info = &rdev->mode_info; struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; union pplib_power_state *power_state; int i, j; int state_index = 0, mode_index = 0; union pplib_clock_info *clock_info; bool valid; union power_info *power_info; int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); u16 data_offset; u8 frev, crev; if (!atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) return 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); /* first mode is usually default, followed by low to high */ for (i = 0; i < power_info->pplib.ucNumStates; i++) { mode_index = 0; power_state = (union pplib_power_state *) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usStateArrayOffset) + i * power_info->pplib.ucStateEntrySize); non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + (power_state->v1.ucNonClockStateIndex * power_info->pplib.ucNonClockSize)); 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++; } } Loading @@ -2252,6 +2234,33 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) 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 { /* add the default mode */ Loading