1e098bc96SEvan Quan /*
2e098bc96SEvan Quan * Copyright 2015 Advanced Micro Devices, Inc.
3e098bc96SEvan Quan *
4e098bc96SEvan Quan * Permission is hereby granted, free of charge, to any person obtaining a
5e098bc96SEvan Quan * copy of this software and associated documentation files (the "Software"),
6e098bc96SEvan Quan * to deal in the Software without restriction, including without limitation
7e098bc96SEvan Quan * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e098bc96SEvan Quan * and/or sell copies of the Software, and to permit persons to whom the
9e098bc96SEvan Quan * Software is furnished to do so, subject to the following conditions:
10e098bc96SEvan Quan *
11e098bc96SEvan Quan * The above copyright notice and this permission notice shall be included in
12e098bc96SEvan Quan * all copies or substantial portions of the Software.
13e098bc96SEvan Quan *
14e098bc96SEvan Quan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15e098bc96SEvan Quan * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16e098bc96SEvan Quan * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17e098bc96SEvan Quan * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18e098bc96SEvan Quan * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19e098bc96SEvan Quan * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20e098bc96SEvan Quan * OTHER DEALINGS IN THE SOFTWARE.
21e098bc96SEvan Quan *
22e098bc96SEvan Quan */
23e098bc96SEvan Quan #include "pp_debug.h"
24e098bc96SEvan Quan #include <linux/module.h>
25e098bc96SEvan Quan #include <linux/slab.h>
26e098bc96SEvan Quan #include <linux/delay.h>
27e098bc96SEvan Quan #include "atom.h"
28e098bc96SEvan Quan #include "ppatomctrl.h"
29e098bc96SEvan Quan #include "atombios.h"
30e098bc96SEvan Quan #include "cgs_common.h"
31e098bc96SEvan Quan #include "ppevvmath.h"
32e098bc96SEvan Quan
33e098bc96SEvan Quan #define MEM_ID_MASK 0xff000000
34e098bc96SEvan Quan #define MEM_ID_SHIFT 24
35e098bc96SEvan Quan #define CLOCK_RANGE_MASK 0x00ffffff
36e098bc96SEvan Quan #define CLOCK_RANGE_SHIFT 0
37e098bc96SEvan Quan #define LOW_NIBBLE_MASK 0xf
38e098bc96SEvan Quan #define DATA_EQU_PREV 0
39e098bc96SEvan Quan #define DATA_FROM_TABLE 4
40e098bc96SEvan Quan
41e098bc96SEvan Quan union voltage_object_info {
42e098bc96SEvan Quan struct _ATOM_VOLTAGE_OBJECT_INFO v1;
43e098bc96SEvan Quan struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
44e098bc96SEvan Quan struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;
45e098bc96SEvan Quan };
46e098bc96SEvan Quan
atomctrl_retrieve_ac_timing(uint8_t index,ATOM_INIT_REG_BLOCK * reg_block,pp_atomctrl_mc_reg_table * table)47e098bc96SEvan Quan static int atomctrl_retrieve_ac_timing(
48e098bc96SEvan Quan uint8_t index,
49e098bc96SEvan Quan ATOM_INIT_REG_BLOCK *reg_block,
50e098bc96SEvan Quan pp_atomctrl_mc_reg_table *table)
51e098bc96SEvan Quan {
52e098bc96SEvan Quan uint32_t i, j;
53e098bc96SEvan Quan uint8_t tmem_id;
54e098bc96SEvan Quan ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
55e098bc96SEvan Quan ((uint8_t *)reg_block + (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block->usRegIndexTblSize));
56e098bc96SEvan Quan
57e098bc96SEvan Quan uint8_t num_ranges = 0;
58e098bc96SEvan Quan
59e098bc96SEvan Quan while (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK &&
60e098bc96SEvan Quan num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES) {
61e098bc96SEvan Quan tmem_id = (uint8_t)((*(uint32_t *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
62e098bc96SEvan Quan
63e098bc96SEvan Quan if (index == tmem_id) {
64e098bc96SEvan Quan table->mc_reg_table_entry[num_ranges].mclk_max =
65e098bc96SEvan Quan (uint32_t)((*(uint32_t *)reg_data & CLOCK_RANGE_MASK) >>
66e098bc96SEvan Quan CLOCK_RANGE_SHIFT);
67e098bc96SEvan Quan
68e098bc96SEvan Quan for (i = 0, j = 1; i < table->last; i++) {
69e098bc96SEvan Quan if ((table->mc_reg_address[i].uc_pre_reg_data &
70e098bc96SEvan Quan LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
71e098bc96SEvan Quan table->mc_reg_table_entry[num_ranges].mc_data[i] =
72e098bc96SEvan Quan (uint32_t)*((uint32_t *)reg_data + j);
73e098bc96SEvan Quan j++;
74e098bc96SEvan Quan } else if ((table->mc_reg_address[i].uc_pre_reg_data &
75e098bc96SEvan Quan LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
76f1e261ceSJesse Zhang if (i)
77e098bc96SEvan Quan table->mc_reg_table_entry[num_ranges].mc_data[i] =
78e098bc96SEvan Quan table->mc_reg_table_entry[num_ranges].mc_data[i-1];
79e098bc96SEvan Quan }
80e098bc96SEvan Quan }
81e098bc96SEvan Quan num_ranges++;
82e098bc96SEvan Quan }
83e098bc96SEvan Quan
84e098bc96SEvan Quan reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
85e098bc96SEvan Quan ((uint8_t *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)) ;
86e098bc96SEvan Quan }
87e098bc96SEvan Quan
88e098bc96SEvan Quan PP_ASSERT_WITH_CODE((*(uint32_t *)reg_data == END_OF_REG_DATA_BLOCK),
89e098bc96SEvan Quan "Invalid VramInfo table.", return -1);
90e098bc96SEvan Quan table->num_entries = num_ranges;
91e098bc96SEvan Quan
92e098bc96SEvan Quan return 0;
93e098bc96SEvan Quan }
94e098bc96SEvan Quan
95e098bc96SEvan Quan /**
9658cfaf25SLee Jones * atomctrl_set_mc_reg_address_table - Get memory clock AC timing registers index from VBIOS table
97e098bc96SEvan Quan * VBIOS set end of memory clock AC timing registers by ucPreRegDataLength bit6 = 1
9858cfaf25SLee Jones * @reg_block: the address ATOM_INIT_REG_BLOCK
9958cfaf25SLee Jones * @table: the address of MCRegTable
10058cfaf25SLee Jones * Return: 0
101e098bc96SEvan Quan */
atomctrl_set_mc_reg_address_table(ATOM_INIT_REG_BLOCK * reg_block,pp_atomctrl_mc_reg_table * table)102e098bc96SEvan Quan static int atomctrl_set_mc_reg_address_table(
103e098bc96SEvan Quan ATOM_INIT_REG_BLOCK *reg_block,
104e098bc96SEvan Quan pp_atomctrl_mc_reg_table *table)
105e098bc96SEvan Quan {
106e098bc96SEvan Quan uint8_t i = 0;
107e098bc96SEvan Quan uint8_t num_entries = (uint8_t)((le16_to_cpu(reg_block->usRegIndexTblSize))
108e098bc96SEvan Quan / sizeof(ATOM_INIT_REG_INDEX_FORMAT));
109e098bc96SEvan Quan ATOM_INIT_REG_INDEX_FORMAT *format = ®_block->asRegIndexBuf[0];
110e098bc96SEvan Quan
111e098bc96SEvan Quan num_entries--; /* subtract 1 data end mark entry */
112e098bc96SEvan Quan
113e098bc96SEvan Quan PP_ASSERT_WITH_CODE((num_entries <= VBIOS_MC_REGISTER_ARRAY_SIZE),
114e098bc96SEvan Quan "Invalid VramInfo table.", return -1);
115e098bc96SEvan Quan
116e098bc96SEvan Quan /* ucPreRegDataLength bit6 = 1 is the end of memory clock AC timing registers */
117e098bc96SEvan Quan while ((!(format->ucPreRegDataLength & ACCESS_PLACEHOLDER)) &&
118e098bc96SEvan Quan (i < num_entries)) {
119e098bc96SEvan Quan table->mc_reg_address[i].s1 =
120e098bc96SEvan Quan (uint16_t)(le16_to_cpu(format->usRegIndex));
121e098bc96SEvan Quan table->mc_reg_address[i].uc_pre_reg_data =
122e098bc96SEvan Quan format->ucPreRegDataLength;
123e098bc96SEvan Quan
124e098bc96SEvan Quan i++;
125e098bc96SEvan Quan format = (ATOM_INIT_REG_INDEX_FORMAT *)
126e098bc96SEvan Quan ((uint8_t *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
127e098bc96SEvan Quan }
128e098bc96SEvan Quan
129e098bc96SEvan Quan table->last = i;
130e098bc96SEvan Quan return 0;
131e098bc96SEvan Quan }
132e098bc96SEvan Quan
atomctrl_initialize_mc_reg_table(struct pp_hwmgr * hwmgr,uint8_t module_index,pp_atomctrl_mc_reg_table * table)133e098bc96SEvan Quan int atomctrl_initialize_mc_reg_table(
134e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
135e098bc96SEvan Quan uint8_t module_index,
136e098bc96SEvan Quan pp_atomctrl_mc_reg_table *table)
137e098bc96SEvan Quan {
138e098bc96SEvan Quan ATOM_VRAM_INFO_HEADER_V2_1 *vram_info;
139e098bc96SEvan Quan ATOM_INIT_REG_BLOCK *reg_block;
140e098bc96SEvan Quan int result = 0;
141e098bc96SEvan Quan u8 frev, crev;
142e098bc96SEvan Quan u16 size;
143e098bc96SEvan Quan
144e098bc96SEvan Quan vram_info = (ATOM_VRAM_INFO_HEADER_V2_1 *)
145e098bc96SEvan Quan smu_atom_get_data_table(hwmgr->adev,
146e098bc96SEvan Quan GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev);
147e098bc96SEvan Quan
148e098bc96SEvan Quan if (module_index >= vram_info->ucNumOfVRAMModule) {
149e098bc96SEvan Quan pr_err("Invalid VramInfo table.");
150e098bc96SEvan Quan result = -1;
151e098bc96SEvan Quan } else if (vram_info->sHeader.ucTableFormatRevision < 2) {
152e098bc96SEvan Quan pr_err("Invalid VramInfo table.");
153e098bc96SEvan Quan result = -1;
154e098bc96SEvan Quan }
155e098bc96SEvan Quan
156e098bc96SEvan Quan if (0 == result) {
157e098bc96SEvan Quan reg_block = (ATOM_INIT_REG_BLOCK *)
158e098bc96SEvan Quan ((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
159e098bc96SEvan Quan result = atomctrl_set_mc_reg_address_table(reg_block, table);
160e098bc96SEvan Quan }
161e098bc96SEvan Quan
162e098bc96SEvan Quan if (0 == result) {
163e098bc96SEvan Quan result = atomctrl_retrieve_ac_timing(module_index,
164e098bc96SEvan Quan reg_block, table);
165e098bc96SEvan Quan }
166e098bc96SEvan Quan
167e098bc96SEvan Quan return result;
168e098bc96SEvan Quan }
169e098bc96SEvan Quan
atomctrl_initialize_mc_reg_table_v2_2(struct pp_hwmgr * hwmgr,uint8_t module_index,pp_atomctrl_mc_reg_table * table)1705f92b48cSEvan Quan int atomctrl_initialize_mc_reg_table_v2_2(
1715f92b48cSEvan Quan struct pp_hwmgr *hwmgr,
1725f92b48cSEvan Quan uint8_t module_index,
1735f92b48cSEvan Quan pp_atomctrl_mc_reg_table *table)
1745f92b48cSEvan Quan {
1755f92b48cSEvan Quan ATOM_VRAM_INFO_HEADER_V2_2 *vram_info;
1765f92b48cSEvan Quan ATOM_INIT_REG_BLOCK *reg_block;
1775f92b48cSEvan Quan int result = 0;
1785f92b48cSEvan Quan u8 frev, crev;
1795f92b48cSEvan Quan u16 size;
1805f92b48cSEvan Quan
1815f92b48cSEvan Quan vram_info = (ATOM_VRAM_INFO_HEADER_V2_2 *)
1825f92b48cSEvan Quan smu_atom_get_data_table(hwmgr->adev,
1835f92b48cSEvan Quan GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev);
1845f92b48cSEvan Quan
1855f92b48cSEvan Quan if (module_index >= vram_info->ucNumOfVRAMModule) {
1865f92b48cSEvan Quan pr_err("Invalid VramInfo table.");
1875f92b48cSEvan Quan result = -1;
1885f92b48cSEvan Quan } else if (vram_info->sHeader.ucTableFormatRevision < 2) {
1895f92b48cSEvan Quan pr_err("Invalid VramInfo table.");
1905f92b48cSEvan Quan result = -1;
1915f92b48cSEvan Quan }
1925f92b48cSEvan Quan
1935f92b48cSEvan Quan if (0 == result) {
1945f92b48cSEvan Quan reg_block = (ATOM_INIT_REG_BLOCK *)
1955f92b48cSEvan Quan ((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
1965f92b48cSEvan Quan result = atomctrl_set_mc_reg_address_table(reg_block, table);
1975f92b48cSEvan Quan }
1985f92b48cSEvan Quan
1995f92b48cSEvan Quan if (0 == result) {
2005f92b48cSEvan Quan result = atomctrl_retrieve_ac_timing(module_index,
2015f92b48cSEvan Quan reg_block, table);
2025f92b48cSEvan Quan }
2035f92b48cSEvan Quan
2045f92b48cSEvan Quan return result;
2055f92b48cSEvan Quan }
2065f92b48cSEvan Quan
20758cfaf25SLee Jones /*
208e098bc96SEvan Quan * Set DRAM timings based on engine clock and memory clock.
209e098bc96SEvan Quan */
atomctrl_set_engine_dram_timings_rv770(struct pp_hwmgr * hwmgr,uint32_t engine_clock,uint32_t memory_clock)210e098bc96SEvan Quan int atomctrl_set_engine_dram_timings_rv770(
211e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
212e098bc96SEvan Quan uint32_t engine_clock,
213e098bc96SEvan Quan uint32_t memory_clock)
214e098bc96SEvan Quan {
215e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
216e098bc96SEvan Quan
217e098bc96SEvan Quan SET_ENGINE_CLOCK_PS_ALLOCATION engine_clock_parameters;
218e098bc96SEvan Quan
219e098bc96SEvan Quan /* They are both in 10KHz Units. */
220e098bc96SEvan Quan engine_clock_parameters.ulTargetEngineClock =
221e098bc96SEvan Quan cpu_to_le32((engine_clock & SET_CLOCK_FREQ_MASK) |
222e098bc96SEvan Quan ((COMPUTE_ENGINE_PLL_PARAM << 24)));
223e098bc96SEvan Quan
224e098bc96SEvan Quan /* in 10 khz units.*/
225e098bc96SEvan Quan engine_clock_parameters.sReserved.ulClock =
226e098bc96SEvan Quan cpu_to_le32(memory_clock & SET_CLOCK_FREQ_MASK);
227e098bc96SEvan Quan
228e098bc96SEvan Quan return amdgpu_atom_execute_table(adev->mode_info.atom_context,
229e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings),
230e098bc96SEvan Quan (uint32_t *)&engine_clock_parameters);
231e098bc96SEvan Quan }
232e098bc96SEvan Quan
23358cfaf25SLee Jones /*
234e098bc96SEvan Quan * Private Function to get the PowerPlay Table Address.
235e098bc96SEvan Quan * WARNING: The tabled returned by this function is in
236e098bc96SEvan Quan * dynamically allocated memory.
237e098bc96SEvan Quan * The caller has to release if by calling kfree.
238e098bc96SEvan Quan */
get_voltage_info_table(void * device)239e098bc96SEvan Quan static ATOM_VOLTAGE_OBJECT_INFO *get_voltage_info_table(void *device)
240e098bc96SEvan Quan {
241e098bc96SEvan Quan int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
242e098bc96SEvan Quan u8 frev, crev;
243e098bc96SEvan Quan u16 size;
244e098bc96SEvan Quan union voltage_object_info *voltage_info;
245e098bc96SEvan Quan
246e098bc96SEvan Quan voltage_info = (union voltage_object_info *)
247e098bc96SEvan Quan smu_atom_get_data_table(device, index,
248e098bc96SEvan Quan &size, &frev, &crev);
249e098bc96SEvan Quan
250e098bc96SEvan Quan if (voltage_info != NULL)
251e098bc96SEvan Quan return (ATOM_VOLTAGE_OBJECT_INFO *) &(voltage_info->v3);
252e098bc96SEvan Quan else
253e098bc96SEvan Quan return NULL;
254e098bc96SEvan Quan }
255e098bc96SEvan Quan
atomctrl_lookup_voltage_type_v3(const ATOM_VOLTAGE_OBJECT_INFO_V3_1 * voltage_object_info_table,uint8_t voltage_type,uint8_t voltage_mode)256e098bc96SEvan Quan static const ATOM_VOLTAGE_OBJECT_V3 *atomctrl_lookup_voltage_type_v3(
257e098bc96SEvan Quan const ATOM_VOLTAGE_OBJECT_INFO_V3_1 * voltage_object_info_table,
258e098bc96SEvan Quan uint8_t voltage_type, uint8_t voltage_mode)
259e098bc96SEvan Quan {
260e098bc96SEvan Quan unsigned int size = le16_to_cpu(voltage_object_info_table->sHeader.usStructureSize);
261e098bc96SEvan Quan unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
262e098bc96SEvan Quan uint8_t *start = (uint8_t *)voltage_object_info_table;
263e098bc96SEvan Quan
264e098bc96SEvan Quan while (offset < size) {
265e098bc96SEvan Quan const ATOM_VOLTAGE_OBJECT_V3 *voltage_object =
266e098bc96SEvan Quan (const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
267e098bc96SEvan Quan
268e098bc96SEvan Quan if (voltage_type == voltage_object->asGpioVoltageObj.sHeader.ucVoltageType &&
269e098bc96SEvan Quan voltage_mode == voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode)
270e098bc96SEvan Quan return voltage_object;
271e098bc96SEvan Quan
272e098bc96SEvan Quan offset += le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize);
273e098bc96SEvan Quan }
274e098bc96SEvan Quan
275e098bc96SEvan Quan return NULL;
276e098bc96SEvan Quan }
277e098bc96SEvan Quan
27858cfaf25SLee Jones /**
279d477eb17SFabio M. De Francesco * atomctrl_get_memory_pll_dividers_si
280e098bc96SEvan Quan *
28158cfaf25SLee Jones * @hwmgr: input parameter: pointer to HwMgr
28258cfaf25SLee Jones * @clock_value: input parameter: memory clock
2839af1197fSLee Jones * @mpll_param: output parameter: memory clock parameters
28458cfaf25SLee Jones * @strobe_mode: input parameter: 1 for strobe mode, 0 for performance mode
285e098bc96SEvan Quan */
atomctrl_get_memory_pll_dividers_si(struct pp_hwmgr * hwmgr,uint32_t clock_value,pp_atomctrl_memory_clock_param * mpll_param,bool strobe_mode)286e098bc96SEvan Quan int atomctrl_get_memory_pll_dividers_si(
287e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
288e098bc96SEvan Quan uint32_t clock_value,
289e098bc96SEvan Quan pp_atomctrl_memory_clock_param *mpll_param,
290e098bc96SEvan Quan bool strobe_mode)
291e098bc96SEvan Quan {
292e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
293e098bc96SEvan Quan COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 mpll_parameters;
294e098bc96SEvan Quan int result;
295e098bc96SEvan Quan
296e098bc96SEvan Quan mpll_parameters.ulClock = cpu_to_le32(clock_value);
297e098bc96SEvan Quan mpll_parameters.ucInputFlag = (uint8_t)((strobe_mode) ? 1 : 0);
298e098bc96SEvan Quan
299e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
300e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
301e098bc96SEvan Quan (uint32_t *)&mpll_parameters);
302e098bc96SEvan Quan
303e098bc96SEvan Quan if (0 == result) {
304e098bc96SEvan Quan mpll_param->mpll_fb_divider.clk_frac =
305e098bc96SEvan Quan le16_to_cpu(mpll_parameters.ulFbDiv.usFbDivFrac);
306e098bc96SEvan Quan mpll_param->mpll_fb_divider.cl_kf =
307e098bc96SEvan Quan le16_to_cpu(mpll_parameters.ulFbDiv.usFbDiv);
308e098bc96SEvan Quan mpll_param->mpll_post_divider =
309e098bc96SEvan Quan (uint32_t)mpll_parameters.ucPostDiv;
310e098bc96SEvan Quan mpll_param->vco_mode =
311e098bc96SEvan Quan (uint32_t)(mpll_parameters.ucPllCntlFlag &
312e098bc96SEvan Quan MPLL_CNTL_FLAG_VCO_MODE_MASK);
313e098bc96SEvan Quan mpll_param->yclk_sel =
314e098bc96SEvan Quan (uint32_t)((mpll_parameters.ucPllCntlFlag &
315e098bc96SEvan Quan MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0);
316e098bc96SEvan Quan mpll_param->qdr =
317e098bc96SEvan Quan (uint32_t)((mpll_parameters.ucPllCntlFlag &
318e098bc96SEvan Quan MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0);
319e098bc96SEvan Quan mpll_param->half_rate =
320e098bc96SEvan Quan (uint32_t)((mpll_parameters.ucPllCntlFlag &
321e098bc96SEvan Quan MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0);
322e098bc96SEvan Quan mpll_param->dll_speed =
323e098bc96SEvan Quan (uint32_t)(mpll_parameters.ucDllSpeed);
324e098bc96SEvan Quan mpll_param->bw_ctrl =
325e098bc96SEvan Quan (uint32_t)(mpll_parameters.ucBWCntl);
326e098bc96SEvan Quan }
327e098bc96SEvan Quan
328e098bc96SEvan Quan return result;
329e098bc96SEvan Quan }
330e098bc96SEvan Quan
33158cfaf25SLee Jones /**
332d477eb17SFabio M. De Francesco * atomctrl_get_memory_pll_dividers_vi
333e098bc96SEvan Quan *
33458cfaf25SLee Jones * @hwmgr: input parameter: pointer to HwMgr
33558cfaf25SLee Jones * @clock_value: input parameter: memory clock
3369af1197fSLee Jones * @mpll_param: output parameter: memory clock parameters
337e098bc96SEvan Quan */
atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr * hwmgr,uint32_t clock_value,pp_atomctrl_memory_clock_param * mpll_param)338e098bc96SEvan Quan int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr *hwmgr,
339e098bc96SEvan Quan uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param)
340e098bc96SEvan Quan {
341e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
342e098bc96SEvan Quan COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2 mpll_parameters;
343e098bc96SEvan Quan int result;
344e098bc96SEvan Quan
345e098bc96SEvan Quan mpll_parameters.ulClock.ulClock = cpu_to_le32(clock_value);
346e098bc96SEvan Quan
347e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
348e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
349e098bc96SEvan Quan (uint32_t *)&mpll_parameters);
350e098bc96SEvan Quan
351e098bc96SEvan Quan if (!result)
352e098bc96SEvan Quan mpll_param->mpll_post_divider =
353e098bc96SEvan Quan (uint32_t)mpll_parameters.ulClock.ucPostDiv;
354e098bc96SEvan Quan
355e098bc96SEvan Quan return result;
356e098bc96SEvan Quan }
357e098bc96SEvan Quan
atomctrl_get_memory_pll_dividers_ai(struct pp_hwmgr * hwmgr,uint32_t clock_value,pp_atomctrl_memory_clock_param_ai * mpll_param)358e098bc96SEvan Quan int atomctrl_get_memory_pll_dividers_ai(struct pp_hwmgr *hwmgr,
359e098bc96SEvan Quan uint32_t clock_value,
360e098bc96SEvan Quan pp_atomctrl_memory_clock_param_ai *mpll_param)
361e098bc96SEvan Quan {
362e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
363e098bc96SEvan Quan COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_3 mpll_parameters = {{0}, 0, 0};
364e098bc96SEvan Quan int result;
365e098bc96SEvan Quan
366e098bc96SEvan Quan mpll_parameters.ulClock.ulClock = cpu_to_le32(clock_value);
367e098bc96SEvan Quan
368e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
369e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
370e098bc96SEvan Quan (uint32_t *)&mpll_parameters);
371e098bc96SEvan Quan
372e098bc96SEvan Quan /* VEGAM's mpll takes sometime to finish computing */
373e098bc96SEvan Quan udelay(10);
374e098bc96SEvan Quan
375e098bc96SEvan Quan if (!result) {
376e098bc96SEvan Quan mpll_param->ulMclk_fcw_int =
377e098bc96SEvan Quan le16_to_cpu(mpll_parameters.usMclk_fcw_int);
378e098bc96SEvan Quan mpll_param->ulMclk_fcw_frac =
379e098bc96SEvan Quan le16_to_cpu(mpll_parameters.usMclk_fcw_frac);
380e098bc96SEvan Quan mpll_param->ulClock =
381e098bc96SEvan Quan le32_to_cpu(mpll_parameters.ulClock.ulClock);
382e098bc96SEvan Quan mpll_param->ulPostDiv = mpll_parameters.ulClock.ucPostDiv;
383e098bc96SEvan Quan }
384e098bc96SEvan Quan
385e098bc96SEvan Quan return result;
386e098bc96SEvan Quan }
387e098bc96SEvan Quan
atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr * hwmgr,uint32_t clock_value,pp_atomctrl_clock_dividers_kong * dividers)388e098bc96SEvan Quan int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr *hwmgr,
389e098bc96SEvan Quan uint32_t clock_value,
390e098bc96SEvan Quan pp_atomctrl_clock_dividers_kong *dividers)
391e098bc96SEvan Quan {
392e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
393e098bc96SEvan Quan COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 pll_parameters;
394e098bc96SEvan Quan int result;
395e098bc96SEvan Quan
396e098bc96SEvan Quan pll_parameters.ulClock = cpu_to_le32(clock_value);
397e098bc96SEvan Quan
398e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
399e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
400e098bc96SEvan Quan (uint32_t *)&pll_parameters);
401e098bc96SEvan Quan
402e098bc96SEvan Quan if (0 == result) {
403e098bc96SEvan Quan dividers->pll_post_divider = pll_parameters.ucPostDiv;
404e098bc96SEvan Quan dividers->real_clock = le32_to_cpu(pll_parameters.ulClock);
405e098bc96SEvan Quan }
406e098bc96SEvan Quan
407e098bc96SEvan Quan return result;
408e098bc96SEvan Quan }
409e098bc96SEvan Quan
atomctrl_get_engine_pll_dividers_vi(struct pp_hwmgr * hwmgr,uint32_t clock_value,pp_atomctrl_clock_dividers_vi * dividers)410e098bc96SEvan Quan int atomctrl_get_engine_pll_dividers_vi(
411e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
412e098bc96SEvan Quan uint32_t clock_value,
413e098bc96SEvan Quan pp_atomctrl_clock_dividers_vi *dividers)
414e098bc96SEvan Quan {
415e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
416e098bc96SEvan Quan COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters;
417e098bc96SEvan Quan int result;
418e098bc96SEvan Quan
419e098bc96SEvan Quan pll_patameters.ulClock.ulClock = cpu_to_le32(clock_value);
420e098bc96SEvan Quan pll_patameters.ulClock.ucPostDiv = COMPUTE_GPUCLK_INPUT_FLAG_SCLK;
421e098bc96SEvan Quan
422e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
423e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
424e098bc96SEvan Quan (uint32_t *)&pll_patameters);
425e098bc96SEvan Quan
426e098bc96SEvan Quan if (0 == result) {
427e098bc96SEvan Quan dividers->pll_post_divider =
428e098bc96SEvan Quan pll_patameters.ulClock.ucPostDiv;
429e098bc96SEvan Quan dividers->real_clock =
430e098bc96SEvan Quan le32_to_cpu(pll_patameters.ulClock.ulClock);
431e098bc96SEvan Quan
432e098bc96SEvan Quan dividers->ul_fb_div.ul_fb_div_frac =
433e098bc96SEvan Quan le16_to_cpu(pll_patameters.ulFbDiv.usFbDivFrac);
434e098bc96SEvan Quan dividers->ul_fb_div.ul_fb_div =
435e098bc96SEvan Quan le16_to_cpu(pll_patameters.ulFbDiv.usFbDiv);
436e098bc96SEvan Quan
437e098bc96SEvan Quan dividers->uc_pll_ref_div =
438e098bc96SEvan Quan pll_patameters.ucPllRefDiv;
439e098bc96SEvan Quan dividers->uc_pll_post_div =
440e098bc96SEvan Quan pll_patameters.ucPllPostDiv;
441e098bc96SEvan Quan dividers->uc_pll_cntl_flag =
442e098bc96SEvan Quan pll_patameters.ucPllCntlFlag;
443e098bc96SEvan Quan }
444e098bc96SEvan Quan
445e098bc96SEvan Quan return result;
446e098bc96SEvan Quan }
447e098bc96SEvan Quan
atomctrl_get_engine_pll_dividers_ai(struct pp_hwmgr * hwmgr,uint32_t clock_value,pp_atomctrl_clock_dividers_ai * dividers)448e098bc96SEvan Quan int atomctrl_get_engine_pll_dividers_ai(struct pp_hwmgr *hwmgr,
449e098bc96SEvan Quan uint32_t clock_value,
450e098bc96SEvan Quan pp_atomctrl_clock_dividers_ai *dividers)
451e098bc96SEvan Quan {
452e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
453e098bc96SEvan Quan COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_7 pll_patameters;
454e098bc96SEvan Quan int result;
455e098bc96SEvan Quan
456e098bc96SEvan Quan pll_patameters.ulClock.ulClock = cpu_to_le32(clock_value);
457e098bc96SEvan Quan pll_patameters.ulClock.ucPostDiv = COMPUTE_GPUCLK_INPUT_FLAG_SCLK;
458e098bc96SEvan Quan
459e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
460e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
461e098bc96SEvan Quan (uint32_t *)&pll_patameters);
462e098bc96SEvan Quan
463e098bc96SEvan Quan if (0 == result) {
464e098bc96SEvan Quan dividers->usSclk_fcw_frac = le16_to_cpu(pll_patameters.usSclk_fcw_frac);
465e098bc96SEvan Quan dividers->usSclk_fcw_int = le16_to_cpu(pll_patameters.usSclk_fcw_int);
466e098bc96SEvan Quan dividers->ucSclkPostDiv = pll_patameters.ucSclkPostDiv;
467e098bc96SEvan Quan dividers->ucSclkVcoMode = pll_patameters.ucSclkVcoMode;
468e098bc96SEvan Quan dividers->ucSclkPllRange = pll_patameters.ucSclkPllRange;
469e098bc96SEvan Quan dividers->ucSscEnable = pll_patameters.ucSscEnable;
470e098bc96SEvan Quan dividers->usSsc_fcw1_frac = le16_to_cpu(pll_patameters.usSsc_fcw1_frac);
471e098bc96SEvan Quan dividers->usSsc_fcw1_int = le16_to_cpu(pll_patameters.usSsc_fcw1_int);
472e098bc96SEvan Quan dividers->usPcc_fcw_int = le16_to_cpu(pll_patameters.usPcc_fcw_int);
473e098bc96SEvan Quan dividers->usSsc_fcw_slew_frac = le16_to_cpu(pll_patameters.usSsc_fcw_slew_frac);
474e098bc96SEvan Quan dividers->usPcc_fcw_slew_frac = le16_to_cpu(pll_patameters.usPcc_fcw_slew_frac);
475e098bc96SEvan Quan }
476e098bc96SEvan Quan return result;
477e098bc96SEvan Quan }
478e098bc96SEvan Quan
atomctrl_get_dfs_pll_dividers_vi(struct pp_hwmgr * hwmgr,uint32_t clock_value,pp_atomctrl_clock_dividers_vi * dividers)479e098bc96SEvan Quan int atomctrl_get_dfs_pll_dividers_vi(
480e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
481e098bc96SEvan Quan uint32_t clock_value,
482e098bc96SEvan Quan pp_atomctrl_clock_dividers_vi *dividers)
483e098bc96SEvan Quan {
484e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
485e098bc96SEvan Quan COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters;
486e098bc96SEvan Quan int result;
487e098bc96SEvan Quan
488e098bc96SEvan Quan pll_patameters.ulClock.ulClock = cpu_to_le32(clock_value);
489e098bc96SEvan Quan pll_patameters.ulClock.ucPostDiv =
490e098bc96SEvan Quan COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK;
491e098bc96SEvan Quan
492e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
493e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
494e098bc96SEvan Quan (uint32_t *)&pll_patameters);
495e098bc96SEvan Quan
496e098bc96SEvan Quan if (0 == result) {
497e098bc96SEvan Quan dividers->pll_post_divider =
498e098bc96SEvan Quan pll_patameters.ulClock.ucPostDiv;
499e098bc96SEvan Quan dividers->real_clock =
500e098bc96SEvan Quan le32_to_cpu(pll_patameters.ulClock.ulClock);
501e098bc96SEvan Quan
502e098bc96SEvan Quan dividers->ul_fb_div.ul_fb_div_frac =
503e098bc96SEvan Quan le16_to_cpu(pll_patameters.ulFbDiv.usFbDivFrac);
504e098bc96SEvan Quan dividers->ul_fb_div.ul_fb_div =
505e098bc96SEvan Quan le16_to_cpu(pll_patameters.ulFbDiv.usFbDiv);
506e098bc96SEvan Quan
507e098bc96SEvan Quan dividers->uc_pll_ref_div =
508e098bc96SEvan Quan pll_patameters.ucPllRefDiv;
509e098bc96SEvan Quan dividers->uc_pll_post_div =
510e098bc96SEvan Quan pll_patameters.ucPllPostDiv;
511e098bc96SEvan Quan dividers->uc_pll_cntl_flag =
512e098bc96SEvan Quan pll_patameters.ucPllCntlFlag;
513e098bc96SEvan Quan }
514e098bc96SEvan Quan
515e098bc96SEvan Quan return result;
516e098bc96SEvan Quan }
517e098bc96SEvan Quan
51858cfaf25SLee Jones /*
519e098bc96SEvan Quan * Get the reference clock in 10KHz
520e098bc96SEvan Quan */
atomctrl_get_reference_clock(struct pp_hwmgr * hwmgr)521e098bc96SEvan Quan uint32_t atomctrl_get_reference_clock(struct pp_hwmgr *hwmgr)
522e098bc96SEvan Quan {
523e098bc96SEvan Quan ATOM_FIRMWARE_INFO *fw_info;
524e098bc96SEvan Quan u8 frev, crev;
525e098bc96SEvan Quan u16 size;
526e098bc96SEvan Quan uint32_t clock;
527e098bc96SEvan Quan
528e098bc96SEvan Quan fw_info = (ATOM_FIRMWARE_INFO *)
529e098bc96SEvan Quan smu_atom_get_data_table(hwmgr->adev,
530e098bc96SEvan Quan GetIndexIntoMasterTable(DATA, FirmwareInfo),
531e098bc96SEvan Quan &size, &frev, &crev);
532e098bc96SEvan Quan
533e098bc96SEvan Quan if (fw_info == NULL)
534e098bc96SEvan Quan clock = 2700;
535e098bc96SEvan Quan else
536e098bc96SEvan Quan clock = (uint32_t)(le16_to_cpu(fw_info->usReferenceClock));
537e098bc96SEvan Quan
538e098bc96SEvan Quan return clock;
539e098bc96SEvan Quan }
540e098bc96SEvan Quan
54158cfaf25SLee Jones /*
542e098bc96SEvan Quan * Returns true if the given voltage type is controlled by GPIO pins.
543e098bc96SEvan Quan * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC,
544e098bc96SEvan Quan * SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ.
545e098bc96SEvan Quan * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE
546e098bc96SEvan Quan */
atomctrl_is_voltage_controlled_by_gpio_v3(struct pp_hwmgr * hwmgr,uint8_t voltage_type,uint8_t voltage_mode)547e098bc96SEvan Quan bool atomctrl_is_voltage_controlled_by_gpio_v3(
548e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
549e098bc96SEvan Quan uint8_t voltage_type,
550e098bc96SEvan Quan uint8_t voltage_mode)
551e098bc96SEvan Quan {
552e098bc96SEvan Quan ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
553e098bc96SEvan Quan (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->adev);
554e098bc96SEvan Quan bool ret;
555e098bc96SEvan Quan
556e098bc96SEvan Quan PP_ASSERT_WITH_CODE((NULL != voltage_info),
557e098bc96SEvan Quan "Could not find Voltage Table in BIOS.", return false;);
558e098bc96SEvan Quan
559e098bc96SEvan Quan ret = (NULL != atomctrl_lookup_voltage_type_v3
560e098bc96SEvan Quan (voltage_info, voltage_type, voltage_mode)) ? true : false;
561e098bc96SEvan Quan
562e098bc96SEvan Quan return ret;
563e098bc96SEvan Quan }
564e098bc96SEvan Quan
atomctrl_get_voltage_table_v3(struct pp_hwmgr * hwmgr,uint8_t voltage_type,uint8_t voltage_mode,pp_atomctrl_voltage_table * voltage_table)565e098bc96SEvan Quan int atomctrl_get_voltage_table_v3(
566e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
567e098bc96SEvan Quan uint8_t voltage_type,
568e098bc96SEvan Quan uint8_t voltage_mode,
569e098bc96SEvan Quan pp_atomctrl_voltage_table *voltage_table)
570e098bc96SEvan Quan {
571e098bc96SEvan Quan ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
572e098bc96SEvan Quan (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->adev);
573e098bc96SEvan Quan const ATOM_VOLTAGE_OBJECT_V3 *voltage_object;
574e098bc96SEvan Quan unsigned int i;
575e098bc96SEvan Quan
576e098bc96SEvan Quan PP_ASSERT_WITH_CODE((NULL != voltage_info),
577e098bc96SEvan Quan "Could not find Voltage Table in BIOS.", return -1;);
578e098bc96SEvan Quan
579e098bc96SEvan Quan voltage_object = atomctrl_lookup_voltage_type_v3
580e098bc96SEvan Quan (voltage_info, voltage_type, voltage_mode);
581e098bc96SEvan Quan
582e098bc96SEvan Quan if (voltage_object == NULL)
583e098bc96SEvan Quan return -1;
584e098bc96SEvan Quan
585e098bc96SEvan Quan PP_ASSERT_WITH_CODE(
586e098bc96SEvan Quan (voltage_object->asGpioVoltageObj.ucGpioEntryNum <=
587e098bc96SEvan Quan PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES),
588e098bc96SEvan Quan "Too many voltage entries!",
589e098bc96SEvan Quan return -1;
590e098bc96SEvan Quan );
591e098bc96SEvan Quan
592e098bc96SEvan Quan for (i = 0; i < voltage_object->asGpioVoltageObj.ucGpioEntryNum; i++) {
593e098bc96SEvan Quan voltage_table->entries[i].value =
594e098bc96SEvan Quan le16_to_cpu(voltage_object->asGpioVoltageObj.asVolGpioLut[i].usVoltageValue);
595e098bc96SEvan Quan voltage_table->entries[i].smio_low =
596e098bc96SEvan Quan le32_to_cpu(voltage_object->asGpioVoltageObj.asVolGpioLut[i].ulVoltageId);
597e098bc96SEvan Quan }
598e098bc96SEvan Quan
599e098bc96SEvan Quan voltage_table->mask_low =
600e098bc96SEvan Quan le32_to_cpu(voltage_object->asGpioVoltageObj.ulGpioMaskVal);
601e098bc96SEvan Quan voltage_table->count =
602e098bc96SEvan Quan voltage_object->asGpioVoltageObj.ucGpioEntryNum;
603e098bc96SEvan Quan voltage_table->phase_delay =
604e098bc96SEvan Quan voltage_object->asGpioVoltageObj.ucPhaseDelay;
605e098bc96SEvan Quan
606e098bc96SEvan Quan return 0;
607e098bc96SEvan Quan }
608e098bc96SEvan Quan
atomctrl_lookup_gpio_pin(ATOM_GPIO_PIN_LUT * gpio_lookup_table,const uint32_t pinId,pp_atomctrl_gpio_pin_assignment * gpio_pin_assignment)609e098bc96SEvan Quan static bool atomctrl_lookup_gpio_pin(
610e098bc96SEvan Quan ATOM_GPIO_PIN_LUT * gpio_lookup_table,
611e098bc96SEvan Quan const uint32_t pinId,
612e098bc96SEvan Quan pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment)
613e098bc96SEvan Quan {
614e098bc96SEvan Quan unsigned int size = le16_to_cpu(gpio_lookup_table->sHeader.usStructureSize);
615e098bc96SEvan Quan unsigned int offset = offsetof(ATOM_GPIO_PIN_LUT, asGPIO_Pin[0]);
616e098bc96SEvan Quan uint8_t *start = (uint8_t *)gpio_lookup_table;
617e098bc96SEvan Quan
618e098bc96SEvan Quan while (offset < size) {
619e098bc96SEvan Quan const ATOM_GPIO_PIN_ASSIGNMENT *pin_assignment =
620e098bc96SEvan Quan (const ATOM_GPIO_PIN_ASSIGNMENT *)(start + offset);
621e098bc96SEvan Quan
622e098bc96SEvan Quan if (pinId == pin_assignment->ucGPIO_ID) {
623e098bc96SEvan Quan gpio_pin_assignment->uc_gpio_pin_bit_shift =
624e098bc96SEvan Quan pin_assignment->ucGpioPinBitShift;
625e098bc96SEvan Quan gpio_pin_assignment->us_gpio_pin_aindex =
626e098bc96SEvan Quan le16_to_cpu(pin_assignment->usGpioPin_AIndex);
627e098bc96SEvan Quan return true;
628e098bc96SEvan Quan }
629e098bc96SEvan Quan
630e098bc96SEvan Quan offset += offsetof(ATOM_GPIO_PIN_ASSIGNMENT, ucGPIO_ID) + 1;
631e098bc96SEvan Quan }
632e098bc96SEvan Quan
633e098bc96SEvan Quan return false;
634e098bc96SEvan Quan }
635e098bc96SEvan Quan
63658cfaf25SLee Jones /*
637e098bc96SEvan Quan * Private Function to get the PowerPlay Table Address.
638e098bc96SEvan Quan * WARNING: The tabled returned by this function is in
639e098bc96SEvan Quan * dynamically allocated memory.
640e098bc96SEvan Quan * The caller has to release if by calling kfree.
641e098bc96SEvan Quan */
get_gpio_lookup_table(void * device)642e098bc96SEvan Quan static ATOM_GPIO_PIN_LUT *get_gpio_lookup_table(void *device)
643e098bc96SEvan Quan {
644e098bc96SEvan Quan u8 frev, crev;
645e098bc96SEvan Quan u16 size;
646e098bc96SEvan Quan void *table_address;
647e098bc96SEvan Quan
648e098bc96SEvan Quan table_address = (ATOM_GPIO_PIN_LUT *)
649e098bc96SEvan Quan smu_atom_get_data_table(device,
650e098bc96SEvan Quan GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT),
651e098bc96SEvan Quan &size, &frev, &crev);
652e098bc96SEvan Quan
653e098bc96SEvan Quan PP_ASSERT_WITH_CODE((NULL != table_address),
654e098bc96SEvan Quan "Error retrieving BIOS Table Address!", return NULL;);
655e098bc96SEvan Quan
656e098bc96SEvan Quan return (ATOM_GPIO_PIN_LUT *)table_address;
657e098bc96SEvan Quan }
658e098bc96SEvan Quan
65958cfaf25SLee Jones /*
660e098bc96SEvan Quan * Returns 1 if the given pin id find in lookup table.
661e098bc96SEvan Quan */
atomctrl_get_pp_assign_pin(struct pp_hwmgr * hwmgr,const uint32_t pinId,pp_atomctrl_gpio_pin_assignment * gpio_pin_assignment)662e098bc96SEvan Quan bool atomctrl_get_pp_assign_pin(
663e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
664e098bc96SEvan Quan const uint32_t pinId,
665e098bc96SEvan Quan pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment)
666e098bc96SEvan Quan {
667e098bc96SEvan Quan bool bRet = false;
668e098bc96SEvan Quan ATOM_GPIO_PIN_LUT *gpio_lookup_table =
669e098bc96SEvan Quan get_gpio_lookup_table(hwmgr->adev);
670e098bc96SEvan Quan
671e098bc96SEvan Quan PP_ASSERT_WITH_CODE((NULL != gpio_lookup_table),
672e098bc96SEvan Quan "Could not find GPIO lookup Table in BIOS.", return false);
673e098bc96SEvan Quan
674e098bc96SEvan Quan bRet = atomctrl_lookup_gpio_pin(gpio_lookup_table, pinId,
675e098bc96SEvan Quan gpio_pin_assignment);
676e098bc96SEvan Quan
677e098bc96SEvan Quan return bRet;
678e098bc96SEvan Quan }
679e098bc96SEvan Quan
atomctrl_calculate_voltage_evv_on_sclk(struct pp_hwmgr * hwmgr,uint8_t voltage_type,uint32_t sclk,uint16_t virtual_voltage_Id,uint16_t * voltage,uint16_t dpm_level,bool debug)680e098bc96SEvan Quan int atomctrl_calculate_voltage_evv_on_sclk(
681e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
682e098bc96SEvan Quan uint8_t voltage_type,
683e098bc96SEvan Quan uint32_t sclk,
684e098bc96SEvan Quan uint16_t virtual_voltage_Id,
685e098bc96SEvan Quan uint16_t *voltage,
686e098bc96SEvan Quan uint16_t dpm_level,
687e098bc96SEvan Quan bool debug)
688e098bc96SEvan Quan {
689e098bc96SEvan Quan ATOM_ASIC_PROFILING_INFO_V3_4 *getASICProfilingInfo;
690e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
691e098bc96SEvan Quan EFUSE_LINEAR_FUNC_PARAM sRO_fuse;
692e098bc96SEvan Quan EFUSE_LINEAR_FUNC_PARAM sCACm_fuse;
693e098bc96SEvan Quan EFUSE_LINEAR_FUNC_PARAM sCACb_fuse;
694e098bc96SEvan Quan EFUSE_LOGISTIC_FUNC_PARAM sKt_Beta_fuse;
695e098bc96SEvan Quan EFUSE_LOGISTIC_FUNC_PARAM sKv_m_fuse;
696e098bc96SEvan Quan EFUSE_LOGISTIC_FUNC_PARAM sKv_b_fuse;
697e098bc96SEvan Quan EFUSE_INPUT_PARAMETER sInput_FuseValues;
698e098bc96SEvan Quan READ_EFUSE_VALUE_PARAMETER sOutput_FuseValues;
699e098bc96SEvan Quan
700e098bc96SEvan Quan uint32_t ul_RO_fused, ul_CACb_fused, ul_CACm_fused, ul_Kt_Beta_fused, ul_Kv_m_fused, ul_Kv_b_fused;
701e098bc96SEvan Quan fInt fSM_A0, fSM_A1, fSM_A2, fSM_A3, fSM_A4, fSM_A5, fSM_A6, fSM_A7;
702e098bc96SEvan Quan fInt fMargin_RO_a, fMargin_RO_b, fMargin_RO_c, fMargin_fixed, fMargin_FMAX_mean, fMargin_Plat_mean, fMargin_FMAX_sigma, fMargin_Plat_sigma, fMargin_DC_sigma;
703e098bc96SEvan Quan fInt fLkg_FT, repeat;
704e098bc96SEvan Quan fInt fMicro_FMAX, fMicro_CR, fSigma_FMAX, fSigma_CR, fSigma_DC, fDC_SCLK, fSquared_Sigma_DC, fSquared_Sigma_CR, fSquared_Sigma_FMAX;
705ddb0fc9aSLee Jones fInt fRLL_LoadLine, fDerateTDP, fVDDC_base, fA_Term, fC_Term, fB_Term, fRO_DC_margin;
706e098bc96SEvan Quan fInt fRO_fused, fCACm_fused, fCACb_fused, fKv_m_fused, fKv_b_fused, fKt_Beta_fused, fFT_Lkg_V0NORM;
707e098bc96SEvan Quan fInt fSclk_margin, fSclk, fEVV_V;
708e098bc96SEvan Quan fInt fV_min, fV_max, fT_prod, fLKG_Factor, fT_FT, fV_FT, fV_x, fTDP_Power, fTDP_Power_right, fTDP_Power_left, fTDP_Current, fV_NL;
709e098bc96SEvan Quan uint32_t ul_FT_Lkg_V0NORM;
710e098bc96SEvan Quan fInt fLn_MaxDivMin, fMin, fAverage, fRange;
711e098bc96SEvan Quan fInt fRoots[2];
712e098bc96SEvan Quan fInt fStepSize = GetScaledFraction(625, 100000);
713e098bc96SEvan Quan
714e098bc96SEvan Quan int result;
715e098bc96SEvan Quan
716e098bc96SEvan Quan getASICProfilingInfo = (ATOM_ASIC_PROFILING_INFO_V3_4 *)
717e098bc96SEvan Quan smu_atom_get_data_table(hwmgr->adev,
718e098bc96SEvan Quan GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo),
719e098bc96SEvan Quan NULL, NULL, NULL);
720e098bc96SEvan Quan
721e098bc96SEvan Quan if (!getASICProfilingInfo)
722e098bc96SEvan Quan return -1;
723e098bc96SEvan Quan
724e098bc96SEvan Quan if (getASICProfilingInfo->asHeader.ucTableFormatRevision < 3 ||
725e098bc96SEvan Quan (getASICProfilingInfo->asHeader.ucTableFormatRevision == 3 &&
726e098bc96SEvan Quan getASICProfilingInfo->asHeader.ucTableContentRevision < 4))
727e098bc96SEvan Quan return -1;
728e098bc96SEvan Quan
729e098bc96SEvan Quan /*-----------------------------------------------------------
730e098bc96SEvan Quan *GETTING MULTI-STEP PARAMETERS RELATED TO CURRENT DPM LEVEL
731e098bc96SEvan Quan *-----------------------------------------------------------
732e098bc96SEvan Quan */
733e098bc96SEvan Quan fRLL_LoadLine = Divide(getASICProfilingInfo->ulLoadLineSlop, 1000);
734e098bc96SEvan Quan
735e098bc96SEvan Quan switch (dpm_level) {
736e098bc96SEvan Quan case 1:
737e098bc96SEvan Quan fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM1), 1000);
738e098bc96SEvan Quan break;
739e098bc96SEvan Quan case 2:
740e098bc96SEvan Quan fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM2), 1000);
741e098bc96SEvan Quan break;
742e098bc96SEvan Quan case 3:
743e098bc96SEvan Quan fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM3), 1000);
744e098bc96SEvan Quan break;
745e098bc96SEvan Quan case 4:
746e098bc96SEvan Quan fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM4), 1000);
747e098bc96SEvan Quan break;
748e098bc96SEvan Quan case 5:
749e098bc96SEvan Quan fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM5), 1000);
750e098bc96SEvan Quan break;
751e098bc96SEvan Quan case 6:
752e098bc96SEvan Quan fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM6), 1000);
753e098bc96SEvan Quan break;
754e098bc96SEvan Quan case 7:
755e098bc96SEvan Quan fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM7), 1000);
756e098bc96SEvan Quan break;
757e098bc96SEvan Quan default:
758e098bc96SEvan Quan pr_err("DPM Level not supported\n");
759e098bc96SEvan Quan fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM0), 1000);
760e098bc96SEvan Quan }
761e098bc96SEvan Quan
762e098bc96SEvan Quan /*-------------------------
763e098bc96SEvan Quan * DECODING FUSE VALUES
764e098bc96SEvan Quan * ------------------------
765e098bc96SEvan Quan */
766e098bc96SEvan Quan /*Decode RO_Fused*/
767e098bc96SEvan Quan sRO_fuse = getASICProfilingInfo->sRoFuse;
768e098bc96SEvan Quan
769e098bc96SEvan Quan sInput_FuseValues.usEfuseIndex = sRO_fuse.usEfuseIndex;
770e098bc96SEvan Quan sInput_FuseValues.ucBitShift = sRO_fuse.ucEfuseBitLSB;
771e098bc96SEvan Quan sInput_FuseValues.ucBitLength = sRO_fuse.ucEfuseLength;
772e098bc96SEvan Quan
773e098bc96SEvan Quan sOutput_FuseValues.sEfuse = sInput_FuseValues;
774e098bc96SEvan Quan
775e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
776e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
777e098bc96SEvan Quan (uint32_t *)&sOutput_FuseValues);
778e098bc96SEvan Quan
779e098bc96SEvan Quan if (result)
780e098bc96SEvan Quan return result;
781e098bc96SEvan Quan
782e098bc96SEvan Quan /* Finally, the actual fuse value */
783e098bc96SEvan Quan ul_RO_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue);
784e098bc96SEvan Quan fMin = GetScaledFraction(le32_to_cpu(sRO_fuse.ulEfuseMin), 1);
785e098bc96SEvan Quan fRange = GetScaledFraction(le32_to_cpu(sRO_fuse.ulEfuseEncodeRange), 1);
786e098bc96SEvan Quan fRO_fused = fDecodeLinearFuse(ul_RO_fused, fMin, fRange, sRO_fuse.ucEfuseLength);
787e098bc96SEvan Quan
788e098bc96SEvan Quan sCACm_fuse = getASICProfilingInfo->sCACm;
789e098bc96SEvan Quan
790e098bc96SEvan Quan sInput_FuseValues.usEfuseIndex = sCACm_fuse.usEfuseIndex;
791e098bc96SEvan Quan sInput_FuseValues.ucBitShift = sCACm_fuse.ucEfuseBitLSB;
792e098bc96SEvan Quan sInput_FuseValues.ucBitLength = sCACm_fuse.ucEfuseLength;
793e098bc96SEvan Quan
794e098bc96SEvan Quan sOutput_FuseValues.sEfuse = sInput_FuseValues;
795e098bc96SEvan Quan
796e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
797e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
798e098bc96SEvan Quan (uint32_t *)&sOutput_FuseValues);
799e098bc96SEvan Quan
800e098bc96SEvan Quan if (result)
801e098bc96SEvan Quan return result;
802e098bc96SEvan Quan
803e098bc96SEvan Quan ul_CACm_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue);
804e098bc96SEvan Quan fMin = GetScaledFraction(le32_to_cpu(sCACm_fuse.ulEfuseMin), 1000);
805e098bc96SEvan Quan fRange = GetScaledFraction(le32_to_cpu(sCACm_fuse.ulEfuseEncodeRange), 1000);
806e098bc96SEvan Quan
807e098bc96SEvan Quan fCACm_fused = fDecodeLinearFuse(ul_CACm_fused, fMin, fRange, sCACm_fuse.ucEfuseLength);
808e098bc96SEvan Quan
809e098bc96SEvan Quan sCACb_fuse = getASICProfilingInfo->sCACb;
810e098bc96SEvan Quan
811e098bc96SEvan Quan sInput_FuseValues.usEfuseIndex = sCACb_fuse.usEfuseIndex;
812e098bc96SEvan Quan sInput_FuseValues.ucBitShift = sCACb_fuse.ucEfuseBitLSB;
813e098bc96SEvan Quan sInput_FuseValues.ucBitLength = sCACb_fuse.ucEfuseLength;
814e098bc96SEvan Quan sOutput_FuseValues.sEfuse = sInput_FuseValues;
815e098bc96SEvan Quan
816e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
817e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
818e098bc96SEvan Quan (uint32_t *)&sOutput_FuseValues);
819e098bc96SEvan Quan
820e098bc96SEvan Quan if (result)
821e098bc96SEvan Quan return result;
822e098bc96SEvan Quan
823e098bc96SEvan Quan ul_CACb_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue);
824e098bc96SEvan Quan fMin = GetScaledFraction(le32_to_cpu(sCACb_fuse.ulEfuseMin), 1000);
825e098bc96SEvan Quan fRange = GetScaledFraction(le32_to_cpu(sCACb_fuse.ulEfuseEncodeRange), 1000);
826e098bc96SEvan Quan
827e098bc96SEvan Quan fCACb_fused = fDecodeLinearFuse(ul_CACb_fused, fMin, fRange, sCACb_fuse.ucEfuseLength);
828e098bc96SEvan Quan
829e098bc96SEvan Quan sKt_Beta_fuse = getASICProfilingInfo->sKt_b;
830e098bc96SEvan Quan
831e098bc96SEvan Quan sInput_FuseValues.usEfuseIndex = sKt_Beta_fuse.usEfuseIndex;
832e098bc96SEvan Quan sInput_FuseValues.ucBitShift = sKt_Beta_fuse.ucEfuseBitLSB;
833e098bc96SEvan Quan sInput_FuseValues.ucBitLength = sKt_Beta_fuse.ucEfuseLength;
834e098bc96SEvan Quan
835e098bc96SEvan Quan sOutput_FuseValues.sEfuse = sInput_FuseValues;
836e098bc96SEvan Quan
837e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
838e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
839e098bc96SEvan Quan (uint32_t *)&sOutput_FuseValues);
840e098bc96SEvan Quan
841e098bc96SEvan Quan if (result)
842e098bc96SEvan Quan return result;
843e098bc96SEvan Quan
844e098bc96SEvan Quan ul_Kt_Beta_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue);
845e098bc96SEvan Quan fAverage = GetScaledFraction(le32_to_cpu(sKt_Beta_fuse.ulEfuseEncodeAverage), 1000);
846e098bc96SEvan Quan fRange = GetScaledFraction(le32_to_cpu(sKt_Beta_fuse.ulEfuseEncodeRange), 1000);
847e098bc96SEvan Quan
848e098bc96SEvan Quan fKt_Beta_fused = fDecodeLogisticFuse(ul_Kt_Beta_fused,
849e098bc96SEvan Quan fAverage, fRange, sKt_Beta_fuse.ucEfuseLength);
850e098bc96SEvan Quan
851e098bc96SEvan Quan sKv_m_fuse = getASICProfilingInfo->sKv_m;
852e098bc96SEvan Quan
853e098bc96SEvan Quan sInput_FuseValues.usEfuseIndex = sKv_m_fuse.usEfuseIndex;
854e098bc96SEvan Quan sInput_FuseValues.ucBitShift = sKv_m_fuse.ucEfuseBitLSB;
855e098bc96SEvan Quan sInput_FuseValues.ucBitLength = sKv_m_fuse.ucEfuseLength;
856e098bc96SEvan Quan
857e098bc96SEvan Quan sOutput_FuseValues.sEfuse = sInput_FuseValues;
858e098bc96SEvan Quan
859e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
860e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
861e098bc96SEvan Quan (uint32_t *)&sOutput_FuseValues);
862e098bc96SEvan Quan if (result)
863e098bc96SEvan Quan return result;
864e098bc96SEvan Quan
865e098bc96SEvan Quan ul_Kv_m_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue);
866e098bc96SEvan Quan fAverage = GetScaledFraction(le32_to_cpu(sKv_m_fuse.ulEfuseEncodeAverage), 1000);
867e098bc96SEvan Quan fRange = GetScaledFraction((le32_to_cpu(sKv_m_fuse.ulEfuseEncodeRange) & 0x7fffffff), 1000);
868e098bc96SEvan Quan fRange = fMultiply(fRange, ConvertToFraction(-1));
869e098bc96SEvan Quan
870e098bc96SEvan Quan fKv_m_fused = fDecodeLogisticFuse(ul_Kv_m_fused,
871e098bc96SEvan Quan fAverage, fRange, sKv_m_fuse.ucEfuseLength);
872e098bc96SEvan Quan
873e098bc96SEvan Quan sKv_b_fuse = getASICProfilingInfo->sKv_b;
874e098bc96SEvan Quan
875e098bc96SEvan Quan sInput_FuseValues.usEfuseIndex = sKv_b_fuse.usEfuseIndex;
876e098bc96SEvan Quan sInput_FuseValues.ucBitShift = sKv_b_fuse.ucEfuseBitLSB;
877e098bc96SEvan Quan sInput_FuseValues.ucBitLength = sKv_b_fuse.ucEfuseLength;
878e098bc96SEvan Quan sOutput_FuseValues.sEfuse = sInput_FuseValues;
879e098bc96SEvan Quan
880e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
881e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
882e098bc96SEvan Quan (uint32_t *)&sOutput_FuseValues);
883e098bc96SEvan Quan
884e098bc96SEvan Quan if (result)
885e098bc96SEvan Quan return result;
886e098bc96SEvan Quan
887e098bc96SEvan Quan ul_Kv_b_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue);
888e098bc96SEvan Quan fAverage = GetScaledFraction(le32_to_cpu(sKv_b_fuse.ulEfuseEncodeAverage), 1000);
889e098bc96SEvan Quan fRange = GetScaledFraction(le32_to_cpu(sKv_b_fuse.ulEfuseEncodeRange), 1000);
890e098bc96SEvan Quan
891e098bc96SEvan Quan fKv_b_fused = fDecodeLogisticFuse(ul_Kv_b_fused,
892e098bc96SEvan Quan fAverage, fRange, sKv_b_fuse.ucEfuseLength);
893e098bc96SEvan Quan
894e098bc96SEvan Quan /* Decoding the Leakage - No special struct container */
895e098bc96SEvan Quan /*
896e098bc96SEvan Quan * usLkgEuseIndex=56
897e098bc96SEvan Quan * ucLkgEfuseBitLSB=6
898e098bc96SEvan Quan * ucLkgEfuseLength=10
899e098bc96SEvan Quan * ulLkgEncodeLn_MaxDivMin=69077
900e098bc96SEvan Quan * ulLkgEncodeMax=1000000
901e098bc96SEvan Quan * ulLkgEncodeMin=1000
902e098bc96SEvan Quan * ulEfuseLogisticAlpha=13
903e098bc96SEvan Quan */
904e098bc96SEvan Quan
905e098bc96SEvan Quan sInput_FuseValues.usEfuseIndex = getASICProfilingInfo->usLkgEuseIndex;
906e098bc96SEvan Quan sInput_FuseValues.ucBitShift = getASICProfilingInfo->ucLkgEfuseBitLSB;
907e098bc96SEvan Quan sInput_FuseValues.ucBitLength = getASICProfilingInfo->ucLkgEfuseLength;
908e098bc96SEvan Quan
909e098bc96SEvan Quan sOutput_FuseValues.sEfuse = sInput_FuseValues;
910e098bc96SEvan Quan
911e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
912e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
913e098bc96SEvan Quan (uint32_t *)&sOutput_FuseValues);
914e098bc96SEvan Quan
915e098bc96SEvan Quan if (result)
916e098bc96SEvan Quan return result;
917e098bc96SEvan Quan
918e098bc96SEvan Quan ul_FT_Lkg_V0NORM = le32_to_cpu(sOutput_FuseValues.ulEfuseValue);
919e098bc96SEvan Quan fLn_MaxDivMin = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulLkgEncodeLn_MaxDivMin), 10000);
920e098bc96SEvan Quan fMin = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulLkgEncodeMin), 10000);
921e098bc96SEvan Quan
922e098bc96SEvan Quan fFT_Lkg_V0NORM = fDecodeLeakageID(ul_FT_Lkg_V0NORM,
923e098bc96SEvan Quan fLn_MaxDivMin, fMin, getASICProfilingInfo->ucLkgEfuseLength);
924e098bc96SEvan Quan fLkg_FT = fFT_Lkg_V0NORM;
925e098bc96SEvan Quan
926e098bc96SEvan Quan /*-------------------------------------------
927e098bc96SEvan Quan * PART 2 - Grabbing all required values
928e098bc96SEvan Quan *-------------------------------------------
929e098bc96SEvan Quan */
930e098bc96SEvan Quan fSM_A0 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A0), 1000000),
931e098bc96SEvan Quan ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A0_sign)));
932e098bc96SEvan Quan fSM_A1 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A1), 1000000),
933e098bc96SEvan Quan ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A1_sign)));
934e098bc96SEvan Quan fSM_A2 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A2), 100000),
935e098bc96SEvan Quan ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A2_sign)));
936e098bc96SEvan Quan fSM_A3 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A3), 1000000),
937e098bc96SEvan Quan ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A3_sign)));
938e098bc96SEvan Quan fSM_A4 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A4), 1000000),
939e098bc96SEvan Quan ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A4_sign)));
940e098bc96SEvan Quan fSM_A5 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A5), 1000),
941e098bc96SEvan Quan ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A5_sign)));
942e098bc96SEvan Quan fSM_A6 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A6), 1000),
943e098bc96SEvan Quan ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A6_sign)));
944e098bc96SEvan Quan fSM_A7 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A7), 1000),
945e098bc96SEvan Quan ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A7_sign)));
946e098bc96SEvan Quan
947e098bc96SEvan Quan fMargin_RO_a = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_RO_a));
948e098bc96SEvan Quan fMargin_RO_b = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_RO_b));
949e098bc96SEvan Quan fMargin_RO_c = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_RO_c));
950e098bc96SEvan Quan
951e098bc96SEvan Quan fMargin_fixed = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_fixed));
952e098bc96SEvan Quan
953e098bc96SEvan Quan fMargin_FMAX_mean = GetScaledFraction(
954e098bc96SEvan Quan le32_to_cpu(getASICProfilingInfo->ulMargin_Fmax_mean), 10000);
955e098bc96SEvan Quan fMargin_Plat_mean = GetScaledFraction(
956e098bc96SEvan Quan le32_to_cpu(getASICProfilingInfo->ulMargin_plat_mean), 10000);
957e098bc96SEvan Quan fMargin_FMAX_sigma = GetScaledFraction(
958e098bc96SEvan Quan le32_to_cpu(getASICProfilingInfo->ulMargin_Fmax_sigma), 10000);
959e098bc96SEvan Quan fMargin_Plat_sigma = GetScaledFraction(
960e098bc96SEvan Quan le32_to_cpu(getASICProfilingInfo->ulMargin_plat_sigma), 10000);
961e098bc96SEvan Quan
962e098bc96SEvan Quan fMargin_DC_sigma = GetScaledFraction(
963e098bc96SEvan Quan le32_to_cpu(getASICProfilingInfo->ulMargin_DC_sigma), 100);
964e098bc96SEvan Quan fMargin_DC_sigma = fDivide(fMargin_DC_sigma, ConvertToFraction(1000));
965e098bc96SEvan Quan
966e098bc96SEvan Quan fCACm_fused = fDivide(fCACm_fused, ConvertToFraction(100));
967e098bc96SEvan Quan fCACb_fused = fDivide(fCACb_fused, ConvertToFraction(100));
968e098bc96SEvan Quan fKt_Beta_fused = fDivide(fKt_Beta_fused, ConvertToFraction(100));
969e098bc96SEvan Quan fKv_m_fused = fNegate(fDivide(fKv_m_fused, ConvertToFraction(100)));
970e098bc96SEvan Quan fKv_b_fused = fDivide(fKv_b_fused, ConvertToFraction(10));
971e098bc96SEvan Quan
972e098bc96SEvan Quan fSclk = GetScaledFraction(sclk, 100);
973e098bc96SEvan Quan
974e098bc96SEvan Quan fV_max = fDivide(GetScaledFraction(
975e098bc96SEvan Quan le32_to_cpu(getASICProfilingInfo->ulMaxVddc), 1000), ConvertToFraction(4));
976e098bc96SEvan Quan fT_prod = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulBoardCoreTemp), 10);
977e098bc96SEvan Quan fLKG_Factor = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulEvvLkgFactor), 100);
978e098bc96SEvan Quan fT_FT = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulLeakageTemp), 10);
979e098bc96SEvan Quan fV_FT = fDivide(GetScaledFraction(
980e098bc96SEvan Quan le32_to_cpu(getASICProfilingInfo->ulLeakageVoltage), 1000), ConvertToFraction(4));
981e098bc96SEvan Quan fV_min = fDivide(GetScaledFraction(
982e098bc96SEvan Quan le32_to_cpu(getASICProfilingInfo->ulMinVddc), 1000), ConvertToFraction(4));
983e098bc96SEvan Quan
984e098bc96SEvan Quan /*-----------------------
985e098bc96SEvan Quan * PART 3
986e098bc96SEvan Quan *-----------------------
987e098bc96SEvan Quan */
988e098bc96SEvan Quan
989e098bc96SEvan Quan fA_Term = fAdd(fMargin_RO_a, fAdd(fMultiply(fSM_A4, fSclk), fSM_A5));
990e098bc96SEvan Quan fB_Term = fAdd(fAdd(fMultiply(fSM_A2, fSclk), fSM_A6), fMargin_RO_b);
991e098bc96SEvan Quan fC_Term = fAdd(fMargin_RO_c,
992e098bc96SEvan Quan fAdd(fMultiply(fSM_A0, fLkg_FT),
993e098bc96SEvan Quan fAdd(fMultiply(fSM_A1, fMultiply(fLkg_FT, fSclk)),
994e098bc96SEvan Quan fAdd(fMultiply(fSM_A3, fSclk),
995e098bc96SEvan Quan fSubtract(fSM_A7, fRO_fused)))));
996e098bc96SEvan Quan
997e098bc96SEvan Quan fVDDC_base = fSubtract(fRO_fused,
998e098bc96SEvan Quan fSubtract(fMargin_RO_c,
999e098bc96SEvan Quan fSubtract(fSM_A3, fMultiply(fSM_A1, fSclk))));
1000e098bc96SEvan Quan fVDDC_base = fDivide(fVDDC_base, fAdd(fMultiply(fSM_A0, fSclk), fSM_A2));
1001e098bc96SEvan Quan
1002e098bc96SEvan Quan repeat = fSubtract(fVDDC_base,
1003e098bc96SEvan Quan fDivide(fMargin_DC_sigma, ConvertToFraction(1000)));
1004e098bc96SEvan Quan
1005e098bc96SEvan Quan fRO_DC_margin = fAdd(fMultiply(fMargin_RO_a,
1006e098bc96SEvan Quan fGetSquare(repeat)),
1007e098bc96SEvan Quan fAdd(fMultiply(fMargin_RO_b, repeat),
1008e098bc96SEvan Quan fMargin_RO_c));
1009e098bc96SEvan Quan
1010e098bc96SEvan Quan fDC_SCLK = fSubtract(fRO_fused,
1011e098bc96SEvan Quan fSubtract(fRO_DC_margin,
1012e098bc96SEvan Quan fSubtract(fSM_A3,
1013e098bc96SEvan Quan fMultiply(fSM_A2, repeat))));
1014e098bc96SEvan Quan fDC_SCLK = fDivide(fDC_SCLK, fAdd(fMultiply(fSM_A0, repeat), fSM_A1));
1015e098bc96SEvan Quan
1016e098bc96SEvan Quan fSigma_DC = fSubtract(fSclk, fDC_SCLK);
1017e098bc96SEvan Quan
1018e098bc96SEvan Quan fMicro_FMAX = fMultiply(fSclk, fMargin_FMAX_mean);
1019e098bc96SEvan Quan fMicro_CR = fMultiply(fSclk, fMargin_Plat_mean);
1020e098bc96SEvan Quan fSigma_FMAX = fMultiply(fSclk, fMargin_FMAX_sigma);
1021e098bc96SEvan Quan fSigma_CR = fMultiply(fSclk, fMargin_Plat_sigma);
1022e098bc96SEvan Quan
1023e098bc96SEvan Quan fSquared_Sigma_DC = fGetSquare(fSigma_DC);
1024e098bc96SEvan Quan fSquared_Sigma_CR = fGetSquare(fSigma_CR);
1025e098bc96SEvan Quan fSquared_Sigma_FMAX = fGetSquare(fSigma_FMAX);
1026e098bc96SEvan Quan
1027e098bc96SEvan Quan fSclk_margin = fAdd(fMicro_FMAX,
1028e098bc96SEvan Quan fAdd(fMicro_CR,
1029e098bc96SEvan Quan fAdd(fMargin_fixed,
1030e098bc96SEvan Quan fSqrt(fAdd(fSquared_Sigma_FMAX,
1031e098bc96SEvan Quan fAdd(fSquared_Sigma_DC, fSquared_Sigma_CR))))));
1032e098bc96SEvan Quan /*
1033e098bc96SEvan Quan fA_Term = fSM_A4 * (fSclk + fSclk_margin) + fSM_A5;
1034e098bc96SEvan Quan fB_Term = fSM_A2 * (fSclk + fSclk_margin) + fSM_A6;
1035e098bc96SEvan Quan fC_Term = fRO_DC_margin + fSM_A0 * fLkg_FT + fSM_A1 * fLkg_FT * (fSclk + fSclk_margin) + fSM_A3 * (fSclk + fSclk_margin) + fSM_A7 - fRO_fused;
1036e098bc96SEvan Quan */
1037e098bc96SEvan Quan
1038e098bc96SEvan Quan fA_Term = fAdd(fMultiply(fSM_A4, fAdd(fSclk, fSclk_margin)), fSM_A5);
1039e098bc96SEvan Quan fB_Term = fAdd(fMultiply(fSM_A2, fAdd(fSclk, fSclk_margin)), fSM_A6);
1040e098bc96SEvan Quan fC_Term = fAdd(fRO_DC_margin,
1041e098bc96SEvan Quan fAdd(fMultiply(fSM_A0, fLkg_FT),
1042e098bc96SEvan Quan fAdd(fMultiply(fMultiply(fSM_A1, fLkg_FT),
1043e098bc96SEvan Quan fAdd(fSclk, fSclk_margin)),
1044e098bc96SEvan Quan fAdd(fMultiply(fSM_A3,
1045e098bc96SEvan Quan fAdd(fSclk, fSclk_margin)),
1046e098bc96SEvan Quan fSubtract(fSM_A7, fRO_fused)))));
1047e098bc96SEvan Quan
1048e098bc96SEvan Quan SolveQuadracticEqn(fA_Term, fB_Term, fC_Term, fRoots);
1049e098bc96SEvan Quan
1050e098bc96SEvan Quan if (GreaterThan(fRoots[0], fRoots[1]))
1051e098bc96SEvan Quan fEVV_V = fRoots[1];
1052e098bc96SEvan Quan else
1053e098bc96SEvan Quan fEVV_V = fRoots[0];
1054e098bc96SEvan Quan
1055e098bc96SEvan Quan if (GreaterThan(fV_min, fEVV_V))
1056e098bc96SEvan Quan fEVV_V = fV_min;
1057e098bc96SEvan Quan else if (GreaterThan(fEVV_V, fV_max))
1058e098bc96SEvan Quan fEVV_V = fSubtract(fV_max, fStepSize);
1059e098bc96SEvan Quan
1060e098bc96SEvan Quan fEVV_V = fRoundUpByStepSize(fEVV_V, fStepSize, 0);
1061e098bc96SEvan Quan
1062e098bc96SEvan Quan /*-----------------
1063e098bc96SEvan Quan * PART 4
1064e098bc96SEvan Quan *-----------------
1065e098bc96SEvan Quan */
1066e098bc96SEvan Quan
1067e098bc96SEvan Quan fV_x = fV_min;
1068e098bc96SEvan Quan
1069e098bc96SEvan Quan while (GreaterThan(fAdd(fV_max, fStepSize), fV_x)) {
1070e098bc96SEvan Quan fTDP_Power_left = fMultiply(fMultiply(fMultiply(fAdd(
1071e098bc96SEvan Quan fMultiply(fCACm_fused, fV_x), fCACb_fused), fSclk),
1072e098bc96SEvan Quan fGetSquare(fV_x)), fDerateTDP);
1073e098bc96SEvan Quan
1074e098bc96SEvan Quan fTDP_Power_right = fMultiply(fFT_Lkg_V0NORM, fMultiply(fLKG_Factor,
1075e098bc96SEvan Quan fMultiply(fExponential(fMultiply(fAdd(fMultiply(fKv_m_fused,
1076e098bc96SEvan Quan fT_prod), fKv_b_fused), fV_x)), fV_x)));
1077e098bc96SEvan Quan fTDP_Power_right = fMultiply(fTDP_Power_right, fExponential(fMultiply(
1078e098bc96SEvan Quan fKt_Beta_fused, fT_prod)));
1079e098bc96SEvan Quan fTDP_Power_right = fDivide(fTDP_Power_right, fExponential(fMultiply(
1080e098bc96SEvan Quan fAdd(fMultiply(fKv_m_fused, fT_prod), fKv_b_fused), fV_FT)));
1081e098bc96SEvan Quan fTDP_Power_right = fDivide(fTDP_Power_right, fExponential(fMultiply(
1082e098bc96SEvan Quan fKt_Beta_fused, fT_FT)));
1083e098bc96SEvan Quan
1084e098bc96SEvan Quan fTDP_Power = fAdd(fTDP_Power_left, fTDP_Power_right);
1085e098bc96SEvan Quan
1086e098bc96SEvan Quan fTDP_Current = fDivide(fTDP_Power, fV_x);
1087e098bc96SEvan Quan
1088e098bc96SEvan Quan fV_NL = fAdd(fV_x, fDivide(fMultiply(fTDP_Current, fRLL_LoadLine),
1089e098bc96SEvan Quan ConvertToFraction(10)));
1090e098bc96SEvan Quan
1091e098bc96SEvan Quan fV_NL = fRoundUpByStepSize(fV_NL, fStepSize, 0);
1092e098bc96SEvan Quan
1093e098bc96SEvan Quan if (GreaterThan(fV_max, fV_NL) &&
1094e098bc96SEvan Quan (GreaterThan(fV_NL, fEVV_V) ||
1095e098bc96SEvan Quan Equal(fV_NL, fEVV_V))) {
1096e098bc96SEvan Quan fV_NL = fMultiply(fV_NL, ConvertToFraction(1000));
1097e098bc96SEvan Quan
1098e098bc96SEvan Quan *voltage = (uint16_t)fV_NL.partial.real;
1099e098bc96SEvan Quan break;
1100e098bc96SEvan Quan } else
1101e098bc96SEvan Quan fV_x = fAdd(fV_x, fStepSize);
1102e098bc96SEvan Quan }
1103e098bc96SEvan Quan
1104e098bc96SEvan Quan return result;
1105e098bc96SEvan Quan }
1106e098bc96SEvan Quan
110758cfaf25SLee Jones /**
1108d477eb17SFabio M. De Francesco * atomctrl_get_voltage_evv_on_sclk: gets voltage via call to ATOM COMMAND table.
110958cfaf25SLee Jones * @hwmgr: input: pointer to hwManager
111058cfaf25SLee Jones * @voltage_type: input: type of EVV voltage VDDC or VDDGFX
111158cfaf25SLee Jones * @sclk: input: in 10Khz unit. DPM state SCLK frequency
1112e098bc96SEvan Quan * which is define in PPTable SCLK/VDDC dependence
1113e098bc96SEvan Quan * table associated with this virtual_voltage_Id
111458cfaf25SLee Jones * @virtual_voltage_Id: input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
111558cfaf25SLee Jones * @voltage: output: real voltage level in unit of mv
1116e098bc96SEvan Quan */
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)1117e098bc96SEvan Quan int atomctrl_get_voltage_evv_on_sclk(
1118e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
1119e098bc96SEvan Quan uint8_t voltage_type,
1120e098bc96SEvan Quan uint32_t sclk, uint16_t virtual_voltage_Id,
1121e098bc96SEvan Quan uint16_t *voltage)
1122e098bc96SEvan Quan {
1123e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
1124e098bc96SEvan Quan GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space;
1125e098bc96SEvan Quan int result;
1126e098bc96SEvan Quan
1127e098bc96SEvan Quan get_voltage_info_param_space.ucVoltageType =
1128e098bc96SEvan Quan voltage_type;
1129e098bc96SEvan Quan get_voltage_info_param_space.ucVoltageMode =
1130e098bc96SEvan Quan ATOM_GET_VOLTAGE_EVV_VOLTAGE;
1131e098bc96SEvan Quan get_voltage_info_param_space.usVoltageLevel =
1132e098bc96SEvan Quan cpu_to_le16(virtual_voltage_Id);
1133e098bc96SEvan Quan get_voltage_info_param_space.ulSCLKFreq =
1134e098bc96SEvan Quan cpu_to_le32(sclk);
1135e098bc96SEvan Quan
1136e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
1137e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, GetVoltageInfo),
1138e098bc96SEvan Quan (uint32_t *)&get_voltage_info_param_space);
1139e098bc96SEvan Quan
1140e098bc96SEvan Quan *voltage = result ? 0 :
1141e098bc96SEvan Quan le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 *)
1142e098bc96SEvan Quan (&get_voltage_info_param_space))->usVoltageLevel);
1143e098bc96SEvan Quan
1144e098bc96SEvan Quan return result;
1145e098bc96SEvan Quan }
1146e098bc96SEvan Quan
1147e098bc96SEvan Quan /**
1148d477eb17SFabio M. De Francesco * atomctrl_get_voltage_evv: gets voltage via call to ATOM COMMAND table.
114958cfaf25SLee Jones * @hwmgr: input: pointer to hwManager
115058cfaf25SLee Jones * @virtual_voltage_id: input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
115158cfaf25SLee Jones * @voltage: output: real voltage level in unit of mv
1152e098bc96SEvan Quan */
atomctrl_get_voltage_evv(struct pp_hwmgr * hwmgr,uint16_t virtual_voltage_id,uint16_t * voltage)1153e098bc96SEvan Quan int atomctrl_get_voltage_evv(struct pp_hwmgr *hwmgr,
1154e098bc96SEvan Quan uint16_t virtual_voltage_id,
1155e098bc96SEvan Quan uint16_t *voltage)
1156e098bc96SEvan Quan {
1157e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
1158e098bc96SEvan Quan GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space;
1159e098bc96SEvan Quan int result;
1160e098bc96SEvan Quan int entry_id;
1161e098bc96SEvan Quan
1162e098bc96SEvan Quan /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
1163e098bc96SEvan Quan for (entry_id = 0; entry_id < hwmgr->dyn_state.vddc_dependency_on_sclk->count; entry_id++) {
1164e098bc96SEvan Quan if (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[entry_id].v == virtual_voltage_id) {
1165e098bc96SEvan Quan /* found */
1166e098bc96SEvan Quan break;
1167e098bc96SEvan Quan }
1168e098bc96SEvan Quan }
1169e098bc96SEvan Quan
1170e098bc96SEvan Quan if (entry_id >= hwmgr->dyn_state.vddc_dependency_on_sclk->count) {
1171e098bc96SEvan Quan pr_debug("Can't find requested voltage id in vddc_dependency_on_sclk table!\n");
1172e098bc96SEvan Quan return -EINVAL;
1173e098bc96SEvan Quan }
1174e098bc96SEvan Quan
1175e098bc96SEvan Quan get_voltage_info_param_space.ucVoltageType = VOLTAGE_TYPE_VDDC;
1176e098bc96SEvan Quan get_voltage_info_param_space.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE;
1177e098bc96SEvan Quan get_voltage_info_param_space.usVoltageLevel = virtual_voltage_id;
1178e098bc96SEvan Quan get_voltage_info_param_space.ulSCLKFreq =
1179e098bc96SEvan Quan cpu_to_le32(hwmgr->dyn_state.vddc_dependency_on_sclk->entries[entry_id].clk);
1180e098bc96SEvan Quan
1181e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
1182e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, GetVoltageInfo),
1183e098bc96SEvan Quan (uint32_t *)&get_voltage_info_param_space);
1184e098bc96SEvan Quan
1185e098bc96SEvan Quan if (0 != result)
1186e098bc96SEvan Quan return result;
1187e098bc96SEvan Quan
1188e098bc96SEvan Quan *voltage = le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 *)
1189e098bc96SEvan Quan (&get_voltage_info_param_space))->usVoltageLevel);
1190e098bc96SEvan Quan
1191e098bc96SEvan Quan return result;
1192e098bc96SEvan Quan }
1193e098bc96SEvan Quan
119458cfaf25SLee Jones /*
1195e098bc96SEvan Quan * Get the mpll reference clock in 10KHz
1196e098bc96SEvan Quan */
atomctrl_get_mpll_reference_clock(struct pp_hwmgr * hwmgr)1197e098bc96SEvan Quan uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr *hwmgr)
1198e098bc96SEvan Quan {
1199e098bc96SEvan Quan ATOM_COMMON_TABLE_HEADER *fw_info;
1200e098bc96SEvan Quan uint32_t clock;
1201e098bc96SEvan Quan u8 frev, crev;
1202e098bc96SEvan Quan u16 size;
1203e098bc96SEvan Quan
1204e098bc96SEvan Quan fw_info = (ATOM_COMMON_TABLE_HEADER *)
1205e098bc96SEvan Quan smu_atom_get_data_table(hwmgr->adev,
1206e098bc96SEvan Quan GetIndexIntoMasterTable(DATA, FirmwareInfo),
1207e098bc96SEvan Quan &size, &frev, &crev);
1208e098bc96SEvan Quan
1209e098bc96SEvan Quan if (fw_info == NULL)
1210e098bc96SEvan Quan clock = 2700;
1211e098bc96SEvan Quan else {
1212e098bc96SEvan Quan if ((fw_info->ucTableFormatRevision == 2) &&
1213e098bc96SEvan Quan (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V2_1))) {
1214e098bc96SEvan Quan ATOM_FIRMWARE_INFO_V2_1 *fwInfo_2_1 =
1215e098bc96SEvan Quan (ATOM_FIRMWARE_INFO_V2_1 *)fw_info;
1216e098bc96SEvan Quan clock = (uint32_t)(le16_to_cpu(fwInfo_2_1->usMemoryReferenceClock));
1217e098bc96SEvan Quan } else {
1218e098bc96SEvan Quan ATOM_FIRMWARE_INFO *fwInfo_0_0 =
1219e098bc96SEvan Quan (ATOM_FIRMWARE_INFO *)fw_info;
1220e098bc96SEvan Quan clock = (uint32_t)(le16_to_cpu(fwInfo_0_0->usReferenceClock));
1221e098bc96SEvan Quan }
1222e098bc96SEvan Quan }
1223e098bc96SEvan Quan
1224e098bc96SEvan Quan return clock;
1225e098bc96SEvan Quan }
1226e098bc96SEvan Quan
122758cfaf25SLee Jones /*
1228e098bc96SEvan Quan * Get the asic internal spread spectrum table
1229e098bc96SEvan Quan */
asic_internal_ss_get_ss_table(void * device)1230660b3bd8SEvan Quan static ATOM_ASIC_INTERNAL_SS_INFO *asic_internal_ss_get_ss_table(void *device)
1231e098bc96SEvan Quan {
1232e098bc96SEvan Quan ATOM_ASIC_INTERNAL_SS_INFO *table = NULL;
1233e098bc96SEvan Quan u8 frev, crev;
1234e098bc96SEvan Quan u16 size;
1235e098bc96SEvan Quan
1236e098bc96SEvan Quan table = (ATOM_ASIC_INTERNAL_SS_INFO *)
1237e098bc96SEvan Quan smu_atom_get_data_table(device,
1238e098bc96SEvan Quan GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info),
1239e098bc96SEvan Quan &size, &frev, &crev);
1240e098bc96SEvan Quan
1241e098bc96SEvan Quan return table;
1242e098bc96SEvan Quan }
1243e098bc96SEvan Quan
atomctrl_is_asic_internal_ss_supported(struct pp_hwmgr * hwmgr)1244f6638d0eSEvan Quan bool atomctrl_is_asic_internal_ss_supported(struct pp_hwmgr *hwmgr)
1245f6638d0eSEvan Quan {
1246f6638d0eSEvan Quan ATOM_ASIC_INTERNAL_SS_INFO *table =
1247f6638d0eSEvan Quan asic_internal_ss_get_ss_table(hwmgr->adev);
1248f6638d0eSEvan Quan
1249f6638d0eSEvan Quan if (table)
1250f6638d0eSEvan Quan return true;
1251f6638d0eSEvan Quan else
1252f6638d0eSEvan Quan return false;
1253f6638d0eSEvan Quan }
1254f6638d0eSEvan Quan
125558cfaf25SLee Jones /*
1256e098bc96SEvan Quan * Get the asic internal spread spectrum assignment
1257e098bc96SEvan Quan */
asic_internal_ss_get_ss_asignment(struct pp_hwmgr * hwmgr,const uint8_t clockSource,const uint32_t clockSpeed,pp_atomctrl_internal_ss_info * ssEntry)1258e098bc96SEvan Quan static int asic_internal_ss_get_ss_asignment(struct pp_hwmgr *hwmgr,
1259e098bc96SEvan Quan const uint8_t clockSource,
1260e098bc96SEvan Quan const uint32_t clockSpeed,
1261e098bc96SEvan Quan pp_atomctrl_internal_ss_info *ssEntry)
1262e098bc96SEvan Quan {
1263e098bc96SEvan Quan ATOM_ASIC_INTERNAL_SS_INFO *table;
1264e098bc96SEvan Quan ATOM_ASIC_SS_ASSIGNMENT *ssInfo;
1265e098bc96SEvan Quan int entry_found = 0;
1266e098bc96SEvan Quan
1267e098bc96SEvan Quan memset(ssEntry, 0x00, sizeof(pp_atomctrl_internal_ss_info));
1268e098bc96SEvan Quan
1269e098bc96SEvan Quan table = asic_internal_ss_get_ss_table(hwmgr->adev);
1270e098bc96SEvan Quan
1271e098bc96SEvan Quan if (NULL == table)
1272e098bc96SEvan Quan return -1;
1273e098bc96SEvan Quan
1274e098bc96SEvan Quan ssInfo = &table->asSpreadSpectrum[0];
1275e098bc96SEvan Quan
1276e098bc96SEvan Quan while (((uint8_t *)ssInfo - (uint8_t *)table) <
1277e098bc96SEvan Quan le16_to_cpu(table->sHeader.usStructureSize)) {
1278e098bc96SEvan Quan if ((clockSource == ssInfo->ucClockIndication) &&
1279e098bc96SEvan Quan ((uint32_t)clockSpeed <= le32_to_cpu(ssInfo->ulTargetClockRange))) {
1280e098bc96SEvan Quan entry_found = 1;
1281e098bc96SEvan Quan break;
1282e098bc96SEvan Quan }
1283e098bc96SEvan Quan
1284e098bc96SEvan Quan ssInfo = (ATOM_ASIC_SS_ASSIGNMENT *)((uint8_t *)ssInfo +
1285e098bc96SEvan Quan sizeof(ATOM_ASIC_SS_ASSIGNMENT));
1286e098bc96SEvan Quan }
1287e098bc96SEvan Quan
1288e098bc96SEvan Quan if (entry_found) {
1289e098bc96SEvan Quan ssEntry->speed_spectrum_percentage =
1290e098bc96SEvan Quan le16_to_cpu(ssInfo->usSpreadSpectrumPercentage);
1291e098bc96SEvan Quan ssEntry->speed_spectrum_rate = le16_to_cpu(ssInfo->usSpreadRateInKhz);
1292e098bc96SEvan Quan
1293e098bc96SEvan Quan if (((GET_DATA_TABLE_MAJOR_REVISION(table) == 2) &&
1294e098bc96SEvan Quan (GET_DATA_TABLE_MINOR_REVISION(table) >= 2)) ||
1295e098bc96SEvan Quan (GET_DATA_TABLE_MAJOR_REVISION(table) == 3)) {
1296e098bc96SEvan Quan ssEntry->speed_spectrum_rate /= 100;
1297e098bc96SEvan Quan }
1298e098bc96SEvan Quan
1299e098bc96SEvan Quan switch (ssInfo->ucSpreadSpectrumMode) {
1300e098bc96SEvan Quan case 0:
1301e098bc96SEvan Quan ssEntry->speed_spectrum_mode =
1302e098bc96SEvan Quan pp_atomctrl_spread_spectrum_mode_down;
1303e098bc96SEvan Quan break;
1304e098bc96SEvan Quan case 1:
1305e098bc96SEvan Quan ssEntry->speed_spectrum_mode =
1306e098bc96SEvan Quan pp_atomctrl_spread_spectrum_mode_center;
1307e098bc96SEvan Quan break;
1308e098bc96SEvan Quan default:
1309e098bc96SEvan Quan ssEntry->speed_spectrum_mode =
1310e098bc96SEvan Quan pp_atomctrl_spread_spectrum_mode_down;
1311e098bc96SEvan Quan break;
1312e098bc96SEvan Quan }
1313e098bc96SEvan Quan }
1314e098bc96SEvan Quan
1315e098bc96SEvan Quan return entry_found ? 0 : 1;
1316e098bc96SEvan Quan }
1317e098bc96SEvan Quan
131858cfaf25SLee Jones /*
1319e098bc96SEvan Quan * Get the memory clock spread spectrum info
1320e098bc96SEvan Quan */
atomctrl_get_memory_clock_spread_spectrum(struct pp_hwmgr * hwmgr,const uint32_t memory_clock,pp_atomctrl_internal_ss_info * ssInfo)1321e098bc96SEvan Quan int atomctrl_get_memory_clock_spread_spectrum(
1322e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
1323e098bc96SEvan Quan const uint32_t memory_clock,
1324e098bc96SEvan Quan pp_atomctrl_internal_ss_info *ssInfo)
1325e098bc96SEvan Quan {
1326e098bc96SEvan Quan return asic_internal_ss_get_ss_asignment(hwmgr,
1327e098bc96SEvan Quan ASIC_INTERNAL_MEMORY_SS, memory_clock, ssInfo);
1328e098bc96SEvan Quan }
132958cfaf25SLee Jones
133058cfaf25SLee Jones /*
1331e098bc96SEvan Quan * Get the engine clock spread spectrum info
1332e098bc96SEvan Quan */
atomctrl_get_engine_clock_spread_spectrum(struct pp_hwmgr * hwmgr,const uint32_t engine_clock,pp_atomctrl_internal_ss_info * ssInfo)1333e098bc96SEvan Quan int atomctrl_get_engine_clock_spread_spectrum(
1334e098bc96SEvan Quan struct pp_hwmgr *hwmgr,
1335e098bc96SEvan Quan const uint32_t engine_clock,
1336e098bc96SEvan Quan pp_atomctrl_internal_ss_info *ssInfo)
1337e098bc96SEvan Quan {
1338e098bc96SEvan Quan return asic_internal_ss_get_ss_asignment(hwmgr,
1339e098bc96SEvan Quan ASIC_INTERNAL_ENGINE_SS, engine_clock, ssInfo);
1340e098bc96SEvan Quan }
1341e098bc96SEvan Quan
atomctrl_read_efuse(struct pp_hwmgr * hwmgr,uint16_t start_index,uint16_t end_index,uint32_t * efuse)1342e098bc96SEvan Quan int atomctrl_read_efuse(struct pp_hwmgr *hwmgr, uint16_t start_index,
1343029479acSEvan Quan uint16_t end_index, uint32_t *efuse)
1344e098bc96SEvan Quan {
1345e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
1346029479acSEvan Quan uint32_t mask;
1347e098bc96SEvan Quan int result;
1348e098bc96SEvan Quan READ_EFUSE_VALUE_PARAMETER efuse_param;
1349e098bc96SEvan Quan
1350029479acSEvan Quan if ((end_index - start_index) == 31)
1351029479acSEvan Quan mask = 0xFFFFFFFF;
1352029479acSEvan Quan else
1353029479acSEvan Quan mask = (1 << ((end_index - start_index) + 1)) - 1;
1354029479acSEvan Quan
1355e098bc96SEvan Quan efuse_param.sEfuse.usEfuseIndex = cpu_to_le16((start_index / 32) * 4);
1356e098bc96SEvan Quan efuse_param.sEfuse.ucBitShift = (uint8_t)
1357e098bc96SEvan Quan (start_index - ((start_index / 32) * 32));
1358e098bc96SEvan Quan efuse_param.sEfuse.ucBitLength = (uint8_t)
1359e098bc96SEvan Quan ((end_index - start_index) + 1);
1360e098bc96SEvan Quan
1361e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
1362e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
1363e098bc96SEvan Quan (uint32_t *)&efuse_param);
1364e098bc96SEvan Quan *efuse = result ? 0 : le32_to_cpu(efuse_param.ulEfuseValue) & mask;
1365e098bc96SEvan Quan
1366e098bc96SEvan Quan return result;
1367e098bc96SEvan Quan }
1368e098bc96SEvan Quan
atomctrl_set_ac_timing_ai(struct pp_hwmgr * hwmgr,uint32_t memory_clock,uint8_t level)1369e098bc96SEvan Quan int atomctrl_set_ac_timing_ai(struct pp_hwmgr *hwmgr, uint32_t memory_clock,
1370e098bc96SEvan Quan uint8_t level)
1371e098bc96SEvan Quan {
1372e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
1373e098bc96SEvan Quan DYNAMICE_MEMORY_SETTINGS_PARAMETER_V2_1 memory_clock_parameters;
1374e098bc96SEvan Quan int result;
1375e098bc96SEvan Quan
1376e098bc96SEvan Quan memory_clock_parameters.asDPMMCReg.ulClock.ulClockFreq =
1377e098bc96SEvan Quan memory_clock & SET_CLOCK_FREQ_MASK;
1378e098bc96SEvan Quan memory_clock_parameters.asDPMMCReg.ulClock.ulComputeClockFlag =
1379e098bc96SEvan Quan ADJUST_MC_SETTING_PARAM;
1380e098bc96SEvan Quan memory_clock_parameters.asDPMMCReg.ucMclkDPMState = level;
1381e098bc96SEvan Quan
1382e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
1383e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings),
1384e098bc96SEvan Quan (uint32_t *)&memory_clock_parameters);
1385e098bc96SEvan Quan
1386e098bc96SEvan Quan return result;
1387e098bc96SEvan Quan }
1388e098bc96SEvan Quan
atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr * hwmgr,uint8_t voltage_type,uint32_t sclk,uint16_t virtual_voltage_Id,uint32_t * voltage)1389e098bc96SEvan Quan int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
1390e098bc96SEvan Quan uint32_t sclk, uint16_t virtual_voltage_Id, uint32_t *voltage)
1391e098bc96SEvan Quan {
1392e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
1393e098bc96SEvan Quan int result;
1394e098bc96SEvan Quan GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_3 get_voltage_info_param_space;
1395e098bc96SEvan Quan
1396e098bc96SEvan Quan get_voltage_info_param_space.ucVoltageType = voltage_type;
1397e098bc96SEvan Quan get_voltage_info_param_space.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE;
1398e098bc96SEvan Quan get_voltage_info_param_space.usVoltageLevel = cpu_to_le16(virtual_voltage_Id);
1399e098bc96SEvan Quan get_voltage_info_param_space.ulSCLKFreq = cpu_to_le32(sclk);
1400e098bc96SEvan Quan
1401e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
1402e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, GetVoltageInfo),
1403e098bc96SEvan Quan (uint32_t *)&get_voltage_info_param_space);
1404e098bc96SEvan Quan
1405e098bc96SEvan Quan *voltage = result ? 0 :
1406e098bc96SEvan Quan le32_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_3 *)(&get_voltage_info_param_space))->ulVoltageLevel);
1407e098bc96SEvan Quan
1408e098bc96SEvan Quan return result;
1409e098bc96SEvan Quan }
1410e098bc96SEvan Quan
atomctrl_get_smc_sclk_range_table(struct pp_hwmgr * hwmgr,struct pp_atom_ctrl_sclk_range_table * table)1411e098bc96SEvan Quan int atomctrl_get_smc_sclk_range_table(struct pp_hwmgr *hwmgr, struct pp_atom_ctrl_sclk_range_table *table)
1412e098bc96SEvan Quan {
1413e098bc96SEvan Quan
1414e098bc96SEvan Quan int i;
1415e098bc96SEvan Quan u8 frev, crev;
1416e098bc96SEvan Quan u16 size;
1417e098bc96SEvan Quan
1418e098bc96SEvan Quan ATOM_SMU_INFO_V2_1 *psmu_info =
1419e098bc96SEvan Quan (ATOM_SMU_INFO_V2_1 *)smu_atom_get_data_table(hwmgr->adev,
1420e098bc96SEvan Quan GetIndexIntoMasterTable(DATA, SMU_Info),
1421e098bc96SEvan Quan &size, &frev, &crev);
1422e098bc96SEvan Quan
1423*6a30634aSIvan Stepchenko if (!psmu_info)
1424*6a30634aSIvan Stepchenko return -EINVAL;
1425e098bc96SEvan Quan
1426e098bc96SEvan Quan for (i = 0; i < psmu_info->ucSclkEntryNum; i++) {
1427e098bc96SEvan Quan table->entry[i].ucVco_setting = psmu_info->asSclkFcwRangeEntry[i].ucVco_setting;
1428e098bc96SEvan Quan table->entry[i].ucPostdiv = psmu_info->asSclkFcwRangeEntry[i].ucPostdiv;
1429e098bc96SEvan Quan table->entry[i].usFcw_pcc =
1430e098bc96SEvan Quan le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucFcw_pcc);
1431e098bc96SEvan Quan table->entry[i].usFcw_trans_upper =
1432e098bc96SEvan Quan le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucFcw_trans_upper);
1433e098bc96SEvan Quan table->entry[i].usRcw_trans_lower =
1434e098bc96SEvan Quan le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucRcw_trans_lower);
1435e098bc96SEvan Quan }
1436e098bc96SEvan Quan
1437e098bc96SEvan Quan return 0;
1438e098bc96SEvan Quan }
1439e098bc96SEvan Quan
atomctrl_get_vddc_shared_railinfo(struct pp_hwmgr * hwmgr,uint8_t * shared_rail)1440a8588b8bSEvan Quan int atomctrl_get_vddc_shared_railinfo(struct pp_hwmgr *hwmgr, uint8_t *shared_rail)
1441a8588b8bSEvan Quan {
1442a8588b8bSEvan Quan ATOM_SMU_INFO_V2_1 *psmu_info =
1443a8588b8bSEvan Quan (ATOM_SMU_INFO_V2_1 *)smu_atom_get_data_table(hwmgr->adev,
1444a8588b8bSEvan Quan GetIndexIntoMasterTable(DATA, SMU_Info),
1445a8588b8bSEvan Quan NULL, NULL, NULL);
1446a8588b8bSEvan Quan if (!psmu_info)
1447a8588b8bSEvan Quan return -1;
1448a8588b8bSEvan Quan
1449a8588b8bSEvan Quan *shared_rail = psmu_info->ucSharePowerSource;
1450a8588b8bSEvan Quan
1451a8588b8bSEvan Quan return 0;
1452a8588b8bSEvan Quan }
1453a8588b8bSEvan Quan
atomctrl_get_avfs_information(struct pp_hwmgr * hwmgr,struct pp_atom_ctrl__avfs_parameters * param)1454e098bc96SEvan Quan int atomctrl_get_avfs_information(struct pp_hwmgr *hwmgr,
1455e098bc96SEvan Quan struct pp_atom_ctrl__avfs_parameters *param)
1456e098bc96SEvan Quan {
1457e098bc96SEvan Quan ATOM_ASIC_PROFILING_INFO_V3_6 *profile = NULL;
1458e098bc96SEvan Quan
1459e098bc96SEvan Quan if (param == NULL)
1460e098bc96SEvan Quan return -EINVAL;
1461e098bc96SEvan Quan
1462e098bc96SEvan Quan profile = (ATOM_ASIC_PROFILING_INFO_V3_6 *)
1463e098bc96SEvan Quan smu_atom_get_data_table(hwmgr->adev,
1464e098bc96SEvan Quan GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo),
1465e098bc96SEvan Quan NULL, NULL, NULL);
1466e098bc96SEvan Quan if (!profile)
1467e098bc96SEvan Quan return -1;
1468e098bc96SEvan Quan
1469e098bc96SEvan Quan param->ulAVFS_meanNsigma_Acontant0 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant0);
1470e098bc96SEvan Quan param->ulAVFS_meanNsigma_Acontant1 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant1);
1471e098bc96SEvan Quan param->ulAVFS_meanNsigma_Acontant2 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant2);
1472e098bc96SEvan Quan param->usAVFS_meanNsigma_DC_tol_sigma = le16_to_cpu(profile->usAVFS_meanNsigma_DC_tol_sigma);
1473e098bc96SEvan Quan param->usAVFS_meanNsigma_Platform_mean = le16_to_cpu(profile->usAVFS_meanNsigma_Platform_mean);
1474e098bc96SEvan Quan param->usAVFS_meanNsigma_Platform_sigma = le16_to_cpu(profile->usAVFS_meanNsigma_Platform_sigma);
1475e098bc96SEvan Quan param->ulGB_VDROOP_TABLE_CKSOFF_a0 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a0);
1476e098bc96SEvan Quan param->ulGB_VDROOP_TABLE_CKSOFF_a1 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a1);
1477e098bc96SEvan Quan param->ulGB_VDROOP_TABLE_CKSOFF_a2 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a2);
1478e098bc96SEvan Quan param->ulGB_VDROOP_TABLE_CKSON_a0 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a0);
1479e098bc96SEvan Quan param->ulGB_VDROOP_TABLE_CKSON_a1 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a1);
1480e098bc96SEvan Quan param->ulGB_VDROOP_TABLE_CKSON_a2 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a2);
1481e098bc96SEvan Quan param->ulAVFSGB_FUSE_TABLE_CKSOFF_m1 = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSOFF_m1);
1482e098bc96SEvan Quan param->usAVFSGB_FUSE_TABLE_CKSOFF_m2 = le16_to_cpu(profile->usAVFSGB_FUSE_TABLE_CKSOFF_m2);
1483e098bc96SEvan Quan param->ulAVFSGB_FUSE_TABLE_CKSOFF_b = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSOFF_b);
1484e098bc96SEvan Quan param->ulAVFSGB_FUSE_TABLE_CKSON_m1 = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSON_m1);
1485e098bc96SEvan Quan param->usAVFSGB_FUSE_TABLE_CKSON_m2 = le16_to_cpu(profile->usAVFSGB_FUSE_TABLE_CKSON_m2);
1486e098bc96SEvan Quan param->ulAVFSGB_FUSE_TABLE_CKSON_b = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSON_b);
1487e098bc96SEvan Quan param->usMaxVoltage_0_25mv = le16_to_cpu(profile->usMaxVoltage_0_25mv);
1488e098bc96SEvan Quan param->ucEnableGB_VDROOP_TABLE_CKSOFF = profile->ucEnableGB_VDROOP_TABLE_CKSOFF;
1489e098bc96SEvan Quan param->ucEnableGB_VDROOP_TABLE_CKSON = profile->ucEnableGB_VDROOP_TABLE_CKSON;
1490e098bc96SEvan Quan param->ucEnableGB_FUSE_TABLE_CKSOFF = profile->ucEnableGB_FUSE_TABLE_CKSOFF;
1491e098bc96SEvan Quan param->ucEnableGB_FUSE_TABLE_CKSON = profile->ucEnableGB_FUSE_TABLE_CKSON;
1492e098bc96SEvan Quan param->usPSM_Age_ComFactor = le16_to_cpu(profile->usPSM_Age_ComFactor);
1493e098bc96SEvan Quan param->ucEnableApplyAVFS_CKS_OFF_Voltage = profile->ucEnableApplyAVFS_CKS_OFF_Voltage;
1494e098bc96SEvan Quan
1495e098bc96SEvan Quan return 0;
1496e098bc96SEvan Quan }
1497e098bc96SEvan Quan
atomctrl_get_svi2_info(struct pp_hwmgr * hwmgr,uint8_t voltage_type,uint8_t * svd_gpio_id,uint8_t * svc_gpio_id,uint16_t * load_line)1498e098bc96SEvan Quan int atomctrl_get_svi2_info(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
1499e098bc96SEvan Quan uint8_t *svd_gpio_id, uint8_t *svc_gpio_id,
1500e098bc96SEvan Quan uint16_t *load_line)
1501e098bc96SEvan Quan {
1502e098bc96SEvan Quan ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
1503e098bc96SEvan Quan (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->adev);
1504e098bc96SEvan Quan
1505e098bc96SEvan Quan const ATOM_VOLTAGE_OBJECT_V3 *voltage_object;
1506e098bc96SEvan Quan
1507e098bc96SEvan Quan PP_ASSERT_WITH_CODE((NULL != voltage_info),
1508e098bc96SEvan Quan "Could not find Voltage Table in BIOS.", return -EINVAL);
1509e098bc96SEvan Quan
1510e098bc96SEvan Quan voltage_object = atomctrl_lookup_voltage_type_v3
1511e098bc96SEvan Quan (voltage_info, voltage_type, VOLTAGE_OBJ_SVID2);
1512e098bc96SEvan Quan
1513e098bc96SEvan Quan *svd_gpio_id = voltage_object->asSVID2Obj.ucSVDGpioId;
1514e098bc96SEvan Quan *svc_gpio_id = voltage_object->asSVID2Obj.ucSVCGpioId;
1515e098bc96SEvan Quan *load_line = voltage_object->asSVID2Obj.usLoadLine_PSI;
1516e098bc96SEvan Quan
1517e098bc96SEvan Quan return 0;
1518e098bc96SEvan Quan }
1519e098bc96SEvan Quan
atomctrl_get_leakage_id_from_efuse(struct pp_hwmgr * hwmgr,uint16_t * virtual_voltage_id)1520e098bc96SEvan Quan int atomctrl_get_leakage_id_from_efuse(struct pp_hwmgr *hwmgr, uint16_t *virtual_voltage_id)
1521e098bc96SEvan Quan {
1522e098bc96SEvan Quan struct amdgpu_device *adev = hwmgr->adev;
1523e098bc96SEvan Quan SET_VOLTAGE_PS_ALLOCATION allocation;
1524e098bc96SEvan Quan SET_VOLTAGE_PARAMETERS_V1_3 *voltage_parameters =
1525e098bc96SEvan Quan (SET_VOLTAGE_PARAMETERS_V1_3 *)&allocation.sASICSetVoltage;
1526e098bc96SEvan Quan int result;
1527e098bc96SEvan Quan
1528e098bc96SEvan Quan voltage_parameters->ucVoltageMode = ATOM_GET_LEAKAGE_ID;
1529e098bc96SEvan Quan
1530e098bc96SEvan Quan result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
1531e098bc96SEvan Quan GetIndexIntoMasterTable(COMMAND, SetVoltage),
1532e098bc96SEvan Quan (uint32_t *)voltage_parameters);
1533e098bc96SEvan Quan
1534e098bc96SEvan Quan *virtual_voltage_id = voltage_parameters->usVoltageLevel;
1535e098bc96SEvan Quan
1536e098bc96SEvan Quan return result;
1537e098bc96SEvan Quan }
1538e098bc96SEvan Quan
atomctrl_get_leakage_vddc_base_on_leakage(struct pp_hwmgr * hwmgr,uint16_t * vddc,uint16_t * vddci,uint16_t virtual_voltage_id,uint16_t efuse_voltage_id)1539e098bc96SEvan Quan int atomctrl_get_leakage_vddc_base_on_leakage(struct pp_hwmgr *hwmgr,
1540e098bc96SEvan Quan uint16_t *vddc, uint16_t *vddci,
1541e098bc96SEvan Quan uint16_t virtual_voltage_id,
1542e098bc96SEvan Quan uint16_t efuse_voltage_id)
1543e098bc96SEvan Quan {
1544e098bc96SEvan Quan int i, j;
1545e098bc96SEvan Quan int ix;
1546e098bc96SEvan Quan u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf;
1547e098bc96SEvan Quan ATOM_ASIC_PROFILING_INFO_V2_1 *profile;
1548e098bc96SEvan Quan
1549e098bc96SEvan Quan *vddc = 0;
1550e098bc96SEvan Quan *vddci = 0;
1551e098bc96SEvan Quan
1552e098bc96SEvan Quan ix = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo);
1553e098bc96SEvan Quan
1554e098bc96SEvan Quan profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *)
1555e098bc96SEvan Quan smu_atom_get_data_table(hwmgr->adev,
1556e098bc96SEvan Quan ix,
1557e098bc96SEvan Quan NULL, NULL, NULL);
1558e098bc96SEvan Quan if (!profile)
1559e098bc96SEvan Quan return -EINVAL;
1560e098bc96SEvan Quan
1561e098bc96SEvan Quan if ((profile->asHeader.ucTableFormatRevision >= 2) &&
1562e098bc96SEvan Quan (profile->asHeader.ucTableContentRevision >= 1) &&
1563e098bc96SEvan Quan (profile->asHeader.usStructureSize >= sizeof(ATOM_ASIC_PROFILING_INFO_V2_1))) {
1564e098bc96SEvan Quan leakage_bin = (u16 *)((char *)profile + profile->usLeakageBinArrayOffset);
1565e098bc96SEvan Quan vddc_id_buf = (u16 *)((char *)profile + profile->usElbVDDC_IdArrayOffset);
1566e098bc96SEvan Quan vddc_buf = (u16 *)((char *)profile + profile->usElbVDDC_LevelArrayOffset);
1567e098bc96SEvan Quan if (profile->ucElbVDDC_Num > 0) {
1568e098bc96SEvan Quan for (i = 0; i < profile->ucElbVDDC_Num; i++) {
1569e098bc96SEvan Quan if (vddc_id_buf[i] == virtual_voltage_id) {
1570e098bc96SEvan Quan for (j = 0; j < profile->ucLeakageBinNum; j++) {
1571e098bc96SEvan Quan if (efuse_voltage_id <= leakage_bin[j]) {
1572e098bc96SEvan Quan *vddc = vddc_buf[j * profile->ucElbVDDC_Num + i];
1573e098bc96SEvan Quan break;
1574e098bc96SEvan Quan }
1575e098bc96SEvan Quan }
1576e098bc96SEvan Quan break;
1577e098bc96SEvan Quan }
1578e098bc96SEvan Quan }
1579e098bc96SEvan Quan }
1580e098bc96SEvan Quan
1581e098bc96SEvan Quan vddci_id_buf = (u16 *)((char *)profile + profile->usElbVDDCI_IdArrayOffset);
1582e098bc96SEvan Quan vddci_buf = (u16 *)((char *)profile + profile->usElbVDDCI_LevelArrayOffset);
1583e098bc96SEvan Quan if (profile->ucElbVDDCI_Num > 0) {
1584e098bc96SEvan Quan for (i = 0; i < profile->ucElbVDDCI_Num; i++) {
1585e098bc96SEvan Quan if (vddci_id_buf[i] == virtual_voltage_id) {
1586e098bc96SEvan Quan for (j = 0; j < profile->ucLeakageBinNum; j++) {
1587e098bc96SEvan Quan if (efuse_voltage_id <= leakage_bin[j]) {
1588e098bc96SEvan Quan *vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i];
1589e098bc96SEvan Quan break;
1590e098bc96SEvan Quan }
1591e098bc96SEvan Quan }
1592e098bc96SEvan Quan break;
1593e098bc96SEvan Quan }
1594e098bc96SEvan Quan }
1595e098bc96SEvan Quan }
1596e098bc96SEvan Quan }
1597e098bc96SEvan Quan
1598e098bc96SEvan Quan return 0;
1599e098bc96SEvan Quan }
1600e098bc96SEvan Quan
atomctrl_get_voltage_range(struct pp_hwmgr * hwmgr,uint32_t * max_vddc,uint32_t * min_vddc)1601e098bc96SEvan Quan void atomctrl_get_voltage_range(struct pp_hwmgr *hwmgr, uint32_t *max_vddc,
1602e098bc96SEvan Quan uint32_t *min_vddc)
1603e098bc96SEvan Quan {
1604e098bc96SEvan Quan void *profile;
1605e098bc96SEvan Quan
1606e098bc96SEvan Quan profile = smu_atom_get_data_table(hwmgr->adev,
1607e098bc96SEvan Quan GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo),
1608e098bc96SEvan Quan NULL, NULL, NULL);
1609e098bc96SEvan Quan
1610e098bc96SEvan Quan if (profile) {
1611e098bc96SEvan Quan switch (hwmgr->chip_id) {
1612e098bc96SEvan Quan case CHIP_TONGA:
1613e098bc96SEvan Quan case CHIP_FIJI:
1614e098bc96SEvan Quan *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMaxVddc) / 4;
1615e098bc96SEvan Quan *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMinVddc) / 4;
1616e098bc96SEvan Quan return;
1617e098bc96SEvan Quan case CHIP_POLARIS11:
1618e098bc96SEvan Quan case CHIP_POLARIS10:
1619e098bc96SEvan Quan case CHIP_POLARIS12:
1620e098bc96SEvan Quan *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMaxVddc) / 100;
1621e098bc96SEvan Quan *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMinVddc) / 100;
1622e098bc96SEvan Quan return;
1623e098bc96SEvan Quan default:
1624e098bc96SEvan Quan break;
1625e098bc96SEvan Quan }
1626e098bc96SEvan Quan }
1627e098bc96SEvan Quan *max_vddc = 0;
1628e098bc96SEvan Quan *min_vddc = 0;
1629e098bc96SEvan Quan }
16308f0804c6SEvan Quan
atomctrl_get_edc_hilo_leakage_offset_table(struct pp_hwmgr * hwmgr,AtomCtrl_HiLoLeakageOffsetTable * table)16318f0804c6SEvan Quan int atomctrl_get_edc_hilo_leakage_offset_table(struct pp_hwmgr *hwmgr,
16328f0804c6SEvan Quan AtomCtrl_HiLoLeakageOffsetTable *table)
16338f0804c6SEvan Quan {
16348f0804c6SEvan Quan ATOM_GFX_INFO_V2_3 *gfxinfo = smu_atom_get_data_table(hwmgr->adev,
16358f0804c6SEvan Quan GetIndexIntoMasterTable(DATA, GFX_Info),
16368f0804c6SEvan Quan NULL, NULL, NULL);
16378f0804c6SEvan Quan if (!gfxinfo)
16388f0804c6SEvan Quan return -ENOENT;
16398f0804c6SEvan Quan
16408f0804c6SEvan Quan table->usHiLoLeakageThreshold = gfxinfo->usHiLoLeakageThreshold;
16418f0804c6SEvan Quan table->usEdcDidtLoDpm7TableOffset = gfxinfo->usEdcDidtLoDpm7TableOffset;
16428f0804c6SEvan Quan table->usEdcDidtHiDpm7TableOffset = gfxinfo->usEdcDidtHiDpm7TableOffset;
16438f0804c6SEvan Quan
16448f0804c6SEvan Quan return 0;
16458f0804c6SEvan Quan }
16468f0804c6SEvan Quan
get_edc_leakage_table(struct pp_hwmgr * hwmgr,uint16_t offset)16478f0804c6SEvan Quan static AtomCtrl_EDCLeakgeTable *get_edc_leakage_table(struct pp_hwmgr *hwmgr,
16488f0804c6SEvan Quan uint16_t offset)
16498f0804c6SEvan Quan {
16508f0804c6SEvan Quan void *table_address;
16518f0804c6SEvan Quan char *temp;
16528f0804c6SEvan Quan
16538f0804c6SEvan Quan table_address = smu_atom_get_data_table(hwmgr->adev,
16548f0804c6SEvan Quan GetIndexIntoMasterTable(DATA, GFX_Info),
16558f0804c6SEvan Quan NULL, NULL, NULL);
16568f0804c6SEvan Quan if (!table_address)
16578f0804c6SEvan Quan return NULL;
16588f0804c6SEvan Quan
16598f0804c6SEvan Quan temp = (char *)table_address;
16608f0804c6SEvan Quan table_address += offset;
16618f0804c6SEvan Quan
16628f0804c6SEvan Quan return (AtomCtrl_EDCLeakgeTable *)temp;
16638f0804c6SEvan Quan }
16648f0804c6SEvan Quan
atomctrl_get_edc_leakage_table(struct pp_hwmgr * hwmgr,AtomCtrl_EDCLeakgeTable * table,uint16_t offset)16658f0804c6SEvan Quan int atomctrl_get_edc_leakage_table(struct pp_hwmgr *hwmgr,
16668f0804c6SEvan Quan AtomCtrl_EDCLeakgeTable *table,
16678f0804c6SEvan Quan uint16_t offset)
16688f0804c6SEvan Quan {
16698f0804c6SEvan Quan uint32_t length, i;
16708f0804c6SEvan Quan AtomCtrl_EDCLeakgeTable *leakage_table =
16718f0804c6SEvan Quan get_edc_leakage_table(hwmgr, offset);
16728f0804c6SEvan Quan
16738f0804c6SEvan Quan if (!leakage_table)
16748f0804c6SEvan Quan return -ENOENT;
16758f0804c6SEvan Quan
16768f0804c6SEvan Quan length = sizeof(leakage_table->DIDT_REG) /
16778f0804c6SEvan Quan sizeof(leakage_table->DIDT_REG[0]);
16788f0804c6SEvan Quan for (i = 0; i < length; i++)
16798f0804c6SEvan Quan table->DIDT_REG[i] = leakage_table->DIDT_REG[i];
16808f0804c6SEvan Quan
16818f0804c6SEvan Quan return 0;
16828f0804c6SEvan Quan }
1683