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