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