1 | /* |
2 | * Copyright 2016 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 | |
24 | #include "smumgr.h" |
25 | #include "vega10_inc.h" |
26 | #include "soc15_common.h" |
27 | #include "vega10_smumgr.h" |
28 | #include "vega10_hwmgr.h" |
29 | #include "vega10_ppsmc.h" |
30 | #include "smu9_driver_if.h" |
31 | #include "smu9_smumgr.h" |
32 | #include "ppatomctrl.h" |
33 | #include "pp_debug.h" |
34 | |
35 | |
36 | static int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, |
37 | uint8_t *table, int16_t table_id) |
38 | { |
39 | struct vega10_smumgr *priv = hwmgr->smu_backend; |
40 | |
41 | PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, |
42 | "Invalid SMU Table ID!" , return -EINVAL); |
43 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, |
44 | "Invalid SMU Table version!" , return -EINVAL); |
45 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, |
46 | "Invalid SMU Table Length!" , return -EINVAL); |
47 | smu9_send_msg_to_smc_with_parameter(hwmgr, |
48 | PPSMC_MSG_SetDriverDramAddrHigh, |
49 | upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); |
50 | smu9_send_msg_to_smc_with_parameter(hwmgr, |
51 | PPSMC_MSG_SetDriverDramAddrLow, |
52 | lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); |
53 | smu9_send_msg_to_smc_with_parameter(hwmgr, |
54 | PPSMC_MSG_TransferTableSmu2Dram, |
55 | priv->smu_tables.entry[table_id].table_id); |
56 | |
57 | memcpy(table, priv->smu_tables.entry[table_id].table, |
58 | priv->smu_tables.entry[table_id].size); |
59 | |
60 | return 0; |
61 | } |
62 | |
63 | static int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, |
64 | uint8_t *table, int16_t table_id) |
65 | { |
66 | struct vega10_smumgr *priv = hwmgr->smu_backend; |
67 | |
68 | PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, |
69 | "Invalid SMU Table ID!" , return -EINVAL); |
70 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, |
71 | "Invalid SMU Table version!" , return -EINVAL); |
72 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, |
73 | "Invalid SMU Table Length!" , return -EINVAL); |
74 | |
75 | memcpy(priv->smu_tables.entry[table_id].table, table, |
76 | priv->smu_tables.entry[table_id].size); |
77 | |
78 | smu9_send_msg_to_smc_with_parameter(hwmgr, |
79 | PPSMC_MSG_SetDriverDramAddrHigh, |
80 | upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); |
81 | smu9_send_msg_to_smc_with_parameter(hwmgr, |
82 | PPSMC_MSG_SetDriverDramAddrLow, |
83 | lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); |
84 | smu9_send_msg_to_smc_with_parameter(hwmgr, |
85 | PPSMC_MSG_TransferTableDram2Smu, |
86 | priv->smu_tables.entry[table_id].table_id); |
87 | |
88 | return 0; |
89 | } |
90 | |
91 | int vega10_enable_smc_features(struct pp_hwmgr *hwmgr, |
92 | bool enable, uint32_t feature_mask) |
93 | { |
94 | int msg = enable ? PPSMC_MSG_EnableSmuFeatures : |
95 | PPSMC_MSG_DisableSmuFeatures; |
96 | |
97 | return smum_send_msg_to_smc_with_parameter(hwmgr, |
98 | msg, feature_mask); |
99 | } |
100 | |
101 | int vega10_get_enabled_smc_features(struct pp_hwmgr *hwmgr, |
102 | uint64_t *features_enabled) |
103 | { |
104 | if (features_enabled == NULL) |
105 | return -EINVAL; |
106 | |
107 | smu9_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeatures); |
108 | *features_enabled = smu9_get_argument(hwmgr); |
109 | |
110 | return 0; |
111 | } |
112 | |
113 | static bool vega10_is_dpm_running(struct pp_hwmgr *hwmgr) |
114 | { |
115 | uint64_t features_enabled = 0; |
116 | |
117 | vega10_get_enabled_smc_features(hwmgr, &features_enabled); |
118 | |
119 | if (features_enabled & SMC_DPM_FEATURES) |
120 | return true; |
121 | else |
122 | return false; |
123 | } |
124 | |
125 | static int vega10_set_tools_address(struct pp_hwmgr *hwmgr) |
126 | { |
127 | struct vega10_smumgr *priv = hwmgr->smu_backend; |
128 | |
129 | if (priv->smu_tables.entry[TOOLSTABLE].mc_addr) { |
130 | smu9_send_msg_to_smc_with_parameter(hwmgr, |
131 | PPSMC_MSG_SetToolsDramAddrHigh, |
132 | upper_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr)); |
133 | smu9_send_msg_to_smc_with_parameter(hwmgr, |
134 | PPSMC_MSG_SetToolsDramAddrLow, |
135 | lower_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr)); |
136 | } |
137 | return 0; |
138 | } |
139 | |
140 | static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) |
141 | { |
142 | uint32_t smc_driver_if_version; |
143 | struct amdgpu_device *adev = hwmgr->adev; |
144 | uint32_t dev_id; |
145 | uint32_t rev_id; |
146 | |
147 | PP_ASSERT_WITH_CODE(!smu9_send_msg_to_smc(hwmgr, |
148 | PPSMC_MSG_GetDriverIfVersion), |
149 | "Attempt to get SMC IF Version Number Failed!" , |
150 | return -EINVAL); |
151 | smc_driver_if_version = smu9_get_argument(hwmgr); |
152 | |
153 | dev_id = adev->pdev->device; |
154 | rev_id = adev->pdev->revision; |
155 | |
156 | if (!((dev_id == 0x687f) && |
157 | ((rev_id == 0xc0) || |
158 | (rev_id == 0xc1) || |
159 | (rev_id == 0xc3)))) { |
160 | if (smc_driver_if_version != SMU9_DRIVER_IF_VERSION) { |
161 | pr_err("Your firmware(0x%x) doesn't match SMU9_DRIVER_IF_VERSION(0x%x). Please update your firmware!\n" , |
162 | smc_driver_if_version, SMU9_DRIVER_IF_VERSION); |
163 | return -EINVAL; |
164 | } |
165 | } |
166 | |
167 | return 0; |
168 | } |
169 | |
170 | static int vega10_smu_init(struct pp_hwmgr *hwmgr) |
171 | { |
172 | struct vega10_smumgr *priv; |
173 | unsigned long tools_size; |
174 | int ret; |
175 | struct cgs_firmware_info info = {0}; |
176 | |
177 | ret = cgs_get_firmware_info(hwmgr->device, |
178 | CGS_UCODE_ID_SMU, |
179 | &info); |
180 | if (ret || !info.kptr) |
181 | return -EINVAL; |
182 | |
183 | priv = kzalloc(sizeof(struct vega10_smumgr), GFP_KERNEL); |
184 | |
185 | if (!priv) |
186 | return -ENOMEM; |
187 | |
188 | hwmgr->smu_backend = priv; |
189 | |
190 | /* allocate space for pptable */ |
191 | ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
192 | sizeof(PPTable_t), |
193 | PAGE_SIZE, |
194 | AMDGPU_GEM_DOMAIN_VRAM, |
195 | &priv->smu_tables.entry[PPTABLE].handle, |
196 | &priv->smu_tables.entry[PPTABLE].mc_addr, |
197 | &priv->smu_tables.entry[PPTABLE].table); |
198 | if (ret) |
199 | goto free_backend; |
200 | |
201 | priv->smu_tables.entry[PPTABLE].version = 0x01; |
202 | priv->smu_tables.entry[PPTABLE].size = sizeof(PPTable_t); |
203 | priv->smu_tables.entry[PPTABLE].table_id = TABLE_PPTABLE; |
204 | |
205 | /* allocate space for watermarks table */ |
206 | ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
207 | sizeof(Watermarks_t), |
208 | PAGE_SIZE, |
209 | AMDGPU_GEM_DOMAIN_VRAM, |
210 | &priv->smu_tables.entry[WMTABLE].handle, |
211 | &priv->smu_tables.entry[WMTABLE].mc_addr, |
212 | &priv->smu_tables.entry[WMTABLE].table); |
213 | |
214 | if (ret) |
215 | goto err0; |
216 | |
217 | priv->smu_tables.entry[WMTABLE].version = 0x01; |
218 | priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t); |
219 | priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS; |
220 | |
221 | /* allocate space for AVFS table */ |
222 | ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
223 | sizeof(AvfsTable_t), |
224 | PAGE_SIZE, |
225 | AMDGPU_GEM_DOMAIN_VRAM, |
226 | &priv->smu_tables.entry[AVFSTABLE].handle, |
227 | &priv->smu_tables.entry[AVFSTABLE].mc_addr, |
228 | &priv->smu_tables.entry[AVFSTABLE].table); |
229 | |
230 | if (ret) |
231 | goto err1; |
232 | |
233 | priv->smu_tables.entry[AVFSTABLE].version = 0x01; |
234 | priv->smu_tables.entry[AVFSTABLE].size = sizeof(AvfsTable_t); |
235 | priv->smu_tables.entry[AVFSTABLE].table_id = TABLE_AVFS; |
236 | |
237 | tools_size = 0x19000; |
238 | if (tools_size) { |
239 | ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
240 | tools_size, |
241 | PAGE_SIZE, |
242 | AMDGPU_GEM_DOMAIN_VRAM, |
243 | &priv->smu_tables.entry[TOOLSTABLE].handle, |
244 | &priv->smu_tables.entry[TOOLSTABLE].mc_addr, |
245 | &priv->smu_tables.entry[TOOLSTABLE].table); |
246 | if (ret) |
247 | goto err2; |
248 | priv->smu_tables.entry[TOOLSTABLE].version = 0x01; |
249 | priv->smu_tables.entry[TOOLSTABLE].size = tools_size; |
250 | priv->smu_tables.entry[TOOLSTABLE].table_id = TABLE_PMSTATUSLOG; |
251 | } |
252 | |
253 | /* allocate space for AVFS Fuse table */ |
254 | ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
255 | sizeof(AvfsFuseOverride_t), |
256 | PAGE_SIZE, |
257 | AMDGPU_GEM_DOMAIN_VRAM, |
258 | &priv->smu_tables.entry[AVFSFUSETABLE].handle, |
259 | &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, |
260 | &priv->smu_tables.entry[AVFSFUSETABLE].table); |
261 | if (ret) |
262 | goto err3; |
263 | |
264 | priv->smu_tables.entry[AVFSFUSETABLE].version = 0x01; |
265 | priv->smu_tables.entry[AVFSFUSETABLE].size = sizeof(AvfsFuseOverride_t); |
266 | priv->smu_tables.entry[AVFSFUSETABLE].table_id = TABLE_AVFS_FUSE_OVERRIDE; |
267 | |
268 | |
269 | return 0; |
270 | |
271 | err3: |
272 | if (priv->smu_tables.entry[TOOLSTABLE].table) |
273 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle, |
274 | &priv->smu_tables.entry[TOOLSTABLE].mc_addr, |
275 | &priv->smu_tables.entry[TOOLSTABLE].table); |
276 | err2: |
277 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle, |
278 | &priv->smu_tables.entry[AVFSTABLE].mc_addr, |
279 | &priv->smu_tables.entry[AVFSTABLE].table); |
280 | err1: |
281 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, |
282 | &priv->smu_tables.entry[WMTABLE].mc_addr, |
283 | &priv->smu_tables.entry[WMTABLE].table); |
284 | err0: |
285 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, |
286 | &priv->smu_tables.entry[PPTABLE].mc_addr, |
287 | &priv->smu_tables.entry[PPTABLE].table); |
288 | free_backend: |
289 | kfree(hwmgr->smu_backend); |
290 | |
291 | return -EINVAL; |
292 | } |
293 | |
294 | static int vega10_smu_fini(struct pp_hwmgr *hwmgr) |
295 | { |
296 | struct vega10_smumgr *priv = hwmgr->smu_backend; |
297 | |
298 | if (priv) { |
299 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, |
300 | &priv->smu_tables.entry[PPTABLE].mc_addr, |
301 | &priv->smu_tables.entry[PPTABLE].table); |
302 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, |
303 | &priv->smu_tables.entry[WMTABLE].mc_addr, |
304 | &priv->smu_tables.entry[WMTABLE].table); |
305 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle, |
306 | &priv->smu_tables.entry[AVFSTABLE].mc_addr, |
307 | &priv->smu_tables.entry[AVFSTABLE].table); |
308 | if (priv->smu_tables.entry[TOOLSTABLE].table) |
309 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle, |
310 | &priv->smu_tables.entry[TOOLSTABLE].mc_addr, |
311 | &priv->smu_tables.entry[TOOLSTABLE].table); |
312 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSFUSETABLE].handle, |
313 | &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, |
314 | &priv->smu_tables.entry[AVFSFUSETABLE].table); |
315 | kfree(hwmgr->smu_backend); |
316 | hwmgr->smu_backend = NULL; |
317 | } |
318 | return 0; |
319 | } |
320 | |
321 | static int vega10_start_smu(struct pp_hwmgr *hwmgr) |
322 | { |
323 | if (!smu9_is_smc_ram_running(hwmgr)) |
324 | return -EINVAL; |
325 | |
326 | PP_ASSERT_WITH_CODE(!vega10_verify_smc_interface(hwmgr), |
327 | "Failed to verify SMC interface!" , |
328 | return -EINVAL); |
329 | |
330 | vega10_set_tools_address(hwmgr); |
331 | |
332 | return 0; |
333 | } |
334 | |
335 | static int vega10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, |
336 | uint16_t table_id, bool rw) |
337 | { |
338 | int ret; |
339 | |
340 | if (rw) |
341 | ret = vega10_copy_table_from_smc(hwmgr, table, table_id); |
342 | else |
343 | ret = vega10_copy_table_to_smc(hwmgr, table, table_id); |
344 | |
345 | return ret; |
346 | } |
347 | |
348 | const struct pp_smumgr_func vega10_smu_funcs = { |
349 | .smu_init = &vega10_smu_init, |
350 | .smu_fini = &vega10_smu_fini, |
351 | .start_smu = &vega10_start_smu, |
352 | .request_smu_load_specific_fw = NULL, |
353 | .send_msg_to_smc = &smu9_send_msg_to_smc, |
354 | .send_msg_to_smc_with_parameter = &smu9_send_msg_to_smc_with_parameter, |
355 | .download_pptable_settings = NULL, |
356 | .upload_pptable_settings = NULL, |
357 | .is_dpm_running = vega10_is_dpm_running, |
358 | .get_argument = smu9_get_argument, |
359 | .smc_table_manager = vega10_smc_table_manager, |
360 | }; |
361 | |