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