]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
drm/amd/powerplay: add CG and PG support for carrizo
[mirror_ubuntu-zesty-kernel.git] / drivers / gpu / drm / amd / powerplay / hwmgr / hwmgr.c
1 /*
2 * Copyright 2015 Advanced Micro Devices, Inc.
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
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.
21 *
22 */
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"
29 #include "hwmgr.h"
30 #include "cz_hwmgr.h"
31
32 int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
33 {
34 struct pp_hwmgr *hwmgr;
35
36 if ((handle == NULL) || (pp_init == NULL))
37 return -EINVAL;
38
39 hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL);
40 if (hwmgr == NULL)
41 return -ENOMEM;
42
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;
51
52 switch (hwmgr->chip_family) {
53 case AMD_FAMILY_CZ:
54 cz_hwmgr_init(hwmgr);
55 break;
56 default:
57 return -EINVAL;
58 }
59
60 phm_init_dynamic_caps(hwmgr);
61
62 return 0;
63 }
64
65 int hwmgr_fini(struct pp_hwmgr *hwmgr)
66 {
67 if (hwmgr == NULL || hwmgr->ps == NULL)
68 return -EINVAL;
69
70 kfree(hwmgr->ps);
71 kfree(hwmgr);
72 return 0;
73 }
74
75 int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
76 {
77 int result;
78 unsigned int i;
79 unsigned int table_entries;
80 struct pp_power_state *state;
81 int size;
82
83 if (hwmgr->hwmgr_func->get_num_of_pp_table_entries == NULL)
84 return -EINVAL;
85
86 if (hwmgr->hwmgr_func->get_power_state_size == NULL)
87 return -EINVAL;
88
89 hwmgr->num_ps = table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr);
90
91 hwmgr->ps_size = size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) +
92 sizeof(struct pp_power_state);
93
94 hwmgr->ps = kzalloc(size * table_entries, GFP_KERNEL);
95
96 state = hwmgr->ps;
97
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;
103 }
104
105 state->id = i + 1; /* assigned unique num for every power state id */
106
107 if (state->classification.flags & PP_StateClassificationFlag_Uvd)
108 hwmgr->uvd_ps = state;
109 state = (struct pp_power_state *)((uint64_t)state + size);
110 }
111
112 return 0;
113 }
114
115
116 /**
117 * Returns once the part of the register indicated by the mask has
118 * reached the given value.
119 */
120 int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
121 uint32_t value, uint32_t mask)
122 {
123 uint32_t i;
124 uint32_t cur_value;
125
126 if (hwmgr == NULL || hwmgr->device == NULL) {
127 printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
128 return -EINVAL;
129 }
130
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))
134 break;
135 udelay(1);
136 }
137
138 /* timeout means wrong logic*/
139 if (i == hwmgr->usec_timeout)
140 return -1;
141 return 0;
142 }
143
144 int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
145 uint32_t index, uint32_t value, uint32_t mask)
146 {
147 uint32_t i;
148 uint32_t cur_value;
149
150 if (hwmgr == NULL || hwmgr->device == NULL) {
151 printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
152 return -EINVAL;
153 }
154
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))
158 break;
159 udelay(1);
160 }
161
162 /* timeout means wrong logic*/
163 if (i == hwmgr->usec_timeout)
164 return -1;
165 return 0;
166 }
167
168
169 /**
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.
173 */
174 void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
175 uint32_t indirect_port,
176 uint32_t index,
177 uint32_t value,
178 uint32_t mask)
179 {
180 if (hwmgr == NULL || hwmgr->device == NULL) {
181 printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
182 return;
183 }
184
185 cgs_write_register(hwmgr->device, indirect_port, index);
186 phm_wait_on_register(hwmgr, indirect_port + 1, mask, value);
187 }
188
189 void phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr,
190 uint32_t indirect_port,
191 uint32_t index,
192 uint32_t value,
193 uint32_t mask)
194 {
195 if (hwmgr == NULL || hwmgr->device == NULL) {
196 printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
197 return;
198 }
199
200 cgs_write_register(hwmgr->device, indirect_port, index);
201 phm_wait_for_register_unequal(hwmgr, indirect_port + 1,
202 value, mask);
203 }
204
205 bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr)
206 {
207 return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating);
208 }
209
210 bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr)
211 {
212 return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating);
213 }