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"
32 int hwmgr_init(struct amd_pp_init
*pp_init
, struct pp_instance
*handle
)
34 struct pp_hwmgr
*hwmgr
;
36 if ((handle
== NULL
) || (pp_init
== NULL
))
39 hwmgr
= kzalloc(sizeof(struct pp_hwmgr
), GFP_KERNEL
);
43 handle
->hwmgr
= hwmgr
;
44 hwmgr
->smumgr
= handle
->smu_mgr
;
45 hwmgr
->device
= pp_init
->device
;
46 hwmgr
->chip_family
= pp_init
->chip_family
;
47 hwmgr
->chip_id
= pp_init
->chip_id
;
48 hwmgr
->hw_revision
= pp_init
->rev_id
;
49 hwmgr
->usec_timeout
= AMD_MAX_USEC_TIMEOUT
;
50 hwmgr
->power_source
= PP_PowerSource_AC
;
52 switch (hwmgr
->chip_family
) {
60 phm_init_dynamic_caps(hwmgr
);
65 int hwmgr_fini(struct pp_hwmgr
*hwmgr
)
67 if (hwmgr
== NULL
|| hwmgr
->ps
== NULL
)
75 int hw_init_power_state_table(struct pp_hwmgr
*hwmgr
)
79 unsigned int table_entries
;
80 struct pp_power_state
*state
;
83 if (hwmgr
->hwmgr_func
->get_num_of_pp_table_entries
== NULL
)
86 if (hwmgr
->hwmgr_func
->get_power_state_size
== NULL
)
89 hwmgr
->num_ps
= table_entries
= hwmgr
->hwmgr_func
->get_num_of_pp_table_entries(hwmgr
);
91 hwmgr
->ps_size
= size
= hwmgr
->hwmgr_func
->get_power_state_size(hwmgr
) +
92 sizeof(struct pp_power_state
);
94 hwmgr
->ps
= kzalloc(size
* table_entries
, GFP_KERNEL
);
98 for (i
= 0; i
< table_entries
; i
++) {
99 result
= hwmgr
->hwmgr_func
->get_pp_table_entry(hwmgr
, i
, state
);
100 if (state
->classification
.flags
& PP_StateClassificationFlag_Boot
) {
101 hwmgr
->boot_ps
= state
;
102 hwmgr
->current_ps
= hwmgr
->request_ps
= state
;
105 state
->id
= i
+ 1; /* assigned unique num for every power state id */
107 if (state
->classification
.flags
& PP_StateClassificationFlag_Uvd
)
108 hwmgr
->uvd_ps
= state
;
109 state
= (struct pp_power_state
*)((uint64_t)state
+ size
);
117 * Returns once the part of the register indicated by the mask has
118 * reached the given value.
120 int phm_wait_on_register(struct pp_hwmgr
*hwmgr
, uint32_t index
,
121 uint32_t value
, uint32_t mask
)
126 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
127 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
131 for (i
= 0; i
< hwmgr
->usec_timeout
; i
++) {
132 cur_value
= cgs_read_register(hwmgr
->device
, index
);
133 if ((cur_value
& mask
) == (value
& mask
))
138 /* timeout means wrong logic*/
139 if (i
== hwmgr
->usec_timeout
)
144 int phm_wait_for_register_unequal(struct pp_hwmgr
*hwmgr
,
145 uint32_t index
, uint32_t value
, uint32_t mask
)
150 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
151 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
155 for (i
= 0; i
< hwmgr
->usec_timeout
; i
++) {
156 cur_value
= cgs_read_register(hwmgr
->device
, index
);
157 if ((cur_value
& mask
) != (value
& mask
))
162 /* timeout means wrong logic*/
163 if (i
== hwmgr
->usec_timeout
)
170 * Returns once the part of the register indicated by the mask has
171 * reached the given value.The indirect space is described by giving
172 * the memory-mapped index of the indirect index register.
174 void phm_wait_on_indirect_register(struct pp_hwmgr
*hwmgr
,
175 uint32_t indirect_port
,
180 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
181 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
185 cgs_write_register(hwmgr
->device
, indirect_port
, index
);
186 phm_wait_on_register(hwmgr
, indirect_port
+ 1, mask
, value
);
189 void phm_wait_for_indirect_register_unequal(struct pp_hwmgr
*hwmgr
,
190 uint32_t indirect_port
,
195 if (hwmgr
== NULL
|| hwmgr
->device
== NULL
) {
196 printk(KERN_ERR
"[ powerplay ] Invalid Hardware Manager!");
200 cgs_write_register(hwmgr
->device
, indirect_port
, index
);
201 phm_wait_for_register_unequal(hwmgr
, indirect_port
+ 1,
205 bool phm_cf_want_uvd_power_gating(struct pp_hwmgr
*hwmgr
)
207 return phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_UVDPowerGating
);
210 bool phm_cf_want_vce_power_gating(struct pp_hwmgr
*hwmgr
)
212 return phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_VCEPowerGating
);