]>
Commit | Line | Data |
---|---|---|
0e5ca0d1 HR |
1 | /* |
2 | * Copyright 2016 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 | * Author: Huang Rui | |
23 | * | |
24 | */ | |
25 | ||
26 | #include <linux/firmware.h> | |
47b757fb SR |
27 | #include <linux/module.h> |
28 | #include <linux/pci.h> | |
29 | ||
0e5ca0d1 HR |
30 | #include "amdgpu.h" |
31 | #include "amdgpu_psp.h" | |
32 | #include "amdgpu_ucode.h" | |
33 | #include "soc15_common.h" | |
34 | #include "psp_v3_1.h" | |
35 | ||
a6651c98 FX |
36 | #include "mp/mp_9_0_offset.h" |
37 | #include "mp/mp_9_0_sh_mask.h" | |
cde5c34f | 38 | #include "gc/gc_9_0_offset.h" |
812f77b7 | 39 | #include "sdma0/sdma0_4_0_offset.h" |
f0a58aa3 | 40 | #include "nbio/nbio_6_1_offset.h" |
0e5ca0d1 | 41 | |
516bc3d8 CK |
42 | #include "oss/osssys_4_0_offset.h" |
43 | #include "oss/osssys_4_0_sh_mask.h" | |
44 | ||
0e5ca0d1 HR |
45 | MODULE_FIRMWARE("amdgpu/vega10_sos.bin"); |
46 | MODULE_FIRMWARE("amdgpu/vega10_asd.bin"); | |
ff13dc67 AD |
47 | MODULE_FIRMWARE("amdgpu/vega12_sos.bin"); |
48 | MODULE_FIRMWARE("amdgpu/vega12_asd.bin"); | |
8fd2d849 | 49 | |
0e5ca0d1 HR |
50 | |
51 | #define smnMP1_FIRMWARE_FLAGS 0x3010028 | |
52 | ||
23529390 HR |
53 | static uint32_t sos_old_versions[] = {1517616, 1510592, 1448594, 1446554}; |
54 | ||
7bd87769 TH |
55 | static bool psp_v3_1_support_vmr_ring(struct psp_context *psp); |
56 | static int psp_v3_1_ring_stop(struct psp_context *psp, | |
57 | enum psp_ring_type ring_type); | |
58 | ||
e7f9ccb4 | 59 | static int psp_v3_1_init_microcode(struct psp_context *psp) |
0e5ca0d1 HR |
60 | { |
61 | struct amdgpu_device *adev = psp->adev; | |
62 | const char *chip_name; | |
63 | char fw_name[30]; | |
64 | int err = 0; | |
65 | const struct psp_firmware_header_v1_0 *hdr; | |
66 | ||
67 | DRM_DEBUG("\n"); | |
68 | ||
69 | switch (adev->asic_type) { | |
70 | case CHIP_VEGA10: | |
71 | chip_name = "vega10"; | |
72 | break; | |
eddfa8df EQ |
73 | case CHIP_VEGA12: |
74 | chip_name = "vega12"; | |
75 | break; | |
0e5ca0d1 HR |
76 | default: BUG(); |
77 | } | |
78 | ||
79 | snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sos.bin", chip_name); | |
80 | err = request_firmware(&adev->psp.sos_fw, fw_name, adev->dev); | |
81 | if (err) | |
82 | goto out; | |
83 | ||
84 | err = amdgpu_ucode_validate(adev->psp.sos_fw); | |
85 | if (err) | |
86 | goto out; | |
87 | ||
88 | hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data; | |
89 | adev->psp.sos_fw_version = le32_to_cpu(hdr->header.ucode_version); | |
90 | adev->psp.sos_feature_version = le32_to_cpu(hdr->ucode_feature_version); | |
91 | adev->psp.sos_bin_size = le32_to_cpu(hdr->sos_size_bytes); | |
92 | adev->psp.sys_bin_size = le32_to_cpu(hdr->header.ucode_size_bytes) - | |
93 | le32_to_cpu(hdr->sos_size_bytes); | |
94 | adev->psp.sys_start_addr = (uint8_t *)hdr + | |
95 | le32_to_cpu(hdr->header.ucode_array_offset_bytes); | |
96 | adev->psp.sos_start_addr = (uint8_t *)adev->psp.sys_start_addr + | |
97 | le32_to_cpu(hdr->sos_offset_bytes); | |
98 | ||
99 | snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_asd.bin", chip_name); | |
100 | err = request_firmware(&adev->psp.asd_fw, fw_name, adev->dev); | |
101 | if (err) | |
102 | goto out; | |
103 | ||
104 | err = amdgpu_ucode_validate(adev->psp.asd_fw); | |
105 | if (err) | |
106 | goto out; | |
107 | ||
108 | hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.asd_fw->data; | |
109 | adev->psp.asd_fw_version = le32_to_cpu(hdr->header.ucode_version); | |
110 | adev->psp.asd_feature_version = le32_to_cpu(hdr->ucode_feature_version); | |
111 | adev->psp.asd_ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); | |
112 | adev->psp.asd_start_addr = (uint8_t *)hdr + | |
113 | le32_to_cpu(hdr->header.ucode_array_offset_bytes); | |
114 | ||
115 | return 0; | |
116 | out: | |
117 | if (err) { | |
118 | dev_err(adev->dev, | |
119 | "psp v3.1: Failed to load firmware \"%s\"\n", | |
120 | fw_name); | |
121 | release_firmware(adev->psp.sos_fw); | |
122 | adev->psp.sos_fw = NULL; | |
123 | release_firmware(adev->psp.asd_fw); | |
124 | adev->psp.asd_fw = NULL; | |
125 | } | |
126 | ||
127 | return err; | |
128 | } | |
129 | ||
e7f9ccb4 | 130 | static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp) |
0e5ca0d1 HR |
131 | { |
132 | int ret; | |
133 | uint32_t psp_gfxdrv_command_reg = 0; | |
0e5ca0d1 | 134 | struct amdgpu_device *adev = psp->adev; |
2b0c3aee | 135 | uint32_t sol_reg; |
6668b734 XY |
136 | |
137 | /* Check sOS sign of life register to confirm sys driver and sOS | |
138 | * are already been loaded. | |
139 | */ | |
3176810d | 140 | sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81); |
6668b734 XY |
141 | if (sol_reg) |
142 | return 0; | |
0e5ca0d1 HR |
143 | |
144 | /* Wait for bootloader to signify that is ready having bit 31 of C2PMSG_35 set to 1 */ | |
145 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), | |
146 | 0x80000000, 0x80000000, false); | |
147 | if (ret) | |
148 | return ret; | |
149 | ||
2b0c3aee | 150 | memset(psp->fw_pri_buf, 0, PSP_1_MEG); |
0e5ca0d1 HR |
151 | |
152 | /* Copy PSP System Driver binary to memory */ | |
2b0c3aee | 153 | memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size); |
0e5ca0d1 | 154 | |
548f2ecc | 155 | /* Provide the sys driver to bootloader */ |
3176810d | 156 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, |
2b0c3aee | 157 | (uint32_t)(psp->fw_pri_mc_addr >> 20)); |
3840fe25 | 158 | psp_gfxdrv_command_reg = PSP_BL__LOAD_SYSDRV; |
3176810d | 159 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, |
0e5ca0d1 HR |
160 | psp_gfxdrv_command_reg); |
161 | ||
162 | /* there might be handshake issue with hardware which needs delay */ | |
163 | mdelay(20); | |
164 | ||
165 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), | |
166 | 0x80000000, 0x80000000, false); | |
167 | ||
0e5ca0d1 HR |
168 | return ret; |
169 | } | |
170 | ||
23529390 HR |
171 | static bool psp_v3_1_match_version(struct amdgpu_device *adev, uint32_t ver) |
172 | { | |
173 | int i; | |
174 | ||
175 | if (ver == adev->psp.sos_fw_version) | |
176 | return true; | |
177 | ||
178 | /* | |
179 | * Double check if the latest four legacy versions. | |
180 | * If yes, it is still the right version. | |
181 | */ | |
182 | for (i = 0; i < sizeof(sos_old_versions) / sizeof(uint32_t); i++) { | |
183 | if (sos_old_versions[i] == adev->psp.sos_fw_version) | |
184 | return true; | |
185 | } | |
186 | ||
187 | return false; | |
188 | } | |
189 | ||
e7f9ccb4 | 190 | static int psp_v3_1_bootloader_load_sos(struct psp_context *psp) |
0e5ca0d1 HR |
191 | { |
192 | int ret; | |
193 | unsigned int psp_gfxdrv_command_reg = 0; | |
0e5ca0d1 | 194 | struct amdgpu_device *adev = psp->adev; |
23529390 | 195 | uint32_t sol_reg, ver; |
6668b734 XY |
196 | |
197 | /* Check sOS sign of life register to confirm sys driver and sOS | |
198 | * are already been loaded. | |
199 | */ | |
3176810d | 200 | sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81); |
e30c50cd ED |
201 | if (sol_reg) { |
202 | psp->sos_fw_version = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_58); | |
203 | printk("sos fw version = 0x%x.\n", psp->sos_fw_version); | |
6668b734 | 204 | return 0; |
e30c50cd | 205 | } |
0e5ca0d1 HR |
206 | |
207 | /* Wait for bootloader to signify that is ready having bit 31 of C2PMSG_35 set to 1 */ | |
208 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), | |
209 | 0x80000000, 0x80000000, false); | |
210 | if (ret) | |
211 | return ret; | |
212 | ||
2b0c3aee | 213 | memset(psp->fw_pri_buf, 0, PSP_1_MEG); |
0e5ca0d1 HR |
214 | |
215 | /* Copy Secure OS binary to PSP memory */ | |
2b0c3aee | 216 | memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size); |
0e5ca0d1 | 217 | |
548f2ecc | 218 | /* Provide the PSP secure OS to bootloader */ |
3176810d | 219 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, |
2b0c3aee | 220 | (uint32_t)(psp->fw_pri_mc_addr >> 20)); |
3840fe25 | 221 | psp_gfxdrv_command_reg = PSP_BL__LOAD_SOSDRV; |
3176810d | 222 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, |
0e5ca0d1 HR |
223 | psp_gfxdrv_command_reg); |
224 | ||
225 | /* there might be handshake issue with hardware which needs delay */ | |
226 | mdelay(20); | |
0e5ca0d1 | 227 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_81), |
3176810d | 228 | RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81), |
0e5ca0d1 | 229 | 0, true); |
0e5ca0d1 | 230 | |
23529390 HR |
231 | ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_58); |
232 | if (!psp_v3_1_match_version(adev, ver)) | |
233 | DRM_WARN("SOS version doesn't match\n"); | |
234 | ||
0e5ca0d1 HR |
235 | return ret; |
236 | } | |
237 | ||
e7f9ccb4 AD |
238 | static int psp_v3_1_ring_init(struct psp_context *psp, |
239 | enum psp_ring_type ring_type) | |
0e5ca0d1 HR |
240 | { |
241 | int ret = 0; | |
0e5ca0d1 HR |
242 | struct psp_ring *ring; |
243 | struct amdgpu_device *adev = psp->adev; | |
244 | ||
245 | ring = &psp->km_ring; | |
246 | ||
247 | ring->ring_type = ring_type; | |
248 | ||
249 | /* allocate 4k Page of Local Frame Buffer memory for ring */ | |
250 | ring->ring_size = 0x1000; | |
251 | ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE, | |
252 | AMDGPU_GEM_DOMAIN_VRAM, | |
253 | &adev->firmware.rbuf, | |
254 | &ring->ring_mem_mc_addr, | |
255 | (void **)&ring->ring_mem); | |
256 | if (ret) { | |
257 | ring->ring_size = 0; | |
258 | return ret; | |
259 | } | |
260 | ||
be70bbda HR |
261 | return 0; |
262 | } | |
263 | ||
516bc3d8 CK |
264 | static void psp_v3_1_reroute_ih(struct psp_context *psp) |
265 | { | |
266 | struct amdgpu_device *adev = psp->adev; | |
267 | uint32_t tmp; | |
268 | ||
269 | /* Change IH ring for VMC */ | |
270 | tmp = REG_SET_FIELD(0, IH_CLIENT_CFG_DATA, CREDIT_RETURN_ADDR, 0x1244b); | |
271 | tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, CLIENT_TYPE, 1); | |
272 | tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1); | |
273 | ||
274 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_69, 3); | |
275 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_70, tmp); | |
276 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, GFX_CTRL_CMD_ID_GBR_IH_SET); | |
277 | ||
278 | mdelay(20); | |
279 | psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64), | |
280 | 0x80000000, 0x8000FFFF, false); | |
281 | ||
282 | /* Change IH ring for UMC */ | |
283 | tmp = REG_SET_FIELD(0, IH_CLIENT_CFG_DATA, CREDIT_RETURN_ADDR, 0x1216b); | |
284 | tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1); | |
285 | ||
286 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_69, 4); | |
287 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_70, tmp); | |
288 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, GFX_CTRL_CMD_ID_GBR_IH_SET); | |
289 | ||
290 | mdelay(20); | |
291 | psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64), | |
292 | 0x80000000, 0x8000FFFF, false); | |
293 | } | |
294 | ||
e7f9ccb4 AD |
295 | static int psp_v3_1_ring_create(struct psp_context *psp, |
296 | enum psp_ring_type ring_type) | |
be70bbda HR |
297 | { |
298 | int ret = 0; | |
299 | unsigned int psp_ring_reg = 0; | |
300 | struct psp_ring *ring = &psp->km_ring; | |
301 | struct amdgpu_device *adev = psp->adev; | |
302 | ||
516bc3d8 CK |
303 | psp_v3_1_reroute_ih(psp); |
304 | ||
7bd87769 TH |
305 | if (psp_v3_1_support_vmr_ring(psp)) { |
306 | ret = psp_v3_1_ring_stop(psp, ring_type); | |
307 | if (ret) { | |
308 | DRM_ERROR("psp_v3_1_ring_stop_sriov failed!\n"); | |
309 | return ret; | |
310 | } | |
311 | ||
312 | /* Write low address of the ring to C2PMSG_102 */ | |
313 | psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr); | |
314 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_ring_reg); | |
315 | /* Write high address of the ring to C2PMSG_103 */ | |
316 | psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr); | |
317 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_103, psp_ring_reg); | |
318 | /* No size initialization for sriov */ | |
319 | /* Write the ring initialization command to C2PMSG_101 */ | |
320 | psp_ring_reg = ring_type; | |
321 | psp_ring_reg = psp_ring_reg << 16; | |
322 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, psp_ring_reg); | |
323 | ||
324 | /* there might be hardware handshake issue which needs delay */ | |
325 | mdelay(20); | |
326 | ||
327 | /* Wait for response flag (bit 31) in C2PMSG_101 */ | |
328 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, | |
329 | mmMP0_SMN_C2PMSG_101), 0x80000000, | |
330 | 0x8000FFFF, false); | |
331 | } else { | |
332 | ||
333 | /* Write low address of the ring to C2PMSG_69 */ | |
334 | psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr); | |
335 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_69, psp_ring_reg); | |
336 | /* Write high address of the ring to C2PMSG_70 */ | |
337 | psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr); | |
338 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_70, psp_ring_reg); | |
339 | /* Write size of ring to C2PMSG_71 */ | |
340 | psp_ring_reg = ring->ring_size; | |
341 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_71, psp_ring_reg); | |
342 | /* Write the ring initialization command to C2PMSG_64 */ | |
343 | psp_ring_reg = ring_type; | |
344 | psp_ring_reg = psp_ring_reg << 16; | |
345 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg); | |
346 | ||
347 | /* there might be hardware handshake issue which needs delay */ | |
348 | mdelay(20); | |
349 | ||
350 | /* Wait for response flag (bit 31) in C2PMSG_64 */ | |
351 | ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, | |
352 | mmMP0_SMN_C2PMSG_64), 0x80000000, | |
353 | 0x8000FFFF, false); | |
0e5ca0d1 | 354 | |
7bd87769 | 355 | } |
0e5ca0d1 HR |
356 | return ret; |
357 | } | |
358 | ||
e7f9ccb4 AD |
359 | static int psp_v3_1_ring_stop(struct psp_context *psp, |
360 | enum psp_ring_type ring_type) | |
e3c5e982 TH |
361 | { |
362 | int ret = 0; | |
e3c5e982 TH |
363 | unsigned int psp_ring_reg = 0; |
364 | struct amdgpu_device *adev = psp->adev; | |
365 | ||
7bd87769 TH |
366 | if (psp_v3_1_support_vmr_ring(psp)) { |
367 | /* Write the Destroy GPCOM ring command to C2PMSG_101 */ | |
368 | psp_ring_reg = GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING; | |
369 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, psp_ring_reg); | |
370 | ||
371 | /* there might be handshake issue which needs delay */ | |
372 | mdelay(20); | |
373 | ||
374 | /* Wait for response flag (bit 31) in C2PMSG_101 */ | |
375 | ret = psp_wait_for(psp, | |
376 | SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101), | |
377 | 0x80000000, 0x80000000, false); | |
378 | } else { | |
379 | /* Write the ring destroy command to C2PMSG_64 */ | |
380 | psp_ring_reg = 3 << 16; | |
381 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg); | |
382 | ||
383 | /* there might be handshake issue which needs delay */ | |
384 | mdelay(20); | |
385 | ||
386 | /* Wait for response flag (bit 31) in C2PMSG_64 */ | |
387 | ret = psp_wait_for(psp, | |
388 | SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64), | |
389 | 0x80000000, 0x80000000, false); | |
390 | } | |
e3c5e982 | 391 | |
4ef72453 EQ |
392 | return ret; |
393 | } | |
394 | ||
e7f9ccb4 AD |
395 | static int psp_v3_1_ring_destroy(struct psp_context *psp, |
396 | enum psp_ring_type ring_type) | |
4ef72453 EQ |
397 | { |
398 | int ret = 0; | |
399 | struct psp_ring *ring = &psp->km_ring; | |
400 | struct amdgpu_device *adev = psp->adev; | |
401 | ||
402 | ret = psp_v3_1_ring_stop(psp, ring_type); | |
403 | if (ret) | |
404 | DRM_ERROR("Fail to stop psp ring\n"); | |
405 | ||
edc4d3db HR |
406 | amdgpu_bo_free_kernel(&adev->firmware.rbuf, |
407 | &ring->ring_mem_mc_addr, | |
408 | (void **)&ring->ring_mem); | |
409 | ||
e3c5e982 TH |
410 | return ret; |
411 | } | |
412 | ||
e7f9ccb4 AD |
413 | static int psp_v3_1_cmd_submit(struct psp_context *psp, |
414 | struct amdgpu_firmware_info *ucode, | |
415 | uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, | |
416 | int index) | |
0e5ca0d1 HR |
417 | { |
418 | unsigned int psp_write_ptr_reg = 0; | |
419 | struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem; | |
420 | struct psp_ring *ring = &psp->km_ring; | |
4694257e EQ |
421 | struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; |
422 | struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + | |
423 | ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; | |
0e5ca0d1 HR |
424 | struct amdgpu_device *adev = psp->adev; |
425 | uint32_t ring_size_dw = ring->ring_size / 4; | |
426 | uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; | |
427 | ||
428 | /* KM (GPCOM) prepare write pointer */ | |
7bd87769 TH |
429 | if (psp_v3_1_support_vmr_ring(psp)) |
430 | psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102); | |
431 | else | |
432 | psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); | |
0e5ca0d1 HR |
433 | |
434 | /* Update KM RB frame pointer to new frame */ | |
435 | /* write_frame ptr increments by size of rb_frame in bytes */ | |
436 | /* psp_write_ptr_reg increments by size of rb_frame in DWORDs */ | |
437 | if ((psp_write_ptr_reg % ring_size_dw) == 0) | |
4694257e | 438 | write_frame = ring_buffer_start; |
0e5ca0d1 | 439 | else |
4694257e EQ |
440 | write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); |
441 | /* Check invalid write_frame ptr address */ | |
442 | if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { | |
443 | DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", | |
444 | ring_buffer_start, ring_buffer_end, write_frame); | |
445 | DRM_ERROR("write_frame is pointing to address out of bounds\n"); | |
446 | return -EINVAL; | |
447 | } | |
0e5ca0d1 HR |
448 | |
449 | /* Initialize KM RB frame */ | |
450 | memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); | |
451 | ||
452 | /* Update KM RB frame */ | |
f03defe0 AD |
453 | write_frame->cmd_buf_addr_hi = upper_32_bits(cmd_buf_mc_addr); |
454 | write_frame->cmd_buf_addr_lo = lower_32_bits(cmd_buf_mc_addr); | |
455 | write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); | |
456 | write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); | |
0e5ca0d1 HR |
457 | write_frame->fence_value = index; |
458 | ||
459 | /* Update the write Pointer in DWORDs */ | |
460 | psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; | |
7bd87769 TH |
461 | if (psp_v3_1_support_vmr_ring(psp)) { |
462 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_write_ptr_reg); | |
463 | /* send interrupt to PSP for SRIOV ring write pointer update */ | |
464 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, | |
465 | GFX_CTRL_CMD_ID_CONSUME_CMD); | |
466 | } else | |
467 | WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, psp_write_ptr_reg); | |
0e5ca0d1 HR |
468 | |
469 | return 0; | |
470 | } | |
471 | ||
472 | static int | |
cd29253f | 473 | psp_v3_1_sram_map(struct amdgpu_device *adev, |
e7f9ccb4 AD |
474 | unsigned int *sram_offset, unsigned int *sram_addr_reg_offset, |
475 | unsigned int *sram_data_reg_offset, | |
476 | enum AMDGPU_UCODE_ID ucode_id) | |
0e5ca0d1 HR |
477 | { |
478 | int ret = 0; | |
479 | ||
480 | switch(ucode_id) { | |
481 | /* TODO: needs to confirm */ | |
482 | #if 0 | |
483 | case AMDGPU_UCODE_ID_SMC: | |
484 | *sram_offset = 0; | |
485 | *sram_addr_reg_offset = 0; | |
486 | *sram_data_reg_offset = 0; | |
487 | break; | |
488 | #endif | |
489 | ||
490 | case AMDGPU_UCODE_ID_CP_CE: | |
491 | *sram_offset = 0x0; | |
492 | *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_CE_UCODE_ADDR); | |
493 | *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_CE_UCODE_DATA); | |
494 | break; | |
495 | ||
496 | case AMDGPU_UCODE_ID_CP_PFP: | |
497 | *sram_offset = 0x0; | |
498 | *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_PFP_UCODE_ADDR); | |
499 | *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_PFP_UCODE_DATA); | |
500 | break; | |
501 | ||
502 | case AMDGPU_UCODE_ID_CP_ME: | |
503 | *sram_offset = 0x0; | |
504 | *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_HYP_ME_UCODE_ADDR); | |
505 | *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_HYP_ME_UCODE_DATA); | |
506 | break; | |
507 | ||
508 | case AMDGPU_UCODE_ID_CP_MEC1: | |
509 | *sram_offset = 0x10000; | |
510 | *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_MEC_ME1_UCODE_ADDR); | |
511 | *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_MEC_ME1_UCODE_DATA); | |
512 | break; | |
513 | ||
514 | case AMDGPU_UCODE_ID_CP_MEC2: | |
515 | *sram_offset = 0x10000; | |
516 | *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_HYP_MEC2_UCODE_ADDR); | |
517 | *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_HYP_MEC2_UCODE_DATA); | |
518 | break; | |
519 | ||
520 | case AMDGPU_UCODE_ID_RLC_G: | |
521 | *sram_offset = 0x2000; | |
522 | *sram_addr_reg_offset = SOC15_REG_OFFSET(GC, 0, mmRLC_GPM_UCODE_ADDR); | |
523 | *sram_data_reg_offset = SOC15_REG_OFFSET(GC, 0, mmRLC_GPM_UCODE_DATA); | |
524 | break; | |
525 | ||
526 | case AMDGPU_UCODE_ID_SDMA0: | |
527 | *sram_offset = 0x0; | |
528 | *sram_addr_reg_offset = SOC15_REG_OFFSET(SDMA0, 0, mmSDMA0_UCODE_ADDR); | |
529 | *sram_data_reg_offset = SOC15_REG_OFFSET(SDMA0, 0, mmSDMA0_UCODE_DATA); | |
530 | break; | |
531 | ||
532 | /* TODO: needs to confirm */ | |
533 | #if 0 | |
534 | case AMDGPU_UCODE_ID_SDMA1: | |
535 | *sram_offset = ; | |
536 | *sram_addr_reg_offset = ; | |
537 | break; | |
538 | ||
539 | case AMDGPU_UCODE_ID_UVD: | |
540 | *sram_offset = ; | |
541 | *sram_addr_reg_offset = ; | |
542 | break; | |
543 | ||
544 | case AMDGPU_UCODE_ID_VCE: | |
545 | *sram_offset = ; | |
546 | *sram_addr_reg_offset = ; | |
547 | break; | |
548 | #endif | |
549 | ||
550 | case AMDGPU_UCODE_ID_MAXIMUM: | |
551 | default: | |
552 | ret = -EINVAL; | |
553 | break; | |
554 | } | |
555 | ||
556 | return ret; | |
557 | } | |
558 | ||
e7f9ccb4 AD |
559 | static bool psp_v3_1_compare_sram_data(struct psp_context *psp, |
560 | struct amdgpu_firmware_info *ucode, | |
561 | enum AMDGPU_UCODE_ID ucode_type) | |
0e5ca0d1 HR |
562 | { |
563 | int err = 0; | |
564 | unsigned int fw_sram_reg_val = 0; | |
565 | unsigned int fw_sram_addr_reg_offset = 0; | |
566 | unsigned int fw_sram_data_reg_offset = 0; | |
567 | unsigned int ucode_size; | |
568 | uint32_t *ucode_mem = NULL; | |
569 | struct amdgpu_device *adev = psp->adev; | |
570 | ||
cd29253f | 571 | err = psp_v3_1_sram_map(adev, &fw_sram_reg_val, &fw_sram_addr_reg_offset, |
0e5ca0d1 HR |
572 | &fw_sram_data_reg_offset, ucode_type); |
573 | if (err) | |
574 | return false; | |
575 | ||
576 | WREG32(fw_sram_addr_reg_offset, fw_sram_reg_val); | |
577 | ||
578 | ucode_size = ucode->ucode_size; | |
579 | ucode_mem = (uint32_t *)ucode->kaddr; | |
61a8cee5 | 580 | while (ucode_size) { |
0e5ca0d1 HR |
581 | fw_sram_reg_val = RREG32(fw_sram_data_reg_offset); |
582 | ||
583 | if (*ucode_mem != fw_sram_reg_val) | |
584 | return false; | |
585 | ||
586 | ucode_mem++; | |
587 | /* 4 bytes */ | |
588 | ucode_size -= 4; | |
589 | } | |
590 | ||
591 | return true; | |
592 | } | |
593 | ||
e7f9ccb4 | 594 | static bool psp_v3_1_smu_reload_quirk(struct psp_context *psp) |
0e5ca0d1 HR |
595 | { |
596 | struct amdgpu_device *adev = psp->adev; | |
8b5de0eb | 597 | uint32_t reg; |
0e5ca0d1 | 598 | |
76f8f699 | 599 | reg = RREG32_PCIE(smnMP1_FIRMWARE_FLAGS | 0x03b00000); |
8b5de0eb | 600 | return (reg & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) ? true : false; |
0e5ca0d1 | 601 | } |
98512bb8 | 602 | |
e7f9ccb4 | 603 | static int psp_v3_1_mode1_reset(struct psp_context *psp) |
98512bb8 KW |
604 | { |
605 | int ret; | |
606 | uint32_t offset; | |
607 | struct amdgpu_device *adev = psp->adev; | |
608 | ||
609 | offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64); | |
610 | ||
611 | ret = psp_wait_for(psp, offset, 0x80000000, 0x8000FFFF, false); | |
612 | ||
613 | if (ret) { | |
614 | DRM_INFO("psp is not working correctly before mode1 reset!\n"); | |
615 | return -EINVAL; | |
616 | } | |
617 | ||
618 | /*send the mode 1 reset command*/ | |
ccce29ab | 619 | WREG32(offset, GFX_CTRL_CMD_ID_MODE1_RST); |
98512bb8 | 620 | |
38cd8a28 | 621 | msleep(500); |
98512bb8 KW |
622 | |
623 | offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_33); | |
624 | ||
625 | ret = psp_wait_for(psp, offset, 0x80000000, 0x80000000, false); | |
626 | ||
627 | if (ret) { | |
628 | DRM_INFO("psp mode 1 reset failed!\n"); | |
629 | return -EINVAL; | |
630 | } | |
631 | ||
632 | DRM_INFO("psp mode1 reset succeed \n"); | |
633 | ||
634 | return 0; | |
635 | } | |
e7f9ccb4 | 636 | |
7bd87769 TH |
637 | static bool psp_v3_1_support_vmr_ring(struct psp_context *psp) |
638 | { | |
9244d3a6 | 639 | if (amdgpu_sriov_vf(psp->adev)) |
7bd87769 TH |
640 | return true; |
641 | ||
642 | return false; | |
643 | } | |
644 | ||
e7f9ccb4 AD |
645 | static const struct psp_funcs psp_v3_1_funcs = { |
646 | .init_microcode = psp_v3_1_init_microcode, | |
647 | .bootloader_load_sysdrv = psp_v3_1_bootloader_load_sysdrv, | |
648 | .bootloader_load_sos = psp_v3_1_bootloader_load_sos, | |
e7f9ccb4 AD |
649 | .ring_init = psp_v3_1_ring_init, |
650 | .ring_create = psp_v3_1_ring_create, | |
651 | .ring_stop = psp_v3_1_ring_stop, | |
652 | .ring_destroy = psp_v3_1_ring_destroy, | |
653 | .cmd_submit = psp_v3_1_cmd_submit, | |
654 | .compare_sram_data = psp_v3_1_compare_sram_data, | |
655 | .smu_reload_quirk = psp_v3_1_smu_reload_quirk, | |
656 | .mode1_reset = psp_v3_1_mode1_reset, | |
7bd87769 | 657 | .support_vmr_ring = psp_v3_1_support_vmr_ring, |
e7f9ccb4 AD |
658 | }; |
659 | ||
660 | void psp_v3_1_set_psp_funcs(struct psp_context *psp) | |
661 | { | |
662 | psp->funcs = &psp_v3_1_funcs; | |
663 | } |