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>
26 #include "ppatomctrl.h"
28 #include "cgs_common.h"
30 #include "ppevvmath.h"
32 #define MEM_ID_MASK 0xff000000
33 #define MEM_ID_SHIFT 24
34 #define CLOCK_RANGE_MASK 0x00ffffff
35 #define CLOCK_RANGE_SHIFT 0
36 #define LOW_NIBBLE_MASK 0xf
37 #define DATA_EQU_PREV 0
38 #define DATA_FROM_TABLE 4
40 union voltage_object_info
{
41 struct _ATOM_VOLTAGE_OBJECT_INFO v1
;
42 struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2
;
43 struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3
;
46 static int atomctrl_retrieve_ac_timing(
48 ATOM_INIT_REG_BLOCK
*reg_block
,
49 pp_atomctrl_mc_reg_table
*table
)
53 ATOM_MEMORY_SETTING_DATA_BLOCK
*reg_data
= (ATOM_MEMORY_SETTING_DATA_BLOCK
*)
54 ((uint8_t *)reg_block
+ (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block
->usRegIndexTblSize
));
56 uint8_t num_ranges
= 0;
58 while (*(uint32_t *)reg_data
!= END_OF_REG_DATA_BLOCK
&&
59 num_ranges
< VBIOS_MAX_AC_TIMING_ENTRIES
) {
60 tmem_id
= (uint8_t)((*(uint32_t *)reg_data
& MEM_ID_MASK
) >> MEM_ID_SHIFT
);
62 if (index
== tmem_id
) {
63 table
->mc_reg_table_entry
[num_ranges
].mclk_max
=
64 (uint32_t)((*(uint32_t *)reg_data
& CLOCK_RANGE_MASK
) >>
67 for (i
= 0, j
= 1; i
< table
->last
; i
++) {
68 if ((table
->mc_reg_address
[i
].uc_pre_reg_data
&
69 LOW_NIBBLE_MASK
) == DATA_FROM_TABLE
) {
70 table
->mc_reg_table_entry
[num_ranges
].mc_data
[i
] =
71 (uint32_t)*((uint32_t *)reg_data
+ j
);
73 } else if ((table
->mc_reg_address
[i
].uc_pre_reg_data
&
74 LOW_NIBBLE_MASK
) == DATA_EQU_PREV
) {
75 table
->mc_reg_table_entry
[num_ranges
].mc_data
[i
] =
76 table
->mc_reg_table_entry
[num_ranges
].mc_data
[i
-1];
82 reg_data
= (ATOM_MEMORY_SETTING_DATA_BLOCK
*)
83 ((uint8_t *)reg_data
+ le16_to_cpu(reg_block
->usRegDataBlkSize
)) ;
86 PP_ASSERT_WITH_CODE((*(uint32_t *)reg_data
== END_OF_REG_DATA_BLOCK
),
87 "Invalid VramInfo table.", return -1);
88 table
->num_entries
= num_ranges
;
94 * Get memory clock AC timing registers index from VBIOS table
95 * VBIOS set end of memory clock AC timing registers by ucPreRegDataLength bit6 = 1
96 * @param reg_block the address ATOM_INIT_REG_BLOCK
97 * @param table the address of MCRegTable
100 static int atomctrl_set_mc_reg_address_table(
101 ATOM_INIT_REG_BLOCK
*reg_block
,
102 pp_atomctrl_mc_reg_table
*table
)
105 uint8_t num_entries
= (uint8_t)((le16_to_cpu(reg_block
->usRegIndexTblSize
))
106 / sizeof(ATOM_INIT_REG_INDEX_FORMAT
));
107 ATOM_INIT_REG_INDEX_FORMAT
*format
= ®_block
->asRegIndexBuf
[0];
109 num_entries
--; /* subtract 1 data end mark entry */
111 PP_ASSERT_WITH_CODE((num_entries
<= VBIOS_MC_REGISTER_ARRAY_SIZE
),
112 "Invalid VramInfo table.", return -1);
114 /* ucPreRegDataLength bit6 = 1 is the end of memory clock AC timing registers */
115 while ((!(format
->ucPreRegDataLength
& ACCESS_PLACEHOLDER
)) &&
117 table
->mc_reg_address
[i
].s1
=
118 (uint16_t)(le16_to_cpu(format
->usRegIndex
));
119 table
->mc_reg_address
[i
].uc_pre_reg_data
=
120 format
->ucPreRegDataLength
;
123 format
= (ATOM_INIT_REG_INDEX_FORMAT
*)
124 ((uint8_t *)format
+ sizeof(ATOM_INIT_REG_INDEX_FORMAT
));
132 int atomctrl_initialize_mc_reg_table(
133 struct pp_hwmgr
*hwmgr
,
134 uint8_t module_index
,
135 pp_atomctrl_mc_reg_table
*table
)
137 ATOM_VRAM_INFO_HEADER_V2_1
*vram_info
;
138 ATOM_INIT_REG_BLOCK
*reg_block
;
143 vram_info
= (ATOM_VRAM_INFO_HEADER_V2_1
*)
144 cgs_atom_get_data_table(hwmgr
->device
,
145 GetIndexIntoMasterTable(DATA
, VRAM_Info
), &size
, &frev
, &crev
);
147 if (module_index
>= vram_info
->ucNumOfVRAMModule
) {
148 printk(KERN_ERR
"[ powerplay ] Invalid VramInfo table.");
150 } else if (vram_info
->sHeader
.ucTableFormatRevision
< 2) {
151 printk(KERN_ERR
"[ powerplay ] Invalid VramInfo table.");
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
);
162 result
= atomctrl_retrieve_ac_timing(module_index
,
170 * Set DRAM timings based on engine clock and memory clock.
172 int atomctrl_set_engine_dram_timings_rv770(
173 struct pp_hwmgr
*hwmgr
,
174 uint32_t engine_clock
,
175 uint32_t memory_clock
)
177 SET_ENGINE_CLOCK_PS_ALLOCATION engine_clock_parameters
;
179 /* They are both in 10KHz Units. */
180 engine_clock_parameters
.ulTargetEngineClock
=
181 cpu_to_le32((engine_clock
& SET_CLOCK_FREQ_MASK
) |
182 ((COMPUTE_ENGINE_PLL_PARAM
<< 24)));
184 /* in 10 khz units.*/
185 engine_clock_parameters
.sReserved
.ulClock
=
186 cpu_to_le32(memory_clock
& SET_CLOCK_FREQ_MASK
);
187 return cgs_atom_exec_cmd_table(hwmgr
->device
,
188 GetIndexIntoMasterTable(COMMAND
, DynamicMemorySettings
),
189 &engine_clock_parameters
);
193 * Private Function to get the PowerPlay Table Address.
194 * WARNING: The tabled returned by this function is in
195 * dynamically allocated memory.
196 * The caller has to release if by calling kfree.
198 static ATOM_VOLTAGE_OBJECT_INFO
*get_voltage_info_table(void *device
)
200 int index
= GetIndexIntoMasterTable(DATA
, VoltageObjectInfo
);
203 union voltage_object_info
*voltage_info
;
205 voltage_info
= (union voltage_object_info
*)
206 cgs_atom_get_data_table(device
, index
,
207 &size
, &frev
, &crev
);
209 if (voltage_info
!= NULL
)
210 return (ATOM_VOLTAGE_OBJECT_INFO
*) &(voltage_info
->v3
);
215 static const ATOM_VOLTAGE_OBJECT_V3
*atomctrl_lookup_voltage_type_v3(
216 const ATOM_VOLTAGE_OBJECT_INFO_V3_1
* voltage_object_info_table
,
217 uint8_t voltage_type
, uint8_t voltage_mode
)
219 unsigned int size
= le16_to_cpu(voltage_object_info_table
->sHeader
.usStructureSize
);
220 unsigned int offset
= offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1
, asVoltageObj
[0]);
221 uint8_t *start
= (uint8_t *)voltage_object_info_table
;
223 while (offset
< size
) {
224 const ATOM_VOLTAGE_OBJECT_V3
*voltage_object
=
225 (const ATOM_VOLTAGE_OBJECT_V3
*)(start
+ offset
);
227 if (voltage_type
== voltage_object
->asGpioVoltageObj
.sHeader
.ucVoltageType
&&
228 voltage_mode
== voltage_object
->asGpioVoltageObj
.sHeader
.ucVoltageMode
)
229 return voltage_object
;
231 offset
+= le16_to_cpu(voltage_object
->asGpioVoltageObj
.sHeader
.usSize
);
237 /** atomctrl_get_memory_pll_dividers_si().
239 * @param hwmgr input parameter: pointer to HwMgr
240 * @param clock_value input parameter: memory clock
241 * @param dividers output parameter: memory PLL dividers
242 * @param strobe_mode input parameter: 1 for strobe mode, 0 for performance mode
244 int atomctrl_get_memory_pll_dividers_si(
245 struct pp_hwmgr
*hwmgr
,
246 uint32_t clock_value
,
247 pp_atomctrl_memory_clock_param
*mpll_param
,
250 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 mpll_parameters
;
253 mpll_parameters
.ulClock
= cpu_to_le32(clock_value
);
254 mpll_parameters
.ucInputFlag
= (uint8_t)((strobe_mode
) ? 1 : 0);
256 result
= cgs_atom_exec_cmd_table
258 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryClockParam
),
262 mpll_param
->mpll_fb_divider
.clk_frac
=
263 le16_to_cpu(mpll_parameters
.ulFbDiv
.usFbDivFrac
);
264 mpll_param
->mpll_fb_divider
.cl_kf
=
265 le16_to_cpu(mpll_parameters
.ulFbDiv
.usFbDiv
);
266 mpll_param
->mpll_post_divider
=
267 (uint32_t)mpll_parameters
.ucPostDiv
;
268 mpll_param
->vco_mode
=
269 (uint32_t)(mpll_parameters
.ucPllCntlFlag
&
270 MPLL_CNTL_FLAG_VCO_MODE_MASK
);
271 mpll_param
->yclk_sel
=
272 (uint32_t)((mpll_parameters
.ucPllCntlFlag
&
273 MPLL_CNTL_FLAG_BYPASS_DQ_PLL
) ? 1 : 0);
275 (uint32_t)((mpll_parameters
.ucPllCntlFlag
&
276 MPLL_CNTL_FLAG_QDR_ENABLE
) ? 1 : 0);
277 mpll_param
->half_rate
=
278 (uint32_t)((mpll_parameters
.ucPllCntlFlag
&
279 MPLL_CNTL_FLAG_AD_HALF_RATE
) ? 1 : 0);
280 mpll_param
->dll_speed
=
281 (uint32_t)(mpll_parameters
.ucDllSpeed
);
282 mpll_param
->bw_ctrl
=
283 (uint32_t)(mpll_parameters
.ucBWCntl
);
289 /** atomctrl_get_memory_pll_dividers_vi().
291 * @param hwmgr input parameter: pointer to HwMgr
292 * @param clock_value input parameter: memory clock
293 * @param dividers output parameter: memory PLL dividers
295 int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr
*hwmgr
,
296 uint32_t clock_value
, pp_atomctrl_memory_clock_param
*mpll_param
)
298 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2 mpll_parameters
;
301 mpll_parameters
.ulClock
.ulClock
= cpu_to_le32(clock_value
);
303 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
304 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryClockParam
),
308 mpll_param
->mpll_post_divider
=
309 (uint32_t)mpll_parameters
.ulClock
.ucPostDiv
;
314 int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr
*hwmgr
,
315 uint32_t clock_value
,
316 pp_atomctrl_clock_dividers_kong
*dividers
)
318 COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 pll_parameters
;
321 pll_parameters
.ulClock
= cpu_to_le32(clock_value
);
323 result
= cgs_atom_exec_cmd_table
325 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
329 dividers
->pll_post_divider
= pll_parameters
.ucPostDiv
;
330 dividers
->real_clock
= le32_to_cpu(pll_parameters
.ulClock
);
336 int atomctrl_get_engine_pll_dividers_vi(
337 struct pp_hwmgr
*hwmgr
,
338 uint32_t clock_value
,
339 pp_atomctrl_clock_dividers_vi
*dividers
)
341 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters
;
344 pll_patameters
.ulClock
.ulClock
= cpu_to_le32(clock_value
);
345 pll_patameters
.ulClock
.ucPostDiv
= COMPUTE_GPUCLK_INPUT_FLAG_SCLK
;
347 result
= cgs_atom_exec_cmd_table
349 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
353 dividers
->pll_post_divider
=
354 pll_patameters
.ulClock
.ucPostDiv
;
355 dividers
->real_clock
=
356 le32_to_cpu(pll_patameters
.ulClock
.ulClock
);
358 dividers
->ul_fb_div
.ul_fb_div_frac
=
359 le16_to_cpu(pll_patameters
.ulFbDiv
.usFbDivFrac
);
360 dividers
->ul_fb_div
.ul_fb_div
=
361 le16_to_cpu(pll_patameters
.ulFbDiv
.usFbDiv
);
363 dividers
->uc_pll_ref_div
=
364 pll_patameters
.ucPllRefDiv
;
365 dividers
->uc_pll_post_div
=
366 pll_patameters
.ucPllPostDiv
;
367 dividers
->uc_pll_cntl_flag
=
368 pll_patameters
.ucPllCntlFlag
;
374 int atomctrl_get_engine_pll_dividers_ai(struct pp_hwmgr
*hwmgr
,
375 uint32_t clock_value
,
376 pp_atomctrl_clock_dividers_ai
*dividers
)
378 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_7 pll_patameters
;
381 pll_patameters
.ulClock
.ulClock
= cpu_to_le32(clock_value
);
382 pll_patameters
.ulClock
.ucPostDiv
= COMPUTE_GPUCLK_INPUT_FLAG_SCLK
;
384 result
= cgs_atom_exec_cmd_table
386 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
390 dividers
->usSclk_fcw_frac
= le16_to_cpu(pll_patameters
.usSclk_fcw_frac
);
391 dividers
->usSclk_fcw_int
= le16_to_cpu(pll_patameters
.usSclk_fcw_int
);
392 dividers
->ucSclkPostDiv
= pll_patameters
.ucSclkPostDiv
;
393 dividers
->ucSclkVcoMode
= pll_patameters
.ucSclkVcoMode
;
394 dividers
->ucSclkPllRange
= pll_patameters
.ucSclkPllRange
;
395 dividers
->ucSscEnable
= pll_patameters
.ucSscEnable
;
396 dividers
->usSsc_fcw1_frac
= le16_to_cpu(pll_patameters
.usSsc_fcw1_frac
);
397 dividers
->usSsc_fcw1_int
= le16_to_cpu(pll_patameters
.usSsc_fcw1_int
);
398 dividers
->usPcc_fcw_int
= le16_to_cpu(pll_patameters
.usPcc_fcw_int
);
399 dividers
->usSsc_fcw_slew_frac
= le16_to_cpu(pll_patameters
.usSsc_fcw_slew_frac
);
400 dividers
->usPcc_fcw_slew_frac
= le16_to_cpu(pll_patameters
.usPcc_fcw_slew_frac
);
405 int atomctrl_get_dfs_pll_dividers_vi(
406 struct pp_hwmgr
*hwmgr
,
407 uint32_t clock_value
,
408 pp_atomctrl_clock_dividers_vi
*dividers
)
410 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters
;
413 pll_patameters
.ulClock
.ulClock
= cpu_to_le32(clock_value
);
414 pll_patameters
.ulClock
.ucPostDiv
=
415 COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK
;
417 result
= cgs_atom_exec_cmd_table
419 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
423 dividers
->pll_post_divider
=
424 pll_patameters
.ulClock
.ucPostDiv
;
425 dividers
->real_clock
=
426 le32_to_cpu(pll_patameters
.ulClock
.ulClock
);
428 dividers
->ul_fb_div
.ul_fb_div_frac
=
429 le16_to_cpu(pll_patameters
.ulFbDiv
.usFbDivFrac
);
430 dividers
->ul_fb_div
.ul_fb_div
=
431 le16_to_cpu(pll_patameters
.ulFbDiv
.usFbDiv
);
433 dividers
->uc_pll_ref_div
=
434 pll_patameters
.ucPllRefDiv
;
435 dividers
->uc_pll_post_div
=
436 pll_patameters
.ucPllPostDiv
;
437 dividers
->uc_pll_cntl_flag
=
438 pll_patameters
.ucPllCntlFlag
;
445 * Get the reference clock in 10KHz
447 uint32_t atomctrl_get_reference_clock(struct pp_hwmgr
*hwmgr
)
449 ATOM_FIRMWARE_INFO
*fw_info
;
454 fw_info
= (ATOM_FIRMWARE_INFO
*)
455 cgs_atom_get_data_table(hwmgr
->device
,
456 GetIndexIntoMasterTable(DATA
, FirmwareInfo
),
457 &size
, &frev
, &crev
);
462 clock
= (uint32_t)(le16_to_cpu(fw_info
->usReferenceClock
));
468 * Returns true if the given voltage type is controlled by GPIO pins.
469 * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC,
470 * SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ.
471 * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE
473 bool atomctrl_is_voltage_controled_by_gpio_v3(
474 struct pp_hwmgr
*hwmgr
,
475 uint8_t voltage_type
,
476 uint8_t voltage_mode
)
478 ATOM_VOLTAGE_OBJECT_INFO_V3_1
*voltage_info
=
479 (ATOM_VOLTAGE_OBJECT_INFO_V3_1
*)get_voltage_info_table(hwmgr
->device
);
482 PP_ASSERT_WITH_CODE((NULL
!= voltage_info
),
483 "Could not find Voltage Table in BIOS.", return false;);
485 ret
= (NULL
!= atomctrl_lookup_voltage_type_v3
486 (voltage_info
, voltage_type
, voltage_mode
)) ? true : false;
491 int atomctrl_get_voltage_table_v3(
492 struct pp_hwmgr
*hwmgr
,
493 uint8_t voltage_type
,
494 uint8_t voltage_mode
,
495 pp_atomctrl_voltage_table
*voltage_table
)
497 ATOM_VOLTAGE_OBJECT_INFO_V3_1
*voltage_info
=
498 (ATOM_VOLTAGE_OBJECT_INFO_V3_1
*)get_voltage_info_table(hwmgr
->device
);
499 const ATOM_VOLTAGE_OBJECT_V3
*voltage_object
;
502 PP_ASSERT_WITH_CODE((NULL
!= voltage_info
),
503 "Could not find Voltage Table in BIOS.", return -1;);
505 voltage_object
= atomctrl_lookup_voltage_type_v3
506 (voltage_info
, voltage_type
, voltage_mode
);
508 if (voltage_object
== NULL
)
512 (voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
<=
513 PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES
),
514 "Too many voltage entries!",
518 for (i
= 0; i
< voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
; i
++) {
519 voltage_table
->entries
[i
].value
=
520 le16_to_cpu(voltage_object
->asGpioVoltageObj
.asVolGpioLut
[i
].usVoltageValue
);
521 voltage_table
->entries
[i
].smio_low
=
522 le32_to_cpu(voltage_object
->asGpioVoltageObj
.asVolGpioLut
[i
].ulVoltageId
);
525 voltage_table
->mask_low
=
526 le32_to_cpu(voltage_object
->asGpioVoltageObj
.ulGpioMaskVal
);
527 voltage_table
->count
=
528 voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
;
529 voltage_table
->phase_delay
=
530 voltage_object
->asGpioVoltageObj
.ucPhaseDelay
;
535 static bool atomctrl_lookup_gpio_pin(
536 ATOM_GPIO_PIN_LUT
* gpio_lookup_table
,
537 const uint32_t pinId
,
538 pp_atomctrl_gpio_pin_assignment
*gpio_pin_assignment
)
540 unsigned int size
= le16_to_cpu(gpio_lookup_table
->sHeader
.usStructureSize
);
541 unsigned int offset
= offsetof(ATOM_GPIO_PIN_LUT
, asGPIO_Pin
[0]);
542 uint8_t *start
= (uint8_t *)gpio_lookup_table
;
544 while (offset
< size
) {
545 const ATOM_GPIO_PIN_ASSIGNMENT
*pin_assignment
=
546 (const ATOM_GPIO_PIN_ASSIGNMENT
*)(start
+ offset
);
548 if (pinId
== pin_assignment
->ucGPIO_ID
) {
549 gpio_pin_assignment
->uc_gpio_pin_bit_shift
=
550 pin_assignment
->ucGpioPinBitShift
;
551 gpio_pin_assignment
->us_gpio_pin_aindex
=
552 le16_to_cpu(pin_assignment
->usGpioPin_AIndex
);
556 offset
+= offsetof(ATOM_GPIO_PIN_ASSIGNMENT
, ucGPIO_ID
) + 1;
563 * Private Function to get the PowerPlay Table Address.
564 * WARNING: The tabled returned by this function is in
565 * dynamically allocated memory.
566 * The caller has to release if by calling kfree.
568 static ATOM_GPIO_PIN_LUT
*get_gpio_lookup_table(void *device
)
574 table_address
= (ATOM_GPIO_PIN_LUT
*)
575 cgs_atom_get_data_table(device
,
576 GetIndexIntoMasterTable(DATA
, GPIO_Pin_LUT
),
577 &size
, &frev
, &crev
);
579 PP_ASSERT_WITH_CODE((NULL
!= table_address
),
580 "Error retrieving BIOS Table Address!", return NULL
;);
582 return (ATOM_GPIO_PIN_LUT
*)table_address
;
586 * Returns 1 if the given pin id find in lookup table.
588 bool atomctrl_get_pp_assign_pin(
589 struct pp_hwmgr
*hwmgr
,
590 const uint32_t pinId
,
591 pp_atomctrl_gpio_pin_assignment
*gpio_pin_assignment
)
594 ATOM_GPIO_PIN_LUT
*gpio_lookup_table
=
595 get_gpio_lookup_table(hwmgr
->device
);
597 PP_ASSERT_WITH_CODE((NULL
!= gpio_lookup_table
),
598 "Could not find GPIO lookup Table in BIOS.", return false);
600 bRet
= atomctrl_lookup_gpio_pin(gpio_lookup_table
, pinId
,
601 gpio_pin_assignment
);
606 int atomctrl_calculate_voltage_evv_on_sclk(
607 struct pp_hwmgr
*hwmgr
,
608 uint8_t voltage_type
,
610 uint16_t virtual_voltage_Id
,
615 ATOM_ASIC_PROFILING_INFO_V3_4
*getASICProfilingInfo
;
617 EFUSE_LINEAR_FUNC_PARAM sRO_fuse
;
618 EFUSE_LINEAR_FUNC_PARAM sCACm_fuse
;
619 EFUSE_LINEAR_FUNC_PARAM sCACb_fuse
;
620 EFUSE_LOGISTIC_FUNC_PARAM sKt_Beta_fuse
;
621 EFUSE_LOGISTIC_FUNC_PARAM sKv_m_fuse
;
622 EFUSE_LOGISTIC_FUNC_PARAM sKv_b_fuse
;
623 EFUSE_INPUT_PARAMETER sInput_FuseValues
;
624 READ_EFUSE_VALUE_PARAMETER sOutput_FuseValues
;
626 uint32_t ul_RO_fused
, ul_CACb_fused
, ul_CACm_fused
, ul_Kt_Beta_fused
, ul_Kv_m_fused
, ul_Kv_b_fused
;
627 fInt fSM_A0
, fSM_A1
, fSM_A2
, fSM_A3
, fSM_A4
, fSM_A5
, fSM_A6
, fSM_A7
;
628 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
;
629 fInt fLkg_FT
, repeat
;
630 fInt fMicro_FMAX
, fMicro_CR
, fSigma_FMAX
, fSigma_CR
, fSigma_DC
, fDC_SCLK
, fSquared_Sigma_DC
, fSquared_Sigma_CR
, fSquared_Sigma_FMAX
;
631 fInt fRLL_LoadLine
, fPowerDPMx
, fDerateTDP
, fVDDC_base
, fA_Term
, fC_Term
, fB_Term
, fRO_DC_margin
;
632 fInt fRO_fused
, fCACm_fused
, fCACb_fused
, fKv_m_fused
, fKv_b_fused
, fKt_Beta_fused
, fFT_Lkg_V0NORM
;
633 fInt fSclk_margin
, fSclk
, fEVV_V
;
634 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
;
635 uint32_t ul_FT_Lkg_V0NORM
;
636 fInt fLn_MaxDivMin
, fMin
, fAverage
, fRange
;
638 fInt fStepSize
= GetScaledFraction(625, 100000);
642 getASICProfilingInfo
= (ATOM_ASIC_PROFILING_INFO_V3_4
*)
643 cgs_atom_get_data_table(hwmgr
->device
,
644 GetIndexIntoMasterTable(DATA
, ASIC_ProfilingInfo
),
647 if (!getASICProfilingInfo
)
650 if (getASICProfilingInfo
->asHeader
.ucTableFormatRevision
< 3 ||
651 (getASICProfilingInfo
->asHeader
.ucTableFormatRevision
== 3 &&
652 getASICProfilingInfo
->asHeader
.ucTableContentRevision
< 4))
655 /*-----------------------------------------------------------
656 *GETTING MULTI-STEP PARAMETERS RELATED TO CURRENT DPM LEVEL
657 *-----------------------------------------------------------
659 fRLL_LoadLine
= Divide(getASICProfilingInfo
->ulLoadLineSlop
, 1000);
663 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm1
));
664 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM1
), 1000);
667 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm2
));
668 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM2
), 1000);
671 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm3
));
672 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM3
), 1000);
675 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm4
));
676 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM4
), 1000);
679 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm5
));
680 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM5
), 1000);
683 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm6
));
684 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM6
), 1000);
687 fPowerDPMx
= Convert_ULONG_ToFraction(le16_to_cpu(getASICProfilingInfo
->usPowerDpm7
));
688 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM7
), 1000);
691 printk(KERN_ERR
"DPM Level not supported\n");
692 fPowerDPMx
= Convert_ULONG_ToFraction(1);
693 fDerateTDP
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulTdpDerateDPM0
), 1000);
696 /*-------------------------
697 * DECODING FUSE VALUES
698 * ------------------------
701 sRO_fuse
= getASICProfilingInfo
->sRoFuse
;
703 sInput_FuseValues
.usEfuseIndex
= sRO_fuse
.usEfuseIndex
;
704 sInput_FuseValues
.ucBitShift
= sRO_fuse
.ucEfuseBitLSB
;
705 sInput_FuseValues
.ucBitLength
= sRO_fuse
.ucEfuseLength
;
707 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
709 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
710 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
711 &sOutput_FuseValues
);
716 /* Finally, the actual fuse value */
717 ul_RO_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
718 fMin
= GetScaledFraction(le32_to_cpu(sRO_fuse
.ulEfuseMin
), 1);
719 fRange
= GetScaledFraction(le32_to_cpu(sRO_fuse
.ulEfuseEncodeRange
), 1);
720 fRO_fused
= fDecodeLinearFuse(ul_RO_fused
, fMin
, fRange
, sRO_fuse
.ucEfuseLength
);
722 sCACm_fuse
= getASICProfilingInfo
->sCACm
;
724 sInput_FuseValues
.usEfuseIndex
= sCACm_fuse
.usEfuseIndex
;
725 sInput_FuseValues
.ucBitShift
= sCACm_fuse
.ucEfuseBitLSB
;
726 sInput_FuseValues
.ucBitLength
= sCACm_fuse
.ucEfuseLength
;
728 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
730 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
731 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
732 &sOutput_FuseValues
);
737 ul_CACm_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
738 fMin
= GetScaledFraction(le32_to_cpu(sCACm_fuse
.ulEfuseMin
), 1000);
739 fRange
= GetScaledFraction(le32_to_cpu(sCACm_fuse
.ulEfuseEncodeRange
), 1000);
741 fCACm_fused
= fDecodeLinearFuse(ul_CACm_fused
, fMin
, fRange
, sCACm_fuse
.ucEfuseLength
);
743 sCACb_fuse
= getASICProfilingInfo
->sCACb
;
745 sInput_FuseValues
.usEfuseIndex
= sCACb_fuse
.usEfuseIndex
;
746 sInput_FuseValues
.ucBitShift
= sCACb_fuse
.ucEfuseBitLSB
;
747 sInput_FuseValues
.ucBitLength
= sCACb_fuse
.ucEfuseLength
;
748 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
750 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
751 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
752 &sOutput_FuseValues
);
757 ul_CACb_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
758 fMin
= GetScaledFraction(le32_to_cpu(sCACb_fuse
.ulEfuseMin
), 1000);
759 fRange
= GetScaledFraction(le32_to_cpu(sCACb_fuse
.ulEfuseEncodeRange
), 1000);
761 fCACb_fused
= fDecodeLinearFuse(ul_CACb_fused
, fMin
, fRange
, sCACb_fuse
.ucEfuseLength
);
763 sKt_Beta_fuse
= getASICProfilingInfo
->sKt_b
;
765 sInput_FuseValues
.usEfuseIndex
= sKt_Beta_fuse
.usEfuseIndex
;
766 sInput_FuseValues
.ucBitShift
= sKt_Beta_fuse
.ucEfuseBitLSB
;
767 sInput_FuseValues
.ucBitLength
= sKt_Beta_fuse
.ucEfuseLength
;
769 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
771 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
772 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
773 &sOutput_FuseValues
);
778 ul_Kt_Beta_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
779 fAverage
= GetScaledFraction(le32_to_cpu(sKt_Beta_fuse
.ulEfuseEncodeAverage
), 1000);
780 fRange
= GetScaledFraction(le32_to_cpu(sKt_Beta_fuse
.ulEfuseEncodeRange
), 1000);
782 fKt_Beta_fused
= fDecodeLogisticFuse(ul_Kt_Beta_fused
,
783 fAverage
, fRange
, sKt_Beta_fuse
.ucEfuseLength
);
785 sKv_m_fuse
= getASICProfilingInfo
->sKv_m
;
787 sInput_FuseValues
.usEfuseIndex
= sKv_m_fuse
.usEfuseIndex
;
788 sInput_FuseValues
.ucBitShift
= sKv_m_fuse
.ucEfuseBitLSB
;
789 sInput_FuseValues
.ucBitLength
= sKv_m_fuse
.ucEfuseLength
;
791 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
793 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
794 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
795 &sOutput_FuseValues
);
799 ul_Kv_m_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
800 fAverage
= GetScaledFraction(le32_to_cpu(sKv_m_fuse
.ulEfuseEncodeAverage
), 1000);
801 fRange
= GetScaledFraction((le32_to_cpu(sKv_m_fuse
.ulEfuseEncodeRange
) & 0x7fffffff), 1000);
802 fRange
= fMultiply(fRange
, ConvertToFraction(-1));
804 fKv_m_fused
= fDecodeLogisticFuse(ul_Kv_m_fused
,
805 fAverage
, fRange
, sKv_m_fuse
.ucEfuseLength
);
807 sKv_b_fuse
= getASICProfilingInfo
->sKv_b
;
809 sInput_FuseValues
.usEfuseIndex
= sKv_b_fuse
.usEfuseIndex
;
810 sInput_FuseValues
.ucBitShift
= sKv_b_fuse
.ucEfuseBitLSB
;
811 sInput_FuseValues
.ucBitLength
= sKv_b_fuse
.ucEfuseLength
;
812 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
814 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
815 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
816 &sOutput_FuseValues
);
821 ul_Kv_b_fused
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
822 fAverage
= GetScaledFraction(le32_to_cpu(sKv_b_fuse
.ulEfuseEncodeAverage
), 1000);
823 fRange
= GetScaledFraction(le32_to_cpu(sKv_b_fuse
.ulEfuseEncodeRange
), 1000);
825 fKv_b_fused
= fDecodeLogisticFuse(ul_Kv_b_fused
,
826 fAverage
, fRange
, sKv_b_fuse
.ucEfuseLength
);
828 /* Decoding the Leakage - No special struct container */
832 * ucLkgEfuseLength=10
833 * ulLkgEncodeLn_MaxDivMin=69077
834 * ulLkgEncodeMax=1000000
835 * ulLkgEncodeMin=1000
836 * ulEfuseLogisticAlpha=13
839 sInput_FuseValues
.usEfuseIndex
= getASICProfilingInfo
->usLkgEuseIndex
;
840 sInput_FuseValues
.ucBitShift
= getASICProfilingInfo
->ucLkgEfuseBitLSB
;
841 sInput_FuseValues
.ucBitLength
= getASICProfilingInfo
->ucLkgEfuseLength
;
843 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
845 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
846 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
847 &sOutput_FuseValues
);
852 ul_FT_Lkg_V0NORM
= le32_to_cpu(sOutput_FuseValues
.ulEfuseValue
);
853 fLn_MaxDivMin
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulLkgEncodeLn_MaxDivMin
), 10000);
854 fMin
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulLkgEncodeMin
), 10000);
856 fFT_Lkg_V0NORM
= fDecodeLeakageID(ul_FT_Lkg_V0NORM
,
857 fLn_MaxDivMin
, fMin
, getASICProfilingInfo
->ucLkgEfuseLength
);
858 fLkg_FT
= fFT_Lkg_V0NORM
;
860 /*-------------------------------------------
861 * PART 2 - Grabbing all required values
862 *-------------------------------------------
864 fSM_A0
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A0
), 1000000),
865 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A0_sign
)));
866 fSM_A1
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A1
), 1000000),
867 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A1_sign
)));
868 fSM_A2
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A2
), 100000),
869 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A2_sign
)));
870 fSM_A3
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A3
), 1000000),
871 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A3_sign
)));
872 fSM_A4
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A4
), 1000000),
873 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A4_sign
)));
874 fSM_A5
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A5
), 1000),
875 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A5_sign
)));
876 fSM_A6
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A6
), 1000),
877 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A6_sign
)));
878 fSM_A7
= fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulSM_A7
), 1000),
879 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A7_sign
)));
881 fMargin_RO_a
= ConvertToFraction(le32_to_cpu(getASICProfilingInfo
->ulMargin_RO_a
));
882 fMargin_RO_b
= ConvertToFraction(le32_to_cpu(getASICProfilingInfo
->ulMargin_RO_b
));
883 fMargin_RO_c
= ConvertToFraction(le32_to_cpu(getASICProfilingInfo
->ulMargin_RO_c
));
885 fMargin_fixed
= ConvertToFraction(le32_to_cpu(getASICProfilingInfo
->ulMargin_fixed
));
887 fMargin_FMAX_mean
= GetScaledFraction(
888 le32_to_cpu(getASICProfilingInfo
->ulMargin_Fmax_mean
), 10000);
889 fMargin_Plat_mean
= GetScaledFraction(
890 le32_to_cpu(getASICProfilingInfo
->ulMargin_plat_mean
), 10000);
891 fMargin_FMAX_sigma
= GetScaledFraction(
892 le32_to_cpu(getASICProfilingInfo
->ulMargin_Fmax_sigma
), 10000);
893 fMargin_Plat_sigma
= GetScaledFraction(
894 le32_to_cpu(getASICProfilingInfo
->ulMargin_plat_sigma
), 10000);
896 fMargin_DC_sigma
= GetScaledFraction(
897 le32_to_cpu(getASICProfilingInfo
->ulMargin_DC_sigma
), 100);
898 fMargin_DC_sigma
= fDivide(fMargin_DC_sigma
, ConvertToFraction(1000));
900 fCACm_fused
= fDivide(fCACm_fused
, ConvertToFraction(100));
901 fCACb_fused
= fDivide(fCACb_fused
, ConvertToFraction(100));
902 fKt_Beta_fused
= fDivide(fKt_Beta_fused
, ConvertToFraction(100));
903 fKv_m_fused
= fNegate(fDivide(fKv_m_fused
, ConvertToFraction(100)));
904 fKv_b_fused
= fDivide(fKv_b_fused
, ConvertToFraction(10));
906 fSclk
= GetScaledFraction(sclk
, 100);
908 fV_max
= fDivide(GetScaledFraction(
909 le32_to_cpu(getASICProfilingInfo
->ulMaxVddc
), 1000), ConvertToFraction(4));
910 fT_prod
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulBoardCoreTemp
), 10);
911 fLKG_Factor
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulEvvLkgFactor
), 100);
912 fT_FT
= GetScaledFraction(le32_to_cpu(getASICProfilingInfo
->ulLeakageTemp
), 10);
913 fV_FT
= fDivide(GetScaledFraction(
914 le32_to_cpu(getASICProfilingInfo
->ulLeakageVoltage
), 1000), ConvertToFraction(4));
915 fV_min
= fDivide(GetScaledFraction(
916 le32_to_cpu(getASICProfilingInfo
->ulMinVddc
), 1000), ConvertToFraction(4));
918 /*-----------------------
920 *-----------------------
923 fA_Term
= fAdd(fMargin_RO_a
, fAdd(fMultiply(fSM_A4
, fSclk
), fSM_A5
));
924 fB_Term
= fAdd(fAdd(fMultiply(fSM_A2
, fSclk
), fSM_A6
), fMargin_RO_b
);
925 fC_Term
= fAdd(fMargin_RO_c
,
926 fAdd(fMultiply(fSM_A0
, fLkg_FT
),
927 fAdd(fMultiply(fSM_A1
, fMultiply(fLkg_FT
, fSclk
)),
928 fAdd(fMultiply(fSM_A3
, fSclk
),
929 fSubtract(fSM_A7
, fRO_fused
)))));
931 fVDDC_base
= fSubtract(fRO_fused
,
932 fSubtract(fMargin_RO_c
,
933 fSubtract(fSM_A3
, fMultiply(fSM_A1
, fSclk
))));
934 fVDDC_base
= fDivide(fVDDC_base
, fAdd(fMultiply(fSM_A0
, fSclk
), fSM_A2
));
936 repeat
= fSubtract(fVDDC_base
,
937 fDivide(fMargin_DC_sigma
, ConvertToFraction(1000)));
939 fRO_DC_margin
= fAdd(fMultiply(fMargin_RO_a
,
941 fAdd(fMultiply(fMargin_RO_b
, repeat
),
944 fDC_SCLK
= fSubtract(fRO_fused
,
945 fSubtract(fRO_DC_margin
,
947 fMultiply(fSM_A2
, repeat
))));
948 fDC_SCLK
= fDivide(fDC_SCLK
, fAdd(fMultiply(fSM_A0
, repeat
), fSM_A1
));
950 fSigma_DC
= fSubtract(fSclk
, fDC_SCLK
);
952 fMicro_FMAX
= fMultiply(fSclk
, fMargin_FMAX_mean
);
953 fMicro_CR
= fMultiply(fSclk
, fMargin_Plat_mean
);
954 fSigma_FMAX
= fMultiply(fSclk
, fMargin_FMAX_sigma
);
955 fSigma_CR
= fMultiply(fSclk
, fMargin_Plat_sigma
);
957 fSquared_Sigma_DC
= fGetSquare(fSigma_DC
);
958 fSquared_Sigma_CR
= fGetSquare(fSigma_CR
);
959 fSquared_Sigma_FMAX
= fGetSquare(fSigma_FMAX
);
961 fSclk_margin
= fAdd(fMicro_FMAX
,
964 fSqrt(fAdd(fSquared_Sigma_FMAX
,
965 fAdd(fSquared_Sigma_DC
, fSquared_Sigma_CR
))))));
967 fA_Term = fSM_A4 * (fSclk + fSclk_margin) + fSM_A5;
968 fB_Term = fSM_A2 * (fSclk + fSclk_margin) + fSM_A6;
969 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;
972 fA_Term
= fAdd(fMultiply(fSM_A4
, fAdd(fSclk
, fSclk_margin
)), fSM_A5
);
973 fB_Term
= fAdd(fMultiply(fSM_A2
, fAdd(fSclk
, fSclk_margin
)), fSM_A6
);
974 fC_Term
= fAdd(fRO_DC_margin
,
975 fAdd(fMultiply(fSM_A0
, fLkg_FT
),
976 fAdd(fMultiply(fMultiply(fSM_A1
, fLkg_FT
),
977 fAdd(fSclk
, fSclk_margin
)),
978 fAdd(fMultiply(fSM_A3
,
979 fAdd(fSclk
, fSclk_margin
)),
980 fSubtract(fSM_A7
, fRO_fused
)))));
982 SolveQuadracticEqn(fA_Term
, fB_Term
, fC_Term
, fRoots
);
984 if (GreaterThan(fRoots
[0], fRoots
[1]))
989 if (GreaterThan(fV_min
, fEVV_V
))
991 else if (GreaterThan(fEVV_V
, fV_max
))
992 fEVV_V
= fSubtract(fV_max
, fStepSize
);
994 fEVV_V
= fRoundUpByStepSize(fEVV_V
, fStepSize
, 0);
1003 while (GreaterThan(fAdd(fV_max
, fStepSize
), fV_x
)) {
1004 fTDP_Power_left
= fMultiply(fMultiply(fMultiply(fAdd(
1005 fMultiply(fCACm_fused
, fV_x
), fCACb_fused
), fSclk
),
1006 fGetSquare(fV_x
)), fDerateTDP
);
1008 fTDP_Power_right
= fMultiply(fFT_Lkg_V0NORM
, fMultiply(fLKG_Factor
,
1009 fMultiply(fExponential(fMultiply(fAdd(fMultiply(fKv_m_fused
,
1010 fT_prod
), fKv_b_fused
), fV_x
)), fV_x
)));
1011 fTDP_Power_right
= fMultiply(fTDP_Power_right
, fExponential(fMultiply(
1012 fKt_Beta_fused
, fT_prod
)));
1013 fTDP_Power_right
= fDivide(fTDP_Power_right
, fExponential(fMultiply(
1014 fAdd(fMultiply(fKv_m_fused
, fT_prod
), fKv_b_fused
), fV_FT
)));
1015 fTDP_Power_right
= fDivide(fTDP_Power_right
, fExponential(fMultiply(
1016 fKt_Beta_fused
, fT_FT
)));
1018 fTDP_Power
= fAdd(fTDP_Power_left
, fTDP_Power_right
);
1020 fTDP_Current
= fDivide(fTDP_Power
, fV_x
);
1022 fV_NL
= fAdd(fV_x
, fDivide(fMultiply(fTDP_Current
, fRLL_LoadLine
),
1023 ConvertToFraction(10)));
1025 fV_NL
= fRoundUpByStepSize(fV_NL
, fStepSize
, 0);
1027 if (GreaterThan(fV_max
, fV_NL
) &&
1028 (GreaterThan(fV_NL
, fEVV_V
) ||
1029 Equal(fV_NL
, fEVV_V
))) {
1030 fV_NL
= fMultiply(fV_NL
, ConvertToFraction(1000));
1032 *voltage
= (uint16_t)fV_NL
.partial
.real
;
1035 fV_x
= fAdd(fV_x
, fStepSize
);
1041 /** atomctrl_get_voltage_evv_on_sclk gets voltage via call to ATOM COMMAND table.
1042 * @param hwmgr input: pointer to hwManager
1043 * @param voltage_type input: type of EVV voltage VDDC or VDDGFX
1044 * @param sclk input: in 10Khz unit. DPM state SCLK frequency
1045 * which is define in PPTable SCLK/VDDC dependence
1046 * table associated with this virtual_voltage_Id
1047 * @param virtual_voltage_Id input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
1048 * @param voltage output: real voltage level in unit of mv
1050 int atomctrl_get_voltage_evv_on_sclk(
1051 struct pp_hwmgr
*hwmgr
,
1052 uint8_t voltage_type
,
1053 uint32_t sclk
, uint16_t virtual_voltage_Id
,
1057 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space
;
1059 get_voltage_info_param_space
.ucVoltageType
=
1061 get_voltage_info_param_space
.ucVoltageMode
=
1062 ATOM_GET_VOLTAGE_EVV_VOLTAGE
;
1063 get_voltage_info_param_space
.usVoltageLevel
=
1064 cpu_to_le16(virtual_voltage_Id
);
1065 get_voltage_info_param_space
.ulSCLKFreq
=
1068 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
1069 GetIndexIntoMasterTable(COMMAND
, GetVoltageInfo
),
1070 &get_voltage_info_param_space
);
1075 *voltage
= le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2
*)
1076 (&get_voltage_info_param_space
))->usVoltageLevel
);
1082 * atomctrl_get_voltage_evv gets voltage via call to ATOM COMMAND table.
1083 * @param hwmgr input: pointer to hwManager
1084 * @param virtual_voltage_id input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
1085 * @param voltage output: real voltage level in unit of mv
1087 int atomctrl_get_voltage_evv(struct pp_hwmgr
*hwmgr
,
1088 uint16_t virtual_voltage_id
,
1093 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space
;
1095 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
1096 for (entry_id
= 0; entry_id
< hwmgr
->dyn_state
.vddc_dependency_on_sclk
->count
; entry_id
++) {
1097 if (hwmgr
->dyn_state
.vddc_dependency_on_sclk
->entries
[entry_id
].v
== virtual_voltage_id
) {
1103 PP_ASSERT_WITH_CODE(entry_id
< hwmgr
->dyn_state
.vddc_dependency_on_sclk
->count
,
1104 "Can't find requested voltage id in vddc_dependency_on_sclk table!",
1108 get_voltage_info_param_space
.ucVoltageType
= VOLTAGE_TYPE_VDDC
;
1109 get_voltage_info_param_space
.ucVoltageMode
= ATOM_GET_VOLTAGE_EVV_VOLTAGE
;
1110 get_voltage_info_param_space
.usVoltageLevel
= virtual_voltage_id
;
1111 get_voltage_info_param_space
.ulSCLKFreq
=
1112 cpu_to_le32(hwmgr
->dyn_state
.vddc_dependency_on_sclk
->entries
[entry_id
].clk
);
1114 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
1115 GetIndexIntoMasterTable(COMMAND
, GetVoltageInfo
),
1116 &get_voltage_info_param_space
);
1121 *voltage
= le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2
*)
1122 (&get_voltage_info_param_space
))->usVoltageLevel
);
1128 * Get the mpll reference clock in 10KHz
1130 uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr
*hwmgr
)
1132 ATOM_COMMON_TABLE_HEADER
*fw_info
;
1137 fw_info
= (ATOM_COMMON_TABLE_HEADER
*)
1138 cgs_atom_get_data_table(hwmgr
->device
,
1139 GetIndexIntoMasterTable(DATA
, FirmwareInfo
),
1140 &size
, &frev
, &crev
);
1142 if (fw_info
== NULL
)
1145 if ((fw_info
->ucTableFormatRevision
== 2) &&
1146 (le16_to_cpu(fw_info
->usStructureSize
) >= sizeof(ATOM_FIRMWARE_INFO_V2_1
))) {
1147 ATOM_FIRMWARE_INFO_V2_1
*fwInfo_2_1
=
1148 (ATOM_FIRMWARE_INFO_V2_1
*)fw_info
;
1149 clock
= (uint32_t)(le16_to_cpu(fwInfo_2_1
->usMemoryReferenceClock
));
1151 ATOM_FIRMWARE_INFO
*fwInfo_0_0
=
1152 (ATOM_FIRMWARE_INFO
*)fw_info
;
1153 clock
= (uint32_t)(le16_to_cpu(fwInfo_0_0
->usReferenceClock
));
1161 * Get the asic internal spread spectrum table
1163 static ATOM_ASIC_INTERNAL_SS_INFO
*asic_internal_ss_get_ss_table(void *device
)
1165 ATOM_ASIC_INTERNAL_SS_INFO
*table
= NULL
;
1169 table
= (ATOM_ASIC_INTERNAL_SS_INFO
*)
1170 cgs_atom_get_data_table(device
,
1171 GetIndexIntoMasterTable(DATA
, ASIC_InternalSS_Info
),
1172 &size
, &frev
, &crev
);
1178 * Get the asic internal spread spectrum assignment
1180 static int asic_internal_ss_get_ss_asignment(struct pp_hwmgr
*hwmgr
,
1181 const uint8_t clockSource
,
1182 const uint32_t clockSpeed
,
1183 pp_atomctrl_internal_ss_info
*ssEntry
)
1185 ATOM_ASIC_INTERNAL_SS_INFO
*table
;
1186 ATOM_ASIC_SS_ASSIGNMENT
*ssInfo
;
1187 int entry_found
= 0;
1189 memset(ssEntry
, 0x00, sizeof(pp_atomctrl_internal_ss_info
));
1191 table
= asic_internal_ss_get_ss_table(hwmgr
->device
);
1196 ssInfo
= &table
->asSpreadSpectrum
[0];
1198 while (((uint8_t *)ssInfo
- (uint8_t *)table
) <
1199 le16_to_cpu(table
->sHeader
.usStructureSize
)) {
1200 if ((clockSource
== ssInfo
->ucClockIndication
) &&
1201 ((uint32_t)clockSpeed
<= le32_to_cpu(ssInfo
->ulTargetClockRange
))) {
1206 ssInfo
= (ATOM_ASIC_SS_ASSIGNMENT
*)((uint8_t *)ssInfo
+
1207 sizeof(ATOM_ASIC_SS_ASSIGNMENT
));
1211 ssEntry
->speed_spectrum_percentage
=
1212 le16_to_cpu(ssInfo
->usSpreadSpectrumPercentage
);
1213 ssEntry
->speed_spectrum_rate
= le16_to_cpu(ssInfo
->usSpreadRateInKhz
);
1215 if (((GET_DATA_TABLE_MAJOR_REVISION(table
) == 2) &&
1216 (GET_DATA_TABLE_MINOR_REVISION(table
) >= 2)) ||
1217 (GET_DATA_TABLE_MAJOR_REVISION(table
) == 3)) {
1218 ssEntry
->speed_spectrum_rate
/= 100;
1221 switch (ssInfo
->ucSpreadSpectrumMode
) {
1223 ssEntry
->speed_spectrum_mode
=
1224 pp_atomctrl_spread_spectrum_mode_down
;
1227 ssEntry
->speed_spectrum_mode
=
1228 pp_atomctrl_spread_spectrum_mode_center
;
1231 ssEntry
->speed_spectrum_mode
=
1232 pp_atomctrl_spread_spectrum_mode_down
;
1237 return entry_found
? 0 : 1;
1241 * Get the memory clock spread spectrum info
1243 int atomctrl_get_memory_clock_spread_spectrum(
1244 struct pp_hwmgr
*hwmgr
,
1245 const uint32_t memory_clock
,
1246 pp_atomctrl_internal_ss_info
*ssInfo
)
1248 return asic_internal_ss_get_ss_asignment(hwmgr
,
1249 ASIC_INTERNAL_MEMORY_SS
, memory_clock
, ssInfo
);
1252 * Get the engine clock spread spectrum info
1254 int atomctrl_get_engine_clock_spread_spectrum(
1255 struct pp_hwmgr
*hwmgr
,
1256 const uint32_t engine_clock
,
1257 pp_atomctrl_internal_ss_info
*ssInfo
)
1259 return asic_internal_ss_get_ss_asignment(hwmgr
,
1260 ASIC_INTERNAL_ENGINE_SS
, engine_clock
, ssInfo
);
1263 int atomctrl_read_efuse(void *device
, uint16_t start_index
,
1264 uint16_t end_index
, uint32_t mask
, uint32_t *efuse
)
1267 READ_EFUSE_VALUE_PARAMETER efuse_param
;
1269 efuse_param
.sEfuse
.usEfuseIndex
= cpu_to_le16((start_index
/ 32) * 4);
1270 efuse_param
.sEfuse
.ucBitShift
= (uint8_t)
1271 (start_index
- ((start_index
/ 32) * 32));
1272 efuse_param
.sEfuse
.ucBitLength
= (uint8_t)
1273 ((end_index
- start_index
) + 1);
1275 result
= cgs_atom_exec_cmd_table(device
,
1276 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
1279 *efuse
= le32_to_cpu(efuse_param
.ulEfuseValue
) & mask
;
1284 int atomctrl_set_ac_timing_ai(struct pp_hwmgr
*hwmgr
, uint32_t memory_clock
,
1287 DYNAMICE_MEMORY_SETTINGS_PARAMETER_V2_1 memory_clock_parameters
;
1290 memory_clock_parameters
.asDPMMCReg
.ulClock
.ulClockFreq
=
1291 memory_clock
& SET_CLOCK_FREQ_MASK
;
1292 memory_clock_parameters
.asDPMMCReg
.ulClock
.ulComputeClockFlag
=
1293 ADJUST_MC_SETTING_PARAM
;
1294 memory_clock_parameters
.asDPMMCReg
.ucMclkDPMState
= level
;
1296 result
= cgs_atom_exec_cmd_table
1298 GetIndexIntoMasterTable(COMMAND
, DynamicMemorySettings
),
1299 &memory_clock_parameters
);
1304 int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr
*hwmgr
, uint8_t voltage_type
,
1305 uint32_t sclk
, uint16_t virtual_voltage_Id
, uint32_t *voltage
)
1309 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_3 get_voltage_info_param_space
;
1311 get_voltage_info_param_space
.ucVoltageType
= voltage_type
;
1312 get_voltage_info_param_space
.ucVoltageMode
= ATOM_GET_VOLTAGE_EVV_VOLTAGE
;
1313 get_voltage_info_param_space
.usVoltageLevel
= cpu_to_le16(virtual_voltage_Id
);
1314 get_voltage_info_param_space
.ulSCLKFreq
= cpu_to_le32(sclk
);
1316 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
1317 GetIndexIntoMasterTable(COMMAND
, GetVoltageInfo
),
1318 &get_voltage_info_param_space
);
1323 *voltage
= le32_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_3
*)
1324 (&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
;