drm/amd/powerplay: implement smu_init[fini]_power function for smu11
[linux-2.6-block.git] / drivers / gpu / drm / amd / powerplay / amdgpu_smu.c
CommitLineData
137d63ab
HR
1/*
2 * Copyright 2019 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 "pp_debug.h"
24#include <linux/firmware.h>
25#include <drm/drmP.h>
26#include "amdgpu.h"
27#include "amdgpu_smu.h"
28#include "soc15_common.h"
07845526 29#include "smu_v11_0.h"
e15da5a4 30#include "atom.h"
137d63ab
HR
31
32static int smu_set_funcs(struct amdgpu_device *adev)
33{
07845526
HR
34 struct smu_context *smu = &adev->smu;
35
36 switch (adev->asic_type) {
37 case CHIP_VEGA20:
38 smu_v11_0_set_smu_funcs(smu);
39 break;
40 default:
41 return -EINVAL;
42 }
43
137d63ab
HR
44 return 0;
45}
46
47static int smu_early_init(void *handle)
48{
49 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
50 struct smu_context *smu = &adev->smu;
51 int ret;
52
53 ret = smu_set_funcs(adev);
54 if (ret)
55 return ret;
56
57 smu->adev = adev;
58 mutex_init(&smu->mutex);
59
60 return 0;
61}
62
e15da5a4
HR
63int smu_get_atom_data_table(struct smu_context *smu, uint32_t table,
64 uint16_t *size, uint8_t *frev, uint8_t *crev,
65 uint8_t **addr)
66{
67 struct amdgpu_device *adev = smu->adev;
68 uint16_t data_start;
69
70 if (!amdgpu_atom_parse_data_header(adev->mode_info.atom_context, table,
71 size, frev, crev, &data_start))
72 return -EINVAL;
73
74 *addr = (uint8_t *)adev->mode_info.atom_context->bios + data_start;
75
76 return 0;
77}
78
b5624000
HR
79static int smu_initialize_pptable(struct smu_context *smu)
80{
81 /* TODO */
82 return 0;
83}
84
85static int smu_smc_table_sw_init(struct smu_context *smu)
86{
87 int ret;
88
89 ret = smu_initialize_pptable(smu);
90 if (ret) {
91 pr_err("Failed to init smu_initialize_pptable!\n");
92 return ret;
93 }
94
cabd44c0
HR
95 /**
96 * Create smu_table structure, and init smc tables such as
97 * TABLE_PPTABLE, TABLE_WATERMARKS, TABLE_SMU_METRICS, and etc.
98 */
99 ret = smu_init_smc_tables(smu);
100 if (ret) {
101 pr_err("Failed to init smc tables!\n");
102 return ret;
103 }
104
17e6081b
HR
105 /**
106 * Create smu_power_context structure, and allocate smu_dpm_context and
107 * context size to fill the smu_power_context data.
108 */
109 ret = smu_init_power(smu);
110 if (ret) {
111 pr_err("Failed to init smu_init_power!\n");
112 return ret;
113 }
114
b5624000
HR
115 return 0;
116}
117
813ce279
KW
118static int smu_smc_table_sw_fini(struct smu_context *smu)
119{
120 int ret;
121
122 ret = smu_fini_smc_tables(smu);
123 if (ret) {
124 pr_err("Failed to smu_fini_smc_tables!\n");
125 return ret;
126 }
127
128 return 0;
129}
130
137d63ab
HR
131static int smu_sw_init(void *handle)
132{
133 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
134 struct smu_context *smu = &adev->smu;
135 int ret;
136
137 if (adev->asic_type < CHIP_VEGA20)
138 return -EINVAL;
139
140 ret = smu_init_microcode(smu);
141 if (ret) {
142 pr_err("Failed to load smu firmware!\n");
143 return ret;
144 }
145
b5624000
HR
146 ret = smu_smc_table_sw_init(smu);
147 if (ret) {
148 pr_err("Failed to sw init smc table!\n");
149 return ret;
150 }
151
137d63ab
HR
152 return 0;
153}
154
155static int smu_sw_fini(void *handle)
156{
157 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
813ce279
KW
158 struct smu_context *smu = &adev->smu;
159 int ret;
137d63ab
HR
160
161 if (adev->asic_type < CHIP_VEGA20)
162 return -EINVAL;
163
813ce279
KW
164 ret = smu_smc_table_sw_fini(smu);
165 if (ret) {
166 pr_err("Failed to sw fini smc table!\n");
167 return ret;
168 }
169
8bf16963
KW
170 ret = smu_fini_power(smu);
171 if (ret) {
172 pr_err("Failed to init smu_fini_power!\n");
173 return ret;
174 }
175
137d63ab
HR
176 return 0;
177}
178
9c9a1747
HR
179static int smu_init_fb_allocations(struct smu_context *smu)
180{
181 /* TODO */
182 return 0;
183}
184
05cadcd3
HR
185static int smu_smc_table_hw_init(struct smu_context *smu)
186{
187 int ret;
188
189 ret = smu_read_pptable_from_vbios(smu);
190 if (ret)
191 return ret;
192
a6b35900
HR
193 /* get boot_values from vbios to set revision, gfxclk, and etc. */
194 ret = smu_get_vbios_bootup_values(smu);
195 if (ret)
196 return ret;
197
46126e6d
HR
198 /*
199 * check if the format_revision in vbios is up to pptable header
200 * version, and the structure size is not 0.
201 */
202 ret = smu_check_pptable(smu);
203 if (ret)
204 return ret;
205
9c9a1747
HR
206 /*
207 * allocate vram bos to store smc table contents.
208 */
209 ret = smu_init_fb_allocations(smu);
210 if (ret)
211 return ret;
212
9e4848a4
HR
213 /*
214 * Parse pptable format and fill PPTable_t smc_pptable to
215 * smu_table_context structure. And read the smc_dpm_table from vbios,
216 * then fill it into smc_pptable.
217 */
218 ret = smu_parse_pptable(smu);
219 if (ret)
220 return ret;
221
86187fec
HR
222 /*
223 * Set initialized values (get from vbios) to dpm tables context such as
224 * gfxclk, memclk, dcefclk, and etc. And enable the DPM feature for each
225 * type of clks.
226 */
227 ret = smu_populate_smc_pptable(smu);
228 if (ret)
229 return ret;
230
a751b095
HR
231 /*
232 * Send msg GetDriverIfVersion to check if the return value is equal
233 * with DRIVER_IF_VERSION of smc header.
234 */
235 ret = smu_check_fw_version(smu);
236 if (ret)
237 return ret;
238
31b5ae49
HR
239 /*
240 * Copy pptable bo in the vram to smc with SMU MSGs such as
241 * SetDriverDramAddr and TransferTableDram2Smu.
242 */
243 ret = smu_write_pptable(smu);
244 if (ret)
245 return ret;
246
a7ebb6d2
HR
247 /*
248 * Set min deep sleep dce fclk with bootup value from vbios via
249 * SetMinDeepSleepDcefclk MSG.
250 */
251 ret = smu_set_min_dcef_deep_sleep(smu);
252 if (ret)
253 return ret;
254
206bc589
HR
255 /*
256 * Set PMSTATUSLOG table bo address with SetToolsDramAddr MSG for tools.
257 */
258 ret = smu_set_tool_table_location(smu);
259
260 return ret;
05cadcd3
HR
261}
262
e65d45f2
HR
263/**
264 * smu_alloc_memory_pool - allocate memory pool in the system memory
265 *
266 * @smu: amdgpu_device pointer
267 *
268 * This memory pool will be used for SMC use and msg SetSystemVirtualDramAddr
269 * and DramLogSetDramAddr can notify it changed.
270 *
271 * Returns 0 on success, error on failure.
272 */
273static int smu_alloc_memory_pool(struct smu_context *smu)
274{
275 return 0;
276}
277
137d63ab
HR
278static int smu_hw_init(void *handle)
279{
280 int ret;
281 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
282 struct smu_context *smu = &adev->smu;
283
284 if (adev->asic_type < CHIP_VEGA20)
285 return -EINVAL;
286
3d2f5200
HR
287 if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
288 ret = smu_load_microcode(smu);
289 if (ret)
290 return ret;
291 }
292
e11c4fd5
HR
293 ret = smu_check_fw_status(smu);
294 if (ret) {
295 pr_err("SMC firmware status is not correct\n");
296 return ret;
297 }
298
137d63ab
HR
299 mutex_lock(&smu->mutex);
300
05cadcd3
HR
301 ret = smu_smc_table_hw_init(smu);
302 if (ret)
303 goto failed;
137d63ab 304
e65d45f2
HR
305 ret = smu_alloc_memory_pool(smu);
306 if (ret)
307 goto failed;
308
c56de9e8
HR
309 /*
310 * Use msg SetSystemVirtualDramAddr and DramLogSetDramAddr can notify
311 * pool location.
312 */
313 ret = smu_notify_memory_pool_location(smu);
314 if (ret)
315 goto failed;
316
137d63ab
HR
317 mutex_unlock(&smu->mutex);
318
319 pr_info("SMU is initialized successfully!\n");
320
321 return 0;
05cadcd3
HR
322
323failed:
324 mutex_unlock(&smu->mutex);
325 return ret;
137d63ab
HR
326}
327
328static int smu_hw_fini(void *handle)
329{
330 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
331 struct smu_context *smu = &adev->smu;
332
333 if (adev->asic_type < CHIP_VEGA20)
334 return -EINVAL;
335
336 return 0;
337}
338
339static int smu_suspend(void *handle)
340{
341 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
342
343 if (adev->asic_type < CHIP_VEGA20)
344 return -EINVAL;
345
346 return 0;
347}
348
349static int smu_resume(void *handle)
350{
351 int ret;
352 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
353 struct smu_context *smu = &adev->smu;
354
355 if (adev->asic_type < CHIP_VEGA20)
356 return -EINVAL;
357
fad3ecf2
HR
358 pr_info("SMU is resuming...\n");
359
360 if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
361 ret = smu_load_microcode(smu);
362 if (ret)
363 return ret;
364 }
365
366 ret = smu_check_fw_status(smu);
367 if (ret) {
368 pr_err("SMC firmware status is not correct\n");
369 return ret;
370 }
371
137d63ab
HR
372 mutex_lock(&smu->mutex);
373
fad3ecf2
HR
374 ret = smu_set_tool_table_location(smu);
375 if (ret)
376 goto failed;
377
378 ret = smu_write_pptable(smu);
379 if (ret)
380 goto failed;
381
382 ret = smu_write_watermarks_table(smu);
383 if (ret)
384 goto failed;
385
386 ret = smu_set_last_dcef_min_deep_sleep_clk(smu);
387 if (ret)
388 goto failed;
389
390 ret = smu_system_features_control(smu, true);
391 if (ret)
392 goto failed;
137d63ab
HR
393
394 mutex_unlock(&smu->mutex);
395
fad3ecf2
HR
396 pr_info("SMU is resumed successfully!\n");
397
137d63ab 398 return 0;
fad3ecf2
HR
399failed:
400 mutex_unlock(&smu->mutex);
401 return ret;
137d63ab
HR
402}
403
404static int smu_set_clockgating_state(void *handle,
405 enum amd_clockgating_state state)
406{
407 return 0;
408}
409
410static int smu_set_powergating_state(void *handle,
411 enum amd_powergating_state state)
412{
413 return 0;
414}
415
416const struct amd_ip_funcs smu_ip_funcs = {
417 .name = "smu",
418 .early_init = smu_early_init,
419 .late_init = NULL,
420 .sw_init = smu_sw_init,
421 .sw_fini = smu_sw_fini,
422 .hw_init = smu_hw_init,
423 .hw_fini = smu_hw_fini,
424 .suspend = smu_suspend,
425 .resume = smu_resume,
426 .is_idle = NULL,
427 .check_soft_reset = NULL,
428 .wait_for_idle = NULL,
429 .soft_reset = NULL,
430 .set_clockgating_state = smu_set_clockgating_state,
431 .set_powergating_state = smu_set_powergating_state,
432};
07845526
HR
433
434const struct amdgpu_ip_block_version smu_v11_0_ip_block =
435{
436 .type = AMD_IP_BLOCK_TYPE_SMC,
437 .major = 11,
438 .minor = 0,
439 .rev = 0,
440 .funcs = &smu_ip_funcs,
441};