2 * Copyright 2016 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.
24 #include "ppatomfwctrl.h"
25 #include "atomfirmware.h"
29 static const union atom_voltage_object_v4
*pp_atomfwctrl_lookup_voltage_type_v4(
30 const struct atom_voltage_objects_info_v4_1
*voltage_object_info_table
,
31 uint8_t voltage_type
, uint8_t voltage_mode
)
33 unsigned int size
= le16_to_cpu(
34 voltage_object_info_table
->table_header
.structuresize
);
36 offsetof(struct atom_voltage_objects_info_v4_1
, voltage_object
[0]);
37 unsigned long start
= (unsigned long)voltage_object_info_table
;
39 while (offset
< size
) {
40 const union atom_voltage_object_v4
*voltage_object
=
41 (const union atom_voltage_object_v4
*)(start
+ offset
);
43 if (voltage_type
== voltage_object
->gpio_voltage_obj
.header
.voltage_type
&&
44 voltage_mode
== voltage_object
->gpio_voltage_obj
.header
.voltage_mode
)
45 return voltage_object
;
47 offset
+= le16_to_cpu(voltage_object
->gpio_voltage_obj
.header
.object_size
);
54 static struct atom_voltage_objects_info_v4_1
*pp_atomfwctrl_get_voltage_info_table(
55 struct pp_hwmgr
*hwmgr
)
57 const void *table_address
;
60 idx
= GetIndexIntoMasterDataTable(voltageobject_info
);
61 table_address
= cgs_atom_get_data_table(hwmgr
->device
,
62 idx
, NULL
, NULL
, NULL
);
66 "Error retrieving BIOS Table Address!",
69 return (struct atom_voltage_objects_info_v4_1
*)table_address
;
73 * Returns TRUE if the given voltage type is controlled by GPIO pins.
74 * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC, SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ.
75 * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE
77 bool pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(struct pp_hwmgr
*hwmgr
,
78 uint8_t voltage_type
, uint8_t voltage_mode
)
80 struct atom_voltage_objects_info_v4_1
*voltage_info
=
81 (struct atom_voltage_objects_info_v4_1
*)
82 pp_atomfwctrl_get_voltage_info_table(hwmgr
);
85 /* If we cannot find the table do NOT try to control this voltage. */
86 PP_ASSERT_WITH_CODE(voltage_info
,
87 "Could not find Voltage Table in BIOS.",
90 ret
= (pp_atomfwctrl_lookup_voltage_type_v4(voltage_info
,
91 voltage_type
, voltage_mode
)) ? true : false;
96 int pp_atomfwctrl_get_voltage_table_v4(struct pp_hwmgr
*hwmgr
,
97 uint8_t voltage_type
, uint8_t voltage_mode
,
98 struct pp_atomfwctrl_voltage_table
*voltage_table
)
100 struct atom_voltage_objects_info_v4_1
*voltage_info
=
101 (struct atom_voltage_objects_info_v4_1
*)
102 pp_atomfwctrl_get_voltage_info_table(hwmgr
);
103 const union atom_voltage_object_v4
*voltage_object
;
107 PP_ASSERT_WITH_CODE(voltage_info
,
108 "Could not find Voltage Table in BIOS.",
111 voltage_object
= pp_atomfwctrl_lookup_voltage_type_v4(voltage_info
,
112 voltage_type
, voltage_mode
);
117 voltage_table
->count
= 0;
118 if (voltage_mode
== VOLTAGE_OBJ_GPIO_LUT
) {
120 (voltage_object
->gpio_voltage_obj
.gpio_entry_num
<=
121 PP_ATOMFWCTRL_MAX_VOLTAGE_ENTRIES
),
122 "Too many voltage entries!",
126 for (i
= 0; i
< voltage_object
->gpio_voltage_obj
.
127 gpio_entry_num
; i
++) {
128 voltage_table
->entries
[i
].value
=
129 le16_to_cpu(voltage_object
->gpio_voltage_obj
.
130 voltage_gpio_lut
[i
].voltage_level_mv
);
131 voltage_table
->entries
[i
].smio_low
=
132 le32_to_cpu(voltage_object
->gpio_voltage_obj
.
133 voltage_gpio_lut
[i
].voltage_gpio_reg_val
);
135 voltage_table
->count
=
136 voltage_object
->gpio_voltage_obj
.gpio_entry_num
;
137 voltage_table
->mask_low
=
139 voltage_object
->gpio_voltage_obj
.gpio_mask_val
);
140 voltage_table
->phase_delay
=
141 voltage_object
->gpio_voltage_obj
.phase_delay_us
;
143 } else if (voltage_mode
== VOLTAGE_OBJ_SVID2
) {
144 voltage_table
->psi1_enable
=
145 voltage_object
->svid2_voltage_obj
.loadline_psi1
& 0x1;
146 voltage_table
->psi0_enable
=
147 voltage_object
->svid2_voltage_obj
.psi0_enable
& 0x1;
148 voltage_table
->max_vid_step
=
149 voltage_object
->svid2_voltage_obj
.maxvstep
;
150 voltage_table
->telemetry_offset
=
151 voltage_object
->svid2_voltage_obj
.telemetry_offset
;
152 voltage_table
->telemetry_slope
=
153 voltage_object
->svid2_voltage_obj
.telemetry_gain
;
155 PP_ASSERT_WITH_CODE(false,
156 "Unsupported Voltage Object Mode!",
163 static struct atom_gpio_pin_lut_v2_1
*pp_atomfwctrl_get_gpio_lookup_table(
164 struct pp_hwmgr
*hwmgr
)
166 const void *table_address
;
169 idx
= GetIndexIntoMasterDataTable(gpio_pin_lut
);
170 table_address
= cgs_atom_get_data_table(hwmgr
->device
,
171 idx
, NULL
, NULL
, NULL
);
172 PP_ASSERT_WITH_CODE(table_address
,
173 "Error retrieving BIOS Table Address!",
176 return (struct atom_gpio_pin_lut_v2_1
*)table_address
;
179 static bool pp_atomfwctrl_lookup_gpio_pin(
180 struct atom_gpio_pin_lut_v2_1
*gpio_lookup_table
,
181 const uint32_t pin_id
,
182 struct pp_atomfwctrl_gpio_pin_assignment
*gpio_pin_assignment
)
184 unsigned int size
= le16_to_cpu(
185 gpio_lookup_table
->table_header
.structuresize
);
186 unsigned int offset
=
187 offsetof(struct atom_gpio_pin_lut_v2_1
, gpio_pin
[0]);
188 unsigned long start
= (unsigned long)gpio_lookup_table
;
190 while (offset
< size
) {
191 const struct atom_gpio_pin_assignment
*pin_assignment
=
192 (const struct atom_gpio_pin_assignment
*)(start
+ offset
);
194 if (pin_id
== pin_assignment
->gpio_id
) {
195 gpio_pin_assignment
->uc_gpio_pin_bit_shift
=
196 pin_assignment
->gpio_bitshift
;
197 gpio_pin_assignment
->us_gpio_pin_aindex
=
198 le16_to_cpu(pin_assignment
->data_a_reg_index
);
201 offset
+= offsetof(struct atom_gpio_pin_assignment
, gpio_id
) + 1;
207 * Returns TRUE if the given pin id find in lookup table.
209 bool pp_atomfwctrl_get_pp_assign_pin(struct pp_hwmgr
*hwmgr
,
210 const uint32_t pin_id
,
211 struct pp_atomfwctrl_gpio_pin_assignment
*gpio_pin_assignment
)
214 struct atom_gpio_pin_lut_v2_1
*gpio_lookup_table
=
215 pp_atomfwctrl_get_gpio_lookup_table(hwmgr
);
217 /* If we cannot find the table do NOT try to control this voltage. */
218 PP_ASSERT_WITH_CODE(gpio_lookup_table
,
219 "Could not find GPIO lookup Table in BIOS.",
222 ret
= pp_atomfwctrl_lookup_gpio_pin(gpio_lookup_table
,
223 pin_id
, gpio_pin_assignment
);
229 * Enter to SelfRefresh mode.
232 int pp_atomfwctrl_enter_self_refresh(struct pp_hwmgr
*hwmgr
)
235 * 1 - leave power to video memory always on
240 /** pp_atomfwctrl_get_gpu_pll_dividers_vega10().
242 * @param hwmgr input parameter: pointer to HwMgr
243 * @param clock_type input parameter: Clock type: 1 - GFXCLK, 2 - UCLK, 0 - All other clocks
244 * @param clock_value input parameter: Clock
245 * @param dividers output parameter:Clock dividers
247 int pp_atomfwctrl_get_gpu_pll_dividers_vega10(struct pp_hwmgr
*hwmgr
,
248 uint32_t clock_type
, uint32_t clock_value
,
249 struct pp_atomfwctrl_clock_dividers_soc15
*dividers
)
251 struct compute_gpu_clock_input_parameter_v1_8 pll_parameters
;
252 struct compute_gpu_clock_output_parameter_v1_8
*pll_output
;
256 pll_parameters
.gpuclock_10khz
= (uint32_t)clock_value
;
257 pll_parameters
.gpu_clock_type
= clock_type
;
259 idx
= GetIndexIntoMasterCmdTable(computegpuclockparam
);
260 result
= cgs_atom_exec_cmd_table(hwmgr
->device
, idx
, &pll_parameters
);
263 pll_output
= (struct compute_gpu_clock_output_parameter_v1_8
*)
265 dividers
->ulClock
= le32_to_cpu(pll_output
->gpuclock_10khz
);
266 dividers
->ulDid
= le32_to_cpu(pll_output
->dfs_did
);
267 dividers
->ulPll_fb_mult
= le32_to_cpu(pll_output
->pll_fb_mult
);
268 dividers
->ulPll_ss_fbsmult
= le32_to_cpu(pll_output
->pll_ss_fbsmult
);
269 dividers
->usPll_ss_slew_frac
= le16_to_cpu(pll_output
->pll_ss_slew_frac
);
270 dividers
->ucPll_ss_enable
= pll_output
->pll_ss_enable
;
275 int pp_atomfwctrl_get_avfs_information(struct pp_hwmgr
*hwmgr
,
276 struct pp_atomfwctrl_avfs_parameters
*param
)
279 struct atom_asic_profiling_info_v4_1
*profile
;
281 idx
= GetIndexIntoMasterDataTable(asic_profiling_info
);
282 profile
= (struct atom_asic_profiling_info_v4_1
*)
283 cgs_atom_get_data_table(hwmgr
->device
,
284 idx
, NULL
, NULL
, NULL
);
289 param
->ulMaxVddc
= le32_to_cpu(profile
->maxvddc
);
290 param
->ulMinVddc
= le32_to_cpu(profile
->minvddc
);
291 param
->ulMeanNsigmaAcontant0
=
292 le32_to_cpu(profile
->avfs_meannsigma_acontant0
);
293 param
->ulMeanNsigmaAcontant1
=
294 le32_to_cpu(profile
->avfs_meannsigma_acontant1
);
295 param
->ulMeanNsigmaAcontant2
=
296 le32_to_cpu(profile
->avfs_meannsigma_acontant2
);
297 param
->usMeanNsigmaDcTolSigma
=
298 le16_to_cpu(profile
->avfs_meannsigma_dc_tol_sigma
);
299 param
->usMeanNsigmaPlatformMean
=
300 le16_to_cpu(profile
->avfs_meannsigma_platform_mean
);
301 param
->usMeanNsigmaPlatformSigma
=
302 le16_to_cpu(profile
->avfs_meannsigma_platform_sigma
);
303 param
->ulGbVdroopTableCksoffA0
=
304 le32_to_cpu(profile
->gb_vdroop_table_cksoff_a0
);
305 param
->ulGbVdroopTableCksoffA1
=
306 le32_to_cpu(profile
->gb_vdroop_table_cksoff_a1
);
307 param
->ulGbVdroopTableCksoffA2
=
308 le32_to_cpu(profile
->gb_vdroop_table_cksoff_a2
);
309 param
->ulGbVdroopTableCksonA0
=
310 le32_to_cpu(profile
->gb_vdroop_table_ckson_a0
);
311 param
->ulGbVdroopTableCksonA1
=
312 le32_to_cpu(profile
->gb_vdroop_table_ckson_a1
);
313 param
->ulGbVdroopTableCksonA2
=
314 le32_to_cpu(profile
->gb_vdroop_table_ckson_a2
);
315 param
->ulGbFuseTableCksoffM1
=
316 le32_to_cpu(profile
->avfsgb_fuse_table_cksoff_m1
);
317 param
->ulGbFuseTableCksoffM2
=
318 le32_to_cpu(profile
->avfsgb_fuse_table_cksoff_m2
);
319 param
->ulGbFuseTableCksoffB
=
320 le32_to_cpu(profile
->avfsgb_fuse_table_cksoff_b
);
321 param
->ulGbFuseTableCksonM1
=
322 le32_to_cpu(profile
->avfsgb_fuse_table_ckson_m1
);
323 param
->ulGbFuseTableCksonM2
=
324 le32_to_cpu(profile
->avfsgb_fuse_table_ckson_m2
);
325 param
->ulGbFuseTableCksonB
=
326 le32_to_cpu(profile
->avfsgb_fuse_table_ckson_b
);
328 param
->ucEnableGbVdroopTableCkson
=
329 profile
->enable_gb_vdroop_table_ckson
;
330 param
->ucEnableGbFuseTableCkson
=
331 profile
->enable_gb_fuse_table_ckson
;
332 param
->usPsmAgeComfactor
=
333 le16_to_cpu(profile
->psm_age_comfactor
);
335 param
->ulDispclk2GfxclkM1
=
336 le32_to_cpu(profile
->dispclk2gfxclk_a
);
337 param
->ulDispclk2GfxclkM2
=
338 le32_to_cpu(profile
->dispclk2gfxclk_b
);
339 param
->ulDispclk2GfxclkB
=
340 le32_to_cpu(profile
->dispclk2gfxclk_c
);
341 param
->ulDcefclk2GfxclkM1
=
342 le32_to_cpu(profile
->dcefclk2gfxclk_a
);
343 param
->ulDcefclk2GfxclkM2
=
344 le32_to_cpu(profile
->dcefclk2gfxclk_b
);
345 param
->ulDcefclk2GfxclkB
=
346 le32_to_cpu(profile
->dcefclk2gfxclk_c
);
347 param
->ulPixelclk2GfxclkM1
=
348 le32_to_cpu(profile
->pixclk2gfxclk_a
);
349 param
->ulPixelclk2GfxclkM2
=
350 le32_to_cpu(profile
->pixclk2gfxclk_b
);
351 param
->ulPixelclk2GfxclkB
=
352 le32_to_cpu(profile
->pixclk2gfxclk_c
);
353 param
->ulPhyclk2GfxclkM1
=
354 le32_to_cpu(profile
->phyclk2gfxclk_a
);
355 param
->ulPhyclk2GfxclkM2
=
356 le32_to_cpu(profile
->phyclk2gfxclk_b
);
357 param
->ulPhyclk2GfxclkB
=
358 le32_to_cpu(profile
->phyclk2gfxclk_c
);
363 int pp_atomfwctrl_get_gpio_information(struct pp_hwmgr
*hwmgr
,
364 struct pp_atomfwctrl_gpio_parameters
*param
)
366 struct atom_smu_info_v3_1
*info
;
369 idx
= GetIndexIntoMasterDataTable(smu_info
);
370 info
= (struct atom_smu_info_v3_1
*)
371 cgs_atom_get_data_table(hwmgr
->device
,
372 idx
, NULL
, NULL
, NULL
);
375 pr_info("Error retrieving BIOS smu_info Table Address!");
379 param
->ucAcDcGpio
= info
->ac_dc_gpio_bit
;
380 param
->ucAcDcPolarity
= info
->ac_dc_polarity
;
381 param
->ucVR0HotGpio
= info
->vr0hot_gpio_bit
;
382 param
->ucVR0HotPolarity
= info
->vr0hot_polarity
;
383 param
->ucVR1HotGpio
= info
->vr1hot_gpio_bit
;
384 param
->ucVR1HotPolarity
= info
->vr1hot_polarity
;
385 param
->ucFwCtfGpio
= info
->fw_ctf_gpio_bit
;
386 param
->ucFwCtfPolarity
= info
->fw_ctf_polarity
;
391 int pp_atomfwctrl__get_clk_information_by_clkid(struct pp_hwmgr
*hwmgr
, BIOS_CLKID id
, uint32_t *frequency
)
393 struct atom_get_smu_clock_info_parameters_v3_1 parameters
;
394 struct atom_get_smu_clock_info_output_parameters_v3_1
*output
;
397 parameters
.clk_id
= id
;
398 parameters
.command
= GET_SMU_CLOCK_INFO_V3_1_GET_CLOCK_FREQ
;
400 ix
= GetIndexIntoMasterCmdTable(getsmuclockinfo
);
401 if (!cgs_atom_exec_cmd_table(hwmgr
->device
, ix
, ¶meters
)) {
402 output
= (struct atom_get_smu_clock_info_output_parameters_v3_1
*)¶meters
;
403 *frequency
= output
->atom_smu_outputclkfreq
.smu_clock_freq_hz
/ 10000;
405 pr_info("Error execute_table getsmuclockinfo!");
412 int pp_atomfwctrl_get_vbios_bootup_values(struct pp_hwmgr
*hwmgr
,
413 struct pp_atomfwctrl_bios_boot_up_values
*boot_values
)
415 struct atom_firmware_info_v3_1
*info
= NULL
;
417 uint32_t frequency
= 0;
419 ix
= GetIndexIntoMasterDataTable(firmwareinfo
);
420 info
= (struct atom_firmware_info_v3_1
*)
421 cgs_atom_get_data_table(hwmgr
->device
,
422 ix
, NULL
, NULL
, NULL
);
425 pr_info("Error retrieving BIOS firmwareinfo!");
429 boot_values
->ulRevision
= info
->firmware_revision
;
430 boot_values
->ulGfxClk
= info
->bootup_sclk_in10khz
;
431 boot_values
->ulUClk
= info
->bootup_mclk_in10khz
;
432 boot_values
->usVddc
= info
->bootup_vddc_mv
;
433 boot_values
->usVddci
= info
->bootup_vddci_mv
;
434 boot_values
->usMvddc
= info
->bootup_mvddc_mv
;
435 boot_values
->usVddGfx
= info
->bootup_vddgfx_mv
;
436 boot_values
->ulSocClk
= 0;
437 boot_values
->ulDCEFClk
= 0;
439 if (!pp_atomfwctrl__get_clk_information_by_clkid(hwmgr
, SMU9_SYSPLL0_SOCCLK_ID
, &frequency
))
440 boot_values
->ulSocClk
= frequency
;
442 if (!pp_atomfwctrl__get_clk_information_by_clkid(hwmgr
, SMU9_SYSPLL0_DCEFCLK_ID
, &frequency
))
443 boot_values
->ulDCEFClk
= frequency
;