xref: /linux/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
1 /*
2  * Copyright 2015 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  */
23 #include "pp_debug.h"
24 #include <linux/module.h>
25 #include <linux/slab.h>
26 #include <linux/delay.h>
27 #include "atom.h"
28 #include "ppatomctrl.h"
29 #include "atombios.h"
30 #include "cgs_common.h"
31 
32 #define MEM_ID_MASK           0xff000000
33 #define MEM_ID_SHIFT          24
34 #define CLOCK_RANGE_MASK      0x00ffffff
35 #define CLOCK_RANGE_SHIFT     0
36 #define LOW_NIBBLE_MASK       0xf
37 #define DATA_EQU_PREV         0
38 #define DATA_FROM_TABLE       4
39 
40 union voltage_object_info {
41 	struct _ATOM_VOLTAGE_OBJECT_INFO v1;
42 	struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
43 	struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;
44 };
45 
46 static int atomctrl_retrieve_ac_timing(
47 		uint8_t index,
48 		ATOM_INIT_REG_BLOCK *reg_block,
49 		u8 *table_end,
50 		pp_atomctrl_mc_reg_table *table)
51 {
52 	uint32_t i, j;
53 	u16 stride = le16_to_cpu(reg_block->usRegDataBlkSize);
54 	uint8_t tmem_id;
55 	ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
56 		((uint8_t *)reg_block + (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block->usRegIndexTblSize));
57 
58 	uint8_t num_ranges = 0;
59 
60 	if (stride < sizeof(uint32_t))
61 		return -EINVAL;
62 
63 	while ((uint8_t *)reg_data + sizeof(uint32_t) <= table_end &&
64 	       *(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK &&
65 			num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES) {
66 		tmem_id = (uint8_t)((*(uint32_t *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
67 
68 		if (index == tmem_id) {
69 			table->mc_reg_table_entry[num_ranges].mclk_max =
70 				(uint32_t)((*(uint32_t *)reg_data & CLOCK_RANGE_MASK) >>
71 						CLOCK_RANGE_SHIFT);
72 
73 			for (i = 0, j = 1; i < table->last; i++) {
74 				if ((table->mc_reg_address[i].uc_pre_reg_data &
75 							LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
76 					if ((uint8_t *)reg_data +
77 					    (j + 1) * sizeof(uint32_t) > table_end)
78 						return -EINVAL;
79 
80 					table->mc_reg_table_entry[num_ranges].mc_data[i] =
81 						(uint32_t)*((uint32_t *)reg_data + j);
82 					j++;
83 				} else if ((table->mc_reg_address[i].uc_pre_reg_data &
84 							LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
85 					if (i)
86 						table->mc_reg_table_entry[num_ranges].mc_data[i] =
87 							table->mc_reg_table_entry[num_ranges].mc_data[i-1];
88 				}
89 			}
90 			num_ranges++;
91 		}
92 
93 		reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
94 			((uint8_t *)reg_data + stride);
95 	}
96 
97 	if ((uint8_t *)reg_data + sizeof(uint32_t) > table_end ||
98 	    *(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK)
99 		return -EINVAL;
100 
101 	table->num_entries = num_ranges;
102 
103 	return 0;
104 }
105 
106 /**
107  * atomctrl_set_mc_reg_address_table - Get memory clock AC timing registers index from VBIOS table
108  * VBIOS set end of memory clock AC timing registers by ucPreRegDataLength bit6 = 1
109  * @reg_block: the address ATOM_INIT_REG_BLOCK
110  * @table: the address of MCRegTable
111  * Return:   0
112  */
113 static int atomctrl_set_mc_reg_address_table(
114 		ATOM_INIT_REG_BLOCK *reg_block,
115 		pp_atomctrl_mc_reg_table *table)
116 {
117 	uint8_t i = 0;
118 	uint8_t num_entries = (uint8_t)((le16_to_cpu(reg_block->usRegIndexTblSize))
119 			/ sizeof(ATOM_INIT_REG_INDEX_FORMAT));
120 	ATOM_INIT_REG_INDEX_FORMAT *format = &reg_block->asRegIndexBuf[0];
121 
122 	num_entries--;        /* subtract 1 data end mark entry */
123 
124 	PP_ASSERT_WITH_CODE((num_entries <= VBIOS_MC_REGISTER_ARRAY_SIZE),
125 			"Invalid VramInfo table.", return -1);
126 
127 	/* ucPreRegDataLength bit6 = 1 is the end of memory clock AC timing registers */
128 	while ((!(format->ucPreRegDataLength & ACCESS_PLACEHOLDER)) &&
129 			(i < num_entries)) {
130 		table->mc_reg_address[i].s1 =
131 			(uint16_t)(le16_to_cpu(format->usRegIndex));
132 		table->mc_reg_address[i].uc_pre_reg_data =
133 			format->ucPreRegDataLength;
134 
135 		i++;
136 		format = (ATOM_INIT_REG_INDEX_FORMAT *)
137 			((uint8_t *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
138 	}
139 
140 	table->last = i;
141 	return 0;
142 }
143 
144 int atomctrl_initialize_mc_reg_table(
145 		struct pp_hwmgr *hwmgr,
146 		uint8_t module_index,
147 		pp_atomctrl_mc_reg_table *table)
148 {
149 	ATOM_VRAM_INFO_HEADER_V2_1 *vram_info;
150 	ATOM_INIT_REG_BLOCK *reg_block;
151 	u8 *table_end;
152 	int result = 0;
153 	u8 frev, crev;
154 	u16 size;
155 
156 	vram_info = (ATOM_VRAM_INFO_HEADER_V2_1 *)
157 		smu_atom_get_data_table(hwmgr->adev,
158 				GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev);
159 	if (!vram_info) {
160 		pr_err("Could not retrieve the VramInfo table!");
161 		return -EINVAL;
162 	}
163 
164 	if (module_index >= vram_info->ucNumOfVRAMModule) {
165 		pr_err("Invalid VramInfo table.");
166 		result = -1;
167 	} else if (vram_info->sHeader.ucTableFormatRevision < 2) {
168 		pr_err("Invalid VramInfo table.");
169 		result = -1;
170 	}
171 
172 	if (0 == result) {
173 		table_end = (uint8_t *)vram_info + size;
174 		reg_block = (ATOM_INIT_REG_BLOCK *)
175 			((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
176 		result = atomctrl_set_mc_reg_address_table(reg_block, table);
177 	}
178 
179 	if (0 == result) {
180 		result = atomctrl_retrieve_ac_timing(module_index,
181 					reg_block, table_end, table);
182 	}
183 
184 	return result;
185 }
186 
187 int atomctrl_initialize_mc_reg_table_v2_2(
188 		struct pp_hwmgr *hwmgr,
189 		uint8_t module_index,
190 		pp_atomctrl_mc_reg_table *table)
191 {
192 	ATOM_VRAM_INFO_HEADER_V2_2 *vram_info;
193 	ATOM_INIT_REG_BLOCK *reg_block;
194 	u8 *table_end;
195 	int result = 0;
196 	u8 frev, crev;
197 	u16 size;
198 
199 	vram_info = (ATOM_VRAM_INFO_HEADER_V2_2 *)
200 		smu_atom_get_data_table(hwmgr->adev,
201 				GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev);
202 	if (!vram_info) {
203 		pr_err("Could not retrieve the VramInfo table!");
204 		return -EINVAL;
205 	}
206 
207 	if (module_index >= vram_info->ucNumOfVRAMModule) {
208 		pr_err("Invalid VramInfo table.");
209 		result = -1;
210 	} else if (vram_info->sHeader.ucTableFormatRevision < 2) {
211 		pr_err("Invalid VramInfo table.");
212 		result = -1;
213 	}
214 
215 	if (0 == result) {
216 		table_end = (uint8_t *)vram_info + size;
217 		reg_block = (ATOM_INIT_REG_BLOCK *)
218 			((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
219 		result = atomctrl_set_mc_reg_address_table(reg_block, table);
220 	}
221 
222 	if (0 == result) {
223 		result = atomctrl_retrieve_ac_timing(module_index,
224 					reg_block, table_end, table);
225 	}
226 
227 	return result;
228 }
229 
230 /*
231  * Set DRAM timings based on engine clock and memory clock.
232  */
233 int atomctrl_set_engine_dram_timings_rv770(
234 		struct pp_hwmgr *hwmgr,
235 		uint32_t engine_clock,
236 		uint32_t memory_clock)
237 {
238 	struct amdgpu_device *adev = hwmgr->adev;
239 
240 	SET_ENGINE_CLOCK_PS_ALLOCATION engine_clock_parameters;
241 
242 	/* They are both in 10KHz Units. */
243 	engine_clock_parameters.ulTargetEngineClock =
244 		cpu_to_le32((engine_clock & SET_CLOCK_FREQ_MASK) |
245 			    ((COMPUTE_ENGINE_PLL_PARAM << 24)));
246 
247 	/* in 10 khz units.*/
248 	engine_clock_parameters.sReserved.ulClock =
249 		cpu_to_le32(memory_clock & SET_CLOCK_FREQ_MASK);
250 
251 	return amdgpu_atom_execute_table(adev->mode_info.atom_context,
252 			GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings),
253 			(uint32_t *)&engine_clock_parameters, sizeof(engine_clock_parameters));
254 }
255 
256 /*
257  * Private Function to get the PowerPlay Table Address.
258  * WARNING: The tabled returned by this function is in
259  * dynamically allocated memory.
260  * The caller has to release if by calling kfree.
261  */
262 static ATOM_VOLTAGE_OBJECT_INFO *get_voltage_info_table(void *device)
263 {
264 	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
265 	u8 frev, crev;
266 	u16 size;
267 	union voltage_object_info *voltage_info;
268 
269 	voltage_info = (union voltage_object_info *)
270 		smu_atom_get_data_table(device, index,
271 			&size, &frev, &crev);
272 
273 	if (voltage_info != NULL)
274 		return (ATOM_VOLTAGE_OBJECT_INFO *) &(voltage_info->v3);
275 	else
276 		return NULL;
277 }
278 
279 static const ATOM_VOLTAGE_OBJECT_V3 *atomctrl_lookup_voltage_type_v3(
280 		const ATOM_VOLTAGE_OBJECT_INFO_V3_1 * voltage_object_info_table,
281 		uint8_t voltage_type, uint8_t voltage_mode)
282 {
283 	unsigned int size = le16_to_cpu(voltage_object_info_table->sHeader.usStructureSize);
284 	unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
285 	uint8_t *start = (uint8_t *)voltage_object_info_table;
286 
287 	while (offset + sizeof(ATOM_VOLTAGE_OBJECT_HEADER_V3) <= size) {
288 		const ATOM_VOLTAGE_OBJECT_V3 *voltage_object =
289 			(const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
290 		u16 obj_size;
291 
292 		obj_size = le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize);
293 		if (obj_size < sizeof(voltage_object->asGpioVoltageObj.sHeader) ||
294 		    offset + obj_size > size)
295 			break;
296 
297 		if (voltage_type == voltage_object->asGpioVoltageObj.sHeader.ucVoltageType &&
298 			voltage_mode == voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode)
299 			return voltage_object;
300 
301 		offset += obj_size;
302 	}
303 
304 	return NULL;
305 }
306 
307 /**
308  * atomctrl_get_memory_pll_dividers_si
309  *
310  * @hwmgr:           input parameter: pointer to HwMgr
311  * @clock_value:     input parameter: memory clock
312  * @mpll_param:      output parameter: memory clock parameters
313  * @strobe_mode:     input parameter: 1 for strobe mode,  0 for performance mode
314  */
315 int atomctrl_get_memory_pll_dividers_si(
316 		struct pp_hwmgr *hwmgr,
317 		uint32_t clock_value,
318 		pp_atomctrl_memory_clock_param *mpll_param,
319 		bool strobe_mode)
320 {
321 	struct amdgpu_device *adev = hwmgr->adev;
322 	COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 mpll_parameters;
323 	int result;
324 
325 	mpll_parameters.ulClock = cpu_to_le32(clock_value);
326 	mpll_parameters.ucInputFlag = (uint8_t)((strobe_mode) ? 1 : 0);
327 
328 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
329 		 GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
330 		(uint32_t *)&mpll_parameters, sizeof(mpll_parameters));
331 
332 	if (0 == result) {
333 		mpll_param->mpll_fb_divider.clk_frac =
334 			le16_to_cpu(mpll_parameters.ulFbDiv.usFbDivFrac);
335 		mpll_param->mpll_fb_divider.cl_kf =
336 			le16_to_cpu(mpll_parameters.ulFbDiv.usFbDiv);
337 		mpll_param->mpll_post_divider =
338 			(uint32_t)mpll_parameters.ucPostDiv;
339 		mpll_param->vco_mode =
340 			(uint32_t)(mpll_parameters.ucPllCntlFlag &
341 					MPLL_CNTL_FLAG_VCO_MODE_MASK);
342 		mpll_param->yclk_sel =
343 			(uint32_t)((mpll_parameters.ucPllCntlFlag &
344 						MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0);
345 		mpll_param->qdr =
346 			(uint32_t)((mpll_parameters.ucPllCntlFlag &
347 						MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0);
348 		mpll_param->half_rate =
349 			(uint32_t)((mpll_parameters.ucPllCntlFlag &
350 						MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0);
351 		mpll_param->dll_speed =
352 			(uint32_t)(mpll_parameters.ucDllSpeed);
353 		mpll_param->bw_ctrl =
354 			(uint32_t)(mpll_parameters.ucBWCntl);
355 	}
356 
357 	return result;
358 }
359 
360 /**
361  * atomctrl_get_memory_pll_dividers_vi
362  *
363  * @hwmgr:                 input parameter: pointer to HwMgr
364  * @clock_value:           input parameter: memory clock
365  * @mpll_param:            output parameter: memory clock parameters
366  */
367 int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr *hwmgr,
368 		uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param)
369 {
370 	struct amdgpu_device *adev = hwmgr->adev;
371 	COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2 mpll_parameters;
372 	int result;
373 
374 	mpll_parameters.ulClock.ulClock = cpu_to_le32(clock_value);
375 
376 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
377 			GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
378 			(uint32_t *)&mpll_parameters, sizeof(mpll_parameters));
379 
380 	if (!result)
381 		mpll_param->mpll_post_divider =
382 				(uint32_t)mpll_parameters.ulClock.ucPostDiv;
383 
384 	return result;
385 }
386 
387 int atomctrl_get_memory_pll_dividers_ai(struct pp_hwmgr *hwmgr,
388 					uint32_t clock_value,
389 					pp_atomctrl_memory_clock_param_ai *mpll_param)
390 {
391 	struct amdgpu_device *adev = hwmgr->adev;
392 	COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_3 mpll_parameters = {{0}, 0, 0};
393 	int result;
394 
395 	mpll_parameters.ulClock.ulClock = cpu_to_le32(clock_value);
396 
397 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
398 			GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam),
399 			(uint32_t *)&mpll_parameters, sizeof(mpll_parameters));
400 
401 	/* VEGAM's mpll takes sometime to finish computing */
402 	udelay(10);
403 
404 	if (!result) {
405 		mpll_param->ulMclk_fcw_int =
406 			le16_to_cpu(mpll_parameters.usMclk_fcw_int);
407 		mpll_param->ulMclk_fcw_frac =
408 			le16_to_cpu(mpll_parameters.usMclk_fcw_frac);
409 		mpll_param->ulClock =
410 			le32_to_cpu(mpll_parameters.ulClock.ulClock);
411 		mpll_param->ulPostDiv = mpll_parameters.ulClock.ucPostDiv;
412 	}
413 
414 	return result;
415 }
416 
417 int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr *hwmgr,
418 					  uint32_t clock_value,
419 					  pp_atomctrl_clock_dividers_kong *dividers)
420 {
421 	struct amdgpu_device *adev = hwmgr->adev;
422 	COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 pll_parameters;
423 	int result;
424 
425 	pll_parameters.ulClock = cpu_to_le32(clock_value);
426 
427 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
428 		 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
429 		(uint32_t *)&pll_parameters, sizeof(pll_parameters));
430 
431 	if (0 == result) {
432 		dividers->pll_post_divider = pll_parameters.ucPostDiv;
433 		dividers->real_clock = le32_to_cpu(pll_parameters.ulClock);
434 	}
435 
436 	return result;
437 }
438 
439 int atomctrl_get_engine_pll_dividers_vi(
440 		struct pp_hwmgr *hwmgr,
441 		uint32_t clock_value,
442 		pp_atomctrl_clock_dividers_vi *dividers)
443 {
444 	struct amdgpu_device *adev = hwmgr->adev;
445 	COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters;
446 	int result;
447 
448 	pll_patameters.ulClock.ulClock = cpu_to_le32(clock_value);
449 	pll_patameters.ulClock.ucPostDiv = COMPUTE_GPUCLK_INPUT_FLAG_SCLK;
450 
451 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
452 		 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
453 		(uint32_t *)&pll_patameters, sizeof(pll_patameters));
454 
455 	if (0 == result) {
456 		dividers->pll_post_divider =
457 			pll_patameters.ulClock.ucPostDiv;
458 		dividers->real_clock =
459 			le32_to_cpu(pll_patameters.ulClock.ulClock);
460 
461 		dividers->ul_fb_div.ul_fb_div_frac =
462 			le16_to_cpu(pll_patameters.ulFbDiv.usFbDivFrac);
463 		dividers->ul_fb_div.ul_fb_div =
464 			le16_to_cpu(pll_patameters.ulFbDiv.usFbDiv);
465 
466 		dividers->uc_pll_ref_div =
467 			pll_patameters.ucPllRefDiv;
468 		dividers->uc_pll_post_div =
469 			pll_patameters.ucPllPostDiv;
470 		dividers->uc_pll_cntl_flag =
471 			pll_patameters.ucPllCntlFlag;
472 	}
473 
474 	return result;
475 }
476 
477 int atomctrl_get_engine_pll_dividers_ai(struct pp_hwmgr *hwmgr,
478 		uint32_t clock_value,
479 		pp_atomctrl_clock_dividers_ai *dividers)
480 {
481 	struct amdgpu_device *adev = hwmgr->adev;
482 	COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_7 pll_patameters;
483 	int result;
484 
485 	pll_patameters.ulClock.ulClock = cpu_to_le32(clock_value);
486 	pll_patameters.ulClock.ucPostDiv = COMPUTE_GPUCLK_INPUT_FLAG_SCLK;
487 
488 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
489 		 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
490 		(uint32_t *)&pll_patameters, sizeof(pll_patameters));
491 
492 	if (0 == result) {
493 		dividers->usSclk_fcw_frac     = le16_to_cpu(pll_patameters.usSclk_fcw_frac);
494 		dividers->usSclk_fcw_int      = le16_to_cpu(pll_patameters.usSclk_fcw_int);
495 		dividers->ucSclkPostDiv       = pll_patameters.ucSclkPostDiv;
496 		dividers->ucSclkVcoMode       = pll_patameters.ucSclkVcoMode;
497 		dividers->ucSclkPllRange      = pll_patameters.ucSclkPllRange;
498 		dividers->ucSscEnable         = pll_patameters.ucSscEnable;
499 		dividers->usSsc_fcw1_frac     = le16_to_cpu(pll_patameters.usSsc_fcw1_frac);
500 		dividers->usSsc_fcw1_int      = le16_to_cpu(pll_patameters.usSsc_fcw1_int);
501 		dividers->usPcc_fcw_int       = le16_to_cpu(pll_patameters.usPcc_fcw_int);
502 		dividers->usSsc_fcw_slew_frac = le16_to_cpu(pll_patameters.usSsc_fcw_slew_frac);
503 		dividers->usPcc_fcw_slew_frac = le16_to_cpu(pll_patameters.usPcc_fcw_slew_frac);
504 	}
505 	return result;
506 }
507 
508 int atomctrl_get_dfs_pll_dividers_vi(
509 		struct pp_hwmgr *hwmgr,
510 		uint32_t clock_value,
511 		pp_atomctrl_clock_dividers_vi *dividers)
512 {
513 	struct amdgpu_device *adev = hwmgr->adev;
514 	COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters;
515 	int result;
516 
517 	pll_patameters.ulClock.ulClock = cpu_to_le32(clock_value);
518 	pll_patameters.ulClock.ucPostDiv =
519 		COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK;
520 
521 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
522 		 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL),
523 		(uint32_t *)&pll_patameters, sizeof(pll_patameters));
524 
525 	if (0 == result) {
526 		dividers->pll_post_divider =
527 			pll_patameters.ulClock.ucPostDiv;
528 		dividers->real_clock =
529 			le32_to_cpu(pll_patameters.ulClock.ulClock);
530 
531 		dividers->ul_fb_div.ul_fb_div_frac =
532 			le16_to_cpu(pll_patameters.ulFbDiv.usFbDivFrac);
533 		dividers->ul_fb_div.ul_fb_div =
534 			le16_to_cpu(pll_patameters.ulFbDiv.usFbDiv);
535 
536 		dividers->uc_pll_ref_div =
537 			pll_patameters.ucPllRefDiv;
538 		dividers->uc_pll_post_div =
539 			pll_patameters.ucPllPostDiv;
540 		dividers->uc_pll_cntl_flag =
541 			pll_patameters.ucPllCntlFlag;
542 	}
543 
544 	return result;
545 }
546 
547 /*
548  * Get the reference clock in 10KHz
549  */
550 uint32_t atomctrl_get_reference_clock(struct pp_hwmgr *hwmgr)
551 {
552 	ATOM_FIRMWARE_INFO *fw_info;
553 	u8 frev, crev;
554 	u16 size;
555 	uint32_t clock;
556 
557 	fw_info = (ATOM_FIRMWARE_INFO *)
558 		smu_atom_get_data_table(hwmgr->adev,
559 			GetIndexIntoMasterTable(DATA, FirmwareInfo),
560 			&size, &frev, &crev);
561 
562 	if (fw_info == NULL)
563 		clock = 2700;
564 	else
565 		clock = (uint32_t)(le16_to_cpu(fw_info->usReferenceClock));
566 
567 	return clock;
568 }
569 
570 /*
571  * Returns true if the given voltage type is controlled by GPIO pins.
572  * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC,
573  * SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ.
574  * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE
575  */
576 bool atomctrl_is_voltage_controlled_by_gpio_v3(
577 		struct pp_hwmgr *hwmgr,
578 		uint8_t voltage_type,
579 		uint8_t voltage_mode)
580 {
581 	ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
582 		(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->adev);
583 	bool ret;
584 
585 	PP_ASSERT_WITH_CODE((NULL != voltage_info),
586 			"Could not find Voltage Table in BIOS.", return false;);
587 
588 	ret = atomctrl_lookup_voltage_type_v3
589 			(voltage_info, voltage_type, voltage_mode) != NULL;
590 
591 	return ret;
592 }
593 
594 int atomctrl_get_voltage_table_v3(
595 		struct pp_hwmgr *hwmgr,
596 		uint8_t voltage_type,
597 		uint8_t voltage_mode,
598 		pp_atomctrl_voltage_table *voltage_table)
599 {
600 	ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
601 		(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->adev);
602 	const ATOM_VOLTAGE_OBJECT_V3 *voltage_object;
603 	unsigned int i;
604 
605 	PP_ASSERT_WITH_CODE((NULL != voltage_info),
606 			"Could not find Voltage Table in BIOS.", return -1;);
607 
608 	voltage_object = atomctrl_lookup_voltage_type_v3
609 		(voltage_info, voltage_type, voltage_mode);
610 
611 	if (voltage_object == NULL)
612 		return -1;
613 
614 	PP_ASSERT_WITH_CODE(
615 			(voltage_object->asGpioVoltageObj.ucGpioEntryNum <=
616 			PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES),
617 			"Too many voltage entries!",
618 			return -1;
619 			);
620 
621 	for (i = 0; i < voltage_object->asGpioVoltageObj.ucGpioEntryNum; i++) {
622 		voltage_table->entries[i].value =
623 			le16_to_cpu(voltage_object->asGpioVoltageObj.asVolGpioLut[i].usVoltageValue);
624 		voltage_table->entries[i].smio_low =
625 			le32_to_cpu(voltage_object->asGpioVoltageObj.asVolGpioLut[i].ulVoltageId);
626 	}
627 
628 	voltage_table->mask_low    =
629 		le32_to_cpu(voltage_object->asGpioVoltageObj.ulGpioMaskVal);
630 	voltage_table->count      =
631 		voltage_object->asGpioVoltageObj.ucGpioEntryNum;
632 	voltage_table->phase_delay =
633 		voltage_object->asGpioVoltageObj.ucPhaseDelay;
634 
635 	return 0;
636 }
637 
638 static bool atomctrl_lookup_gpio_pin(
639 		ATOM_GPIO_PIN_LUT * gpio_lookup_table,
640 		const uint32_t pinId,
641 		pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment)
642 {
643 	unsigned int size = le16_to_cpu(gpio_lookup_table->sHeader.usStructureSize);
644 	unsigned int offset = offsetof(ATOM_GPIO_PIN_LUT, asGPIO_Pin[0]);
645 	uint8_t *start = (uint8_t *)gpio_lookup_table;
646 
647 	while (offset < size) {
648 		const ATOM_GPIO_PIN_ASSIGNMENT *pin_assignment =
649 			(const ATOM_GPIO_PIN_ASSIGNMENT *)(start + offset);
650 
651 		if (pinId == pin_assignment->ucGPIO_ID) {
652 			gpio_pin_assignment->uc_gpio_pin_bit_shift =
653 				pin_assignment->ucGpioPinBitShift;
654 			gpio_pin_assignment->us_gpio_pin_aindex =
655 				le16_to_cpu(pin_assignment->usGpioPin_AIndex);
656 			return true;
657 		}
658 
659 		offset += offsetof(ATOM_GPIO_PIN_ASSIGNMENT, ucGPIO_ID) + 1;
660 	}
661 
662 	return false;
663 }
664 
665 /*
666  * Private Function to get the PowerPlay Table Address.
667  * WARNING: The tabled returned by this function is in
668  * dynamically allocated memory.
669  * The caller has to release if by calling kfree.
670  */
671 static ATOM_GPIO_PIN_LUT *get_gpio_lookup_table(void *device)
672 {
673 	u8 frev, crev;
674 	u16 size;
675 	void *table_address;
676 
677 	table_address = (ATOM_GPIO_PIN_LUT *)
678 		smu_atom_get_data_table(device,
679 				GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT),
680 				&size, &frev, &crev);
681 
682 	PP_ASSERT_WITH_CODE((NULL != table_address),
683 			"Error retrieving BIOS Table Address!", return NULL;);
684 
685 	return (ATOM_GPIO_PIN_LUT *)table_address;
686 }
687 
688 /*
689  * Returns 1 if the given pin id find in lookup table.
690  */
691 bool atomctrl_get_pp_assign_pin(
692 		struct pp_hwmgr *hwmgr,
693 		const uint32_t pinId,
694 		pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment)
695 {
696 	bool bRet = false;
697 	ATOM_GPIO_PIN_LUT *gpio_lookup_table =
698 		get_gpio_lookup_table(hwmgr->adev);
699 
700 	PP_ASSERT_WITH_CODE((NULL != gpio_lookup_table),
701 			"Could not find GPIO lookup Table in BIOS.", return false);
702 
703 	bRet = atomctrl_lookup_gpio_pin(gpio_lookup_table, pinId,
704 		gpio_pin_assignment);
705 
706 	return bRet;
707 }
708 
709 /**
710  * atomctrl_get_voltage_evv_on_sclk: gets voltage via call to ATOM COMMAND table.
711  * @hwmgr:              input: pointer to hwManager
712  * @voltage_type:       input: type of EVV voltage VDDC or VDDGFX
713  * @sclk:               input: in 10Khz unit. DPM state SCLK frequency
714  *		         which is define in PPTable SCLK/VDDC dependence
715  *			 table associated with this virtual_voltage_Id
716  * @virtual_voltage_Id: input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
717  * @voltage: 	        output: real voltage level in unit of mv
718  */
719 int atomctrl_get_voltage_evv_on_sclk(
720 		struct pp_hwmgr *hwmgr,
721 		uint8_t voltage_type,
722 		uint32_t sclk, uint16_t virtual_voltage_Id,
723 		uint16_t *voltage)
724 {
725 	struct amdgpu_device *adev = hwmgr->adev;
726 	GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space;
727 	int result;
728 
729 	get_voltage_info_param_space.ucVoltageType   =
730 		voltage_type;
731 	get_voltage_info_param_space.ucVoltageMode   =
732 		ATOM_GET_VOLTAGE_EVV_VOLTAGE;
733 	get_voltage_info_param_space.usVoltageLevel  =
734 		cpu_to_le16(virtual_voltage_Id);
735 	get_voltage_info_param_space.ulSCLKFreq      =
736 		cpu_to_le32(sclk);
737 
738 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
739 			GetIndexIntoMasterTable(COMMAND, GetVoltageInfo),
740 			(uint32_t *)&get_voltage_info_param_space, sizeof(get_voltage_info_param_space));
741 
742 	*voltage = result ? 0 :
743 			le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 *)
744 				(&get_voltage_info_param_space))->usVoltageLevel);
745 
746 	return result;
747 }
748 
749 /**
750  * atomctrl_get_voltage_evv: gets voltage via call to ATOM COMMAND table.
751  * @hwmgr:              input: pointer to hwManager
752  * @virtual_voltage_id: input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
753  * @voltage: 	       output: real voltage level in unit of mv
754  */
755 int atomctrl_get_voltage_evv(struct pp_hwmgr *hwmgr,
756 			     uint16_t virtual_voltage_id,
757 			     uint16_t *voltage)
758 {
759 	struct amdgpu_device *adev = hwmgr->adev;
760 	GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space;
761 	int result;
762 	int entry_id;
763 
764 	/* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
765 	for (entry_id = 0; entry_id < hwmgr->dyn_state.vddc_dependency_on_sclk->count; entry_id++) {
766 		if (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[entry_id].v == virtual_voltage_id) {
767 			/* found */
768 			break;
769 		}
770 	}
771 
772 	if (entry_id >= hwmgr->dyn_state.vddc_dependency_on_sclk->count) {
773 	        pr_debug("Can't find requested voltage id in vddc_dependency_on_sclk table!\n");
774 	        return -EINVAL;
775 	}
776 
777 	get_voltage_info_param_space.ucVoltageType = VOLTAGE_TYPE_VDDC;
778 	get_voltage_info_param_space.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE;
779 	get_voltage_info_param_space.usVoltageLevel = virtual_voltage_id;
780 	get_voltage_info_param_space.ulSCLKFreq =
781 		cpu_to_le32(hwmgr->dyn_state.vddc_dependency_on_sclk->entries[entry_id].clk);
782 
783 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
784 			GetIndexIntoMasterTable(COMMAND, GetVoltageInfo),
785 			(uint32_t *)&get_voltage_info_param_space, sizeof(get_voltage_info_param_space));
786 
787 	if (0 != result)
788 		return result;
789 
790 	*voltage = le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 *)
791 				(&get_voltage_info_param_space))->usVoltageLevel);
792 
793 	return result;
794 }
795 
796 /*
797  * Get the mpll reference clock in 10KHz
798  */
799 uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr *hwmgr)
800 {
801 	ATOM_COMMON_TABLE_HEADER *fw_info;
802 	uint32_t clock;
803 	u8 frev, crev;
804 	u16 size;
805 
806 	fw_info = (ATOM_COMMON_TABLE_HEADER *)
807 		smu_atom_get_data_table(hwmgr->adev,
808 				GetIndexIntoMasterTable(DATA, FirmwareInfo),
809 				&size, &frev, &crev);
810 
811 	if (fw_info == NULL)
812 		clock = 2700;
813 	else {
814 		if ((fw_info->ucTableFormatRevision == 2) &&
815 			(le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V2_1))) {
816 			ATOM_FIRMWARE_INFO_V2_1 *fwInfo_2_1 =
817 				(ATOM_FIRMWARE_INFO_V2_1 *)fw_info;
818 			clock = (uint32_t)(le16_to_cpu(fwInfo_2_1->usMemoryReferenceClock));
819 		} else {
820 			ATOM_FIRMWARE_INFO *fwInfo_0_0 =
821 				(ATOM_FIRMWARE_INFO *)fw_info;
822 			clock = (uint32_t)(le16_to_cpu(fwInfo_0_0->usReferenceClock));
823 		}
824 	}
825 
826 	return clock;
827 }
828 
829 /*
830  * Get the asic internal spread spectrum table
831  */
832 static ATOM_ASIC_INTERNAL_SS_INFO *asic_internal_ss_get_ss_table(void *device)
833 {
834 	ATOM_ASIC_INTERNAL_SS_INFO *table = NULL;
835 	u8 frev, crev;
836 	u16 size;
837 
838 	table = (ATOM_ASIC_INTERNAL_SS_INFO *)
839 		smu_atom_get_data_table(device,
840 			GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info),
841 			&size, &frev, &crev);
842 
843 	return table;
844 }
845 
846 bool atomctrl_is_asic_internal_ss_supported(struct pp_hwmgr *hwmgr)
847 {
848 	ATOM_ASIC_INTERNAL_SS_INFO *table =
849 		asic_internal_ss_get_ss_table(hwmgr->adev);
850 
851 	if (table)
852 		return true;
853 	else
854 		return false;
855 }
856 
857 /*
858  * Get the asic internal spread spectrum assignment
859  */
860 static int asic_internal_ss_get_ss_asignment(struct pp_hwmgr *hwmgr,
861 		const uint8_t clockSource,
862 		const uint32_t clockSpeed,
863 		pp_atomctrl_internal_ss_info *ssEntry)
864 {
865 	ATOM_ASIC_INTERNAL_SS_INFO *table;
866 	ATOM_ASIC_SS_ASSIGNMENT *ssInfo;
867 	int entry_found = 0;
868 
869 	memset(ssEntry, 0x00, sizeof(pp_atomctrl_internal_ss_info));
870 
871 	table = asic_internal_ss_get_ss_table(hwmgr->adev);
872 
873 	if (NULL == table)
874 		return -1;
875 
876 	ssInfo = &table->asSpreadSpectrum[0];
877 
878 	while (((uint8_t *)ssInfo - (uint8_t *)table) <
879 		le16_to_cpu(table->sHeader.usStructureSize)) {
880 		if ((clockSource == ssInfo->ucClockIndication) &&
881 			((uint32_t)clockSpeed <= le32_to_cpu(ssInfo->ulTargetClockRange))) {
882 			entry_found = 1;
883 			break;
884 		}
885 
886 		ssInfo = (ATOM_ASIC_SS_ASSIGNMENT *)((uint8_t *)ssInfo +
887 				sizeof(ATOM_ASIC_SS_ASSIGNMENT));
888 	}
889 
890 	if (entry_found) {
891 		ssEntry->speed_spectrum_percentage =
892 			le16_to_cpu(ssInfo->usSpreadSpectrumPercentage);
893 		ssEntry->speed_spectrum_rate = le16_to_cpu(ssInfo->usSpreadRateInKhz);
894 
895 		if (((GET_DATA_TABLE_MAJOR_REVISION(table) == 2) &&
896 			(GET_DATA_TABLE_MINOR_REVISION(table) >= 2)) ||
897 			(GET_DATA_TABLE_MAJOR_REVISION(table) == 3)) {
898 			ssEntry->speed_spectrum_rate /= 100;
899 		}
900 
901 		switch (ssInfo->ucSpreadSpectrumMode) {
902 		case 0:
903 			ssEntry->speed_spectrum_mode =
904 				pp_atomctrl_spread_spectrum_mode_down;
905 			break;
906 		case 1:
907 			ssEntry->speed_spectrum_mode =
908 				pp_atomctrl_spread_spectrum_mode_center;
909 			break;
910 		default:
911 			ssEntry->speed_spectrum_mode =
912 				pp_atomctrl_spread_spectrum_mode_down;
913 			break;
914 		}
915 	}
916 
917 	return entry_found ? 0 : 1;
918 }
919 
920 /*
921  * Get the memory clock spread spectrum info
922  */
923 int atomctrl_get_memory_clock_spread_spectrum(
924 		struct pp_hwmgr *hwmgr,
925 		const uint32_t memory_clock,
926 		pp_atomctrl_internal_ss_info *ssInfo)
927 {
928 	return asic_internal_ss_get_ss_asignment(hwmgr,
929 			ASIC_INTERNAL_MEMORY_SS, memory_clock, ssInfo);
930 }
931 
932 /*
933  * Get the engine clock spread spectrum info
934  */
935 int atomctrl_get_engine_clock_spread_spectrum(
936 		struct pp_hwmgr *hwmgr,
937 		const uint32_t engine_clock,
938 		pp_atomctrl_internal_ss_info *ssInfo)
939 {
940 	return asic_internal_ss_get_ss_asignment(hwmgr,
941 			ASIC_INTERNAL_ENGINE_SS, engine_clock, ssInfo);
942 }
943 
944 int atomctrl_read_efuse(struct pp_hwmgr *hwmgr, uint16_t start_index,
945 		uint16_t end_index, uint32_t *efuse)
946 {
947 	struct amdgpu_device *adev = hwmgr->adev;
948 	uint32_t mask;
949 	int result;
950 	READ_EFUSE_VALUE_PARAMETER efuse_param;
951 
952 	if ((end_index - start_index)  == 31)
953 		mask = 0xFFFFFFFF;
954 	else
955 		mask = (1 << ((end_index - start_index) + 1)) - 1;
956 
957 	efuse_param.sEfuse.usEfuseIndex = cpu_to_le16((start_index / 32) * 4);
958 	efuse_param.sEfuse.ucBitShift = (uint8_t)
959 			(start_index - ((start_index / 32) * 32));
960 	efuse_param.sEfuse.ucBitLength  = (uint8_t)
961 			((end_index - start_index) + 1);
962 
963 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
964 			GetIndexIntoMasterTable(COMMAND, ReadEfuseValue),
965 			(uint32_t *)&efuse_param, sizeof(efuse_param));
966 	*efuse = result ? 0 : le32_to_cpu(efuse_param.ulEfuseValue) & mask;
967 
968 	return result;
969 }
970 
971 int atomctrl_set_ac_timing_ai(struct pp_hwmgr *hwmgr, uint32_t memory_clock,
972 			      uint8_t level)
973 {
974 	struct amdgpu_device *adev = hwmgr->adev;
975 	DYNAMICE_MEMORY_SETTINGS_PARAMETER_V2_1 memory_clock_parameters;
976 	int result;
977 
978 	memory_clock_parameters.asDPMMCReg.ulClock.ulClockFreq =
979 		memory_clock & SET_CLOCK_FREQ_MASK;
980 	memory_clock_parameters.asDPMMCReg.ulClock.ulComputeClockFlag =
981 		ADJUST_MC_SETTING_PARAM;
982 	memory_clock_parameters.asDPMMCReg.ucMclkDPMState = level;
983 
984 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
985 		 GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings),
986 		(uint32_t *)&memory_clock_parameters, sizeof(memory_clock_parameters));
987 
988 	return result;
989 }
990 
991 int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
992 				uint32_t sclk, uint16_t virtual_voltage_Id, uint32_t *voltage)
993 {
994 	struct amdgpu_device *adev = hwmgr->adev;
995 	int result;
996 	GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_3 get_voltage_info_param_space;
997 
998 	get_voltage_info_param_space.ucVoltageType = voltage_type;
999 	get_voltage_info_param_space.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE;
1000 	get_voltage_info_param_space.usVoltageLevel = cpu_to_le16(virtual_voltage_Id);
1001 	get_voltage_info_param_space.ulSCLKFreq = cpu_to_le32(sclk);
1002 
1003 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
1004 			GetIndexIntoMasterTable(COMMAND, GetVoltageInfo),
1005 			(uint32_t *)&get_voltage_info_param_space, sizeof(get_voltage_info_param_space));
1006 
1007 	*voltage = result ? 0 :
1008 		le32_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_3 *)(&get_voltage_info_param_space))->ulVoltageLevel);
1009 
1010 	return result;
1011 }
1012 
1013 int atomctrl_get_smc_sclk_range_table(struct pp_hwmgr *hwmgr, struct pp_atom_ctrl_sclk_range_table *table)
1014 {
1015 
1016 	int i;
1017 	u8 frev, crev;
1018 	u16 size;
1019 
1020 	ATOM_SMU_INFO_V2_1 *psmu_info =
1021 		(ATOM_SMU_INFO_V2_1 *)smu_atom_get_data_table(hwmgr->adev,
1022 			GetIndexIntoMasterTable(DATA, SMU_Info),
1023 			&size, &frev, &crev);
1024 
1025 	if (!psmu_info)
1026 		return -EINVAL;
1027 
1028 	for (i = 0; i < psmu_info->ucSclkEntryNum; i++) {
1029 		table->entry[i].ucVco_setting = psmu_info->asSclkFcwRangeEntry[i].ucVco_setting;
1030 		table->entry[i].ucPostdiv = psmu_info->asSclkFcwRangeEntry[i].ucPostdiv;
1031 		table->entry[i].usFcw_pcc =
1032 			le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucFcw_pcc);
1033 		table->entry[i].usFcw_trans_upper =
1034 			le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucFcw_trans_upper);
1035 		table->entry[i].usRcw_trans_lower =
1036 			le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucRcw_trans_lower);
1037 	}
1038 
1039 	return 0;
1040 }
1041 
1042 int atomctrl_get_vddc_shared_railinfo(struct pp_hwmgr *hwmgr, uint8_t *shared_rail)
1043 {
1044 	ATOM_SMU_INFO_V2_1 *psmu_info =
1045 		(ATOM_SMU_INFO_V2_1 *)smu_atom_get_data_table(hwmgr->adev,
1046 			GetIndexIntoMasterTable(DATA, SMU_Info),
1047 			NULL, NULL, NULL);
1048 	if (!psmu_info)
1049 		return -1;
1050 
1051 	*shared_rail = psmu_info->ucSharePowerSource;
1052 
1053 	return 0;
1054 }
1055 
1056 int atomctrl_get_avfs_information(struct pp_hwmgr *hwmgr,
1057 				  struct pp_atom_ctrl__avfs_parameters *param)
1058 {
1059 	ATOM_ASIC_PROFILING_INFO_V3_6 *profile = NULL;
1060 
1061 	if (param == NULL)
1062 		return -EINVAL;
1063 
1064 	profile = (ATOM_ASIC_PROFILING_INFO_V3_6 *)
1065 			smu_atom_get_data_table(hwmgr->adev,
1066 					GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo),
1067 					NULL, NULL, NULL);
1068 	if (!profile)
1069 		return -1;
1070 
1071 	param->ulAVFS_meanNsigma_Acontant0 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant0);
1072 	param->ulAVFS_meanNsigma_Acontant1 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant1);
1073 	param->ulAVFS_meanNsigma_Acontant2 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant2);
1074 	param->usAVFS_meanNsigma_DC_tol_sigma = le16_to_cpu(profile->usAVFS_meanNsigma_DC_tol_sigma);
1075 	param->usAVFS_meanNsigma_Platform_mean = le16_to_cpu(profile->usAVFS_meanNsigma_Platform_mean);
1076 	param->usAVFS_meanNsigma_Platform_sigma = le16_to_cpu(profile->usAVFS_meanNsigma_Platform_sigma);
1077 	param->ulGB_VDROOP_TABLE_CKSOFF_a0 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a0);
1078 	param->ulGB_VDROOP_TABLE_CKSOFF_a1 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a1);
1079 	param->ulGB_VDROOP_TABLE_CKSOFF_a2 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a2);
1080 	param->ulGB_VDROOP_TABLE_CKSON_a0 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a0);
1081 	param->ulGB_VDROOP_TABLE_CKSON_a1 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a1);
1082 	param->ulGB_VDROOP_TABLE_CKSON_a2 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a2);
1083 	param->ulAVFSGB_FUSE_TABLE_CKSOFF_m1 = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSOFF_m1);
1084 	param->usAVFSGB_FUSE_TABLE_CKSOFF_m2 = le16_to_cpu(profile->usAVFSGB_FUSE_TABLE_CKSOFF_m2);
1085 	param->ulAVFSGB_FUSE_TABLE_CKSOFF_b = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSOFF_b);
1086 	param->ulAVFSGB_FUSE_TABLE_CKSON_m1 = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSON_m1);
1087 	param->usAVFSGB_FUSE_TABLE_CKSON_m2 = le16_to_cpu(profile->usAVFSGB_FUSE_TABLE_CKSON_m2);
1088 	param->ulAVFSGB_FUSE_TABLE_CKSON_b = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSON_b);
1089 	param->usMaxVoltage_0_25mv = le16_to_cpu(profile->usMaxVoltage_0_25mv);
1090 	param->ucEnableGB_VDROOP_TABLE_CKSOFF = profile->ucEnableGB_VDROOP_TABLE_CKSOFF;
1091 	param->ucEnableGB_VDROOP_TABLE_CKSON = profile->ucEnableGB_VDROOP_TABLE_CKSON;
1092 	param->ucEnableGB_FUSE_TABLE_CKSOFF = profile->ucEnableGB_FUSE_TABLE_CKSOFF;
1093 	param->ucEnableGB_FUSE_TABLE_CKSON = profile->ucEnableGB_FUSE_TABLE_CKSON;
1094 	param->usPSM_Age_ComFactor = le16_to_cpu(profile->usPSM_Age_ComFactor);
1095 	param->ucEnableApplyAVFS_CKS_OFF_Voltage = profile->ucEnableApplyAVFS_CKS_OFF_Voltage;
1096 
1097 	return 0;
1098 }
1099 
1100 int  atomctrl_get_svi2_info(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
1101 				uint8_t *svd_gpio_id, uint8_t *svc_gpio_id,
1102 				uint16_t *load_line)
1103 {
1104 	ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info =
1105 		(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->adev);
1106 
1107 	const ATOM_VOLTAGE_OBJECT_V3 *voltage_object;
1108 
1109 	PP_ASSERT_WITH_CODE((NULL != voltage_info),
1110 			"Could not find Voltage Table in BIOS.", return -EINVAL);
1111 
1112 	voltage_object = atomctrl_lookup_voltage_type_v3
1113 		(voltage_info, voltage_type,  VOLTAGE_OBJ_SVID2);
1114 
1115 	*svd_gpio_id = voltage_object->asSVID2Obj.ucSVDGpioId;
1116 	*svc_gpio_id = voltage_object->asSVID2Obj.ucSVCGpioId;
1117 	*load_line = voltage_object->asSVID2Obj.usLoadLine_PSI;
1118 
1119 	return 0;
1120 }
1121 
1122 int atomctrl_get_leakage_id_from_efuse(struct pp_hwmgr *hwmgr, uint16_t *virtual_voltage_id)
1123 {
1124 	struct amdgpu_device *adev = hwmgr->adev;
1125 	SET_VOLTAGE_PS_ALLOCATION allocation;
1126 	SET_VOLTAGE_PARAMETERS_V1_3 *voltage_parameters =
1127 			(SET_VOLTAGE_PARAMETERS_V1_3 *)&allocation.sASICSetVoltage;
1128 	int result;
1129 
1130 	voltage_parameters->ucVoltageMode = ATOM_GET_LEAKAGE_ID;
1131 
1132 	result = amdgpu_atom_execute_table(adev->mode_info.atom_context,
1133 			GetIndexIntoMasterTable(COMMAND, SetVoltage),
1134 			(uint32_t *)voltage_parameters, sizeof(*voltage_parameters));
1135 
1136 	*virtual_voltage_id = voltage_parameters->usVoltageLevel;
1137 
1138 	return result;
1139 }
1140 
1141 int atomctrl_get_leakage_vddc_base_on_leakage(struct pp_hwmgr *hwmgr,
1142 					uint16_t *vddc, uint16_t *vddci,
1143 					uint16_t virtual_voltage_id,
1144 					uint16_t efuse_voltage_id)
1145 {
1146 	int i, j;
1147 	int ix;
1148 	u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf;
1149 	ATOM_ASIC_PROFILING_INFO_V2_1 *profile;
1150 
1151 	*vddc = 0;
1152 	*vddci = 0;
1153 
1154 	ix = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo);
1155 
1156 	profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *)
1157 			smu_atom_get_data_table(hwmgr->adev,
1158 					ix,
1159 					NULL, NULL, NULL);
1160 	if (!profile)
1161 		return -EINVAL;
1162 
1163 	if ((profile->asHeader.ucTableFormatRevision >= 2) &&
1164 		(profile->asHeader.ucTableContentRevision >= 1) &&
1165 		(profile->asHeader.usStructureSize >= sizeof(ATOM_ASIC_PROFILING_INFO_V2_1))) {
1166 		leakage_bin = (u16 *)((char *)profile + profile->usLeakageBinArrayOffset);
1167 		vddc_id_buf = (u16 *)((char *)profile + profile->usElbVDDC_IdArrayOffset);
1168 		vddc_buf = (u16 *)((char *)profile + profile->usElbVDDC_LevelArrayOffset);
1169 		if (profile->ucElbVDDC_Num > 0) {
1170 			for (i = 0; i < profile->ucElbVDDC_Num; i++) {
1171 				if (vddc_id_buf[i] == virtual_voltage_id) {
1172 					for (j = 0; j < profile->ucLeakageBinNum; j++) {
1173 						if (efuse_voltage_id <= leakage_bin[j]) {
1174 							*vddc = vddc_buf[j * profile->ucElbVDDC_Num + i];
1175 							break;
1176 						}
1177 					}
1178 					break;
1179 				}
1180 			}
1181 		}
1182 
1183 		vddci_id_buf = (u16 *)((char *)profile + profile->usElbVDDCI_IdArrayOffset);
1184 		vddci_buf   = (u16 *)((char *)profile + profile->usElbVDDCI_LevelArrayOffset);
1185 		if (profile->ucElbVDDCI_Num > 0) {
1186 			for (i = 0; i < profile->ucElbVDDCI_Num; i++) {
1187 				if (vddci_id_buf[i] == virtual_voltage_id) {
1188 					for (j = 0; j < profile->ucLeakageBinNum; j++) {
1189 						if (efuse_voltage_id <= leakage_bin[j]) {
1190 							*vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i];
1191 							break;
1192 						}
1193 					}
1194 					break;
1195 				}
1196 			}
1197 		}
1198 	}
1199 
1200 	return 0;
1201 }
1202 
1203 void atomctrl_get_voltage_range(struct pp_hwmgr *hwmgr, uint32_t *max_vddc,
1204 							uint32_t *min_vddc)
1205 {
1206 	void *profile;
1207 
1208 	profile = smu_atom_get_data_table(hwmgr->adev,
1209 					GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo),
1210 					NULL, NULL, NULL);
1211 
1212 	if (profile) {
1213 		switch (hwmgr->chip_id) {
1214 		case CHIP_TONGA:
1215 		case CHIP_FIJI:
1216 			*max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMaxVddc) / 4;
1217 			*min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMinVddc) / 4;
1218 			return;
1219 		case CHIP_POLARIS11:
1220 		case CHIP_POLARIS10:
1221 		case CHIP_POLARIS12:
1222 			*max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMaxVddc) / 100;
1223 			*min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMinVddc) / 100;
1224 			return;
1225 		default:
1226 			break;
1227 		}
1228 	}
1229 	*max_vddc = 0;
1230 	*min_vddc = 0;
1231 }
1232 
1233 int atomctrl_get_edc_hilo_leakage_offset_table(struct pp_hwmgr *hwmgr,
1234 					       AtomCtrl_HiLoLeakageOffsetTable *table)
1235 {
1236 	ATOM_GFX_INFO_V2_3 *gfxinfo = smu_atom_get_data_table(hwmgr->adev,
1237 					GetIndexIntoMasterTable(DATA, GFX_Info),
1238 					NULL, NULL, NULL);
1239 	if (!gfxinfo)
1240 		return -ENOENT;
1241 
1242 	table->usHiLoLeakageThreshold = gfxinfo->usHiLoLeakageThreshold;
1243 	table->usEdcDidtLoDpm7TableOffset = gfxinfo->usEdcDidtLoDpm7TableOffset;
1244 	table->usEdcDidtHiDpm7TableOffset = gfxinfo->usEdcDidtHiDpm7TableOffset;
1245 
1246 	return 0;
1247 }
1248 
1249 static AtomCtrl_EDCLeakgeTable *get_edc_leakage_table(struct pp_hwmgr *hwmgr,
1250 						      uint16_t offset)
1251 {
1252 	void *table_address;
1253 	char *temp;
1254 
1255 	table_address = smu_atom_get_data_table(hwmgr->adev,
1256 			GetIndexIntoMasterTable(DATA, GFX_Info),
1257 			NULL, NULL, NULL);
1258 	if (!table_address)
1259 		return NULL;
1260 
1261 	temp = (char *)table_address;
1262 	table_address += offset;
1263 
1264 	return (AtomCtrl_EDCLeakgeTable *)temp;
1265 }
1266 
1267 int atomctrl_get_edc_leakage_table(struct pp_hwmgr *hwmgr,
1268 				   AtomCtrl_EDCLeakgeTable *table,
1269 				   uint16_t offset)
1270 {
1271 	uint32_t length, i;
1272 	AtomCtrl_EDCLeakgeTable *leakage_table =
1273 		get_edc_leakage_table(hwmgr, offset);
1274 
1275 	if (!leakage_table)
1276 		return -ENOENT;
1277 
1278 	length = sizeof(leakage_table->DIDT_REG) /
1279 		 sizeof(leakage_table->DIDT_REG[0]);
1280 	for (i = 0; i < length; i++)
1281 		table->DIDT_REG[i] = leakage_table->DIDT_REG[i];
1282 
1283 	return 0;
1284 }
1285