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