Commit c82baa28 authored by yanyang1's avatar yanyang1 Committed by Alex Deucher

drm/amd/powerplay: add Tonga dpm support (v3)

This implements DPM for tonga.  DPM handles dynamic
clock and voltage scaling.

v2: merge all the patches related with tonga dpm
v3: merge dpm force level fix, cgs display fix, spelling fix
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Reviewed-by: default avatarJammy Zhou <Jammy.Zhou@amd.com>
Signed-off-by: default avataryanyang1 <young.yang@amd.com>
Signed-off-by: default avatarRex Zhu <Rex.Zhu@amd.com>
Signed-off-by: default avatarEric Huang <JinHuiEric.Huang@amd.com>
parent 1060029f
......@@ -2,7 +2,10 @@
subdir-ccflags-y += -Iinclude/drm \
-Idrivers/gpu/drm/amd/powerplay/inc/ \
-Idrivers/gpu/drm/amd/include/asic_reg \
-Idrivers/gpu/drm/amd/include
-Idrivers/gpu/drm/amd/include \
-Idrivers/gpu/drm/amd/powerplay/smumgr\
-Idrivers/gpu/drm/amd/powerplay/hwmgr \
-Idrivers/gpu/drm/amd/powerplay/eventmgr
AMD_PP_PATH = ../powerplay
......
......@@ -4,7 +4,9 @@
HARDWARE_MGR = hwmgr.o processpptables.o functiontables.o \
hardwaremanager.o pp_acpi.o cz_hwmgr.o \
cz_clockpowergating.o
cz_clockpowergating.o \
tonga_processpptables.o ppatomctrl.o \
tonga_hwmgr.o pppcielanes.o
AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR))
......
......@@ -28,6 +28,7 @@
#include "power_state.h"
#include "hwmgr.h"
#include "cz_hwmgr.h"
#include "tonga_hwmgr.h"
int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
{
......@@ -53,6 +54,15 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
case AMD_FAMILY_CZ:
cz_hwmgr_init(hwmgr);
break;
case AMD_FAMILY_VI:
switch (hwmgr->chip_id) {
case CHIP_TONGA:
tonga_hwmgr_init(hwmgr);
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
......
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef PP_HWMGR_PPT_H
#define PP_HWMGR_PPT_H
#include "hardwaremanager.h"
#include "smumgr.h"
#include "atom-types.h"
struct phm_ppt_v1_clock_voltage_dependency_record {
uint32_t clk;
uint8_t vddInd;
uint16_t vdd_offset;
uint16_t vddc;
uint16_t vddgfx;
uint16_t vddci;
uint16_t mvdd;
uint8_t phases;
uint8_t cks_enable;
uint8_t cks_voffset;
};
typedef struct phm_ppt_v1_clock_voltage_dependency_record phm_ppt_v1_clock_voltage_dependency_record;
struct phm_ppt_v1_clock_voltage_dependency_table {
uint32_t count; /* Number of entries. */
phm_ppt_v1_clock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
};
typedef struct phm_ppt_v1_clock_voltage_dependency_table phm_ppt_v1_clock_voltage_dependency_table;
/* Multimedia Clock Voltage Dependency records and table */
struct phm_ppt_v1_mm_clock_voltage_dependency_record {
uint32_t dclk; /* UVD D-clock */
uint32_t vclk; /* UVD V-clock */
uint32_t eclk; /* VCE clock */
uint32_t aclk; /* ACP clock */
uint32_t samclock; /* SAMU clock */
uint8_t vddcInd;
uint16_t vddgfx_offset;
uint16_t vddc;
uint16_t vddgfx;
uint8_t phases;
};
typedef struct phm_ppt_v1_mm_clock_voltage_dependency_record phm_ppt_v1_mm_clock_voltage_dependency_record;
struct phm_ppt_v1_mm_clock_voltage_dependency_table {
uint32_t count; /* Number of entries. */
phm_ppt_v1_mm_clock_voltage_dependency_record entries[1]; /* Dynamically allocate count entries. */
};
typedef struct phm_ppt_v1_mm_clock_voltage_dependency_table phm_ppt_v1_mm_clock_voltage_dependency_table;
struct phm_ppt_v1_voltage_lookup_record {
uint16_t us_calculated;
uint16_t us_vdd; /* Base voltage */
uint16_t us_cac_low;
uint16_t us_cac_mid;
uint16_t us_cac_high;
};
typedef struct phm_ppt_v1_voltage_lookup_record phm_ppt_v1_voltage_lookup_record;
struct phm_ppt_v1_voltage_lookup_table {
uint32_t count;
phm_ppt_v1_voltage_lookup_record entries[1]; /* Dynamically allocate count entries. */
};
typedef struct phm_ppt_v1_voltage_lookup_table phm_ppt_v1_voltage_lookup_table;
/* PCIE records and Table */
struct phm_ppt_v1_pcie_record {
uint8_t gen_speed;
uint8_t lane_width;
};
typedef struct phm_ppt_v1_pcie_record phm_ppt_v1_pcie_record;
struct phm_ppt_v1_pcie_table {
uint32_t count; /* Number of entries. */
phm_ppt_v1_pcie_record entries[1]; /* Dynamically allocate count entries. */
};
typedef struct phm_ppt_v1_pcie_table phm_ppt_v1_pcie_table;
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include "ppatomctrl.h"
#include "atombios.h"
#include "cgs_common.h"
#include "pp_debug.h"
#define MEM_ID_MASK 0xff000000
#define MEM_ID_SHIFT 24
#define CLOCK_RANGE_MASK 0x00ffffff
#define CLOCK_RANGE_SHIFT 0
#define LOW_NIBBLE_MASK 0xf
#define DATA_EQU_PREV 0
#define DATA_FROM_TABLE 4
union voltage_object_info {
struct _ATOM_VOLTAGE_OBJECT_INFO v1;
struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;
};
static int atomctrl_retrieve_ac_timing(
uint8_t index,
ATOM_INIT_REG_BLOCK *reg_block,
pp_atomctrl_mc_reg_table *table)
{
uint32_t i, j;
uint8_t tmem_id;
ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
((uint8_t *)reg_block + (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block->usRegIndexTblSize));
uint8_t num_ranges = 0;
while (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK &&
num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES) {
tmem_id = (uint8_t)((*(uint32_t *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
if (index == tmem_id) {
table->mc_reg_table_entry[num_ranges].mclk_max =
(uint32_t)((*(uint32_t *)reg_data & CLOCK_RANGE_MASK) >>
CLOCK_RANGE_SHIFT);
for (i = 0, j = 1; i < table->last; i++) {
if ((table->mc_reg_address[i].uc_pre_reg_data &
LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
table->mc_reg_table_entry[num_ranges].mc_data[i] =
(uint32_t)*((uint32_t *)reg_data + j);
j++;
} else if ((table->mc_reg_address[i].uc_pre_reg_data &
LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
table->mc_reg_table_entry[num_ranges].mc_data[i] =
table->mc_reg_table_entry[num_ranges].mc_data[i-1];
}
}
num_ranges++;
}
reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
((uint8_t *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)) ;
}
PP_ASSERT_WITH_CODE((*(uint32_t *)reg_data == END_OF_REG_DATA_BLOCK),
"Invalid VramInfo table.", return -1);
table->num_entries = num_ranges;
return 0;
}
/**
* Get memory clock AC timing registers index from VBIOS table
* VBIOS set end of memory clock AC timing registers by ucPreRegDataLength bit6 = 1
* @param reg_block the address ATOM_INIT_REG_BLOCK
* @param table the address of MCRegTable
* @return PP_Result_OK
*/
static int atomctrl_set_mc_reg_address_table(
ATOM_INIT_REG_BLOCK *reg_block,
pp_atomctrl_mc_reg_table *table)
{
uint8_t i = 0;
uint8_t num_entries = (uint8_t)((le16_to_cpu(reg_block->usRegIndexTblSize))
/ sizeof(ATOM_INIT_REG_INDEX_FORMAT));
ATOM_INIT_REG_INDEX_FORMAT *format = &reg_block->asRegIndexBuf[0];
num_entries--; /* subtract 1 data end mark entry */
PP_ASSERT_WITH_CODE((num_entries <= VBIOS_MC_REGISTER_ARRAY_SIZE),
"Invalid VramInfo table.", return -1);
/* ucPreRegDataLength bit6 = 1 is the end of memory clock AC timing registers */
while ((!(format->ucPreRegDataLength & ACCESS_PLACEHOLDER)) &&
(i < num_entries)) {
table->mc_reg_address[i].s1 =
(uint16_t)(le16_to_cpu(format->usRegIndex));
table->mc_reg_address[i].uc_pre_reg_data =
format->ucPreRegDataLength;
i++;
format = (ATOM_INIT_REG_INDEX_FORMAT *)
((uint8_t *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
}
table->last = i;
return 0;
}
int atomctrl_initialize_mc_reg_table(
struct pp_hwmgr *hwmgr,
uint8_t module_index,
pp_atomctrl_mc_reg_table *table)
{
ATOM_VRAM_INFO_HEADER_V2_1 *vram_info;
ATOM_INIT_REG_BLOCK *reg_block;
int result = 0;
u8 frev, crev;
u16 size;
vram_info = (ATOM_VRAM_INFO_HEADER_V2_1 *)
cgs_atom_get_data_table(hwmgr->device,
GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev);
if (module_index >= vram_info->ucNumOfVRAMModule) {
printk(KERN_ERR "[ powerplay ] Invalid VramInfo table.");
result = -1;
} else if (vram_info->sHeader.ucTableFormatRevision < 2) {
printk(KERN_ERR "[ powerplay ] Invalid VramInfo table.");
result = -1;
}
if (0 == result) {
reg_block = (ATOM_INIT_REG_BLOCK *)
((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
result = atomctrl_set_mc_reg_address_table(reg_block, table);
}
if (0 == result) {
result = atomctrl_retrieve_ac_timing(module_index,
reg_block, table);
}
return result;
}
/**
* Set DRAM timings based on engine clock and memory clock.
*/
int atomctrl_set_engine_dram_timings_rv770(
struct pp_hwmgr *hwmgr,
uint32_t engine_clock,
uint32_t memory_clock)
{
SET_ENGINE_CLOCK_PS_ALLOCATION engine_clock_parameters;
/* They are both in 10KHz Units. */
engine_clock_parameters.ulTargetEngineClock =
(uint32_t) engine_clock & SET_CLOCK_FREQ_MASK;
engine_clock_parameters.ulTargetEngineClock |=
(COMPUTE_ENGINE_PLL_PARAM << 24);
/* in 10 khz units.*/
engine_clock_parameters.sReserved.ulClock =
(uint32_t) memory_clock & SET_CLOCK_FREQ_MASK;
return cgs_atom_exec_cmd_table(hwmgr->device,
GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings),
&engine_clock_parameters);
}
/**
* Private Function to get the PowerPlay Table Address.
* WARNING: The tabled returned by this function is in
* dynamically allocated memory.
* The caller has to release if by calling kfree.
*/
static ATOM_VOLTAGE_OBJECT_INFO *get_voltage_info_table(void *device)
{
int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
u8 frev, crev;
u16 size;
union voltage_object_info *voltage_info;
voltage_info = (union voltage_object_info *)
cgs_atom_get_data_table(device, index,
&size, &frev, &crev);
if (voltage_info != NULL)
return (ATOM_VOLTAGE_OBJECT_INFO *) &(voltage_info->v3);
else
return NULL;
}
static const ATOM_VOLTAGE_OBJECT_V3 *atomctrl_lookup_voltage_type_v3(
const ATOM_VOLTAGE_OBJECT_INFO_V3_1 * voltage_object_info_table,
uint8_t voltage_type, uint8_t voltage_mode)
{
unsigned int size = le16_to_cpu(voltage_object_info_table->sHeader.usStructureSize);
unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
uint8_t *start = (uint8_t *)voltage_object_info_table;
while (offset < size) {
const ATOM_VOLTAGE_OBJECT_V3 *voltage_object =
(const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
if (voltage_type == voltage_object->asGpioVoltageObj.sHeader.ucVoltageType &&
voltage_mode == voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode)
return voltage_object;
offset += le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize);
}
return NULL;
}
/** atomctrl_get_memory_pll_dividers_si().
*
* @param hwmgr input parameter: pointer to HwMgr
* @param clock_value input parameter: memory clock
* @param dividers output parameter: memory PLL dividers
* @param strobe_mode input parameter: 1 for strobe mode, 0 for performance mode
*/
int atomctrl_get_memory_pll_dividers_si(
struct pp_hwmgr *hwmgr,
uint32_t clock_value,
pp_atomctrl_memory_clock_param *mpll_param,
bool strobe_mode)
{
COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 mpll_parameters;
int result;
mpll_parameters.ulClock = (uint32_t) clock_value;
mpll_parameters.ucInputFlag = (uint8_t)((strobe_mode) ? 1 : 0);
result = cgs_atom_exec_cmd_table
(hwmgr->device,
GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
&mpll_parameters);
if (0 == result) {
mpll_param->mpll_fb_divider.clk_frac =
mpll_parameters.ulFbDiv.usFbDivFrac;
mpll_param->mpll_fb_divider.cl_kf =
mpll_parameters.ulFbDiv.usFbDiv;
mpll_param->mpll_post_divider =
(uint32_t)mpll_parameters.ucPostDiv;
mpll_param->vco_mode =
(uint32_t)(mpll_parameters.ucPllCntlFlag &
MPLL_CNTL_FLAG_VCO_MODE_MASK);
mpll_param->yclk_sel =
(uint32_t)((mpll_parameters.ucPllCntlFlag &
MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0);
mpll_param->qdr =
(uint32_t)((mpll_parameters.ucPllCntlFlag &
MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0);
mpll_param->half_rate =
(uint32_t)((mpll_parameters.ucPllCntlFlag &
MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0);
mpll_param->dll_speed =
(uint32_t)(mpll_parameters.ucDllSpeed);
mpll_param->bw_ctrl =
(uint32_t)(mpll_parameters.ucBWCntl);
}
return result;
}
int atomctrl_get_engine_pll_dividers_vi(
struct pp_hwmgr *hwmgr,
uint32_t clock_value,
pp_atomctrl_clock_dividers_vi *dividers)
{
COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters;
int result;
pll_patameters.ulClock.ulClock = clock_value;
pll_patameters.ulClock.ucPostDiv = COMPUTE_GPUCLK_INPUT_FLAG_SCLK;
result = cgs_atom_exec_cmd_table
(hwmgr->device,
GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
&pll_patameters);
if (0 == result) {
dividers->pll_post_divider =
pll_patameters.ulClock.ucPostDiv;
dividers->real_clock =
pll_patameters.ulClock.ulClock;
dividers->ul_fb_div.ul_fb_div_frac =
pll_patameters.ulFbDiv.usFbDivFrac;
dividers->ul_fb_div.ul_fb_div =
pll_patameters.ulFbDiv.usFbDiv;
dividers->uc_pll_ref_div =
pll_patameters.ucPllRefDiv;
dividers->uc_pll_post_div =
pll_patameters.ucPllPostDiv;
dividers->uc_pll_cntl_flag =
pll_patameters.ucPllCntlFlag;
}
return result;
}
int atomctrl_get_dfs_pll_dividers_vi(
struct pp_hwmgr *hwmgr,
uint32_t clock_value,
pp_atomctrl_clock_dividers_vi *dividers)
{
COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters;
int result;
pll_patameters.ulClock.ulClock = clock_value;
pll_patameters.ulClock.ucPostDiv =
COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK;
result = cgs_atom_exec_cmd_table
(hwmgr->device,
GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
&pll_patameters);
if (0 == result) {
dividers->pll_post_divider =
pll_patameters.ulClock.ucPostDiv;
dividers->real_clock =
pll_patameters.ulClock.ulClock;
dividers->ul_fb_div.ul_fb_div_frac =
pll_patameters.ulFbDiv.usFbDivFrac;
dividers->ul_fb_div.ul_fb_div =
pll_patameters.ulFbDiv.usFbDiv;
dividers->uc_pll_ref_div =
pll_patameters.ucPllRefDiv;
dividers->uc_pll_post_div =
pll_patameters.ucPllPostDiv;
dividers->uc_pll_cntl_flag =
pll_patameters.ucPllCntlFlag;
}
return result;
}
/**
* Get the reference clock in 10KHz
*/
uint32_t atomctrl_get_reference_clock(struct pp_hwmgr *hwmgr)
{
ATOM_FIRMWARE_INFO *fw_info;
u8 frev, crev;
u16 size;
uint32_t clock;
fw_info = (ATOM_FIRMWARE_INFO *)
cgs_atom_get_data_table(hwmgr->device,
GetIndexIntoMasterTable(DATA, FirmwareInfo),
&size, &frev, &crev);
if (fw_info == NULL)
clock = 2700;
else
clock = (uint32_t)(le16_to_cpu(fw_info->usReferenceClock));
return clock;
}
/**
* Returns 0 if the given voltage type is controlled by GPIO pins.
* voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC,
* SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ.
* voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE
*/
bool atomctrl_is_voltage_controled_by_gpio_v3(
struct pp_hwmgr *hwmgr,
uint8_t voltage_type,
uint8_t voltage_mode)
{
ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->device);
bool ret;
PP_ASSERT_WITH_CODE((NULL != voltage_info),
"Could not find Voltage Table in BIOS.", return -1;);
ret = (NULL != atomctrl_lookup_voltage_type_v3
(voltage_info, voltage_type, voltage_mode)) ? 0 : 1;
return ret;
}
int atomctrl_get_voltage_table_v3(
struct pp_hwmgr *hwmgr,
uint8_t voltage_type,
uint8_t voltage_mode,
pp_atomctrl_voltage_table *voltage_table)
{
ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->device);
const ATOM_VOLTAGE_OBJECT_V3 *voltage_object;
unsigned int i;
PP_ASSERT_WITH_CODE((NULL != voltage_info),
"Could not find Voltage Table in BIOS.", return -1;);
voltage_object = atomctrl_lookup_voltage_type_v3
(voltage_info, voltage_type, voltage_mode);
if (voltage_object == NULL)
return -1;
PP_ASSERT_WITH_CODE(
(voltage_object->asGpioVoltageObj.ucGpioEntryNum <=
PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES),
"Too many voltage entries!",
return -1;
);
for (i = 0; i < voltage_object->asGpioVoltageObj.ucGpioEntryNum; i++) {
voltage_table->entries[i].value =
voltage_object->asGpioVoltageObj.asVolGpioLut[i].usVoltageValue;
voltage_table->entries[i].smio_low =
voltage_object->asGpioVoltageObj.asVolGpioLut[i].ulVoltageId;
}
voltage_table->mask_low =
voltage_object->asGpioVoltageObj.ulGpioMaskVal;
voltage_table->count =
voltage_object->asGpioVoltageObj.ucGpioEntryNum;
voltage_table->phase_delay =
voltage_object->asGpioVoltageObj.ucPhaseDelay;
return 0;
}
static bool atomctrl_lookup_gpio_pin(
ATOM_GPIO_PIN_LUT * gpio_lookup_table,
const uint32_t pinId,
pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment)
{
unsigned int size = le16_to_cpu(gpio_lookup_table->sHeader.usStructureSize);
unsigned int offset = offsetof(ATOM_GPIO_PIN_LUT, asGPIO_Pin[0]);
uint8_t *start = (uint8_t *)gpio_lookup_table;
while (offset < size) {
const ATOM_GPIO_PIN_ASSIGNMENT *pin_assignment =
(const ATOM_GPIO_PIN_ASSIGNMENT *)(start + offset);
if (pinId == pin_assignment->ucGPIO_ID) {
gpio_pin_assignment->uc_gpio_pin_bit_shift =
pin_assignment->ucGpioPinBitShift;
gpio_pin_assignment->us_gpio_pin_aindex =
le16_to_cpu(pin_assignment->usGpioPin_AIndex);
return 0;
}
offset += offsetof(ATOM_GPIO_PIN_ASSIGNMENT, ucGPIO_ID) + 1;
}
return 1;
}
/**
* Private Function to get the PowerPlay Table Address.
* WARNING: The tabled returned by this function is in
* dynamically allocated memory.
* The caller has to release if by calling kfree.
*/
static ATOM_GPIO_PIN_LUT *get_gpio_lookup_table(void *device)
{
u8 frev, crev;
u16 size;
void *table_address;
table_address = (ATOM_GPIO_PIN_LUT *)
cgs_atom_get_data_table(device,
GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT),
&size, &frev, &crev);
PP_ASSERT_WITH_CODE((NULL != table_address),
"Error retrieving BIOS Table Address!", return NULL;);
return (ATOM_GPIO_PIN_LUT *)table_address;
}
/**
* Returns 1 if the given pin id find in lookup table.
*/
bool atomctrl_get_pp_assign_pin(
struct pp_hwmgr *hwmgr,
const uint32_t pinId,
pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment)
{
bool bRet = 0;
ATOM_GPIO_PIN_LUT *gpio_lookup_table =
get_gpio_lookup_table(hwmgr->device);
PP_ASSERT_WITH_CODE((NULL != gpio_lookup_table),
"Could not find GPIO lookup Table in BIOS.", return -1);
bRet = atomctrl_lookup_gpio_pin(gpio_lookup_table, pinId,
gpio_pin_assignment);
return bRet;
}
/** atomctrl_get_voltage_evv_on_sclk gets voltage via call to ATOM COMMAND table.
* @param hwmgr input: pointer to hwManager
* @param voltage_type input: type of EVV voltage VDDC or VDDGFX
* @param sclk input: in 10Khz unit. DPM state SCLK frequency
* which is define in PPTable SCLK/VDDC dependence
* table associated with this virtual_voltage_Id
* @param virtual_voltage_Id input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
* @param voltage output: real voltage level in unit of mv
*/
int atomctrl_get_voltage_evv_on_sclk(
struct pp_hwmgr *hwmgr,
uint8_t voltage_type,
uint32_t sclk, uint16_t virtual_voltage_Id,
uint16_t *voltage)
{
int result;
GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space;
get_voltage_info_param_space.ucVoltageType =
voltage_type;
get_voltage_info_param_space.ucVoltageMode =
ATOM_GET_VOLTAGE_EVV_VOLTAGE;
get_voltage_info_param_space.usVoltageLevel =
virtual_voltage_Id;
get_voltage_info_param_space.ulSCLKFreq =
sclk;
result = cgs_atom_exec_cmd_table(hwmgr->device,
GetIndexIntoMasterTable(COMMAND, GetVoltageInfo),
&get_voltage_info_param_space);
if (0 != result)
return result;
*voltage = ((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 *)
(&get_voltage_info_param_space))->usVoltageLevel;
return result;
}
/**
* Get the mpll reference clock in 10KHz
*/
uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr *hwmgr)
{
ATOM_COMMON_TABLE_HEADER *fw_info;
uint32_t clock;
u8 frev, crev;
u16 size;
fw_info = (ATOM_COMMON_TABLE_HEADER *)
cgs_atom_get_data_table(hwmgr->device,
GetIndexIntoMasterTable(DATA, FirmwareInfo),
&size, &frev, &crev);
if (fw_info == NULL)
clock = 2700;
else {
if ((fw_info->ucTableFormatRevision == 2) &&
(le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V2_1))) {
ATOM_FIRMWARE_INFO_V2_1 *fwInfo_2_1 =
(ATOM_FIRMWARE_INFO_V2_1 *)fw_info;
clock = (uint32_t)(le16_to_cpu(fwInfo_2_1->usMemoryReferenceClock));
} else {
ATOM_FIRMWARE_INFO *fwInfo_0_0 =
(ATOM_FIRMWARE_INFO *)fw_info;
clock = (uint32_t)(le16_to_cpu(fwInfo_0_0->usReferenceClock));
}
}
return clock;
}
/**
* Get the asic internal spread spectrum table
*/
static ATOM_ASIC_INTERNAL_SS_INFO *asic_internal_ss_get_ss_table(void *device)
{
ATOM_ASIC_INTERNAL_SS_INFO *table = NULL;
u8 frev, crev;
u16 size;
table = (ATOM_ASIC_INTERNAL_SS_INFO *)
cgs_atom_get_data_table(device,
GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info),
&size, &frev, &crev);
return table;
}
/**
* Get the asic internal spread spectrum assignment
*/
static int asic_internal_ss_get_ss_asignment(struct pp_hwmgr *hwmgr,
const uint8_t clockSource,
const uint32_t clockSpeed,
pp_atomctrl_internal_ss_info *ssEntry)
{
ATOM_ASIC_INTERNAL_SS_INFO *table;
ATOM_ASIC_SS_ASSIGNMENT *ssInfo;
int entry_found = 0;
memset(ssEntry, 0x00, sizeof(pp_atomctrl_internal_ss_info));
table = asic_internal_ss_get_ss_table(hwmgr->device);
if (NULL == table)
return -1;
ssInfo = &table->asSpreadSpectrum[0];
while (((uint8_t *)ssInfo - (uint8_t *)table) <
le16_to_cpu(table->sHeader.usStructureSize)) {
if ((clockSource == ssInfo->ucClockIndication) &&
((uint32_t)clockSpeed <= le32_to_cpu(ssInfo->ulTargetClockRange))) {
entry_found = 1;
break;
}
ssInfo = (ATOM_ASIC_SS_ASSIGNMENT *)((uint8_t *)ssInfo +
sizeof(ATOM_ASIC_SS_ASSIGNMENT));
}
if (entry_found) {
ssEntry->speed_spectrum_percentage =
ssInfo->usSpreadSpectrumPercentage;
ssEntry->speed_spectrum_rate = ssInfo->usSpreadRateInKhz;
if (((GET_DATA_TABLE_MAJOR_REVISION(table) == 2) &&
(GET_DATA_TABLE_MINOR_REVISION(table) >= 2)) ||
(GET_DATA_TABLE_MAJOR_REVISION(table) == 3)) {
ssEntry->speed_spectrum_rate /= 100;
}
switch (ssInfo->ucSpreadSpectrumMode) {
case 0:
ssEntry->speed_spectrum_mode =
pp_atomctrl_spread_spectrum_mode_down;
break;
case 1:
ssEntry->speed_spectrum_mode =
pp_atomctrl_spread_spectrum_mode_center;
break;
default:
ssEntry->speed_spectrum_mode =
pp_atomctrl_spread_spectrum_mode_down;
break;
}
}
return entry_found ? 0 : 1;
}
/**
* Get the memory clock spread spectrum info
*/
int atomctrl_get_memory_clock_spread_spectrum(
struct pp_hwmgr *hwmgr,
const uint32_t memory_clock,
pp_atomctrl_internal_ss_info *ssInfo)
{
return asic_internal_ss_get_ss_asignment(hwmgr,
ASIC_INTERNAL_MEMORY_SS, memory_clock, ssInfo);
}
/**
* Get the engine clock spread spectrum info
*/
int atomctrl_get_engine_clock_spread_spectrum(
struct pp_hwmgr *hwmgr,
const uint32_t engine_clock,
pp_atomctrl_internal_ss_info *ssInfo)
{
return asic_internal_ss_get_ss_asignment(hwmgr,
ASIC_INTERNAL_ENGINE_SS, engine_clock, ssInfo);
}
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef PP_ATOMVOLTAGECTRL_H
#define PP_ATOMVOLTAGECTRL_H
#include "hwmgr.h"
#define MEM_TYPE_GDDR5 0x50
#define MEM_TYPE_GDDR4 0x40
#define MEM_TYPE_GDDR3 0x30
#define MEM_TYPE_DDR2 0x20
#define MEM_TYPE_GDDR1 0x10
#define MEM_TYPE_DDR3 0xb0
#define MEM_TYPE_MASK 0xF0
/* As returned from PowerConnectorDetectionTable. */
#define PP_ATOM_POWER_BUDGET_DISABLE_OVERDRIVE 0x80
#define PP_ATOM_POWER_BUDGET_SHOW_WARNING 0x40
#define PP_ATOM_POWER_BUDGET_SHOW_WAIVER 0x20
#define PP_ATOM_POWER_POWER_BUDGET_BEHAVIOUR 0x0F
/* New functions for Evergreen and beyond. */
#define PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES 32
struct pp_atomctrl_clock_dividers {
uint32_t pll_post_divider;
uint32_t pll_feedback_divider;
uint32_t pll_ref_divider;
bool enable_post_divider;
};
typedef struct pp_atomctrl_clock_dividers pp_atomctrl_clock_dividers;
union pp_atomctrl_tcipll_fb_divider {
struct {
uint32_t ul_fb_div_frac : 14;
uint32_t ul_fb_div : 12;
uint32_t un_used : 6;
};
uint32_t ul_fb_divider;
};
typedef union pp_atomctrl_tcipll_fb_divider pp_atomctrl_tcipll_fb_divider;
struct pp_atomctrl_clock_dividers_rv730 {
uint32_t pll_post_divider;
pp_atomctrl_tcipll_fb_divider mpll_feedback_divider;
uint32_t pll_ref_divider;
bool enable_post_divider;
bool enable_dithen;
uint32_t vco_mode;
};
typedef struct pp_atomctrl_clock_dividers_rv730 pp_atomctrl_clock_dividers_rv730;
struct pp_atomctrl_clock_dividers_kong {
uint32_t pll_post_divider;
uint32_t real_clock;
};
typedef struct pp_atomctrl_clock_dividers_kong pp_atomctrl_clock_dividers_kong;
struct pp_atomctrl_clock_dividers_ci {
uint32_t pll_post_divider; /* post divider value */
uint32_t real_clock;
pp_atomctrl_tcipll_fb_divider ul_fb_div; /* Output Parameter: PLL FB divider */
uint8_t uc_pll_ref_div; /* Output Parameter: PLL ref divider */
uint8_t uc_pll_post_div; /* Output Parameter: PLL post divider */
uint8_t uc_pll_cntl_flag; /*Output Flags: control flag */
};
typedef struct pp_atomctrl_clock_dividers_ci pp_atomctrl_clock_dividers_ci;
struct pp_atomctrl_clock_dividers_vi {
uint32_t pll_post_divider; /* post divider value */
uint32_t real_clock;
pp_atomctrl_tcipll_fb_divider ul_fb_div; /*Output Parameter: PLL FB divider */
uint8_t uc_pll_ref_div; /*Output Parameter: PLL ref divider */
uint8_t uc_pll_post_div; /*Output Parameter: PLL post divider */
uint8_t uc_pll_cntl_flag; /*Output Flags: control flag */
};
typedef struct pp_atomctrl_clock_dividers_vi pp_atomctrl_clock_dividers_vi;
union pp_atomctrl_s_mpll_fb_divider {
struct {
uint32_t cl_kf : 12;
uint32_t clk_frac : 12;
uint32_t un_used : 8;
};
uint32_t ul_fb_divider;
};
typedef union pp_atomctrl_s_mpll_fb_divider pp_atomctrl_s_mpll_fb_divider;
enum pp_atomctrl_spread_spectrum_mode {
pp_atomctrl_spread_spectrum_mode_down = 0,
pp_atomctrl_spread_spectrum_mode_center
};
typedef enum pp_atomctrl_spread_spectrum_mode pp_atomctrl_spread_spectrum_mode;
struct pp_atomctrl_memory_clock_param {
pp_atomctrl_s_mpll_fb_divider mpll_fb_divider;
uint32_t mpll_post_divider;
uint32_t bw_ctrl;
uint32_t dll_speed;
uint32_t vco_mode;
uint32_t yclk_sel;
uint32_t qdr;
uint32_t half_rate;
};
typedef struct pp_atomctrl_memory_clock_param pp_atomctrl_memory_clock_param;
struct pp_atomctrl_internal_ss_info {
uint32_t speed_spectrum_percentage; /* in 1/100 percentage */
uint32_t speed_spectrum_rate; /* in KHz */
pp_atomctrl_spread_spectrum_mode speed_spectrum_mode;
};
typedef struct pp_atomctrl_internal_ss_info pp_atomctrl_internal_ss_info;
#ifndef NUMBER_OF_M3ARB_PARAMS
#define NUMBER_OF_M3ARB_PARAMS 3
#endif
#ifndef NUMBER_OF_M3ARB_PARAM_SETS
#define NUMBER_OF_M3ARB_PARAM_SETS 10
#endif
struct pp_atomctrl_kong_system_info {
uint32_t ul_bootup_uma_clock; /* in 10kHz unit */
uint16_t us_max_nb_voltage; /* high NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse; */
uint16_t us_min_nb_voltage; /* low NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse; */
uint16_t us_bootup_nb_voltage; /* boot up NB voltage */
uint8_t uc_htc_tmp_lmt; /* bit [22:16] of D24F3x64 Hardware Thermal Control (HTC) Register, may not be needed, TBD */
uint8_t uc_tj_offset; /* bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed, TBD */
/* 0: default 1: uvd 2: fs-3d */
uint32_t ul_csr_m3_srb_cntl[NUMBER_OF_M3ARB_PARAM_SETS][NUMBER_OF_M3ARB_PARAMS];/* arrays with values for CSR M3 arbiter for default */
};
typedef struct pp_atomctrl_kong_system_info pp_atomctrl_kong_system_info;
struct pp_atomctrl_memory_info {
uint8_t memory_vendor;
uint8_t memory_type;
};
typedef struct pp_atomctrl_memory_info pp_atomctrl_memory_info;
#define MAX_AC_TIMING_ENTRIES 16
struct pp_atomctrl_memory_clock_range_table {
uint8_t num_entries;
uint8_t rsv[3];
uint32_t mclk[MAX_AC_TIMING_ENTRIES];
};
typedef struct pp_atomctrl_memory_clock_range_table pp_atomctrl_memory_clock_range_table;
struct pp_atomctrl_voltage_table_entry {
uint16_t value;
uint32_t smio_low;
};
typedef struct pp_atomctrl_voltage_table_entry pp_atomctrl_voltage_table_entry;
struct pp_atomctrl_voltage_table {
uint32_t count;
uint32_t mask_low;
uint32_t phase_delay; /* Used for ATOM_GPIO_VOLTAGE_OBJECT_V3 and later */
pp_atomctrl_voltage_table_entry entries[PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES];
};
typedef struct pp_atomctrl_voltage_table pp_atomctrl_voltage_table;
#define VBIOS_MC_REGISTER_ARRAY_SIZE 32
#define VBIOS_MAX_AC_TIMING_ENTRIES 20
struct pp_atomctrl_mc_reg_entry {
uint32_t mclk_max;
uint32_t mc_data[VBIOS_MC_REGISTER_ARRAY_SIZE];
};
typedef struct pp_atomctrl_mc_reg_entry pp_atomctrl_mc_reg_entry;
struct pp_atomctrl_mc_register_address {
uint16_t s1;
uint8_t uc_pre_reg_data;
};
typedef struct pp_atomctrl_mc_register_address pp_atomctrl_mc_register_address;
struct pp_atomctrl_mc_reg_table {
uint8_t last; /* number of registers */
uint8_t num_entries; /* number of AC timing entries */
pp_atomctrl_mc_reg_entry mc_reg_table_entry[VBIOS_MAX_AC_TIMING_ENTRIES];
pp_atomctrl_mc_register_address mc_reg_address[VBIOS_MC_REGISTER_ARRAY_SIZE];
};
typedef struct pp_atomctrl_mc_reg_table pp_atomctrl_mc_reg_table;
struct pp_atomctrl_gpio_pin_assignment {
uint16_t us_gpio_pin_aindex;
uint8_t uc_gpio_pin_bit_shift;
};
typedef struct pp_atomctrl_gpio_pin_assignment pp_atomctrl_gpio_pin_assignment;
extern bool atomctrl_get_pp_assign_pin(struct pp_hwmgr *hwmgr, const uint32_t pinId, pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment);
extern int atomctrl_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint32_t sclk, uint16_t virtual_voltage_Id, uint16_t *voltage);
extern uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr *hwmgr);
extern int atomctrl_get_memory_clock_spread_spectrum(struct pp_hwmgr *hwmgr, const uint32_t memory_clock, pp_atomctrl_internal_ss_info *ssInfo);
extern int atomctrl_get_engine_clock_spread_spectrum(struct pp_hwmgr *hwmgr, const uint32_t engine_clock, pp_atomctrl_internal_ss_info *ssInfo);
extern int atomctrl_initialize_mc_reg_table(struct pp_hwmgr *hwmgr, uint8_t module_index, pp_atomctrl_mc_reg_table *table);
extern int atomctrl_set_engine_dram_timings_rv770(struct pp_hwmgr *hwmgr, uint32_t engine_clock, uint32_t memory_clock);
extern uint32_t atomctrl_get_reference_clock(struct pp_hwmgr *hwmgr);
extern int atomctrl_get_memory_pll_dividers_si(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param, bool strobe_mode);
extern int atomctrl_get_engine_pll_dividers_vi(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_clock_dividers_vi *dividers);
extern int atomctrl_get_dfs_pll_dividers_vi(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_clock_dividers_vi *dividers);
extern bool atomctrl_is_voltage_controled_by_gpio_v3(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode);
extern int atomctrl_get_voltage_table_v3(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode, pp_atomctrl_voltage_table *voltage_table);
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef PP_INTERRUPT_H
#define PP_INTERRUPT_H
/**
* The type of the interrupt callback functions in PowerPlay
*/
typedef void (*pp_interrupt_callback) (void *context, uint32_t ul_context_data);
/**
* Event Manager action chain list information
*/
struct pp_interrupt_registration_info {
pp_interrupt_callback callback; /* Pointer to callback function */
void *context; /* Pointer to callback function context */
uint32_t *interrupt_enable_id; /* Registered interrupt id */
};
typedef struct pp_interrupt_registration_info pp_interrupt_registration_info;
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <linux/types.h>
#include "atom-types.h"
#include "atombios.h"
#include "pppcielanes.h"
/** \file
* Functions related to PCIe lane changes.
*/
/* For converting from number of lanes to lane bits. */
static const unsigned char pp_r600_encode_lanes[] = {
0, /* 0 Not Supported */
1, /* 1 Lane */
2, /* 2 Lanes */
0, /* 3 Not Supported */
3, /* 4 Lanes */
0, /* 5 Not Supported */
0, /* 6 Not Supported */
0, /* 7 Not Supported */
4, /* 8 Lanes */
0, /* 9 Not Supported */
0, /* 10 Not Supported */
0, /* 11 Not Supported */
5, /* 12 Lanes (Not actually supported) */
0, /* 13 Not Supported */
0, /* 14 Not Supported */
0, /* 15 Not Supported */
6 /* 16 Lanes */
};
static const unsigned char pp_r600_decoded_lanes[8] = { 16, 1, 2, 4, 8, 12, 16, };
uint8_t encode_pcie_lane_width(uint32_t num_lanes)
{
return pp_r600_encode_lanes[num_lanes];
}
uint8_t decode_pcie_lane_width(uint32_t num_lanes)
{
return pp_r600_decoded_lanes[num_lanes];
}
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef PP_PCIELANES_H
#define PP_PCIELANES_H
extern uint8_t encode_pcie_lane_width(uint32_t num_lanes);
extern uint8_t decode_pcie_lane_width(uint32_t num_lanes);
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef TONGA_DYN_DEFAULTS_H
#define TONGA_DYN_DEFAULTS_H
/** \file
* Volcanic Islands Dynamic default parameters.
*/
enum TONGAdpm_TrendDetection {
TONGAdpm_TrendDetection_AUTO,
TONGAdpm_TrendDetection_UP,
TONGAdpm_TrendDetection_DOWN
};
typedef enum TONGAdpm_TrendDetection TONGAdpm_TrendDetection;
/* Bit vector representing same fields as hardware register. */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 /* CP_Gfx_busy */
/* HDP_busy */
/* IH_busy */
/* DRM_busy */
/* DRMDMA_busy */
/* UVD_busy */
/* VCE_busy */
/* ACP_busy */
/* SAMU_busy */
/* AVP_busy */
/* SDMA enabled */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1 0x000400 /* FE_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
/* SH_Gfx_busy */
/* RB_Gfx_busy */
/* VCE_busy */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080 /* SH_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
/* FE_Gfx_busy */
/* RB_Gfx_busy */
/* ACP_busy */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200 /* RB_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
/* FE_Gfx_busy */
/* SH_Gfx_busy */
/* UVD_busy */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680 /* UVD_busy */
/* VCE_busy */
/* ACP_busy */
/* SAMU_busy */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033 /* GFX, HDP, DRMDMA */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033 /* GFX, HDP, DRMDMA */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000 /* GFX, HDP, DRMDMA */
/* thermal protection counter (units).*/
#define PPTONGA_THERMALPROTECTCOUNTER_DFLT 0x200 /* ~19us */
/* static screen threshold unit */
#define PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT 0
/* static screen threshold */
#define PPTONGA_STATICSCREENTHRESHOLD_DFLT 0x00C8
/* gfx idle clock stop threshold */
#define PPTONGA_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200 /* ~19us with static screen threshold unit of 0 */
/* Fixed reference divider to use when building baby stepping tables. */
#define PPTONGA_REFERENCEDIVIDER_DFLT 4
/*
* ULV voltage change delay time
* Used to be delay_vreg in N.I. split for S.I.
* Using N.I. delay_vreg value as default
* ReferenceClock = 2700
* VoltageResponseTime = 1000
* VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
*/
#define PPTONGA_ULVVOLTAGECHANGEDELAY_DFLT 1687
#define PPTONGA_CGULVPARAMETER_DFLT 0x00040035
#define PPTONGA_CGULVCONTROL_DFLT 0x00007450
#define PPTONGA_TARGETACTIVITY_DFLT 30 /*30% */
#define PPTONGA_MCLK_TARGETACTIVITY_DFLT 10 /*10% */
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef TONGA_HWMGR_H
#define TONGA_HWMGR_H
#include "hwmgr.h"
#include "smu72_discrete.h"
#include "ppatomctrl.h"
#include "ppinterrupt.h"
#include "tonga_powertune.h"
#define TONGA_MAX_HARDWARE_POWERLEVELS 2
#define TONGA_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15
struct tonga_performance_level {
uint32_t memory_clock;
uint32_t engine_clock;
uint16_t pcie_gen;
uint16_t pcie_lane;
};
struct _phw_tonga_bacos {
uint32_t best_match;
uint32_t baco_flags;
struct tonga_performance_level performance_level;
};
typedef struct _phw_tonga_bacos phw_tonga_bacos;
struct _phw_tonga_uvd_clocks {
uint32_t VCLK;
uint32_t DCLK;
};
typedef struct _phw_tonga_uvd_clocks phw_tonga_uvd_clocks;
struct _phw_tonga_vce_clocks {
uint32_t EVCLK;
uint32_t ECCLK;
};
typedef struct _phw_tonga_vce_clocks phw_tonga_vce_clocks;
struct tonga_power_state {
uint32_t magic;
phw_tonga_uvd_clocks uvd_clocks;
phw_tonga_vce_clocks vce_clocks;
uint32_t sam_clk;
uint32_t acp_clk;
uint16_t performance_level_count;
bool dc_compatible;
uint32_t sclk_threshold;
struct tonga_performance_level performance_levels[TONGA_MAX_HARDWARE_POWERLEVELS];
};
struct _phw_tonga_dpm_level {
bool enabled;
uint32_t value;
uint32_t param1;
};
typedef struct _phw_tonga_dpm_level phw_tonga_dpm_level;
#define TONGA_MAX_DEEPSLEEP_DIVIDER_ID 5
#define MAX_REGULAR_DPM_NUMBER 8
#define TONGA_MINIMUM_ENGINE_CLOCK 2500
struct tonga_single_dpm_table {
uint32_t count;
phw_tonga_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
};
struct tonga_dpm_table {
struct tonga_single_dpm_table sclk_table;
struct tonga_single_dpm_table mclk_table;
struct tonga_single_dpm_table pcie_speed_table;
struct tonga_single_dpm_table vddc_table;
struct tonga_single_dpm_table vdd_gfx_table;
struct tonga_single_dpm_table vdd_ci_table;
struct tonga_single_dpm_table mvdd_table;
};
typedef struct _phw_tonga_dpm_table phw_tonga_dpm_table;
struct _phw_tonga_clock_regisiters {
uint32_t vCG_SPLL_FUNC_CNTL;
uint32_t vCG_SPLL_FUNC_CNTL_2;
uint32_t vCG_SPLL_FUNC_CNTL_3;
uint32_t vCG_SPLL_FUNC_CNTL_4;
uint32_t vCG_SPLL_SPREAD_SPECTRUM;
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
uint32_t vDLL_CNTL;
uint32_t vMCLK_PWRMGT_CNTL;
uint32_t vMPLL_AD_FUNC_CNTL;
uint32_t vMPLL_DQ_FUNC_CNTL;
uint32_t vMPLL_FUNC_CNTL;
uint32_t vMPLL_FUNC_CNTL_1;
uint32_t vMPLL_FUNC_CNTL_2;
uint32_t vMPLL_SS1;
uint32_t vMPLL_SS2;
};
typedef struct _phw_tonga_clock_regisiters phw_tonga_clock_registers;
struct _phw_tonga_voltage_smio_registers {
uint32_t vs0_vid_lower_smio_cntl;
};
typedef struct _phw_tonga_voltage_smio_registers phw_tonga_voltage_smio_registers;
struct _phw_tonga_mc_reg_entry {
uint32_t mclk_max;
uint32_t mc_data[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
};
typedef struct _phw_tonga_mc_reg_entry phw_tonga_mc_reg_entry;
struct _phw_tonga_mc_reg_table {
uint8_t last; /* number of registers*/
uint8_t num_entries; /* number of entries in mc_reg_table_entry used*/
uint16_t validflag; /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
phw_tonga_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
SMU72_Discrete_MCRegisterAddress mc_reg_address[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
};
typedef struct _phw_tonga_mc_reg_table phw_tonga_mc_reg_table;
#define DISABLE_MC_LOADMICROCODE 1
#define DISABLE_MC_CFGPROGRAMMING 2
/*Ultra Low Voltage parameter structure */
struct _phw_tonga_ulv_parm{
bool ulv_supported;
uint32_t ch_ulv_parameter;
uint32_t ulv_volt_change_delay;
struct tonga_performance_level ulv_power_level;
};
typedef struct _phw_tonga_ulv_parm phw_tonga_ulv_parm;
#define TONGA_MAX_LEAKAGE_COUNT 8
struct _phw_tonga_leakage_voltage {
uint16_t count;
uint16_t leakage_id[TONGA_MAX_LEAKAGE_COUNT];
uint16_t actual_voltage[TONGA_MAX_LEAKAGE_COUNT];
};
typedef struct _phw_tonga_leakage_voltage phw_tonga_leakage_voltage;
struct _phw_tonga_display_timing {
uint32_t min_clock_insr;
uint32_t num_existing_displays;
};
typedef struct _phw_tonga_display_timing phw_tonga_display_timing;
struct _phw_tonga_dpmlevel_enable_mask {
uint32_t uvd_dpm_enable_mask;
uint32_t vce_dpm_enable_mask;
uint32_t acp_dpm_enable_mask;
uint32_t samu_dpm_enable_mask;
uint32_t sclk_dpm_enable_mask;
uint32_t mclk_dpm_enable_mask;
uint32_t pcie_dpm_enable_mask;
};
typedef struct _phw_tonga_dpmlevel_enable_mask phw_tonga_dpmlevel_enable_mask;
struct _phw_tonga_pcie_perf_range {
uint16_t max;
uint16_t min;
};
typedef struct _phw_tonga_pcie_perf_range phw_tonga_pcie_perf_range;
struct _phw_tonga_vbios_boot_state {
uint16_t mvdd_bootup_value;
uint16_t vddc_bootup_value;
uint16_t vddci_bootup_value;
uint16_t vddgfx_bootup_value;
uint32_t sclk_bootup_value;
uint32_t mclk_bootup_value;
uint16_t pcie_gen_bootup_value;
uint16_t pcie_lane_bootup_value;
};
typedef struct _phw_tonga_vbios_boot_state phw_tonga_vbios_boot_state;
#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
#define DPMTABLE_UPDATE_SCLK 0x00000004
#define DPMTABLE_UPDATE_MCLK 0x00000008
/* We need to review which fields are needed. */
/* This is mostly a copy of the RV7xx/Evergreen structure which is close, but not identical to the N.Islands one. */
struct tonga_hwmgr {
struct tonga_dpm_table dpm_table;
struct tonga_dpm_table golden_dpm_table;
uint32_t voting_rights_clients0;
uint32_t voting_rights_clients1;
uint32_t voting_rights_clients2;
uint32_t voting_rights_clients3;
uint32_t voting_rights_clients4;
uint32_t voting_rights_clients5;
uint32_t voting_rights_clients6;
uint32_t voting_rights_clients7;
uint32_t static_screen_threshold_unit;
uint32_t static_screen_threshold;
uint32_t voltage_control;
uint32_t vdd_gfx_control;
uint32_t vddc_vddci_delta;
uint32_t vddc_vddgfx_delta;
pp_interrupt_registration_info internal_high_thermal_interrupt_info;
pp_interrupt_registration_info internal_low_thermal_interrupt_info;
pp_interrupt_registration_info smc_to_host_interrupt_info;
uint32_t active_auto_throttle_sources;
pp_interrupt_registration_info external_throttle_interrupt;
pp_interrupt_callback external_throttle_callback;
void *external_throttle_context;
pp_interrupt_registration_info ctf_interrupt_info;
pp_interrupt_callback ctf_callback;
void *ctf_context;
phw_tonga_clock_registers clock_registers;
phw_tonga_voltage_smio_registers voltage_smio_registers;
bool is_memory_GDDR5;
uint16_t acpi_vddc;
bool pspp_notify_required; /* Flag to indicate if PSPP notification to SBIOS is required */
uint16_t force_pcie_gen; /* The forced PCI-E speed if not 0xffff */
uint16_t acpi_pcie_gen; /* The PCI-E speed at ACPI time */
uint32_t pcie_gen_cap; /* The PCI-E speed capabilities bitmap from CAIL */
uint32_t pcie_lane_cap; /* The PCI-E lane capabilities bitmap from CAIL */
uint32_t pcie_spc_cap; /* Symbol Per Clock Capabilities from registry */
phw_tonga_leakage_voltage vddc_leakage; /* The Leakage VDDC supported (based on leakage ID).*/
phw_tonga_leakage_voltage vddcgfx_leakage; /* The Leakage VDDC supported (based on leakage ID). */
phw_tonga_leakage_voltage vddci_leakage; /* The Leakage VDDCI supported (based on leakage ID). */
uint32_t mvdd_control;
uint32_t vddc_mask_low;
uint32_t mvdd_mask_low;
uint16_t max_vddc_in_pp_table; /* the maximum VDDC value in the powerplay table*/
uint16_t min_vddc_in_pp_table;
uint16_t max_vddci_in_pp_table; /* the maximum VDDCI value in the powerplay table */
uint16_t min_vddci_in_pp_table;
uint32_t mclk_strobe_mode_threshold;
uint32_t mclk_stutter_mode_threshold;
uint32_t mclk_edc_enable_threshold;
uint32_t mclk_edc_wr_enable_threshold;
bool is_uvd_enabled;
bool is_xdma_enabled;
phw_tonga_vbios_boot_state vbios_boot_state;
bool battery_state;
bool is_tlu_enabled;
bool pcie_performance_request;
/* -------------- SMC SRAM Address of firmware header tables ----------------*/
uint32_t sram_end; /* The first address after the SMC SRAM. */
uint32_t dpm_table_start; /* The start of the dpm table in the SMC SRAM. */
uint32_t soft_regs_start; /* The start of the soft registers in the SMC SRAM. */
uint32_t mc_reg_table_start; /* The start of the mc register table in the SMC SRAM. */
uint32_t fan_table_start; /* The start of the fan table in the SMC SRAM. */
uint32_t arb_table_start; /* The start of the ARB setting table in the SMC SRAM. */
SMU72_Discrete_DpmTable smc_state_table; /* The carbon copy of the SMC state table. */
SMU72_Discrete_MCRegisters mc_reg_table;
SMU72_Discrete_Ulv ulv_setting; /* The carbon copy of ULV setting. */
/* -------------- Stuff originally coming from Evergreen --------------------*/
phw_tonga_mc_reg_table tonga_mc_reg_table;
uint32_t vdd_ci_control;
pp_atomctrl_voltage_table vddc_voltage_table;
pp_atomctrl_voltage_table vddci_voltage_table;
pp_atomctrl_voltage_table vddgfx_voltage_table;
pp_atomctrl_voltage_table mvdd_voltage_table;
uint32_t mgcg_cgtt_local2;
uint32_t mgcg_cgtt_local3;
uint32_t gpio_debug;
uint32_t mc_micro_code_feature;
uint32_t highest_mclk;
uint16_t acpi_vdd_ci;
uint8_t mvdd_high_index;
uint8_t mvdd_low_index;
bool dll_defaule_on;
bool performance_request_registered;
/* ----------------- Low Power Features ---------------------*/
phw_tonga_bacos bacos;
phw_tonga_ulv_parm ulv;
/* ----------------- CAC Stuff ---------------------*/
uint32_t cac_table_start;
bool cac_configuration_required; /* TRUE if PP_CACConfigurationRequired == 1 */
bool driver_calculate_cac_leakage; /* TRUE if PP_DriverCalculateCACLeakage == 1 */
bool cac_enabled;
/* ----------------- DPM2 Parameters ---------------------*/
uint32_t power_containment_features;
bool enable_bapm_feature;
bool enable_tdc_limit_feature;
bool enable_pkg_pwr_tracking_feature;
bool disable_uvd_power_tune_feature;
phw_tonga_pt_defaults *power_tune_defaults;
SMU72_Discrete_PmFuses power_tune_table;
uint32_t ul_dte_tj_offset; /* Fudge factor in DPM table to correct HW DTE errors */
uint32_t fast_watemark_threshold; /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */
/* ----------------- Phase Shedding ---------------------*/
bool vddc_phase_shed_control;
/* --------------------- DI/DT --------------------------*/
phw_tonga_display_timing display_timing;
/* --------- ReadRegistry data for memory and engine clock margins ---- */
uint32_t engine_clock_data;
uint32_t memory_clock_data;
/* -------- Thermal Temperature Setting --------------*/
phw_tonga_dpmlevel_enable_mask dpm_level_enable_mask;
uint32_t need_update_smu7_dpm_table;
uint32_t sclk_dpm_key_disabled;
uint32_t mclk_dpm_key_disabled;
uint32_t pcie_dpm_key_disabled;
uint32_t min_engine_clocks; /* used to store the previous dal min sclock */
phw_tonga_pcie_perf_range pcie_gen_performance;
phw_tonga_pcie_perf_range pcie_lane_performance;
phw_tonga_pcie_perf_range pcie_gen_power_saving;
phw_tonga_pcie_perf_range pcie_lane_power_saving;
bool use_pcie_performance_levels;
bool use_pcie_power_saving_levels;
uint32_t activity_target[SMU72_MAX_LEVELS_GRAPHICS]; /* percentage value from 0-100, default 50 */
uint32_t mclk_activity_target;
uint32_t low_sclk_interrupt_threshold;
uint32_t last_mclk_dpm_enable_mask;
bool uvd_enabled;
uint32_t pcc_monitor_enabled;
/* --------- Power Gating States ------------*/
bool uvd_power_gated; /* 1: gated, 0:not gated */
bool vce_power_gated; /* 1: gated, 0:not gated */
bool samu_power_gated; /* 1: gated, 0:not gated */
bool acp_power_gated; /* 1: gated, 0:not gated */
bool pg_acp_init;
};
typedef struct tonga_hwmgr tonga_hwmgr;
#define TONGA_DPM2_NEAR_TDP_DEC 10
#define TONGA_DPM2_ABOVE_SAFE_INC 5
#define TONGA_DPM2_BELOW_SAFE_INC 20
#define TONGA_DPM2_LTA_WINDOW_SIZE 7 /* Log2 of the LTA window size (l2numWin_TDP). Eg. If LTA windows size is 128, then this value should be Log2(128) = 7. */
#define TONGA_DPM2_LTS_TRUNCATE 0
#define TONGA_DPM2_TDP_SAFE_LIMIT_PERCENT 80 /* Maximum 100 */
#define TONGA_DPM2_MAXPS_PERCENT_H 90 /* Maximum 0xFF */
#define TONGA_DPM2_MAXPS_PERCENT_M 90 /* Maximum 0xFF */
#define TONGA_DPM2_PWREFFICIENCYRATIO_MARGIN 50
#define TONGA_DPM2_SQ_RAMP_MAX_POWER 0x3FFF
#define TONGA_DPM2_SQ_RAMP_MIN_POWER 0x12
#define TONGA_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15
#define TONGA_DPM2_SQ_RAMP_SHORT_TERM_INTERVAL_SIZE 0x1E
#define TONGA_DPM2_SQ_RAMP_LONG_TERM_INTERVAL_RATIO 0xF
#define TONGA_VOLTAGE_CONTROL_NONE 0x0
#define TONGA_VOLTAGE_CONTROL_BY_GPIO 0x1
#define TONGA_VOLTAGE_CONTROL_BY_SVID2 0x2
#define TONGA_VOLTAGE_CONTROL_MERGED 0x3
#define TONGA_Q88_FORMAT_CONVERSION_UNIT 256 /*To convert to Q8.8 format for firmware */
#define TONGA_UNUSED_GPIO_PIN 0x7F
/* Following flags shows PCIe link speed supported in driver which are decided by chipset and ASIC */
#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 0x00010000
#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 0x00020000
#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 0x00040000
#define CAIL_PCIE_LINK_SPEED_SUPPORT_MASK 0xFFFF0000
#define CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT 16
/* Following flags shows PCIe link speed supported by ASIC H/W.*/
#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 0x00000001
#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 0x00000002
#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3 0x00000004
#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_MASK 0x0000FFFF
#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_SHIFT 0
/* Following flags shows PCIe lane width switch supported in driver which are decided by chipset and ASIC */
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X1 0x00010000
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 0x00020000
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 0x00040000
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 0x00080000
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 0x00100000
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 0x00200000
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 0x00400000
#define CAIL_PCIE_LINK_WIDTH_SUPPORT_SHIFT 16
#define PP_HOST_TO_SMC_UL(X) cpu_to_be32(X)
#define PP_SMC_TO_HOST_UL(X) be32_to_cpu(X)
#define PP_HOST_TO_SMC_US(X) cpu_to_be16(X)
#define PP_SMC_TO_HOST_US(X) be16_to_cpu(X)
#define CONVERT_FROM_HOST_TO_SMC_UL(X) ((X) = PP_HOST_TO_SMC_UL(X))
#define CONVERT_FROM_SMC_TO_HOST_UL(X) ((X) = PP_SMC_TO_HOST_UL(X))
#define CONVERT_FROM_HOST_TO_SMC_US(X) ((X) = PP_HOST_TO_SMC_US(X))
int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef TONGA_POWERTUNE_H
#define TONGA_POWERTUNE_H
enum _phw_tonga_ptc_config_reg_type {
TONGA_CONFIGREG_MMR = 0,
TONGA_CONFIGREG_SMC_IND,
TONGA_CONFIGREG_DIDT_IND,
TONGA_CONFIGREG_CACHE,
TONGA_CONFIGREG_MAX
};
typedef enum _phw_tonga_ptc_config_reg_type phw_tonga_ptc_config_reg_type;
/* PowerContainment Features */
#define POWERCONTAINMENT_FEATURE_BAPM 0x00000001
#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
struct _phw_tonga_pt_config_reg {
uint32_t Offset;
uint32_t Mask;
uint32_t Shift;
uint32_t Value;
phw_tonga_ptc_config_reg_type Type;
};
typedef struct _phw_tonga_pt_config_reg phw_tonga_pt_config_reg;
struct _phw_tonga_pt_defaults {
uint8_t svi_load_line_en;
uint8_t svi_load_line_vddC;
uint8_t tdc_vddc_throttle_release_limit_perc;
uint8_t tdc_mawt;
uint8_t tdc_waterfall_ctl;
uint8_t dte_ambient_temp_base;
uint32_t display_cac;
uint32_t bamp_temp_gradient;
uint16_t bapmti_r[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
uint16_t bapmti_rc[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
};
typedef struct _phw_tonga_pt_defaults phw_tonga_pt_defaults;
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef TONGA_PPTABLE_H
#define TONGA_PPTABLE_H
/** \file
* This is a PowerPlay table header file
*/
#pragma pack(push, 1)
#include "hwmgr.h"
#define ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f
#define ATOM_TONGA_PP_FANPARAMETERS_NOFAN 0x80 /* No fan is connected to this controller. */
#define ATOM_TONGA_PP_THERMALCONTROLLER_NONE 0
#define ATOM_TONGA_PP_THERMALCONTROLLER_LM96163 17
#define ATOM_TONGA_PP_THERMALCONTROLLER_TONGA 21
#define ATOM_TONGA_PP_THERMALCONTROLLER_FIJI 22
/*
* Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal.
* We probably should reserve the bit 0x80 for this use.
* To keep the number of these types low we should also use the same code for all ASICs (i.e. do not distinguish RV6xx and RV7xx Internal here).
* The driver can pick the correct internal controller based on the ASIC.
*/
#define ATOM_TONGA_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL 0x89 /* ADT7473 Fan Control + Internal Thermal Controller */
#define ATOM_TONGA_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL 0x8D /* EMC2103 Fan Control + Internal Thermal Controller */
/*/* ATOM_TONGA_POWERPLAYTABLE::ulPlatformCaps */
#define ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL 0x1 /* This cap indicates whether vddgfx will be a separated power rail. */
#define ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY 0x2 /* This cap indicates whether this is a mobile part and CCC need to show Powerplay page. */
#define ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE 0x4 /* This cap indicates whether power source notificaiton is done by SBIOS directly. */
#define ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND 0x8 /* Enable the option to overwrite voltage island feature to be disabled, regardless of VddGfx power rail support. */
#define ____RETIRE16____ 0x10
#define ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC 0x20 /* This cap indicates whether power source notificaiton is done by GPIO directly. */
#define ____RETIRE64____ 0x40
#define ____RETIRE128____ 0x80
#define ____RETIRE256____ 0x100
#define ____RETIRE512____ 0x200
#define ____RETIRE1024____ 0x400
#define ____RETIRE2048____ 0x800
#define ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL 0x1000 /* This cap indicates dynamic MVDD is required. Uncheck to disable it. */
#define ____RETIRE2000____ 0x2000
#define ____RETIRE4000____ 0x4000
#define ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL 0x8000 /* This cap indicates dynamic VDDCI is required. Uncheck to disable it. */
#define ____RETIRE10000____ 0x10000
#define ATOM_TONGA_PP_PLATFORM_CAP_BACO 0x20000 /* Enable to indicate the driver supports BACO state. */
#define ATOM_TONGA_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17 0x100000 /* Enable to indicate the driver supports thermal2GPIO17. */
#define ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL 0x1000000 /* Enable to indicate if thermal and PCC are sharing the same GPIO */
#define ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE 0x2000000
/* ATOM_PPLIB_NONCLOCK_INFO::usClassification */
#define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007
#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0
#define ATOM_PPLIB_CLASSIFICATION_UI_NONE 0
#define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY 1
#define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED 3
#define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE 5
/* 2, 4, 6, 7 are reserved */
#define ATOM_PPLIB_CLASSIFICATION_BOOT 0x0008
#define ATOM_PPLIB_CLASSIFICATION_THERMAL 0x0010
#define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE 0x0020
#define ATOM_PPLIB_CLASSIFICATION_REST 0x0040
#define ATOM_PPLIB_CLASSIFICATION_FORCED 0x0080
#define ATOM_PPLIB_CLASSIFICATION_ACPI 0x1000
/* ATOM_PPLIB_NONCLOCK_INFO::usClassification2 */
#define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001
#define ATOM_Tonga_DISALLOW_ON_DC 0x00004000
#define ATOM_Tonga_ENABLE_VARIBRIGHT 0x00008000
#define ATOM_Tonga_TABLE_REVISION_TONGA 7
typedef struct _ATOM_Tonga_POWERPLAYTABLE {
ATOM_COMMON_TABLE_HEADER sHeader;
UCHAR ucTableRevision;
USHORT usTableSize; /*the size of header structure */
ULONG ulGoldenPPID;
ULONG ulGoldenRevision;
USHORT usFormatID;
USHORT usVoltageTime; /*in microseconds */
ULONG ulPlatformCaps; /*See ATOM_Tonga_CAPS_* */
ULONG ulMaxODEngineClock; /*For Overdrive. */
ULONG ulMaxODMemoryClock; /*For Overdrive. */
USHORT usPowerControlLimit;
USHORT usUlvVoltageOffset; /*in mv units */
USHORT usStateArrayOffset; /*points to ATOM_Tonga_State_Array */
USHORT usFanTableOffset; /*points to ATOM_Tonga_Fan_Table */
USHORT usThermalControllerOffset; /*points to ATOM_Tonga_Thermal_Controller */
USHORT usReserv; /*CustomThermalPolicy removed for Tonga. Keep this filed as reserved. */
USHORT usMclkDependencyTableOffset; /*points to ATOM_Tonga_MCLK_Dependency_Table */
USHORT usSclkDependencyTableOffset; /*points to ATOM_Tonga_SCLK_Dependency_Table */
USHORT usVddcLookupTableOffset; /*points to ATOM_Tonga_Voltage_Lookup_Table */
USHORT usVddgfxLookupTableOffset; /*points to ATOM_Tonga_Voltage_Lookup_Table */
USHORT usMMDependencyTableOffset; /*points to ATOM_Tonga_MM_Dependency_Table */
USHORT usVCEStateTableOffset; /*points to ATOM_Tonga_VCE_State_Table; */
USHORT usPPMTableOffset; /*points to ATOM_Tonga_PPM_Table */
USHORT usPowerTuneTableOffset; /*points to ATOM_PowerTune_Table */
USHORT usHardLimitTableOffset; /*points to ATOM_Tonga_Hard_Limit_Table */
USHORT usPCIETableOffset; /*points to ATOM_Tonga_PCIE_Table */
USHORT usGPIOTableOffset; /*points to ATOM_Tonga_GPIO_Table */
USHORT usReserved[6]; /*TODO: modify reserved size to fit structure aligning */
} ATOM_Tonga_POWERPLAYTABLE;
typedef struct _ATOM_Tonga_State {
UCHAR ucEngineClockIndexHigh;
UCHAR ucEngineClockIndexLow;
UCHAR ucMemoryClockIndexHigh;
UCHAR ucMemoryClockIndexLow;
UCHAR ucPCIEGenLow;
UCHAR ucPCIEGenHigh;
UCHAR ucPCIELaneLow;
UCHAR ucPCIELaneHigh;
USHORT usClassification;
ULONG ulCapsAndSettings;
USHORT usClassification2;
UCHAR ucUnused[4];
} ATOM_Tonga_State;
typedef struct _ATOM_Tonga_State_Array {
UCHAR ucRevId;
UCHAR ucNumEntries; /* Number of entries. */
ATOM_Tonga_State states[1]; /* Dynamically allocate entries. */
} ATOM_Tonga_State_Array;
typedef struct _ATOM_Tonga_MCLK_Dependency_Record {
UCHAR ucVddcInd; /* Vddc voltage */
USHORT usVddci;
USHORT usVddgfxOffset; /* Offset relative to Vddc voltage */
USHORT usMvdd;
ULONG ulMclk;
USHORT usReserved;
} ATOM_Tonga_MCLK_Dependency_Record;
typedef struct _ATOM_Tonga_MCLK_Dependency_Table {
UCHAR ucRevId;
UCHAR ucNumEntries; /* Number of entries. */
ATOM_Tonga_MCLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */
} ATOM_Tonga_MCLK_Dependency_Table;
typedef struct _ATOM_Tonga_SCLK_Dependency_Record {
UCHAR ucVddInd; /* Base voltage */
USHORT usVddcOffset; /* Offset relative to base voltage */
ULONG ulSclk;
USHORT usEdcCurrent;
UCHAR ucReliabilityTemperature;
UCHAR ucCKSVOffsetandDisable; /* Bits 0~6: Voltage offset for CKS, Bit 7: Disable/enable for the SCLK level. */
} ATOM_Tonga_SCLK_Dependency_Record;
typedef struct _ATOM_Tonga_SCLK_Dependency_Table {
UCHAR ucRevId;
UCHAR ucNumEntries; /* Number of entries. */
ATOM_Tonga_SCLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */
} ATOM_Tonga_SCLK_Dependency_Table;
typedef struct _ATOM_Tonga_PCIE_Record {
UCHAR ucPCIEGenSpeed;
UCHAR usPCIELaneWidth;
UCHAR ucReserved[2];
} ATOM_Tonga_PCIE_Record;
typedef struct _ATOM_Tonga_PCIE_Table {
UCHAR ucRevId;
UCHAR ucNumEntries; /* Number of entries. */
ATOM_Tonga_PCIE_Record entries[1]; /* Dynamically allocate entries. */
} ATOM_Tonga_PCIE_Table;
typedef struct _ATOM_Tonga_MM_Dependency_Record {
UCHAR ucVddcInd; /* VDDC voltage */
USHORT usVddgfxOffset; /* Offset relative to VDDC voltage */
ULONG ulDClk; /* UVD D-clock */
ULONG ulVClk; /* UVD V-clock */
ULONG ulEClk; /* VCE clock */
ULONG ulAClk; /* ACP clock */
ULONG ulSAMUClk; /* SAMU clock */
} ATOM_Tonga_MM_Dependency_Record;
typedef struct _ATOM_Tonga_MM_Dependency_Table {
UCHAR ucRevId;
UCHAR ucNumEntries; /* Number of entries. */
ATOM_Tonga_MM_Dependency_Record entries[1]; /* Dynamically allocate entries. */
} ATOM_Tonga_MM_Dependency_Table;
typedef struct _ATOM_Tonga_Voltage_Lookup_Record {
USHORT usVdd; /* Base voltage */
USHORT usCACLow;
USHORT usCACMid;
USHORT usCACHigh;
} ATOM_Tonga_Voltage_Lookup_Record;
typedef struct _ATOM_Tonga_Voltage_Lookup_Table {
UCHAR ucRevId;
UCHAR ucNumEntries; /* Number of entries. */
ATOM_Tonga_Voltage_Lookup_Record entries[1]; /* Dynamically allocate entries. */
} ATOM_Tonga_Voltage_Lookup_Table;
typedef struct _ATOM_Tonga_Fan_Table {
UCHAR ucRevId; /* Change this if the table format changes or version changes so that the other fields are not the same. */
UCHAR ucTHyst; /* Temperature hysteresis. Integer. */
USHORT usTMin; /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
USHORT usTMed; /* The middle temperature where we change slopes. */
USHORT usTHigh; /* The high point above TMed for adjusting the second slope. */
USHORT usPWMMin; /* The minimum PWM value in percent (0.01% increments). */
USHORT usPWMMed; /* The PWM value (in percent) at TMed. */
USHORT usPWMHigh; /* The PWM value at THigh. */
USHORT usTMax; /* The max temperature */
UCHAR ucFanControlMode; /* Legacy or Fuzzy Fan mode */
USHORT usFanPWMMax; /* Maximum allowed fan power in percent */
USHORT usFanOutputSensitivity; /* Sensitivity of fan reaction to temepature changes */
USHORT usFanRPMMax; /* The default value in RPM */
ULONG ulMinFanSCLKAcousticLimit; /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
UCHAR ucTargetTemperature; /* Advanced fan controller target temperature. */
UCHAR ucMinimumPWMLimit; /* The minimum PWM that the advanced fan controller can set. This should be set to the highest PWM that will run the fan at its lowest RPM. */
USHORT usReserved;
} ATOM_Tonga_Fan_Table;
typedef struct _ATOM_Fiji_Fan_Table {
UCHAR ucRevId; /* Change this if the table format changes or version changes so that the other fields are not the same. */
UCHAR ucTHyst; /* Temperature hysteresis. Integer. */
USHORT usTMin; /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
USHORT usTMed; /* The middle temperature where we change slopes. */
USHORT usTHigh; /* The high point above TMed for adjusting the second slope. */
USHORT usPWMMin; /* The minimum PWM value in percent (0.01% increments). */
USHORT usPWMMed; /* The PWM value (in percent) at TMed. */
USHORT usPWMHigh; /* The PWM value at THigh. */
USHORT usTMax; /* The max temperature */
UCHAR ucFanControlMode; /* Legacy or Fuzzy Fan mode */
USHORT usFanPWMMax; /* Maximum allowed fan power in percent */
USHORT usFanOutputSensitivity; /* Sensitivity of fan reaction to temepature changes */
USHORT usFanRPMMax; /* The default value in RPM */
ULONG ulMinFanSCLKAcousticLimit; /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
UCHAR ucTargetTemperature; /* Advanced fan controller target temperature. */
UCHAR ucMinimumPWMLimit; /* The minimum PWM that the advanced fan controller can set. This should be set to the highest PWM that will run the fan at its lowest RPM. */
USHORT usFanGainEdge;
USHORT usFanGainHotspot;
USHORT usFanGainLiquid;
USHORT usFanGainVrVddc;
USHORT usFanGainVrMvdd;
USHORT usFanGainPlx;
USHORT usFanGainHbm;
USHORT usReserved;
} ATOM_Fiji_Fan_Table;
typedef struct _ATOM_Tonga_Thermal_Controller {
UCHAR ucRevId;
UCHAR ucType; /* one of ATOM_TONGA_PP_THERMALCONTROLLER_* */
UCHAR ucI2cLine; /* as interpreted by DAL I2C */
UCHAR ucI2cAddress;
UCHAR ucFanParameters; /* Fan Control Parameters. */
UCHAR ucFanMinRPM; /* Fan Minimum RPM (hundreds) -- for display purposes only. */
UCHAR ucFanMaxRPM; /* Fan Maximum RPM (hundreds) -- for display purposes only. */
UCHAR ucReserved;
UCHAR ucFlags; /* to be defined */
} ATOM_Tonga_Thermal_Controller;
typedef struct _ATOM_Tonga_VCE_State_Record {
UCHAR ucVCEClockIndex; /*index into usVCEDependencyTableOffset of 'ATOM_Tonga_MM_Dependency_Table' type */
UCHAR ucFlag; /* 2 bits indicates memory p-states */
UCHAR ucSCLKIndex; /*index into ATOM_Tonga_SCLK_Dependency_Table */
UCHAR ucMCLKIndex; /*index into ATOM_Tonga_MCLK_Dependency_Table */
} ATOM_Tonga_VCE_State_Record;
typedef struct _ATOM_Tonga_VCE_State_Table {
UCHAR ucRevId;
UCHAR ucNumEntries;
ATOM_Tonga_VCE_State_Record entries[1];
} ATOM_Tonga_VCE_State_Table;
typedef struct _ATOM_Tonga_PowerTune_Table {
UCHAR ucRevId;
USHORT usTDP;
USHORT usConfigurableTDP;
USHORT usTDC;
USHORT usBatteryPowerLimit;
USHORT usSmallPowerLimit;
USHORT usLowCACLeakage;
USHORT usHighCACLeakage;
USHORT usMaximumPowerDeliveryLimit;
USHORT usTjMax;
USHORT usPowerTuneDataSetID;
USHORT usEDCLimit;
USHORT usSoftwareShutdownTemp;
USHORT usClockStretchAmount;
USHORT usReserve[2];
} ATOM_Tonga_PowerTune_Table;
typedef struct _ATOM_Fiji_PowerTune_Table {
UCHAR ucRevId;
USHORT usTDP;
USHORT usConfigurableTDP;
USHORT usTDC;
USHORT usBatteryPowerLimit;
USHORT usSmallPowerLimit;
USHORT usLowCACLeakage;
USHORT usHighCACLeakage;
USHORT usMaximumPowerDeliveryLimit;
USHORT usTjMax; /* For Fiji, this is also usTemperatureLimitEdge; */
USHORT usPowerTuneDataSetID;
USHORT usEDCLimit;
USHORT usSoftwareShutdownTemp;
USHORT usClockStretchAmount;
USHORT usTemperatureLimitHotspot; /*The following are added for Fiji */
USHORT usTemperatureLimitLiquid1;
USHORT usTemperatureLimitLiquid2;
USHORT usTemperatureLimitVrVddc;
USHORT usTemperatureLimitVrMvdd;
USHORT usTemperatureLimitPlx;
UCHAR ucLiquid1_I2C_address; /*Liquid */
UCHAR ucLiquid2_I2C_address;
UCHAR ucLiquid_I2C_Line;
UCHAR ucVr_I2C_address; /*VR */
UCHAR ucVr_I2C_Line;
UCHAR ucPlx_I2C_address; /*PLX */
UCHAR ucPlx_I2C_Line;
USHORT usReserved;
} ATOM_Fiji_PowerTune_Table;
#define ATOM_PPM_A_A 1
#define ATOM_PPM_A_I 2
typedef struct _ATOM_Tonga_PPM_Table {
UCHAR ucRevId;
UCHAR ucPpmDesign; /*A+I or A+A */
USHORT usCpuCoreNumber;
ULONG ulPlatformTDP;
ULONG ulSmallACPlatformTDP;
ULONG ulPlatformTDC;
ULONG ulSmallACPlatformTDC;
ULONG ulApuTDP;
ULONG ulDGpuTDP;
ULONG ulDGpuUlvPower;
ULONG ulTjmax;
} ATOM_Tonga_PPM_Table;
typedef struct _ATOM_Tonga_Hard_Limit_Record {
ULONG ulSCLKLimit;
ULONG ulMCLKLimit;
USHORT usVddcLimit;
USHORT usVddciLimit;
USHORT usVddgfxLimit;
} ATOM_Tonga_Hard_Limit_Record;
typedef struct _ATOM_Tonga_Hard_Limit_Table {
UCHAR ucRevId;
UCHAR ucNumEntries;
ATOM_Tonga_Hard_Limit_Record entries[1];
} ATOM_Tonga_Hard_Limit_Table;
typedef struct _ATOM_Tonga_GPIO_Table {
UCHAR ucRevId;
UCHAR ucVRHotTriggeredSclkDpmIndex; /* If VRHot signal is triggered SCLK will be limited to this DPM level */
UCHAR ucReserve[5];
} ATOM_Tonga_GPIO_Table;
typedef struct _PPTable_Generic_SubTable_Header {
UCHAR ucRevId;
} PPTable_Generic_SubTable_Header;
#pragma pack(pop)
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include "tonga_processpptables.h"
#include "ppatomctrl.h"
#include "atombios.h"
#include "pp_debug.h"
#include "hwmgr.h"
#include "cgs_common.h"
#include "tonga_pptable.h"
/**
* Private Function used during initialization.
* @param hwmgr Pointer to the hardware manager.
* @param setIt A flag indication if the capability should be set (TRUE) or reset (FALSE).
* @param cap Which capability to set/reset.
*/
static void set_hw_cap(struct pp_hwmgr *hwmgr, bool setIt, enum phm_platform_caps cap)
{
if (setIt)
phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
else
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
}
/**
* Private Function used during initialization.
* @param hwmgr Pointer to the hardware manager.
* @param powerplay_caps the bit array (from BIOS) of capability bits.
* @exception the current implementation always returns 1.
*/
static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps)
{
PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE16____),
"ATOM_PP_PLATFORM_CAP_ASPM_L1 is not supported!", continue);
PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE64____),
"ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY is not supported!", continue);
PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE512____),
"ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL is not supported!", continue);
PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE1024____),
"ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 is not supported!", continue);
PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE2048____),
"ATOM_PP_PLATFORM_CAP_HTLINKCONTROL is not supported!", continue);
set_hw_cap(
hwmgr,
0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY),
PHM_PlatformCaps_PowerPlaySupport
);
set_hw_cap(
hwmgr,
0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
PHM_PlatformCaps_BiosPowerSourceControl
);
set_hw_cap(
hwmgr,
0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC),
PHM_PlatformCaps_AutomaticDCTransition
);
set_hw_cap(
hwmgr,
0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL),
PHM_PlatformCaps_EnableMVDDControl
);
set_hw_cap(
hwmgr,
0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL),
PHM_PlatformCaps_ControlVDDCI
);
set_hw_cap(
hwmgr,
0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL),
PHM_PlatformCaps_ControlVDDGFX
);
set_hw_cap(
hwmgr,
0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_BACO),
PHM_PlatformCaps_BACO
);
set_hw_cap(
hwmgr,
0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND),
PHM_PlatformCaps_DisableVoltageIsland
);
set_hw_cap(
hwmgr,
0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
PHM_PlatformCaps_CombinePCCWithThermalSignal
);
set_hw_cap(
hwmgr,
0 != (powerplay_caps & ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
PHM_PlatformCaps_LoadPostProductionFirmware
);
return 0;
}
/**
* Private Function to get the PowerPlay Table Address.
*/
const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
{
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
u16 size;
u8 frev, crev;
void *table_address;
table_address = (ATOM_Tonga_POWERPLAYTABLE *)
cgs_atom_get_data_table(hwmgr->device, index, &size, &frev, &crev);
hwmgr->soft_pp_table = table_address; /*Cache the result in RAM.*/
return table_address;
}
static int get_vddc_lookup_table(
struct pp_hwmgr *hwmgr,
phm_ppt_v1_voltage_lookup_table **lookup_table,
const ATOM_Tonga_Voltage_Lookup_Table *vddc_lookup_pp_tables,
uint32_t max_levels
)
{
uint32_t table_size, i;
phm_ppt_v1_voltage_lookup_table *table;
PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries),
"Invalid CAC Leakage PowerPlay Table!", return 1);
table_size = sizeof(uint32_t) +
sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels;
table = (phm_ppt_v1_voltage_lookup_table *)
kzalloc(table_size, GFP_KERNEL);
if (NULL == table)
return -1;
memset(table, 0x00, table_size);
table->count = vddc_lookup_pp_tables->ucNumEntries;
for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) {
table->entries[i].us_calculated = 0;
table->entries[i].us_vdd =
vddc_lookup_pp_tables->entries[i].usVdd;
table->entries[i].us_cac_low =
vddc_lookup_pp_tables->entries[i].usCACLow;
table->entries[i].us_cac_mid =
vddc_lookup_pp_tables->entries[i].usCACMid;
table->entries[i].us_cac_high =
vddc_lookup_pp_tables->entries[i].usCACHigh;
}
*lookup_table = table;
return 0;
}
/**
* Private Function used during initialization.
* Initialize Platform Power Management Parameter table
* @param hwmgr Pointer to the hardware manager.
* @param atom_ppm_table Pointer to PPM table in VBIOS
*/
static int get_platform_power_management_table(
struct pp_hwmgr *hwmgr,
ATOM_Tonga_PPM_Table *atom_ppm_table)
{
struct phm_ppm_table *ptr = kzalloc(sizeof(ATOM_Tonga_PPM_Table), GFP_KERNEL);
struct phm_ppt_v1_information *pp_table_information =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
if (NULL == ptr)
return -1;
ptr->ppm_design
= atom_ppm_table->ucPpmDesign;
ptr->cpu_core_number
= atom_ppm_table->usCpuCoreNumber;
ptr->platform_tdp
= atom_ppm_table->ulPlatformTDP;
ptr->small_ac_platform_tdp
= atom_ppm_table->ulSmallACPlatformTDP;
ptr->platform_tdc
= atom_ppm_table->ulPlatformTDC;
ptr->small_ac_platform_tdc
= atom_ppm_table->ulSmallACPlatformTDC;
ptr->apu_tdp
= atom_ppm_table->ulApuTDP;
ptr->dgpu_tdp
= atom_ppm_table->ulDGpuTDP;
ptr->dgpu_ulv_power
= atom_ppm_table->ulDGpuUlvPower;
ptr->tj_max
= atom_ppm_table->ulTjmax;
pp_table_information->ppm_parameter_table = ptr;
return 0;
}
/**
* Private Function used during initialization.
* Initialize TDP limits for DPM2
* @param hwmgr Pointer to the hardware manager.
* @param powerplay_table Pointer to the PowerPlay Table.
*/
static int init_dpm_2_parameters(
struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
)
{
int result = 0;
struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
ATOM_Tonga_PPM_Table *atom_ppm_table;
uint32_t disable_ppm = 0;
uint32_t disable_power_control = 0;
pp_table_information->us_ulv_voltage_offset =
le16_to_cpu(powerplay_table->usUlvVoltageOffset);
pp_table_information->ppm_parameter_table = NULL;
pp_table_information->vddc_lookup_table = NULL;
pp_table_information->vddgfx_lookup_table = NULL;
/* TDP limits */
hwmgr->platform_descriptor.TDPODLimit =
le16_to_cpu(powerplay_table->usPowerControlLimit);
hwmgr->platform_descriptor.TDPAdjustment = 0;
hwmgr->platform_descriptor.VidAdjustment = 0;
hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
hwmgr->platform_descriptor.VidMinLimit = 0;
hwmgr->platform_descriptor.VidMaxLimit = 1500000;
hwmgr->platform_descriptor.VidStep = 6250;
disable_power_control = 0;
if (0 == disable_power_control) {
/* enable TDP overdrive (PowerControl) feature as well if supported */
if (hwmgr->platform_descriptor.TDPODLimit != 0)
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerControl);
}
if (0 != powerplay_table->usVddcLookupTableOffset) {
const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable =
(ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
le16_to_cpu(powerplay_table->usVddcLookupTableOffset));
result = get_vddc_lookup_table(hwmgr,
&pp_table_information->vddc_lookup_table, pVddcCACTable, 16);
}
if (0 != powerplay_table->usVddgfxLookupTableOffset) {
const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable =
(ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset));
result = get_vddc_lookup_table(hwmgr,
&pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16);
}
disable_ppm = 0;
if (0 == disable_ppm) {
atom_ppm_table = (ATOM_Tonga_PPM_Table *)
(((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset));
if (0 != powerplay_table->usPPMTableOffset) {
if (1 == get_platform_power_management_table(hwmgr, atom_ppm_table)) {
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_EnablePlatformPowerManagement);
}
}
}
return result;
}
static int get_valid_clk(
struct pp_hwmgr *hwmgr,
struct phm_clock_array **clk_table,
const phm_ppt_v1_clock_voltage_dependency_table * clk_volt_pp_table
)
{
uint32_t table_size, i;
struct phm_clock_array *table;
PP_ASSERT_WITH_CODE((0 != clk_volt_pp_table->count),
"Invalid PowerPlay Table!", return -1);
table_size = sizeof(uint32_t) +
sizeof(uint32_t) * clk_volt_pp_table->count;
table = (struct phm_clock_array *)kzalloc(table_size, GFP_KERNEL);
if (NULL == table)
return -1;
memset(table, 0x00, table_size);
table->count = (uint32_t)clk_volt_pp_table->count;
for (i = 0; i < table->count; i++)
table->values[i] = (uint32_t)clk_volt_pp_table->entries[i].clk;
*clk_table = table;
return 0;
}
static int get_hard_limits(
struct pp_hwmgr *hwmgr,
struct phm_clock_and_voltage_limits *limits,
const ATOM_Tonga_Hard_Limit_Table * limitable
)
{
PP_ASSERT_WITH_CODE((0 != limitable->ucNumEntries), "Invalid PowerPlay Table!", return -1);
/* currently we always take entries[0] parameters */
limits->sclk = (uint32_t)limitable->entries[0].ulSCLKLimit;
limits->mclk = (uint32_t)limitable->entries[0].ulMCLKLimit;
limits->vddc = (uint16_t)limitable->entries[0].usVddcLimit;
limits->vddci = (uint16_t)limitable->entries[0].usVddciLimit;
limits->vddgfx = (uint16_t)limitable->entries[0].usVddgfxLimit;
return 0;
}
static int get_mclk_voltage_dependency_table(
struct pp_hwmgr *hwmgr,
phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_mclk_dep_table,
const ATOM_Tonga_MCLK_Dependency_Table * mclk_dep_table
)
{
uint32_t table_size, i;
phm_ppt_v1_clock_voltage_dependency_table *mclk_table;
PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
* mclk_dep_table->ucNumEntries;
mclk_table = (phm_ppt_v1_clock_voltage_dependency_table *)
kzalloc(table_size, GFP_KERNEL);
if (NULL == mclk_table)
return -1;
memset(mclk_table, 0x00, table_size);
mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries;
for (i = 0; i < mclk_dep_table->ucNumEntries; i++) {
mclk_table->entries[i].vddInd =
mclk_dep_table->entries[i].ucVddcInd;
mclk_table->entries[i].vdd_offset =
mclk_dep_table->entries[i].usVddgfxOffset;
mclk_table->entries[i].vddci =
mclk_dep_table->entries[i].usVddci;
mclk_table->entries[i].mvdd =
mclk_dep_table->entries[i].usMvdd;
mclk_table->entries[i].clk =
mclk_dep_table->entries[i].ulMclk;
}
*pp_tonga_mclk_dep_table = mclk_table;
return 0;
}
static int get_sclk_voltage_dependency_table(
struct pp_hwmgr *hwmgr,
phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_sclk_dep_table,
const ATOM_Tonga_SCLK_Dependency_Table * sclk_dep_table
)
{
uint32_t table_size, i;
phm_ppt_v1_clock_voltage_dependency_table *sclk_table;
PP_ASSERT_WITH_CODE((0 != sclk_dep_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record)
* sclk_dep_table->ucNumEntries;
sclk_table = (phm_ppt_v1_clock_voltage_dependency_table *)
kzalloc(table_size, GFP_KERNEL);
if (NULL == sclk_table)
return -1;
memset(sclk_table, 0x00, table_size);
sclk_table->count = (uint32_t)sclk_dep_table->ucNumEntries;
for (i = 0; i < sclk_dep_table->ucNumEntries; i++) {
sclk_table->entries[i].vddInd =
sclk_dep_table->entries[i].ucVddInd;
sclk_table->entries[i].vdd_offset =
sclk_dep_table->entries[i].usVddcOffset;
sclk_table->entries[i].clk =
sclk_dep_table->entries[i].ulSclk;
sclk_table->entries[i].cks_enable =
(((sclk_dep_table->entries[i].ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0;
sclk_table->entries[i].cks_voffset =
(sclk_dep_table->entries[i].ucCKSVOffsetandDisable & 0x7F);
}
*pp_tonga_sclk_dep_table = sclk_table;
return 0;
}
static int get_pcie_table(
struct pp_hwmgr *hwmgr,
phm_ppt_v1_pcie_table **pp_tonga_pcie_table,
const ATOM_Tonga_PCIE_Table * atom_pcie_table
)
{
uint32_t table_size, i, pcie_count;
phm_ppt_v1_pcie_table *pcie_table;
struct phm_ppt_v1_information *pp_table_information =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
PP_ASSERT_WITH_CODE((0 != atom_pcie_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
table_size = sizeof(uint32_t) +
sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries;
pcie_table = (phm_ppt_v1_pcie_table *)kzalloc(table_size, GFP_KERNEL);
if (NULL == pcie_table)
return -1;
memset(pcie_table, 0x00, table_size);
/*
* Make sure the number of pcie entries are less than or equal to sclk dpm levels.
* Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1.
*/
pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1;
if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count)
pcie_count = (uint32_t)atom_pcie_table->ucNumEntries;
else
printk(KERN_ERR "[ powerplay ] Number of Pcie Entries exceed the number of SCLK Dpm Levels! \
Disregarding the excess entries... \n");
pcie_table->count = pcie_count;
for (i = 0; i < pcie_count; i++) {
pcie_table->entries[i].gen_speed =
atom_pcie_table->entries[i].ucPCIEGenSpeed;
pcie_table->entries[i].lane_width =
atom_pcie_table->entries[i].usPCIELaneWidth;
}
*pp_tonga_pcie_table = pcie_table;
return 0;
}
static int get_cac_tdp_table(
struct pp_hwmgr *hwmgr,
struct phm_cac_tdp_table **cac_tdp_table,
const PPTable_Generic_SubTable_Header * table
)
{
uint32_t table_size;
struct phm_cac_tdp_table *tdp_table;
table_size = sizeof(uint32_t) + sizeof(struct phm_cac_tdp_table);
tdp_table = kzalloc(table_size, GFP_KERNEL);
if (NULL == tdp_table)
return -1;
memset(tdp_table, 0x00, table_size);
hwmgr->dyn_state.cac_dtp_table = kzalloc(table_size, GFP_KERNEL);
if (NULL == hwmgr->dyn_state.cac_dtp_table)
return -1;
memset(hwmgr->dyn_state.cac_dtp_table, 0x00, table_size);
if (table->ucRevId < 3) {
const ATOM_Tonga_PowerTune_Table *tonga_table =
(ATOM_Tonga_PowerTune_Table *)table;
tdp_table->usTDP = tonga_table->usTDP;
tdp_table->usConfigurableTDP =
tonga_table->usConfigurableTDP;
tdp_table->usTDC = tonga_table->usTDC;
tdp_table->usBatteryPowerLimit =
tonga_table->usBatteryPowerLimit;
tdp_table->usSmallPowerLimit =
tonga_table->usSmallPowerLimit;
tdp_table->usLowCACLeakage =
tonga_table->usLowCACLeakage;
tdp_table->usHighCACLeakage =
tonga_table->usHighCACLeakage;
tdp_table->usMaximumPowerDeliveryLimit =
tonga_table->usMaximumPowerDeliveryLimit;
tdp_table->usDefaultTargetOperatingTemp =
tonga_table->usTjMax;
tdp_table->usTargetOperatingTemp =
tonga_table->usTjMax; /*Set the initial temp to the same as default */
tdp_table->usPowerTuneDataSetID =
tonga_table->usPowerTuneDataSetID;
tdp_table->usSoftwareShutdownTemp =
tonga_table->usSoftwareShutdownTemp;
tdp_table->usClockStretchAmount =
tonga_table->usClockStretchAmount;
} else { /* Fiji and newer */
const ATOM_Fiji_PowerTune_Table *fijitable =
(ATOM_Fiji_PowerTune_Table *)table;
tdp_table->usTDP = fijitable->usTDP;
tdp_table->usConfigurableTDP = fijitable->usConfigurableTDP;
tdp_table->usTDC = fijitable->usTDC;
tdp_table->usBatteryPowerLimit = fijitable->usBatteryPowerLimit;
tdp_table->usSmallPowerLimit = fijitable->usSmallPowerLimit;
tdp_table->usLowCACLeakage = fijitable->usLowCACLeakage;
tdp_table->usHighCACLeakage = fijitable->usHighCACLeakage;
tdp_table->usMaximumPowerDeliveryLimit =
fijitable->usMaximumPowerDeliveryLimit;
tdp_table->usDefaultTargetOperatingTemp =
fijitable->usTjMax;
tdp_table->usTargetOperatingTemp =
fijitable->usTjMax; /*Set the initial temp to the same as default */
tdp_table->usPowerTuneDataSetID =
fijitable->usPowerTuneDataSetID;
tdp_table->usSoftwareShutdownTemp =
fijitable->usSoftwareShutdownTemp;
tdp_table->usClockStretchAmount =
fijitable->usClockStretchAmount;
tdp_table->usTemperatureLimitHotspot =
fijitable->usTemperatureLimitHotspot;
tdp_table->usTemperatureLimitLiquid1 =
fijitable->usTemperatureLimitLiquid1;
tdp_table->usTemperatureLimitLiquid2 =
fijitable->usTemperatureLimitLiquid2;
tdp_table->usTemperatureLimitVrVddc =
fijitable->usTemperatureLimitVrVddc;
tdp_table->usTemperatureLimitVrMvdd =
fijitable->usTemperatureLimitVrMvdd;
tdp_table->usTemperatureLimitPlx =
fijitable->usTemperatureLimitPlx;
tdp_table->ucLiquid1_I2C_address =
fijitable->ucLiquid1_I2C_address;
tdp_table->ucLiquid2_I2C_address =
fijitable->ucLiquid2_I2C_address;
tdp_table->ucLiquid_I2C_Line =
fijitable->ucLiquid_I2C_Line;
tdp_table->ucVr_I2C_address = fijitable->ucVr_I2C_address;
tdp_table->ucVr_I2C_Line = fijitable->ucVr_I2C_Line;
tdp_table->ucPlx_I2C_address = fijitable->ucPlx_I2C_address;
tdp_table->ucPlx_I2C_Line = fijitable->ucPlx_I2C_Line;
}
*cac_tdp_table = tdp_table;
return 0;
}
static int get_mm_clock_voltage_table(
struct pp_hwmgr *hwmgr,
phm_ppt_v1_mm_clock_voltage_dependency_table **tonga_mm_table,
const ATOM_Tonga_MM_Dependency_Table * mm_dependency_table
)
{
uint32_t table_size, i;
const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record;
phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table;
PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
table_size = sizeof(uint32_t) +
sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record)
* mm_dependency_table->ucNumEntries;
mm_table = (phm_ppt_v1_mm_clock_voltage_dependency_table *)
kzalloc(table_size, GFP_KERNEL);
if (NULL == mm_table)
return -1;
memset(mm_table, 0x00, table_size);
mm_table->count = mm_dependency_table->ucNumEntries;
for (i = 0; i < mm_dependency_table->ucNumEntries; i++) {
mm_dependency_record = &mm_dependency_table->entries[i];
mm_table->entries[i].vddcInd = mm_dependency_record->ucVddcInd;
mm_table->entries[i].vddgfx_offset = mm_dependency_record->usVddgfxOffset;
mm_table->entries[i].aclk = mm_dependency_record->ulAClk;
mm_table->entries[i].samclock = mm_dependency_record->ulSAMUClk;
mm_table->entries[i].eclk = mm_dependency_record->ulEClk;
mm_table->entries[i].vclk = mm_dependency_record->ulVClk;
mm_table->entries[i].dclk = mm_dependency_record->ulDClk;
}
*tonga_mm_table = mm_table;
return 0;
}
/**
* Private Function used during initialization.
* Initialize clock voltage dependency
* @param hwmgr Pointer to the hardware manager.
* @param powerplay_table Pointer to the PowerPlay Table.
*/
static int init_clock_voltage_dependency(
struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
)
{
int result = 0;
struct phm_ppt_v1_information *pp_table_information =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table =
(const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usMMDependencyTableOffset));
const PPTable_Generic_SubTable_Header *pPowerTuneTable =
(const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usPowerTuneTableOffset));
const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
(const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table =
(const ATOM_Tonga_SCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
const ATOM_Tonga_Hard_Limit_Table *pHardLimits =
(const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usHardLimitTableOffset));
const ATOM_Tonga_PCIE_Table *pcie_table =
(const ATOM_Tonga_PCIE_Table *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usPCIETableOffset));
pp_table_information->vdd_dep_on_sclk = NULL;
pp_table_information->vdd_dep_on_mclk = NULL;
pp_table_information->mm_dep_table = NULL;
pp_table_information->pcie_table = NULL;
if (powerplay_table->usMMDependencyTableOffset != 0)
result = get_mm_clock_voltage_table(hwmgr,
&pp_table_information->mm_dep_table, mm_dependency_table);
if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0)
result = get_cac_tdp_table(hwmgr,
&pp_table_information->cac_dtp_table, pPowerTuneTable);
if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0)
result = get_sclk_voltage_dependency_table(hwmgr,
&pp_table_information->vdd_dep_on_sclk, sclk_dep_table);
if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0)
result = get_mclk_voltage_dependency_table(hwmgr,
&pp_table_information->vdd_dep_on_mclk, mclk_dep_table);
if (result == 0 && powerplay_table->usPCIETableOffset != 0)
result = get_pcie_table(hwmgr,
&pp_table_information->pcie_table, pcie_table);
if (result == 0 && powerplay_table->usHardLimitTableOffset != 0)
result = get_hard_limits(hwmgr,
&pp_table_information->max_clock_voltage_on_dc, pHardLimits);
hwmgr->dyn_state.max_clock_voltage_on_dc.sclk =
pp_table_information->max_clock_voltage_on_dc.sclk;
hwmgr->dyn_state.max_clock_voltage_on_dc.mclk =
pp_table_information->max_clock_voltage_on_dc.mclk;
hwmgr->dyn_state.max_clock_voltage_on_dc.vddc =
pp_table_information->max_clock_voltage_on_dc.vddc;
hwmgr->dyn_state.max_clock_voltage_on_dc.vddci =
pp_table_information->max_clock_voltage_on_dc.vddci;
if (result == 0 && (NULL != pp_table_information->vdd_dep_on_mclk)
&& (0 != pp_table_information->vdd_dep_on_mclk->count))
result = get_valid_clk(hwmgr, &pp_table_information->valid_mclk_values,
pp_table_information->vdd_dep_on_mclk);
if (result == 0 && (NULL != pp_table_information->vdd_dep_on_sclk)
&& (0 != pp_table_information->vdd_dep_on_sclk->count))
result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values,
pp_table_information->vdd_dep_on_sclk);
return result;
}
/** Retrieves the (signed) Overdrive limits from VBIOS.
* The max engine clock, memory clock and max temperature come from the firmware info table.
*
* The information is placed into the platform descriptor.
*
* @param hwmgr source of the VBIOS table and owner of the platform descriptor to be updated.
* @param powerplay_table the address of the PowerPlay table.
*
* @return 1 as long as the firmware info table was present and of a supported version.
*/
static int init_over_drive_limits(
struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table)
{
hwmgr->platform_descriptor.overdriveLimit.engineClock =
le16_to_cpu(powerplay_table->ulMaxODEngineClock);
hwmgr->platform_descriptor.overdriveLimit.memoryClock =
le16_to_cpu(powerplay_table->ulMaxODMemoryClock);
hwmgr->platform_descriptor.minOverdriveVDDC = 0;
hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
hwmgr->platform_descriptor.overdriveVDDCStep = 0;
if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 \
&& hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) {
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_ACOverdriveSupport);
}
return 0;
}
/**
* Private Function used during initialization.
* Inspect the PowerPlay table for obvious signs of corruption.
* @param hwmgr Pointer to the hardware manager.
* @param powerplay_table Pointer to the PowerPlay Table.
* @exception This implementation always returns 1.
*/
static int init_thermal_controller(
struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
)
{
const PPTable_Generic_SubTable_Header *fan_table;
ATOM_Tonga_Thermal_Controller *thermal_controller;
thermal_controller = (ATOM_Tonga_Thermal_Controller *)
(((unsigned long)powerplay_table) +
le16_to_cpu(powerplay_table->usThermalControllerOffset));
PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset),
"Thermal controller table not set!", return -1);
hwmgr->thermal_controller.ucType = thermal_controller->ucType;
hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine;
hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress;
hwmgr->thermal_controller.fanInfo.bNoFan =
(0 != (thermal_controller->ucFanParameters & ATOM_TONGA_PP_FANPARAMETERS_NOFAN));
hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
thermal_controller->ucFanParameters &
ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
hwmgr->thermal_controller.fanInfo.ulMinRPM
= thermal_controller->ucFanMinRPM * 100UL;
hwmgr->thermal_controller.fanInfo.ulMaxRPM
= thermal_controller->ucFanMaxRPM * 100UL;
set_hw_cap(
hwmgr,
ATOM_TONGA_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
PHM_PlatformCaps_ThermalController
);
if (0 == powerplay_table->usFanTableOffset)
return -1;
fan_table = (const PPTable_Generic_SubTable_Header *)
(((unsigned long)powerplay_table) +
le16_to_cpu(powerplay_table->usFanTableOffset));
PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset),
"Fan table not set!", return -1);
PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId),
"Unsupported fan table format!", return -1);
hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay
= 100000;
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
if (fan_table->ucRevId < 8) {
const ATOM_Tonga_Fan_Table *tonga_fan_table =
(ATOM_Tonga_Fan_Table *)fan_table;
hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
= tonga_fan_table->ucTHyst;
hwmgr->thermal_controller.advanceFanControlParameters.usTMin
= tonga_fan_table->usTMin;
hwmgr->thermal_controller.advanceFanControlParameters.usTMed
= tonga_fan_table->usTMed;
hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
= tonga_fan_table->usTHigh;
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
= tonga_fan_table->usPWMMin;
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
= tonga_fan_table->usPWMMed;
hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
= tonga_fan_table->usPWMHigh;
hwmgr->thermal_controller.advanceFanControlParameters.usTMax
= 10900; /* hard coded */
hwmgr->thermal_controller.advanceFanControlParameters.usTMax
= tonga_fan_table->usTMax;
hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
= tonga_fan_table->ucFanControlMode;
hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
= tonga_fan_table->usFanPWMMax;
hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
= 4836;
hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
= tonga_fan_table->usFanOutputSensitivity;
hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
= tonga_fan_table->usFanRPMMax;
hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
= (tonga_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places. SMC wants MHz. */
hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
= tonga_fan_table->ucTargetTemperature;
hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
= tonga_fan_table->ucMinimumPWMLimit;
} else {
const ATOM_Fiji_Fan_Table *fiji_fan_table =
(ATOM_Fiji_Fan_Table *)fan_table;
hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst
= fiji_fan_table->ucTHyst;
hwmgr->thermal_controller.advanceFanControlParameters.usTMin
= fiji_fan_table->usTMin;
hwmgr->thermal_controller.advanceFanControlParameters.usTMed
= fiji_fan_table->usTMed;
hwmgr->thermal_controller.advanceFanControlParameters.usTHigh
= fiji_fan_table->usTHigh;
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin
= fiji_fan_table->usPWMMin;
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed
= fiji_fan_table->usPWMMed;
hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh
= fiji_fan_table->usPWMHigh;
hwmgr->thermal_controller.advanceFanControlParameters.usTMax
= fiji_fan_table->usTMax;
hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode
= fiji_fan_table->ucFanControlMode;
hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM
= fiji_fan_table->usFanPWMMax;
hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity
= 4836;
hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity
= fiji_fan_table->usFanOutputSensitivity;
hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM
= fiji_fan_table->usFanRPMMax;
hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit
= (fiji_fan_table->ulMinFanSCLKAcousticLimit / 100); /* PPTable stores it in 10Khz unit for 2 decimal places. SMC wants MHz. */
hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature
= fiji_fan_table->ucTargetTemperature;
hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit
= fiji_fan_table->ucMinimumPWMLimit;
hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge
= fiji_fan_table->usFanGainEdge;
hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot
= fiji_fan_table->usFanGainHotspot;
hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid
= fiji_fan_table->usFanGainLiquid;
hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc
= fiji_fan_table->usFanGainVrVddc;
hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd
= fiji_fan_table->usFanGainVrMvdd;
hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx
= fiji_fan_table->usFanGainPlx;
hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm
= fiji_fan_table->usFanGainHbm;
}
return 0;
}
/**
* Private Function used during initialization.
* Inspect the PowerPlay table for obvious signs of corruption.
* @param hwmgr Pointer to the hardware manager.
* @param powerplay_table Pointer to the PowerPlay Table.
* @exception 2 if the powerplay table is incorrect.
*/
static int check_powerplay_tables(
struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
)
{
const ATOM_Tonga_State_Array *state_arrays;
state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) +
le16_to_cpu(powerplay_table->usStateArrayOffset));
PP_ASSERT_WITH_CODE((ATOM_Tonga_TABLE_REVISION_TONGA <=
powerplay_table->sHeader.ucTableFormatRevision),
"Unsupported PPTable format!", return -1);
PP_ASSERT_WITH_CODE((0 != powerplay_table->usStateArrayOffset),
"State table is not set!", return -1);
PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize),
"Invalid PowerPlay Table!", return -1);
PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
return 0;
}
int tonga_pp_tables_initialize(struct pp_hwmgr *hwmgr)
{
int result = 0;
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table;
hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v1_information), GFP_KERNEL);
if (NULL == hwmgr->pptable)
return -1;
memset(hwmgr->pptable, 0x00, sizeof(struct phm_ppt_v1_information));
powerplay_table = get_powerplay_table(hwmgr);
PP_ASSERT_WITH_CODE((NULL != powerplay_table),
"Missing PowerPlay Table!", return -1);
result = check_powerplay_tables(hwmgr, powerplay_table);
if (0 == result)
result = set_platform_caps(hwmgr,
le32_to_cpu(powerplay_table->ulPlatformCaps));
if (0 == result)
result = init_thermal_controller(hwmgr, powerplay_table);
if (0 == result)
result = init_over_drive_limits(hwmgr, powerplay_table);
if (0 == result)
result = init_clock_voltage_dependency(hwmgr, powerplay_table);
if (0 == result)
result = init_dpm_2_parameters(hwmgr, powerplay_table);
return result;
}
int tonga_pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
{
int result = 0;
struct phm_ppt_v1_information *pp_table_information =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
if (NULL != hwmgr->soft_pp_table) {
kfree(hwmgr->soft_pp_table);
hwmgr->soft_pp_table = NULL;
}
if (NULL != pp_table_information->vdd_dep_on_sclk)
pp_table_information->vdd_dep_on_sclk = NULL;
if (NULL != pp_table_information->vdd_dep_on_mclk)
pp_table_information->vdd_dep_on_mclk = NULL;
if (NULL != pp_table_information->valid_mclk_values)
pp_table_information->valid_mclk_values = NULL;
if (NULL != pp_table_information->valid_sclk_values)
pp_table_information->valid_sclk_values = NULL;
if (NULL != pp_table_information->vddc_lookup_table)
pp_table_information->vddc_lookup_table = NULL;
if (NULL != pp_table_information->vddgfx_lookup_table)
pp_table_information->vddgfx_lookup_table = NULL;
if (NULL != pp_table_information->mm_dep_table)
pp_table_information->mm_dep_table = NULL;
if (NULL != pp_table_information->cac_dtp_table)
pp_table_information->cac_dtp_table = NULL;
if (NULL != hwmgr->dyn_state.cac_dtp_table)
hwmgr->dyn_state.cac_dtp_table = NULL;
if (NULL != pp_table_information->ppm_parameter_table)
pp_table_information->ppm_parameter_table = NULL;
if (NULL != pp_table_information->pcie_table)
pp_table_information->pcie_table = NULL;
if (NULL != hwmgr->pptable) {
kfree(hwmgr->pptable);
hwmgr->pptable = NULL;
}
return result;
}
const struct pp_table_func tonga_pptable_funcs = {
.pptable_init = tonga_pp_tables_initialize,
.pptable_fini = tonga_pp_tables_uninitialize,
};
int tonga_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr)
{
const ATOM_Tonga_State_Array * state_arrays;
const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
PP_ASSERT_WITH_CODE((NULL != pp_table),
"Missing PowerPlay Table!", return -1);
PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >=
ATOM_Tonga_TABLE_REVISION_TONGA),
"Incorrect PowerPlay table revision!", return -1);
state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
le16_to_cpu(pp_table->usStateArrayOffset));
return (uint32_t)(state_arrays->ucNumEntries);
}
/**
* Private function to convert flags stored in the BIOS to software flags in PowerPlay.
*/
static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr,
uint16_t classification, uint16_t classification2)
{
uint32_t result = 0;
if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
result |= PP_StateClassificationFlag_Boot;
if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
result |= PP_StateClassificationFlag_Thermal;
if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
result |= PP_StateClassificationFlag_LimitedPowerSource;
if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
result |= PP_StateClassificationFlag_Rest;
if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
result |= PP_StateClassificationFlag_Forced;
if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
result |= PP_StateClassificationFlag_ACPI;
if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
result |= PP_StateClassificationFlag_LimitedPowerSource_2;
return result;
}
/**
* Create a Power State out of an entry in the PowerPlay table.
* This function is called by the hardware back-end.
* @param hwmgr Pointer to the hardware manager.
* @param entry_index The index of the entry to be extracted from the table.
* @param power_state The address of the PowerState instance being created.
* @return -1 if the entry cannot be retrieved.
*/
int tonga_get_powerplay_table_entry(struct pp_hwmgr *hwmgr,
uint32_t entry_index, struct pp_power_state *power_state,
int (*call_back_func)(struct pp_hwmgr *, void *,
struct pp_power_state *, void *, uint32_t))
{
int result = 0;
const ATOM_Tonga_State_Array * state_arrays;
const ATOM_Tonga_State *state_entry;
const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
PP_ASSERT_WITH_CODE((NULL != pp_table), "Missing PowerPlay Table!", return -1;);
power_state->classification.bios_index = entry_index;
if (pp_table->sHeader.ucTableFormatRevision >=
ATOM_Tonga_TABLE_REVISION_TONGA) {
state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
le16_to_cpu(pp_table->usStateArrayOffset));
PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset),
"Invalid PowerPlay Table State Array Offset.", return -1);
PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
"Invalid PowerPlay Table State Array.", return -1);
PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries),
"Invalid PowerPlay Table State Array Entry.", return -1);
state_entry = &(state_arrays->states[entry_index]);
result = call_back_func(hwmgr, (void *)state_entry, power_state,
(void *)pp_table,
make_classification_flags(hwmgr,
le16_to_cpu(state_entry->usClassification),
le16_to_cpu(state_entry->usClassification2)));
}
if (!result && (power_state->classification.flags &
PP_StateClassificationFlag_Boot))
result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware));
return result;
}
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef TONGA_PROCESSPPTABLES_H
#define TONGA_PROCESSPPTABLES_H
#include "hwmgr.h"
extern const struct pp_table_func tonga_pptable_funcs;
extern int tonga_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr);
extern int tonga_get_powerplay_table_entry(struct pp_hwmgr *hwmgr, uint32_t entry_index,
struct pp_power_state *power_state, int (*call_back_func)(struct pp_hwmgr *, void *,
struct pp_power_state *, void *, uint32_t));
#endif
......@@ -28,6 +28,7 @@
#include "pp_instance.h"
#include "hardwaremanager.h"
#include "pp_power_source.h"
#include "hwmgr_ppt.h"
struct pp_instance;
struct pp_hwmgr;
......@@ -400,7 +401,24 @@ struct phm_clock_and_voltage_limits {
uint16_t vddgfx;
};
/* Structure to hold PPTable information */
struct phm_ppt_v1_information {
struct phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_on_sclk;
struct phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_on_mclk;
struct phm_clock_array *valid_sclk_values;
struct phm_clock_array *valid_mclk_values;
struct phm_clock_and_voltage_limits max_clock_voltage_on_dc;
struct phm_clock_and_voltage_limits max_clock_voltage_on_ac;
struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl;
struct phm_ppm_table *ppm_parameter_table;
struct phm_cac_tdp_table *cac_dtp_table;
struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_dep_table;
struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table;
struct phm_ppt_v1_voltage_lookup_table *vddgfx_lookup_table;
struct phm_ppt_v1_pcie_table *pcie_table;
uint16_t us_ulv_voltage_offset;
};
struct phm_dynamic_state_info {
struct phm_clock_voltage_dependency_table *vddc_dependency_on_sclk;
......@@ -434,6 +452,70 @@ struct phm_dynamic_state_info {
struct phm_vq_budgeting_table *vq_budgeting_table;
};
struct pp_fan_info {
bool bNoFan;
uint8_t ucTachometerPulsesPerRevolution;
uint32_t ulMinRPM;
uint32_t ulMaxRPM;
};
struct pp_advance_fan_control_parameters {
uint16_t usTMin; /* The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. */
uint16_t usTMed; /* The middle temperature where we change slopes. */
uint16_t usTHigh; /* The high temperature for setting the second slope. */
uint16_t usPWMMin; /* The minimum PWM value in percent (0.01% increments). */
uint16_t usPWMMed; /* The PWM value (in percent) at TMed. */
uint16_t usPWMHigh; /* The PWM value at THigh. */
uint8_t ucTHyst; /* Temperature hysteresis. Integer. */
uint32_t ulCycleDelay; /* The time between two invocations of the fan control routine in microseconds. */
uint16_t usTMax; /* The max temperature */
uint8_t ucFanControlMode;
uint16_t usFanPWMMinLimit;
uint16_t usFanPWMMaxLimit;
uint16_t usFanPWMStep;
uint16_t usDefaultMaxFanPWM;
uint16_t usFanOutputSensitivity;
uint16_t usDefaultFanOutputSensitivity;
uint16_t usMaxFanPWM; /* The max Fan PWM value for Fuzzy Fan Control feature */
uint16_t usFanRPMMinLimit; /* Minimum limit range in percentage, need to calculate based on minRPM/MaxRpm */
uint16_t usFanRPMMaxLimit; /* Maximum limit range in percentage, usually set to 100% by default */
uint16_t usFanRPMStep; /* Step increments/decerements, in percent */
uint16_t usDefaultMaxFanRPM; /* The max Fan RPM value for Fuzzy Fan Control feature, default from PPTable */
uint16_t usMaxFanRPM; /* The max Fan RPM value for Fuzzy Fan Control feature, user defined */
uint16_t usFanCurrentLow; /* Low current */
uint16_t usFanCurrentHigh; /* High current */
uint16_t usFanRPMLow; /* Low RPM */
uint16_t usFanRPMHigh; /* High RPM */
uint32_t ulMinFanSCLKAcousticLimit; /* Minimum Fan Controller SCLK Frequency Acoustic Limit. */
uint8_t ucTargetTemperature; /* Advanced fan controller target temperature. */
uint8_t ucMinimumPWMLimit; /* The minimum PWM that the advanced fan controller can set. This should be set to the highest PWM that will run the fan at its lowest RPM. */
uint16_t usFanGainEdge; /* The following is added for Fiji */
uint16_t usFanGainHotspot;
uint16_t usFanGainLiquid;
uint16_t usFanGainVrVddc;
uint16_t usFanGainVrMvdd;
uint16_t usFanGainPlx;
uint16_t usFanGainHbm;
};
struct pp_thermal_controller_info {
uint8_t ucType;
uint8_t ucI2cLine;
uint8_t ucI2cAddress;
struct pp_fan_info fanInfo;
struct pp_advance_fan_control_parameters advanceFanControlParameters;
};
struct phm_microcode_version_info {
uint32_t SMC;
uint32_t DMCU;
uint32_t MC;
uint32_t NB;
};
/**
* The main hardware manager structure.
*/
struct pp_hwmgr {
uint32_t chip_family;
uint32_t chip_id;
......@@ -466,6 +548,8 @@ struct pp_hwmgr {
struct pp_power_state *ps;
enum pp_power_source power_source;
uint32_t num_ps;
struct pp_thermal_controller_info thermal_controller;
struct phm_microcode_version_info microcode_version_info;
uint32_t ps_size;
struct pp_power_state *current_ps;
struct pp_power_state *request_ps;
......@@ -487,7 +571,13 @@ extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
extern int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
uint32_t index, uint32_t value, uint32_t mask);
extern uint32_t phm_read_indirect_register(struct pp_hwmgr *hwmgr,
uint32_t indirect_port, uint32_t index);
extern void phm_write_indirect_register(struct pp_hwmgr *hwmgr,
uint32_t indirect_port,
uint32_t index,
uint32_t value);
extern void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
uint32_t indirect_port,
......
......@@ -31,7 +31,7 @@
#define PP_ASSERT_WITH_CODE(cond, msg, code) \
do { \
if (!(cond)) { \
printk(msg); \
printk("%s\n", msg); \
code; \
} \
} while (0)
......
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef SMU_UCODE_XFER_VI_H
#define SMU_UCODE_XFER_VI_H
#define SMU_DRAMData_TOC_VERSION 1
#define MAX_IH_REGISTER_COUNT 65535
#define SMU_DIGEST_SIZE_BYTES 20
#define SMU_FB_SIZE_BYTES 1048576
#define SMU_MAX_ENTRIES 12
#define UCODE_ID_SMU 0
#define UCODE_ID_SDMA0 1
#define UCODE_ID_SDMA1 2
#define UCODE_ID_CP_CE 3
#define UCODE_ID_CP_PFP 4
#define UCODE_ID_CP_ME 5
#define UCODE_ID_CP_MEC 6
#define UCODE_ID_CP_MEC_JT1 7
#define UCODE_ID_CP_MEC_JT2 8
#define UCODE_ID_GMCON_RENG 9
#define UCODE_ID_RLC_G 10
#define UCODE_ID_IH_REG_RESTORE 11
#define UCODE_ID_VBIOS 12
#define UCODE_ID_MISC_METADATA 13
#define UCODE_ID_RLC_SCRATCH 32
#define UCODE_ID_RLC_SRM_ARAM 33
#define UCODE_ID_RLC_SRM_DRAM 34
#define UCODE_ID_MEC_STORAGE 35
#define UCODE_ID_VBIOS_PARAMETERS 36
#define UCODE_META_DATA 0xFF
#define UCODE_ID_SMU_MASK 0x00000001
#define UCODE_ID_SDMA0_MASK 0x00000002
#define UCODE_ID_SDMA1_MASK 0x00000004
#define UCODE_ID_CP_CE_MASK 0x00000008
#define UCODE_ID_CP_PFP_MASK 0x00000010
#define UCODE_ID_CP_ME_MASK 0x00000020
#define UCODE_ID_CP_MEC_MASK 0x00000040
#define UCODE_ID_CP_MEC_JT1_MASK 0x00000080
#define UCODE_ID_CP_MEC_JT2_MASK 0x00000100
#define UCODE_ID_GMCON_RENG_MASK 0x00000200
#define UCODE_ID_RLC_G_MASK 0x00000400
#define UCODE_ID_IH_REG_RESTORE_MASK 0x00000800
#define UCODE_ID_VBIOS_MASK 0x00001000
#define UCODE_FLAG_UNHALT_MASK 0x1
struct SMU_Entry {
#ifndef __BIG_ENDIAN
uint16_t id;
uint16_t version;
uint32_t image_addr_high;
uint32_t image_addr_low;
uint32_t meta_data_addr_high;
uint32_t meta_data_addr_low;
uint32_t data_size_byte;
uint16_t flags;
uint16_t num_register_entries;
#else
uint16_t version;
uint16_t id;
uint32_t image_addr_high;
uint32_t image_addr_low;
uint32_t meta_data_addr_high;
uint32_t meta_data_addr_low;
uint32_t data_size_byte;
uint16_t num_register_entries;
uint16_t flags;
#endif
};
struct SMU_DRAMData_TOC {
uint32_t structure_version;
uint32_t num_entries;
struct SMU_Entry entry[SMU_MAX_ENTRIES];
};
#endif
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