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_dfs_pll_dividers_vi(
377 struct pp_hwmgr
*hwmgr
,
378 uint32_t clock_value
,
379 pp_atomctrl_clock_dividers_vi
*dividers
)
381 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters
;
384 pll_patameters
.ulClock
.ulClock
= clock_value
;
385 pll_patameters
.ulClock
.ucPostDiv
=
386 COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK
;
388 result
= cgs_atom_exec_cmd_table
390 GetIndexIntoMasterTable(COMMAND
, ComputeMemoryEnginePLL
),
394 dividers
->pll_post_divider
=
395 pll_patameters
.ulClock
.ucPostDiv
;
396 dividers
->real_clock
=
397 pll_patameters
.ulClock
.ulClock
;
399 dividers
->ul_fb_div
.ul_fb_div_frac
=
400 pll_patameters
.ulFbDiv
.usFbDivFrac
;
401 dividers
->ul_fb_div
.ul_fb_div
=
402 pll_patameters
.ulFbDiv
.usFbDiv
;
404 dividers
->uc_pll_ref_div
=
405 pll_patameters
.ucPllRefDiv
;
406 dividers
->uc_pll_post_div
=
407 pll_patameters
.ucPllPostDiv
;
408 dividers
->uc_pll_cntl_flag
=
409 pll_patameters
.ucPllCntlFlag
;
416 * Get the reference clock in 10KHz
418 uint32_t atomctrl_get_reference_clock(struct pp_hwmgr
*hwmgr
)
420 ATOM_FIRMWARE_INFO
*fw_info
;
425 fw_info
= (ATOM_FIRMWARE_INFO
*)
426 cgs_atom_get_data_table(hwmgr
->device
,
427 GetIndexIntoMasterTable(DATA
, FirmwareInfo
),
428 &size
, &frev
, &crev
);
433 clock
= (uint32_t)(le16_to_cpu(fw_info
->usReferenceClock
));
439 * Returns true if the given voltage type is controlled by GPIO pins.
440 * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC,
441 * SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ.
442 * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE
444 bool atomctrl_is_voltage_controled_by_gpio_v3(
445 struct pp_hwmgr
*hwmgr
,
446 uint8_t voltage_type
,
447 uint8_t voltage_mode
)
449 ATOM_VOLTAGE_OBJECT_INFO_V3_1
*voltage_info
=
450 (ATOM_VOLTAGE_OBJECT_INFO_V3_1
*)get_voltage_info_table(hwmgr
->device
);
453 PP_ASSERT_WITH_CODE((NULL
!= voltage_info
),
454 "Could not find Voltage Table in BIOS.", return false;);
456 ret
= (NULL
!= atomctrl_lookup_voltage_type_v3
457 (voltage_info
, voltage_type
, voltage_mode
)) ? true : false;
462 int atomctrl_get_voltage_table_v3(
463 struct pp_hwmgr
*hwmgr
,
464 uint8_t voltage_type
,
465 uint8_t voltage_mode
,
466 pp_atomctrl_voltage_table
*voltage_table
)
468 ATOM_VOLTAGE_OBJECT_INFO_V3_1
*voltage_info
=
469 (ATOM_VOLTAGE_OBJECT_INFO_V3_1
*)get_voltage_info_table(hwmgr
->device
);
470 const ATOM_VOLTAGE_OBJECT_V3
*voltage_object
;
473 PP_ASSERT_WITH_CODE((NULL
!= voltage_info
),
474 "Could not find Voltage Table in BIOS.", return -1;);
476 voltage_object
= atomctrl_lookup_voltage_type_v3
477 (voltage_info
, voltage_type
, voltage_mode
);
479 if (voltage_object
== NULL
)
483 (voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
<=
484 PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES
),
485 "Too many voltage entries!",
489 for (i
= 0; i
< voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
; i
++) {
490 voltage_table
->entries
[i
].value
=
491 voltage_object
->asGpioVoltageObj
.asVolGpioLut
[i
].usVoltageValue
;
492 voltage_table
->entries
[i
].smio_low
=
493 voltage_object
->asGpioVoltageObj
.asVolGpioLut
[i
].ulVoltageId
;
496 voltage_table
->mask_low
=
497 voltage_object
->asGpioVoltageObj
.ulGpioMaskVal
;
498 voltage_table
->count
=
499 voltage_object
->asGpioVoltageObj
.ucGpioEntryNum
;
500 voltage_table
->phase_delay
=
501 voltage_object
->asGpioVoltageObj
.ucPhaseDelay
;
506 static bool atomctrl_lookup_gpio_pin(
507 ATOM_GPIO_PIN_LUT
* gpio_lookup_table
,
508 const uint32_t pinId
,
509 pp_atomctrl_gpio_pin_assignment
*gpio_pin_assignment
)
511 unsigned int size
= le16_to_cpu(gpio_lookup_table
->sHeader
.usStructureSize
);
512 unsigned int offset
= offsetof(ATOM_GPIO_PIN_LUT
, asGPIO_Pin
[0]);
513 uint8_t *start
= (uint8_t *)gpio_lookup_table
;
515 while (offset
< size
) {
516 const ATOM_GPIO_PIN_ASSIGNMENT
*pin_assignment
=
517 (const ATOM_GPIO_PIN_ASSIGNMENT
*)(start
+ offset
);
519 if (pinId
== pin_assignment
->ucGPIO_ID
) {
520 gpio_pin_assignment
->uc_gpio_pin_bit_shift
=
521 pin_assignment
->ucGpioPinBitShift
;
522 gpio_pin_assignment
->us_gpio_pin_aindex
=
523 le16_to_cpu(pin_assignment
->usGpioPin_AIndex
);
527 offset
+= offsetof(ATOM_GPIO_PIN_ASSIGNMENT
, ucGPIO_ID
) + 1;
534 * Private Function to get the PowerPlay Table Address.
535 * WARNING: The tabled returned by this function is in
536 * dynamically allocated memory.
537 * The caller has to release if by calling kfree.
539 static ATOM_GPIO_PIN_LUT
*get_gpio_lookup_table(void *device
)
545 table_address
= (ATOM_GPIO_PIN_LUT
*)
546 cgs_atom_get_data_table(device
,
547 GetIndexIntoMasterTable(DATA
, GPIO_Pin_LUT
),
548 &size
, &frev
, &crev
);
550 PP_ASSERT_WITH_CODE((NULL
!= table_address
),
551 "Error retrieving BIOS Table Address!", return NULL
;);
553 return (ATOM_GPIO_PIN_LUT
*)table_address
;
557 * Returns 1 if the given pin id find in lookup table.
559 bool atomctrl_get_pp_assign_pin(
560 struct pp_hwmgr
*hwmgr
,
561 const uint32_t pinId
,
562 pp_atomctrl_gpio_pin_assignment
*gpio_pin_assignment
)
565 ATOM_GPIO_PIN_LUT
*gpio_lookup_table
=
566 get_gpio_lookup_table(hwmgr
->device
);
568 PP_ASSERT_WITH_CODE((NULL
!= gpio_lookup_table
),
569 "Could not find GPIO lookup Table in BIOS.", return -1);
571 bRet
= atomctrl_lookup_gpio_pin(gpio_lookup_table
, pinId
,
572 gpio_pin_assignment
);
577 int atomctrl_calculate_voltage_evv_on_sclk(
578 struct pp_hwmgr
*hwmgr
,
579 uint8_t voltage_type
,
581 uint16_t virtual_voltage_Id
,
586 ATOM_ASIC_PROFILING_INFO_V3_4
*getASICProfilingInfo
;
588 EFUSE_LINEAR_FUNC_PARAM sRO_fuse
;
589 EFUSE_LINEAR_FUNC_PARAM sCACm_fuse
;
590 EFUSE_LINEAR_FUNC_PARAM sCACb_fuse
;
591 EFUSE_LOGISTIC_FUNC_PARAM sKt_Beta_fuse
;
592 EFUSE_LOGISTIC_FUNC_PARAM sKv_m_fuse
;
593 EFUSE_LOGISTIC_FUNC_PARAM sKv_b_fuse
;
594 EFUSE_INPUT_PARAMETER sInput_FuseValues
;
595 READ_EFUSE_VALUE_PARAMETER sOutput_FuseValues
;
597 uint32_t ul_RO_fused
, ul_CACb_fused
, ul_CACm_fused
, ul_Kt_Beta_fused
, ul_Kv_m_fused
, ul_Kv_b_fused
;
598 fInt fSM_A0
, fSM_A1
, fSM_A2
, fSM_A3
, fSM_A4
, fSM_A5
, fSM_A6
, fSM_A7
;
599 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
;
600 fInt fLkg_FT
, repeat
;
601 fInt fMicro_FMAX
, fMicro_CR
, fSigma_FMAX
, fSigma_CR
, fSigma_DC
, fDC_SCLK
, fSquared_Sigma_DC
, fSquared_Sigma_CR
, fSquared_Sigma_FMAX
;
602 fInt fRLL_LoadLine
, fPowerDPMx
, fDerateTDP
, fVDDC_base
, fA_Term
, fC_Term
, fB_Term
, fRO_DC_margin
;
603 fInt fRO_fused
, fCACm_fused
, fCACb_fused
, fKv_m_fused
, fKv_b_fused
, fKt_Beta_fused
, fFT_Lkg_V0NORM
;
604 fInt fSclk_margin
, fSclk
, fEVV_V
;
605 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
;
606 uint32_t ul_FT_Lkg_V0NORM
;
607 fInt fLn_MaxDivMin
, fMin
, fAverage
, fRange
;
609 fInt fStepSize
= GetScaledFraction(625, 100000);
613 getASICProfilingInfo
= (ATOM_ASIC_PROFILING_INFO_V3_4
*)
614 cgs_atom_get_data_table(hwmgr
->device
,
615 GetIndexIntoMasterTable(DATA
, ASIC_ProfilingInfo
),
618 if (!getASICProfilingInfo
)
621 if(getASICProfilingInfo
->asHeader
.ucTableFormatRevision
< 3 ||
622 (getASICProfilingInfo
->asHeader
.ucTableFormatRevision
== 3 &&
623 getASICProfilingInfo
->asHeader
.ucTableContentRevision
< 4))
626 /*-----------------------------------------------------------
627 *GETTING MULTI-STEP PARAMETERS RELATED TO CURRENT DPM LEVEL
628 *-----------------------------------------------------------
630 fRLL_LoadLine
= Divide(getASICProfilingInfo
->ulLoadLineSlop
, 1000);
634 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm1
);
635 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM1
, 1000);
638 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm2
);
639 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM2
, 1000);
642 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm3
);
643 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM3
, 1000);
646 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm4
);
647 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM4
, 1000);
650 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm5
);
651 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM5
, 1000);
654 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm6
);
655 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM6
, 1000);
658 fPowerDPMx
= Convert_ULONG_ToFraction(getASICProfilingInfo
->usPowerDpm7
);
659 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM7
, 1000);
662 printk(KERN_ERR
"DPM Level not supported\n");
663 fPowerDPMx
= Convert_ULONG_ToFraction(1);
664 fDerateTDP
= GetScaledFraction(getASICProfilingInfo
->ulTdpDerateDPM0
, 1000);
667 /*-------------------------
668 * DECODING FUSE VALUES
669 * ------------------------
672 sRO_fuse
= getASICProfilingInfo
->sRoFuse
;
674 sInput_FuseValues
.usEfuseIndex
= sRO_fuse
.usEfuseIndex
;
675 sInput_FuseValues
.ucBitShift
= sRO_fuse
.ucEfuseBitLSB
;
676 sInput_FuseValues
.ucBitLength
= sRO_fuse
.ucEfuseLength
;
678 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
680 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
681 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
682 &sOutput_FuseValues
);
687 /* Finally, the actual fuse value */
688 ul_RO_fused
= sOutput_FuseValues
.ulEfuseValue
;
689 fMin
= GetScaledFraction(sRO_fuse
.ulEfuseMin
, 1);
690 fRange
= GetScaledFraction(sRO_fuse
.ulEfuseEncodeRange
, 1);
691 fRO_fused
= fDecodeLinearFuse(ul_RO_fused
, fMin
, fRange
, sRO_fuse
.ucEfuseLength
);
693 sCACm_fuse
= getASICProfilingInfo
->sCACm
;
695 sInput_FuseValues
.usEfuseIndex
= sCACm_fuse
.usEfuseIndex
;
696 sInput_FuseValues
.ucBitShift
= sCACm_fuse
.ucEfuseBitLSB
;
697 sInput_FuseValues
.ucBitLength
= sCACm_fuse
.ucEfuseLength
;
699 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
701 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
702 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
703 &sOutput_FuseValues
);
708 ul_CACm_fused
= sOutput_FuseValues
.ulEfuseValue
;
709 fMin
= GetScaledFraction(sCACm_fuse
.ulEfuseMin
, 1000);
710 fRange
= GetScaledFraction(sCACm_fuse
.ulEfuseEncodeRange
, 1000);
712 fCACm_fused
= fDecodeLinearFuse(ul_CACm_fused
, fMin
, fRange
, sCACm_fuse
.ucEfuseLength
);
714 sCACb_fuse
= getASICProfilingInfo
->sCACb
;
716 sInput_FuseValues
.usEfuseIndex
= sCACb_fuse
.usEfuseIndex
;
717 sInput_FuseValues
.ucBitShift
= sCACb_fuse
.ucEfuseBitLSB
;
718 sInput_FuseValues
.ucBitLength
= sCACb_fuse
.ucEfuseLength
;
719 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
721 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
722 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
723 &sOutput_FuseValues
);
728 ul_CACb_fused
= sOutput_FuseValues
.ulEfuseValue
;
729 fMin
= GetScaledFraction(sCACb_fuse
.ulEfuseMin
, 1000);
730 fRange
= GetScaledFraction(sCACb_fuse
.ulEfuseEncodeRange
, 1000);
732 fCACb_fused
= fDecodeLinearFuse(ul_CACb_fused
, fMin
, fRange
, sCACb_fuse
.ucEfuseLength
);
734 sKt_Beta_fuse
= getASICProfilingInfo
->sKt_b
;
736 sInput_FuseValues
.usEfuseIndex
= sKt_Beta_fuse
.usEfuseIndex
;
737 sInput_FuseValues
.ucBitShift
= sKt_Beta_fuse
.ucEfuseBitLSB
;
738 sInput_FuseValues
.ucBitLength
= sKt_Beta_fuse
.ucEfuseLength
;
740 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
742 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
743 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
744 &sOutput_FuseValues
);
749 ul_Kt_Beta_fused
= sOutput_FuseValues
.ulEfuseValue
;
750 fAverage
= GetScaledFraction(sKt_Beta_fuse
.ulEfuseEncodeAverage
, 1000);
751 fRange
= GetScaledFraction(sKt_Beta_fuse
.ulEfuseEncodeRange
, 1000);
753 fKt_Beta_fused
= fDecodeLogisticFuse(ul_Kt_Beta_fused
,
754 fAverage
, fRange
, sKt_Beta_fuse
.ucEfuseLength
);
756 sKv_m_fuse
= getASICProfilingInfo
->sKv_m
;
758 sInput_FuseValues
.usEfuseIndex
= sKv_m_fuse
.usEfuseIndex
;
759 sInput_FuseValues
.ucBitShift
= sKv_m_fuse
.ucEfuseBitLSB
;
760 sInput_FuseValues
.ucBitLength
= sKv_m_fuse
.ucEfuseLength
;
762 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
764 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
765 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
766 &sOutput_FuseValues
);
770 ul_Kv_m_fused
= sOutput_FuseValues
.ulEfuseValue
;
771 fAverage
= GetScaledFraction(sKv_m_fuse
.ulEfuseEncodeAverage
, 1000);
772 fRange
= GetScaledFraction((sKv_m_fuse
.ulEfuseEncodeRange
& 0x7fffffff), 1000);
773 fRange
= fMultiply(fRange
, ConvertToFraction(-1));
775 fKv_m_fused
= fDecodeLogisticFuse(ul_Kv_m_fused
,
776 fAverage
, fRange
, sKv_m_fuse
.ucEfuseLength
);
778 sKv_b_fuse
= getASICProfilingInfo
->sKv_b
;
780 sInput_FuseValues
.usEfuseIndex
= sKv_b_fuse
.usEfuseIndex
;
781 sInput_FuseValues
.ucBitShift
= sKv_b_fuse
.ucEfuseBitLSB
;
782 sInput_FuseValues
.ucBitLength
= sKv_b_fuse
.ucEfuseLength
;
783 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
785 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
786 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
787 &sOutput_FuseValues
);
792 ul_Kv_b_fused
= sOutput_FuseValues
.ulEfuseValue
;
793 fAverage
= GetScaledFraction(sKv_b_fuse
.ulEfuseEncodeAverage
, 1000);
794 fRange
= GetScaledFraction(sKv_b_fuse
.ulEfuseEncodeRange
, 1000);
796 fKv_b_fused
= fDecodeLogisticFuse(ul_Kv_b_fused
,
797 fAverage
, fRange
, sKv_b_fuse
.ucEfuseLength
);
799 /* Decoding the Leakage - No special struct container */
803 * ucLkgEfuseLength=10
804 * ulLkgEncodeLn_MaxDivMin=69077
805 * ulLkgEncodeMax=1000000
806 * ulLkgEncodeMin=1000
807 * ulEfuseLogisticAlpha=13
810 sInput_FuseValues
.usEfuseIndex
= getASICProfilingInfo
->usLkgEuseIndex
;
811 sInput_FuseValues
.ucBitShift
= getASICProfilingInfo
->ucLkgEfuseBitLSB
;
812 sInput_FuseValues
.ucBitLength
= getASICProfilingInfo
->ucLkgEfuseLength
;
814 sOutput_FuseValues
.sEfuse
= sInput_FuseValues
;
816 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
817 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
818 &sOutput_FuseValues
);
823 ul_FT_Lkg_V0NORM
= sOutput_FuseValues
.ulEfuseValue
;
824 fLn_MaxDivMin
= GetScaledFraction(getASICProfilingInfo
->ulLkgEncodeLn_MaxDivMin
, 10000);
825 fMin
= GetScaledFraction(getASICProfilingInfo
->ulLkgEncodeMin
, 10000);
827 fFT_Lkg_V0NORM
= fDecodeLeakageID(ul_FT_Lkg_V0NORM
,
828 fLn_MaxDivMin
, fMin
, getASICProfilingInfo
->ucLkgEfuseLength
);
829 fLkg_FT
= fFT_Lkg_V0NORM
;
831 /*-------------------------------------------
832 * PART 2 - Grabbing all required values
833 *-------------------------------------------
835 fSM_A0
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A0
, 1000000),
836 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A0_sign
)));
837 fSM_A1
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A1
, 1000000),
838 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A1_sign
)));
839 fSM_A2
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A2
, 100000),
840 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A2_sign
)));
841 fSM_A3
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A3
, 1000000),
842 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A3_sign
)));
843 fSM_A4
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A4
, 1000000),
844 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A4_sign
)));
845 fSM_A5
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A5
, 1000),
846 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A5_sign
)));
847 fSM_A6
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A6
, 1000),
848 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A6_sign
)));
849 fSM_A7
= fMultiply(GetScaledFraction(getASICProfilingInfo
->ulSM_A7
, 1000),
850 ConvertToFraction(uPow(-1, getASICProfilingInfo
->ucSM_A7_sign
)));
852 fMargin_RO_a
= ConvertToFraction(getASICProfilingInfo
->ulMargin_RO_a
);
853 fMargin_RO_b
= ConvertToFraction(getASICProfilingInfo
->ulMargin_RO_b
);
854 fMargin_RO_c
= ConvertToFraction(getASICProfilingInfo
->ulMargin_RO_c
);
856 fMargin_fixed
= ConvertToFraction(getASICProfilingInfo
->ulMargin_fixed
);
858 fMargin_FMAX_mean
= GetScaledFraction(
859 getASICProfilingInfo
->ulMargin_Fmax_mean
, 10000);
860 fMargin_Plat_mean
= GetScaledFraction(
861 getASICProfilingInfo
->ulMargin_plat_mean
, 10000);
862 fMargin_FMAX_sigma
= GetScaledFraction(
863 getASICProfilingInfo
->ulMargin_Fmax_sigma
, 10000);
864 fMargin_Plat_sigma
= GetScaledFraction(
865 getASICProfilingInfo
->ulMargin_plat_sigma
, 10000);
867 fMargin_DC_sigma
= GetScaledFraction(
868 getASICProfilingInfo
->ulMargin_DC_sigma
, 100);
869 fMargin_DC_sigma
= fDivide(fMargin_DC_sigma
, ConvertToFraction(1000));
871 fCACm_fused
= fDivide(fCACm_fused
, ConvertToFraction(100));
872 fCACb_fused
= fDivide(fCACb_fused
, ConvertToFraction(100));
873 fKt_Beta_fused
= fDivide(fKt_Beta_fused
, ConvertToFraction(100));
874 fKv_m_fused
= fNegate(fDivide(fKv_m_fused
, ConvertToFraction(100)));
875 fKv_b_fused
= fDivide(fKv_b_fused
, ConvertToFraction(10));
877 fSclk
= GetScaledFraction(sclk
, 100);
879 fV_max
= fDivide(GetScaledFraction(
880 getASICProfilingInfo
->ulMaxVddc
, 1000), ConvertToFraction(4));
881 fT_prod
= GetScaledFraction(getASICProfilingInfo
->ulBoardCoreTemp
, 10);
882 fLKG_Factor
= GetScaledFraction(getASICProfilingInfo
->ulEvvLkgFactor
, 100);
883 fT_FT
= GetScaledFraction(getASICProfilingInfo
->ulLeakageTemp
, 10);
884 fV_FT
= fDivide(GetScaledFraction(
885 getASICProfilingInfo
->ulLeakageVoltage
, 1000), ConvertToFraction(4));
886 fV_min
= fDivide(GetScaledFraction(
887 getASICProfilingInfo
->ulMinVddc
, 1000), ConvertToFraction(4));
889 /*-----------------------
891 *-----------------------
894 fA_Term
= fAdd(fMargin_RO_a
, fAdd(fMultiply(fSM_A4
,fSclk
), fSM_A5
));
895 fB_Term
= fAdd(fAdd(fMultiply(fSM_A2
, fSclk
), fSM_A6
), fMargin_RO_b
);
896 fC_Term
= fAdd(fMargin_RO_c
,
897 fAdd(fMultiply(fSM_A0
,fLkg_FT
),
898 fAdd(fMultiply(fSM_A1
, fMultiply(fLkg_FT
,fSclk
)),
899 fAdd(fMultiply(fSM_A3
, fSclk
),
900 fSubtract(fSM_A7
,fRO_fused
)))));
902 fVDDC_base
= fSubtract(fRO_fused
,
903 fSubtract(fMargin_RO_c
,
904 fSubtract(fSM_A3
, fMultiply(fSM_A1
, fSclk
))));
905 fVDDC_base
= fDivide(fVDDC_base
, fAdd(fMultiply(fSM_A0
,fSclk
), fSM_A2
));
907 repeat
= fSubtract(fVDDC_base
,
908 fDivide(fMargin_DC_sigma
, ConvertToFraction(1000)));
910 fRO_DC_margin
= fAdd(fMultiply(fMargin_RO_a
,
912 fAdd(fMultiply(fMargin_RO_b
, repeat
),
915 fDC_SCLK
= fSubtract(fRO_fused
,
916 fSubtract(fRO_DC_margin
,
918 fMultiply(fSM_A2
, repeat
))));
919 fDC_SCLK
= fDivide(fDC_SCLK
, fAdd(fMultiply(fSM_A0
,repeat
), fSM_A1
));
921 fSigma_DC
= fSubtract(fSclk
, fDC_SCLK
);
923 fMicro_FMAX
= fMultiply(fSclk
, fMargin_FMAX_mean
);
924 fMicro_CR
= fMultiply(fSclk
, fMargin_Plat_mean
);
925 fSigma_FMAX
= fMultiply(fSclk
, fMargin_FMAX_sigma
);
926 fSigma_CR
= fMultiply(fSclk
, fMargin_Plat_sigma
);
928 fSquared_Sigma_DC
= fGetSquare(fSigma_DC
);
929 fSquared_Sigma_CR
= fGetSquare(fSigma_CR
);
930 fSquared_Sigma_FMAX
= fGetSquare(fSigma_FMAX
);
932 fSclk_margin
= fAdd(fMicro_FMAX
,
935 fSqrt(fAdd(fSquared_Sigma_FMAX
,
936 fAdd(fSquared_Sigma_DC
, fSquared_Sigma_CR
))))));
938 fA_Term = fSM_A4 * (fSclk + fSclk_margin) + fSM_A5;
939 fB_Term = fSM_A2 * (fSclk + fSclk_margin) + fSM_A6;
940 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;
943 fA_Term
= fAdd(fMultiply(fSM_A4
, fAdd(fSclk
, fSclk_margin
)), fSM_A5
);
944 fB_Term
= fAdd(fMultiply(fSM_A2
, fAdd(fSclk
, fSclk_margin
)), fSM_A6
);
945 fC_Term
= fAdd(fRO_DC_margin
,
946 fAdd(fMultiply(fSM_A0
, fLkg_FT
),
947 fAdd(fMultiply(fMultiply(fSM_A1
, fLkg_FT
),
948 fAdd(fSclk
, fSclk_margin
)),
949 fAdd(fMultiply(fSM_A3
,
950 fAdd(fSclk
, fSclk_margin
)),
951 fSubtract(fSM_A7
, fRO_fused
)))));
953 SolveQuadracticEqn(fA_Term
, fB_Term
, fC_Term
, fRoots
);
955 if (GreaterThan(fRoots
[0], fRoots
[1]))
960 if (GreaterThan(fV_min
, fEVV_V
))
962 else if (GreaterThan(fEVV_V
, fV_max
))
963 fEVV_V
= fSubtract(fV_max
, fStepSize
);
965 fEVV_V
= fRoundUpByStepSize(fEVV_V
, fStepSize
, 0);
974 while (GreaterThan(fAdd(fV_max
, fStepSize
), fV_x
)) {
975 fTDP_Power_left
= fMultiply(fMultiply(fMultiply(fAdd(
976 fMultiply(fCACm_fused
, fV_x
), fCACb_fused
), fSclk
),
977 fGetSquare(fV_x
)), fDerateTDP
);
979 fTDP_Power_right
= fMultiply(fFT_Lkg_V0NORM
, fMultiply(fLKG_Factor
,
980 fMultiply(fExponential(fMultiply(fAdd(fMultiply(fKv_m_fused
,
981 fT_prod
), fKv_b_fused
), fV_x
)), fV_x
)));
982 fTDP_Power_right
= fMultiply(fTDP_Power_right
, fExponential(fMultiply(
983 fKt_Beta_fused
, fT_prod
)));
984 fTDP_Power_right
= fDivide(fTDP_Power_right
, fExponential(fMultiply(
985 fAdd(fMultiply(fKv_m_fused
, fT_prod
), fKv_b_fused
), fV_FT
)));
986 fTDP_Power_right
= fDivide(fTDP_Power_right
, fExponential(fMultiply(
987 fKt_Beta_fused
, fT_FT
)));
989 fTDP_Power
= fAdd(fTDP_Power_left
, fTDP_Power_right
);
991 fTDP_Current
= fDivide(fTDP_Power
, fV_x
);
993 fV_NL
= fAdd(fV_x
, fDivide(fMultiply(fTDP_Current
, fRLL_LoadLine
),
994 ConvertToFraction(10)));
996 fV_NL
= fRoundUpByStepSize(fV_NL
, fStepSize
, 0);
998 if (GreaterThan(fV_max
, fV_NL
) &&
999 (GreaterThan(fV_NL
,fEVV_V
) ||
1000 Equal(fV_NL
, fEVV_V
))) {
1001 fV_NL
= fMultiply(fV_NL
, ConvertToFraction(1000));
1003 *voltage
= (uint16_t)fV_NL
.partial
.real
;
1006 fV_x
= fAdd(fV_x
, fStepSize
);
1012 /** atomctrl_get_voltage_evv_on_sclk gets voltage via call to ATOM COMMAND table.
1013 * @param hwmgr input: pointer to hwManager
1014 * @param voltage_type input: type of EVV voltage VDDC or VDDGFX
1015 * @param sclk input: in 10Khz unit. DPM state SCLK frequency
1016 * which is define in PPTable SCLK/VDDC dependence
1017 * table associated with this virtual_voltage_Id
1018 * @param virtual_voltage_Id input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08
1019 * @param voltage output: real voltage level in unit of mv
1021 int atomctrl_get_voltage_evv_on_sclk(
1022 struct pp_hwmgr
*hwmgr
,
1023 uint8_t voltage_type
,
1024 uint32_t sclk
, uint16_t virtual_voltage_Id
,
1028 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space
;
1030 get_voltage_info_param_space
.ucVoltageType
=
1032 get_voltage_info_param_space
.ucVoltageMode
=
1033 ATOM_GET_VOLTAGE_EVV_VOLTAGE
;
1034 get_voltage_info_param_space
.usVoltageLevel
=
1036 get_voltage_info_param_space
.ulSCLKFreq
=
1039 result
= cgs_atom_exec_cmd_table(hwmgr
->device
,
1040 GetIndexIntoMasterTable(COMMAND
, GetVoltageInfo
),
1041 &get_voltage_info_param_space
);
1046 *voltage
= ((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2
*)
1047 (&get_voltage_info_param_space
))->usVoltageLevel
;
1053 * Get the mpll reference clock in 10KHz
1055 uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr
*hwmgr
)
1057 ATOM_COMMON_TABLE_HEADER
*fw_info
;
1062 fw_info
= (ATOM_COMMON_TABLE_HEADER
*)
1063 cgs_atom_get_data_table(hwmgr
->device
,
1064 GetIndexIntoMasterTable(DATA
, FirmwareInfo
),
1065 &size
, &frev
, &crev
);
1067 if (fw_info
== NULL
)
1070 if ((fw_info
->ucTableFormatRevision
== 2) &&
1071 (le16_to_cpu(fw_info
->usStructureSize
) >= sizeof(ATOM_FIRMWARE_INFO_V2_1
))) {
1072 ATOM_FIRMWARE_INFO_V2_1
*fwInfo_2_1
=
1073 (ATOM_FIRMWARE_INFO_V2_1
*)fw_info
;
1074 clock
= (uint32_t)(le16_to_cpu(fwInfo_2_1
->usMemoryReferenceClock
));
1076 ATOM_FIRMWARE_INFO
*fwInfo_0_0
=
1077 (ATOM_FIRMWARE_INFO
*)fw_info
;
1078 clock
= (uint32_t)(le16_to_cpu(fwInfo_0_0
->usReferenceClock
));
1086 * Get the asic internal spread spectrum table
1088 static ATOM_ASIC_INTERNAL_SS_INFO
*asic_internal_ss_get_ss_table(void *device
)
1090 ATOM_ASIC_INTERNAL_SS_INFO
*table
= NULL
;
1094 table
= (ATOM_ASIC_INTERNAL_SS_INFO
*)
1095 cgs_atom_get_data_table(device
,
1096 GetIndexIntoMasterTable(DATA
, ASIC_InternalSS_Info
),
1097 &size
, &frev
, &crev
);
1103 * Get the asic internal spread spectrum assignment
1105 static int asic_internal_ss_get_ss_asignment(struct pp_hwmgr
*hwmgr
,
1106 const uint8_t clockSource
,
1107 const uint32_t clockSpeed
,
1108 pp_atomctrl_internal_ss_info
*ssEntry
)
1110 ATOM_ASIC_INTERNAL_SS_INFO
*table
;
1111 ATOM_ASIC_SS_ASSIGNMENT
*ssInfo
;
1112 int entry_found
= 0;
1114 memset(ssEntry
, 0x00, sizeof(pp_atomctrl_internal_ss_info
));
1116 table
= asic_internal_ss_get_ss_table(hwmgr
->device
);
1121 ssInfo
= &table
->asSpreadSpectrum
[0];
1123 while (((uint8_t *)ssInfo
- (uint8_t *)table
) <
1124 le16_to_cpu(table
->sHeader
.usStructureSize
)) {
1125 if ((clockSource
== ssInfo
->ucClockIndication
) &&
1126 ((uint32_t)clockSpeed
<= le32_to_cpu(ssInfo
->ulTargetClockRange
))) {
1131 ssInfo
= (ATOM_ASIC_SS_ASSIGNMENT
*)((uint8_t *)ssInfo
+
1132 sizeof(ATOM_ASIC_SS_ASSIGNMENT
));
1136 ssEntry
->speed_spectrum_percentage
=
1137 ssInfo
->usSpreadSpectrumPercentage
;
1138 ssEntry
->speed_spectrum_rate
= ssInfo
->usSpreadRateInKhz
;
1140 if (((GET_DATA_TABLE_MAJOR_REVISION(table
) == 2) &&
1141 (GET_DATA_TABLE_MINOR_REVISION(table
) >= 2)) ||
1142 (GET_DATA_TABLE_MAJOR_REVISION(table
) == 3)) {
1143 ssEntry
->speed_spectrum_rate
/= 100;
1146 switch (ssInfo
->ucSpreadSpectrumMode
) {
1148 ssEntry
->speed_spectrum_mode
=
1149 pp_atomctrl_spread_spectrum_mode_down
;
1152 ssEntry
->speed_spectrum_mode
=
1153 pp_atomctrl_spread_spectrum_mode_center
;
1156 ssEntry
->speed_spectrum_mode
=
1157 pp_atomctrl_spread_spectrum_mode_down
;
1162 return entry_found
? 0 : 1;
1166 * Get the memory clock spread spectrum info
1168 int atomctrl_get_memory_clock_spread_spectrum(
1169 struct pp_hwmgr
*hwmgr
,
1170 const uint32_t memory_clock
,
1171 pp_atomctrl_internal_ss_info
*ssInfo
)
1173 return asic_internal_ss_get_ss_asignment(hwmgr
,
1174 ASIC_INTERNAL_MEMORY_SS
, memory_clock
, ssInfo
);
1177 * Get the engine clock spread spectrum info
1179 int atomctrl_get_engine_clock_spread_spectrum(
1180 struct pp_hwmgr
*hwmgr
,
1181 const uint32_t engine_clock
,
1182 pp_atomctrl_internal_ss_info
*ssInfo
)
1184 return asic_internal_ss_get_ss_asignment(hwmgr
,
1185 ASIC_INTERNAL_ENGINE_SS
, engine_clock
, ssInfo
);
1188 int atomctrl_read_efuse(void *device
, uint16_t start_index
,
1189 uint16_t end_index
, uint32_t mask
, uint32_t *efuse
)
1192 READ_EFUSE_VALUE_PARAMETER efuse_param
;
1194 efuse_param
.sEfuse
.usEfuseIndex
= (start_index
/ 32) * 4;
1195 efuse_param
.sEfuse
.ucBitShift
= (uint8_t)
1196 (start_index
- ((start_index
/ 32) * 32));
1197 efuse_param
.sEfuse
.ucBitLength
= (uint8_t)
1198 ((end_index
- start_index
) + 1);
1200 result
= cgs_atom_exec_cmd_table(device
,
1201 GetIndexIntoMasterTable(COMMAND
, ReadEfuseValue
),
1204 *efuse
= efuse_param
.ulEfuseValue
& mask
;