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"
35 #define VOLTAGE_SCALE 4
37 extern int cz_hwmgr_init(struct pp_hwmgr
*hwmgr
);
38 extern int tonga_hwmgr_init(struct pp_hwmgr
*hwmgr
);
39 extern int fiji_hwmgr_init(struct pp_hwmgr
*hwmgr
);
40 extern int polaris10_hwmgr_init(struct pp_hwmgr
*hwmgr
);
42 int hwmgr_init(struct amd_pp_init
*pp_init
, struct pp_instance
*handle
)
44 struct pp_hwmgr
*hwmgr
;
46 if ((handle
== NULL
) || (pp_init
== NULL
))
49 hwmgr
= kzalloc(sizeof(struct pp_hwmgr
), GFP_KERNEL
);
53 handle
->hwmgr
= hwmgr
;
54 hwmgr
->smumgr
= handle
->smu_mgr
;
55 hwmgr
->device
= pp_init
->device
;
56 hwmgr
->chip_family
= pp_init
->chip_family
;
57 hwmgr
->chip_id
= pp_init
->chip_id
;
58 hwmgr
->hw_revision
= pp_init
->rev_id
;
59 hwmgr
->usec_timeout
= AMD_MAX_USEC_TIMEOUT
;
60 hwmgr
->power_source
= PP_PowerSource_AC
;
62 switch (hwmgr
->chip_family
) {
67 switch (hwmgr
->chip_id
) {
69 tonga_hwmgr_init(hwmgr
);
72 fiji_hwmgr_init(hwmgr
);
76 polaris10_hwmgr_init(hwmgr
);
86 phm_init_dynamic_caps(hwmgr
);
91 int hwmgr_fini(struct pp_hwmgr
*hwmgr
)
93 if (hwmgr
== NULL
|| hwmgr
->ps
== NULL
)
97 kfree(hwmgr
->backend
);
99 kfree(hwmgr
->start_thermal_controller
.function_list
);
101 kfree(hwmgr
->set_temperature_range
.function_list
);
108 int hw_init_power_state_table(struct pp_hwmgr
*hwmgr
)
112 unsigned int table_entries
;
113 struct pp_power_state
*state
;
116 if (hwmgr
->hwmgr_func
->get_num_of_pp_table_entries
== NULL
)
119 if (hwmgr
->hwmgr_func
->get_power_state_size
== NULL
)
122 hwmgr
->num_ps
= table_entries
= hwmgr
->hwmgr_func
->get_num_of_pp_table_entries(hwmgr
);
124 hwmgr
->ps_size
= size
= hwmgr
->hwmgr_func
->get_power_state_size(hwmgr
) +
125 sizeof(struct pp_power_state
);
127 hwmgr
->ps
= kzalloc(size
* table_entries
, GFP_KERNEL
);
129 if (hwmgr
->ps
== NULL
)
134 for (i
= 0; i
< table_entries
; i
++) {
135 result
= hwmgr
->hwmgr_func
->get_pp_table_entry(hwmgr
, i
, state
);
137 if (state
->classification
.flags
& PP_StateClassificationFlag_Boot
) {
138 hwmgr
->boot_ps
= state
;
139 hwmgr
->current_ps
= hwmgr
->request_ps
= state
;
142 state
->id
= i
+ 1; /* assigned unique num for every power state id */
144 if (state
->classification
.flags
& PP_StateClassificationFlag_Uvd
)
145 hwmgr
->uvd_ps
= state
;
146 state
= (struct pp_power_state
*)((unsigned long)state
+ size
);
154 * Returns once the part of the register indicated by the mask has
155 * reached the given value.
157 int phm_wait_on_register(struct pp_hwmgr
*hwmgr
, uint32_t index
,
158 uint32_t value
, uint32_t mask
)
163 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
164 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
168 for (i
= 0; i
< hwmgr
->usec_timeout
; i
++) {
169 cur_value
= cgs_read_register(hwmgr
->device
, index
);
170 if ((cur_value
& mask
) == (value
& mask
))
175 /* timeout means wrong logic*/
176 if (i
== hwmgr
->usec_timeout
)
181 int phm_wait_for_register_unequal(struct pp_hwmgr
*hwmgr
,
182 uint32_t index
, uint32_t value
, uint32_t mask
)
187 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
188 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
192 for (i
= 0; i
< hwmgr
->usec_timeout
; i
++) {
193 cur_value
= cgs_read_register(hwmgr
->device
, index
);
194 if ((cur_value
& mask
) != (value
& mask
))
199 /* timeout means wrong logic*/
200 if (i
== hwmgr
->usec_timeout
)
207 * Returns once the part of the register indicated by the mask has
208 * reached the given value.The indirect space is described by giving
209 * the memory-mapped index of the indirect index register.
211 void phm_wait_on_indirect_register(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_on_register(hwmgr
, indirect_port
+ 1, mask
, value
);
226 void phm_wait_for_indirect_register_unequal(struct pp_hwmgr
*hwmgr
,
227 uint32_t indirect_port
,
232 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
233 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
237 cgs_write_register(hwmgr
->device
, indirect_port
, index
);
238 phm_wait_for_register_unequal(hwmgr
, indirect_port
+ 1,
242 bool phm_cf_want_uvd_power_gating(struct pp_hwmgr
*hwmgr
)
244 return phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_UVDPowerGating
);
247 bool phm_cf_want_vce_power_gating(struct pp_hwmgr
*hwmgr
)
249 return phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_VCEPowerGating
);
253 int phm_trim_voltage_table(struct pp_atomctrl_voltage_table
*vol_table
)
258 struct pp_atomctrl_voltage_table
*table
;
260 PP_ASSERT_WITH_CODE((NULL
!= vol_table
),
261 "Voltage Table empty.", return -EINVAL
);
263 table
= kzalloc(sizeof(struct pp_atomctrl_voltage_table
),
269 table
->mask_low
= vol_table
->mask_low
;
270 table
->phase_delay
= vol_table
->phase_delay
;
272 for (i
= 0; i
< vol_table
->count
; i
++) {
273 vvalue
= vol_table
->entries
[i
].value
;
276 for (j
= 0; j
< table
->count
; j
++) {
277 if (vvalue
== table
->entries
[j
].value
) {
284 table
->entries
[table
->count
].value
= vvalue
;
285 table
->entries
[table
->count
].smio_low
=
286 vol_table
->entries
[i
].smio_low
;
291 memcpy(vol_table
, table
, sizeof(struct pp_atomctrl_voltage_table
));
297 int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table
*vol_table
,
298 phm_ppt_v1_clock_voltage_dependency_table
*dep_table
)
303 PP_ASSERT_WITH_CODE((0 != dep_table
->count
),
304 "Voltage Dependency Table empty.", return -EINVAL
);
306 PP_ASSERT_WITH_CODE((NULL
!= vol_table
),
307 "vol_table empty.", return -EINVAL
);
309 vol_table
->mask_low
= 0;
310 vol_table
->phase_delay
= 0;
311 vol_table
->count
= dep_table
->count
;
313 for (i
= 0; i
< dep_table
->count
; i
++) {
314 vol_table
->entries
[i
].value
= dep_table
->entries
[i
].mvdd
;
315 vol_table
->entries
[i
].smio_low
= 0;
318 result
= phm_trim_voltage_table(vol_table
);
319 PP_ASSERT_WITH_CODE((0 == result
),
320 "Failed to trim MVDD table.", return result
);
325 int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table
*vol_table
,
326 phm_ppt_v1_clock_voltage_dependency_table
*dep_table
)
331 PP_ASSERT_WITH_CODE((0 != dep_table
->count
),
332 "Voltage Dependency Table empty.", return -EINVAL
);
334 PP_ASSERT_WITH_CODE((NULL
!= vol_table
),
335 "vol_table empty.", return -EINVAL
);
337 vol_table
->mask_low
= 0;
338 vol_table
->phase_delay
= 0;
339 vol_table
->count
= dep_table
->count
;
341 for (i
= 0; i
< dep_table
->count
; i
++) {
342 vol_table
->entries
[i
].value
= dep_table
->entries
[i
].vddci
;
343 vol_table
->entries
[i
].smio_low
= 0;
346 result
= phm_trim_voltage_table(vol_table
);
347 PP_ASSERT_WITH_CODE((0 == result
),
348 "Failed to trim VDDCI table.", return result
);
353 int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table
*vol_table
,
354 phm_ppt_v1_voltage_lookup_table
*lookup_table
)
358 PP_ASSERT_WITH_CODE((0 != lookup_table
->count
),
359 "Voltage Lookup Table empty.", return -EINVAL
);
361 PP_ASSERT_WITH_CODE((NULL
!= vol_table
),
362 "vol_table empty.", return -EINVAL
);
364 vol_table
->mask_low
= 0;
365 vol_table
->phase_delay
= 0;
367 vol_table
->count
= lookup_table
->count
;
369 for (i
= 0; i
< vol_table
->count
; i
++) {
370 vol_table
->entries
[i
].value
= lookup_table
->entries
[i
].us_vdd
;
371 vol_table
->entries
[i
].smio_low
= 0;
377 void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps
,
378 struct pp_atomctrl_voltage_table
*vol_table
)
380 unsigned int i
, diff
;
382 if (vol_table
->count
<= max_vol_steps
)
385 diff
= vol_table
->count
- max_vol_steps
;
387 for (i
= 0; i
< max_vol_steps
; i
++)
388 vol_table
->entries
[i
] = vol_table
->entries
[i
+ diff
];
390 vol_table
->count
= max_vol_steps
;
395 int phm_reset_single_dpm_table(void *table
,
396 uint32_t count
, int max
)
400 struct vi_dpm_table
*dpm_table
= (struct vi_dpm_table
*)table
;
402 PP_ASSERT_WITH_CODE(count
<= max
,
403 "Fatal error, can not set up single DPM table entries to exceed max number!",
406 dpm_table
->count
= count
;
407 for (i
= 0; i
< max
; i
++)
408 dpm_table
->dpm_level
[i
].enabled
= false;
413 void phm_setup_pcie_table_entry(
415 uint32_t index
, uint32_t pcie_gen
,
418 struct vi_dpm_table
*dpm_table
= (struct vi_dpm_table
*)table
;
419 dpm_table
->dpm_level
[index
].value
= pcie_gen
;
420 dpm_table
->dpm_level
[index
].param1
= pcie_lanes
;
421 dpm_table
->dpm_level
[index
].enabled
= 1;
424 int32_t phm_get_dpm_level_enable_mask_value(void *table
)
428 struct vi_dpm_table
*dpm_table
= (struct vi_dpm_table
*)table
;
430 for (i
= dpm_table
->count
; i
> 0; i
--) {
432 if (dpm_table
->dpm_level
[i
- 1].enabled
)
441 uint8_t phm_get_voltage_index(
442 struct phm_ppt_v1_voltage_lookup_table
*lookup_table
, uint16_t voltage
)
444 uint8_t count
= (uint8_t) (lookup_table
->count
);
447 PP_ASSERT_WITH_CODE((NULL
!= lookup_table
),
448 "Lookup Table empty.", return 0);
449 PP_ASSERT_WITH_CODE((0 != count
),
450 "Lookup Table empty.", return 0);
452 for (i
= 0; i
< lookup_table
->count
; i
++) {
453 /* find first voltage equal or bigger than requested */
454 if (lookup_table
->entries
[i
].us_vdd
>= voltage
)
457 /* voltage is bigger than max voltage in the table */
461 uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table
*vddci_table
, uint16_t vddci
)
465 for (i
= 0; i
< vddci_table
->count
; i
++) {
466 if (vddci_table
->entries
[i
].value
>= vddci
)
467 return vddci_table
->entries
[i
].value
;
470 PP_ASSERT_WITH_CODE(false,
471 "VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
472 return vddci_table
->entries
[i
-1].value
);
475 int phm_find_boot_level(void *table
,
476 uint32_t value
, uint32_t *boot_level
)
478 int result
= -EINVAL
;
480 struct vi_dpm_table
*dpm_table
= (struct vi_dpm_table
*)table
;
482 for (i
= 0; i
< dpm_table
->count
; i
++) {
483 if (value
== dpm_table
->dpm_level
[i
].value
) {
492 int phm_get_sclk_for_voltage_evv(struct pp_hwmgr
*hwmgr
,
493 phm_ppt_v1_voltage_lookup_table
*lookup_table
,
494 uint16_t virtual_voltage_id
, int32_t *sclk
)
498 struct phm_ppt_v1_information
*table_info
=
499 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
501 PP_ASSERT_WITH_CODE(lookup_table
->count
!= 0, "Lookup table is empty", return -EINVAL
);
503 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
504 for (entryId
= 0; entryId
< table_info
->vdd_dep_on_sclk
->count
; entryId
++) {
505 voltageId
= table_info
->vdd_dep_on_sclk
->entries
[entryId
].vddInd
;
506 if (lookup_table
->entries
[voltageId
].us_vdd
== virtual_voltage_id
)
510 PP_ASSERT_WITH_CODE(entryId
< table_info
->vdd_dep_on_sclk
->count
,
511 "Can't find requested voltage id in vdd_dep_on_sclk table!",
515 *sclk
= table_info
->vdd_dep_on_sclk
->entries
[entryId
].clk
;
521 * Initialize Dynamic State Adjustment Rule Settings
523 * @param hwmgr the address of the powerplay hardware manager.
525 int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr
*hwmgr
)
528 struct phm_clock_voltage_dependency_table
*table_clk_vlt
;
529 struct phm_ppt_v1_information
*pptable_info
= (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
531 /* initialize vddc_dep_on_dal_pwrl table */
532 table_size
= sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record
);
533 table_clk_vlt
= (struct phm_clock_voltage_dependency_table
*)kzalloc(table_size
, GFP_KERNEL
);
535 if (NULL
== table_clk_vlt
) {
536 printk(KERN_ERR
"[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
539 table_clk_vlt
->count
= 4;
540 table_clk_vlt
->entries
[0].clk
= PP_DAL_POWERLEVEL_ULTRALOW
;
541 table_clk_vlt
->entries
[0].v
= 0;
542 table_clk_vlt
->entries
[1].clk
= PP_DAL_POWERLEVEL_LOW
;
543 table_clk_vlt
->entries
[1].v
= 720;
544 table_clk_vlt
->entries
[2].clk
= PP_DAL_POWERLEVEL_NOMINAL
;
545 table_clk_vlt
->entries
[2].v
= 810;
546 table_clk_vlt
->entries
[3].clk
= PP_DAL_POWERLEVEL_PERFORMANCE
;
547 table_clk_vlt
->entries
[3].v
= 900;
548 pptable_info
->vddc_dep_on_dal_pwrl
= table_clk_vlt
;
549 hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
= table_clk_vlt
;
555 int phm_hwmgr_backend_fini(struct pp_hwmgr
*hwmgr
)
557 if (NULL
!= hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
) {
558 kfree(hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
);
559 hwmgr
->dyn_state
.vddc_dep_on_dal_pwrl
= NULL
;
562 if (NULL
!= hwmgr
->backend
) {
563 kfree(hwmgr
->backend
);
564 hwmgr
->backend
= NULL
;
570 uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr
*hwmgr
, uint32_t mask
)
574 while (0 == (mask
& (1 << level
)))
580 void phm_apply_dal_min_voltage_request(struct pp_hwmgr
*hwmgr
)
582 struct phm_ppt_v1_information
*table_info
=
583 (struct phm_ppt_v1_information
*)hwmgr
->pptable
;
584 struct phm_clock_voltage_dependency_table
*table
=
585 table_info
->vddc_dep_on_dal_pwrl
;
586 struct phm_ppt_v1_clock_voltage_dependency_table
*vddc_table
;
587 enum PP_DAL_POWERLEVEL dal_power_level
= hwmgr
->dal_power_level
;
588 uint32_t req_vddc
= 0, req_volt
, i
;
590 if (!table
|| table
->count
<= 0
591 || dal_power_level
< PP_DAL_POWERLEVEL_ULTRALOW
592 || dal_power_level
> PP_DAL_POWERLEVEL_PERFORMANCE
)
595 for (i
= 0; i
< table
->count
; i
++) {
596 if (dal_power_level
== table
->entries
[i
].clk
) {
597 req_vddc
= table
->entries
[i
].v
;
602 vddc_table
= table_info
->vdd_dep_on_sclk
;
603 for (i
= 0; i
< vddc_table
->count
; i
++) {
604 if (req_vddc
<= vddc_table
->entries
[i
].vddc
) {
605 req_volt
= (((uint32_t)vddc_table
->entries
[i
].vddc
) * VOLTAGE_SCALE
);
606 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
607 PPSMC_MSG_VddC_Request
, req_volt
);
611 printk(KERN_ERR
"DAL requested level can not"
612 " found a available voltage in VDDC DPM Table \n");