diff options
| author | Alex Deucher <alexdeucher@gmail.com> | 2010-11-22 17:56:35 -0500 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2010-11-22 18:23:32 -0500 |
| commit | b0e664140a170382531a8c8b5396bf7e6903d5e3 (patch) | |
| tree | 1e098f3997186b4a8d04f2eb0529ed0bd588fc65 | |
| parent | 560154e9a27f2f260fcb2dd18c488203246f257e (diff) | |
drm/radeon/kms: add power table parsing support for Ontario fusion APUs
The vbios power tables on my inagua board seem a bit funky...
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
| -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 | } |
