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 (uint32_t) engine_clock
& SET_CLOCK_FREQ_MASK
;
183 engine_clock_parameters
.ulTargetEngineClock
|=
184 (COMPUTE_ENGINE_PLL_PARAM
<< 24);
186 /* in 10 khz units.*/
187 engine_clock_parameters
.sReserved
.ulClock
=
188 (uint32_t) memory_clock
& SET_CLOCK_FREQ_MASK
;
189 return cgs_atom_exec_cmd_table(hwmgr
->device
,
190 GetIndexIntoMasterTable(COMMAND
, DynamicMemorySettings
),
191 &engine_clock_parameters
);
195 * Private Function to get the PowerPlay Table Address.
196 * WARNING: The tabled returned by this function is in
197 * dynamically allocated memory.
198 * The caller has to release if by calling kfree.
200 static ATOM_VOLTAGE_OBJECT_INFO
*get_voltage_info_table(void *device
)
202 int index
= GetIndexIntoMasterTable(DATA
, VoltageObjectInfo
);
205 union voltage_object_info
*voltage_info
;
207 voltage_info
= (union voltage_object_info
*)
208 cgs_atom_get_data_table(device
, index
,
209 &size
, &frev
, &crev
);
211 if (voltage_info
!= NULL
)
212 return (ATOM_VOLTAGE_OBJECT_INFO
*) &(voltage_info
->v3
);
217 static const ATOM_VOLTAGE_OBJECT_V3
*atomctrl_lookup_voltage_type_v3(
218 const ATOM_VOLTAGE_OBJECT_INFO_V3_1
* voltage_object_info_table
,
219 uint8_t voltage_type
, uint8_t voltage_mode
)
221 unsigned int size
= le16_to_cpu(voltage_object_info_table
->sHeader
.usStructureSize
);
222 unsigned int offset
= offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1
, asVoltageObj
[0]);
223 uint8_t *start
= (uint8_t *)voltage_object_info_table
;
225 while (offset
< size
) {
226 const ATOM_VOLTAGE_OBJECT_V3
*voltage_object
=
227 (const ATOM_VOLTAGE_OBJECT_V3
*)(start
+ offset
);
229 if (voltage_type
== voltage_object
->asGpioVoltageObj
.sHeader
.ucVoltageType
&&
230 voltage_mode
== voltage_object
->asGpioVoltageObj
.sHeader
.ucVoltageMode
)
231 return voltage_object
;
233 offset
+= le16_to_cpu(voltage_object
->asGpioVoltageObj
.sHeader
.usSize
);
239 /** atomctrl_get_memory_pll_dividers_si().
241 * @param hwmgr input parameter: pointer to HwMgr
242 * @param clock_value input parameter: memory clock
243 * @param dividers output parameter: memory PLL dividers
244 * @param strobe_mode input parameter: 1 for strobe mode, 0 for performance mode
246 int atomctrl_get_memory_pll_dividers_si(
247 struct pp_hwmgr
*hwmgr
,
248 uint32_t clock_value
,
249 pp_atomctrl_memory_clock_param
*mpll_param
,
252 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 mpll_parameters
;
255 mpll_parameters
.ulClock
= (uint32_t) clock_value
;
256 mpll_parameters
.ucInputFlag
= (uint8_t)((strobe_mode
) ? 1 : 0);
258 result
= cgs_atom_exec_cmd_table
260 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryClockParam
),
264 mpll_param
->mpll_fb_divider
.clk_frac
=
265 mpll_parameters
.ulFbDiv
.usFbDivFrac
;
266 mpll_param
->mpll_fb_divider
.cl_kf
=
267 mpll_parameters
.ulFbDiv
.usFbDiv
;
268 mpll_param
->mpll_post_divider
=
269 (uint32_t)mpll_parameters
.ucPostDiv
;
270 mpll_param
->vco_mode
=
271 (uint32_t)(mpll_parameters
.ucPllCntlFlag
&
272 MPLL_CNTL_FLAG_VCO_MODE_MASK
);
273 mpll_param
->yclk_sel
=
274 (uint32_t)((mpll_parameters
.ucPllCntlFlag
&
275 MPLL_CNTL_FLAG_BYPASS_DQ_PLL
) ? 1 : 0);
277 (uint32_t)((mpll_parameters
.ucPllCntlFlag
&
278 MPLL_CNTL_FLAG_QDR_ENABLE
) ? 1 : 0);
279 mpll_param
->half_rate
=
280 (uint32_t)((mpll_parameters
.ucPllCntlFlag
&
281 MPLL_CNTL_FLAG_AD_HALF_RATE
) ? 1 : 0);
282 mpll_param
->dll_speed
=
283 (uint32_t)(mpll_parameters
.ucDllSpeed
);
284 mpll_param
->bw_ctrl
=
285 (uint32_t)(mpll_parameters
.ucBWCntl
);
291 /** atomctrl_get_memory_pll_dividers_vi().
293 * @param hwmgr input parameter: pointer to HwMgr
294 * @param clock_value input parameter: memory clock
295 * @param dividers output parameter: memory PLL dividers
297 int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr
*hwmgr
,
298 uint32_t clock_value
, pp_atomctrl_memory_clock_param
*mpll_param
)
300 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2 mpll_parameters
;
303 mpll_parameters
.ulClock
.ulClock
= (uint32_t)clock_value
;
305 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
306 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryClockParam
),
310 mpll_param
->mpll_post_divider
=
311 (uint32_t)mpll_parameters
.ulClock
.ucPostDiv
;
316 int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr
*hwmgr
,
317 uint32_t clock_value
,
318 pp_atomctrl_clock_dividers_kong
*dividers
)
320 COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 pll_parameters
;
323 pll_parameters
.ulClock
= clock_value
;
325 result
= cgs_atom_exec_cmd_table
327 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
331 dividers
->pll_post_divider
= pll_parameters
.ucPostDiv
;
332 dividers
->real_clock
= pll_parameters
.ulClock
;
338 int atomctrl_get_engine_pll_dividers_vi(
339 struct pp_hwmgr
*hwmgr
,
340 uint32_t clock_value
,
341 pp_atomctrl_clock_dividers_vi
*dividers
)
343 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters
;
346 pll_patameters
.ulClock
.ulClock
= clock_value
;
347 pll_patameters
.ulClock
.ucPostDiv
= COMPUTE_GPUCLK_INPUT_FLAG_SCLK
;
349 result
= cgs_atom_exec_cmd_table
351 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
355 dividers
->pll_post_divider
=
356 pll_patameters
.ulClock
.ucPostDiv
;
357 dividers
->real_clock
=
358 pll_patameters
.ulClock
.ulClock
;
360 dividers
->ul_fb_div
.ul_fb_div_frac
=
361 pll_patameters
.ulFbDiv
.usFbDivFrac
;
362 dividers
->ul_fb_div
.ul_fb_div
=
363 pll_patameters
.ulFbDiv
.usFbDiv
;
365 dividers
->uc_pll_ref_div
=
366 pll_patameters
.ucPllRefDiv
;
367 dividers
->uc_pll_post_div
=
368 pll_patameters
.ucPllPostDiv
;
369 dividers
->uc_pll_cntl_flag
=
370 pll_patameters
.ucPllCntlFlag
;
376 int atomctrl_get_engine_pll_dividers_ai(struct pp_hwmgr
*hwmgr
,
377 uint32_t clock_value
,
378 pp_atomctrl_clock_dividers_ai
*dividers
)
380 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_7 pll_patameters
;
383 pll_patameters
.ulClock
.ulClock
= clock_value
;
384 pll_patameters
.ulClock
.ucPostDiv
= COMPUTE_GPUCLK_INPUT_FLAG_SCLK
;
386 result
= cgs_atom_exec_cmd_table
388 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
392 dividers
->usSclk_fcw_frac
= le16_to_cpu(pll_patameters
.usSclk_fcw_frac
);
393 dividers
->usSclk_fcw_int
= le16_to_cpu(pll_patameters
.usSclk_fcw_int
);
394 dividers
->ucSclkPostDiv
= pll_patameters
.ucSclkPostDiv
;
395 dividers
->ucSclkVcoMode
= pll_patameters
.ucSclkVcoMode
;
396 dividers
->ucSclkPllRange
= pll_patameters
.ucSclkPllRange
;
397 dividers
->ucSscEnable
= pll_patameters
.ucSscEnable
;
398 dividers
->usSsc_fcw1_frac
= le16_to_cpu(pll_patameters
.usSsc_fcw1_frac
);
399 dividers
->usSsc_fcw1_int
= le16_to_cpu(pll_patameters
.usSsc_fcw1_int
);
400 dividers
->usPcc_fcw_int
= le16_to_cpu(pll_patameters
.usPcc_fcw_int
);
401 dividers
->usSsc_fcw_slew_frac
= le16_to_cpu(pll_patameters
.usSsc_fcw_slew_frac
);
402 dividers
->usPcc_fcw_slew_frac
= le16_to_cpu(pll_patameters
.usPcc_fcw_slew_frac
);
407 int atomctrl_get_dfs_pll_dividers_vi(
408 struct pp_hwmgr
*hwmgr
,
409 uint32_t clock_value
,
410 pp_atomctrl_clock_dividers_vi
*dividers
)
412 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters
;
415 pll_patameters
.ulClock
.ulClock
= clock_value
;
416 pll_patameters
.ulClock
.ucPostDiv
=
417 COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK
;
419 result
= cgs_atom_exec_cmd_table
421 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
425 dividers
->pll_post_divider
=
426 pll_patameters
.ulClock
.ucPostDiv
;
427 dividers
->real_clock
=
428 pll_patameters
.ulClock
.ulClock
;
430 dividers
->ul_fb_div
.ul_fb_div_frac
=
431 pll_patameters
.ulFbDiv
.usFbDivFrac
;
432 dividers
->ul_fb_div
.ul_fb_div
=
433 pll_patameters
.ulFbDiv
.usFbDiv
;
435 dividers
->uc_pll_ref_div
=
436 pll_patameters
.ucPllRefDiv
;
437 dividers
->uc_pll_post_div
=
438 pll_patameters
.ucPllPostDiv
;
439 dividers
->uc_pll_cntl_flag
=
440 pll_patameters
.ucPllCntlFlag
;
447 * Get the reference clock in 10KHz
449 uint32_t atomctrl_get_reference_clock(struct pp_hwmgr
*hwmgr
)
451 ATOM_FIRMWARE_INFO
*fw_info
;
456 fw_info
= (ATOM_FIRMWARE_INFO
*)
457 cgs_atom_get_data_table(hwmgr
->device
,
458 GetIndexIntoMasterTable(DATA
, FirmwareInfo
),
459 &size
, &frev
, &crev
);
464 clock
= (uint32_t)(le16_to_cpu(fw_info
->usReferenceClock
));
470 * Returns true if the given voltage type is controlled by GPIO pins.
471 * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC,
472 * SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ.
473 * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE
475 bool atomctrl_is_voltage_controled_by_gpio_v3(
476 struct pp_hwmgr
*hwmgr
,
477 uint8_t voltage_type
,
478 uint8_t voltage_mode
)
480 ATOM_VOLTAGE_OBJECT_INFO_V3_1
*voltage_info
=
481 (ATOM_VOLTAGE_OBJECT_INFO_V3_1
*)get_voltage_info_table(hwmgr
->device
);
484 PP_ASSERT_WITH_CODE((NULL
!= voltage_info
),
485 "Could not find Voltage Table in BIOS.", return false;);
487 ret
= (NULL
!= atomctrl_lookup_voltage_type_v3
488 (voltage_info
, voltage_type
, voltage_mode
)) ? true : false;
493 int atomctrl_get_voltage_table_v3(
494 struct pp_hwmgr
*hwmgr
,
495 uint8_t voltage_type
,
496 uint8_t voltage_mode
,
497 pp_atomctrl_voltage_table
*voltage_table
)
499 ATOM_VOLTAGE_OBJECT_INFO_V3_1
*voltage_info
=
500 (ATOM_VOLTAGE_OBJECT_INFO_V3_1
*)get_voltage_info_table(hwmgr
->device
);
501 const ATOM_VOLTAGE_OBJECT_V3
*voltage_object
;
504 PP_ASSERT_WITH_CODE((NULL
!= voltage_info
),
505 "Could not find Voltage Table in BIOS.", return -1;);
507 voltage_object
= atomctrl_lookup_voltage_type_v3
508 (voltage_info
, voltage_type
, voltage_mode
);
510 if (voltage_object
== NULL
)
514 (voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
<=
515 PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES
),
516 "Too many voltage entries!",
520 for (i
= 0; i
< voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
; i
++) {
521 voltage_table
->entries
[i
].value
=
522 voltage_object
->asGpioVoltageObj
.asVolGpioLut
[i
].usVoltageValue
;
523 voltage_table
->entries
[i
].smio_low
=
524 voltage_object
->asGpioVoltageObj
.asVolGpioLut
[i
].ulVoltageId
;
527 voltage_table
->mask_low
=
528 voltage_object
->asGpioVoltageObj
.ulGpioMaskVal
;
529 voltage_table
->count
=
530 voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
;
531 voltage_table
->phase_delay
=
532 voltage_object
->asGpioVoltageObj
.ucPhaseDelay
;
537 static bool atomctrl_lookup_gpio_pin(
538 ATOM_GPIO_PIN_LUT
* gpio_lookup_table
,
539 const uint32_t pinId
,
540 pp_atomctrl_gpio_pin_assignment
*gpio_pin_assignment
)
542 unsigned int size
= le16_to_cpu(gpio_lookup_table
->sHeader
.usStructureSize
);
543 unsigned int offset
= offsetof(ATOM_GPIO_PIN_LUT
, asGPIO_Pin
[0]);
544 uint8_t *start
= (uint8_t *)gpio_lookup_table
;
546 while (offset
< size
) {
547 const ATOM_GPIO_PIN_ASSIGNMENT
*pin_assignment
=
548 (const ATOM_GPIO_PIN_ASSIGNMENT
*)(start
+ offset
);
550 if (pinId
== pin_assignment
->ucGPIO_ID
) {
551 gpio_pin_assignment
->uc_gpio_pin_bit_shift
=
552 pin_assignment
->ucGpioPinBitShift
;
553 gpio_pin_assignment
->us_gpio_pin_aindex
=
554 le16_to_cpu(pin_assignment
->usGpioPin_AIndex
);
558 offset
+= offsetof(ATOM_GPIO_PIN_ASSIGNMENT
, ucGPIO_ID
) + 1;
565 * Private Function to get the PowerPlay Table Address.
566 * WARNING: The tabled returned by this function is in
567 * dynamically allocated memory.
568 * The caller has to release if by calling kfree.
570 static ATOM_GPIO_PIN_LUT
*get_gpio_lookup_table(void *device
)
576 table_address
= (ATOM_GPIO_PIN_LUT
*)
577 cgs_atom_get_data_table(device
,
578 GetIndexIntoMasterTable(DATA
, GPIO_Pin_LUT
),
579 &size
, &frev
, &crev
);
581 PP_ASSERT_WITH_CODE((NULL
!= table_address
),
582 "Error retrieving BIOS Table Address!", return NULL
;);
584 return (ATOM_GPIO_PIN_LUT
*)table_address
;
588 * Returns 1 if the given pin id find in lookup table.
590 bool atomctrl_get_pp_assign_pin(
591 struct pp_hwmgr
*hwmgr
,
592 const uint32_t pinId
,
593 pp_atomctrl_gpio_pin_assignment
*gpio_pin_assignment
)
596 ATOM_GPIO_PIN_LUT
*gpio_lookup_table
=
597 get_gpio_lookup_table(hwmgr
->device
);
599 PP_ASSERT_WITH_CODE((NULL
!= gpio_lookup_table
),
600 "Could not find GPIO lookup Table in BIOS.", return -1);
602 bRet
= atomctrl_lookup_gpio_pin(gpio_lookup_table
, pinId
,
603 gpio_pin_assignment
);
608 int atomctrl_calculate_voltage_evv_on_sclk(
609 struct pp_hwmgr
*hwmgr
,
610 uint8_t voltage_type
,
612 uint16_t virtual_voltage_Id
,
617 ATOM_ASIC_PROFILING_INFO_V3_4
*getASICProfilingInfo
;
619 EFUSE_LINEAR_FUNC_PARAM sRO_fuse
;
620 EFUSE_LINEAR_FUNC_PARAM sCACm_fuse
;
621 EFUSE_LINEAR_FUNC_PARAM sCACb_fuse
;
622 EFUSE_LOGISTIC_FUNC_PARAM sKt_Beta_fuse
;
623 EFUSE_LOGISTIC_FUNC_PARAM sKv_m_fuse
;
624 EFUSE_LOGISTIC_FUNC_PARAM sKv_b_fuse
;
625 EFUSE_INPUT_PARAMETER sInput_FuseValues
;
626 READ_EFUSE_VALUE_PARAMETER sOutput_FuseValues
;
628 uint32_t ul_RO_fused
, ul_CACb_fused
, ul_CACm_fused
, ul_Kt_Beta_fused
, ul_Kv_m_fused
, ul_Kv_b_fused
;
629 fInt fSM_A0
, fSM_A1
, fSM_A2
, fSM_A3
, fSM_A4
, fSM_A5
, fSM_A6
, fSM_A7
;
630 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
;
631 fInt fLkg_FT
, repeat
;
632 fInt fMicro_FMAX
, fMicro_CR
, fSigma_FMAX
, fSigma_CR
, fSigma_DC
, fDC_SCLK
, fSquared_Sigma_DC
, fSquared_Sigma_CR
, fSquared_Sigma_FMAX
;
633 fInt fRLL_LoadLine
, fPowerDPMx
, fDerateTDP
, fVDDC_base
, fA_Term
, fC_Term
, fB_Term
, fRO_DC_margin
;
634 fInt fRO_fused
, fCACm_fused
, fCACb_fused
, fKv_m_fused
, fKv_b_fused
, fKt_Beta_fused
, fFT_Lkg_V0NORM
;
635 fInt fSclk_margin
, fSclk
, fEVV_V
;
636 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
;
637 uint32_t ul_FT_Lkg_V0NORM
;
638 fInt fLn_MaxDivMin
, fMin
, fAverage
, fRange
;
640 fInt fStepSize
= GetScaledFraction(625, 100000);
644 getASICProfilingInfo
= (ATOM_ASIC_PROFILING_INFO_V3_4
*)
645 cgs_atom_get_data_table(hwmgr
->device
,
646 GetIndexIntoMasterTable(DATA
, ASIC_ProfilingInfo
),
649 if (!getASICProfilingInfo
)
652 if (getASICProfilingInfo
->asHeader
.ucTableFormatRevision
< 3 ||
653 (getASICProfilingInfo
->asHeader
.ucTableFormatRevision
== 3 &&
654 getASICProfilingInfo
->asHeader
.ucTableContentRevision
< 4))
657 /*-----------------------------------------------------------
658 *GETTING MULTI-STEP PARAMETERS RELATED TO CURRENT DPM LEVEL
659 *-----------------------------------------------------------
661 fRLL_LoadLine
= Divide(getASICProfilingInfo
->ulLoadLineSlop
, 1000);
665 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm1
);
666 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM1
, 1000);
669 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm2
);
670 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM2
, 1000);
673 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm3
);
674 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM3
, 1000);
677 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm4
);
678 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM4
, 1000);
681 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm5
);
682 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM5
, 1000);
685 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm6
);
686 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM6
, 1000);
689 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm7
);
690 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM7
, 1000);
693 printk(KERN_ERR
"DPM Level not supported\n");
694 fPowerDPMx
= Convert_ULONG_ToFraction(1);
695 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM0
, 1000);
698 /*-------------------------
699 * DECODING FUSE VALUES
700 * ------------------------
703 sRO_fuse
= getASICProfilingInfo
->sRoFuse
;
705 sInput_FuseValues
.usEfuseIndex
= sRO_fuse
.usEfuseIndex
;
706 sInput_FuseValues
.ucBitShift
= sRO_fuse
.ucEfuseBitLSB
;
707 sInput_FuseValues
.ucBitLength
= sRO_fuse
.ucEfuseLength
;
709 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
711 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
712 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
713 &sOutput_FuseValues
);
718 /* Finally, the actual fuse value */
719 ul_RO_fused
= sOutput_FuseValues
.ulEfuseValue
;
720 fMin
= GetScaledFraction(sRO_fuse
.ulEfuseMin
, 1);
721 fRange
= GetScaledFraction(sRO_fuse
.ulEfuseEncodeRange
, 1);
722 fRO_fused
= fDecodeLinearFuse(ul_RO_fused
, fMin
, fRange
, sRO_fuse
.ucEfuseLength
);
724 sCACm_fuse
= getASICProfilingInfo
->sCACm
;
726 sInput_FuseValues
.usEfuseIndex
= sCACm_fuse
.usEfuseIndex
;
727 sInput_FuseValues
.ucBitShift
= sCACm_fuse
.ucEfuseBitLSB
;
728 sInput_FuseValues
.ucBitLength
= sCACm_fuse
.ucEfuseLength
;
730 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
732 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
733 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
734 &sOutput_FuseValues
);
739 ul_CACm_fused
= sOutput_FuseValues
.ulEfuseValue
;
740 fMin
= GetScaledFraction(sCACm_fuse
.ulEfuseMin
, 1000);
741 fRange
= GetScaledFraction(sCACm_fuse
.ulEfuseEncodeRange
, 1000);
743 fCACm_fused
= fDecodeLinearFuse(ul_CACm_fused
, fMin
, fRange
, sCACm_fuse
.ucEfuseLength
);
745 sCACb_fuse
= getASICProfilingInfo
->sCACb
;
747 sInput_FuseValues
.usEfuseIndex
= sCACb_fuse
.usEfuseIndex
;
748 sInput_FuseValues
.ucBitShift
= sCACb_fuse
.ucEfuseBitLSB
;
749 sInput_FuseValues
.ucBitLength
= sCACb_fuse
.ucEfuseLength
;
750 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
752 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
753 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
754 &sOutput_FuseValues
);
759 ul_CACb_fused
= sOutput_FuseValues
.ulEfuseValue
;
760 fMin
= GetScaledFraction(sCACb_fuse
.ulEfuseMin
, 1000);
761 fRange
= GetScaledFraction(sCACb_fuse
.ulEfuseEncodeRange
, 1000);
763 fCACb_fused
= fDecodeLinearFuse(ul_CACb_fused
, fMin
, fRange
, sCACb_fuse
.ucEfuseLength
);
765 sKt_Beta_fuse
= getASICProfilingInfo
->sKt_b
;
767 sInput_FuseValues
.usEfuseIndex
= sKt_Beta_fuse
.usEfuseIndex
;
768 sInput_FuseValues
.ucBitShift
= sKt_Beta_fuse
.ucEfuseBitLSB
;
769 sInput_FuseValues
.ucBitLength
= sKt_Beta_fuse
.ucEfuseLength
;
771 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
773 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
774 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
775 &sOutput_FuseValues
);
780 ul_Kt_Beta_fused
= sOutput_FuseValues
.ulEfuseValue
;
781 fAverage
= GetScaledFraction(sKt_Beta_fuse
.ulEfuseEncodeAverage
, 1000);
782 fRange
= GetScaledFraction(sKt_Beta_fuse
.ulEfuseEncodeRange
, 1000);
784 fKt_Beta_fused
= fDecodeLogisticFuse(ul_Kt_Beta_fused
,
785 fAverage
, fRange
, sKt_Beta_fuse
.ucEfuseLength
);
787 sKv_m_fuse
= getASICProfilingInfo
->sKv_m
;
789 sInput_FuseValues
.usEfuseIndex
= sKv_m_fuse
.usEfuseIndex
;
790 sInput_FuseValues
.ucBitShift
= sKv_m_fuse
.ucEfuseBitLSB
;
791 sInput_FuseValues
.ucBitLength
= sKv_m_fuse
.ucEfuseLength
;
793 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
795 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
796 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
797 &sOutput_FuseValues
);
801 ul_Kv_m_fused
= sOutput_FuseValues
.ulEfuseValue
;
802 fAverage
= GetScaledFraction(sKv_m_fuse
.ulEfuseEncodeAverage
, 1000);
803 fRange
= GetScaledFraction((sKv_m_fuse
.ulEfuseEncodeRange
& 0x7fffffff), 1000);
804 fRange
= fMultiply(fRange
, ConvertToFraction(-1));
806 fKv_m_fused
= fDecodeLogisticFuse(ul_Kv_m_fused
,
807 fAverage
, fRange
, sKv_m_fuse
.ucEfuseLength
);
809 sKv_b_fuse
= getASICProfilingInfo
->sKv_b
;
811 sInput_FuseValues
.usEfuseIndex
= sKv_b_fuse
.usEfuseIndex
;
812 sInput_FuseValues
.ucBitShift
= sKv_b_fuse
.ucEfuseBitLSB
;
813 sInput_FuseValues
.ucBitLength
= sKv_b_fuse
.ucEfuseLength
;
814 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
816 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
817 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
818 &sOutput_FuseValues
);
823 ul_Kv_b_fused
= sOutput_FuseValues
.ulEfuseValue
;
824 fAverage
= GetScaledFraction(sKv_b_fuse
.ulEfuseEncodeAverage
, 1000);
825 fRange
= GetScaledFraction(sKv_b_fuse
.ulEfuseEncodeRange
, 1000);
827 fKv_b_fused
= fDecodeLogisticFuse(ul_Kv_b_fused
,
828 fAverage
, fRange
, sKv_b_fuse
.ucEfuseLength
);
830 /* Decoding the Leakage - No special struct container */
834 * ucLkgEfuseLength=10
835 * ulLkgEncodeLn_MaxDivMin=69077
836 * ulLkgEncodeMax=1000000
837 * ulLkgEncodeMin=1000
838 * ulEfuseLogisticAlpha=13
841 sInput_FuseValues
.usEfuseIndex
= getASICProfilingInfo
->usLkgEuseIndex
;
842 sInput_FuseValues
.ucBitShift
= getASICProfilingInfo
->ucLkgEfuseBitLSB
;
843 sInput_FuseValues
.ucBitLength
= getASICProfilingInfo
->ucLkgEfuseLength
;
845 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
847 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
848 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
849 &sOutput_FuseValues
);
854 ul_FT_Lkg_V0NORM
= sOutput_FuseValues
.ulEfuseValue
;
855 fLn_MaxDivMin
= GetScaledFraction(getASICProfilingInfo
->ulLkgEncodeLn_MaxDivMin
, 10000);
856 fMin
= GetScaledFraction(getASICProfilingInfo
->ulLkgEncodeMin
, 10000);
858 fFT_Lkg_V0NORM
= fDecodeLeakageID(ul_FT_Lkg_V0NORM
,
859 fLn_MaxDivMin
, fMin
, getASICProfilingInfo
->ucLkgEfuseLength
);
860 fLkg_FT
= fFT_Lkg_V0NORM
;
862 /*-------------------------------------------
863 * PART 2 - Grabbing all required values
864 *-------------------------------------------
866 fSM_A0
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A0
, 1000000),
867 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A0_sign
)));
868 fSM_A1
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A1
, 1000000),
869 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A1_sign
)));
870 fSM_A2
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A2
, 100000),
871 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A2_sign
)));
872 fSM_A3
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A3
, 1000000),
873 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A3_sign
)));
874 fSM_A4
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A4
, 1000000),
875 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A4_sign
)));
876 fSM_A5
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A5
, 1000),
877 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A5_sign
)));
878 fSM_A6
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A6
, 1000),
879 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A6_sign
)));
880 fSM_A7
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A7
, 1000),
881 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A7_sign
)));
883 fMargin_RO_a
= ConvertToFraction(getASICProfilingInfo
->ulMargin_RO_a
);
884 fMargin_RO_b
= ConvertToFraction(getASICProfilingInfo
->ulMargin_RO_b
);
885 fMargin_RO_c
= ConvertToFraction(getASICProfilingInfo
->ulMargin_RO_c
);
887 fMargin_fixed
= ConvertToFraction(getASICProfilingInfo
->ulMargin_fixed
);
889 fMargin_FMAX_mean
= GetScaledFraction(
890 getASICProfilingInfo
->ulMargin_Fmax_mean
, 10000);
891 fMargin_Plat_mean
= GetScaledFraction(
892 getASICProfilingInfo
->ulMargin_plat_mean
, 10000);
893 fMargin_FMAX_sigma
= GetScaledFraction(
894 getASICProfilingInfo
->ulMargin_Fmax_sigma
, 10000);
895 fMargin_Plat_sigma
= GetScaledFraction(
896 getASICProfilingInfo
->ulMargin_plat_sigma
, 10000);
898 fMargin_DC_sigma
= GetScaledFraction(
899 getASICProfilingInfo
->ulMargin_DC_sigma
, 100);
900 fMargin_DC_sigma
= fDivide(fMargin_DC_sigma
, ConvertToFraction(1000));
902 fCACm_fused
= fDivide(fCACm_fused
, ConvertToFraction(100));
903 fCACb_fused
= fDivide(fCACb_fused
, ConvertToFraction(100));
904 fKt_Beta_fused
= fDivide(fKt_Beta_fused
, ConvertToFraction(100));
905 fKv_m_fused
= fNegate(fDivide(fKv_m_fused
, ConvertToFraction(100)));
906 fKv_b_fused
= fDivide(fKv_b_fused
, ConvertToFraction(10));
908 fSclk
= GetScaledFraction(sclk
, 100);
910 fV_max
= fDivide(GetScaledFraction(
911 getASICProfilingInfo
->ulMaxVddc
, 1000), ConvertToFraction(4));
912 fT_prod
= GetScaledFraction(getASICProfilingInfo
->ulBoardCoreTemp
, 10);
913 fLKG_Factor
= GetScaledFraction(getASICProfilingInfo
->ulEvvLkgFactor
, 100);
914 fT_FT
= GetScaledFraction(getASICProfilingInfo
->ulLeakageTemp
, 10);
915 fV_FT
= fDivide(GetScaledFraction(
916 getASICProfilingInfo
->ulLeakageVoltage
, 1000), ConvertToFraction(4));
917 fV_min
= fDivide(GetScaledFraction(
918 getASICProfilingInfo
->ulMinVddc
, 1000), ConvertToFraction(4));
920 /*-----------------------
922 *-----------------------
925 fA_Term
= fAdd(fMargin_RO_a
, fAdd(fMultiply(fSM_A4
, fSclk
), fSM_A5
));
926 fB_Term
= fAdd(fAdd(fMultiply(fSM_A2
, fSclk
), fSM_A6
), fMargin_RO_b
);
927 fC_Term
= fAdd(fMargin_RO_c
,
928 fAdd(fMultiply(fSM_A0
,fLkg_FT
),
929 fAdd(fMultiply(fSM_A1
, fMultiply(fLkg_FT
, fSclk
)),
930 fAdd(fMultiply(fSM_A3
, fSclk
),
931 fSubtract(fSM_A7
, fRO_fused
)))));
933 fVDDC_base
= fSubtract(fRO_fused
,
934 fSubtract(fMargin_RO_c
,
935 fSubtract(fSM_A3
, fMultiply(fSM_A1
, fSclk
))));
936 fVDDC_base
= fDivide(fVDDC_base
, fAdd(fMultiply(fSM_A0
, fSclk
), fSM_A2
));
938 repeat
= fSubtract(fVDDC_base
,
939 fDivide(fMargin_DC_sigma
, ConvertToFraction(1000)));
941 fRO_DC_margin
= fAdd(fMultiply(fMargin_RO_a
,
943 fAdd(fMultiply(fMargin_RO_b
, repeat
),
946 fDC_SCLK
= fSubtract(fRO_fused
,
947 fSubtract(fRO_DC_margin
,
949 fMultiply(fSM_A2
, repeat
))));
950 fDC_SCLK
= fDivide(fDC_SCLK
, fAdd(fMultiply(fSM_A0
, repeat
), fSM_A1
));
952 fSigma_DC
= fSubtract(fSclk
, fDC_SCLK
);
954 fMicro_FMAX
= fMultiply(fSclk
, fMargin_FMAX_mean
);
955 fMicro_CR
= fMultiply(fSclk
, fMargin_Plat_mean
);
956 fSigma_FMAX
= fMultiply(fSclk
, fMargin_FMAX_sigma
);
957 fSigma_CR
= fMultiply(fSclk
, fMargin_Plat_sigma
);
959 fSquared_Sigma_DC
= fGetSquare(fSigma_DC
);
960 fSquared_Sigma_CR
= fGetSquare(fSigma_CR
);
961 fSquared_Sigma_FMAX
= fGetSquare(fSigma_FMAX
);
963 fSclk_margin
= fAdd(fMicro_FMAX
,
966 fSqrt(fAdd(fSquared_Sigma_FMAX
,
967 fAdd(fSquared_Sigma_DC
, fSquared_Sigma_CR
))))));
969 fA_Term = fSM_A4 * (fSclk + fSclk_margin) + fSM_A5;
970 fB_Term = fSM_A2 * (fSclk + fSclk_margin) + fSM_A6;
971 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;
974 fA_Term
= fAdd(fMultiply(fSM_A4
, fAdd(fSclk
, fSclk_margin
)), fSM_A5
);
975 fB_Term
= fAdd(fMultiply(fSM_A2
, fAdd(fSclk
, fSclk_margin
)), fSM_A6
);
976 fC_Term
= fAdd(fRO_DC_margin
,
977 fAdd(fMultiply(fSM_A0
, fLkg_FT
),
978 fAdd(fMultiply(fMultiply(fSM_A1
, fLkg_FT
),
979 fAdd(fSclk
, fSclk_margin
)),
980 fAdd(fMultiply(fSM_A3
,
981 fAdd(fSclk
, fSclk_margin
)),
982 fSubtract(fSM_A7
, fRO_fused
)))));
984 SolveQuadracticEqn(fA_Term
, fB_Term
, fC_Term
, fRoots
);
986 if (GreaterThan(fRoots
[0], fRoots
[1]))
991 if (GreaterThan(fV_min
, fEVV_V
))
993 else if (GreaterThan(fEVV_V
, fV_max
))
994 fEVV_V
= fSubtract(fV_max
, fStepSize
);
996 fEVV_V
= fRoundUpByStepSize(fEVV_V
, fStepSize
, 0);
1005 while (GreaterThan(fAdd(fV_max
, fStepSize
), fV_x
)) {
1006 fTDP_Power_left
= fMultiply(fMultiply(fMultiply(fAdd(
1007 fMultiply(fCACm_fused
, fV_x
), fCACb_fused
), fSclk
),
1008 fGetSquare(fV_x
)), fDerateTDP
);
1010 fTDP_Power_right
= fMultiply(fFT_Lkg_V0NORM
, fMultiply(fLKG_Factor
,
1011 fMultiply(fExponential(fMultiply(fAdd(fMultiply(fKv_m_fused
,
1012 fT_prod
), fKv_b_fused
), fV_x
)), fV_x
)));
1013 fTDP_Power_right
= fMultiply(fTDP_Power_right
, fExponential(fMultiply(
1014 fKt_Beta_fused
, fT_prod
)));
1015 fTDP_Power_right
= fDivide(fTDP_Power_right
, fExponential(fMultiply(
1016 fAdd(fMultiply(fKv_m_fused
, fT_prod
), fKv_b_fused
), fV_FT
)));
1017 fTDP_Power_right
= fDivide(fTDP_Power_right
, fExponential(fMultiply(
1018 fKt_Beta_fused
, fT_FT
)));
1020 fTDP_Power
= fAdd(fTDP_Power_left
, fTDP_Power_right
);
1022 fTDP_Current
= fDivide(fTDP_Power
, fV_x
);
1024 fV_NL
= fAdd(fV_x
, fDivide(fMultiply(fTDP_Current
, fRLL_LoadLine
),
1025 ConvertToFraction(10)));
1027 fV_NL
= fRoundUpByStepSize(fV_NL
, fStepSize
, 0);
1029 if (GreaterThan(fV_max
, fV_NL
) &&
1030 (GreaterThan(fV_NL
, fEVV_V
) ||
1031 Equal(fV_NL
, fEVV_V
))) {
1032 fV_NL
= fMultiply(fV_NL
, ConvertToFraction(1000));
1034 *voltage
= (uint16_t)fV_NL
.partial
.real
;
1037 fV_x
= fAdd(fV_x
, fStepSize
);
1043 /** atomctrl_get_voltage_evv_on_sclk gets voltage via call to ATOM COMMAND table.
1044 * @param hwmgr input: pointer to hwManager
1045 * @param voltage_type input: type of EVV voltage VDDC or VDDGFX
1046 * @param sclk input: in 10Khz unit. DPM state SCLK frequency
1047 * which is define in PPTable SCLK/VDDC dependence
1048 * table associated with this virtual_voltage_Id
1049 * @param virtual_voltage_Id input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
1050 * @param voltage output: real voltage level in unit of mv
1052 int atomctrl_get_voltage_evv_on_sclk(
1053 struct pp_hwmgr
*hwmgr
,
1054 uint8_t voltage_type
,
1055 uint32_t sclk
, uint16_t virtual_voltage_Id
,
1059 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space
;
1061 get_voltage_info_param_space
.ucVoltageType
=
1063 get_voltage_info_param_space
.ucVoltageMode
=
1064 ATOM_GET_VOLTAGE_EVV_VOLTAGE
;
1065 get_voltage_info_param_space
.usVoltageLevel
=
1067 get_voltage_info_param_space
.ulSCLKFreq
=
1070 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
1071 GetIndexIntoMasterTable(COMMAND
, GetVoltageInfo
),
1072 &get_voltage_info_param_space
);
1077 *voltage
= ((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2
*)
1078 (&get_voltage_info_param_space
))->usVoltageLevel
;
1084 * Get the mpll reference clock in 10KHz
1086 uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr
*hwmgr
)
1088 ATOM_COMMON_TABLE_HEADER
*fw_info
;
1093 fw_info
= (ATOM_COMMON_TABLE_HEADER
*)
1094 cgs_atom_get_data_table(hwmgr
->device
,
1095 GetIndexIntoMasterTable(DATA
, FirmwareInfo
),
1096 &size
, &frev
, &crev
);
1098 if (fw_info
== NULL
)
1101 if ((fw_info
->ucTableFormatRevision
== 2) &&
1102 (le16_to_cpu(fw_info
->usStructureSize
) >= sizeof(ATOM_FIRMWARE_INFO_V2_1
))) {
1103 ATOM_FIRMWARE_INFO_V2_1
*fwInfo_2_1
=
1104 (ATOM_FIRMWARE_INFO_V2_1
*)fw_info
;
1105 clock
= (uint32_t)(le16_to_cpu(fwInfo_2_1
->usMemoryReferenceClock
));
1107 ATOM_FIRMWARE_INFO
*fwInfo_0_0
=
1108 (ATOM_FIRMWARE_INFO
*)fw_info
;
1109 clock
= (uint32_t)(le16_to_cpu(fwInfo_0_0
->usReferenceClock
));
1117 * Get the asic internal spread spectrum table
1119 static ATOM_ASIC_INTERNAL_SS_INFO
*asic_internal_ss_get_ss_table(void *device
)
1121 ATOM_ASIC_INTERNAL_SS_INFO
*table
= NULL
;
1125 table
= (ATOM_ASIC_INTERNAL_SS_INFO
*)
1126 cgs_atom_get_data_table(device
,
1127 GetIndexIntoMasterTable(DATA
, ASIC_InternalSS_Info
),
1128 &size
, &frev
, &crev
);
1134 * Get the asic internal spread spectrum assignment
1136 static int asic_internal_ss_get_ss_asignment(struct pp_hwmgr
*hwmgr
,
1137 const uint8_t clockSource
,
1138 const uint32_t clockSpeed
,
1139 pp_atomctrl_internal_ss_info
*ssEntry
)
1141 ATOM_ASIC_INTERNAL_SS_INFO
*table
;
1142 ATOM_ASIC_SS_ASSIGNMENT
*ssInfo
;
1143 int entry_found
= 0;
1145 memset(ssEntry
, 0x00, sizeof(pp_atomctrl_internal_ss_info
));
1147 table
= asic_internal_ss_get_ss_table(hwmgr
->device
);
1152 ssInfo
= &table
->asSpreadSpectrum
[0];
1154 while (((uint8_t *)ssInfo
- (uint8_t *)table
) <
1155 le16_to_cpu(table
->sHeader
.usStructureSize
)) {
1156 if ((clockSource
== ssInfo
->ucClockIndication
) &&
1157 ((uint32_t)clockSpeed
<= le32_to_cpu(ssInfo
->ulTargetClockRange
))) {
1162 ssInfo
= (ATOM_ASIC_SS_ASSIGNMENT
*)((uint8_t *)ssInfo
+
1163 sizeof(ATOM_ASIC_SS_ASSIGNMENT
));
1167 ssEntry
->speed_spectrum_percentage
=
1168 ssInfo
->usSpreadSpectrumPercentage
;
1169 ssEntry
->speed_spectrum_rate
= ssInfo
->usSpreadRateInKhz
;
1171 if (((GET_DATA_TABLE_MAJOR_REVISION(table
) == 2) &&
1172 (GET_DATA_TABLE_MINOR_REVISION(table
) >= 2)) ||
1173 (GET_DATA_TABLE_MAJOR_REVISION(table
) == 3)) {
1174 ssEntry
->speed_spectrum_rate
/= 100;
1177 switch (ssInfo
->ucSpreadSpectrumMode
) {
1179 ssEntry
->speed_spectrum_mode
=
1180 pp_atomctrl_spread_spectrum_mode_down
;
1183 ssEntry
->speed_spectrum_mode
=
1184 pp_atomctrl_spread_spectrum_mode_center
;
1187 ssEntry
->speed_spectrum_mode
=
1188 pp_atomctrl_spread_spectrum_mode_down
;
1193 return entry_found
? 0 : 1;
1197 * Get the memory clock spread spectrum info
1199 int atomctrl_get_memory_clock_spread_spectrum(
1200 struct pp_hwmgr
*hwmgr
,
1201 const uint32_t memory_clock
,
1202 pp_atomctrl_internal_ss_info
*ssInfo
)
1204 return asic_internal_ss_get_ss_asignment(hwmgr
,
1205 ASIC_INTERNAL_MEMORY_SS
, memory_clock
, ssInfo
);
1208 * Get the engine clock spread spectrum info
1210 int atomctrl_get_engine_clock_spread_spectrum(
1211 struct pp_hwmgr
*hwmgr
,
1212 const uint32_t engine_clock
,
1213 pp_atomctrl_internal_ss_info
*ssInfo
)
1215 return asic_internal_ss_get_ss_asignment(hwmgr
,
1216 ASIC_INTERNAL_ENGINE_SS
, engine_clock
, ssInfo
);
1219 int atomctrl_read_efuse(void *device
, uint16_t start_index
,
1220 uint16_t end_index
, uint32_t mask
, uint32_t *efuse
)
1223 READ_EFUSE_VALUE_PARAMETER efuse_param
;
1225 efuse_param
.sEfuse
.usEfuseIndex
= (start_index
/ 32) * 4;
1226 efuse_param
.sEfuse
.ucBitShift
= (uint8_t)
1227 (start_index
- ((start_index
/ 32) * 32));
1228 efuse_param
.sEfuse
.ucBitLength
= (uint8_t)
1229 ((end_index
- start_index
) + 1);
1231 result
= cgs_atom_exec_cmd_table(device
,
1232 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
1235 *efuse
= efuse_param
.ulEfuseValue
& mask
;
1240 int atomctrl_set_ac_timing_ai(struct pp_hwmgr
*hwmgr
, uint32_t memory_clock
,
1243 DYNAMICE_MEMORY_SETTINGS_PARAMETER_V2_1 memory_clock_parameters
;
1246 memory_clock_parameters
.asDPMMCReg
.ulClock
.ulClockFreq
= memory_clock
& SET_CLOCK_FREQ_MASK
;
1247 memory_clock_parameters
.asDPMMCReg
.ulClock
.ulComputeClockFlag
= ADJUST_MC_SETTING_PARAM
;
1248 memory_clock_parameters
.asDPMMCReg
.ucMclkDPMState
= level
;
1250 result
= cgs_atom_exec_cmd_table
1252 GetIndexIntoMasterTable(COMMAND
, DynamicMemorySettings
),
1253 &memory_clock_parameters
);
1258 int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr
*hwmgr
, uint8_t voltage_type
,
1259 uint32_t sclk
, uint16_t virtual_voltage_Id
, uint32_t *voltage
)
1263 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_3 get_voltage_info_param_space
;
1265 get_voltage_info_param_space
.ucVoltageType
= voltage_type
;
1266 get_voltage_info_param_space
.ucVoltageMode
= ATOM_GET_VOLTAGE_EVV_VOLTAGE
;
1267 get_voltage_info_param_space
.usVoltageLevel
= virtual_voltage_Id
;
1268 get_voltage_info_param_space
.ulSCLKFreq
= sclk
;
1270 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
1271 GetIndexIntoMasterTable(COMMAND
, GetVoltageInfo
),
1272 &get_voltage_info_param_space
);
1277 *voltage
= ((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_3
*)(&get_voltage_info_param_space
))->ulVoltageLevel
;
1282 int atomctrl_get_smc_sclk_range_table(struct pp_hwmgr
*hwmgr
, struct pp_atom_ctrl_sclk_range_table
*table
)
1289 ATOM_SMU_INFO_V2_1
*psmu_info
=
1290 (ATOM_SMU_INFO_V2_1
*)cgs_atom_get_data_table(hwmgr
->device
,
1291 GetIndexIntoMasterTable(DATA
, SMU_Info
),
1292 &size
, &frev
, &crev
);
1295 for (i
= 0; i
< psmu_info
->ucSclkEntryNum
; i
++) {
1296 table
->entry
[i
].ucVco_setting
= psmu_info
->asSclkFcwRangeEntry
[i
].ucVco_setting
;
1297 table
->entry
[i
].ucPostdiv
= psmu_info
->asSclkFcwRangeEntry
[i
].ucPostdiv
;
1298 table
->entry
[i
].usFcw_pcc
= psmu_info
->asSclkFcwRangeEntry
[i
].ucFcw_pcc
;
1299 table
->entry
[i
].usFcw_trans_upper
= psmu_info
->asSclkFcwRangeEntry
[i
].ucFcw_trans_upper
;
1300 table
->entry
[i
].usRcw_trans_lower
= psmu_info
->asSclkFcwRangeEntry
[i
].ucRcw_trans_lower
;
1306 int atomctrl_get_avfs_information(struct pp_hwmgr
*hwmgr
, struct pp_atom_ctrl__avfs_parameters
*param
)
1308 ATOM_ASIC_PROFILING_INFO_V3_6
*profile
= NULL
;
1313 profile
= (ATOM_ASIC_PROFILING_INFO_V3_6
*)
1314 cgs_atom_get_data_table(hwmgr
->device
,
1315 GetIndexIntoMasterTable(DATA
, ASIC_ProfilingInfo
),
1320 param
->ulAVFS_meanNsigma_Acontant0
= profile
->ulAVFS_meanNsigma_Acontant0
;
1321 param
->ulAVFS_meanNsigma_Acontant1
= profile
->ulAVFS_meanNsigma_Acontant1
;
1322 param
->ulAVFS_meanNsigma_Acontant2
= profile
->ulAVFS_meanNsigma_Acontant2
;
1323 param
->usAVFS_meanNsigma_DC_tol_sigma
= profile
->usAVFS_meanNsigma_DC_tol_sigma
;
1324 param
->usAVFS_meanNsigma_Platform_mean
= profile
->usAVFS_meanNsigma_Platform_mean
;
1325 param
->usAVFS_meanNsigma_Platform_sigma
= profile
->usAVFS_meanNsigma_Platform_sigma
;
1326 param
->ulGB_VDROOP_TABLE_CKSOFF_a0
= profile
->ulGB_VDROOP_TABLE_CKSOFF_a0
;
1327 param
->ulGB_VDROOP_TABLE_CKSOFF_a1
= profile
->ulGB_VDROOP_TABLE_CKSOFF_a1
;
1328 param
->ulGB_VDROOP_TABLE_CKSOFF_a2
= profile
->ulGB_VDROOP_TABLE_CKSOFF_a2
;
1329 param
->ulGB_VDROOP_TABLE_CKSON_a0
= profile
->ulGB_VDROOP_TABLE_CKSON_a0
;
1330 param
->ulGB_VDROOP_TABLE_CKSON_a1
= profile
->ulGB_VDROOP_TABLE_CKSON_a1
;
1331 param
->ulGB_VDROOP_TABLE_CKSON_a2
= profile
->ulGB_VDROOP_TABLE_CKSON_a2
;
1332 param
->ulAVFSGB_FUSE_TABLE_CKSOFF_m1
= profile
->ulAVFSGB_FUSE_TABLE_CKSOFF_m1
;
1333 param
->usAVFSGB_FUSE_TABLE_CKSOFF_m2
= profile
->usAVFSGB_FUSE_TABLE_CKSOFF_m2
;
1334 param
->ulAVFSGB_FUSE_TABLE_CKSOFF_b
= profile
->ulAVFSGB_FUSE_TABLE_CKSOFF_b
;
1335 param
->ulAVFSGB_FUSE_TABLE_CKSON_m1
= profile
->ulAVFSGB_FUSE_TABLE_CKSON_m1
;
1336 param
->usAVFSGB_FUSE_TABLE_CKSON_m2
= profile
->usAVFSGB_FUSE_TABLE_CKSON_m2
;
1337 param
->ulAVFSGB_FUSE_TABLE_CKSON_b
= profile
->ulAVFSGB_FUSE_TABLE_CKSON_b
;
1338 param
->usMaxVoltage_0_25mv
= profile
->usMaxVoltage_0_25mv
;
1339 param
->ucEnableGB_VDROOP_TABLE_CKSOFF
= profile
->ucEnableGB_VDROOP_TABLE_CKSOFF
;
1340 param
->ucEnableGB_VDROOP_TABLE_CKSON
= profile
->ucEnableGB_VDROOP_TABLE_CKSON
;
1341 param
->ucEnableGB_FUSE_TABLE_CKSOFF
= profile
->ucEnableGB_FUSE_TABLE_CKSOFF
;
1342 param
->ucEnableGB_FUSE_TABLE_CKSON
= profile
->ucEnableGB_FUSE_TABLE_CKSON
;
1343 param
->usPSM_Age_ComFactor
= profile
->usPSM_Age_ComFactor
;
1344 param
->ucEnableApplyAVFS_CKS_OFF_Voltage
= profile
->ucEnableApplyAVFS_CKS_OFF_Voltage
;