1 | /* |
2 | * Copyright 2015 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 | |
25 | #include "pp_debug.h" |
26 | #include "smumgr.h" |
27 | #include "smu_ucode_xfer_vi.h" |
28 | #include "ppatomctrl.h" |
29 | #include "cgs_common.h" |
30 | #include "smu7_ppsmc.h" |
31 | #include "smu7_smumgr.h" |
32 | #include "smu7_common.h" |
33 | |
34 | #include "polaris10_pwrvirus.h" |
35 | |
36 | #define SMU7_SMC_SIZE 0x20000 |
37 | |
38 | static int smu7_set_smc_sram_address(struct pp_hwmgr *hwmgr, uint32_t smc_addr, uint32_t limit) |
39 | { |
40 | PP_ASSERT_WITH_CODE((0 == (3 & smc_addr)), "SMC address must be 4 byte aligned." , return -EINVAL); |
41 | PP_ASSERT_WITH_CODE((limit > (smc_addr + 3)), "SMC addr is beyond the SMC RAM area." , return -EINVAL); |
42 | |
43 | cgs_write_register(hwmgr->device, mmSMC_IND_INDEX_11, smc_addr); |
44 | PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0); /* on ci, SMC_IND_ACCESS_CNTL is different */ |
45 | return 0; |
46 | } |
47 | |
48 | |
49 | int smu7_copy_bytes_from_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address, uint32_t *dest, uint32_t byte_count, uint32_t limit) |
50 | { |
51 | uint32_t data; |
52 | uint32_t addr; |
53 | uint8_t *dest_byte; |
54 | uint8_t i, data_byte[4] = {0}; |
55 | uint32_t *pdata = (uint32_t *)&data_byte; |
56 | |
57 | PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned." , return -EINVAL); |
58 | PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area." , return -EINVAL); |
59 | |
60 | addr = smc_start_address; |
61 | |
62 | while (byte_count >= 4) { |
63 | smu7_read_smc_sram_dword(hwmgr, addr, &data, limit); |
64 | |
65 | *dest = PP_SMC_TO_HOST_UL(data); |
66 | |
67 | dest += 1; |
68 | byte_count -= 4; |
69 | addr += 4; |
70 | } |
71 | |
72 | if (byte_count) { |
73 | smu7_read_smc_sram_dword(hwmgr, addr, &data, limit); |
74 | *pdata = PP_SMC_TO_HOST_UL(data); |
75 | /* Cast dest into byte type in dest_byte. This way, we don't overflow if the allocated memory is not 4-byte aligned. */ |
76 | dest_byte = (uint8_t *)dest; |
77 | for (i = 0; i < byte_count; i++) |
78 | dest_byte[i] = data_byte[i]; |
79 | } |
80 | |
81 | return 0; |
82 | } |
83 | |
84 | |
85 | int smu7_copy_bytes_to_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address, |
86 | const uint8_t *src, uint32_t byte_count, uint32_t limit) |
87 | { |
88 | int result; |
89 | uint32_t data = 0; |
90 | uint32_t original_data; |
91 | uint32_t addr = 0; |
92 | uint32_t ; |
93 | |
94 | PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned." , return -EINVAL); |
95 | PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area." , return -EINVAL); |
96 | |
97 | addr = smc_start_address; |
98 | |
99 | while (byte_count >= 4) { |
100 | /* Bytes are written into the SMC addres space with the MSB first. */ |
101 | data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3]; |
102 | |
103 | result = smu7_set_smc_sram_address(hwmgr, addr, limit); |
104 | |
105 | if (0 != result) |
106 | return result; |
107 | |
108 | cgs_write_register(hwmgr->device, mmSMC_IND_DATA_11, data); |
109 | |
110 | src += 4; |
111 | byte_count -= 4; |
112 | addr += 4; |
113 | } |
114 | |
115 | if (0 != byte_count) { |
116 | |
117 | data = 0; |
118 | |
119 | result = smu7_set_smc_sram_address(hwmgr, addr, limit); |
120 | |
121 | if (0 != result) |
122 | return result; |
123 | |
124 | |
125 | original_data = cgs_read_register(hwmgr->device, mmSMC_IND_DATA_11); |
126 | |
127 | extra_shift = 8 * (4 - byte_count); |
128 | |
129 | while (byte_count > 0) { |
130 | /* Bytes are written into the SMC addres space with the MSB first. */ |
131 | data = (0x100 * data) + *src++; |
132 | byte_count--; |
133 | } |
134 | |
135 | data <<= extra_shift; |
136 | |
137 | data |= (original_data & ~((~0UL) << extra_shift)); |
138 | |
139 | result = smu7_set_smc_sram_address(hwmgr, addr, limit); |
140 | |
141 | if (0 != result) |
142 | return result; |
143 | |
144 | cgs_write_register(hwmgr->device, mmSMC_IND_DATA_11, data); |
145 | } |
146 | |
147 | return 0; |
148 | } |
149 | |
150 | |
151 | int smu7_program_jump_on_start(struct pp_hwmgr *hwmgr) |
152 | { |
153 | static const unsigned char data[4] = { 0xE0, 0x00, 0x80, 0x40 }; |
154 | |
155 | smu7_copy_bytes_to_smc(hwmgr, 0x0, data, 4, sizeof(data)+1); |
156 | |
157 | return 0; |
158 | } |
159 | |
160 | bool smu7_is_smc_ram_running(struct pp_hwmgr *hwmgr) |
161 | { |
162 | return ((0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable)) |
163 | && (0x20100 <= cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMC_PC_C))); |
164 | } |
165 | |
166 | int smu7_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) |
167 | { |
168 | int ret; |
169 | |
170 | PHM_WAIT_FIELD_UNEQUAL(hwmgr, SMC_RESP_0, SMC_RESP, 0); |
171 | |
172 | ret = PHM_READ_FIELD(hwmgr->device, SMC_RESP_0, SMC_RESP); |
173 | |
174 | if (ret == 0xFE) |
175 | pr_debug("last message was not supported\n" ); |
176 | else if (ret != 1) |
177 | pr_info("\n last message was failed ret is %d\n" , ret); |
178 | |
179 | cgs_write_register(hwmgr->device, mmSMC_RESP_0, 0); |
180 | cgs_write_register(hwmgr->device, mmSMC_MESSAGE_0, msg); |
181 | |
182 | PHM_WAIT_FIELD_UNEQUAL(hwmgr, SMC_RESP_0, SMC_RESP, 0); |
183 | |
184 | ret = PHM_READ_FIELD(hwmgr->device, SMC_RESP_0, SMC_RESP); |
185 | |
186 | if (ret == 0xFE) |
187 | pr_debug("message %x was not supported\n" , msg); |
188 | else if (ret != 1) |
189 | pr_info("\n failed to send message %x ret is %d \n" , msg, ret); |
190 | |
191 | return 0; |
192 | } |
193 | |
194 | int smu7_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, uint16_t msg) |
195 | { |
196 | cgs_write_register(hwmgr->device, mmSMC_MESSAGE_0, msg); |
197 | |
198 | return 0; |
199 | } |
200 | |
201 | int smu7_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter) |
202 | { |
203 | PHM_WAIT_FIELD_UNEQUAL(hwmgr, SMC_RESP_0, SMC_RESP, 0); |
204 | |
205 | cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, parameter); |
206 | |
207 | return smu7_send_msg_to_smc(hwmgr, msg); |
208 | } |
209 | |
210 | int smu7_send_msg_to_smc_with_parameter_without_waiting(struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter) |
211 | { |
212 | cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, parameter); |
213 | |
214 | return smu7_send_msg_to_smc_without_waiting(hwmgr, msg); |
215 | } |
216 | |
217 | int smu7_send_msg_to_smc_offset(struct pp_hwmgr *hwmgr) |
218 | { |
219 | cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, 0x20000); |
220 | |
221 | cgs_write_register(hwmgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test); |
222 | |
223 | PHM_WAIT_FIELD_UNEQUAL(hwmgr, SMC_RESP_0, SMC_RESP, 0); |
224 | |
225 | if (1 != PHM_READ_FIELD(hwmgr->device, SMC_RESP_0, SMC_RESP)) |
226 | pr_info("Failed to send Message.\n" ); |
227 | |
228 | return 0; |
229 | } |
230 | |
231 | enum cgs_ucode_id smu7_convert_fw_type_to_cgs(uint32_t fw_type) |
232 | { |
233 | enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM; |
234 | |
235 | switch (fw_type) { |
236 | case UCODE_ID_SMU: |
237 | result = CGS_UCODE_ID_SMU; |
238 | break; |
239 | case UCODE_ID_SMU_SK: |
240 | result = CGS_UCODE_ID_SMU_SK; |
241 | break; |
242 | case UCODE_ID_SDMA0: |
243 | result = CGS_UCODE_ID_SDMA0; |
244 | break; |
245 | case UCODE_ID_SDMA1: |
246 | result = CGS_UCODE_ID_SDMA1; |
247 | break; |
248 | case UCODE_ID_CP_CE: |
249 | result = CGS_UCODE_ID_CP_CE; |
250 | break; |
251 | case UCODE_ID_CP_PFP: |
252 | result = CGS_UCODE_ID_CP_PFP; |
253 | break; |
254 | case UCODE_ID_CP_ME: |
255 | result = CGS_UCODE_ID_CP_ME; |
256 | break; |
257 | case UCODE_ID_CP_MEC: |
258 | result = CGS_UCODE_ID_CP_MEC; |
259 | break; |
260 | case UCODE_ID_CP_MEC_JT1: |
261 | result = CGS_UCODE_ID_CP_MEC_JT1; |
262 | break; |
263 | case UCODE_ID_CP_MEC_JT2: |
264 | result = CGS_UCODE_ID_CP_MEC_JT2; |
265 | break; |
266 | case UCODE_ID_RLC_G: |
267 | result = CGS_UCODE_ID_RLC_G; |
268 | break; |
269 | case UCODE_ID_MEC_STORAGE: |
270 | result = CGS_UCODE_ID_STORAGE; |
271 | break; |
272 | default: |
273 | break; |
274 | } |
275 | |
276 | return result; |
277 | } |
278 | |
279 | |
280 | int smu7_read_smc_sram_dword(struct pp_hwmgr *hwmgr, uint32_t smc_addr, uint32_t *value, uint32_t limit) |
281 | { |
282 | int result; |
283 | |
284 | result = smu7_set_smc_sram_address(hwmgr, smc_addr, limit); |
285 | |
286 | *value = result ? 0 : cgs_read_register(hwmgr->device, mmSMC_IND_DATA_11); |
287 | |
288 | return result; |
289 | } |
290 | |
291 | int smu7_write_smc_sram_dword(struct pp_hwmgr *hwmgr, uint32_t smc_addr, uint32_t value, uint32_t limit) |
292 | { |
293 | int result; |
294 | |
295 | result = smu7_set_smc_sram_address(hwmgr, smc_addr, limit); |
296 | |
297 | if (result) |
298 | return result; |
299 | |
300 | cgs_write_register(hwmgr->device, mmSMC_IND_DATA_11, value); |
301 | |
302 | return 0; |
303 | } |
304 | |
305 | static int smu7_populate_single_firmware_entry(struct pp_hwmgr *hwmgr, |
306 | uint32_t fw_type, |
307 | struct SMU_Entry *entry) |
308 | { |
309 | int result = 0; |
310 | struct cgs_firmware_info info = {0}; |
311 | |
312 | result = cgs_get_firmware_info(hwmgr->device, |
313 | smu7_convert_fw_type_to_cgs(fw_type), |
314 | &info); |
315 | |
316 | if (!result) { |
317 | entry->version = info.fw_version; |
318 | entry->id = (uint16_t)fw_type; |
319 | entry->image_addr_high = upper_32_bits(info.mc_addr); |
320 | entry->image_addr_low = lower_32_bits(info.mc_addr); |
321 | entry->meta_data_addr_high = 0; |
322 | entry->meta_data_addr_low = 0; |
323 | |
324 | /* digest need be excluded out */ |
325 | if (!hwmgr->not_vf) |
326 | info.image_size -= 20; |
327 | entry->data_size_byte = info.image_size; |
328 | entry->num_register_entries = 0; |
329 | } |
330 | |
331 | if ((fw_type == UCODE_ID_RLC_G) |
332 | || (fw_type == UCODE_ID_CP_MEC)) |
333 | entry->flags = 1; |
334 | else |
335 | entry->flags = 0; |
336 | |
337 | return 0; |
338 | } |
339 | |
340 | int smu7_request_smu_load_fw(struct pp_hwmgr *hwmgr) |
341 | { |
342 | struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); |
343 | uint32_t fw_to_load; |
344 | int r = 0; |
345 | |
346 | amdgpu_ucode_init_bo(hwmgr->adev); |
347 | |
348 | if (smu_data->soft_regs_start) |
349 | cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, |
350 | smu_data->soft_regs_start + smum_get_offsetof(hwmgr, |
351 | SMU_SoftRegisters, UcodeLoadStatus), |
352 | 0x0); |
353 | |
354 | if (hwmgr->chip_id > CHIP_TOPAZ) { /* add support for Topaz */ |
355 | if (hwmgr->not_vf) { |
356 | smu7_send_msg_to_smc_with_parameter(hwmgr, |
357 | PPSMC_MSG_SMU_DRAM_ADDR_HI, |
358 | upper_32_bits(smu_data->smu_buffer.mc_addr)); |
359 | smu7_send_msg_to_smc_with_parameter(hwmgr, |
360 | PPSMC_MSG_SMU_DRAM_ADDR_LO, |
361 | lower_32_bits(smu_data->smu_buffer.mc_addr)); |
362 | } |
363 | fw_to_load = UCODE_ID_RLC_G_MASK |
364 | + UCODE_ID_SDMA0_MASK |
365 | + UCODE_ID_SDMA1_MASK |
366 | + UCODE_ID_CP_CE_MASK |
367 | + UCODE_ID_CP_ME_MASK |
368 | + UCODE_ID_CP_PFP_MASK |
369 | + UCODE_ID_CP_MEC_MASK; |
370 | } else { |
371 | fw_to_load = UCODE_ID_RLC_G_MASK |
372 | + UCODE_ID_SDMA0_MASK |
373 | + UCODE_ID_SDMA1_MASK |
374 | + UCODE_ID_CP_CE_MASK |
375 | + UCODE_ID_CP_ME_MASK |
376 | + UCODE_ID_CP_PFP_MASK |
377 | + UCODE_ID_CP_MEC_MASK |
378 | + UCODE_ID_CP_MEC_JT1_MASK |
379 | + UCODE_ID_CP_MEC_JT2_MASK; |
380 | } |
381 | |
382 | if (!smu_data->toc) { |
383 | struct SMU_DRAMData_TOC *toc; |
384 | |
385 | smu_data->toc = kzalloc(sizeof(struct SMU_DRAMData_TOC), GFP_KERNEL); |
386 | if (!smu_data->toc) |
387 | return -ENOMEM; |
388 | toc = smu_data->toc; |
389 | toc->num_entries = 0; |
390 | toc->structure_version = 1; |
391 | |
392 | PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, |
393 | UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]), |
394 | "Failed to Get Firmware Entry." , r = -EINVAL; goto failed); |
395 | PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, |
396 | UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]), |
397 | "Failed to Get Firmware Entry." , r = -EINVAL; goto failed); |
398 | PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, |
399 | UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]), |
400 | "Failed to Get Firmware Entry." , r = -EINVAL; goto failed); |
401 | PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, |
402 | UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]), |
403 | "Failed to Get Firmware Entry." , r = -EINVAL; goto failed); |
404 | PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, |
405 | UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]), |
406 | "Failed to Get Firmware Entry." , r = -EINVAL; goto failed); |
407 | PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, |
408 | UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]), |
409 | "Failed to Get Firmware Entry." , r = -EINVAL; goto failed); |
410 | PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, |
411 | UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]), |
412 | "Failed to Get Firmware Entry." , r = -EINVAL; goto failed); |
413 | PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, |
414 | UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]), |
415 | "Failed to Get Firmware Entry." , r = -EINVAL; goto failed); |
416 | PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, |
417 | UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]), |
418 | "Failed to Get Firmware Entry." , r = -EINVAL; goto failed); |
419 | if (!hwmgr->not_vf) |
420 | PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, |
421 | UCODE_ID_MEC_STORAGE, &toc->entry[toc->num_entries++]), |
422 | "Failed to Get Firmware Entry." , r = -EINVAL; goto failed); |
423 | } |
424 | memcpy_toio(smu_data->header_buffer.kaddr, smu_data->toc, |
425 | sizeof(struct SMU_DRAMData_TOC)); |
426 | smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, upper_32_bits(smu_data->header_buffer.mc_addr)); |
427 | smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DRV_DRAM_ADDR_LO, lower_32_bits(smu_data->header_buffer.mc_addr)); |
428 | |
429 | smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_LoadUcodes, fw_to_load); |
430 | |
431 | r = smu7_check_fw_load_finish(hwmgr, fw_to_load); |
432 | if (!r) |
433 | return 0; |
434 | |
435 | pr_err("SMU load firmware failed\n" ); |
436 | |
437 | failed: |
438 | kfree(smu_data->toc); |
439 | smu_data->toc = NULL; |
440 | return r; |
441 | } |
442 | |
443 | /* Check if the FW has been loaded, SMU will not return if loading has not finished. */ |
444 | int smu7_check_fw_load_finish(struct pp_hwmgr *hwmgr, uint32_t fw_type) |
445 | { |
446 | struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); |
447 | uint32_t ret; |
448 | |
449 | ret = phm_wait_on_indirect_register(hwmgr, mmSMC_IND_INDEX_11, |
450 | smu_data->soft_regs_start + smum_get_offsetof(hwmgr, |
451 | SMU_SoftRegisters, UcodeLoadStatus), |
452 | fw_type, fw_type); |
453 | return ret; |
454 | } |
455 | |
456 | int smu7_reload_firmware(struct pp_hwmgr *hwmgr) |
457 | { |
458 | return hwmgr->smumgr_funcs->start_smu(hwmgr); |
459 | } |
460 | |
461 | static int smu7_upload_smc_firmware_data(struct pp_hwmgr *hwmgr, uint32_t length, uint32_t *src, uint32_t limit) |
462 | { |
463 | uint32_t byte_count = length; |
464 | |
465 | PP_ASSERT_WITH_CODE((limit >= byte_count), "SMC address is beyond the SMC RAM area." , return -EINVAL); |
466 | |
467 | cgs_write_register(hwmgr->device, mmSMC_IND_INDEX_11, 0x20000); |
468 | PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 1); |
469 | |
470 | for (; byte_count >= 4; byte_count -= 4) |
471 | cgs_write_register(hwmgr->device, mmSMC_IND_DATA_11, *src++); |
472 | |
473 | PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0); |
474 | |
475 | PP_ASSERT_WITH_CODE((0 == byte_count), "SMC size must be divisible by 4." , return -EINVAL); |
476 | |
477 | return 0; |
478 | } |
479 | |
480 | |
481 | int smu7_upload_smu_firmware_image(struct pp_hwmgr *hwmgr) |
482 | { |
483 | int result = 0; |
484 | struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); |
485 | |
486 | struct cgs_firmware_info info = {0}; |
487 | |
488 | if (smu_data->security_hard_key == 1) |
489 | cgs_get_firmware_info(hwmgr->device, |
490 | smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), &info); |
491 | else |
492 | cgs_get_firmware_info(hwmgr->device, |
493 | smu7_convert_fw_type_to_cgs(UCODE_ID_SMU_SK), &info); |
494 | |
495 | hwmgr->is_kicker = info.is_kicker; |
496 | hwmgr->smu_version = info.version; |
497 | result = smu7_upload_smc_firmware_data(hwmgr, info.image_size, (uint32_t *)info.kptr, SMU7_SMC_SIZE); |
498 | |
499 | return result; |
500 | } |
501 | |
502 | static void execute_pwr_table(struct pp_hwmgr *hwmgr, const PWR_Command_Table *pvirus, int size) |
503 | { |
504 | int i; |
505 | uint32_t reg, data; |
506 | |
507 | for (i = 0; i < size; i++) { |
508 | reg = pvirus->reg; |
509 | data = pvirus->data; |
510 | if (reg != 0xffffffff) |
511 | cgs_write_register(hwmgr->device, reg, data); |
512 | else |
513 | break; |
514 | pvirus++; |
515 | } |
516 | } |
517 | |
518 | static void execute_pwr_dfy_table(struct pp_hwmgr *hwmgr, const PWR_DFY_Section *section) |
519 | { |
520 | int i; |
521 | |
522 | cgs_write_register(hwmgr->device, mmCP_DFY_CNTL, section->dfy_cntl); |
523 | cgs_write_register(hwmgr->device, mmCP_DFY_ADDR_HI, section->dfy_addr_hi); |
524 | cgs_write_register(hwmgr->device, mmCP_DFY_ADDR_LO, section->dfy_addr_lo); |
525 | for (i = 0; i < section->dfy_size; i++) |
526 | cgs_write_register(hwmgr->device, mmCP_DFY_DATA_0, section->dfy_data[i]); |
527 | } |
528 | |
529 | int smu7_setup_pwr_virus(struct pp_hwmgr *hwmgr) |
530 | { |
531 | execute_pwr_table(hwmgr, pwr_virus_table_pre, ARRAY_SIZE(pwr_virus_table_pre)); |
532 | execute_pwr_dfy_table(hwmgr, &pwr_virus_section1); |
533 | execute_pwr_dfy_table(hwmgr, &pwr_virus_section2); |
534 | execute_pwr_dfy_table(hwmgr, &pwr_virus_section3); |
535 | execute_pwr_dfy_table(hwmgr, &pwr_virus_section4); |
536 | execute_pwr_dfy_table(hwmgr, &pwr_virus_section5); |
537 | execute_pwr_dfy_table(hwmgr, &pwr_virus_section6); |
538 | execute_pwr_table(hwmgr, pwr_virus_table_post, ARRAY_SIZE(pwr_virus_table_post)); |
539 | |
540 | return 0; |
541 | } |
542 | |
543 | int smu7_init(struct pp_hwmgr *hwmgr) |
544 | { |
545 | struct smu7_smumgr *smu_data; |
546 | int r; |
547 | /* Allocate memory for backend private data */ |
548 | smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); |
549 | smu_data->header_buffer.data_size = |
550 | ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; |
551 | |
552 | /* Allocate FW image data structure and header buffer and |
553 | * send the header buffer address to SMU */ |
554 | r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
555 | smu_data->header_buffer.data_size, |
556 | PAGE_SIZE, |
557 | AMDGPU_GEM_DOMAIN_VRAM, |
558 | &smu_data->header_buffer.handle, |
559 | &smu_data->header_buffer.mc_addr, |
560 | &smu_data->header_buffer.kaddr); |
561 | |
562 | if (r) |
563 | return -EINVAL; |
564 | |
565 | if (!hwmgr->not_vf) |
566 | return 0; |
567 | |
568 | smu_data->smu_buffer.data_size = 200*4096; |
569 | r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, |
570 | smu_data->smu_buffer.data_size, |
571 | PAGE_SIZE, |
572 | AMDGPU_GEM_DOMAIN_VRAM, |
573 | &smu_data->smu_buffer.handle, |
574 | &smu_data->smu_buffer.mc_addr, |
575 | &smu_data->smu_buffer.kaddr); |
576 | |
577 | if (r) { |
578 | amdgpu_bo_free_kernel(&smu_data->header_buffer.handle, |
579 | &smu_data->header_buffer.mc_addr, |
580 | &smu_data->header_buffer.kaddr); |
581 | return -EINVAL; |
582 | } |
583 | |
584 | if (smum_is_hw_avfs_present(hwmgr) && |
585 | (hwmgr->feature_mask & PP_AVFS_MASK)) |
586 | hwmgr->avfs_supported = true; |
587 | |
588 | return 0; |
589 | } |
590 | |
591 | |
592 | int smu7_smu_fini(struct pp_hwmgr *hwmgr) |
593 | { |
594 | struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); |
595 | |
596 | amdgpu_bo_free_kernel(&smu_data->header_buffer.handle, |
597 | &smu_data->header_buffer.mc_addr, |
598 | &smu_data->header_buffer.kaddr); |
599 | |
600 | if (hwmgr->not_vf) |
601 | amdgpu_bo_free_kernel(&smu_data->smu_buffer.handle, |
602 | &smu_data->smu_buffer.mc_addr, |
603 | &smu_data->smu_buffer.kaddr); |
604 | |
605 | |
606 | kfree(smu_data->toc); |
607 | smu_data->toc = NULL; |
608 | kfree(hwmgr->smu_backend); |
609 | hwmgr->smu_backend = NULL; |
610 | return 0; |
611 | } |
612 | |