]>
Commit | Line | Data |
---|---|---|
1060029f JZ |
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 | #include <linux/types.h> | |
24 | #include <linux/kernel.h> | |
25 | #include <linux/slab.h> | |
26 | #include <linux/gfp.h> | |
27 | ||
28 | #include "smumgr.h" | |
29 | #include "tonga_smumgr.h" | |
30 | #include "pp_debug.h" | |
31 | #include "smu_ucode_xfer_vi.h" | |
32 | #include "tonga_ppsmc.h" | |
33 | #include "smu/smu_7_1_2_d.h" | |
34 | #include "smu/smu_7_1_2_sh_mask.h" | |
35 | #include "cgs_common.h" | |
36 | ||
37 | #define TONGA_SMC_SIZE 0x20000 | |
38 | #define BUFFER_SIZE 80000 | |
39 | #define MAX_STRING_SIZE 15 | |
40 | #define BUFFER_SIZETWO 131072 /*128 *1024*/ | |
41 | ||
42 | /** | |
43 | * Set the address for reading/writing the SMC SRAM space. | |
44 | * @param smumgr the address of the powerplay hardware manager. | |
45 | * @param smcAddress the address in the SMC RAM to access. | |
46 | */ | |
47 | static int tonga_set_smc_sram_address(struct pp_smumgr *smumgr, | |
48 | uint32_t smcAddress, uint32_t limit) | |
49 | { | |
50 | if (smumgr == NULL || smumgr->device == NULL) | |
51 | return -EINVAL; | |
52 | PP_ASSERT_WITH_CODE((0 == (3 & smcAddress)), | |
53 | "SMC address must be 4 byte aligned.", | |
54 | return -1;); | |
55 | ||
56 | PP_ASSERT_WITH_CODE((limit > (smcAddress + 3)), | |
57 | "SMC address is beyond the SMC RAM area.", | |
58 | return -1;); | |
59 | ||
60 | cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, smcAddress); | |
61 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_11, 0); | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | /** | |
67 | * Copy bytes from an array into the SMC RAM space. | |
68 | * | |
69 | * @param smumgr the address of the powerplay SMU manager. | |
70 | * @param smcStartAddress the start address in the SMC RAM to copy bytes to. | |
71 | * @param src the byte array to copy the bytes from. | |
72 | * @param byteCount the number of bytes to copy. | |
73 | */ | |
74 | int tonga_copy_bytes_to_smc(struct pp_smumgr *smumgr, | |
75 | uint32_t smcStartAddress, const uint8_t *src, | |
76 | uint32_t byteCount, uint32_t limit) | |
77 | { | |
78 | uint32_t addr; | |
79 | uint32_t data, orig_data; | |
80 | int result = 0; | |
81 | uint32_t extra_shift; | |
82 | ||
83 | if (smumgr == NULL || smumgr->device == NULL) | |
84 | return -EINVAL; | |
85 | PP_ASSERT_WITH_CODE((0 == (3 & smcStartAddress)), | |
86 | "SMC address must be 4 byte aligned.", | |
87 | return 0;); | |
88 | ||
89 | PP_ASSERT_WITH_CODE((limit > (smcStartAddress + byteCount)), | |
90 | "SMC address is beyond the SMC RAM area.", | |
91 | return 0;); | |
92 | ||
93 | addr = smcStartAddress; | |
94 | ||
95 | while (byteCount >= 4) { | |
96 | /* | |
97 | * Bytes are written into the | |
98 | * SMC address space with the MSB first | |
99 | */ | |
100 | data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; | |
101 | ||
102 | result = tonga_set_smc_sram_address(smumgr, addr, limit); | |
103 | ||
104 | if (result) | |
105 | goto out; | |
106 | ||
107 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data); | |
108 | ||
109 | src += 4; | |
110 | byteCount -= 4; | |
111 | addr += 4; | |
112 | } | |
113 | ||
114 | if (0 != byteCount) { | |
115 | /* Now write odd bytes left, do a read modify write cycle */ | |
116 | data = 0; | |
117 | ||
118 | result = tonga_set_smc_sram_address(smumgr, addr, limit); | |
119 | if (result) | |
120 | goto out; | |
121 | ||
122 | orig_data = cgs_read_register(smumgr->device, | |
123 | mmSMC_IND_DATA_0); | |
124 | extra_shift = 8 * (4 - byteCount); | |
125 | ||
126 | while (byteCount > 0) { | |
127 | data = (data << 8) + *src++; | |
128 | byteCount--; | |
129 | } | |
130 | ||
131 | data <<= extra_shift; | |
132 | data |= (orig_data & ~((~0UL) << extra_shift)); | |
133 | ||
134 | result = tonga_set_smc_sram_address(smumgr, addr, limit); | |
135 | if (result) | |
136 | goto out; | |
137 | ||
138 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data); | |
139 | } | |
140 | ||
141 | out: | |
142 | return result; | |
143 | } | |
144 | ||
145 | ||
146 | int tonga_program_jump_on_start(struct pp_smumgr *smumgr) | |
147 | { | |
f498d9ed | 148 | static const unsigned char pData[] = { 0xE0, 0x00, 0x80, 0x40 }; |
1060029f JZ |
149 | |
150 | tonga_copy_bytes_to_smc(smumgr, 0x0, pData, 4, sizeof(pData)+1); | |
151 | ||
152 | return 0; | |
153 | } | |
154 | ||
155 | /** | |
156 | * Return if the SMC is currently running. | |
157 | * | |
158 | * @param smumgr the address of the powerplay hardware manager. | |
159 | */ | |
160 | static int tonga_is_smc_ram_running(struct pp_smumgr *smumgr) | |
161 | { | |
162 | return ((0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
163 | SMC_SYSCON_CLOCK_CNTL_0, ck_disable)) | |
164 | && (0x20100 <= cgs_read_ind_register(smumgr->device, | |
165 | CGS_IND_REG__SMC, ixSMC_PC_C))); | |
166 | } | |
167 | ||
168 | static int tonga_send_msg_to_smc_offset(struct pp_smumgr *smumgr) | |
169 | { | |
170 | if (smumgr == NULL || smumgr->device == NULL) | |
171 | return -EINVAL; | |
172 | ||
173 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
174 | ||
175 | cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, 0x20000); | |
176 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, PPSMC_MSG_Test); | |
177 | ||
178 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
179 | ||
180 | return 0; | |
181 | } | |
182 | ||
183 | /** | |
184 | * Send a message to the SMC, and wait for its response. | |
185 | * | |
186 | * @param smumgr the address of the powerplay hardware manager. | |
187 | * @param msg the message to send. | |
188 | * @return The response that came from the SMC. | |
189 | */ | |
190 | static int tonga_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg) | |
191 | { | |
192 | if (smumgr == NULL || smumgr->device == NULL) | |
193 | return -EINVAL; | |
194 | ||
195 | if (!tonga_is_smc_ram_running(smumgr)) | |
196 | return -1; | |
197 | ||
198 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
199 | PP_ASSERT_WITH_CODE( | |
200 | 1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP), | |
201 | "Failed to send Previous Message.", | |
f3b5cb3e | 202 | ); |
1060029f JZ |
203 | |
204 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg); | |
205 | ||
206 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
207 | PP_ASSERT_WITH_CODE( | |
208 | 1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP), | |
209 | "Failed to send Message.", | |
f3b5cb3e | 210 | ); |
1060029f JZ |
211 | |
212 | return 0; | |
213 | } | |
214 | ||
215 | /* | |
216 | * Send a message to the SMC, and do not wait for its response. | |
217 | * | |
218 | * @param smumgr the address of the powerplay hardware manager. | |
219 | * @param msg the message to send. | |
220 | * @return The response that came from the SMC. | |
221 | */ | |
222 | static int tonga_send_msg_to_smc_without_waiting | |
223 | (struct pp_smumgr *smumgr, uint16_t msg) | |
224 | { | |
225 | if (smumgr == NULL || smumgr->device == NULL) | |
226 | return -EINVAL; | |
227 | ||
228 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
229 | PP_ASSERT_WITH_CODE( | |
230 | 1 == SMUM_READ_FIELD(smumgr->device, SMC_RESP_0, SMC_RESP), | |
231 | "Failed to send Previous Message.", | |
f3b5cb3e | 232 | ); |
1060029f JZ |
233 | cgs_write_register(smumgr->device, mmSMC_MESSAGE_0, msg); |
234 | ||
235 | return 0; | |
236 | } | |
237 | ||
238 | /* | |
239 | * Send a message to the SMC with parameter | |
240 | * | |
241 | * @param smumgr: the address of the powerplay hardware manager. | |
242 | * @param msg: the message to send. | |
243 | * @param parameter: the parameter to send | |
244 | * @return The response that came from the SMC. | |
245 | */ | |
246 | static int tonga_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, | |
247 | uint16_t msg, uint32_t parameter) | |
248 | { | |
249 | if (smumgr == NULL || smumgr->device == NULL) | |
250 | return -EINVAL; | |
251 | ||
252 | if (!tonga_is_smc_ram_running(smumgr)) | |
253 | return PPSMC_Result_Failed; | |
254 | ||
255 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
256 | cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter); | |
257 | ||
258 | return tonga_send_msg_to_smc(smumgr, msg); | |
259 | } | |
260 | ||
261 | /* | |
262 | * Send a message to the SMC with parameter, do not wait for response | |
263 | * | |
264 | * @param smumgr: the address of the powerplay hardware manager. | |
265 | * @param msg: the message to send. | |
266 | * @param parameter: the parameter to send | |
267 | * @return The response that came from the SMC. | |
268 | */ | |
269 | static int tonga_send_msg_to_smc_with_parameter_without_waiting( | |
270 | struct pp_smumgr *smumgr, | |
271 | uint16_t msg, uint32_t parameter) | |
272 | { | |
273 | if (smumgr == NULL || smumgr->device == NULL) | |
274 | return -EINVAL; | |
275 | ||
276 | SMUM_WAIT_FIELD_UNEQUAL(smumgr, SMC_RESP_0, SMC_RESP, 0); | |
277 | ||
278 | cgs_write_register(smumgr->device, mmSMC_MSG_ARG_0, parameter); | |
279 | ||
280 | return tonga_send_msg_to_smc_without_waiting(smumgr, msg); | |
281 | } | |
282 | ||
283 | /* | |
284 | * Read a 32bit value from the SMC SRAM space. | |
285 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | |
286 | * @param smumgr the address of the powerplay hardware manager. | |
287 | * @param smcAddress the address in the SMC RAM to access. | |
288 | * @param value and output parameter for the data read from the SMC SRAM. | |
289 | */ | |
290 | int tonga_read_smc_sram_dword(struct pp_smumgr *smumgr, | |
291 | uint32_t smcAddress, uint32_t *value, | |
292 | uint32_t limit) | |
293 | { | |
294 | int result; | |
295 | ||
296 | result = tonga_set_smc_sram_address(smumgr, smcAddress, limit); | |
297 | ||
298 | if (0 != result) | |
299 | return result; | |
300 | ||
301 | *value = cgs_read_register(smumgr->device, mmSMC_IND_DATA_0); | |
302 | ||
303 | return 0; | |
304 | } | |
305 | ||
306 | /* | |
307 | * Write a 32bit value to the SMC SRAM space. | |
308 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | |
309 | * @param smumgr the address of the powerplay hardware manager. | |
310 | * @param smcAddress the address in the SMC RAM to access. | |
311 | * @param value to write to the SMC SRAM. | |
312 | */ | |
313 | int tonga_write_smc_sram_dword(struct pp_smumgr *smumgr, | |
314 | uint32_t smcAddress, uint32_t value, | |
315 | uint32_t limit) | |
316 | { | |
317 | int result; | |
318 | ||
319 | result = tonga_set_smc_sram_address(smumgr, smcAddress, limit); | |
320 | ||
321 | if (0 != result) | |
322 | return result; | |
323 | ||
324 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, value); | |
325 | ||
326 | return 0; | |
327 | } | |
328 | ||
329 | static int tonga_smu_fini(struct pp_smumgr *smumgr) | |
330 | { | |
86e4cdd6 ML |
331 | struct tonga_smumgr *priv = (struct tonga_smumgr *)(smumgr->backend); |
332 | ||
333 | smu_free_memory(smumgr->device, (void *)priv->smu_buffer.handle); | |
334 | smu_free_memory(smumgr->device, (void *)priv->header_buffer.handle); | |
335 | ||
1060029f JZ |
336 | if (smumgr->backend != NULL) { |
337 | kfree(smumgr->backend); | |
338 | smumgr->backend = NULL; | |
339 | } | |
5bbc16cc ML |
340 | |
341 | cgs_rel_firmware(smumgr->device, CGS_UCODE_ID_SMU); | |
1060029f JZ |
342 | return 0; |
343 | } | |
344 | ||
345 | static enum cgs_ucode_id tonga_convert_fw_type_to_cgs(uint32_t fw_type) | |
346 | { | |
347 | enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM; | |
348 | ||
349 | switch (fw_type) { | |
350 | case UCODE_ID_SMU: | |
351 | result = CGS_UCODE_ID_SMU; | |
352 | break; | |
353 | case UCODE_ID_SDMA0: | |
354 | result = CGS_UCODE_ID_SDMA0; | |
355 | break; | |
356 | case UCODE_ID_SDMA1: | |
357 | result = CGS_UCODE_ID_SDMA1; | |
358 | break; | |
359 | case UCODE_ID_CP_CE: | |
360 | result = CGS_UCODE_ID_CP_CE; | |
361 | break; | |
362 | case UCODE_ID_CP_PFP: | |
363 | result = CGS_UCODE_ID_CP_PFP; | |
364 | break; | |
365 | case UCODE_ID_CP_ME: | |
366 | result = CGS_UCODE_ID_CP_ME; | |
367 | break; | |
368 | case UCODE_ID_CP_MEC: | |
369 | result = CGS_UCODE_ID_CP_MEC; | |
370 | break; | |
371 | case UCODE_ID_CP_MEC_JT1: | |
372 | result = CGS_UCODE_ID_CP_MEC_JT1; | |
373 | break; | |
374 | case UCODE_ID_CP_MEC_JT2: | |
375 | result = CGS_UCODE_ID_CP_MEC_JT2; | |
376 | break; | |
377 | case UCODE_ID_RLC_G: | |
378 | result = CGS_UCODE_ID_RLC_G; | |
379 | break; | |
380 | default: | |
381 | break; | |
382 | } | |
383 | ||
384 | return result; | |
385 | } | |
386 | ||
387 | /** | |
388 | * Convert the PPIRI firmware type to SMU type mask. | |
389 | * For MEC, we need to check all MEC related type | |
390 | */ | |
391 | static uint16_t tonga_get_mask_for_firmware_type(uint16_t firmwareType) | |
392 | { | |
393 | uint16_t result = 0; | |
394 | ||
395 | switch (firmwareType) { | |
396 | case UCODE_ID_SDMA0: | |
397 | result = UCODE_ID_SDMA0_MASK; | |
398 | break; | |
399 | case UCODE_ID_SDMA1: | |
400 | result = UCODE_ID_SDMA1_MASK; | |
401 | break; | |
402 | case UCODE_ID_CP_CE: | |
403 | result = UCODE_ID_CP_CE_MASK; | |
404 | break; | |
405 | case UCODE_ID_CP_PFP: | |
406 | result = UCODE_ID_CP_PFP_MASK; | |
407 | break; | |
408 | case UCODE_ID_CP_ME: | |
409 | result = UCODE_ID_CP_ME_MASK; | |
410 | break; | |
411 | case UCODE_ID_CP_MEC: | |
412 | case UCODE_ID_CP_MEC_JT1: | |
413 | case UCODE_ID_CP_MEC_JT2: | |
414 | result = UCODE_ID_CP_MEC_MASK; | |
415 | break; | |
416 | case UCODE_ID_RLC_G: | |
417 | result = UCODE_ID_RLC_G_MASK; | |
418 | break; | |
419 | default: | |
420 | break; | |
421 | } | |
422 | ||
423 | return result; | |
424 | } | |
425 | ||
426 | /** | |
427 | * Check if the FW has been loaded, | |
428 | * SMU will not return if loading has not finished. | |
429 | */ | |
430 | static int tonga_check_fw_load_finish(struct pp_smumgr *smumgr, uint32_t fwType) | |
431 | { | |
432 | uint16_t fwMask = tonga_get_mask_for_firmware_type(fwType); | |
433 | ||
434 | if (0 != SMUM_WAIT_VFPF_INDIRECT_REGISTER(smumgr, SMC_IND, | |
435 | SOFT_REGISTERS_TABLE_28, fwMask, fwMask)) { | |
436 | printk(KERN_ERR "[ powerplay ] check firmware loading failed\n"); | |
437 | return -EINVAL; | |
438 | } | |
439 | ||
440 | return 0; | |
441 | } | |
442 | ||
443 | /* Populate one firmware image to the data structure */ | |
444 | static int tonga_populate_single_firmware_entry(struct pp_smumgr *smumgr, | |
445 | uint16_t firmware_type, | |
446 | struct SMU_Entry *pentry) | |
447 | { | |
448 | int result; | |
449 | struct cgs_firmware_info info = {0}; | |
450 | ||
451 | result = cgs_get_firmware_info( | |
452 | smumgr->device, | |
453 | tonga_convert_fw_type_to_cgs(firmware_type), | |
454 | &info); | |
455 | ||
456 | if (result == 0) { | |
457 | pentry->version = 0; | |
458 | pentry->id = (uint16_t)firmware_type; | |
459 | pentry->image_addr_high = smu_upper_32_bits(info.mc_addr); | |
460 | pentry->image_addr_low = smu_lower_32_bits(info.mc_addr); | |
461 | pentry->meta_data_addr_high = 0; | |
462 | pentry->meta_data_addr_low = 0; | |
463 | pentry->data_size_byte = info.image_size; | |
464 | pentry->num_register_entries = 0; | |
465 | ||
466 | if (firmware_type == UCODE_ID_RLC_G) | |
467 | pentry->flags = 1; | |
468 | else | |
469 | pentry->flags = 0; | |
470 | } else { | |
471 | return result; | |
472 | } | |
473 | ||
474 | return result; | |
475 | } | |
476 | ||
477 | static int tonga_request_smu_reload_fw(struct pp_smumgr *smumgr) | |
478 | { | |
479 | struct tonga_smumgr *tonga_smu = | |
480 | (struct tonga_smumgr *)(smumgr->backend); | |
481 | uint16_t fw_to_load; | |
482 | int result = 0; | |
483 | struct SMU_DRAMData_TOC *toc; | |
484 | /** | |
485 | * First time this gets called during SmuMgr init, | |
486 | * we haven't processed SMU header file yet, | |
487 | * so Soft Register Start offset is unknown. | |
488 | * However, for this case, UcodeLoadStatus is already 0, | |
489 | * so we can skip this if the Soft Registers Start offset is 0. | |
490 | */ | |
491 | cgs_write_ind_register(smumgr->device, | |
492 | CGS_IND_REG__SMC, ixSOFT_REGISTERS_TABLE_28, 0); | |
493 | ||
494 | tonga_send_msg_to_smc_with_parameter(smumgr, | |
495 | PPSMC_MSG_SMU_DRAM_ADDR_HI, | |
496 | tonga_smu->smu_buffer.mc_addr_high); | |
497 | tonga_send_msg_to_smc_with_parameter(smumgr, | |
498 | PPSMC_MSG_SMU_DRAM_ADDR_LO, | |
499 | tonga_smu->smu_buffer.mc_addr_low); | |
500 | ||
501 | toc = (struct SMU_DRAMData_TOC *)tonga_smu->pHeader; | |
502 | toc->num_entries = 0; | |
503 | toc->structure_version = 1; | |
504 | ||
505 | PP_ASSERT_WITH_CODE( | |
506 | 0 == tonga_populate_single_firmware_entry(smumgr, | |
507 | UCODE_ID_RLC_G, | |
508 | &toc->entry[toc->num_entries++]), | |
509 | "Failed to Get Firmware Entry.\n", | |
510 | return -1); | |
511 | PP_ASSERT_WITH_CODE( | |
512 | 0 == tonga_populate_single_firmware_entry(smumgr, | |
513 | UCODE_ID_CP_CE, | |
514 | &toc->entry[toc->num_entries++]), | |
515 | "Failed to Get Firmware Entry.\n", | |
516 | return -1); | |
517 | PP_ASSERT_WITH_CODE( | |
518 | 0 == tonga_populate_single_firmware_entry | |
519 | (smumgr, UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]), | |
520 | "Failed to Get Firmware Entry.\n", return -1); | |
521 | PP_ASSERT_WITH_CODE( | |
522 | 0 == tonga_populate_single_firmware_entry | |
523 | (smumgr, UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]), | |
524 | "Failed to Get Firmware Entry.\n", return -1); | |
525 | PP_ASSERT_WITH_CODE( | |
526 | 0 == tonga_populate_single_firmware_entry | |
527 | (smumgr, UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]), | |
528 | "Failed to Get Firmware Entry.\n", return -1); | |
529 | PP_ASSERT_WITH_CODE( | |
530 | 0 == tonga_populate_single_firmware_entry | |
531 | (smumgr, UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]), | |
532 | "Failed to Get Firmware Entry.\n", return -1); | |
533 | PP_ASSERT_WITH_CODE( | |
534 | 0 == tonga_populate_single_firmware_entry | |
535 | (smumgr, UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]), | |
536 | "Failed to Get Firmware Entry.\n", return -1); | |
537 | PP_ASSERT_WITH_CODE( | |
538 | 0 == tonga_populate_single_firmware_entry | |
539 | (smumgr, UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]), | |
540 | "Failed to Get Firmware Entry.\n", return -1); | |
541 | PP_ASSERT_WITH_CODE( | |
542 | 0 == tonga_populate_single_firmware_entry | |
543 | (smumgr, UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]), | |
544 | "Failed to Get Firmware Entry.\n", return -1); | |
545 | ||
546 | tonga_send_msg_to_smc_with_parameter(smumgr, | |
547 | PPSMC_MSG_DRV_DRAM_ADDR_HI, | |
548 | tonga_smu->header_buffer.mc_addr_high); | |
549 | tonga_send_msg_to_smc_with_parameter(smumgr, | |
550 | PPSMC_MSG_DRV_DRAM_ADDR_LO, | |
551 | tonga_smu->header_buffer.mc_addr_low); | |
552 | ||
553 | fw_to_load = UCODE_ID_RLC_G_MASK | |
554 | + UCODE_ID_SDMA0_MASK | |
555 | + UCODE_ID_SDMA1_MASK | |
556 | + UCODE_ID_CP_CE_MASK | |
557 | + UCODE_ID_CP_ME_MASK | |
558 | + UCODE_ID_CP_PFP_MASK | |
559 | + UCODE_ID_CP_MEC_MASK; | |
560 | ||
561 | PP_ASSERT_WITH_CODE( | |
562 | 0 == tonga_send_msg_to_smc_with_parameter_without_waiting( | |
563 | smumgr, PPSMC_MSG_LoadUcodes, fw_to_load), | |
564 | "Fail to Request SMU Load uCode", return 0); | |
565 | ||
566 | return result; | |
567 | } | |
568 | ||
569 | static int tonga_request_smu_load_specific_fw(struct pp_smumgr *smumgr, | |
570 | uint32_t firmwareType) | |
571 | { | |
572 | return 0; | |
573 | } | |
574 | ||
575 | /** | |
576 | * Upload the SMC firmware to the SMC microcontroller. | |
577 | * | |
578 | * @param smumgr the address of the powerplay hardware manager. | |
579 | * @param pFirmware the data structure containing the various sections of the firmware. | |
580 | */ | |
581 | static int tonga_smu_upload_firmware_image(struct pp_smumgr *smumgr) | |
582 | { | |
583 | const uint8_t *src; | |
584 | uint32_t byte_count; | |
585 | uint32_t *data; | |
586 | struct cgs_firmware_info info = {0}; | |
587 | ||
588 | if (smumgr == NULL || smumgr->device == NULL) | |
589 | return -EINVAL; | |
590 | ||
591 | cgs_get_firmware_info(smumgr->device, | |
592 | tonga_convert_fw_type_to_cgs(UCODE_ID_SMU), &info); | |
593 | ||
594 | if (info.image_size & 3) { | |
595 | printk(KERN_ERR "[ powerplay ] SMC ucode is not 4 bytes aligned\n"); | |
596 | return -EINVAL; | |
597 | } | |
598 | ||
599 | if (info.image_size > TONGA_SMC_SIZE) { | |
600 | printk(KERN_ERR "[ powerplay ] SMC address is beyond the SMC RAM area\n"); | |
601 | return -EINVAL; | |
602 | } | |
603 | ||
604 | cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, 0x20000); | |
605 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1); | |
606 | ||
607 | byte_count = info.image_size; | |
608 | src = (const uint8_t *)info.kptr; | |
609 | ||
610 | data = (uint32_t *)src; | |
611 | for (; byte_count >= 4; data++, byte_count -= 4) | |
612 | cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data[0]); | |
613 | ||
614 | SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | |
615 | ||
616 | return 0; | |
617 | } | |
618 | ||
619 | static int tonga_start_in_protection_mode(struct pp_smumgr *smumgr) | |
620 | { | |
621 | int result; | |
622 | ||
623 | /* Assert reset */ | |
624 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
625 | SMC_SYSCON_RESET_CNTL, rst_reg, 1); | |
626 | ||
627 | result = tonga_smu_upload_firmware_image(smumgr); | |
628 | if (result) | |
629 | return result; | |
630 | ||
631 | /* Clear status */ | |
632 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, | |
633 | ixSMU_STATUS, 0); | |
634 | ||
635 | /* Enable clock */ | |
636 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
637 | SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | |
638 | ||
639 | /* De-assert reset */ | |
640 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
641 | SMC_SYSCON_RESET_CNTL, rst_reg, 0); | |
642 | ||
643 | /* Set SMU Auto Start */ | |
644 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
645 | SMU_INPUT_DATA, AUTO_START, 1); | |
646 | ||
647 | /* Clear firmware interrupt enable flag */ | |
648 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, | |
649 | ixFIRMWARE_FLAGS, 0); | |
650 | ||
651 | SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, | |
652 | RCU_UC_EVENTS, INTERRUPTS_ENABLED, 1); | |
653 | ||
654 | /** | |
655 | * Call Test SMU message with 0x20000 offset to trigger SMU start | |
656 | */ | |
657 | tonga_send_msg_to_smc_offset(smumgr); | |
658 | ||
659 | /* Wait for done bit to be set */ | |
660 | SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, | |
661 | SMU_STATUS, SMU_DONE, 0); | |
662 | ||
663 | /* Check pass/failed indicator */ | |
664 | if (1 != SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, | |
665 | CGS_IND_REG__SMC, SMU_STATUS, SMU_PASS)) { | |
666 | printk(KERN_ERR "[ powerplay ] SMU Firmware start failed\n"); | |
667 | return -EINVAL; | |
668 | } | |
669 | ||
670 | /* Wait for firmware to initialize */ | |
671 | SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, | |
672 | FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1); | |
673 | ||
674 | return 0; | |
675 | } | |
676 | ||
677 | ||
678 | static int tonga_start_in_non_protection_mode(struct pp_smumgr *smumgr) | |
679 | { | |
680 | int result = 0; | |
681 | ||
682 | /* wait for smc boot up */ | |
683 | SMUM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND, | |
684 | RCU_UC_EVENTS, boot_seq_done, 0); | |
685 | ||
686 | /*Clear firmware interrupt enable flag*/ | |
687 | cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC, | |
688 | ixFIRMWARE_FLAGS, 0); | |
689 | ||
690 | ||
691 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
692 | SMC_SYSCON_RESET_CNTL, rst_reg, 1); | |
693 | ||
694 | result = tonga_smu_upload_firmware_image(smumgr); | |
695 | ||
696 | if (result != 0) | |
697 | return result; | |
698 | ||
699 | /* Set smc instruct start point at 0x0 */ | |
700 | tonga_program_jump_on_start(smumgr); | |
701 | ||
702 | ||
703 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
704 | SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | |
705 | ||
706 | /*De-assert reset*/ | |
707 | SMUM_WRITE_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
708 | SMC_SYSCON_RESET_CNTL, rst_reg, 0); | |
709 | ||
710 | /* Wait for firmware to initialize */ | |
711 | SMUM_WAIT_VFPF_INDIRECT_FIELD(smumgr, SMC_IND, | |
712 | FIRMWARE_FLAGS, INTERRUPTS_ENABLED, 1); | |
713 | ||
714 | return result; | |
715 | } | |
716 | ||
717 | static int tonga_start_smu(struct pp_smumgr *smumgr) | |
718 | { | |
719 | int result; | |
720 | ||
721 | /* Only start SMC if SMC RAM is not running */ | |
722 | if (!tonga_is_smc_ram_running(smumgr)) { | |
723 | /*Check if SMU is running in protected mode*/ | |
724 | if (0 == SMUM_READ_VFPF_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC, | |
725 | SMU_FIRMWARE, SMU_MODE)) { | |
726 | result = tonga_start_in_non_protection_mode(smumgr); | |
727 | if (result) | |
728 | return result; | |
729 | } else { | |
730 | result = tonga_start_in_protection_mode(smumgr); | |
731 | if (result) | |
732 | return result; | |
733 | } | |
734 | } | |
735 | ||
736 | result = tonga_request_smu_reload_fw(smumgr); | |
737 | ||
738 | return result; | |
739 | } | |
740 | ||
741 | /** | |
742 | * Write a 32bit value to the SMC SRAM space. | |
743 | * ALL PARAMETERS ARE IN HOST BYTE ORDER. | |
744 | * @param smumgr the address of the powerplay hardware manager. | |
745 | * @param smcAddress the address in the SMC RAM to access. | |
746 | * @param value to write to the SMC SRAM. | |
747 | */ | |
748 | static int tonga_smu_init(struct pp_smumgr *smumgr) | |
749 | { | |
750 | struct tonga_smumgr *tonga_smu; | |
751 | uint8_t *internal_buf; | |
752 | uint64_t mc_addr = 0; | |
753 | /* Allocate memory for backend private data */ | |
754 | tonga_smu = (struct tonga_smumgr *)(smumgr->backend); | |
755 | tonga_smu->header_buffer.data_size = | |
756 | ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; | |
757 | tonga_smu->smu_buffer.data_size = 200*4096; | |
758 | ||
759 | smu_allocate_memory(smumgr->device, | |
760 | tonga_smu->header_buffer.data_size, | |
761 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | |
762 | PAGE_SIZE, | |
763 | &mc_addr, | |
764 | &tonga_smu->header_buffer.kaddr, | |
765 | &tonga_smu->header_buffer.handle); | |
766 | ||
767 | tonga_smu->pHeader = tonga_smu->header_buffer.kaddr; | |
768 | tonga_smu->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); | |
769 | tonga_smu->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); | |
770 | ||
771 | PP_ASSERT_WITH_CODE((NULL != tonga_smu->pHeader), | |
772 | "Out of memory.", | |
773 | kfree(smumgr->backend); | |
774 | cgs_free_gpu_mem(smumgr->device, | |
775 | (cgs_handle_t)tonga_smu->header_buffer.handle); | |
776 | return -1); | |
777 | ||
778 | smu_allocate_memory(smumgr->device, | |
779 | tonga_smu->smu_buffer.data_size, | |
780 | CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, | |
781 | PAGE_SIZE, | |
782 | &mc_addr, | |
783 | &tonga_smu->smu_buffer.kaddr, | |
784 | &tonga_smu->smu_buffer.handle); | |
785 | ||
786 | internal_buf = tonga_smu->smu_buffer.kaddr; | |
787 | tonga_smu->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); | |
788 | tonga_smu->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); | |
789 | ||
790 | PP_ASSERT_WITH_CODE((NULL != internal_buf), | |
791 | "Out of memory.", | |
792 | kfree(smumgr->backend); | |
793 | cgs_free_gpu_mem(smumgr->device, | |
794 | (cgs_handle_t)tonga_smu->smu_buffer.handle); | |
795 | return -1;); | |
796 | ||
797 | return 0; | |
798 | } | |
799 | ||
800 | static const struct pp_smumgr_func tonga_smu_funcs = { | |
801 | .smu_init = &tonga_smu_init, | |
802 | .smu_fini = &tonga_smu_fini, | |
803 | .start_smu = &tonga_start_smu, | |
804 | .check_fw_load_finish = &tonga_check_fw_load_finish, | |
805 | .request_smu_load_fw = &tonga_request_smu_reload_fw, | |
806 | .request_smu_load_specific_fw = &tonga_request_smu_load_specific_fw, | |
807 | .send_msg_to_smc = &tonga_send_msg_to_smc, | |
808 | .send_msg_to_smc_with_parameter = &tonga_send_msg_to_smc_with_parameter, | |
809 | .download_pptable_settings = NULL, | |
810 | .upload_pptable_settings = NULL, | |
811 | }; | |
812 | ||
813 | int tonga_smum_init(struct pp_smumgr *smumgr) | |
814 | { | |
815 | struct tonga_smumgr *tonga_smu = NULL; | |
816 | ||
817 | tonga_smu = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL); | |
818 | ||
819 | if (tonga_smu == NULL) | |
c15c8d70 | 820 | return -ENOMEM; |
1060029f JZ |
821 | |
822 | smumgr->backend = tonga_smu; | |
823 | smumgr->smumgr_funcs = &tonga_smu_funcs; | |
824 | ||
825 | return 0; | |
826 | } |