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