xref: /linux/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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) {
76*12c69674SJesse 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 = &reg_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),
2304630d503SAlexander Richards 			(uint32_t *)&engine_clock_parameters, sizeof(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),
3014630d503SAlexander Richards 		(uint32_t *)&mpll_parameters, sizeof(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),
3494630d503SAlexander Richards 			(uint32_t *)&mpll_parameters, sizeof(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),
3704630d503SAlexander Richards 			(uint32_t *)&mpll_parameters, sizeof(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),
4004630d503SAlexander Richards 		(uint32_t *)&pll_parameters, sizeof(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),
4244630d503SAlexander Richards 		(uint32_t *)&pll_patameters, sizeof(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),
4614630d503SAlexander Richards 		(uint32_t *)&pll_patameters, sizeof(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),
4944630d503SAlexander Richards 		(uint32_t *)&pll_patameters, sizeof(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),
7774630d503SAlexander Richards 			(uint32_t *)&sOutput_FuseValues, sizeof(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),
7984630d503SAlexander Richards 			(uint32_t *)&sOutput_FuseValues, sizeof(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),
8184630d503SAlexander Richards 			(uint32_t *)&sOutput_FuseValues, sizeof(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),
8394630d503SAlexander Richards 			(uint32_t *)&sOutput_FuseValues, sizeof(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),
8614630d503SAlexander Richards 			(uint32_t *)&sOutput_FuseValues, sizeof(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),
8824630d503SAlexander Richards 			(uint32_t *)&sOutput_FuseValues, sizeof(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),
9134630d503SAlexander Richards 			(uint32_t *)&sOutput_FuseValues, sizeof(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),
11384630d503SAlexander Richards 			(uint32_t *)&get_voltage_info_param_space, sizeof(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),
11834630d503SAlexander Richards 			(uint32_t *)&get_voltage_info_param_space, sizeof(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),
13634630d503SAlexander Richards 			(uint32_t *)&efuse_param, sizeof(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),
13844630d503SAlexander Richards 		(uint32_t *)&memory_clock_parameters, sizeof(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),
14034630d503SAlexander Richards 			(uint32_t *)&get_voltage_info_param_space, sizeof(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 
1423e098bc96SEvan Quan 
1424e098bc96SEvan Quan 	for (i = 0; i < psmu_info->ucSclkEntryNum; i++) {
1425e098bc96SEvan Quan 		table->entry[i].ucVco_setting = psmu_info->asSclkFcwRangeEntry[i].ucVco_setting;
1426e098bc96SEvan Quan 		table->entry[i].ucPostdiv = psmu_info->asSclkFcwRangeEntry[i].ucPostdiv;
1427e098bc96SEvan Quan 		table->entry[i].usFcw_pcc =
1428e098bc96SEvan Quan 			le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucFcw_pcc);
1429e098bc96SEvan Quan 		table->entry[i].usFcw_trans_upper =
1430e098bc96SEvan Quan 			le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucFcw_trans_upper);
1431e098bc96SEvan Quan 		table->entry[i].usRcw_trans_lower =
1432e098bc96SEvan Quan 			le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucRcw_trans_lower);
1433e098bc96SEvan Quan 	}
1434e098bc96SEvan Quan 
1435e098bc96SEvan Quan 	return 0;
1436e098bc96SEvan Quan }
1437e098bc96SEvan Quan 
atomctrl_get_vddc_shared_railinfo(struct pp_hwmgr * hwmgr,uint8_t * shared_rail)1438a8588b8bSEvan Quan int atomctrl_get_vddc_shared_railinfo(struct pp_hwmgr *hwmgr, uint8_t *shared_rail)
1439a8588b8bSEvan Quan {
1440a8588b8bSEvan Quan 	ATOM_SMU_INFO_V2_1 *psmu_info =
1441a8588b8bSEvan Quan 		(ATOM_SMU_INFO_V2_1 *)smu_atom_get_data_table(hwmgr->adev,
1442a8588b8bSEvan Quan 			GetIndexIntoMasterTable(DATA, SMU_Info),
1443a8588b8bSEvan Quan 			NULL, NULL, NULL);
1444a8588b8bSEvan Quan 	if (!psmu_info)
1445a8588b8bSEvan Quan 		return -1;
1446a8588b8bSEvan Quan 
1447a8588b8bSEvan Quan 	*shared_rail = psmu_info->ucSharePowerSource;
1448a8588b8bSEvan Quan 
1449a8588b8bSEvan Quan 	return 0;
1450a8588b8bSEvan Quan }
1451a8588b8bSEvan Quan 
atomctrl_get_avfs_information(struct pp_hwmgr * hwmgr,struct pp_atom_ctrl__avfs_parameters * param)1452e098bc96SEvan Quan int atomctrl_get_avfs_information(struct pp_hwmgr *hwmgr,
1453e098bc96SEvan Quan 				  struct pp_atom_ctrl__avfs_parameters *param)
1454e098bc96SEvan Quan {
1455e098bc96SEvan Quan 	ATOM_ASIC_PROFILING_INFO_V3_6 *profile = NULL;
1456e098bc96SEvan Quan 
1457e098bc96SEvan Quan 	if (param == NULL)
1458e098bc96SEvan Quan 		return -EINVAL;
1459e098bc96SEvan Quan 
1460e098bc96SEvan Quan 	profile = (ATOM_ASIC_PROFILING_INFO_V3_6 *)
1461e098bc96SEvan Quan 			smu_atom_get_data_table(hwmgr->adev,
1462e098bc96SEvan Quan 					GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo),
1463e098bc96SEvan Quan 					NULL, NULL, NULL);
1464e098bc96SEvan Quan 	if (!profile)
1465e098bc96SEvan Quan 		return -1;
1466e098bc96SEvan Quan 
1467e098bc96SEvan Quan 	param->ulAVFS_meanNsigma_Acontant0 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant0);
1468e098bc96SEvan Quan 	param->ulAVFS_meanNsigma_Acontant1 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant1);
1469e098bc96SEvan Quan 	param->ulAVFS_meanNsigma_Acontant2 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant2);
1470e098bc96SEvan Quan 	param->usAVFS_meanNsigma_DC_tol_sigma = le16_to_cpu(profile->usAVFS_meanNsigma_DC_tol_sigma);
1471e098bc96SEvan Quan 	param->usAVFS_meanNsigma_Platform_mean = le16_to_cpu(profile->usAVFS_meanNsigma_Platform_mean);
1472e098bc96SEvan Quan 	param->usAVFS_meanNsigma_Platform_sigma = le16_to_cpu(profile->usAVFS_meanNsigma_Platform_sigma);
1473e098bc96SEvan Quan 	param->ulGB_VDROOP_TABLE_CKSOFF_a0 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a0);
1474e098bc96SEvan Quan 	param->ulGB_VDROOP_TABLE_CKSOFF_a1 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a1);
1475e098bc96SEvan Quan 	param->ulGB_VDROOP_TABLE_CKSOFF_a2 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a2);
1476e098bc96SEvan Quan 	param->ulGB_VDROOP_TABLE_CKSON_a0 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a0);
1477e098bc96SEvan Quan 	param->ulGB_VDROOP_TABLE_CKSON_a1 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a1);
1478e098bc96SEvan Quan 	param->ulGB_VDROOP_TABLE_CKSON_a2 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a2);
1479e098bc96SEvan Quan 	param->ulAVFSGB_FUSE_TABLE_CKSOFF_m1 = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSOFF_m1);
1480e098bc96SEvan Quan 	param->usAVFSGB_FUSE_TABLE_CKSOFF_m2 = le16_to_cpu(profile->usAVFSGB_FUSE_TABLE_CKSOFF_m2);
1481e098bc96SEvan Quan 	param->ulAVFSGB_FUSE_TABLE_CKSOFF_b = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSOFF_b);
1482e098bc96SEvan Quan 	param->ulAVFSGB_FUSE_TABLE_CKSON_m1 = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSON_m1);
1483e098bc96SEvan Quan 	param->usAVFSGB_FUSE_TABLE_CKSON_m2 = le16_to_cpu(profile->usAVFSGB_FUSE_TABLE_CKSON_m2);
1484e098bc96SEvan Quan 	param->ulAVFSGB_FUSE_TABLE_CKSON_b = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSON_b);
1485e098bc96SEvan Quan 	param->usMaxVoltage_0_25mv = le16_to_cpu(profile->usMaxVoltage_0_25mv);
1486e098bc96SEvan Quan 	param->ucEnableGB_VDROOP_TABLE_CKSOFF = profile->ucEnableGB_VDROOP_TABLE_CKSOFF;
1487e098bc96SEvan Quan 	param->ucEnableGB_VDROOP_TABLE_CKSON = profile->ucEnableGB_VDROOP_TABLE_CKSON;
1488e098bc96SEvan Quan 	param->ucEnableGB_FUSE_TABLE_CKSOFF = profile->ucEnableGB_FUSE_TABLE_CKSOFF;
1489e098bc96SEvan Quan 	param->ucEnableGB_FUSE_TABLE_CKSON = profile->ucEnableGB_FUSE_TABLE_CKSON;
1490e098bc96SEvan Quan 	param->usPSM_Age_ComFactor = le16_to_cpu(profile->usPSM_Age_ComFactor);
1491e098bc96SEvan Quan 	param->ucEnableApplyAVFS_CKS_OFF_Voltage = profile->ucEnableApplyAVFS_CKS_OFF_Voltage;
1492e098bc96SEvan Quan 
1493e098bc96SEvan Quan 	return 0;
1494e098bc96SEvan Quan }
1495e098bc96SEvan 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)1496e098bc96SEvan Quan int  atomctrl_get_svi2_info(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
1497e098bc96SEvan Quan 				uint8_t *svd_gpio_id, uint8_t *svc_gpio_id,
1498e098bc96SEvan Quan 				uint16_t *load_line)
1499e098bc96SEvan Quan {
1500e098bc96SEvan Quan 	ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
1501e098bc96SEvan Quan 		(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->adev);
1502e098bc96SEvan Quan 
1503e098bc96SEvan Quan 	const ATOM_VOLTAGE_OBJECT_V3 *voltage_object;
1504e098bc96SEvan Quan 
1505e098bc96SEvan Quan 	PP_ASSERT_WITH_CODE((NULL != voltage_info),
1506e098bc96SEvan Quan 			"Could not find Voltage Table in BIOS.", return -EINVAL);
1507e098bc96SEvan Quan 
1508e098bc96SEvan Quan 	voltage_object = atomctrl_lookup_voltage_type_v3
1509e098bc96SEvan Quan 		(voltage_info, voltage_type,  VOLTAGE_OBJ_SVID2);
1510e098bc96SEvan Quan 
1511e098bc96SEvan Quan 	*svd_gpio_id = voltage_object->asSVID2Obj.ucSVDGpioId;
1512e098bc96SEvan Quan 	*svc_gpio_id = voltage_object->asSVID2Obj.ucSVCGpioId;
1513e098bc96SEvan Quan 	*load_line = voltage_object->asSVID2Obj.usLoadLine_PSI;
1514e098bc96SEvan Quan 
1515e098bc96SEvan Quan 	return 0;
1516e098bc96SEvan Quan }
1517e098bc96SEvan Quan 
atomctrl_get_leakage_id_from_efuse(struct pp_hwmgr * hwmgr,uint16_t * virtual_voltage_id)1518e098bc96SEvan Quan int atomctrl_get_leakage_id_from_efuse(struct pp_hwmgr *hwmgr, uint16_t *virtual_voltage_id)
1519e098bc96SEvan Quan {
1520e098bc96SEvan Quan 	struct amdgpu_device *adev = hwmgr->adev;
1521e098bc96SEvan Quan 	SET_VOLTAGE_PS_ALLOCATION allocation;
1522e098bc96SEvan Quan 	SET_VOLTAGE_PARAMETERS_V1_3 *voltage_parameters =
1523e098bc96SEvan Quan 			(SET_VOLTAGE_PARAMETERS_V1_3 *)&allocation.sASICSetVoltage;
1524e098bc96SEvan Quan 	int result;
1525e098bc96SEvan Quan 
1526e098bc96SEvan Quan 	voltage_parameters->ucVoltageMode = ATOM_GET_LEAKAGE_ID;
1527e098bc96SEvan Quan 
1528e098bc96SEvan Quan 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
1529e098bc96SEvan Quan 			GetIndexIntoMasterTable(COMMAND, SetVoltage),
15303e221746SSamasth Norway Ananda 			(uint32_t *)voltage_parameters, sizeof(*voltage_parameters));
1531e098bc96SEvan Quan 
1532e098bc96SEvan Quan 	*virtual_voltage_id = voltage_parameters->usVoltageLevel;
1533e098bc96SEvan Quan 
1534e098bc96SEvan Quan 	return result;
1535e098bc96SEvan Quan }
1536e098bc96SEvan 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)1537e098bc96SEvan Quan int atomctrl_get_leakage_vddc_base_on_leakage(struct pp_hwmgr *hwmgr,
1538e098bc96SEvan Quan 					uint16_t *vddc, uint16_t *vddci,
1539e098bc96SEvan Quan 					uint16_t virtual_voltage_id,
1540e098bc96SEvan Quan 					uint16_t efuse_voltage_id)
1541e098bc96SEvan Quan {
1542e098bc96SEvan Quan 	int i, j;
1543e098bc96SEvan Quan 	int ix;
1544e098bc96SEvan Quan 	u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf;
1545e098bc96SEvan Quan 	ATOM_ASIC_PROFILING_INFO_V2_1 *profile;
1546e098bc96SEvan Quan 
1547e098bc96SEvan Quan 	*vddc = 0;
1548e098bc96SEvan Quan 	*vddci = 0;
1549e098bc96SEvan Quan 
1550e098bc96SEvan Quan 	ix = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo);
1551e098bc96SEvan Quan 
1552e098bc96SEvan Quan 	profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *)
1553e098bc96SEvan Quan 			smu_atom_get_data_table(hwmgr->adev,
1554e098bc96SEvan Quan 					ix,
1555e098bc96SEvan Quan 					NULL, NULL, NULL);
1556e098bc96SEvan Quan 	if (!profile)
1557e098bc96SEvan Quan 		return -EINVAL;
1558e098bc96SEvan Quan 
1559e098bc96SEvan Quan 	if ((profile->asHeader.ucTableFormatRevision >= 2) &&
1560e098bc96SEvan Quan 		(profile->asHeader.ucTableContentRevision >= 1) &&
1561e098bc96SEvan Quan 		(profile->asHeader.usStructureSize >= sizeof(ATOM_ASIC_PROFILING_INFO_V2_1))) {
1562e098bc96SEvan Quan 		leakage_bin = (u16 *)((char *)profile + profile->usLeakageBinArrayOffset);
1563e098bc96SEvan Quan 		vddc_id_buf = (u16 *)((char *)profile + profile->usElbVDDC_IdArrayOffset);
1564e098bc96SEvan Quan 		vddc_buf = (u16 *)((char *)profile + profile->usElbVDDC_LevelArrayOffset);
1565e098bc96SEvan Quan 		if (profile->ucElbVDDC_Num > 0) {
1566e098bc96SEvan Quan 			for (i = 0; i < profile->ucElbVDDC_Num; i++) {
1567e098bc96SEvan Quan 				if (vddc_id_buf[i] == virtual_voltage_id) {
1568e098bc96SEvan Quan 					for (j = 0; j < profile->ucLeakageBinNum; j++) {
1569e098bc96SEvan Quan 						if (efuse_voltage_id <= leakage_bin[j]) {
1570e098bc96SEvan Quan 							*vddc = vddc_buf[j * profile->ucElbVDDC_Num + i];
1571e098bc96SEvan Quan 							break;
1572e098bc96SEvan Quan 						}
1573e098bc96SEvan Quan 					}
1574e098bc96SEvan Quan 					break;
1575e098bc96SEvan Quan 				}
1576e098bc96SEvan Quan 			}
1577e098bc96SEvan Quan 		}
1578e098bc96SEvan Quan 
1579e098bc96SEvan Quan 		vddci_id_buf = (u16 *)((char *)profile + profile->usElbVDDCI_IdArrayOffset);
1580e098bc96SEvan Quan 		vddci_buf   = (u16 *)((char *)profile + profile->usElbVDDCI_LevelArrayOffset);
1581e098bc96SEvan Quan 		if (profile->ucElbVDDCI_Num > 0) {
1582e098bc96SEvan Quan 			for (i = 0; i < profile->ucElbVDDCI_Num; i++) {
1583e098bc96SEvan Quan 				if (vddci_id_buf[i] == virtual_voltage_id) {
1584e098bc96SEvan Quan 					for (j = 0; j < profile->ucLeakageBinNum; j++) {
1585e098bc96SEvan Quan 						if (efuse_voltage_id <= leakage_bin[j]) {
1586e098bc96SEvan Quan 							*vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i];
1587e098bc96SEvan Quan 							break;
1588e098bc96SEvan Quan 						}
1589e098bc96SEvan Quan 					}
1590e098bc96SEvan Quan 					break;
1591e098bc96SEvan Quan 				}
1592e098bc96SEvan Quan 			}
1593e098bc96SEvan Quan 		}
1594e098bc96SEvan Quan 	}
1595e098bc96SEvan Quan 
1596e098bc96SEvan Quan 	return 0;
1597e098bc96SEvan Quan }
1598e098bc96SEvan Quan 
atomctrl_get_voltage_range(struct pp_hwmgr * hwmgr,uint32_t * max_vddc,uint32_t * min_vddc)1599e098bc96SEvan Quan void atomctrl_get_voltage_range(struct pp_hwmgr *hwmgr, uint32_t *max_vddc,
1600e098bc96SEvan Quan 							uint32_t *min_vddc)
1601e098bc96SEvan Quan {
1602e098bc96SEvan Quan 	void *profile;
1603e098bc96SEvan Quan 
1604e098bc96SEvan Quan 	profile = smu_atom_get_data_table(hwmgr->adev,
1605e098bc96SEvan Quan 					GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo),
1606e098bc96SEvan Quan 					NULL, NULL, NULL);
1607e098bc96SEvan Quan 
1608e098bc96SEvan Quan 	if (profile) {
1609e098bc96SEvan Quan 		switch (hwmgr->chip_id) {
1610e098bc96SEvan Quan 		case CHIP_TONGA:
1611e098bc96SEvan Quan 		case CHIP_FIJI:
1612e098bc96SEvan Quan 			*max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMaxVddc) / 4;
1613e098bc96SEvan Quan 			*min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMinVddc) / 4;
1614e098bc96SEvan Quan 			return;
1615e098bc96SEvan Quan 		case CHIP_POLARIS11:
1616e098bc96SEvan Quan 		case CHIP_POLARIS10:
1617e098bc96SEvan Quan 		case CHIP_POLARIS12:
1618e098bc96SEvan Quan 			*max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMaxVddc) / 100;
1619e098bc96SEvan Quan 			*min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMinVddc) / 100;
1620e098bc96SEvan Quan 			return;
1621e098bc96SEvan Quan 		default:
1622e098bc96SEvan Quan 			break;
1623e098bc96SEvan Quan 		}
1624e098bc96SEvan Quan 	}
1625e098bc96SEvan Quan 	*max_vddc = 0;
1626e098bc96SEvan Quan 	*min_vddc = 0;
1627e098bc96SEvan Quan }
16288f0804c6SEvan Quan 
atomctrl_get_edc_hilo_leakage_offset_table(struct pp_hwmgr * hwmgr,AtomCtrl_HiLoLeakageOffsetTable * table)16298f0804c6SEvan Quan int atomctrl_get_edc_hilo_leakage_offset_table(struct pp_hwmgr *hwmgr,
16308f0804c6SEvan Quan 					       AtomCtrl_HiLoLeakageOffsetTable *table)
16318f0804c6SEvan Quan {
16328f0804c6SEvan Quan 	ATOM_GFX_INFO_V2_3 *gfxinfo = smu_atom_get_data_table(hwmgr->adev,
16338f0804c6SEvan Quan 					GetIndexIntoMasterTable(DATA, GFX_Info),
16348f0804c6SEvan Quan 					NULL, NULL, NULL);
16358f0804c6SEvan Quan 	if (!gfxinfo)
16368f0804c6SEvan Quan 		return -ENOENT;
16378f0804c6SEvan Quan 
16388f0804c6SEvan Quan 	table->usHiLoLeakageThreshold = gfxinfo->usHiLoLeakageThreshold;
16398f0804c6SEvan Quan 	table->usEdcDidtLoDpm7TableOffset = gfxinfo->usEdcDidtLoDpm7TableOffset;
16408f0804c6SEvan Quan 	table->usEdcDidtHiDpm7TableOffset = gfxinfo->usEdcDidtHiDpm7TableOffset;
16418f0804c6SEvan Quan 
16428f0804c6SEvan Quan 	return 0;
16438f0804c6SEvan Quan }
16448f0804c6SEvan Quan 
get_edc_leakage_table(struct pp_hwmgr * hwmgr,uint16_t offset)16458f0804c6SEvan Quan static AtomCtrl_EDCLeakgeTable *get_edc_leakage_table(struct pp_hwmgr *hwmgr,
16468f0804c6SEvan Quan 						      uint16_t offset)
16478f0804c6SEvan Quan {
16488f0804c6SEvan Quan 	void *table_address;
16498f0804c6SEvan Quan 	char *temp;
16508f0804c6SEvan Quan 
16518f0804c6SEvan Quan 	table_address = smu_atom_get_data_table(hwmgr->adev,
16528f0804c6SEvan Quan 			GetIndexIntoMasterTable(DATA, GFX_Info),
16538f0804c6SEvan Quan 			NULL, NULL, NULL);
16548f0804c6SEvan Quan 	if (!table_address)
16558f0804c6SEvan Quan 		return NULL;
16568f0804c6SEvan Quan 
16578f0804c6SEvan Quan 	temp = (char *)table_address;
16588f0804c6SEvan Quan 	table_address += offset;
16598f0804c6SEvan Quan 
16608f0804c6SEvan Quan 	return (AtomCtrl_EDCLeakgeTable *)temp;
16618f0804c6SEvan Quan }
16628f0804c6SEvan Quan 
atomctrl_get_edc_leakage_table(struct pp_hwmgr * hwmgr,AtomCtrl_EDCLeakgeTable * table,uint16_t offset)16638f0804c6SEvan Quan int atomctrl_get_edc_leakage_table(struct pp_hwmgr *hwmgr,
16648f0804c6SEvan Quan 				   AtomCtrl_EDCLeakgeTable *table,
16658f0804c6SEvan Quan 				   uint16_t offset)
16668f0804c6SEvan Quan {
16678f0804c6SEvan Quan 	uint32_t length, i;
16688f0804c6SEvan Quan 	AtomCtrl_EDCLeakgeTable *leakage_table =
16698f0804c6SEvan Quan 		get_edc_leakage_table(hwmgr, offset);
16708f0804c6SEvan Quan 
16718f0804c6SEvan Quan 	if (!leakage_table)
16728f0804c6SEvan Quan 		return -ENOENT;
16738f0804c6SEvan Quan 
16748f0804c6SEvan Quan 	length = sizeof(leakage_table->DIDT_REG) /
16758f0804c6SEvan Quan 		 sizeof(leakage_table->DIDT_REG[0]);
16768f0804c6SEvan Quan 	for (i = 0; i < length; i++)
16778f0804c6SEvan Quan 		table->DIDT_REG[i] = leakage_table->DIDT_REG[i];
16788f0804c6SEvan Quan 
16798f0804c6SEvan Quan 	return 0;
16808f0804c6SEvan Quan }
1681