Commit | Line | Data |
---|---|---|
654f761c FX |
1 | /* |
2 | * Copyright 2018 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 <linux/firmware.h> | |
f867723b | 24 | #include <linux/module.h> |
7044cb6c | 25 | #include <linux/vmalloc.h> |
f89f8c6b | 26 | #include <drm/drm_drv.h> |
f867723b | 27 | |
654f761c FX |
28 | #include "amdgpu.h" |
29 | #include "amdgpu_psp.h" | |
c2c6f816 | 30 | #include "amdgpu_ras.h" |
654f761c FX |
31 | #include "amdgpu_ucode.h" |
32 | #include "soc15_common.h" | |
33 | #include "psp_v11_0.h" | |
34 | ||
35 | #include "mp/mp_11_0_offset.h" | |
36 | #include "mp/mp_11_0_sh_mask.h" | |
37 | #include "gc/gc_9_0_offset.h" | |
38 | #include "sdma0/sdma0_4_0_offset.h" | |
39 | #include "nbio/nbio_7_4_offset.h" | |
40 | ||
b849aaa4 CK |
41 | #include "oss/osssys_4_0_offset.h" |
42 | #include "oss/osssys_4_0_sh_mask.h" | |
43 | ||
654f761c | 44 | MODULE_FIRMWARE("amdgpu/vega20_sos.bin"); |
06d6370e | 45 | MODULE_FIRMWARE("amdgpu/vega20_asd.bin"); |
51e7177f | 46 | MODULE_FIRMWARE("amdgpu/vega20_ta.bin"); |
bc290fe5 | 47 | MODULE_FIRMWARE("amdgpu/navi10_sos.bin"); |
a698faf8 | 48 | MODULE_FIRMWARE("amdgpu/navi10_asd.bin"); |
a2e4b418 | 49 | MODULE_FIRMWARE("amdgpu/navi10_ta.bin"); |
82522b2d | 50 | MODULE_FIRMWARE("amdgpu/navi14_sos.bin"); |
8687b47e | 51 | MODULE_FIRMWARE("amdgpu/navi14_asd.bin"); |
a2e4b418 | 52 | MODULE_FIRMWARE("amdgpu/navi14_ta.bin"); |
739cdbd6 XY |
53 | MODULE_FIRMWARE("amdgpu/navi12_sos.bin"); |
54 | MODULE_FIRMWARE("amdgpu/navi12_asd.bin"); | |
a2e4b418 | 55 | MODULE_FIRMWARE("amdgpu/navi12_ta.bin"); |
f36d9ab9 JC |
56 | MODULE_FIRMWARE("amdgpu/arcturus_sos.bin"); |
57 | MODULE_FIRMWARE("amdgpu/arcturus_asd.bin"); | |
4fb60b02 | 58 | MODULE_FIRMWARE("amdgpu/arcturus_ta.bin"); |
344fed0b | 59 | MODULE_FIRMWARE("amdgpu/sienna_cichlid_sos.bin"); |
6ece96a1 | 60 | MODULE_FIRMWARE("amdgpu/sienna_cichlid_ta.bin"); |
c82b38ec | 61 | MODULE_FIRMWARE("amdgpu/navy_flounder_sos.bin"); |
24b763d0 | 62 | MODULE_FIRMWARE("amdgpu/navy_flounder_ta.bin"); |
ed3b7353 HR |
63 | MODULE_FIRMWARE("amdgpu/vangogh_asd.bin"); |
64 | MODULE_FIRMWARE("amdgpu/vangogh_toc.bin"); | |
462c272b | 65 | MODULE_FIRMWARE("amdgpu/dimgrey_cavefish_sos.bin"); |
2bdb8302 | 66 | MODULE_FIRMWARE("amdgpu/dimgrey_cavefish_ta.bin"); |
c0729819 | 67 | MODULE_FIRMWARE("amdgpu/beige_goby_sos.bin"); |
ac87f942 | 68 | MODULE_FIRMWARE("amdgpu/beige_goby_ta.bin"); |
654f761c FX |
69 | |
70 | /* address block */ | |
71 | #define smnMP1_FIRMWARE_FLAGS 0x3010024 | |
bc290fe5 TZ |
72 | /* navi10 reg offset define */ |
73 | #define mmRLC_GPM_UCODE_ADDR_NV10 0x5b61 | |
74 | #define mmRLC_GPM_UCODE_DATA_NV10 0x5b62 | |
75 | #define mmSDMA0_UCODE_ADDR_NV10 0x5880 | |
76 | #define mmSDMA0_UCODE_DATA_NV10 0x5881 | |
367039bf TY |
77 | /* memory training timeout define */ |
78 | #define MEM_TRAIN_SEND_MSG_TIMEOUT_US 3000000 | |
654f761c | 79 | |
0dc93fd1 AG |
80 | /* For large FW files the time to complete can be very long */ |
81 | #define USBC_PD_POLLING_LIMIT_S 240 | |
82 | ||
25a3e8ac AG |
83 | /* Read USB-PD from LFB */ |
84 | #define GFX_CMD_USB_PD_USE_LFB 0x480 | |
85 | ||
654f761c FX |
86 | static int psp_v11_0_init_microcode(struct psp_context *psp) |
87 | { | |
88 | struct amdgpu_device *adev = psp->adev; | |
89 | const char *chip_name; | |
0a305e34 | 90 | char fw_name[PSP_FW_NAME_LEN]; |
654f761c | 91 | int err = 0; |
51e7177f | 92 | const struct ta_firmware_header_v1_0 *ta_hdr; |
654f761c FX |
93 | |
94 | DRM_DEBUG("\n"); | |
95 | ||
96 | switch (adev->asic_type) { | |
97 | case CHIP_VEGA20: | |
98 | chip_name = "vega20"; | |
99 | break; | |
bc290fe5 TZ |
100 | case CHIP_NAVI10: |
101 | chip_name = "navi10"; | |
102 | break; | |
82522b2d XY |
103 | case CHIP_NAVI14: |
104 | chip_name = "navi14"; | |
105 | break; | |
739cdbd6 XY |
106 | case CHIP_NAVI12: |
107 | chip_name = "navi12"; | |
108 | break; | |
dc0d9622 JC |
109 | case CHIP_ARCTURUS: |
110 | chip_name = "arcturus"; | |
111 | break; | |
344fed0b LG |
112 | case CHIP_SIENNA_CICHLID: |
113 | chip_name = "sienna_cichlid"; | |
114 | break; | |
c82b38ec JC |
115 | case CHIP_NAVY_FLOUNDER: |
116 | chip_name = "navy_flounder"; | |
117 | break; | |
ed3b7353 HR |
118 | case CHIP_VANGOGH: |
119 | chip_name = "vangogh"; | |
120 | break; | |
462c272b TZ |
121 | case CHIP_DIMGREY_CAVEFISH: |
122 | chip_name = "dimgrey_cavefish"; | |
123 | break; | |
c0729819 CG |
124 | case CHIP_BEIGE_GOBY: |
125 | chip_name = "beige_goby"; | |
126 | break; | |
654f761c FX |
127 | default: |
128 | BUG(); | |
129 | } | |
130 | ||
06d6370e | 131 | |
a954f3ff HZ |
132 | switch (adev->asic_type) { |
133 | case CHIP_VEGA20: | |
4fb60b02 | 134 | case CHIP_ARCTURUS: |
5120cb54 HR |
135 | err = psp_init_sos_microcode(psp, chip_name); |
136 | if (err) | |
137 | return err; | |
138 | err = psp_init_asd_microcode(psp, chip_name); | |
139 | if (err) | |
140 | return err; | |
a954f3ff HZ |
141 | snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name); |
142 | err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev); | |
143 | if (err) { | |
144 | release_firmware(adev->psp.ta_fw); | |
145 | adev->psp.ta_fw = NULL; | |
146 | dev_info(adev->dev, | |
147 | "psp v11.0: Failed to load firmware \"%s\"\n", fw_name); | |
148 | } else { | |
149 | err = amdgpu_ucode_validate(adev->psp.ta_fw); | |
150 | if (err) | |
151 | goto out2; | |
152 | ||
153 | ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data; | |
154 | adev->psp.ta_xgmi_ucode_version = le32_to_cpu(ta_hdr->ta_xgmi_ucode_version); | |
155 | adev->psp.ta_xgmi_ucode_size = le32_to_cpu(ta_hdr->ta_xgmi_size_bytes); | |
156 | adev->psp.ta_xgmi_start_addr = (uint8_t *)ta_hdr + | |
157 | le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); | |
158 | adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); | |
159 | adev->psp.ta_ras_ucode_version = le32_to_cpu(ta_hdr->ta_ras_ucode_version); | |
160 | adev->psp.ta_ras_ucode_size = le32_to_cpu(ta_hdr->ta_ras_size_bytes); | |
161 | adev->psp.ta_ras_start_addr = (uint8_t *)adev->psp.ta_xgmi_start_addr + | |
162 | le32_to_cpu(ta_hdr->ta_ras_offset_bytes); | |
163 | } | |
164 | break; | |
165 | case CHIP_NAVI10: | |
e470d287 | 166 | case CHIP_NAVI14: |
739cdbd6 | 167 | case CHIP_NAVI12: |
5120cb54 HR |
168 | err = psp_init_sos_microcode(psp, chip_name); |
169 | if (err) | |
170 | return err; | |
171 | err = psp_init_asd_microcode(psp, chip_name); | |
172 | if (err) | |
173 | return err; | |
1a0f3667 ML |
174 | if (amdgpu_sriov_vf(adev)) |
175 | break; | |
a7f4ba7a BL |
176 | snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name); |
177 | err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev); | |
178 | if (err) { | |
179 | release_firmware(adev->psp.ta_fw); | |
180 | adev->psp.ta_fw = NULL; | |
181 | dev_info(adev->dev, | |
182 | "psp v11.0: Failed to load firmware \"%s\"\n", fw_name); | |
183 | } else { | |
184 | err = amdgpu_ucode_validate(adev->psp.ta_fw); | |
185 | if (err) | |
186 | goto out2; | |
187 | ||
188 | ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data; | |
189 | adev->psp.ta_hdcp_ucode_version = le32_to_cpu(ta_hdr->ta_hdcp_ucode_version); | |
190 | adev->psp.ta_hdcp_ucode_size = le32_to_cpu(ta_hdr->ta_hdcp_size_bytes); | |
191 | adev->psp.ta_hdcp_start_addr = (uint8_t *)ta_hdr + | |
192 | le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); | |
193 | ||
194 | adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); | |
195 | ||
196 | adev->psp.ta_dtm_ucode_version = le32_to_cpu(ta_hdr->ta_dtm_ucode_version); | |
197 | adev->psp.ta_dtm_ucode_size = le32_to_cpu(ta_hdr->ta_dtm_size_bytes); | |
198 | adev->psp.ta_dtm_start_addr = (uint8_t *)adev->psp.ta_hdcp_start_addr + | |
199 | le32_to_cpu(ta_hdr->ta_dtm_offset_bytes); | |
200 | } | |
a954f3ff | 201 | break; |
344fed0b | 202 | case CHIP_SIENNA_CICHLID: |
0a668aee | 203 | case CHIP_NAVY_FLOUNDER: |
2bdb8302 | 204 | case CHIP_DIMGREY_CAVEFISH: |
5120cb54 HR |
205 | err = psp_init_sos_microcode(psp, chip_name); |
206 | if (err) | |
207 | return err; | |
2bdb8302 | 208 | err = psp_init_ta_microcode(psp, chip_name); |
c0729819 CG |
209 | if (err) |
210 | return err; | |
211 | break; | |
212 | case CHIP_BEIGE_GOBY: | |
213 | err = psp_init_sos_microcode(psp, chip_name); | |
ac87f942 AP |
214 | if (err) |
215 | return err; | |
2bdb8302 | 216 | err = psp_init_ta_microcode(psp, chip_name); |
462c272b TZ |
217 | if (err) |
218 | return err; | |
219 | break; | |
5120cb54 HR |
220 | case CHIP_VANGOGH: |
221 | err = psp_init_asd_microcode(psp, chip_name); | |
222 | if (err) | |
223 | return err; | |
224 | err = psp_init_toc_microcode(psp, chip_name); | |
225 | if (err) | |
226 | return err; | |
6ece96a1 | 227 | break; |
a954f3ff HZ |
228 | default: |
229 | BUG(); | |
1d69511e | 230 | } |
51e7177f | 231 | |
654f761c | 232 | return 0; |
06d6370e EQ |
233 | |
234 | out2: | |
235 | release_firmware(adev->psp.ta_fw); | |
236 | adev->psp.ta_fw = NULL; | |
654f761c FX |
237 | return err; |
238 | } | |
239 | ||
3fdd2da0 | 240 | static int psp_v11_0_wait_for_bootloader(struct psp_context *psp) |
097dc53e JC |
241 | { |
242 | struct amdgpu_device *adev = psp->adev; | |
243 | ||
244 | int ret; | |
245 | int retry_loop; | |
246 | ||
247 | for (retry_loop = 0; retry_loop < 10; retry_loop++) { | |
248 | /* Wait for bootloader to signify that is | |
249 | ready having bit 31 of C2PMSG_35 set to 1 */ | |
250 | ret = psp_wait_for(psp, | |
251 | SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), | |
252 | 0x80000000, | |
253 | 0x80000000, | |
254 | false); | |
255 | ||
256 | if (ret == 0) | |
257 | return 0; | |
258 | } | |
259 | ||
260 | return ret; | |
261 | } | |
262 | ||
a7d4c920 TY |
263 | static bool psp_v11_0_is_sos_alive(struct psp_context *psp) |
264 | { | |
265 | struct amdgpu_device *adev = psp->adev; | |
266 | uint32_t sol_reg; | |
267 | ||
268 | sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81); | |
269 | ||
270 | return sol_reg != 0x0; | |
271 | } | |
272 | ||
42989359 HZ |
273 | static int psp_v11_0_bootloader_load_kdb(struct psp_context *psp) |
274 | { | |
275 | int ret; | |
276 | uint32_t psp_gfxdrv_command_reg = 0; | |
277 | struct amdgpu_device *adev = psp->adev; | |
42989359 HZ |
278 | |
279 | /* Check tOS sign of life register to confirm sys driver and sOS | |
280 | * are already been loaded. | |
281 | */ | |
d4d27897 | 282 | if (psp_v11_0_is_sos_alive(psp)) |
42989359 | 283 | return 0; |
42989359 | 284 | |
097dc53e | 285 | ret = psp_v11_0_wait_for_bootloader(psp); |
42989359 HZ |
286 | if (ret) |
287 | return ret; | |
288 | ||
42989359 | 289 | /* Copy PSP KDB binary to memory */ |
222e0a71 | 290 | psp_copy_fw(psp, psp->kdb.start_addr, psp->kdb.size_bytes); |
42989359 | 291 | |
73469970 | 292 | /* Provide the PSP KDB to bootloader */ |
42989359 HZ |
293 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, |
294 | (uint32_t)(psp->fw_pri_mc_addr >> 20)); | |
295 | psp_gfxdrv_command_reg = PSP_BL__LOAD_KEY_DATABASE; | |
296 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, | |
297 | psp_gfxdrv_command_reg); | |
298 | ||
097dc53e | 299 | ret = psp_v11_0_wait_for_bootloader(psp); |
42989359 HZ |
300 | |
301 | return ret; | |
302 | } | |
303 | ||
70509057 LG |
304 | static int psp_v11_0_bootloader_load_spl(struct psp_context *psp) |
305 | { | |
306 | int ret; | |
307 | uint32_t psp_gfxdrv_command_reg = 0; | |
308 | struct amdgpu_device *adev = psp->adev; | |
309 | ||
310 | /* Check tOS sign of life register to confirm sys driver and sOS | |
311 | * are already been loaded. | |
312 | */ | |
313 | if (psp_v11_0_is_sos_alive(psp)) | |
314 | return 0; | |
315 | ||
316 | ret = psp_v11_0_wait_for_bootloader(psp); | |
317 | if (ret) | |
318 | return ret; | |
319 | ||
70509057 | 320 | /* Copy PSP SPL binary to memory */ |
222e0a71 | 321 | psp_copy_fw(psp, psp->spl.start_addr, psp->spl.size_bytes); |
70509057 LG |
322 | |
323 | /* Provide the PSP SPL to bootloader */ | |
324 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, | |
325 | (uint32_t)(psp->fw_pri_mc_addr >> 20)); | |
326 | psp_gfxdrv_command_reg = PSP_BL__LOAD_TOS_SPL_TABLE; | |
327 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, | |
328 | psp_gfxdrv_command_reg); | |
329 | ||
330 | ret = psp_v11_0_wait_for_bootloader(psp); | |
331 | ||
332 | return ret; | |
333 | } | |
334 | ||
654f761c FX |
335 | static int psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp) |
336 | { | |
337 | int ret; | |
338 | uint32_t psp_gfxdrv_command_reg = 0; | |
339 | struct amdgpu_device *adev = psp->adev; | |
654f761c FX |
340 | |
341 | /* Check sOS sign of life register to confirm sys driver and sOS | |
342 | * are already been loaded. | |
343 | */ | |
d4d27897 | 344 | if (psp_v11_0_is_sos_alive(psp)) |
654f761c FX |
345 | return 0; |
346 | ||
097dc53e | 347 | ret = psp_v11_0_wait_for_bootloader(psp); |
654f761c FX |
348 | if (ret) |
349 | return ret; | |
350 | ||
654f761c | 351 | /* Copy PSP System Driver binary to memory */ |
222e0a71 | 352 | psp_copy_fw(psp, psp->sys.start_addr, psp->sys.size_bytes); |
654f761c | 353 | |
548f2ecc | 354 | /* Provide the sys driver to bootloader */ |
654f761c FX |
355 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, |
356 | (uint32_t)(psp->fw_pri_mc_addr >> 20)); | |
3840fe25 | 357 | psp_gfxdrv_command_reg = PSP_BL__LOAD_SYSDRV; |
654f761c FX |
358 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, |
359 | psp_gfxdrv_command_reg); | |
360 | ||
361 | /* there might be handshake issue with hardware which needs delay */ | |
362 | mdelay(20); | |
363 | ||
097dc53e | 364 | ret = psp_v11_0_wait_for_bootloader(psp); |
654f761c FX |
365 | |
366 | return ret; | |
367 | } | |
368 | ||
369 | static int psp_v11_0_bootloader_load_sos(struct psp_context *psp) | |
370 | { | |
371 | int ret; | |
372 | unsigned int psp_gfxdrv_command_reg = 0; | |
373 | struct amdgpu_device *adev = psp->adev; | |
654f761c FX |
374 | |
375 | /* Check sOS sign of life register to confirm sys driver and sOS | |
376 | * are already been loaded. | |
377 | */ | |
a7d4c920 | 378 | if (psp_v11_0_is_sos_alive(psp)) |
654f761c FX |
379 | return 0; |
380 | ||
097dc53e | 381 | ret = psp_v11_0_wait_for_bootloader(psp); |
654f761c FX |
382 | if (ret) |
383 | return ret; | |
384 | ||
654f761c | 385 | /* Copy Secure OS binary to PSP memory */ |
222e0a71 | 386 | psp_copy_fw(psp, psp->sos.start_addr, psp->sos.size_bytes); |
654f761c | 387 | |
548f2ecc | 388 | /* Provide the PSP secure OS to bootloader */ |
654f761c FX |
389 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, |
390 | (uint32_t)(psp->fw_pri_mc_addr >> 20)); | |
3840fe25 | 391 | psp_gfxdrv_command_reg = PSP_BL__LOAD_SOSDRV; |
654f761c FX |
392 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, |
393 | psp_gfxdrv_command_reg); | |
394 | ||
395 | /* there might be handshake issue with hardware which needs delay */ | |
396 | mdelay(20); | |
397 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_81), | |
398 | RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81), | |
399 | 0, true); | |
400 | ||
401 | return ret; | |
402 | } | |
403 | ||
654f761c FX |
404 | static int psp_v11_0_ring_init(struct psp_context *psp, |
405 | enum psp_ring_type ring_type) | |
406 | { | |
407 | int ret = 0; | |
408 | struct psp_ring *ring; | |
409 | struct amdgpu_device *adev = psp->adev; | |
410 | ||
411 | ring = &psp->km_ring; | |
412 | ||
413 | ring->ring_type = ring_type; | |
414 | ||
415 | /* allocate 4k Page of Local Frame Buffer memory for ring */ | |
416 | ring->ring_size = 0x1000; | |
417 | ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE, | |
418 | AMDGPU_GEM_DOMAIN_VRAM, | |
419 | &adev->firmware.rbuf, | |
420 | &ring->ring_mem_mc_addr, | |
421 | (void **)&ring->ring_mem); | |
422 | if (ret) { | |
423 | ring->ring_size = 0; | |
424 | return ret; | |
425 | } | |
426 | ||
427 | return 0; | |
428 | } | |
429 | ||
51c0f58e JZ |
430 | static int psp_v11_0_ring_stop(struct psp_context *psp, |
431 | enum psp_ring_type ring_type) | |
432 | { | |
433 | int ret = 0; | |
434 | struct amdgpu_device *adev = psp->adev; | |
435 | ||
436 | /* Write the ring destroy command*/ | |
a2676149 | 437 | if (amdgpu_sriov_vf(adev)) |
51c0f58e JZ |
438 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, |
439 | GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING); | |
440 | else | |
441 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, | |
442 | GFX_CTRL_CMD_ID_DESTROY_RINGS); | |
443 | ||
444 | /* there might be handshake issue with hardware which needs delay */ | |
445 | mdelay(20); | |
446 | ||
447 | /* Wait for response flag (bit 31) */ | |
a2676149 | 448 | if (amdgpu_sriov_vf(adev)) |
51c0f58e JZ |
449 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101), |
450 | 0x80000000, 0x80000000, false); | |
451 | else | |
452 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64), | |
453 | 0x80000000, 0x80000000, false); | |
454 | ||
455 | return ret; | |
456 | } | |
457 | ||
654f761c FX |
458 | static int psp_v11_0_ring_create(struct psp_context *psp, |
459 | enum psp_ring_type ring_type) | |
460 | { | |
461 | int ret = 0; | |
462 | unsigned int psp_ring_reg = 0; | |
463 | struct psp_ring *ring = &psp->km_ring; | |
464 | struct amdgpu_device *adev = psp->adev; | |
465 | ||
a2676149 | 466 | if (amdgpu_sriov_vf(adev)) { |
29b4ac0e | 467 | ring->ring_wptr = 0; |
51c0f58e JZ |
468 | ret = psp_v11_0_ring_stop(psp, ring_type); |
469 | if (ret) { | |
470 | DRM_ERROR("psp_v11_0_ring_stop_sriov failed!\n"); | |
471 | return ret; | |
472 | } | |
473 | ||
5ec996df XY |
474 | /* Write low address of the ring to C2PMSG_102 */ |
475 | psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr); | |
476 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_ring_reg); | |
477 | /* Write high address of the ring to C2PMSG_103 */ | |
478 | psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr); | |
479 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_103, psp_ring_reg); | |
480 | ||
481 | /* Write the ring initialization command to C2PMSG_101 */ | |
482 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, | |
483 | GFX_CTRL_CMD_ID_INIT_GPCOM_RING); | |
484 | ||
485 | /* there might be handshake issue with hardware which needs delay */ | |
486 | mdelay(20); | |
487 | ||
488 | /* Wait for response flag (bit 31) in C2PMSG_101 */ | |
489 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101), | |
490 | 0x80000000, 0x8000FFFF, false); | |
491 | ||
492 | } else { | |
d7e7f1ea XY |
493 | /* Wait for sOS ready for ring creation */ |
494 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64), | |
495 | 0x80000000, 0x80000000, false); | |
496 | if (ret) { | |
497 | DRM_ERROR("Failed to wait for sOS ready for ring creation\n"); | |
498 | return ret; | |
499 | } | |
500 | ||
5ec996df XY |
501 | /* Write low address of the ring to C2PMSG_69 */ |
502 | psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr); | |
503 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_69, psp_ring_reg); | |
504 | /* Write high address of the ring to C2PMSG_70 */ | |
505 | psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr); | |
506 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_70, psp_ring_reg); | |
507 | /* Write size of ring to C2PMSG_71 */ | |
508 | psp_ring_reg = ring->ring_size; | |
509 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_71, psp_ring_reg); | |
510 | /* Write the ring initialization command to C2PMSG_64 */ | |
511 | psp_ring_reg = ring_type; | |
512 | psp_ring_reg = psp_ring_reg << 16; | |
513 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg); | |
514 | ||
515 | /* there might be handshake issue with hardware which needs delay */ | |
516 | mdelay(20); | |
517 | ||
518 | /* Wait for response flag (bit 31) in C2PMSG_64 */ | |
519 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64), | |
520 | 0x80000000, 0x8000FFFF, false); | |
521 | } | |
654f761c FX |
522 | |
523 | return ret; | |
524 | } | |
525 | ||
654f761c FX |
526 | |
527 | static int psp_v11_0_ring_destroy(struct psp_context *psp, | |
528 | enum psp_ring_type ring_type) | |
529 | { | |
530 | int ret = 0; | |
531 | struct psp_ring *ring = &psp->km_ring; | |
532 | struct amdgpu_device *adev = psp->adev; | |
533 | ||
534 | ret = psp_v11_0_ring_stop(psp, ring_type); | |
535 | if (ret) | |
536 | DRM_ERROR("Fail to stop psp ring\n"); | |
537 | ||
538 | amdgpu_bo_free_kernel(&adev->firmware.rbuf, | |
539 | &ring->ring_mem_mc_addr, | |
540 | (void **)&ring->ring_mem); | |
541 | ||
542 | return ret; | |
543 | } | |
544 | ||
654f761c FX |
545 | static int psp_v11_0_mode1_reset(struct psp_context *psp) |
546 | { | |
547 | int ret; | |
548 | uint32_t offset; | |
549 | struct amdgpu_device *adev = psp->adev; | |
550 | ||
551 | offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64); | |
552 | ||
553 | ret = psp_wait_for(psp, offset, 0x80000000, 0x8000FFFF, false); | |
554 | ||
555 | if (ret) { | |
556 | DRM_INFO("psp is not working correctly before mode1 reset!\n"); | |
557 | return -EINVAL; | |
558 | } | |
559 | ||
560 | /*send the mode 1 reset command*/ | |
561 | WREG32(offset, GFX_CTRL_CMD_ID_MODE1_RST); | |
562 | ||
38cd8a28 | 563 | msleep(500); |
654f761c FX |
564 | |
565 | offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_33); | |
566 | ||
567 | ret = psp_wait_for(psp, offset, 0x80000000, 0x80000000, false); | |
568 | ||
569 | if (ret) { | |
570 | DRM_INFO("psp mode 1 reset failed!\n"); | |
571 | return -EINVAL; | |
572 | } | |
573 | ||
574 | DRM_INFO("psp mode1 reset succeed \n"); | |
575 | ||
576 | return 0; | |
577 | } | |
578 | ||
367039bf TY |
579 | static int psp_v11_0_memory_training_send_msg(struct psp_context *psp, int msg) |
580 | { | |
581 | int ret; | |
582 | int i; | |
583 | uint32_t data_32; | |
584 | int max_wait; | |
585 | struct amdgpu_device *adev = psp->adev; | |
586 | ||
587 | data_32 = (psp->mem_train_ctx.c2p_train_data_offset >> 20); | |
588 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, data_32); | |
589 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, msg); | |
590 | ||
591 | max_wait = MEM_TRAIN_SEND_MSG_TIMEOUT_US / adev->usec_timeout; | |
592 | for (i = 0; i < max_wait; i++) { | |
593 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), | |
594 | 0x80000000, 0x80000000, false); | |
595 | if (ret == 0) | |
596 | break; | |
597 | } | |
598 | if (i < max_wait) | |
599 | ret = 0; | |
600 | else | |
601 | ret = -ETIME; | |
602 | ||
603 | DRM_DEBUG("training %s %s, cost %d @ %d ms\n", | |
604 | (msg == PSP_BL__DRAM_SHORT_TRAIN) ? "short" : "long", | |
605 | (ret == 0) ? "succeed" : "failed", | |
606 | i, adev->usec_timeout/1000); | |
607 | return ret; | |
608 | } | |
609 | ||
367039bf | 610 | /* |
4a497510 | 611 | * save and restore process |
367039bf TY |
612 | */ |
613 | static int psp_v11_0_memory_training(struct psp_context *psp, uint32_t ops) | |
614 | { | |
367039bf | 615 | struct psp_memory_training_context *ctx = &psp->mem_train_ctx; |
8acedab0 | 616 | uint32_t *pcache = (uint32_t *)ctx->sys_cache; |
240c811c TY |
617 | struct amdgpu_device *adev = psp->adev; |
618 | uint32_t p2c_header[4]; | |
619 | uint32_t sz; | |
620 | void *buf; | |
f89f8c6b | 621 | int ret, idx; |
367039bf TY |
622 | |
623 | if (ctx->init == PSP_MEM_TRAIN_NOT_SUPPORT) { | |
624 | DRM_DEBUG("Memory training is not supported.\n"); | |
625 | return 0; | |
626 | } else if (ctx->init != PSP_MEM_TRAIN_INIT_SUCCESS) { | |
627 | DRM_ERROR("Memory training initialization failure.\n"); | |
628 | return -EINVAL; | |
629 | } | |
630 | ||
631 | if (psp_v11_0_is_sos_alive(psp)) { | |
632 | DRM_DEBUG("SOS is alive, skip memory training.\n"); | |
633 | return 0; | |
634 | } | |
635 | ||
240c811c | 636 | amdgpu_device_vram_access(adev, ctx->p2c_train_data_offset, p2c_header, sizeof(p2c_header), false); |
367039bf TY |
637 | DRM_DEBUG("sys_cache[%08x,%08x,%08x,%08x] p2c_header[%08x,%08x,%08x,%08x]\n", |
638 | pcache[0], pcache[1], pcache[2], pcache[3], | |
639 | p2c_header[0], p2c_header[1], p2c_header[2], p2c_header[3]); | |
640 | ||
641 | if (ops & PSP_MEM_TRAIN_SEND_SHORT_MSG) { | |
642 | DRM_DEBUG("Short training depends on restore.\n"); | |
643 | ops |= PSP_MEM_TRAIN_RESTORE; | |
644 | } | |
645 | ||
646 | if ((ops & PSP_MEM_TRAIN_RESTORE) && | |
647 | pcache[0] != MEM_TRAIN_SYSTEM_SIGNATURE) { | |
648 | DRM_DEBUG("sys_cache[0] is invalid, restore depends on save.\n"); | |
649 | ops |= PSP_MEM_TRAIN_SAVE; | |
650 | } | |
651 | ||
652 | if (p2c_header[0] == MEM_TRAIN_SYSTEM_SIGNATURE && | |
653 | !(pcache[0] == MEM_TRAIN_SYSTEM_SIGNATURE && | |
654 | pcache[3] == p2c_header[3])) { | |
655 | DRM_DEBUG("sys_cache is invalid or out-of-date, need save training data to sys_cache.\n"); | |
656 | ops |= PSP_MEM_TRAIN_SAVE; | |
657 | } | |
658 | ||
659 | if ((ops & PSP_MEM_TRAIN_SAVE) && | |
660 | p2c_header[0] != MEM_TRAIN_SYSTEM_SIGNATURE) { | |
661 | DRM_DEBUG("p2c_header[0] is invalid, save depends on long training.\n"); | |
662 | ops |= PSP_MEM_TRAIN_SEND_LONG_MSG; | |
663 | } | |
664 | ||
665 | if (ops & PSP_MEM_TRAIN_SEND_LONG_MSG) { | |
666 | ops &= ~PSP_MEM_TRAIN_SEND_SHORT_MSG; | |
667 | ops |= PSP_MEM_TRAIN_SAVE; | |
668 | } | |
669 | ||
670 | DRM_DEBUG("Memory training ops:%x.\n", ops); | |
671 | ||
672 | if (ops & PSP_MEM_TRAIN_SEND_LONG_MSG) { | |
240c811c | 673 | /* |
7c4f2b23 BC |
674 | * Long training will encroach a certain amount on the bottom of VRAM; |
675 | * save the content from the bottom of VRAM to system memory | |
676 | * before training, and restore it after training to avoid | |
240c811c TY |
677 | * VRAM corruption. |
678 | */ | |
679 | sz = GDDR6_MEM_TRAINING_ENCROACHED_SIZE; | |
680 | ||
681 | if (adev->gmc.visible_vram_size < sz || !adev->mman.aper_base_kaddr) { | |
682 | DRM_ERROR("visible_vram_size %llx or aper_base_kaddr %p is not initialized.\n", | |
683 | adev->gmc.visible_vram_size, | |
684 | adev->mman.aper_base_kaddr); | |
685 | return -EINVAL; | |
686 | } | |
687 | ||
688 | buf = vmalloc(sz); | |
689 | if (!buf) { | |
690 | DRM_ERROR("failed to allocate system memory.\n"); | |
691 | return -ENOMEM; | |
692 | } | |
693 | ||
f89f8c6b AG |
694 | if (drm_dev_enter(&adev->ddev, &idx)) { |
695 | memcpy_fromio(buf, adev->mman.aper_base_kaddr, sz); | |
696 | ret = psp_v11_0_memory_training_send_msg(psp, PSP_BL__DRAM_LONG_TRAIN); | |
697 | if (ret) { | |
698 | DRM_ERROR("Send long training msg failed.\n"); | |
699 | vfree(buf); | |
700 | drm_dev_exit(idx); | |
701 | return ret; | |
702 | } | |
703 | ||
704 | memcpy_toio(adev->mman.aper_base_kaddr, buf, sz); | |
705 | adev->hdp.funcs->flush_hdp(adev, NULL); | |
240c811c | 706 | vfree(buf); |
f89f8c6b AG |
707 | drm_dev_exit(idx); |
708 | } else { | |
709 | vfree(buf); | |
710 | return -ENODEV; | |
367039bf TY |
711 | } |
712 | } | |
713 | ||
714 | if (ops & PSP_MEM_TRAIN_SAVE) { | |
715 | amdgpu_device_vram_access(psp->adev, ctx->p2c_train_data_offset, ctx->sys_cache, ctx->train_data_size, false); | |
716 | } | |
717 | ||
718 | if (ops & PSP_MEM_TRAIN_RESTORE) { | |
719 | amdgpu_device_vram_access(psp->adev, ctx->c2p_train_data_offset, ctx->sys_cache, ctx->train_data_size, true); | |
720 | } | |
721 | ||
722 | if (ops & PSP_MEM_TRAIN_SEND_SHORT_MSG) { | |
723 | ret = psp_v11_0_memory_training_send_msg(psp, (amdgpu_force_long_training > 0) ? | |
724 | PSP_BL__DRAM_LONG_TRAIN : PSP_BL__DRAM_SHORT_TRAIN); | |
725 | if (ret) { | |
726 | DRM_ERROR("send training msg failed.\n"); | |
727 | return ret; | |
728 | } | |
729 | } | |
730 | ctx->training_cnt++; | |
731 | return 0; | |
732 | } | |
733 | ||
13a390a6 HZ |
734 | static uint32_t psp_v11_0_ring_get_wptr(struct psp_context *psp) |
735 | { | |
736 | uint32_t data; | |
737 | struct amdgpu_device *adev = psp->adev; | |
738 | ||
a2676149 | 739 | if (amdgpu_sriov_vf(adev)) |
f1688bd6 | 740 | data = psp->km_ring.ring_wptr; |
13a390a6 HZ |
741 | else |
742 | data = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); | |
743 | ||
744 | return data; | |
745 | } | |
746 | ||
747 | static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value) | |
748 | { | |
749 | struct amdgpu_device *adev = psp->adev; | |
750 | ||
a2676149 | 751 | if (amdgpu_sriov_vf(adev)) { |
13a390a6 HZ |
752 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, value); |
753 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, GFX_CTRL_CMD_ID_CONSUME_CMD); | |
f1688bd6 | 754 | psp->km_ring.ring_wptr = value; |
13a390a6 HZ |
755 | } else |
756 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value); | |
757 | } | |
758 | ||
25a3e8ac | 759 | static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, uint64_t fw_pri_mc_addr) |
0dc93fd1 AG |
760 | { |
761 | struct amdgpu_device *adev = psp->adev; | |
762 | uint32_t reg_status; | |
763 | int ret, i = 0; | |
764 | ||
25a3e8ac AG |
765 | /* |
766 | * LFB address which is aligned to 1MB address and has to be | |
767 | * right-shifted by 20 so that LFB address can be passed on a 32-bit C2P | |
768 | * register | |
769 | */ | |
770 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, (fw_pri_mc_addr >> 20)); | |
0dc93fd1 AG |
771 | |
772 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), | |
773 | 0x80000000, 0x80000000, false); | |
774 | if (ret) | |
775 | return ret; | |
776 | ||
25a3e8ac AG |
777 | /* Fireup interrupt so PSP can pick up the address */ |
778 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, (GFX_CMD_USB_PD_USE_LFB << 16)); | |
0dc93fd1 AG |
779 | |
780 | /* FW load takes very long time */ | |
781 | do { | |
782 | msleep(1000); | |
783 | reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); | |
784 | ||
785 | if (reg_status & 0x80000000) | |
786 | goto done; | |
787 | ||
788 | } while (++i < USBC_PD_POLLING_LIMIT_S); | |
789 | ||
790 | return -ETIME; | |
791 | done: | |
792 | ||
793 | if ((reg_status & 0xFFFF) != 0) { | |
25a3e8ac | 794 | DRM_ERROR("Address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = 0x%04x\n", |
0dc93fd1 AG |
795 | reg_status & 0xFFFF); |
796 | return -EIO; | |
797 | } | |
798 | ||
799 | return 0; | |
800 | } | |
801 | ||
802 | static int psp_v11_0_read_usbc_pd_fw(struct psp_context *psp, uint32_t *fw_ver) | |
803 | { | |
804 | struct amdgpu_device *adev = psp->adev; | |
805 | int ret; | |
806 | ||
807 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, C2PMSG_CMD_GFX_USB_PD_FW_VER); | |
808 | ||
809 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), | |
810 | 0x80000000, 0x80000000, false); | |
811 | if (!ret) | |
812 | *fw_ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36); | |
813 | ||
814 | return ret; | |
815 | } | |
816 | ||
654f761c FX |
817 | static const struct psp_funcs psp_v11_0_funcs = { |
818 | .init_microcode = psp_v11_0_init_microcode, | |
42989359 | 819 | .bootloader_load_kdb = psp_v11_0_bootloader_load_kdb, |
70509057 | 820 | .bootloader_load_spl = psp_v11_0_bootloader_load_spl, |
654f761c FX |
821 | .bootloader_load_sysdrv = psp_v11_0_bootloader_load_sysdrv, |
822 | .bootloader_load_sos = psp_v11_0_bootloader_load_sos, | |
654f761c FX |
823 | .ring_init = psp_v11_0_ring_init, |
824 | .ring_create = psp_v11_0_ring_create, | |
825 | .ring_stop = psp_v11_0_ring_stop, | |
826 | .ring_destroy = psp_v11_0_ring_destroy, | |
654f761c | 827 | .mode1_reset = psp_v11_0_mode1_reset, |
367039bf | 828 | .mem_training = psp_v11_0_memory_training, |
13a390a6 HZ |
829 | .ring_get_wptr = psp_v11_0_ring_get_wptr, |
830 | .ring_set_wptr = psp_v11_0_ring_set_wptr, | |
0dc93fd1 AG |
831 | .load_usbc_pd_fw = psp_v11_0_load_usbc_pd_fw, |
832 | .read_usbc_pd_fw = psp_v11_0_read_usbc_pd_fw | |
654f761c FX |
833 | }; |
834 | ||
835 | void psp_v11_0_set_psp_funcs(struct psp_context *psp) | |
836 | { | |
837 | psp->funcs = &psp_v11_0_funcs; | |
838 | } |