2 * Copyright 2015 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
23 #include <linux/module.h>
24 #include <linux/slab.h>
27 #include "ppatomctrl.h"
29 #include "cgs_common.h"
31 #include "ppevvmath.h"
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
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
;
47 static int atomctrl_retrieve_ac_timing(
49 ATOM_INIT_REG_BLOCK
*reg_block
,
50 pp_atomctrl_mc_reg_table
*table
)
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
));
57 uint8_t num_ranges
= 0;
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
);
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
) >>
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
);
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];
83 reg_data
= (ATOM_MEMORY_SETTING_DATA_BLOCK
*)
84 ((uint8_t *)reg_data
+ le16_to_cpu(reg_block
->usRegDataBlkSize
)) ;
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
;
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
101 static int atomctrl_set_mc_reg_address_table(
102 ATOM_INIT_REG_BLOCK
*reg_block
,
103 pp_atomctrl_mc_reg_table
*table
)
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
= ®_block
->asRegIndexBuf
[0];
110 num_entries
--; /* subtract 1 data end mark entry */
112 PP_ASSERT_WITH_CODE((num_entries
<= VBIOS_MC_REGISTER_ARRAY_SIZE
),
113 "Invalid VramInfo table.", return -1);
115 /* ucPreRegDataLength bit6 = 1 is the end of memory clock AC timing registers */
116 while ((!(format
->ucPreRegDataLength
& ACCESS_PLACEHOLDER
)) &&
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
;
124 format
= (ATOM_INIT_REG_INDEX_FORMAT
*)
125 ((uint8_t *)format
+ sizeof(ATOM_INIT_REG_INDEX_FORMAT
));
133 int atomctrl_initialize_mc_reg_table(
134 struct pp_hwmgr
*hwmgr
,
135 uint8_t module_index
,
136 pp_atomctrl_mc_reg_table
*table
)
138 ATOM_VRAM_INFO_HEADER_V2_1
*vram_info
;
139 ATOM_INIT_REG_BLOCK
*reg_block
;
144 vram_info
= (ATOM_VRAM_INFO_HEADER_V2_1
*)
145 cgs_atom_get_data_table(hwmgr
->device
,
146 GetIndexIntoMasterTable(DATA
, VRAM_Info
), &size
, &frev
, &crev
);
148 if (module_index
>= vram_info
->ucNumOfVRAMModule
) {
149 printk(KERN_ERR
"[ powerplay ] Invalid VramInfo table.");
151 } else if (vram_info
->sHeader
.ucTableFormatRevision
< 2) {
152 printk(KERN_ERR
"[ powerplay ] Invalid VramInfo table.");
157 reg_block
= (ATOM_INIT_REG_BLOCK
*)
158 ((uint8_t *)vram_info
+ le16_to_cpu(vram_info
->usMemClkPatchTblOffset
));
159 result
= atomctrl_set_mc_reg_address_table(reg_block
, table
);
163 result
= atomctrl_retrieve_ac_timing(module_index
,
171 * Set DRAM timings based on engine clock and memory clock.
173 int atomctrl_set_engine_dram_timings_rv770(
174 struct pp_hwmgr
*hwmgr
,
175 uint32_t engine_clock
,
176 uint32_t memory_clock
)
178 SET_ENGINE_CLOCK_PS_ALLOCATION engine_clock_parameters
;
180 /* They are both in 10KHz Units. */
181 engine_clock_parameters
.ulTargetEngineClock
=
182 cpu_to_le32((engine_clock
& SET_CLOCK_FREQ_MASK
) |
183 ((COMPUTE_ENGINE_PLL_PARAM
<< 24)));
185 /* in 10 khz units.*/
186 engine_clock_parameters
.sReserved
.ulClock
=
187 cpu_to_le32(memory_clock
& SET_CLOCK_FREQ_MASK
);
188 return cgs_atom_exec_cmd_table(hwmgr
->device
,
189 GetIndexIntoMasterTable(COMMAND
, DynamicMemorySettings
),
190 &engine_clock_parameters
);
194 * Private Function to get the PowerPlay Table Address.
195 * WARNING: The tabled returned by this function is in
196 * dynamically allocated memory.
197 * The caller has to release if by calling kfree.
199 static ATOM_VOLTAGE_OBJECT_INFO
*get_voltage_info_table(void *device
)
201 int index
= GetIndexIntoMasterTable(DATA
, VoltageObjectInfo
);
204 union voltage_object_info
*voltage_info
;
206 voltage_info
= (union voltage_object_info
*)
207 cgs_atom_get_data_table(device
, index
,
208 &size
, &frev
, &crev
);
210 if (voltage_info
!= NULL
)
211 return (ATOM_VOLTAGE_OBJECT_INFO
*) &(voltage_info
->v3
);
216 static const ATOM_VOLTAGE_OBJECT_V3
*atomctrl_lookup_voltage_type_v3(
217 const ATOM_VOLTAGE_OBJECT_INFO_V3_1
* voltage_object_info_table
,
218 uint8_t voltage_type
, uint8_t voltage_mode
)
220 unsigned int size
= le16_to_cpu(voltage_object_info_table
->sHeader
.usStructureSize
);
221 unsigned int offset
= offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1
, asVoltageObj
[0]);
222 uint8_t *start
= (uint8_t *)voltage_object_info_table
;
224 while (offset
< size
) {
225 const ATOM_VOLTAGE_OBJECT_V3
*voltage_object
=
226 (const ATOM_VOLTAGE_OBJECT_V3
*)(start
+ offset
);
228 if (voltage_type
== voltage_object
->asGpioVoltageObj
.sHeader
.ucVoltageType
&&
229 voltage_mode
== voltage_object
->asGpioVoltageObj
.sHeader
.ucVoltageMode
)
230 return voltage_object
;
232 offset
+= le16_to_cpu(voltage_object
->asGpioVoltageObj
.sHeader
.usSize
);
238 /** atomctrl_get_memory_pll_dividers_si().
240 * @param hwmgr input parameter: pointer to HwMgr
241 * @param clock_value input parameter: memory clock
242 * @param dividers output parameter: memory PLL dividers
243 * @param strobe_mode input parameter: 1 for strobe mode, 0 for performance mode
245 int atomctrl_get_memory_pll_dividers_si(
246 struct pp_hwmgr
*hwmgr
,
247 uint32_t clock_value
,
248 pp_atomctrl_memory_clock_param
*mpll_param
,
251 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 mpll_parameters
;
254 mpll_parameters
.ulClock
= cpu_to_le32(clock_value
);
255 mpll_parameters
.ucInputFlag
= (uint8_t)((strobe_mode
) ? 1 : 0);
257 result
= cgs_atom_exec_cmd_table
259 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryClockParam
),
263 mpll_param
->mpll_fb_divider
.clk_frac
=
264 le16_to_cpu(mpll_parameters
.ulFbDiv
.usFbDivFrac
);
265 mpll_param
->mpll_fb_divider
.cl_kf
=
266 le16_to_cpu(mpll_parameters
.ulFbDiv
.usFbDiv
);
267 mpll_param
->mpll_post_divider
=
268 (uint32_t)mpll_parameters
.ucPostDiv
;
269 mpll_param
->vco_mode
=
270 (uint32_t)(mpll_parameters
.ucPllCntlFlag
&
271 MPLL_CNTL_FLAG_VCO_MODE_MASK
);
272 mpll_param
->yclk_sel
=
273 (uint32_t)((mpll_parameters
.ucPllCntlFlag
&
274 MPLL_CNTL_FLAG_BYPASS_DQ_PLL
) ? 1 : 0);
276 (uint32_t)((mpll_parameters
.ucPllCntlFlag
&
277 MPLL_CNTL_FLAG_QDR_ENABLE
) ? 1 : 0);
278 mpll_param
->half_rate
=
279 (uint32_t)((mpll_parameters
.ucPllCntlFlag
&
280 MPLL_CNTL_FLAG_AD_HALF_RATE
) ? 1 : 0);
281 mpll_param
->dll_speed
=
282 (uint32_t)(mpll_parameters
.ucDllSpeed
);
283 mpll_param
->bw_ctrl
=
284 (uint32_t)(mpll_parameters
.ucBWCntl
);
290 /** atomctrl_get_memory_pll_dividers_vi().
292 * @param hwmgr input parameter: pointer to HwMgr
293 * @param clock_value input parameter: memory clock
294 * @param dividers output parameter: memory PLL dividers
296 int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr
*hwmgr
,
297 uint32_t clock_value
, pp_atomctrl_memory_clock_param
*mpll_param
)
299 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2 mpll_parameters
;
302 mpll_parameters
.ulClock
.ulClock
= cpu_to_le32(clock_value
);
304 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
305 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryClockParam
),
309 mpll_param
->mpll_post_divider
=
310 (uint32_t)mpll_parameters
.ulClock
.ucPostDiv
;
315 int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr
*hwmgr
,
316 uint32_t clock_value
,
317 pp_atomctrl_clock_dividers_kong
*dividers
)
319 COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 pll_parameters
;
322 pll_parameters
.ulClock
= cpu_to_le32(clock_value
);
324 result
= cgs_atom_exec_cmd_table
326 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
330 dividers
->pll_post_divider
= pll_parameters
.ucPostDiv
;
331 dividers
->real_clock
= le32_to_cpu(pll_parameters
.ulClock
);
337 int atomctrl_get_engine_pll_dividers_vi(
338 struct pp_hwmgr
*hwmgr
,
339 uint32_t clock_value
,
340 pp_atomctrl_clock_dividers_vi
*dividers
)
342 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters
;
345 pll_patameters
.ulClock
.ulClock
= cpu_to_le32(clock_value
);
346 pll_patameters
.ulClock
.ucPostDiv
= COMPUTE_GPUCLK_INPUT_FLAG_SCLK
;
348 result
= cgs_atom_exec_cmd_table
350 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
354 dividers
->pll_post_divider
=
355 pll_patameters
.ulClock
.ucPostDiv
;
356 dividers
->real_clock
=
357 le32_to_cpu(pll_patameters
.ulClock
.ulClock
);
359 dividers
->ul_fb_div
.ul_fb_div_frac
=
360 le16_to_cpu(pll_patameters
.ulFbDiv
.usFbDivFrac
);
361 dividers
->ul_fb_div
.ul_fb_div
=
362 le16_to_cpu(pll_patameters
.ulFbDiv
.usFbDiv
);
364 dividers
->uc_pll_ref_div
=
365 pll_patameters
.ucPllRefDiv
;
366 dividers
->uc_pll_post_div
=
367 pll_patameters
.ucPllPostDiv
;
368 dividers
->uc_pll_cntl_flag
=
369 pll_patameters
.ucPllCntlFlag
;
375 int atomctrl_get_engine_pll_dividers_ai(struct pp_hwmgr
*hwmgr
,
376 uint32_t clock_value
,
377 pp_atomctrl_clock_dividers_ai
*dividers
)
379 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_7 pll_patameters
;
382 pll_patameters
.ulClock
.ulClock
= cpu_to_le32(clock_value
);
383 pll_patameters
.ulClock
.ucPostDiv
= COMPUTE_GPUCLK_INPUT_FLAG_SCLK
;
385 result
= cgs_atom_exec_cmd_table
387 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
391 dividers
->usSclk_fcw_frac
= le16_to_cpu(pll_patameters
.usSclk_fcw_frac
);
392 dividers
->usSclk_fcw_int
= le16_to_cpu(pll_patameters
.usSclk_fcw_int
);
393 dividers
->ucSclkPostDiv
= pll_patameters
.ucSclkPostDiv
;
394 dividers
->ucSclkVcoMode
= pll_patameters
.ucSclkVcoMode
;
395 dividers
->ucSclkPllRange
= pll_patameters
.ucSclkPllRange
;
396 dividers
->ucSscEnable
= pll_patameters
.ucSscEnable
;
397 dividers
->usSsc_fcw1_frac
= le16_to_cpu(pll_patameters
.usSsc_fcw1_frac
);
398 dividers
->usSsc_fcw1_int
= le16_to_cpu(pll_patameters
.usSsc_fcw1_int
);
399 dividers
->usPcc_fcw_int
= le16_to_cpu(pll_patameters
.usPcc_fcw_int
);
400 dividers
->usSsc_fcw_slew_frac
= le16_to_cpu(pll_patameters
.usSsc_fcw_slew_frac
);
401 dividers
->usPcc_fcw_slew_frac
= le16_to_cpu(pll_patameters
.usPcc_fcw_slew_frac
);
406 int atomctrl_get_dfs_pll_dividers_vi(
407 struct pp_hwmgr
*hwmgr
,
408 uint32_t clock_value
,
409 pp_atomctrl_clock_dividers_vi
*dividers
)
411 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters
;
414 pll_patameters
.ulClock
.ulClock
= cpu_to_le32(clock_value
);
415 pll_patameters
.ulClock
.ucPostDiv
=
416 COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK
;
418 result
= cgs_atom_exec_cmd_table
420 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
424 dividers
->pll_post_divider
=
425 pll_patameters
.ulClock
.ucPostDiv
;
426 dividers
->real_clock
=
427 le32_to_cpu(pll_patameters
.ulClock
.ulClock
);
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
);
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
;
446 * Get the reference clock in 10KHz
448 uint32_t atomctrl_get_reference_clock(struct pp_hwmgr
*hwmgr
)
450 ATOM_FIRMWARE_INFO
*fw_info
;
455 fw_info
= (ATOM_FIRMWARE_INFO
*)
456 cgs_atom_get_data_table(hwmgr
->device
,
457 GetIndexIntoMasterTable(DATA
, FirmwareInfo
),
458 &size
, &frev
, &crev
);
463 clock
= (uint32_t)(le16_to_cpu(fw_info
->usReferenceClock
));
469 * Returns true if the given voltage type is controlled by GPIO pins.
470 * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC,
471 * SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ.
472 * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE
474 bool atomctrl_is_voltage_controled_by_gpio_v3(
475 struct pp_hwmgr
*hwmgr
,
476 uint8_t voltage_type
,
477 uint8_t voltage_mode
)
479 ATOM_VOLTAGE_OBJECT_INFO_V3_1
*voltage_info
=
480 (ATOM_VOLTAGE_OBJECT_INFO_V3_1
*)get_voltage_info_table(hwmgr
->device
);
483 PP_ASSERT_WITH_CODE((NULL
!= voltage_info
),
484 "Could not find Voltage Table in BIOS.", return false;);
486 ret
= (NULL
!= atomctrl_lookup_voltage_type_v3
487 (voltage_info
, voltage_type
, voltage_mode
)) ? true : false;
492 int atomctrl_get_voltage_table_v3(
493 struct pp_hwmgr
*hwmgr
,
494 uint8_t voltage_type
,
495 uint8_t voltage_mode
,
496 pp_atomctrl_voltage_table
*voltage_table
)
498 ATOM_VOLTAGE_OBJECT_INFO_V3_1
*voltage_info
=
499 (ATOM_VOLTAGE_OBJECT_INFO_V3_1
*)get_voltage_info_table(hwmgr
->device
);
500 const ATOM_VOLTAGE_OBJECT_V3
*voltage_object
;
503 PP_ASSERT_WITH_CODE((NULL
!= voltage_info
),
504 "Could not find Voltage Table in BIOS.", return -1;);
506 voltage_object
= atomctrl_lookup_voltage_type_v3
507 (voltage_info
, voltage_type
, voltage_mode
);
509 if (voltage_object
== NULL
)
513 (voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
<=
514 PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES
),
515 "Too many voltage entries!",
519 for (i
= 0; i
< voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
; i
++) {
520 voltage_table
->entries
[i
].value
=
521 le16_to_cpu(voltage_object
->asGpioVoltageObj
.asVolGpioLut
[i
].usVoltageValue
);
522 voltage_table
->entries
[i
].smio_low
=
523 le32_to_cpu(voltage_object
->asGpioVoltageObj
.asVolGpioLut
[i
].ulVoltageId
);
526 voltage_table
->mask_low
=
527 le32_to_cpu(voltage_object
->asGpioVoltageObj
.ulGpioMaskVal
);
528 voltage_table
->count
=
529 voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
;
530 voltage_table
->phase_delay
=
531 voltage_object
->asGpioVoltageObj
.ucPhaseDelay
;
536 static bool atomctrl_lookup_gpio_pin(
537 ATOM_GPIO_PIN_LUT
* gpio_lookup_table
,
538 const uint32_t pinId
,
539 pp_atomctrl_gpio_pin_assignment
*gpio_pin_assignment
)
541 unsigned int size
= le16_to_cpu(gpio_lookup_table
->sHeader
.usStructureSize
);
542 unsigned int offset
= offsetof(ATOM_GPIO_PIN_LUT
, asGPIO_Pin
[0]);
543 uint8_t *start
= (uint8_t *)gpio_lookup_table
;
545 while (offset
< size
) {
546 const ATOM_GPIO_PIN_ASSIGNMENT
*pin_assignment
=
547 (const ATOM_GPIO_PIN_ASSIGNMENT
*)(start
+ offset
);
549 if (pinId
== pin_assignment
->ucGPIO_ID
) {
550 gpio_pin_assignment
->uc_gpio_pin_bit_shift
=
551 pin_assignment
->ucGpioPinBitShift
;
552 gpio_pin_assignment
->us_gpio_pin_aindex
=
553 le16_to_cpu(pin_assignment
->usGpioPin_AIndex
);
557 offset
+= offsetof(ATOM_GPIO_PIN_ASSIGNMENT
, ucGPIO_ID
) + 1;
564 * Private Function to get the PowerPlay Table Address.
565 * WARNING: The tabled returned by this function is in
566 * dynamically allocated memory.
567 * The caller has to release if by calling kfree.
569 static ATOM_GPIO_PIN_LUT
*get_gpio_lookup_table(void *device
)
575 table_address
= (ATOM_GPIO_PIN_LUT
*)
576 cgs_atom_get_data_table(device
,
577 GetIndexIntoMasterTable(DATA
, GPIO_Pin_LUT
),
578 &size
, &frev
, &crev
);
580 PP_ASSERT_WITH_CODE((NULL
!= table_address
),
581 "Error retrieving BIOS Table Address!", return NULL
;);
583 return (ATOM_GPIO_PIN_LUT
*)table_address
;
587 * Returns 1 if the given pin id find in lookup table.
589 bool atomctrl_get_pp_assign_pin(
590 struct pp_hwmgr
*hwmgr
,
591 const uint32_t pinId
,
592 pp_atomctrl_gpio_pin_assignment
*gpio_pin_assignment
)
595 ATOM_GPIO_PIN_LUT
*gpio_lookup_table
=
596 get_gpio_lookup_table(hwmgr
->device
);
598 PP_ASSERT_WITH_CODE((NULL
!= gpio_lookup_table
),
599 "Could not find GPIO lookup Table in BIOS.", return false);
601 bRet
= atomctrl_lookup_gpio_pin(gpio_lookup_table
, pinId
,
602 gpio_pin_assignment
);
607 int atomctrl_calculate_voltage_evv_on_sclk(
608 struct pp_hwmgr
*hwmgr
,
609 uint8_t voltage_type
,
611 uint16_t virtual_voltage_Id
,
616 ATOM_ASIC_PROFILING_INFO_V3_4
*getASICProfilingInfo
;
618 EFUSE_LINEAR_FUNC_PARAM sRO_fuse
;
619 EFUSE_LINEAR_FUNC_PARAM sCACm_fuse
;
620 EFUSE_LINEAR_FUNC_PARAM sCACb_fuse
;
621 EFUSE_LOGISTIC_FUNC_PARAM sKt_Beta_fuse
;
622 EFUSE_LOGISTIC_FUNC_PARAM sKv_m_fuse
;
623 EFUSE_LOGISTIC_FUNC_PARAM sKv_b_fuse
;
624 EFUSE_INPUT_PARAMETER sInput_FuseValues
;
625 READ_EFUSE_VALUE_PARAMETER sOutput_FuseValues
;
627 uint32_t ul_RO_fused
, ul_CACb_fused
, ul_CACm_fused
, ul_Kt_Beta_fused
, ul_Kv_m_fused
, ul_Kv_b_fused
;
628 fInt fSM_A0
, fSM_A1
, fSM_A2
, fSM_A3
, fSM_A4
, fSM_A5
, fSM_A6
, fSM_A7
;
629 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
;
630 fInt fLkg_FT
, repeat
;
631 fInt fMicro_FMAX
, fMicro_CR
, fSigma_FMAX
, fSigma_CR
, fSigma_DC
, fDC_SCLK
, fSquared_Sigma_DC
, fSquared_Sigma_CR
, fSquared_Sigma_FMAX
;
632 fInt fRLL_LoadLine
, fPowerDPMx
, fDerateTDP
, fVDDC_base
, fA_Term
, fC_Term
, fB_Term
, fRO_DC_margin
;
633 fInt fRO_fused
, fCACm_fused
, fCACb_fused
, fKv_m_fused
, fKv_b_fused
, fKt_Beta_fused
, fFT_Lkg_V0NORM
;
634 fInt fSclk_margin
, fSclk
, fEVV_V
;
635 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
;
636 uint32_t ul_FT_Lkg_V0NORM
;
637 fInt fLn_MaxDivMin
, fMin
, fAverage
, fRange
;
639 fInt fStepSize
= GetScaledFraction(625, 100000);
643 getASICProfilingInfo
= (ATOM_ASIC_PROFILING_INFO_V3_4
*)
644 cgs_atom_get_data_table(hwmgr
->device
,
645 GetIndexIntoMasterTable(DATA
, ASIC_ProfilingInfo
),
648 if (!getASICProfilingInfo
)
651 if (getASICProfilingInfo
->asHeader
.ucTableFormatRevision
< 3 ||
652 (getASICProfilingInfo
->asHeader
.ucTableFormatRevision
== 3 &&
653 getASICProfilingInfo
->asHeader
.ucTableContentRevision
< 4))
656 /*-----------------------------------------------------------
657 *GETTING MULTI-STEP PARAMETERS RELATED TO CURRENT DPM LEVEL
658 *-----------------------------------------------------------
660 fRLL_LoadLine
= Divide(getASICProfilingInfo
->ulLoadLineSlop
, 1000);
664 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm1
));
665 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM1
), 1000);
668 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm2
));
669 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM2
), 1000);
672 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm3
));
673 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM3
), 1000);
676 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm4
));
677 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM4
), 1000);
680 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm5
));
681 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM5
), 1000);
684 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm6
));
685 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM6
), 1000);
688 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm7
));
689 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM7
), 1000);
692 printk(KERN_ERR
"DPM Level not supported\n");
693 fPowerDPMx
= Convert_ULONG_ToFraction(1);
694 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM0
), 1000);
697 /*-------------------------
698 * DECODING FUSE VALUES
699 * ------------------------
702 sRO_fuse
= getASICProfilingInfo
->sRoFuse
;
704 sInput_FuseValues
.usEfuseIndex
= sRO_fuse
.usEfuseIndex
;
705 sInput_FuseValues
.ucBitShift
= sRO_fuse
.ucEfuseBitLSB
;
706 sInput_FuseValues
.ucBitLength
= sRO_fuse
.ucEfuseLength
;
708 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
710 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
711 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
712 &sOutput_FuseValues
);
717 /* Finally, the actual fuse value */
718 ul_RO_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
719 fMin
= GetScaledFraction(le32_to_cpu(sRO_fuse
.ulEfuseMin
), 1);
720 fRange
= GetScaledFraction(le32_to_cpu(sRO_fuse
.ulEfuseEncodeRange
), 1);
721 fRO_fused
= fDecodeLinearFuse(ul_RO_fused
, fMin
, fRange
, sRO_fuse
.ucEfuseLength
);
723 sCACm_fuse
= getASICProfilingInfo
->sCACm
;
725 sInput_FuseValues
.usEfuseIndex
= sCACm_fuse
.usEfuseIndex
;
726 sInput_FuseValues
.ucBitShift
= sCACm_fuse
.ucEfuseBitLSB
;
727 sInput_FuseValues
.ucBitLength
= sCACm_fuse
.ucEfuseLength
;
729 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
731 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
732 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
733 &sOutput_FuseValues
);
738 ul_CACm_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
739 fMin
= GetScaledFraction(le32_to_cpu(sCACm_fuse
.ulEfuseMin
), 1000);
740 fRange
= GetScaledFraction(le32_to_cpu(sCACm_fuse
.ulEfuseEncodeRange
), 1000);
742 fCACm_fused
= fDecodeLinearFuse(ul_CACm_fused
, fMin
, fRange
, sCACm_fuse
.ucEfuseLength
);
744 sCACb_fuse
= getASICProfilingInfo
->sCACb
;
746 sInput_FuseValues
.usEfuseIndex
= sCACb_fuse
.usEfuseIndex
;
747 sInput_FuseValues
.ucBitShift
= sCACb_fuse
.ucEfuseBitLSB
;
748 sInput_FuseValues
.ucBitLength
= sCACb_fuse
.ucEfuseLength
;
749 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
751 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
752 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
753 &sOutput_FuseValues
);
758 ul_CACb_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
759 fMin
= GetScaledFraction(le32_to_cpu(sCACb_fuse
.ulEfuseMin
), 1000);
760 fRange
= GetScaledFraction(le32_to_cpu(sCACb_fuse
.ulEfuseEncodeRange
), 1000);
762 fCACb_fused
= fDecodeLinearFuse(ul_CACb_fused
, fMin
, fRange
, sCACb_fuse
.ucEfuseLength
);
764 sKt_Beta_fuse
= getASICProfilingInfo
->sKt_b
;
766 sInput_FuseValues
.usEfuseIndex
= sKt_Beta_fuse
.usEfuseIndex
;
767 sInput_FuseValues
.ucBitShift
= sKt_Beta_fuse
.ucEfuseBitLSB
;
768 sInput_FuseValues
.ucBitLength
= sKt_Beta_fuse
.ucEfuseLength
;
770 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
772 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
773 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
774 &sOutput_FuseValues
);
779 ul_Kt_Beta_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
780 fAverage
= GetScaledFraction(le32_to_cpu(sKt_Beta_fuse
.ulEfuseEncodeAverage
), 1000);
781 fRange
= GetScaledFraction(le32_to_cpu(sKt_Beta_fuse
.ulEfuseEncodeRange
), 1000);
783 fKt_Beta_fused
= fDecodeLogisticFuse(ul_Kt_Beta_fused
,
784 fAverage
, fRange
, sKt_Beta_fuse
.ucEfuseLength
);
786 sKv_m_fuse
= getASICProfilingInfo
->sKv_m
;
788 sInput_FuseValues
.usEfuseIndex
= sKv_m_fuse
.usEfuseIndex
;
789 sInput_FuseValues
.ucBitShift
= sKv_m_fuse
.ucEfuseBitLSB
;
790 sInput_FuseValues
.ucBitLength
= sKv_m_fuse
.ucEfuseLength
;
792 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
794 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
795 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
796 &sOutput_FuseValues
);
800 ul_Kv_m_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
801 fAverage
= GetScaledFraction(le32_to_cpu(sKv_m_fuse
.ulEfuseEncodeAverage
), 1000);
802 fRange
= GetScaledFraction((le32_to_cpu(sKv_m_fuse
.ulEfuseEncodeRange
) & 0x7fffffff), 1000);
803 fRange
= fMultiply(fRange
, ConvertToFraction(-1));
805 fKv_m_fused
= fDecodeLogisticFuse(ul_Kv_m_fused
,
806 fAverage
, fRange
, sKv_m_fuse
.ucEfuseLength
);
808 sKv_b_fuse
= getASICProfilingInfo
->sKv_b
;
810 sInput_FuseValues
.usEfuseIndex
= sKv_b_fuse
.usEfuseIndex
;
811 sInput_FuseValues
.ucBitShift
= sKv_b_fuse
.ucEfuseBitLSB
;
812 sInput_FuseValues
.ucBitLength
= sKv_b_fuse
.ucEfuseLength
;
813 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
815 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
816 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
817 &sOutput_FuseValues
);
822 ul_Kv_b_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
823 fAverage
= GetScaledFraction(le32_to_cpu(sKv_b_fuse
.ulEfuseEncodeAverage
), 1000);
824 fRange
= GetScaledFraction(le32_to_cpu(sKv_b_fuse
.ulEfuseEncodeRange
), 1000);
826 fKv_b_fused
= fDecodeLogisticFuse(ul_Kv_b_fused
,
827 fAverage
, fRange
, sKv_b_fuse
.ucEfuseLength
);
829 /* Decoding the Leakage - No special struct container */
833 * ucLkgEfuseLength=10
834 * ulLkgEncodeLn_MaxDivMin=69077
835 * ulLkgEncodeMax=1000000
836 * ulLkgEncodeMin=1000
837 * ulEfuseLogisticAlpha=13
840 sInput_FuseValues
.usEfuseIndex
= getASICProfilingInfo
->usLkgEuseIndex
;
841 sInput_FuseValues
.ucBitShift
= getASICProfilingInfo
->ucLkgEfuseBitLSB
;
842 sInput_FuseValues
.ucBitLength
= getASICProfilingInfo
->ucLkgEfuseLength
;
844 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
846 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
847 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
848 &sOutput_FuseValues
);
853 ul_FT_Lkg_V0NORM
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
854 fLn_MaxDivMin
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulLkgEncodeLn_MaxDivMin
), 10000);
855 fMin
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulLkgEncodeMin
), 10000);
857 fFT_Lkg_V0NORM
= fDecodeLeakageID(ul_FT_Lkg_V0NORM
,
858 fLn_MaxDivMin
, fMin
, getASICProfilingInfo
->ucLkgEfuseLength
);
859 fLkg_FT
= fFT_Lkg_V0NORM
;
861 /*-------------------------------------------
862 * PART 2 - Grabbing all required values
863 *-------------------------------------------
865 fSM_A0
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A0
), 1000000),
866 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A0_sign
)));
867 fSM_A1
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A1
), 1000000),
868 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A1_sign
)));
869 fSM_A2
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A2
), 100000),
870 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A2_sign
)));
871 fSM_A3
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A3
), 1000000),
872 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A3_sign
)));
873 fSM_A4
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A4
), 1000000),
874 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A4_sign
)));
875 fSM_A5
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A5
), 1000),
876 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A5_sign
)));
877 fSM_A6
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A6
), 1000),
878 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A6_sign
)));
879 fSM_A7
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A7
), 1000),
880 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A7_sign
)));
882 fMargin_RO_a
= ConvertToFraction(le32_to_cpu(getASICProfilingInfo
->ulMargin_RO_a
));
883 fMargin_RO_b
= ConvertToFraction(le32_to_cpu(getASICProfilingInfo
->ulMargin_RO_b
));
884 fMargin_RO_c
= ConvertToFraction(le32_to_cpu(getASICProfilingInfo
->ulMargin_RO_c
));
886 fMargin_fixed
= ConvertToFraction(le32_to_cpu(getASICProfilingInfo
->ulMargin_fixed
));
888 fMargin_FMAX_mean
= GetScaledFraction(
889 le32_to_cpu(getASICProfilingInfo
->ulMargin_Fmax_mean
), 10000);
890 fMargin_Plat_mean
= GetScaledFraction(
891 le32_to_cpu(getASICProfilingInfo
->ulMargin_plat_mean
), 10000);
892 fMargin_FMAX_sigma
= GetScaledFraction(
893 le32_to_cpu(getASICProfilingInfo
->ulMargin_Fmax_sigma
), 10000);
894 fMargin_Plat_sigma
= GetScaledFraction(
895 le32_to_cpu(getASICProfilingInfo
->ulMargin_plat_sigma
), 10000);
897 fMargin_DC_sigma
= GetScaledFraction(
898 le32_to_cpu(getASICProfilingInfo
->ulMargin_DC_sigma
), 100);
899 fMargin_DC_sigma
= fDivide(fMargin_DC_sigma
, ConvertToFraction(1000));
901 fCACm_fused
= fDivide(fCACm_fused
, ConvertToFraction(100));
902 fCACb_fused
= fDivide(fCACb_fused
, ConvertToFraction(100));
903 fKt_Beta_fused
= fDivide(fKt_Beta_fused
, ConvertToFraction(100));
904 fKv_m_fused
= fNegate(fDivide(fKv_m_fused
, ConvertToFraction(100)));
905 fKv_b_fused
= fDivide(fKv_b_fused
, ConvertToFraction(10));
907 fSclk
= GetScaledFraction(sclk
, 100);
909 fV_max
= fDivide(GetScaledFraction(
910 le32_to_cpu(getASICProfilingInfo
->ulMaxVddc
), 1000), ConvertToFraction(4));
911 fT_prod
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulBoardCoreTemp
), 10);
912 fLKG_Factor
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulEvvLkgFactor
), 100);
913 fT_FT
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulLeakageTemp
), 10);
914 fV_FT
= fDivide(GetScaledFraction(
915 le32_to_cpu(getASICProfilingInfo
->ulLeakageVoltage
), 1000), ConvertToFraction(4));
916 fV_min
= fDivide(GetScaledFraction(
917 le32_to_cpu(getASICProfilingInfo
->ulMinVddc
), 1000), ConvertToFraction(4));
919 /*-----------------------
921 *-----------------------
924 fA_Term
= fAdd(fMargin_RO_a
, fAdd(fMultiply(fSM_A4
, fSclk
), fSM_A5
));
925 fB_Term
= fAdd(fAdd(fMultiply(fSM_A2
, fSclk
), fSM_A6
), fMargin_RO_b
);
926 fC_Term
= fAdd(fMargin_RO_c
,
927 fAdd(fMultiply(fSM_A0
, fLkg_FT
),
928 fAdd(fMultiply(fSM_A1
, fMultiply(fLkg_FT
, fSclk
)),
929 fAdd(fMultiply(fSM_A3
, fSclk
),
930 fSubtract(fSM_A7
, fRO_fused
)))));
932 fVDDC_base
= fSubtract(fRO_fused
,
933 fSubtract(fMargin_RO_c
,
934 fSubtract(fSM_A3
, fMultiply(fSM_A1
, fSclk
))));
935 fVDDC_base
= fDivide(fVDDC_base
, fAdd(fMultiply(fSM_A0
, fSclk
), fSM_A2
));
937 repeat
= fSubtract(fVDDC_base
,
938 fDivide(fMargin_DC_sigma
, ConvertToFraction(1000)));
940 fRO_DC_margin
= fAdd(fMultiply(fMargin_RO_a
,
942 fAdd(fMultiply(fMargin_RO_b
, repeat
),
945 fDC_SCLK
= fSubtract(fRO_fused
,
946 fSubtract(fRO_DC_margin
,
948 fMultiply(fSM_A2
, repeat
))));
949 fDC_SCLK
= fDivide(fDC_SCLK
, fAdd(fMultiply(fSM_A0
, repeat
), fSM_A1
));
951 fSigma_DC
= fSubtract(fSclk
, fDC_SCLK
);
953 fMicro_FMAX
= fMultiply(fSclk
, fMargin_FMAX_mean
);
954 fMicro_CR
= fMultiply(fSclk
, fMargin_Plat_mean
);
955 fSigma_FMAX
= fMultiply(fSclk
, fMargin_FMAX_sigma
);
956 fSigma_CR
= fMultiply(fSclk
, fMargin_Plat_sigma
);
958 fSquared_Sigma_DC
= fGetSquare(fSigma_DC
);
959 fSquared_Sigma_CR
= fGetSquare(fSigma_CR
);
960 fSquared_Sigma_FMAX
= fGetSquare(fSigma_FMAX
);
962 fSclk_margin
= fAdd(fMicro_FMAX
,
965 fSqrt(fAdd(fSquared_Sigma_FMAX
,
966 fAdd(fSquared_Sigma_DC
, fSquared_Sigma_CR
))))));
968 fA_Term = fSM_A4 * (fSclk + fSclk_margin) + fSM_A5;
969 fB_Term = fSM_A2 * (fSclk + fSclk_margin) + fSM_A6;
970 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;
973 fA_Term
= fAdd(fMultiply(fSM_A4
, fAdd(fSclk
, fSclk_margin
)), fSM_A5
);
974 fB_Term
= fAdd(fMultiply(fSM_A2
, fAdd(fSclk
, fSclk_margin
)), fSM_A6
);
975 fC_Term
= fAdd(fRO_DC_margin
,
976 fAdd(fMultiply(fSM_A0
, fLkg_FT
),
977 fAdd(fMultiply(fMultiply(fSM_A1
, fLkg_FT
),
978 fAdd(fSclk
, fSclk_margin
)),
979 fAdd(fMultiply(fSM_A3
,
980 fAdd(fSclk
, fSclk_margin
)),
981 fSubtract(fSM_A7
, fRO_fused
)))));
983 SolveQuadracticEqn(fA_Term
, fB_Term
, fC_Term
, fRoots
);
985 if (GreaterThan(fRoots
[0], fRoots
[1]))
990 if (GreaterThan(fV_min
, fEVV_V
))
992 else if (GreaterThan(fEVV_V
, fV_max
))
993 fEVV_V
= fSubtract(fV_max
, fStepSize
);
995 fEVV_V
= fRoundUpByStepSize(fEVV_V
, fStepSize
, 0);
1004 while (GreaterThan(fAdd(fV_max
, fStepSize
), fV_x
)) {
1005 fTDP_Power_left
= fMultiply(fMultiply(fMultiply(fAdd(
1006 fMultiply(fCACm_fused
, fV_x
), fCACb_fused
), fSclk
),
1007 fGetSquare(fV_x
)), fDerateTDP
);
1009 fTDP_Power_right
= fMultiply(fFT_Lkg_V0NORM
, fMultiply(fLKG_Factor
,
1010 fMultiply(fExponential(fMultiply(fAdd(fMultiply(fKv_m_fused
,
1011 fT_prod
), fKv_b_fused
), fV_x
)), fV_x
)));
1012 fTDP_Power_right
= fMultiply(fTDP_Power_right
, fExponential(fMultiply(
1013 fKt_Beta_fused
, fT_prod
)));
1014 fTDP_Power_right
= fDivide(fTDP_Power_right
, fExponential(fMultiply(
1015 fAdd(fMultiply(fKv_m_fused
, fT_prod
), fKv_b_fused
), fV_FT
)));
1016 fTDP_Power_right
= fDivide(fTDP_Power_right
, fExponential(fMultiply(
1017 fKt_Beta_fused
, fT_FT
)));
1019 fTDP_Power
= fAdd(fTDP_Power_left
, fTDP_Power_right
);
1021 fTDP_Current
= fDivide(fTDP_Power
, fV_x
);
1023 fV_NL
= fAdd(fV_x
, fDivide(fMultiply(fTDP_Current
, fRLL_LoadLine
),
1024 ConvertToFraction(10)));
1026 fV_NL
= fRoundUpByStepSize(fV_NL
, fStepSize
, 0);
1028 if (GreaterThan(fV_max
, fV_NL
) &&
1029 (GreaterThan(fV_NL
, fEVV_V
) ||
1030 Equal(fV_NL
, fEVV_V
))) {
1031 fV_NL
= fMultiply(fV_NL
, ConvertToFraction(1000));
1033 *voltage
= (uint16_t)fV_NL
.partial
.real
;
1036 fV_x
= fAdd(fV_x
, fStepSize
);
1042 /** atomctrl_get_voltage_evv_on_sclk gets voltage via call to ATOM COMMAND table.
1043 * @param hwmgr input: pointer to hwManager
1044 * @param voltage_type input: type of EVV voltage VDDC or VDDGFX
1045 * @param sclk input: in 10Khz unit. DPM state SCLK frequency
1046 * which is define in PPTable SCLK/VDDC dependence
1047 * table associated with this virtual_voltage_Id
1048 * @param virtual_voltage_Id input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
1049 * @param voltage output: real voltage level in unit of mv
1051 int atomctrl_get_voltage_evv_on_sclk(
1052 struct pp_hwmgr
*hwmgr
,
1053 uint8_t voltage_type
,
1054 uint32_t sclk
, uint16_t virtual_voltage_Id
,
1058 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space
;
1060 get_voltage_info_param_space
.ucVoltageType
=
1062 get_voltage_info_param_space
.ucVoltageMode
=
1063 ATOM_GET_VOLTAGE_EVV_VOLTAGE
;
1064 get_voltage_info_param_space
.usVoltageLevel
=
1065 cpu_to_le16(virtual_voltage_Id
);
1066 get_voltage_info_param_space
.ulSCLKFreq
=
1069 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
1070 GetIndexIntoMasterTable(COMMAND
, GetVoltageInfo
),
1071 &get_voltage_info_param_space
);
1076 *voltage
= le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2
*)
1077 (&get_voltage_info_param_space
))->usVoltageLevel
);
1083 * atomctrl_get_voltage_evv gets voltage via call to ATOM COMMAND table.
1084 * @param hwmgr input: pointer to hwManager
1085 * @param virtual_voltage_id input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
1086 * @param voltage output: real voltage level in unit of mv
1088 int atomctrl_get_voltage_evv(struct pp_hwmgr
*hwmgr
,
1089 uint16_t virtual_voltage_id
,
1094 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space
;
1096 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
1097 for (entry_id
= 0; entry_id
< hwmgr
->dyn_state
.vddc_dependency_on_sclk
->count
; entry_id
++) {
1098 if (hwmgr
->dyn_state
.vddc_dependency_on_sclk
->entries
[entry_id
].v
== virtual_voltage_id
) {
1104 PP_ASSERT_WITH_CODE(entry_id
< hwmgr
->dyn_state
.vddc_dependency_on_sclk
->count
,
1105 "Can't find requested voltage id in vddc_dependency_on_sclk table!",
1109 get_voltage_info_param_space
.ucVoltageType
= VOLTAGE_TYPE_VDDC
;
1110 get_voltage_info_param_space
.ucVoltageMode
= ATOM_GET_VOLTAGE_EVV_VOLTAGE
;
1111 get_voltage_info_param_space
.usVoltageLevel
= virtual_voltage_id
;
1112 get_voltage_info_param_space
.ulSCLKFreq
=
1113 cpu_to_le32(hwmgr
->dyn_state
.vddc_dependency_on_sclk
->entries
[entry_id
].clk
);
1115 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
1116 GetIndexIntoMasterTable(COMMAND
, GetVoltageInfo
),
1117 &get_voltage_info_param_space
);
1122 *voltage
= le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2
*)
1123 (&get_voltage_info_param_space
))->usVoltageLevel
);
1129 * Get the mpll reference clock in 10KHz
1131 uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr
*hwmgr
)
1133 ATOM_COMMON_TABLE_HEADER
*fw_info
;
1138 fw_info
= (ATOM_COMMON_TABLE_HEADER
*)
1139 cgs_atom_get_data_table(hwmgr
->device
,
1140 GetIndexIntoMasterTable(DATA
, FirmwareInfo
),
1141 &size
, &frev
, &crev
);
1143 if (fw_info
== NULL
)
1146 if ((fw_info
->ucTableFormatRevision
== 2) &&
1147 (le16_to_cpu(fw_info
->usStructureSize
) >= sizeof(ATOM_FIRMWARE_INFO_V2_1
))) {
1148 ATOM_FIRMWARE_INFO_V2_1
*fwInfo_2_1
=
1149 (ATOM_FIRMWARE_INFO_V2_1
*)fw_info
;
1150 clock
= (uint32_t)(le16_to_cpu(fwInfo_2_1
->usMemoryReferenceClock
));
1152 ATOM_FIRMWARE_INFO
*fwInfo_0_0
=
1153 (ATOM_FIRMWARE_INFO
*)fw_info
;
1154 clock
= (uint32_t)(le16_to_cpu(fwInfo_0_0
->usReferenceClock
));
1162 * Get the asic internal spread spectrum table
1164 static ATOM_ASIC_INTERNAL_SS_INFO
*asic_internal_ss_get_ss_table(void *device
)
1166 ATOM_ASIC_INTERNAL_SS_INFO
*table
= NULL
;
1170 table
= (ATOM_ASIC_INTERNAL_SS_INFO
*)
1171 cgs_atom_get_data_table(device
,
1172 GetIndexIntoMasterTable(DATA
, ASIC_InternalSS_Info
),
1173 &size
, &frev
, &crev
);
1179 * Get the asic internal spread spectrum assignment
1181 static int asic_internal_ss_get_ss_asignment(struct pp_hwmgr
*hwmgr
,
1182 const uint8_t clockSource
,
1183 const uint32_t clockSpeed
,
1184 pp_atomctrl_internal_ss_info
*ssEntry
)
1186 ATOM_ASIC_INTERNAL_SS_INFO
*table
;
1187 ATOM_ASIC_SS_ASSIGNMENT
*ssInfo
;
1188 int entry_found
= 0;
1190 memset(ssEntry
, 0x00, sizeof(pp_atomctrl_internal_ss_info
));
1192 table
= asic_internal_ss_get_ss_table(hwmgr
->device
);
1197 ssInfo
= &table
->asSpreadSpectrum
[0];
1199 while (((uint8_t *)ssInfo
- (uint8_t *)table
) <
1200 le16_to_cpu(table
->sHeader
.usStructureSize
)) {
1201 if ((clockSource
== ssInfo
->ucClockIndication
) &&
1202 ((uint32_t)clockSpeed
<= le32_to_cpu(ssInfo
->ulTargetClockRange
))) {
1207 ssInfo
= (ATOM_ASIC_SS_ASSIGNMENT
*)((uint8_t *)ssInfo
+
1208 sizeof(ATOM_ASIC_SS_ASSIGNMENT
));
1212 ssEntry
->speed_spectrum_percentage
=
1213 le16_to_cpu(ssInfo
->usSpreadSpectrumPercentage
);
1214 ssEntry
->speed_spectrum_rate
= le16_to_cpu(ssInfo
->usSpreadRateInKhz
);
1216 if (((GET_DATA_TABLE_MAJOR_REVISION(table
) == 2) &&
1217 (GET_DATA_TABLE_MINOR_REVISION(table
) >= 2)) ||
1218 (GET_DATA_TABLE_MAJOR_REVISION(table
) == 3)) {
1219 ssEntry
->speed_spectrum_rate
/= 100;
1222 switch (ssInfo
->ucSpreadSpectrumMode
) {
1224 ssEntry
->speed_spectrum_mode
=
1225 pp_atomctrl_spread_spectrum_mode_down
;
1228 ssEntry
->speed_spectrum_mode
=
1229 pp_atomctrl_spread_spectrum_mode_center
;
1232 ssEntry
->speed_spectrum_mode
=
1233 pp_atomctrl_spread_spectrum_mode_down
;
1238 return entry_found
? 0 : 1;
1242 * Get the memory clock spread spectrum info
1244 int atomctrl_get_memory_clock_spread_spectrum(
1245 struct pp_hwmgr
*hwmgr
,
1246 const uint32_t memory_clock
,
1247 pp_atomctrl_internal_ss_info
*ssInfo
)
1249 return asic_internal_ss_get_ss_asignment(hwmgr
,
1250 ASIC_INTERNAL_MEMORY_SS
, memory_clock
, ssInfo
);
1253 * Get the engine clock spread spectrum info
1255 int atomctrl_get_engine_clock_spread_spectrum(
1256 struct pp_hwmgr
*hwmgr
,
1257 const uint32_t engine_clock
,
1258 pp_atomctrl_internal_ss_info
*ssInfo
)
1260 return asic_internal_ss_get_ss_asignment(hwmgr
,
1261 ASIC_INTERNAL_ENGINE_SS
, engine_clock
, ssInfo
);
1264 int atomctrl_read_efuse(void *device
, uint16_t start_index
,
1265 uint16_t end_index
, uint32_t mask
, uint32_t *efuse
)
1268 READ_EFUSE_VALUE_PARAMETER efuse_param
;
1270 efuse_param
.sEfuse
.usEfuseIndex
= cpu_to_le16((start_index
/ 32) * 4);
1271 efuse_param
.sEfuse
.ucBitShift
= (uint8_t)
1272 (start_index
- ((start_index
/ 32) * 32));
1273 efuse_param
.sEfuse
.ucBitLength
= (uint8_t)
1274 ((end_index
- start_index
) + 1);
1276 result
= cgs_atom_exec_cmd_table(device
,
1277 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
1280 *efuse
= le32_to_cpu(efuse_param
.ulEfuseValue
) & mask
;
1285 int atomctrl_set_ac_timing_ai(struct pp_hwmgr
*hwmgr
, uint32_t memory_clock
,
1288 DYNAMICE_MEMORY_SETTINGS_PARAMETER_V2_1 memory_clock_parameters
;
1291 memory_clock_parameters
.asDPMMCReg
.ulClock
.ulClockFreq
=
1292 memory_clock
& SET_CLOCK_FREQ_MASK
;
1293 memory_clock_parameters
.asDPMMCReg
.ulClock
.ulComputeClockFlag
=
1294 ADJUST_MC_SETTING_PARAM
;
1295 memory_clock_parameters
.asDPMMCReg
.ucMclkDPMState
= level
;
1297 result
= cgs_atom_exec_cmd_table
1299 GetIndexIntoMasterTable(COMMAND
, DynamicMemorySettings
),
1300 &memory_clock_parameters
);
1305 int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr
*hwmgr
, uint8_t voltage_type
,
1306 uint32_t sclk
, uint16_t virtual_voltage_Id
, uint32_t *voltage
)
1310 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_3 get_voltage_info_param_space
;
1312 get_voltage_info_param_space
.ucVoltageType
= voltage_type
;
1313 get_voltage_info_param_space
.ucVoltageMode
= ATOM_GET_VOLTAGE_EVV_VOLTAGE
;
1314 get_voltage_info_param_space
.usVoltageLevel
= cpu_to_le16(virtual_voltage_Id
);
1315 get_voltage_info_param_space
.ulSCLKFreq
= cpu_to_le32(sclk
);
1317 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
1318 GetIndexIntoMasterTable(COMMAND
, GetVoltageInfo
),
1319 &get_voltage_info_param_space
);
1324 *voltage
= le32_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_3
*)(&get_voltage_info_param_space
))->ulVoltageLevel
);
1329 int atomctrl_get_smc_sclk_range_table(struct pp_hwmgr
*hwmgr
, struct pp_atom_ctrl_sclk_range_table
*table
)
1336 ATOM_SMU_INFO_V2_1
*psmu_info
=
1337 (ATOM_SMU_INFO_V2_1
*)cgs_atom_get_data_table(hwmgr
->device
,
1338 GetIndexIntoMasterTable(DATA
, SMU_Info
),
1339 &size
, &frev
, &crev
);
1342 for (i
= 0; i
< psmu_info
->ucSclkEntryNum
; i
++) {
1343 table
->entry
[i
].ucVco_setting
= psmu_info
->asSclkFcwRangeEntry
[i
].ucVco_setting
;
1344 table
->entry
[i
].ucPostdiv
= psmu_info
->asSclkFcwRangeEntry
[i
].ucPostdiv
;
1345 table
->entry
[i
].usFcw_pcc
=
1346 le16_to_cpu(psmu_info
->asSclkFcwRangeEntry
[i
].ucFcw_pcc
);
1347 table
->entry
[i
].usFcw_trans_upper
=
1348 le16_to_cpu(psmu_info
->asSclkFcwRangeEntry
[i
].ucFcw_trans_upper
);
1349 table
->entry
[i
].usRcw_trans_lower
=
1350 le16_to_cpu(psmu_info
->asSclkFcwRangeEntry
[i
].ucRcw_trans_lower
);
1356 int atomctrl_get_avfs_information(struct pp_hwmgr
*hwmgr
,
1357 struct pp_atom_ctrl__avfs_parameters
*param
)
1359 ATOM_ASIC_PROFILING_INFO_V3_6
*profile
= NULL
;
1364 profile
= (ATOM_ASIC_PROFILING_INFO_V3_6
*)
1365 cgs_atom_get_data_table(hwmgr
->device
,
1366 GetIndexIntoMasterTable(DATA
, ASIC_ProfilingInfo
),
1371 param
->ulAVFS_meanNsigma_Acontant0
= le32_to_cpu(profile
->ulAVFS_meanNsigma_Acontant0
);
1372 param
->ulAVFS_meanNsigma_Acontant1
= le32_to_cpu(profile
->ulAVFS_meanNsigma_Acontant1
);
1373 param
->ulAVFS_meanNsigma_Acontant2
= le32_to_cpu(profile
->ulAVFS_meanNsigma_Acontant2
);
1374 param
->usAVFS_meanNsigma_DC_tol_sigma
= le16_to_cpu(profile
->usAVFS_meanNsigma_DC_tol_sigma
);
1375 param
->usAVFS_meanNsigma_Platform_mean
= le16_to_cpu(profile
->usAVFS_meanNsigma_Platform_mean
);
1376 param
->usAVFS_meanNsigma_Platform_sigma
= le16_to_cpu(profile
->usAVFS_meanNsigma_Platform_sigma
);
1377 param
->ulGB_VDROOP_TABLE_CKSOFF_a0
= le32_to_cpu(profile
->ulGB_VDROOP_TABLE_CKSOFF_a0
);
1378 param
->ulGB_VDROOP_TABLE_CKSOFF_a1
= le32_to_cpu(profile
->ulGB_VDROOP_TABLE_CKSOFF_a1
);
1379 param
->ulGB_VDROOP_TABLE_CKSOFF_a2
= le32_to_cpu(profile
->ulGB_VDROOP_TABLE_CKSOFF_a2
);
1380 param
->ulGB_VDROOP_TABLE_CKSON_a0
= le32_to_cpu(profile
->ulGB_VDROOP_TABLE_CKSON_a0
);
1381 param
->ulGB_VDROOP_TABLE_CKSON_a1
= le32_to_cpu(profile
->ulGB_VDROOP_TABLE_CKSON_a1
);
1382 param
->ulGB_VDROOP_TABLE_CKSON_a2
= le32_to_cpu(profile
->ulGB_VDROOP_TABLE_CKSON_a2
);
1383 param
->ulAVFSGB_FUSE_TABLE_CKSOFF_m1
= le32_to_cpu(profile
->ulAVFSGB_FUSE_TABLE_CKSOFF_m1
);
1384 param
->usAVFSGB_FUSE_TABLE_CKSOFF_m2
= le16_to_cpu(profile
->usAVFSGB_FUSE_TABLE_CKSOFF_m2
);
1385 param
->ulAVFSGB_FUSE_TABLE_CKSOFF_b
= le32_to_cpu(profile
->ulAVFSGB_FUSE_TABLE_CKSOFF_b
);
1386 param
->ulAVFSGB_FUSE_TABLE_CKSON_m1
= le32_to_cpu(profile
->ulAVFSGB_FUSE_TABLE_CKSON_m1
);
1387 param
->usAVFSGB_FUSE_TABLE_CKSON_m2
= le16_to_cpu(profile
->usAVFSGB_FUSE_TABLE_CKSON_m2
);
1388 param
->ulAVFSGB_FUSE_TABLE_CKSON_b
= le32_to_cpu(profile
->ulAVFSGB_FUSE_TABLE_CKSON_b
);
1389 param
->usMaxVoltage_0_25mv
= le16_to_cpu(profile
->usMaxVoltage_0_25mv
);
1390 param
->ucEnableGB_VDROOP_TABLE_CKSOFF
= profile
->ucEnableGB_VDROOP_TABLE_CKSOFF
;
1391 param
->ucEnableGB_VDROOP_TABLE_CKSON
= profile
->ucEnableGB_VDROOP_TABLE_CKSON
;
1392 param
->ucEnableGB_FUSE_TABLE_CKSOFF
= profile
->ucEnableGB_FUSE_TABLE_CKSOFF
;
1393 param
->ucEnableGB_FUSE_TABLE_CKSON
= profile
->ucEnableGB_FUSE_TABLE_CKSON
;
1394 param
->usPSM_Age_ComFactor
= le16_to_cpu(profile
->usPSM_Age_ComFactor
);
1395 param
->ucEnableApplyAVFS_CKS_OFF_Voltage
= profile
->ucEnableApplyAVFS_CKS_OFF_Voltage
;