diff options
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 106 |
1 files changed, 101 insertions, 5 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 7056e20d329d..ac882639b3ed 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
@@ -1766,7 +1766,8 @@ static const char *pp_lib_thermal_controller_names[] = { | |||
1766 | "NONE", | 1766 | "NONE", |
1767 | "External GPIO", | 1767 | "External GPIO", |
1768 | "Evergreen", | 1768 | "Evergreen", |
1769 | "adt7473 with internal", | 1769 | "emc2103", |
1770 | "Sumo", | ||
1770 | }; | 1771 | }; |
1771 | 1772 | ||
1772 | union power_info { | 1773 | union power_info { |
@@ -1774,12 +1775,15 @@ union power_info { | |||
1774 | struct _ATOM_POWERPLAY_INFO_V2 info_2; | 1775 | struct _ATOM_POWERPLAY_INFO_V2 info_2; |
1775 | struct _ATOM_POWERPLAY_INFO_V3 info_3; | 1776 | struct _ATOM_POWERPLAY_INFO_V3 info_3; |
1776 | struct _ATOM_PPLIB_POWERPLAYTABLE pplib; | 1777 | struct _ATOM_PPLIB_POWERPLAYTABLE pplib; |
1778 | struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; | ||
1779 | struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; | ||
1777 | }; | 1780 | }; |
1778 | 1781 | ||
1779 | union pplib_clock_info { | 1782 | union pplib_clock_info { |
1780 | struct _ATOM_PPLIB_R600_CLOCK_INFO r600; | 1783 | struct _ATOM_PPLIB_R600_CLOCK_INFO r600; |
1781 | struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; | 1784 | struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; |
1782 | struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; | 1785 | struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; |
1786 | struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; | ||
1783 | }; | 1787 | }; |
1784 | 1788 | ||
1785 | union pplib_power_state { | 1789 | union pplib_power_state { |
@@ -2022,10 +2026,17 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r | |||
2022 | (controller->ucFanParameters & | 2026 | (controller->ucFanParameters & |
2023 | ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); | 2027 | ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); |
2024 | rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; | 2028 | rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; |
2029 | } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) { | ||
2030 | DRM_INFO("Internal thermal controller %s fan control\n", | ||
2031 | (controller->ucFanParameters & | ||
2032 | ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); | ||
2033 | rdev->pm.int_thermal_type = THERMAL_TYPE_SUMO; | ||
2025 | } else if ((controller->ucType == | 2034 | } else if ((controller->ucType == |
2026 | ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || | 2035 | ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || |
2027 | (controller->ucType == | 2036 | (controller->ucType == |
2028 | ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL)) { | 2037 | ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) || |
2038 | (controller->ucType == | ||
2039 | ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) { | ||
2029 | DRM_INFO("Special thermal controller config\n"); | 2040 | DRM_INFO("Special thermal controller config\n"); |
2030 | } else { | 2041 | } else { |
2031 | DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", | 2042 | DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", |
@@ -2129,9 +2140,15 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, | |||
2129 | u32 sclk, mclk; | 2140 | u32 sclk, mclk; |
2130 | 2141 | ||
2131 | if (rdev->flags & RADEON_IS_IGP) { | 2142 | if (rdev->flags & RADEON_IS_IGP) { |
2132 | sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow); | 2143 | if (rdev->family >= CHIP_PALM) { |
2133 | sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; | 2144 | sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); |
2134 | rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; | 2145 | sclk |= clock_info->sumo.ucEngineClockHigh << 16; |
2146 | rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; | ||
2147 | } else { | ||
2148 | sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow); | ||
2149 | sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; | ||
2150 | rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; | ||
2151 | } | ||
2135 | } else if (ASIC_IS_DCE4(rdev)) { | 2152 | } else if (ASIC_IS_DCE4(rdev)) { |
2136 | sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); | 2153 | sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); |
2137 | sclk |= clock_info->evergreen.ucEngineClockHigh << 16; | 2154 | sclk |= clock_info->evergreen.ucEngineClockHigh << 16; |
@@ -2237,6 +2254,82 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) | |||
2237 | return state_index; | 2254 | return state_index; |
2238 | } | 2255 | } |
2239 | 2256 | ||
2257 | static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) | ||
2258 | { | ||
2259 | struct radeon_mode_info *mode_info = &rdev->mode_info; | ||
2260 | struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; | ||
2261 | union pplib_power_state *power_state; | ||
2262 | int i, j, non_clock_array_index, clock_array_index; | ||
2263 | int state_index = 0, mode_index = 0; | ||
2264 | union pplib_clock_info *clock_info; | ||
2265 | struct StateArray *state_array; | ||
2266 | struct ClockInfoArray *clock_info_array; | ||
2267 | struct NonClockInfoArray *non_clock_info_array; | ||
2268 | bool valid; | ||
2269 | union power_info *power_info; | ||
2270 | int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); | ||
2271 | u16 data_offset; | ||
2272 | u8 frev, crev; | ||
2273 | |||
2274 | if (!atom_parse_data_header(mode_info->atom_context, index, NULL, | ||
2275 | &frev, &crev, &data_offset)) | ||
2276 | return state_index; | ||
2277 | power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); | ||
2278 | |||
2279 | radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); | ||
2280 | state_array = (struct StateArray *) | ||
2281 | (mode_info->atom_context->bios + data_offset + | ||
2282 | power_info->pplib.usStateArrayOffset); | ||
2283 | clock_info_array = (struct ClockInfoArray *) | ||
2284 | (mode_info->atom_context->bios + data_offset + | ||
2285 | power_info->pplib.usClockInfoArrayOffset); | ||
2286 | non_clock_info_array = (struct NonClockInfoArray *) | ||
2287 | (mode_info->atom_context->bios + data_offset + | ||
2288 | power_info->pplib.usNonClockInfoArrayOffset); | ||
2289 | for (i = 0; i < state_array->ucNumEntries; i++) { | ||
2290 | mode_index = 0; | ||
2291 | power_state = (union pplib_power_state *)&state_array->states[i]; | ||
2292 | /* XXX this might be an inagua bug... */ | ||
2293 | non_clock_array_index = i; /* power_state->v2.nonClockInfoIndex */ | ||
2294 | non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) | ||
2295 | &non_clock_info_array->nonClockInfo[non_clock_array_index]; | ||
2296 | for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { | ||
2297 | clock_array_index = power_state->v2.clockInfoIndex[j]; | ||
2298 | /* XXX this might be an inagua bug... */ | ||
2299 | if (clock_array_index >= clock_info_array->ucNumEntries) | ||
2300 | continue; | ||
2301 | clock_info = (union pplib_clock_info *) | ||
2302 | &clock_info_array->clockInfo[clock_array_index]; | ||
2303 | valid = radeon_atombios_parse_pplib_clock_info(rdev, | ||
2304 | state_index, mode_index, | ||
2305 | clock_info); | ||
2306 | if (valid) | ||
2307 | mode_index++; | ||
2308 | } | ||
2309 | rdev->pm.power_state[state_index].num_clock_modes = mode_index; | ||
2310 | if (mode_index) { | ||
2311 | radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index, | ||
2312 | non_clock_info); | ||
2313 | state_index++; | ||
2314 | } | ||
2315 | } | ||
2316 | /* if multiple clock modes, mark the lowest as no display */ | ||
2317 | for (i = 0; i < state_index; i++) { | ||
2318 | if (rdev->pm.power_state[i].num_clock_modes > 1) | ||
2319 | rdev->pm.power_state[i].clock_info[0].flags |= | ||
2320 | RADEON_PM_MODE_NO_DISPLAY; | ||
2321 | } | ||
2322 | /* first mode is usually default */ | ||
2323 | if (rdev->pm.default_power_state_index == -1) { | ||
2324 | rdev->pm.power_state[0].type = | ||
2325 | POWER_STATE_TYPE_DEFAULT; | ||
2326 | rdev->pm.default_power_state_index = 0; | ||
2327 | rdev->pm.power_state[0].default_clock_mode = | ||
2328 | &rdev->pm.power_state[0].clock_info[0]; | ||
2329 | } | ||
2330 | return state_index; | ||
2331 | } | ||
2332 | |||
2240 | void radeon_atombios_get_power_modes(struct radeon_device *rdev) | 2333 | void radeon_atombios_get_power_modes(struct radeon_device *rdev) |
2241 | { | 2334 | { |
2242 | struct radeon_mode_info *mode_info = &rdev->mode_info; | 2335 | struct radeon_mode_info *mode_info = &rdev->mode_info; |
@@ -2259,6 +2352,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) | |||
2259 | case 5: | 2352 | case 5: |
2260 | state_index = radeon_atombios_parse_power_table_4_5(rdev); | 2353 | state_index = radeon_atombios_parse_power_table_4_5(rdev); |
2261 | break; | 2354 | break; |
2355 | case 6: | ||
2356 | state_index = radeon_atombios_parse_power_table_6(rdev); | ||
2357 | break; | ||
2262 | default: | 2358 | default: |
2263 | break; | 2359 | break; |
2264 | } | 2360 | } |