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