diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/tonga_smc.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/tonga_smc.c | 852 |
1 files changed, 852 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_smc.c b/drivers/gpu/drm/amd/amdgpu/tonga_smc.c new file mode 100644 index 000000000000..5fc53a40c7ac --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/tonga_smc.c | |||
@@ -0,0 +1,852 @@ | |||
1 | /* | ||
2 | * Copyright 2014 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 | |||
24 | #include <linux/firmware.h> | ||
25 | #include "drmP.h" | ||
26 | #include "amdgpu.h" | ||
27 | #include "tonga_ppsmc.h" | ||
28 | #include "tonga_smumgr.h" | ||
29 | #include "smu_ucode_xfer_vi.h" | ||
30 | #include "amdgpu_ucode.h" | ||
31 | |||
32 | #include "smu/smu_7_1_2_d.h" | ||
33 | #include "smu/smu_7_1_2_sh_mask.h" | ||
34 | |||
35 | #define TONGA_SMC_SIZE 0x20000 | ||
36 | |||
37 | static int tonga_set_smc_sram_address(struct amdgpu_device *adev, uint32_t smc_address, uint32_t limit) | ||
38 | { | ||
39 | uint32_t val; | ||
40 | |||
41 | if (smc_address & 3) | ||
42 | return -EINVAL; | ||
43 | |||
44 | if ((smc_address + 3) > limit) | ||
45 | return -EINVAL; | ||
46 | |||
47 | WREG32(mmSMC_IND_INDEX_0, smc_address); | ||
48 | |||
49 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
50 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | ||
51 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static int tonga_copy_bytes_to_smc(struct amdgpu_device *adev, uint32_t smc_start_address, const uint8_t *src, uint32_t byte_count, uint32_t limit) | ||
57 | { | ||
58 | uint32_t addr; | ||
59 | uint32_t data, orig_data; | ||
60 | int result = 0; | ||
61 | uint32_t extra_shift; | ||
62 | unsigned long flags; | ||
63 | |||
64 | if (smc_start_address & 3) | ||
65 | return -EINVAL; | ||
66 | |||
67 | if ((smc_start_address + byte_count) > limit) | ||
68 | return -EINVAL; | ||
69 | |||
70 | addr = smc_start_address; | ||
71 | |||
72 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
73 | while (byte_count >= 4) { | ||
74 | /* Bytes are written into the SMC addres space with the MSB first */ | ||
75 | data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; | ||
76 | |||
77 | result = tonga_set_smc_sram_address(adev, addr, limit); | ||
78 | |||
79 | if (result) | ||
80 | goto out; | ||
81 | |||
82 | WREG32(mmSMC_IND_DATA_0, data); | ||
83 | |||
84 | src += 4; | ||
85 | byte_count -= 4; | ||
86 | addr += 4; | ||
87 | } | ||
88 | |||
89 | if (0 != byte_count) { | ||
90 | /* Now write odd bytes left, do a read modify write cycle */ | ||
91 | data = 0; | ||
92 | |||
93 | result = tonga_set_smc_sram_address(adev, addr, limit); | ||
94 | if (result) | ||
95 | goto out; | ||
96 | |||
97 | orig_data = RREG32(mmSMC_IND_DATA_0); | ||
98 | extra_shift = 8 * (4 - byte_count); | ||
99 | |||
100 | while (byte_count > 0) { | ||
101 | data = (data << 8) + *src++; | ||
102 | byte_count--; | ||
103 | } | ||
104 | |||
105 | data <<= extra_shift; | ||
106 | data |= (orig_data & ~((~0UL) << extra_shift)); | ||
107 | |||
108 | result = tonga_set_smc_sram_address(adev, addr, limit); | ||
109 | if (result) | ||
110 | goto out; | ||
111 | |||
112 | WREG32(mmSMC_IND_DATA_0, data); | ||
113 | } | ||
114 | |||
115 | out: | ||
116 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
117 | return result; | ||
118 | } | ||
119 | |||
120 | static int tonga_program_jump_on_start(struct amdgpu_device *adev) | ||
121 | { | ||
122 | static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40}; | ||
123 | tonga_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static bool tonga_is_smc_ram_running(struct amdgpu_device *adev) | ||
129 | { | ||
130 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
131 | val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable); | ||
132 | |||
133 | return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C))); | ||
134 | } | ||
135 | |||
136 | static int wait_smu_response(struct amdgpu_device *adev) | ||
137 | { | ||
138 | int i; | ||
139 | uint32_t val; | ||
140 | |||
141 | for (i = 0; i < adev->usec_timeout; i++) { | ||
142 | val = RREG32(mmSMC_RESP_0); | ||
143 | if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP)) | ||
144 | break; | ||
145 | udelay(1); | ||
146 | } | ||
147 | |||
148 | if (i == adev->usec_timeout) | ||
149 | return -EINVAL; | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int tonga_send_msg_to_smc_offset(struct amdgpu_device *adev) | ||
155 | { | ||
156 | if (wait_smu_response(adev)) { | ||
157 | DRM_ERROR("Failed to send previous message\n"); | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | WREG32(mmSMC_MSG_ARG_0, 0x20000); | ||
162 | WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_Test); | ||
163 | |||
164 | if (wait_smu_response(adev)) { | ||
165 | DRM_ERROR("Failed to send message\n"); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int tonga_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg) | ||
173 | { | ||
174 | if (!tonga_is_smc_ram_running(adev)) | ||
175 | { | ||
176 | return -EINVAL;; | ||
177 | } | ||
178 | |||
179 | if (wait_smu_response(adev)) { | ||
180 | DRM_ERROR("Failed to send previous message\n"); | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | WREG32(mmSMC_MESSAGE_0, msg); | ||
185 | |||
186 | if (wait_smu_response(adev)) { | ||
187 | DRM_ERROR("Failed to send message\n"); | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int tonga_send_msg_to_smc_without_waiting(struct amdgpu_device *adev, | ||
195 | PPSMC_Msg msg) | ||
196 | { | ||
197 | if (wait_smu_response(adev)) { | ||
198 | DRM_ERROR("Failed to send previous message\n"); | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | |||
202 | WREG32(mmSMC_MESSAGE_0, msg); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int tonga_send_msg_to_smc_with_parameter(struct amdgpu_device *adev, | ||
208 | PPSMC_Msg msg, | ||
209 | uint32_t parameter) | ||
210 | { | ||
211 | if (!tonga_is_smc_ram_running(adev)) | ||
212 | return -EINVAL; | ||
213 | |||
214 | if (wait_smu_response(adev)) { | ||
215 | DRM_ERROR("Failed to send previous message\n"); | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | WREG32(mmSMC_MSG_ARG_0, parameter); | ||
220 | |||
221 | return tonga_send_msg_to_smc(adev, msg); | ||
222 | } | ||
223 | |||
224 | static int tonga_send_msg_to_smc_with_parameter_without_waiting( | ||
225 | struct amdgpu_device *adev, | ||
226 | PPSMC_Msg msg, uint32_t parameter) | ||
227 | { | ||
228 | if (wait_smu_response(adev)) { | ||
229 | DRM_ERROR("Failed to send previous message\n"); | ||
230 | return -EINVAL; | ||
231 | } | ||
232 | |||
233 | WREG32(mmSMC_MSG_ARG_0, parameter); | ||
234 | |||
235 | return tonga_send_msg_to_smc_without_waiting(adev, msg); | ||
236 | } | ||
237 | |||
238 | #if 0 /* not used yet */ | ||
239 | static int tonga_wait_for_smc_inactive(struct amdgpu_device *adev) | ||
240 | { | ||
241 | int i; | ||
242 | uint32_t val; | ||
243 | |||
244 | if (!tonga_is_smc_ram_running(adev)) | ||
245 | return -EINVAL; | ||
246 | |||
247 | for (i = 0; i < adev->usec_timeout; i++) { | ||
248 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
249 | if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0) | ||
250 | break; | ||
251 | udelay(1); | ||
252 | } | ||
253 | |||
254 | if (i == adev->usec_timeout) | ||
255 | return -EINVAL; | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | #endif | ||
260 | |||
261 | static int tonga_smu_upload_firmware_image(struct amdgpu_device *adev) | ||
262 | { | ||
263 | const struct smc_firmware_header_v1_0 *hdr; | ||
264 | uint32_t ucode_size; | ||
265 | uint32_t ucode_start_address; | ||
266 | const uint8_t *src; | ||
267 | uint32_t val; | ||
268 | uint32_t byte_count; | ||
269 | uint32_t *data; | ||
270 | unsigned long flags; | ||
271 | |||
272 | if (!adev->pm.fw) | ||
273 | return -EINVAL; | ||
274 | |||
275 | hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data; | ||
276 | amdgpu_ucode_print_smc_hdr(&hdr->header); | ||
277 | |||
278 | adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version); | ||
279 | ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); | ||
280 | ucode_start_address = le32_to_cpu(hdr->ucode_start_addr); | ||
281 | src = (const uint8_t *) | ||
282 | (adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); | ||
283 | |||
284 | if (ucode_size & 3) { | ||
285 | DRM_ERROR("SMC ucode is not 4 bytes aligned\n"); | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | if (ucode_size > TONGA_SMC_SIZE) { | ||
290 | DRM_ERROR("SMC address is beyond the SMC RAM area\n"); | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | |||
294 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
295 | WREG32(mmSMC_IND_INDEX_0, ucode_start_address); | ||
296 | |||
297 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
298 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1); | ||
299 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
300 | |||
301 | byte_count = ucode_size; | ||
302 | data = (uint32_t *)src; | ||
303 | for (; byte_count >= 4; data++, byte_count -= 4) | ||
304 | WREG32(mmSMC_IND_DATA_0, data[0]); | ||
305 | |||
306 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
307 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | ||
308 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
309 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | #if 0 /* not used yet */ | ||
315 | static int tonga_read_smc_sram_dword(struct amdgpu_device *adev, | ||
316 | uint32_t smc_address, | ||
317 | uint32_t *value, | ||
318 | uint32_t limit) | ||
319 | { | ||
320 | int result; | ||
321 | unsigned long flags; | ||
322 | |||
323 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
324 | result = tonga_set_smc_sram_address(adev, smc_address, limit); | ||
325 | if (result == 0) | ||
326 | *value = RREG32(mmSMC_IND_DATA_0); | ||
327 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
328 | return result; | ||
329 | } | ||
330 | |||
331 | static int tonga_write_smc_sram_dword(struct amdgpu_device *adev, | ||
332 | uint32_t smc_address, | ||
333 | uint32_t value, | ||
334 | uint32_t limit) | ||
335 | { | ||
336 | int result; | ||
337 | unsigned long flags; | ||
338 | |||
339 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
340 | result = tonga_set_smc_sram_address(adev, smc_address, limit); | ||
341 | if (result == 0) | ||
342 | WREG32(mmSMC_IND_DATA_0, value); | ||
343 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
344 | return result; | ||
345 | } | ||
346 | |||
347 | static int tonga_smu_stop_smc(struct amdgpu_device *adev) | ||
348 | { | ||
349 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
350 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1); | ||
351 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
352 | |||
353 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
354 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1); | ||
355 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | #endif | ||
360 | |||
361 | static enum AMDGPU_UCODE_ID tonga_convert_fw_type(uint32_t fw_type) | ||
362 | { | ||
363 | switch (fw_type) { | ||
364 | case UCODE_ID_SDMA0: | ||
365 | return AMDGPU_UCODE_ID_SDMA0; | ||
366 | case UCODE_ID_SDMA1: | ||
367 | return AMDGPU_UCODE_ID_SDMA1; | ||
368 | case UCODE_ID_CP_CE: | ||
369 | return AMDGPU_UCODE_ID_CP_CE; | ||
370 | case UCODE_ID_CP_PFP: | ||
371 | return AMDGPU_UCODE_ID_CP_PFP; | ||
372 | case UCODE_ID_CP_ME: | ||
373 | return AMDGPU_UCODE_ID_CP_ME; | ||
374 | case UCODE_ID_CP_MEC: | ||
375 | case UCODE_ID_CP_MEC_JT1: | ||
376 | return AMDGPU_UCODE_ID_CP_MEC1; | ||
377 | case UCODE_ID_CP_MEC_JT2: | ||
378 | return AMDGPU_UCODE_ID_CP_MEC2; | ||
379 | case UCODE_ID_RLC_G: | ||
380 | return AMDGPU_UCODE_ID_RLC_G; | ||
381 | default: | ||
382 | DRM_ERROR("ucode type is out of range!\n"); | ||
383 | return AMDGPU_UCODE_ID_MAXIMUM; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | static int tonga_smu_populate_single_firmware_entry(struct amdgpu_device *adev, | ||
388 | uint32_t fw_type, | ||
389 | struct SMU_Entry *entry) | ||
390 | { | ||
391 | enum AMDGPU_UCODE_ID id = tonga_convert_fw_type(fw_type); | ||
392 | struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id]; | ||
393 | const struct gfx_firmware_header_v1_0 *header = NULL; | ||
394 | uint64_t gpu_addr; | ||
395 | uint32_t data_size; | ||
396 | |||
397 | if (ucode->fw == NULL) | ||
398 | return -EINVAL; | ||
399 | |||
400 | gpu_addr = ucode->mc_addr; | ||
401 | header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data; | ||
402 | data_size = le32_to_cpu(header->header.ucode_size_bytes); | ||
403 | |||
404 | if ((fw_type == UCODE_ID_CP_MEC_JT1) || | ||
405 | (fw_type == UCODE_ID_CP_MEC_JT2)) { | ||
406 | gpu_addr += le32_to_cpu(header->jt_offset) << 2; | ||
407 | data_size = le32_to_cpu(header->jt_size) << 2; | ||
408 | } | ||
409 | |||
410 | entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version); | ||
411 | entry->id = (uint16_t)fw_type; | ||
412 | entry->image_addr_high = upper_32_bits(gpu_addr); | ||
413 | entry->image_addr_low = lower_32_bits(gpu_addr); | ||
414 | entry->meta_data_addr_high = 0; | ||
415 | entry->meta_data_addr_low = 0; | ||
416 | entry->data_size_byte = data_size; | ||
417 | entry->num_register_entries = 0; | ||
418 | |||
419 | if (fw_type == UCODE_ID_RLC_G) | ||
420 | entry->flags = 1; | ||
421 | else | ||
422 | entry->flags = 0; | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static int tonga_smu_request_load_fw(struct amdgpu_device *adev) | ||
428 | { | ||
429 | struct tonga_smu_private_data *private = (struct tonga_smu_private_data *)adev->smu.priv; | ||
430 | struct SMU_DRAMData_TOC *toc; | ||
431 | uint32_t fw_to_load; | ||
432 | |||
433 | WREG32_SMC(ixSOFT_REGISTERS_TABLE_28, 0); | ||
434 | |||
435 | tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_HI, private->smu_buffer_addr_high); | ||
436 | tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_LO, private->smu_buffer_addr_low); | ||
437 | |||
438 | toc = (struct SMU_DRAMData_TOC *)private->header; | ||
439 | toc->num_entries = 0; | ||
440 | toc->structure_version = 1; | ||
441 | |||
442 | if (!adev->firmware.smu_load) | ||
443 | return 0; | ||
444 | |||
445 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G, | ||
446 | &toc->entry[toc->num_entries++])) { | ||
447 | DRM_ERROR("Failed to get firmware entry for RLC\n"); | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | |||
451 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE, | ||
452 | &toc->entry[toc->num_entries++])) { | ||
453 | DRM_ERROR("Failed to get firmware entry for CE\n"); | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | |||
457 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP, | ||
458 | &toc->entry[toc->num_entries++])) { | ||
459 | DRM_ERROR("Failed to get firmware entry for PFP\n"); | ||
460 | return -EINVAL; | ||
461 | } | ||
462 | |||
463 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME, | ||
464 | &toc->entry[toc->num_entries++])) { | ||
465 | DRM_ERROR("Failed to get firmware entry for ME\n"); | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | |||
469 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC, | ||
470 | &toc->entry[toc->num_entries++])) { | ||
471 | DRM_ERROR("Failed to get firmware entry for MEC\n"); | ||
472 | return -EINVAL; | ||
473 | } | ||
474 | |||
475 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1, | ||
476 | &toc->entry[toc->num_entries++])) { | ||
477 | DRM_ERROR("Failed to get firmware entry for MEC_JT1\n"); | ||
478 | return -EINVAL; | ||
479 | } | ||
480 | |||
481 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2, | ||
482 | &toc->entry[toc->num_entries++])) { | ||
483 | DRM_ERROR("Failed to get firmware entry for MEC_JT2\n"); | ||
484 | return -EINVAL; | ||
485 | } | ||
486 | |||
487 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0, | ||
488 | &toc->entry[toc->num_entries++])) { | ||
489 | DRM_ERROR("Failed to get firmware entry for SDMA0\n"); | ||
490 | return -EINVAL; | ||
491 | } | ||
492 | |||
493 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1, | ||
494 | &toc->entry[toc->num_entries++])) { | ||
495 | DRM_ERROR("Failed to get firmware entry for SDMA1\n"); | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | |||
499 | tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high); | ||
500 | tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low); | ||
501 | |||
502 | fw_to_load = UCODE_ID_RLC_G_MASK | | ||
503 | UCODE_ID_SDMA0_MASK | | ||
504 | UCODE_ID_SDMA1_MASK | | ||
505 | UCODE_ID_CP_CE_MASK | | ||
506 | UCODE_ID_CP_ME_MASK | | ||
507 | UCODE_ID_CP_PFP_MASK | | ||
508 | UCODE_ID_CP_MEC_MASK; | ||
509 | |||
510 | if (tonga_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) { | ||
511 | DRM_ERROR("Fail to request SMU load ucode\n"); | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | |||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static uint32_t tonga_smu_get_mask_for_fw_type(uint32_t fw_type) | ||
519 | { | ||
520 | switch (fw_type) { | ||
521 | case AMDGPU_UCODE_ID_SDMA0: | ||
522 | return UCODE_ID_SDMA0_MASK; | ||
523 | case AMDGPU_UCODE_ID_SDMA1: | ||
524 | return UCODE_ID_SDMA1_MASK; | ||
525 | case AMDGPU_UCODE_ID_CP_CE: | ||
526 | return UCODE_ID_CP_CE_MASK; | ||
527 | case AMDGPU_UCODE_ID_CP_PFP: | ||
528 | return UCODE_ID_CP_PFP_MASK; | ||
529 | case AMDGPU_UCODE_ID_CP_ME: | ||
530 | return UCODE_ID_CP_ME_MASK; | ||
531 | case AMDGPU_UCODE_ID_CP_MEC1: | ||
532 | return UCODE_ID_CP_MEC_MASK; | ||
533 | case AMDGPU_UCODE_ID_CP_MEC2: | ||
534 | return UCODE_ID_CP_MEC_MASK; | ||
535 | case AMDGPU_UCODE_ID_RLC_G: | ||
536 | return UCODE_ID_RLC_G_MASK; | ||
537 | default: | ||
538 | DRM_ERROR("ucode type is out of range!\n"); | ||
539 | return 0; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | static int tonga_smu_check_fw_load_finish(struct amdgpu_device *adev, | ||
544 | uint32_t fw_type) | ||
545 | { | ||
546 | uint32_t fw_mask = tonga_smu_get_mask_for_fw_type(fw_type); | ||
547 | int i; | ||
548 | |||
549 | for (i = 0; i < adev->usec_timeout; i++) { | ||
550 | if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_28) & fw_mask)) | ||
551 | break; | ||
552 | udelay(1); | ||
553 | } | ||
554 | |||
555 | if (i == adev->usec_timeout) { | ||
556 | DRM_ERROR("check firmware loading failed\n"); | ||
557 | return -EINVAL; | ||
558 | } | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static int tonga_smu_start_in_protection_mode(struct amdgpu_device *adev) | ||
564 | { | ||
565 | int result; | ||
566 | uint32_t val; | ||
567 | int i; | ||
568 | |||
569 | /* Assert reset */ | ||
570 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
571 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1); | ||
572 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
573 | |||
574 | result = tonga_smu_upload_firmware_image(adev); | ||
575 | if (result) | ||
576 | return result; | ||
577 | |||
578 | /* Clear status */ | ||
579 | WREG32_SMC(ixSMU_STATUS, 0); | ||
580 | |||
581 | /* Enable clock */ | ||
582 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
583 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | ||
584 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
585 | |||
586 | /* De-assert reset */ | ||
587 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
588 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0); | ||
589 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
590 | |||
591 | /* Set SMU Auto Start */ | ||
592 | val = RREG32_SMC(ixSMU_INPUT_DATA); | ||
593 | val = REG_SET_FIELD(val, SMU_INPUT_DATA, AUTO_START, 1); | ||
594 | WREG32_SMC(ixSMU_INPUT_DATA, val); | ||
595 | |||
596 | /* Clear firmware interrupt enable flag */ | ||
597 | WREG32_SMC(ixFIRMWARE_FLAGS, 0); | ||
598 | |||
599 | for (i = 0; i < adev->usec_timeout; i++) { | ||
600 | val = RREG32_SMC(ixRCU_UC_EVENTS); | ||
601 | if (REG_GET_FIELD(val, RCU_UC_EVENTS, INTERRUPTS_ENABLED)) | ||
602 | break; | ||
603 | udelay(1); | ||
604 | } | ||
605 | |||
606 | if (i == adev->usec_timeout) { | ||
607 | DRM_ERROR("Interrupt is not enabled by firmware\n"); | ||
608 | return -EINVAL; | ||
609 | } | ||
610 | |||
611 | /* Call Test SMU message with 0x20000 offset | ||
612 | * to trigger SMU start | ||
613 | */ | ||
614 | tonga_send_msg_to_smc_offset(adev); | ||
615 | |||
616 | /* Wait for done bit to be set */ | ||
617 | for (i = 0; i < adev->usec_timeout; i++) { | ||
618 | val = RREG32_SMC(ixSMU_STATUS); | ||
619 | if (REG_GET_FIELD(val, SMU_STATUS, SMU_DONE)) | ||
620 | break; | ||
621 | udelay(1); | ||
622 | } | ||
623 | |||
624 | if (i == adev->usec_timeout) { | ||
625 | DRM_ERROR("Timeout for SMU start\n"); | ||
626 | return -EINVAL; | ||
627 | } | ||
628 | |||
629 | /* Check pass/failed indicator */ | ||
630 | val = RREG32_SMC(ixSMU_STATUS); | ||
631 | if (!REG_GET_FIELD(val, SMU_STATUS, SMU_PASS)) { | ||
632 | DRM_ERROR("SMU Firmware start failed\n"); | ||
633 | return -EINVAL; | ||
634 | } | ||
635 | |||
636 | /* Wait for firmware to initialize */ | ||
637 | for (i = 0; i < adev->usec_timeout; i++) { | ||
638 | val = RREG32_SMC(ixFIRMWARE_FLAGS); | ||
639 | if(REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED)) | ||
640 | break; | ||
641 | udelay(1); | ||
642 | } | ||
643 | |||
644 | if (i == adev->usec_timeout) { | ||
645 | DRM_ERROR("SMU firmware initialization failed\n"); | ||
646 | return -EINVAL; | ||
647 | } | ||
648 | |||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static int tonga_smu_start_in_non_protection_mode(struct amdgpu_device *adev) | ||
653 | { | ||
654 | int i, result; | ||
655 | uint32_t val; | ||
656 | |||
657 | /* wait for smc boot up */ | ||
658 | for (i = 0; i < adev->usec_timeout; i++) { | ||
659 | val = RREG32_SMC(ixRCU_UC_EVENTS); | ||
660 | val = REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done); | ||
661 | if (val) | ||
662 | break; | ||
663 | udelay(1); | ||
664 | } | ||
665 | |||
666 | if (i == adev->usec_timeout) { | ||
667 | DRM_ERROR("SMC boot sequence is not completed\n"); | ||
668 | return -EINVAL; | ||
669 | } | ||
670 | |||
671 | /* Clear firmware interrupt enable flag */ | ||
672 | WREG32_SMC(ixFIRMWARE_FLAGS, 0); | ||
673 | |||
674 | /* Assert reset */ | ||
675 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
676 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1); | ||
677 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
678 | |||
679 | result = tonga_smu_upload_firmware_image(adev); | ||
680 | if (result) | ||
681 | return result; | ||
682 | |||
683 | /* Set smc instruct start point at 0x0 */ | ||
684 | tonga_program_jump_on_start(adev); | ||
685 | |||
686 | /* Enable clock */ | ||
687 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
688 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | ||
689 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
690 | |||
691 | /* De-assert reset */ | ||
692 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
693 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0); | ||
694 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
695 | |||
696 | /* Wait for firmware to initialize */ | ||
697 | for (i = 0; i < adev->usec_timeout; i++) { | ||
698 | val = RREG32_SMC(ixFIRMWARE_FLAGS); | ||
699 | if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED)) | ||
700 | break; | ||
701 | udelay(1); | ||
702 | } | ||
703 | |||
704 | if (i == adev->usec_timeout) { | ||
705 | DRM_ERROR("Timeout for SMC firmware initialization\n"); | ||
706 | return -EINVAL; | ||
707 | } | ||
708 | |||
709 | return 0; | ||
710 | } | ||
711 | |||
712 | int tonga_smu_start(struct amdgpu_device *adev) | ||
713 | { | ||
714 | int result; | ||
715 | uint32_t val; | ||
716 | |||
717 | if (!tonga_is_smc_ram_running(adev)) { | ||
718 | val = RREG32_SMC(ixSMU_FIRMWARE); | ||
719 | if (!REG_GET_FIELD(val, SMU_FIRMWARE, SMU_MODE)) { | ||
720 | result = tonga_smu_start_in_non_protection_mode(adev); | ||
721 | if (result) | ||
722 | return result; | ||
723 | } else { | ||
724 | result = tonga_smu_start_in_protection_mode(adev); | ||
725 | if (result) | ||
726 | return result; | ||
727 | } | ||
728 | } | ||
729 | |||
730 | return tonga_smu_request_load_fw(adev); | ||
731 | } | ||
732 | |||
733 | static const struct amdgpu_smumgr_funcs tonga_smumgr_funcs = { | ||
734 | .check_fw_load_finish = tonga_smu_check_fw_load_finish, | ||
735 | .request_smu_load_fw = NULL, | ||
736 | .request_smu_specific_fw = NULL, | ||
737 | }; | ||
738 | |||
739 | int tonga_smu_init(struct amdgpu_device *adev) | ||
740 | { | ||
741 | struct tonga_smu_private_data *private; | ||
742 | uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; | ||
743 | uint32_t smu_internal_buffer_size = 200*4096; | ||
744 | struct amdgpu_bo **toc_buf = &adev->smu.toc_buf; | ||
745 | struct amdgpu_bo **smu_buf = &adev->smu.smu_buf; | ||
746 | uint64_t mc_addr; | ||
747 | void *toc_buf_ptr; | ||
748 | void *smu_buf_ptr; | ||
749 | int ret; | ||
750 | |||
751 | private = kzalloc(sizeof(struct tonga_smu_private_data), GFP_KERNEL); | ||
752 | if (NULL == private) | ||
753 | return -ENOMEM; | ||
754 | |||
755 | /* allocate firmware buffers */ | ||
756 | if (adev->firmware.smu_load) | ||
757 | amdgpu_ucode_init_bo(adev); | ||
758 | |||
759 | adev->smu.priv = private; | ||
760 | adev->smu.fw_flags = 0; | ||
761 | |||
762 | /* Allocate FW image data structure and header buffer */ | ||
763 | ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE, | ||
764 | true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, toc_buf); | ||
765 | if (ret) { | ||
766 | DRM_ERROR("Failed to allocate memory for TOC buffer\n"); | ||
767 | return -ENOMEM; | ||
768 | } | ||
769 | |||
770 | /* Allocate buffer for SMU internal buffer */ | ||
771 | ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE, | ||
772 | true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, smu_buf); | ||
773 | if (ret) { | ||
774 | DRM_ERROR("Failed to allocate memory for SMU internal buffer\n"); | ||
775 | return -ENOMEM; | ||
776 | } | ||
777 | |||
778 | /* Retrieve GPU address for header buffer and internal buffer */ | ||
779 | ret = amdgpu_bo_reserve(adev->smu.toc_buf, false); | ||
780 | if (ret) { | ||
781 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
782 | DRM_ERROR("Failed to reserve the TOC buffer\n"); | ||
783 | return -EINVAL; | ||
784 | } | ||
785 | |||
786 | ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr); | ||
787 | if (ret) { | ||
788 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
789 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
790 | DRM_ERROR("Failed to pin the TOC buffer\n"); | ||
791 | return -EINVAL; | ||
792 | } | ||
793 | |||
794 | ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr); | ||
795 | if (ret) { | ||
796 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
797 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
798 | DRM_ERROR("Failed to map the TOC buffer\n"); | ||
799 | return -EINVAL; | ||
800 | } | ||
801 | |||
802 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
803 | private->header_addr_low = lower_32_bits(mc_addr); | ||
804 | private->header_addr_high = upper_32_bits(mc_addr); | ||
805 | private->header = toc_buf_ptr; | ||
806 | |||
807 | ret = amdgpu_bo_reserve(adev->smu.smu_buf, false); | ||
808 | if (ret) { | ||
809 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
810 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
811 | DRM_ERROR("Failed to reserve the SMU internal buffer\n"); | ||
812 | return -EINVAL; | ||
813 | } | ||
814 | |||
815 | ret = amdgpu_bo_pin(adev->smu.smu_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr); | ||
816 | if (ret) { | ||
817 | amdgpu_bo_unreserve(adev->smu.smu_buf); | ||
818 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
819 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
820 | DRM_ERROR("Failed to pin the SMU internal buffer\n"); | ||
821 | return -EINVAL; | ||
822 | } | ||
823 | |||
824 | ret = amdgpu_bo_kmap(*smu_buf, &smu_buf_ptr); | ||
825 | if (ret) { | ||
826 | amdgpu_bo_unreserve(adev->smu.smu_buf); | ||
827 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
828 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
829 | DRM_ERROR("Failed to map the SMU internal buffer\n"); | ||
830 | return -EINVAL; | ||
831 | } | ||
832 | |||
833 | amdgpu_bo_unreserve(adev->smu.smu_buf); | ||
834 | private->smu_buffer_addr_low = lower_32_bits(mc_addr); | ||
835 | private->smu_buffer_addr_high = upper_32_bits(mc_addr); | ||
836 | |||
837 | adev->smu.smumgr_funcs = &tonga_smumgr_funcs; | ||
838 | |||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | int tonga_smu_fini(struct amdgpu_device *adev) | ||
843 | { | ||
844 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
845 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
846 | kfree(adev->smu.priv); | ||
847 | adev->smu.priv = NULL; | ||
848 | if (adev->firmware.fw_buf) | ||
849 | amdgpu_ucode_fini_bo(adev); | ||
850 | |||
851 | return 0; | ||
852 | } | ||