2028,6 → 2028,8 |
num_modes = power_info->info.ucNumOfPowerModeEntries; |
if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) |
num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; |
if (num_modes == 0) |
return state_index; |
rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * num_modes, GFP_KERNEL); |
if (!rdev->pm.power_state) |
return state_index; |
2307,7 → 2309,7 |
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[mode_index - 1]; |
if (ASIC_IS_DCE5(rdev) && !(rdev->flags & RADEON_IS_IGP)) { |
if ((rdev->family >= CHIP_BARTS) && !(rdev->flags & RADEON_IS_IGP)) { |
/* NI chips post without MC ucode, so default clocks are strobe mode only */ |
rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk; |
rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk; |
2345,7 → 2347,7 |
sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; |
rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; |
} |
} else if (ASIC_IS_DCE6(rdev)) { |
} else if (rdev->family >= CHIP_TAHITI) { |
sclk = le16_to_cpu(clock_info->si.usEngineClockLow); |
sclk |= clock_info->si.ucEngineClockHigh << 16; |
mclk = le16_to_cpu(clock_info->si.usMemoryClockLow); |
2358,7 → 2360,7 |
le16_to_cpu(clock_info->si.usVDDC); |
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci = |
le16_to_cpu(clock_info->si.usVDDCI); |
} else if (ASIC_IS_DCE4(rdev)) { |
} else if (rdev->family >= CHIP_CEDAR) { |
sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); |
sclk |= clock_info->evergreen.ucEngineClockHigh << 16; |
mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow); |
2432,6 → 2434,8 |
power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); |
|
radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); |
if (power_info->pplib.ucNumStates == 0) |
return state_index; |
rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * |
power_info->pplib.ucNumStates, GFP_KERNEL); |
if (!rdev->pm.power_state) |
2514,6 → 2518,7 |
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); |
u16 data_offset; |
u8 frev, crev; |
u8 *power_state_offset; |
|
if (!atom_parse_data_header(mode_info->atom_context, index, NULL, |
&frev, &crev, &data_offset)) |
2530,15 → 2535,17 |
non_clock_info_array = (struct _NonClockInfoArray *) |
(mode_info->atom_context->bios + data_offset + |
le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); |
if (state_array->ucNumEntries == 0) |
return state_index; |
rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * |
state_array->ucNumEntries, GFP_KERNEL); |
if (!rdev->pm.power_state) |
return state_index; |
power_state_offset = (u8 *)state_array->states; |
for (i = 0; i < state_array->ucNumEntries; i++) { |
mode_index = 0; |
power_state = (union pplib_power_state *)&state_array->states[i]; |
/* XXX this might be an inagua bug... */ |
non_clock_array_index = i; /* power_state->v2.nonClockInfoIndex */ |
power_state = (union pplib_power_state *)power_state_offset; |
non_clock_array_index = power_state->v2.nonClockInfoIndex; |
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) |
&non_clock_info_array->nonClockInfo[non_clock_array_index]; |
rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * |
2550,9 → 2557,6 |
if (power_state->v2.ucNumDPMLevels) { |
for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { |
clock_array_index = power_state->v2.clockInfoIndex[j]; |
/* XXX this might be an inagua bug... */ |
if (clock_array_index >= clock_info_array->ucNumEntries) |
continue; |
clock_info = (union pplib_clock_info *) |
&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; |
valid = radeon_atombios_parse_pplib_clock_info(rdev, |
2574,6 → 2578,7 |
non_clock_info); |
state_index++; |
} |
power_state_offset += 2 + power_state->v2.ucNumDPMLevels; |
} |
/* if multiple clock modes, mark the lowest as no display */ |
for (i = 0; i < state_index; i++) { |
2620,7 → 2625,9 |
default: |
break; |
} |
} else { |
} |
|
if (state_index == 0) { |
rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL); |
if (rdev->pm.power_state) { |
rdev->pm.power_state[0].clock_info = |
2654,6 → 2661,111 |
rdev->pm.current_vddc = 0; |
} |
|
union get_clock_dividers { |
struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS v1; |
struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 v2; |
struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3; |
struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4; |
struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5; |
}; |
|
int radeon_atom_get_clock_dividers(struct radeon_device *rdev, |
u8 clock_type, |
u32 clock, |
bool strobe_mode, |
struct atom_clock_dividers *dividers) |
{ |
union get_clock_dividers args; |
int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL); |
u8 frev, crev; |
|
memset(&args, 0, sizeof(args)); |
memset(dividers, 0, sizeof(struct atom_clock_dividers)); |
|
if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) |
return -EINVAL; |
|
switch (crev) { |
case 1: |
/* r4xx, r5xx */ |
args.v1.ucAction = clock_type; |
args.v1.ulClock = cpu_to_le32(clock); /* 10 khz */ |
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
|
dividers->post_div = args.v1.ucPostDiv; |
dividers->fb_div = args.v1.ucFbDiv; |
dividers->enable_post_div = true; |
break; |
case 2: |
case 3: |
/* r6xx, r7xx, evergreen, ni */ |
if (rdev->family <= CHIP_RV770) { |
args.v2.ucAction = clock_type; |
args.v2.ulClock = cpu_to_le32(clock); /* 10 khz */ |
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
|
dividers->post_div = args.v2.ucPostDiv; |
dividers->fb_div = le16_to_cpu(args.v2.usFbDiv); |
dividers->ref_div = args.v2.ucAction; |
if (rdev->family == CHIP_RV770) { |
dividers->enable_post_div = (le32_to_cpu(args.v2.ulClock) & (1 << 24)) ? |
true : false; |
dividers->vco_mode = (le32_to_cpu(args.v2.ulClock) & (1 << 25)) ? 1 : 0; |
} else |
dividers->enable_post_div = (dividers->fb_div & 1) ? true : false; |
} else { |
if (clock_type == COMPUTE_ENGINE_PLL_PARAM) { |
args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock); |
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
|
dividers->post_div = args.v3.ucPostDiv; |
dividers->enable_post_div = (args.v3.ucCntlFlag & |
ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false; |
dividers->enable_dithen = (args.v3.ucCntlFlag & |
ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true; |
dividers->fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv); |
dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac); |
dividers->ref_div = args.v3.ucRefDiv; |
dividers->vco_mode = (args.v3.ucCntlFlag & |
ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0; |
} else { |
args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock); |
if (strobe_mode) |
args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN; |
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
|
dividers->post_div = args.v5.ucPostDiv; |
dividers->enable_post_div = (args.v5.ucCntlFlag & |
ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false; |
dividers->enable_dithen = (args.v5.ucCntlFlag & |
ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true; |
dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv); |
dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac); |
dividers->ref_div = args.v5.ucRefDiv; |
dividers->vco_mode = (args.v5.ucCntlFlag & |
ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0; |
} |
} |
break; |
case 4: |
/* fusion */ |
args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */ |
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
|
dividers->post_div = args.v4.ucPostDiv; |
dividers->real_clock = le32_to_cpu(args.v4.ulClock); |
break; |
default: |
return -EINVAL; |
} |
return 0; |
} |
|
void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) |
{ |
DYNAMIC_CLOCK_GATING_PS_ALLOCATION args; |