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