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