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"
31 #include "tonga_hwmgr.h"
33 int hwmgr_init(struct amd_pp_init
*pp_init
, struct pp_instance
*handle
)
35 struct pp_hwmgr
*hwmgr
;
37 if ((handle
== NULL
) || (pp_init
== NULL
))
40 hwmgr
= kzalloc(sizeof(struct pp_hwmgr
), GFP_KERNEL
);
44 handle
->hwmgr
= hwmgr
;
45 hwmgr
->smumgr
= handle
->smu_mgr
;
46 hwmgr
->device
= pp_init
->device
;
47 hwmgr
->chip_family
= pp_init
->chip_family
;
48 hwmgr
->chip_id
= pp_init
->chip_id
;
49 hwmgr
->hw_revision
= pp_init
->rev_id
;
50 hwmgr
->usec_timeout
= AMD_MAX_USEC_TIMEOUT
;
51 hwmgr
->power_source
= PP_PowerSource_AC
;
53 switch (hwmgr
->chip_family
) {
58 switch (hwmgr
->chip_id
) {
60 tonga_hwmgr_init(hwmgr
);
70 phm_init_dynamic_caps(hwmgr
);
75 int hwmgr_fini(struct pp_hwmgr
*hwmgr
)
77 if (hwmgr
== NULL
|| hwmgr
->ps
== NULL
)
85 int hw_init_power_state_table(struct pp_hwmgr
*hwmgr
)
89 unsigned int table_entries
;
90 struct pp_power_state
*state
;
93 if (hwmgr
->hwmgr_func
->get_num_of_pp_table_entries
== NULL
)
96 if (hwmgr
->hwmgr_func
->get_power_state_size
== NULL
)
99 hwmgr
->num_ps
= table_entries
= hwmgr
->hwmgr_func
->get_num_of_pp_table_entries(hwmgr
);
101 hwmgr
->ps_size
= size
= hwmgr
->hwmgr_func
->get_power_state_size(hwmgr
) +
102 sizeof(struct pp_power_state
);
104 hwmgr
->ps
= kzalloc(size
* table_entries
, GFP_KERNEL
);
108 for (i
= 0; i
< table_entries
; i
++) {
109 result
= hwmgr
->hwmgr_func
->get_pp_table_entry(hwmgr
, i
, state
);
110 if (state
->classification
.flags
& PP_StateClassificationFlag_Boot
) {
111 hwmgr
->boot_ps
= state
;
112 hwmgr
->current_ps
= hwmgr
->request_ps
= state
;
115 state
->id
= i
+ 1; /* assigned unique num for every power state id */
117 if (state
->classification
.flags
& PP_StateClassificationFlag_Uvd
)
118 hwmgr
->uvd_ps
= state
;
119 state
= (struct pp_power_state
*)((uint64_t)state
+ size
);
127 * Returns once the part of the register indicated by the mask has
128 * reached the given value.
130 int phm_wait_on_register(struct pp_hwmgr
*hwmgr
, uint32_t index
,
131 uint32_t value
, uint32_t mask
)
136 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
137 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
141 for (i
= 0; i
< hwmgr
->usec_timeout
; i
++) {
142 cur_value
= cgs_read_register(hwmgr
->device
, index
);
143 if ((cur_value
& mask
) == (value
& mask
))
148 /* timeout means wrong logic*/
149 if (i
== hwmgr
->usec_timeout
)
154 int phm_wait_for_register_unequal(struct pp_hwmgr
*hwmgr
,
155 uint32_t index
, uint32_t value
, uint32_t mask
)
160 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
161 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
165 for (i
= 0; i
< hwmgr
->usec_timeout
; i
++) {
166 cur_value
= cgs_read_register(hwmgr
->device
, index
);
167 if ((cur_value
& mask
) != (value
& mask
))
172 /* timeout means wrong logic*/
173 if (i
== hwmgr
->usec_timeout
)
180 * Returns once the part of the register indicated by the mask has
181 * reached the given value.The indirect space is described by giving
182 * the memory-mapped index of the indirect index register.
184 void phm_wait_on_indirect_register(struct pp_hwmgr
*hwmgr
,
185 uint32_t indirect_port
,
190 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
191 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
195 cgs_write_register(hwmgr
->device
, indirect_port
, index
);
196 phm_wait_on_register(hwmgr
, indirect_port
+ 1, mask
, value
);
199 void phm_wait_for_indirect_register_unequal(struct pp_hwmgr
*hwmgr
,
200 uint32_t indirect_port
,
205 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
206 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
210 cgs_write_register(hwmgr
->device
, indirect_port
, index
);
211 phm_wait_for_register_unequal(hwmgr
, indirect_port
+ 1,
215 bool phm_cf_want_uvd_power_gating(struct pp_hwmgr
*hwmgr
)
217 return phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_UVDPowerGating
);
220 bool phm_cf_want_vce_power_gating(struct pp_hwmgr
*hwmgr
)
222 return phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_VCEPowerGating
);