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/delay.h"
24 #include <linux/types.h>
25 #include <linux/kernel.h>
26 #include <linux/slab.h>
27 #include "cgs_common.h"
28 #include "power_state.h"
30 #include "pppcielanes.h"
32 #include "ppatomctrl.h"
34 extern int cz_hwmgr_init(struct pp_hwmgr
*hwmgr
);
35 extern int tonga_hwmgr_init(struct pp_hwmgr
*hwmgr
);
36 extern int fiji_hwmgr_init(struct pp_hwmgr
*hwmgr
);
38 int hwmgr_init(struct amd_pp_init
*pp_init
, struct pp_instance
*handle
)
40 struct pp_hwmgr
*hwmgr
;
42 if ((handle
== NULL
) || (pp_init
== NULL
))
45 hwmgr
= kzalloc(sizeof(struct pp_hwmgr
), GFP_KERNEL
);
49 handle
->hwmgr
= hwmgr
;
50 hwmgr
->smumgr
= handle
->smu_mgr
;
51 hwmgr
->device
= pp_init
->device
;
52 hwmgr
->chip_family
= pp_init
->chip_family
;
53 hwmgr
->chip_id
= pp_init
->chip_id
;
54 hwmgr
->hw_revision
= pp_init
->rev_id
;
55 hwmgr
->usec_timeout
= AMD_MAX_USEC_TIMEOUT
;
56 hwmgr
->power_source
= PP_PowerSource_AC
;
58 switch (hwmgr
->chip_family
) {
63 switch (hwmgr
->chip_id
) {
65 tonga_hwmgr_init(hwmgr
);
68 fiji_hwmgr_init(hwmgr
);
78 phm_init_dynamic_caps(hwmgr
);
83 int hwmgr_fini(struct pp_hwmgr
*hwmgr
)
85 if (hwmgr
== NULL
|| hwmgr
->ps
== NULL
)
93 int hw_init_power_state_table(struct pp_hwmgr
*hwmgr
)
97 unsigned int table_entries
;
98 struct pp_power_state
*state
;
101 if (hwmgr
->hwmgr_func
->get_num_of_pp_table_entries
== NULL
)
104 if (hwmgr
->hwmgr_func
->get_power_state_size
== NULL
)
107 hwmgr
->num_ps
= table_entries
= hwmgr
->hwmgr_func
->get_num_of_pp_table_entries(hwmgr
);
109 hwmgr
->ps_size
= size
= hwmgr
->hwmgr_func
->get_power_state_size(hwmgr
) +
110 sizeof(struct pp_power_state
);
112 hwmgr
->ps
= kzalloc(size
* table_entries
, GFP_KERNEL
);
114 if (hwmgr
->ps
== NULL
)
119 for (i
= 0; i
< table_entries
; i
++) {
120 result
= hwmgr
->hwmgr_func
->get_pp_table_entry(hwmgr
, i
, state
);
122 if (state
->classification
.flags
& PP_StateClassificationFlag_Boot
) {
123 hwmgr
->boot_ps
= state
;
124 hwmgr
->current_ps
= hwmgr
->request_ps
= state
;
127 state
->id
= i
+ 1; /* assigned unique num for every power state id */
129 if (state
->classification
.flags
& PP_StateClassificationFlag_Uvd
)
130 hwmgr
->uvd_ps
= state
;
131 state
= (struct pp_power_state
*)((unsigned long)state
+ size
);
139 * Returns once the part of the register indicated by the mask has
140 * reached the given value.
142 int phm_wait_on_register(struct pp_hwmgr
*hwmgr
, uint32_t index
,
143 uint32_t value
, uint32_t mask
)
148 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
149 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
153 for (i
= 0; i
< hwmgr
->usec_timeout
; i
++) {
154 cur_value
= cgs_read_register(hwmgr
->device
, index
);
155 if ((cur_value
& mask
) == (value
& mask
))
160 /* timeout means wrong logic*/
161 if (i
== hwmgr
->usec_timeout
)
166 int phm_wait_for_register_unequal(struct pp_hwmgr
*hwmgr
,
167 uint32_t index
, uint32_t value
, uint32_t mask
)
172 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
173 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
177 for (i
= 0; i
< hwmgr
->usec_timeout
; i
++) {
178 cur_value
= cgs_read_register(hwmgr
->device
, index
);
179 if ((cur_value
& mask
) != (value
& mask
))
184 /* timeout means wrong logic*/
185 if (i
== hwmgr
->usec_timeout
)
192 * Returns once the part of the register indicated by the mask has
193 * reached the given value.The indirect space is described by giving
194 * the memory-mapped index of the indirect index register.
196 void phm_wait_on_indirect_register(struct pp_hwmgr
*hwmgr
,
197 uint32_t indirect_port
,
202 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
203 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
207 cgs_write_register(hwmgr
->device
, indirect_port
, index
);
208 phm_wait_on_register(hwmgr
, indirect_port
+ 1, mask
, value
);
211 void phm_wait_for_indirect_register_unequal(struct pp_hwmgr
*hwmgr
,
212 uint32_t indirect_port
,
217 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
218 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
222 cgs_write_register(hwmgr
->device
, indirect_port
, index
);
223 phm_wait_for_register_unequal(hwmgr
, indirect_port
+ 1,
227 bool phm_cf_want_uvd_power_gating(struct pp_hwmgr
*hwmgr
)
229 return phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_UVDPowerGating
);
232 bool phm_cf_want_vce_power_gating(struct pp_hwmgr
*hwmgr
)
234 return phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_VCEPowerGating
);
238 int phm_trim_voltage_table(struct pp_atomctrl_voltage_table
*vol_table
)
243 struct pp_atomctrl_voltage_table
*table
;
245 PP_ASSERT_WITH_CODE((NULL
!= vol_table
),
246 "Voltage Table empty.", return -EINVAL
);
248 table
= kzalloc(sizeof(struct pp_atomctrl_voltage_table
),
254 table
->mask_low
= vol_table
->mask_low
;
255 table
->phase_delay
= vol_table
->phase_delay
;
257 for (i
= 0; i
< vol_table
->count
; i
++) {
258 vvalue
= vol_table
->entries
[i
].value
;
261 for (j
= 0; j
< table
->count
; j
++) {
262 if (vvalue
== table
->entries
[j
].value
) {
269 table
->entries
[table
->count
].value
= vvalue
;
270 table
->entries
[table
->count
].smio_low
=
271 vol_table
->entries
[i
].smio_low
;
276 memcpy(vol_table
, table
, sizeof(struct pp_atomctrl_voltage_table
));
282 int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table
*vol_table
,
283 phm_ppt_v1_clock_voltage_dependency_table
*dep_table
)
288 PP_ASSERT_WITH_CODE((0 != dep_table
->count
),
289 "Voltage Dependency Table empty.", return -EINVAL
);
291 PP_ASSERT_WITH_CODE((NULL
!= vol_table
),
292 "vol_table empty.", return -EINVAL
);
294 vol_table
->mask_low
= 0;
295 vol_table
->phase_delay
= 0;
296 vol_table
->count
= dep_table
->count
;
298 for (i
= 0; i
< dep_table
->count
; i
++) {
299 vol_table
->entries
[i
].value
= dep_table
->entries
[i
].mvdd
;
300 vol_table
->entries
[i
].smio_low
= 0;
303 result
= phm_trim_voltage_table(vol_table
);
304 PP_ASSERT_WITH_CODE((0 == result
),
305 "Failed to trim MVDD table.", return result
);
310 int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table
*vol_table
,
311 phm_ppt_v1_clock_voltage_dependency_table
*dep_table
)
316 PP_ASSERT_WITH_CODE((0 != dep_table
->count
),
317 "Voltage Dependency Table empty.", return -EINVAL
);
319 PP_ASSERT_WITH_CODE((NULL
!= vol_table
),
320 "vol_table empty.", return -EINVAL
);
322 vol_table
->mask_low
= 0;
323 vol_table
->phase_delay
= 0;
324 vol_table
->count
= dep_table
->count
;
326 for (i
= 0; i
< dep_table
->count
; i
++) {
327 vol_table
->entries
[i
].value
= dep_table
->entries
[i
].vddci
;
328 vol_table
->entries
[i
].smio_low
= 0;
331 result
= phm_trim_voltage_table(vol_table
);
332 PP_ASSERT_WITH_CODE((0 == result
),
333 "Failed to trim VDDCI table.", return result
);
338 int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table
*vol_table
,
339 phm_ppt_v1_voltage_lookup_table
*lookup_table
)
343 PP_ASSERT_WITH_CODE((0 != lookup_table
->count
),
344 "Voltage Lookup Table empty.", return -EINVAL
);
346 PP_ASSERT_WITH_CODE((NULL
!= vol_table
),
347 "vol_table empty.", return -EINVAL
);
349 vol_table
->mask_low
= 0;
350 vol_table
->phase_delay
= 0;
352 vol_table
->count
= lookup_table
->count
;
354 for (i
= 0; i
< vol_table
->count
; i
++) {
355 vol_table
->entries
[i
].value
= lookup_table
->entries
[i
].us_vdd
;
356 vol_table
->entries
[i
].smio_low
= 0;
362 void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps
,
363 struct pp_atomctrl_voltage_table
*vol_table
)
365 unsigned int i
, diff
;
367 if (vol_table
->count
<= max_vol_steps
)
370 diff
= vol_table
->count
- max_vol_steps
;
372 for (i
= 0; i
< max_vol_steps
; i
++)
373 vol_table
->entries
[i
] = vol_table
->entries
[i
+ diff
];
375 vol_table
->count
= max_vol_steps
;
380 int phm_reset_single_dpm_table(void *table
,
381 uint32_t count
, int max
)
385 struct vi_dpm_table
*dpm_table
= (struct vi_dpm_table
*)table
;
387 PP_ASSERT_WITH_CODE(count
<= max
,
388 "Fatal error, can not set up single DPM table entries to exceed max number!",
391 dpm_table
->count
= count
;
392 for (i
= 0; i
< max
; i
++)
393 dpm_table
->dpm_level
[i
].enabled
= false;
398 void phm_setup_pcie_table_entry(
400 uint32_t index
, uint32_t pcie_gen
,
403 struct vi_dpm_table
*dpm_table
= (struct vi_dpm_table
*)table
;
404 dpm_table
->dpm_level
[index
].value
= pcie_gen
;
405 dpm_table
->dpm_level
[index
].param1
= pcie_lanes
;
406 dpm_table
->dpm_level
[index
].enabled
= 1;
409 int32_t phm_get_dpm_level_enable_mask_value(void *table
)
413 struct vi_dpm_table
*dpm_table
= (struct vi_dpm_table
*)table
;
415 for (i
= dpm_table
->count
; i
> 0; i
--) {
417 if (dpm_table
->dpm_level
[i
- 1].enabled
)
426 uint8_t phm_get_voltage_index(
427 struct phm_ppt_v1_voltage_lookup_table
*lookup_table
, uint16_t voltage
)
429 uint8_t count
= (uint8_t) (lookup_table
->count
);
432 PP_ASSERT_WITH_CODE((NULL
!= lookup_table
),
433 "Lookup Table empty.", return 0);
434 PP_ASSERT_WITH_CODE((0 != count
),
435 "Lookup Table empty.", return 0);
437 for (i
= 0; i
< lookup_table
->count
; i
++) {
438 /* find first voltage equal or bigger than requested */
439 if (lookup_table
->entries
[i
].us_vdd
>= voltage
)
442 /* voltage is bigger than max voltage in the table */
446 uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table
*vddci_table
, uint16_t vddci
)
450 for (i
= 0; i
< vddci_table
->count
; i
++) {
451 if (vddci_table
->entries
[i
].value
>= vddci
)
452 return vddci_table
->entries
[i
].value
;
455 PP_ASSERT_WITH_CODE(false,
456 "VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
457 return vddci_table
->entries
[i
].value
);
460 int phm_find_boot_level(void *table
,
461 uint32_t value
, uint32_t *boot_level
)
463 int result
= -EINVAL
;
465 struct vi_dpm_table
*dpm_table
= (struct vi_dpm_table
*)table
;
467 for (i
= 0; i
< dpm_table
->count
; i
++) {
468 if (value
== dpm_table
->dpm_level
[i
].value
) {
477 int phm_get_sclk_for_voltage_evv(struct pp_hwmgr
*hwmgr
,
478 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
479 uint16_t virtual_voltage_id
, int32_t *sclk
)
483 struct phm_ppt_v1_information
*table_info
=
484 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
486 PP_ASSERT_WITH_CODE(lookup_table
->count
!= 0, "Lookup table is empty", return -EINVAL
);
488 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
489 for (entryId
= 0; entryId
< table_info
->vdd_dep_on_sclk
->count
; entryId
++) {
490 voltageId
= table_info
->vdd_dep_on_sclk
->entries
[entryId
].vddInd
;
491 if (lookup_table
->entries
[voltageId
].us_vdd
== virtual_voltage_id
)
495 PP_ASSERT_WITH_CODE(entryId
< table_info
->vdd_dep_on_sclk
->count
,
496 "Can't find requested voltage id in vdd_dep_on_sclk table!",
500 *sclk
= table_info
->vdd_dep_on_sclk
->entries
[entryId
].clk
;
506 * Initialize Dynamic State Adjustment Rule Settings
508 * @param hwmgr the address of the powerplay hardware manager.
510 int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr
*hwmgr
)
513 struct phm_clock_voltage_dependency_table
*table_clk_vlt
;
514 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
516 /* initialize vddc_dep_on_dal_pwrl table */
517 table_size
= sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record
);
518 table_clk_vlt
= (struct phm_clock_voltage_dependency_table
*)kzalloc(table_size
, GFP_KERNEL
);
520 if (NULL
== table_clk_vlt
) {
521 printk(KERN_ERR
"[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
524 table_clk_vlt
->count
= 4;
525 table_clk_vlt
->entries
[0].clk
= PP_DAL_POWERLEVEL_ULTRALOW
;
526 table_clk_vlt
->entries
[0].v
= 0;
527 table_clk_vlt
->entries
[1].clk
= PP_DAL_POWERLEVEL_LOW
;
528 table_clk_vlt
->entries
[1].v
= 720;
529 table_clk_vlt
->entries
[2].clk
= PP_DAL_POWERLEVEL_NOMINAL
;
530 table_clk_vlt
->entries
[2].v
= 810;
531 table_clk_vlt
->entries
[3].clk
= PP_DAL_POWERLEVEL_PERFORMANCE
;
532 table_clk_vlt
->entries
[3].v
= 900;
533 pptable_info
->vddc_dep_on_dal_pwrl
= table_clk_vlt
;
534 hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
= table_clk_vlt
;
540 int phm_hwmgr_backend_fini(struct pp_hwmgr
*hwmgr
)
542 if (NULL
!= hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
) {
543 kfree(hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
);
544 hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
= NULL
;
547 if (NULL
!= hwmgr
->backend
) {
548 kfree(hwmgr
->backend
);
549 hwmgr
->backend
= NULL
;
555 uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr
*hwmgr
, uint32_t mask
)
559 while (0 == (mask
& (1 << level
)))