1 | /* |
2 | * Copyright 2017 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 "vega12_inc.h" |
26 | #include "soc15_common.h" |
27 | #include "smu9_smumgr.h" |
28 | #include "vega12_smumgr.h" |
29 | #include "vega12_ppsmc.h" |
30 | #include "vega12/smu9_driver_if.h" |
31 | #include "ppatomctrl.h" |
32 | #include "pp_debug.h" |
33 | |
34 | |
35 | /* |
36 | * Copy table from SMC into driver FB |
37 | * @param hwmgr the address of the HW manager |
38 | * @param table_id the driver's table ID to copy from |
39 | */ |
40 | static int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr, |
41 | uint8_t *table, int16_t table_id) |
42 | { |
43 | struct vega12_smumgr *priv = |
44 | (struct vega12_smumgr *)(hwmgr->smu_backend); |
45 | |
46 | PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT, |
47 | "Invalid SMU Table ID!" , return -EINVAL); |
48 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, |
49 | "Invalid SMU Table version!" , return -EINVAL); |
50 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, |
51 | "Invalid SMU Table Length!" , return -EINVAL); |
52 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, |
53 | PPSMC_MSG_SetDriverDramAddrHigh, |
54 | upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, |
55 | "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!" , return -EINVAL); |
56 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, |
57 | PPSMC_MSG_SetDriverDramAddrLow, |
58 | lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, |
59 | "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!" , |
60 | return -EINVAL); |
61 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, |
62 | PPSMC_MSG_TransferTableSmu2Dram, |
63 | table_id) == 0, |
64 | "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!" , |
65 | return -EINVAL); |
66 | |
67 | memcpy(table, priv->smu_tables.entry[table_id].table, |
68 | priv->smu_tables.entry[table_id].size); |
69 | |
70 | return 0; |
71 | } |
72 | |
73 | /* |
74 | * Copy table from Driver FB into SMC |
75 | * @param hwmgr the address of the HW manager |
76 | * @param table_id the table to copy from |
77 | */ |
78 | static int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr, |
79 | uint8_t *table, int16_t table_id) |
80 | { |
81 | struct vega12_smumgr *priv = |
82 | (struct vega12_smumgr *)(hwmgr->smu_backend); |
83 | |
84 | PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT, |
85 | "Invalid SMU Table ID!" , return -EINVAL); |
86 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, |
87 | "Invalid SMU Table version!" , return -EINVAL); |
88 | PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, |
89 | "Invalid SMU Table Length!" , return -EINVAL); |
90 | |
91 | memcpy(priv->smu_tables.entry[table_id].table, table, |
92 | priv->smu_tables.entry[table_id].size); |
93 | |
94 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, |
95 | PPSMC_MSG_SetDriverDramAddrHigh, |
96 | upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, |
97 | "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!" , |
98 | return -EINVAL;); |
99 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, |
100 | PPSMC_MSG_SetDriverDramAddrLow, |
101 | lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, |
102 | "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!" , |
103 | return -EINVAL); |
104 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, |
105 | PPSMC_MSG_TransferTableDram2Smu, |
106 | table_id) == 0, |
107 | "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!" , |
108 | return -EINVAL); |
109 | |
110 | return 0; |
111 | } |
112 | |
113 | int vega12_enable_smc_features(struct pp_hwmgr *hwmgr, |
114 | bool enable, uint64_t feature_mask) |
115 | { |
116 | uint32_t smu_features_low, smu_features_high; |
117 | |
118 | smu_features_low = (uint32_t)((feature_mask & SMU_FEATURES_LOW_MASK) >> SMU_FEATURES_LOW_SHIFT); |
119 | smu_features_high = (uint32_t)((feature_mask & SMU_FEATURES_HIGH_MASK) >> SMU_FEATURES_HIGH_SHIFT); |
120 | |
121 | if (enable) { |
122 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, |
123 | PPSMC_MSG_EnableSmuFeaturesLow, smu_features_low) == 0, |
124 | "[EnableDisableSMCFeatures] Attemp to enable SMU features Low failed!" , |
125 | return -EINVAL); |
126 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, |
127 | PPSMC_MSG_EnableSmuFeaturesHigh, smu_features_high) == 0, |
128 | "[EnableDisableSMCFeatures] Attemp to enable SMU features High failed!" , |
129 | return -EINVAL); |
130 | } else { |
131 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, |
132 | PPSMC_MSG_DisableSmuFeaturesLow, smu_features_low) == 0, |
133 | "[EnableDisableSMCFeatures] Attemp to disable SMU features Low failed!" , |
134 | return -EINVAL); |
135 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, |
136 | PPSMC_MSG_DisableSmuFeaturesHigh, smu_features_high) == 0, |
137 | "[EnableDisableSMCFeatures] Attemp to disable SMU features High failed!" , |
138 | return -EINVAL); |
139 | } |
140 | |
141 | return 0; |
142 | } |
143 | |
144 | int vega12_get_enabled_smc_features(struct pp_hwmgr *hwmgr, |
145 | uint64_t *features_enabled) |
146 | { |
147 | uint32_t smc_features_low, smc_features_high; |
148 | |
149 | if (features_enabled == NULL) |
150 | return -EINVAL; |
151 | |
152 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc(hwmgr, |
153 | PPSMC_MSG_GetEnabledSmuFeaturesLow) == 0, |
154 | "[GetEnabledSMCFeatures] Attemp to get SMU features Low failed!" , |
155 | return -EINVAL); |
156 | smc_features_low = smu9_get_argument(hwmgr); |
157 | |
158 | PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc(hwmgr, |
159 | PPSMC_MSG_GetEnabledSmuFeaturesHigh) == 0, |
160 | "[GetEnabledSMCFeatures] Attemp to get SMU features High failed!" , |
161 | return -EINVAL); |
162 | smc_features_high = smu9_get_argument(hwmgr); |
163 | |
164 | *features_enabled = ((((uint64_t)smc_features_low << SMU_FEATURES_LOW_SHIFT) & SMU_FEATURES_LOW_MASK) | |
165 | (((uint64_t)smc_features_high << SMU_FEATURES_HIGH_SHIFT) & SMU_FEATURES_HIGH_MASK)); |
166 | |
167 | return 0; |
168 | } |
169 | |
170 | static bool vega12_is_dpm_running(struct pp_hwmgr *hwmgr) |
171 | { |
172 | uint64_t features_enabled = 0; |
173 | |
174 | vega12_get_enabled_smc_features(hwmgr, &features_enabled); |
175 | |
176 | if (features_enabled & SMC_DPM_FEATURES) |
177 | return true; |
178 | else |
179 | return false; |
180 | } |
181 | |
182 | static int vega12_set_tools_address(struct pp_hwmgr *hwmgr) |
183 | { |
184 | struct vega12_smumgr *priv = |
185 | (struct vega12_smumgr *)(hwmgr->smu_backend); |
186 | |
187 | if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr) { |
188 | if (!smu9_send_msg_to_smc_with_parameter(hwmgr, |
189 | PPSMC_MSG_SetToolsDramAddrHigh, |
190 | upper_32_bits(priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr))) |
191 | smu9_send_msg_to_smc_with_parameter(hwmgr, |
192 | PPSMC_MSG_SetToolsDramAddrLow, |
193 | lower_32_bits(priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr)); |
194 | } |
195 | return 0; |
196 | } |
197 | |
198 | static int vega12_smu_init(struct pp_hwmgr *hwmgr) |
199 | { |
200 | struct vega12_smumgr *priv; |
201 | unsigned long tools_size; |
202 | struct cgs_firmware_info info = {0}; |
203 | int ret; |
204 | |
205 | ret = cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_SMU, |
206 | &info); |
207 | if (ret || !info.kptr) |
208 | return -EINVAL; |
209 | |
210 | priv = kzalloc(sizeof(struct vega12_smumgr), GFP_KERNEL); |
211 | if (!priv) |
212 | return -ENOMEM; |
213 | |
214 | hwmgr->smu_backend = priv; |
215 | |
216 | /* allocate space for pptable */ |
217 | ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
218 | sizeof(PPTable_t), |
219 | PAGE_SIZE, |
220 | AMDGPU_GEM_DOMAIN_VRAM, |
221 | &priv->smu_tables.entry[TABLE_PPTABLE].handle, |
222 | &priv->smu_tables.entry[TABLE_PPTABLE].mc_addr, |
223 | &priv->smu_tables.entry[TABLE_PPTABLE].table); |
224 | if (ret) |
225 | goto free_backend; |
226 | |
227 | priv->smu_tables.entry[TABLE_PPTABLE].version = 0x01; |
228 | priv->smu_tables.entry[TABLE_PPTABLE].size = sizeof(PPTable_t); |
229 | |
230 | /* allocate space for watermarks table */ |
231 | ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
232 | sizeof(Watermarks_t), |
233 | PAGE_SIZE, |
234 | AMDGPU_GEM_DOMAIN_VRAM, |
235 | &priv->smu_tables.entry[TABLE_WATERMARKS].handle, |
236 | &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr, |
237 | &priv->smu_tables.entry[TABLE_WATERMARKS].table); |
238 | |
239 | if (ret) |
240 | goto err0; |
241 | |
242 | priv->smu_tables.entry[TABLE_WATERMARKS].version = 0x01; |
243 | priv->smu_tables.entry[TABLE_WATERMARKS].size = sizeof(Watermarks_t); |
244 | |
245 | tools_size = 0x19000; |
246 | if (tools_size) { |
247 | ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
248 | tools_size, |
249 | PAGE_SIZE, |
250 | AMDGPU_GEM_DOMAIN_VRAM, |
251 | &priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle, |
252 | &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr, |
253 | &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table); |
254 | if (ret) |
255 | goto err1; |
256 | |
257 | priv->smu_tables.entry[TABLE_PMSTATUSLOG].version = 0x01; |
258 | priv->smu_tables.entry[TABLE_PMSTATUSLOG].size = tools_size; |
259 | } |
260 | |
261 | /* allocate space for AVFS Fuse table */ |
262 | ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
263 | sizeof(AvfsFuseOverride_t), |
264 | PAGE_SIZE, |
265 | AMDGPU_GEM_DOMAIN_VRAM, |
266 | &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle, |
267 | &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr, |
268 | &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table); |
269 | |
270 | if (ret) |
271 | goto err2; |
272 | |
273 | priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].version = 0x01; |
274 | priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].size = sizeof(AvfsFuseOverride_t); |
275 | |
276 | /* allocate space for OverDrive table */ |
277 | ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
278 | sizeof(OverDriveTable_t), |
279 | PAGE_SIZE, |
280 | AMDGPU_GEM_DOMAIN_VRAM, |
281 | &priv->smu_tables.entry[TABLE_OVERDRIVE].handle, |
282 | &priv->smu_tables.entry[TABLE_OVERDRIVE].mc_addr, |
283 | &priv->smu_tables.entry[TABLE_OVERDRIVE].table); |
284 | if (ret) |
285 | goto err3; |
286 | |
287 | priv->smu_tables.entry[TABLE_OVERDRIVE].version = 0x01; |
288 | priv->smu_tables.entry[TABLE_OVERDRIVE].size = sizeof(OverDriveTable_t); |
289 | |
290 | return 0; |
291 | |
292 | err3: |
293 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle, |
294 | &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr, |
295 | &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table); |
296 | err2: |
297 | if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].table) |
298 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle, |
299 | &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr, |
300 | &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table); |
301 | err1: |
302 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_WATERMARKS].handle, |
303 | &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr, |
304 | &priv->smu_tables.entry[TABLE_WATERMARKS].table); |
305 | err0: |
306 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle, |
307 | &priv->smu_tables.entry[TABLE_PPTABLE].mc_addr, |
308 | &priv->smu_tables.entry[TABLE_PPTABLE].table); |
309 | free_backend: |
310 | kfree(hwmgr->smu_backend); |
311 | |
312 | return -EINVAL; |
313 | } |
314 | |
315 | static int vega12_smu_fini(struct pp_hwmgr *hwmgr) |
316 | { |
317 | struct vega12_smumgr *priv = |
318 | (struct vega12_smumgr *)(hwmgr->smu_backend); |
319 | |
320 | if (priv) { |
321 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle, |
322 | &priv->smu_tables.entry[TABLE_PPTABLE].mc_addr, |
323 | &priv->smu_tables.entry[TABLE_PPTABLE].table); |
324 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_WATERMARKS].handle, |
325 | &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr, |
326 | &priv->smu_tables.entry[TABLE_WATERMARKS].table); |
327 | if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].table) |
328 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle, |
329 | &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr, |
330 | &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table); |
331 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle, |
332 | &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr, |
333 | &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table); |
334 | amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_OVERDRIVE].handle, |
335 | &priv->smu_tables.entry[TABLE_OVERDRIVE].mc_addr, |
336 | &priv->smu_tables.entry[TABLE_OVERDRIVE].table); |
337 | kfree(hwmgr->smu_backend); |
338 | hwmgr->smu_backend = NULL; |
339 | } |
340 | return 0; |
341 | } |
342 | |
343 | static int vega12_start_smu(struct pp_hwmgr *hwmgr) |
344 | { |
345 | PP_ASSERT_WITH_CODE(smu9_is_smc_ram_running(hwmgr), |
346 | "SMC is not running!" , |
347 | return -EINVAL); |
348 | |
349 | vega12_set_tools_address(hwmgr); |
350 | |
351 | return 0; |
352 | } |
353 | |
354 | static int vega12_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, |
355 | uint16_t table_id, bool rw) |
356 | { |
357 | int ret; |
358 | |
359 | if (rw) |
360 | ret = vega12_copy_table_from_smc(hwmgr, table, table_id); |
361 | else |
362 | ret = vega12_copy_table_to_smc(hwmgr, table, table_id); |
363 | |
364 | return ret; |
365 | } |
366 | |
367 | const struct pp_smumgr_func vega12_smu_funcs = { |
368 | .smu_init = &vega12_smu_init, |
369 | .smu_fini = &vega12_smu_fini, |
370 | .start_smu = &vega12_start_smu, |
371 | .request_smu_load_specific_fw = NULL, |
372 | .send_msg_to_smc = &smu9_send_msg_to_smc, |
373 | .send_msg_to_smc_with_parameter = &smu9_send_msg_to_smc_with_parameter, |
374 | .download_pptable_settings = NULL, |
375 | .upload_pptable_settings = NULL, |
376 | .is_dpm_running = vega12_is_dpm_running, |
377 | .get_argument = smu9_get_argument, |
378 | .smc_table_manager = vega12_smc_table_manager, |
379 | }; |
380 | |