]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
7737d5c6 | 2 | /* |
4e7b25e4 | 3 | * Copyright (C) 2006-2009 Freescale Semiconductor, Inc. |
7737d5c6 DL |
4 | * |
5 | * Dave Liu <[email protected]> | |
6 | * based on source code of Shlomi Gridish | |
7737d5c6 DL |
7 | */ |
8 | ||
b5bf5cb3 | 9 | #include <common.h> |
5aa03ddd | 10 | #include <malloc.h> |
b8ec2385 | 11 | #include <command.h> |
1221ce45 | 12 | #include <linux/errno.h> |
b5bf5cb3 MY |
13 | #include <asm/io.h> |
14 | #include <linux/immap_qe.h> | |
2459afb1 | 15 | #include <fsl_qe.h> |
c5e6637f | 16 | #include <mmc.h> |
3db71108 | 17 | #include <u-boot/crc.h> |
c5e6637f | 18 | |
73fb5838 | 19 | #ifdef CONFIG_ARCH_LS1021A |
9c7c86f4 ZQ |
20 | #include <asm/arch/immap_ls102xa.h> |
21 | #endif | |
c5e6637f RB |
22 | #ifdef CONFIG_ARM64 |
23 | #include <asm/armv8/mmu.h> | |
24 | #include <asm/arch/cpu.h> | |
5aa03ddd ZQ |
25 | #endif |
26 | ||
ca721fb2 ZQ |
27 | #define MPC85xx_DEVDISR_QE_DISABLE 0x1 |
28 | ||
7737d5c6 | 29 | qe_map_t *qe_immr = NULL; |
3bf46e6a | 30 | #ifdef CONFIG_QE |
7737d5c6 | 31 | static qe_snum_t snums[QE_NUM_OF_SNUM]; |
3bf46e6a | 32 | #endif |
7737d5c6 | 33 | |
1218abf1 WD |
34 | DECLARE_GLOBAL_DATA_PTR; |
35 | ||
7737d5c6 DL |
36 | void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data) |
37 | { | |
d3a6532c | 38 | u32 cecr; |
7737d5c6 DL |
39 | |
40 | if (cmd == QE_RESET) { | |
41 | out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG)); | |
42 | } else { | |
43 | out_be32(&qe_immr->cp.cecdr, cmd_data); | |
44 | out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG | | |
45 | ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd)); | |
46 | } | |
47 | /* Wait for the QE_CR_FLG to clear */ | |
48 | do { | |
49 | cecr = in_be32(&qe_immr->cp.cecr); | |
50 | } while (cecr & QE_CR_FLG); | |
51 | ||
52 | return; | |
53 | } | |
54 | ||
93d33204 | 55 | #ifdef CONFIG_QE |
7737d5c6 DL |
56 | uint qe_muram_alloc(uint size, uint align) |
57 | { | |
7737d5c6 DL |
58 | uint retloc; |
59 | uint align_mask, off; | |
60 | uint savebase; | |
61 | ||
62 | align_mask = align - 1; | |
45bae2e3 | 63 | savebase = gd->arch.mp_alloc_base; |
7737d5c6 | 64 | |
45bae2e3 SG |
65 | off = gd->arch.mp_alloc_base & align_mask; |
66 | if (off != 0) | |
67 | gd->arch.mp_alloc_base += (align - off); | |
7737d5c6 DL |
68 | |
69 | if ((off = size & align_mask) != 0) | |
70 | size += (align - off); | |
71 | ||
45bae2e3 SG |
72 | if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) { |
73 | gd->arch.mp_alloc_base = savebase; | |
7737d5c6 DL |
74 | printf("%s: ran out of ram.\n", __FUNCTION__); |
75 | } | |
76 | ||
45bae2e3 SG |
77 | retloc = gd->arch.mp_alloc_base; |
78 | gd->arch.mp_alloc_base += size; | |
7737d5c6 DL |
79 | |
80 | memset((void *)&qe_immr->muram[retloc], 0, size); | |
81 | ||
82 | __asm__ __volatile__("sync"); | |
83 | ||
84 | return retloc; | |
85 | } | |
93d33204 | 86 | #endif |
7737d5c6 DL |
87 | |
88 | void *qe_muram_addr(uint offset) | |
89 | { | |
90 | return (void *)&qe_immr->muram[offset]; | |
91 | } | |
92 | ||
3bf46e6a | 93 | #ifdef CONFIG_QE |
7737d5c6 DL |
94 | static void qe_sdma_init(void) |
95 | { | |
96 | volatile sdma_t *p; | |
97 | uint sdma_buffer_base; | |
98 | ||
99 | p = (volatile sdma_t *)&qe_immr->sdma; | |
100 | ||
101 | /* All of DMA transaction in bus 1 */ | |
102 | out_be32(&p->sdaqr, 0); | |
103 | out_be32(&p->sdaqmr, 0); | |
104 | ||
105 | /* Allocate 2KB temporary buffer for sdma */ | |
ff9658d7 | 106 | sdma_buffer_base = qe_muram_alloc(2048, 4096); |
7737d5c6 DL |
107 | out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK); |
108 | ||
109 | /* Clear sdma status */ | |
110 | out_be32(&p->sdsr, 0x03000000); | |
111 | ||
112 | /* Enable global mode on bus 1, and 2KB buffer size */ | |
113 | out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT)); | |
114 | } | |
115 | ||
4e7b25e4 HW |
116 | /* This table is a list of the serial numbers of the Threads, taken from the |
117 | * "SNUM Table" chart in the QE Reference Manual. The order is not important, | |
118 | * we just need to know what the SNUMs are for the threads. | |
119 | */ | |
120 | static u8 thread_snum[] = { | |
a88731a6 | 121 | /* Evthreads 16-29 are not supported in MPC8309 */ |
4bc97a3b | 122 | #if !defined(CONFIG_ARCH_MPC8309) |
7737d5c6 DL |
123 | 0x04, 0x05, 0x0c, 0x0d, |
124 | 0x14, 0x15, 0x1c, 0x1d, | |
125 | 0x24, 0x25, 0x2c, 0x2d, | |
a88731a6 GF |
126 | 0x34, 0x35, |
127 | #endif | |
128 | 0x88, 0x89, 0x98, 0x99, | |
129 | 0xa8, 0xa9, 0xb8, 0xb9, | |
130 | 0xc8, 0xc9, 0xd8, 0xd9, | |
131 | 0xe8, 0xe9, 0x08, 0x09, | |
132 | 0x18, 0x19, 0x28, 0x29, | |
133 | 0x38, 0x39, 0x48, 0x49, | |
134 | 0x58, 0x59, 0x68, 0x69, | |
135 | 0x78, 0x79, 0x80, 0x81 | |
7737d5c6 DL |
136 | }; |
137 | ||
138 | static void qe_snums_init(void) | |
139 | { | |
140 | int i; | |
141 | ||
142 | for (i = 0; i < QE_NUM_OF_SNUM; i++) { | |
143 | snums[i].state = QE_SNUM_STATE_FREE; | |
144 | snums[i].num = thread_snum[i]; | |
145 | } | |
146 | } | |
147 | ||
148 | int qe_get_snum(void) | |
149 | { | |
150 | int snum = -EBUSY; | |
151 | int i; | |
152 | ||
153 | for (i = 0; i < QE_NUM_OF_SNUM; i++) { | |
154 | if (snums[i].state == QE_SNUM_STATE_FREE) { | |
155 | snums[i].state = QE_SNUM_STATE_USED; | |
156 | snum = snums[i].num; | |
157 | break; | |
158 | } | |
159 | } | |
160 | ||
161 | return snum; | |
162 | } | |
163 | ||
164 | void qe_put_snum(u8 snum) | |
165 | { | |
166 | int i; | |
167 | ||
168 | for (i = 0; i < QE_NUM_OF_SNUM; i++) { | |
169 | if (snums[i].num == snum) { | |
170 | snums[i].state = QE_SNUM_STATE_FREE; | |
171 | break; | |
172 | } | |
173 | } | |
174 | } | |
175 | ||
c5e6637f RB |
176 | #ifdef CONFIG_TFABOOT |
177 | void qe_init(uint qe_base) | |
178 | { | |
179 | enum boot_src src = get_boot_src(); | |
180 | ||
181 | /* Init the QE IMMR base */ | |
182 | qe_immr = (qe_map_t *)qe_base; | |
183 | ||
184 | if (src == BOOT_SOURCE_IFC_NOR) { | |
185 | /* | |
186 | * Upload microcode to IRAM for those SOCs | |
187 | * which do not have ROM in QE. | |
188 | */ | |
189 | qe_upload_firmware((const void *)(CONFIG_SYS_QE_FW_ADDR + | |
190 | CONFIG_SYS_FSL_IFC_BASE)); | |
191 | ||
192 | /* enable the microcode in IRAM */ | |
193 | out_be32(&qe_immr->iram.iready, QE_IRAM_READY); | |
194 | } | |
195 | ||
196 | gd->arch.mp_alloc_base = QE_DATAONLY_BASE; | |
197 | gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE; | |
198 | ||
199 | qe_sdma_init(); | |
200 | qe_snums_init(); | |
201 | } | |
202 | #else | |
7737d5c6 DL |
203 | void qe_init(uint qe_base) |
204 | { | |
7737d5c6 DL |
205 | /* Init the QE IMMR base */ |
206 | qe_immr = (qe_map_t *)qe_base; | |
207 | ||
f2717b47 | 208 | #ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR |
c0a14aed WD |
209 | /* |
210 | * Upload microcode to IRAM for those SOCs which do not have ROM in QE. | |
211 | */ | |
dcf1d774 | 212 | qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR); |
2d4de6ae | 213 | |
c0a14aed WD |
214 | /* enable the microcode in IRAM */ |
215 | out_be32(&qe_immr->iram.iready,QE_IRAM_READY); | |
2d4de6ae HW |
216 | #endif |
217 | ||
45bae2e3 SG |
218 | gd->arch.mp_alloc_base = QE_DATAONLY_BASE; |
219 | gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE; | |
7737d5c6 DL |
220 | |
221 | qe_sdma_init(); | |
222 | qe_snums_init(); | |
223 | } | |
3bf46e6a | 224 | #endif |
c5e6637f | 225 | #endif |
7737d5c6 | 226 | |
93d33204 | 227 | #ifdef CONFIG_U_QE |
c5e6637f RB |
228 | #ifdef CONFIG_TFABOOT |
229 | void u_qe_init(void) | |
230 | { | |
231 | enum boot_src src = get_boot_src(); | |
232 | ||
233 | qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET); | |
234 | ||
235 | void *addr = (void *)CONFIG_SYS_QE_FW_ADDR; | |
236 | ||
237 | if (src == BOOT_SOURCE_IFC_NOR) | |
238 | addr = (void *)(CONFIG_SYS_QE_FW_ADDR + CONFIG_SYS_FSL_IFC_BASE); | |
239 | ||
240 | if (src == BOOT_SOURCE_QSPI_NOR) | |
241 | addr = (void *)(CONFIG_SYS_QE_FW_ADDR + CONFIG_SYS_FSL_QSPI_BASE); | |
242 | ||
243 | if (src == BOOT_SOURCE_SD_MMC) { | |
244 | int dev = CONFIG_SYS_MMC_ENV_DEV; | |
245 | u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512; | |
246 | u32 blk = CONFIG_SYS_QE_FW_ADDR / 512; | |
247 | ||
248 | if (mmc_initialize(gd->bd)) { | |
249 | printf("%s: mmc_initialize() failed\n", __func__); | |
250 | return; | |
251 | } | |
252 | addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); | |
253 | struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); | |
254 | ||
255 | if (!mmc) { | |
256 | free(addr); | |
257 | printf("\nMMC cannot find device for ucode\n"); | |
258 | } else { | |
259 | printf("\nMMC read: dev # %u, block # %u, count %u ...\n", | |
260 | dev, blk, cnt); | |
261 | mmc_init(mmc); | |
262 | (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt, | |
263 | addr); | |
264 | } | |
265 | } | |
266 | if (!u_qe_upload_firmware(addr)) | |
267 | out_be32(&qe_immr->iram.iready, QE_IRAM_READY); | |
268 | if (src == BOOT_SOURCE_SD_MMC) | |
269 | free(addr); | |
270 | } | |
271 | #else | |
93d33204 ZQ |
272 | void u_qe_init(void) |
273 | { | |
d3e6d30c | 274 | qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET); |
93d33204 | 275 | |
5aa03ddd ZQ |
276 | void *addr = (void *)CONFIG_SYS_QE_FW_ADDR; |
277 | #ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC | |
278 | int dev = CONFIG_SYS_MMC_ENV_DEV; | |
279 | u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512; | |
280 | u32 blk = CONFIG_SYS_QE_FW_ADDR / 512; | |
281 | ||
282 | if (mmc_initialize(gd->bd)) { | |
283 | printf("%s: mmc_initialize() failed\n", __func__); | |
284 | return; | |
285 | } | |
286 | addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); | |
287 | struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); | |
288 | ||
289 | if (!mmc) { | |
290 | free(addr); | |
291 | printf("\nMMC cannot find device for ucode\n"); | |
292 | } else { | |
293 | printf("\nMMC read: dev # %u, block # %u, count %u ...\n", | |
294 | dev, blk, cnt); | |
295 | mmc_init(mmc); | |
c3ced8a6 | 296 | (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt, |
5aa03ddd | 297 | addr); |
5aa03ddd ZQ |
298 | } |
299 | #endif | |
a7a81756 ZQ |
300 | if (!u_qe_upload_firmware(addr)) |
301 | out_be32(&qe_immr->iram.iready, QE_IRAM_READY); | |
5aa03ddd ZQ |
302 | #ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC |
303 | free(addr); | |
304 | #endif | |
93d33204 ZQ |
305 | } |
306 | #endif | |
c5e6637f | 307 | #endif |
93d33204 | 308 | |
ae42eb03 ZQ |
309 | #ifdef CONFIG_U_QE |
310 | void u_qe_resume(void) | |
311 | { | |
312 | qe_map_t *qe_immrr; | |
ae42eb03 | 313 | |
d3e6d30c | 314 | qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET); |
ae42eb03 ZQ |
315 | u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr); |
316 | out_be32(&qe_immrr->iram.iready, QE_IRAM_READY); | |
317 | } | |
318 | #endif | |
319 | ||
7737d5c6 DL |
320 | void qe_reset(void) |
321 | { | |
322 | qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, | |
323 | (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0); | |
324 | } | |
325 | ||
3bf46e6a | 326 | #ifdef CONFIG_QE |
7737d5c6 DL |
327 | void qe_assign_page(uint snum, uint para_ram_base) |
328 | { | |
329 | u32 cecr; | |
330 | ||
331 | out_be32(&qe_immr->cp.cecdr, para_ram_base); | |
332 | out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT) | |
333 | | QE_CR_FLG | QE_ASSIGN_PAGE); | |
334 | ||
335 | /* Wait for the QE_CR_FLG to clear */ | |
336 | do { | |
337 | cecr = in_be32(&qe_immr->cp.cecr); | |
338 | } while (cecr & QE_CR_FLG ); | |
339 | ||
340 | return; | |
341 | } | |
3bf46e6a | 342 | #endif |
7737d5c6 DL |
343 | |
344 | /* | |
345 | * brg: 0~15 as BRG1~BRG16 | |
346 | rate: baud rate | |
347 | * BRG input clock comes from the BRGCLK (internal clock generated from | |
348 | the QE clock, it is one-half of the QE clock), If need the clock source | |
349 | from CLKn pin, we have te change the function. | |
350 | */ | |
351 | ||
1206c184 | 352 | #define BRG_CLK (gd->arch.brg_clk) |
7737d5c6 | 353 | |
93d33204 | 354 | #ifdef CONFIG_QE |
7737d5c6 DL |
355 | int qe_set_brg(uint brg, uint rate) |
356 | { | |
7737d5c6 DL |
357 | volatile uint *bp; |
358 | u32 divisor; | |
359 | int div16 = 0; | |
360 | ||
361 | if (brg >= QE_NUM_OF_BRGS) | |
362 | return -EINVAL; | |
363 | bp = (uint *)&qe_immr->brg.brgc1; | |
364 | bp += brg; | |
365 | ||
366 | divisor = (BRG_CLK / rate); | |
367 | if (divisor > QE_BRGC_DIVISOR_MAX + 1) { | |
368 | div16 = 1; | |
369 | divisor /= 16; | |
370 | } | |
371 | ||
372 | *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; | |
373 | __asm__ __volatile__("sync"); | |
374 | ||
375 | if (div16) { | |
376 | *bp |= QE_BRGC_DIV16; | |
377 | __asm__ __volatile__("sync"); | |
378 | } | |
379 | ||
380 | return 0; | |
381 | } | |
93d33204 | 382 | #endif |
7737d5c6 DL |
383 | |
384 | /* Set ethernet MII clock master | |
385 | */ | |
386 | int qe_set_mii_clk_src(int ucc_num) | |
387 | { | |
388 | u32 cmxgcr; | |
389 | ||
390 | /* check if the UCC number is in range. */ | |
391 | if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) { | |
392 | printf("%s: ucc num not in ranges\n", __FUNCTION__); | |
393 | return -EINVAL; | |
394 | } | |
395 | ||
396 | cmxgcr = in_be32(&qe_immr->qmx.cmxgcr); | |
397 | cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK; | |
398 | cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT); | |
399 | out_be32(&qe_immr->qmx.cmxgcr, cmxgcr); | |
400 | ||
401 | return 0; | |
402 | } | |
403 | ||
b8ec2385 TT |
404 | /* Firmware information stored here for qe_get_firmware_info() */ |
405 | static struct qe_firmware_info qe_firmware_info; | |
406 | ||
407 | /* | |
408 | * Set to 1 if QE firmware has been uploaded, and therefore | |
409 | * qe_firmware_info contains valid data. | |
410 | */ | |
411 | static int qe_firmware_uploaded; | |
412 | ||
413 | /* | |
414 | * Upload a QE microcode | |
415 | * | |
416 | * This function is a worker function for qe_upload_firmware(). It does | |
417 | * the actual uploading of the microcode. | |
418 | */ | |
419 | static void qe_upload_microcode(const void *base, | |
420 | const struct qe_microcode *ucode) | |
421 | { | |
422 | const u32 *code = base + be32_to_cpu(ucode->code_offset); | |
423 | unsigned int i; | |
424 | ||
425 | if (ucode->major || ucode->minor || ucode->revision) | |
426 | printf("QE: uploading microcode '%s' version %u.%u.%u\n", | |
e94a8fd3 ZQ |
427 | (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor, |
428 | (u16)ucode->revision); | |
b8ec2385 | 429 | else |
e94a8fd3 | 430 | printf("QE: uploading microcode '%s'\n", (char *)ucode->id); |
b8ec2385 TT |
431 | |
432 | /* Use auto-increment */ | |
433 | out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) | | |
434 | QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR); | |
435 | ||
436 | for (i = 0; i < be32_to_cpu(ucode->count); i++) | |
437 | out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i])); | |
438 | } | |
439 | ||
440 | /* | |
441 | * Upload a microcode to the I-RAM at a specific address. | |
442 | * | |
d76485b9 HS |
443 | * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for |
444 | * information on QE microcode uploading. | |
b8ec2385 TT |
445 | * |
446 | * Currently, only version 1 is supported, so the 'version' field must be | |
447 | * set to 1. | |
448 | * | |
449 | * The SOC model and revision are not validated, they are only displayed for | |
450 | * informational purposes. | |
451 | * | |
452 | * 'calc_size' is the calculated size, in bytes, of the firmware structure and | |
453 | * all of the microcode structures, minus the CRC. | |
454 | * | |
455 | * 'length' is the size that the structure says it is, including the CRC. | |
456 | */ | |
457 | int qe_upload_firmware(const struct qe_firmware *firmware) | |
458 | { | |
459 | unsigned int i; | |
460 | unsigned int j; | |
461 | u32 crc; | |
462 | size_t calc_size = sizeof(struct qe_firmware); | |
463 | size_t length; | |
464 | const struct qe_header *hdr; | |
ca721fb2 | 465 | #ifdef CONFIG_DEEP_SLEEP |
73fb5838 | 466 | #ifdef CONFIG_ARCH_LS1021A |
9c7c86f4 ZQ |
467 | struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; |
468 | #else | |
ca721fb2 | 469 | ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); |
9c7c86f4 | 470 | #endif |
ca721fb2 | 471 | #endif |
b8ec2385 TT |
472 | if (!firmware) { |
473 | printf("Invalid address\n"); | |
474 | return -EINVAL; | |
475 | } | |
476 | ||
477 | hdr = &firmware->header; | |
478 | length = be32_to_cpu(hdr->length); | |
479 | ||
480 | /* Check the magic */ | |
481 | if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || | |
482 | (hdr->magic[2] != 'F')) { | |
12eeb135 | 483 | printf("QE microcode not found\n"); |
ca721fb2 ZQ |
484 | #ifdef CONFIG_DEEP_SLEEP |
485 | setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); | |
486 | #endif | |
b8ec2385 TT |
487 | return -EPERM; |
488 | } | |
489 | ||
490 | /* Check the version */ | |
491 | if (hdr->version != 1) { | |
492 | printf("Unsupported version\n"); | |
493 | return -EPERM; | |
494 | } | |
495 | ||
496 | /* Validate some of the fields */ | |
491fb6de | 497 | if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { |
b8ec2385 TT |
498 | printf("Invalid data\n"); |
499 | return -EINVAL; | |
500 | } | |
501 | ||
502 | /* Validate the length and check if there's a CRC */ | |
503 | calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); | |
504 | ||
505 | for (i = 0; i < firmware->count; i++) | |
506 | /* | |
507 | * For situations where the second RISC uses the same microcode | |
508 | * as the first, the 'code_offset' and 'count' fields will be | |
509 | * zero, so it's okay to add those. | |
510 | */ | |
511 | calc_size += sizeof(u32) * | |
512 | be32_to_cpu(firmware->microcode[i].count); | |
513 | ||
514 | /* Validate the length */ | |
515 | if (length != calc_size + sizeof(u32)) { | |
516 | printf("Invalid length\n"); | |
517 | return -EPERM; | |
518 | } | |
519 | ||
d3a6532c WD |
520 | /* |
521 | * Validate the CRC. We would normally call crc32_no_comp(), but that | |
522 | * function isn't available unless you turn on JFFS support. | |
523 | */ | |
b8ec2385 TT |
524 | crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size)); |
525 | if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) { | |
526 | printf("Firmware CRC is invalid\n"); | |
527 | return -EIO; | |
528 | } | |
529 | ||
530 | /* | |
531 | * If the microcode calls for it, split the I-RAM. | |
532 | */ | |
533 | if (!firmware->split) { | |
534 | out_be16(&qe_immr->cp.cercr, | |
535 | in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR); | |
536 | } | |
537 | ||
538 | if (firmware->soc.model) | |
539 | printf("Firmware '%s' for %u V%u.%u\n", | |
540 | firmware->id, be16_to_cpu(firmware->soc.model), | |
541 | firmware->soc.major, firmware->soc.minor); | |
542 | else | |
543 | printf("Firmware '%s'\n", firmware->id); | |
544 | ||
545 | /* | |
546 | * The QE only supports one microcode per RISC, so clear out all the | |
547 | * saved microcode information and put in the new. | |
548 | */ | |
549 | memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); | |
0e0224ee | 550 | strncpy(qe_firmware_info.id, (char *)firmware->id, 62); |
b8ec2385 TT |
551 | qe_firmware_info.extended_modes = firmware->extended_modes; |
552 | memcpy(qe_firmware_info.vtraps, firmware->vtraps, | |
553 | sizeof(firmware->vtraps)); | |
554 | qe_firmware_uploaded = 1; | |
555 | ||
556 | /* Loop through each microcode. */ | |
557 | for (i = 0; i < firmware->count; i++) { | |
558 | const struct qe_microcode *ucode = &firmware->microcode[i]; | |
559 | ||
560 | /* Upload a microcode if it's present */ | |
561 | if (ucode->code_offset) | |
562 | qe_upload_microcode(firmware, ucode); | |
563 | ||
564 | /* Program the traps for this processor */ | |
565 | for (j = 0; j < 16; j++) { | |
566 | u32 trap = be32_to_cpu(ucode->traps[j]); | |
567 | ||
568 | if (trap) | |
569 | out_be32(&qe_immr->rsp[i].tibcr[j], trap); | |
570 | } | |
571 | ||
572 | /* Enable traps */ | |
573 | out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); | |
574 | } | |
575 | ||
576 | return 0; | |
577 | } | |
578 | ||
5632d15c ZQ |
579 | #ifdef CONFIG_U_QE |
580 | /* | |
581 | * Upload a microcode to the I-RAM at a specific address. | |
582 | * | |
d76485b9 HS |
583 | * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for |
584 | * information on QE microcode uploading. | |
5632d15c ZQ |
585 | * |
586 | * Currently, only version 1 is supported, so the 'version' field must be | |
587 | * set to 1. | |
588 | * | |
589 | * The SOC model and revision are not validated, they are only displayed for | |
590 | * informational purposes. | |
591 | * | |
592 | * 'calc_size' is the calculated size, in bytes, of the firmware structure and | |
593 | * all of the microcode structures, minus the CRC. | |
594 | * | |
595 | * 'length' is the size that the structure says it is, including the CRC. | |
596 | */ | |
597 | int u_qe_upload_firmware(const struct qe_firmware *firmware) | |
598 | { | |
599 | unsigned int i; | |
600 | unsigned int j; | |
601 | u32 crc; | |
602 | size_t calc_size = sizeof(struct qe_firmware); | |
603 | size_t length; | |
604 | const struct qe_header *hdr; | |
605 | #ifdef CONFIG_DEEP_SLEEP | |
73fb5838 | 606 | #ifdef CONFIG_ARCH_LS1021A |
9c7c86f4 ZQ |
607 | struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; |
608 | #else | |
5632d15c | 609 | ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); |
9c7c86f4 | 610 | #endif |
5632d15c ZQ |
611 | #endif |
612 | if (!firmware) { | |
613 | printf("Invalid address\n"); | |
614 | return -EINVAL; | |
615 | } | |
616 | ||
617 | hdr = &firmware->header; | |
618 | length = be32_to_cpu(hdr->length); | |
619 | ||
620 | /* Check the magic */ | |
621 | if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || | |
622 | (hdr->magic[2] != 'F')) { | |
623 | printf("Not a microcode\n"); | |
624 | #ifdef CONFIG_DEEP_SLEEP | |
625 | setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); | |
626 | #endif | |
627 | return -EPERM; | |
628 | } | |
629 | ||
630 | /* Check the version */ | |
631 | if (hdr->version != 1) { | |
632 | printf("Unsupported version\n"); | |
633 | return -EPERM; | |
634 | } | |
635 | ||
636 | /* Validate some of the fields */ | |
637 | if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { | |
638 | printf("Invalid data\n"); | |
639 | return -EINVAL; | |
640 | } | |
641 | ||
642 | /* Validate the length and check if there's a CRC */ | |
643 | calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); | |
644 | ||
645 | for (i = 0; i < firmware->count; i++) | |
646 | /* | |
647 | * For situations where the second RISC uses the same microcode | |
648 | * as the first, the 'code_offset' and 'count' fields will be | |
649 | * zero, so it's okay to add those. | |
650 | */ | |
651 | calc_size += sizeof(u32) * | |
652 | be32_to_cpu(firmware->microcode[i].count); | |
653 | ||
654 | /* Validate the length */ | |
655 | if (length != calc_size + sizeof(u32)) { | |
656 | printf("Invalid length\n"); | |
657 | return -EPERM; | |
658 | } | |
659 | ||
660 | /* | |
661 | * Validate the CRC. We would normally call crc32_no_comp(), but that | |
662 | * function isn't available unless you turn on JFFS support. | |
663 | */ | |
664 | crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size)); | |
665 | if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) { | |
666 | printf("Firmware CRC is invalid\n"); | |
667 | return -EIO; | |
668 | } | |
669 | ||
670 | /* | |
671 | * If the microcode calls for it, split the I-RAM. | |
672 | */ | |
673 | if (!firmware->split) { | |
674 | out_be16(&qe_immr->cp.cercr, | |
675 | in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR); | |
676 | } | |
677 | ||
678 | if (firmware->soc.model) | |
679 | printf("Firmware '%s' for %u V%u.%u\n", | |
680 | firmware->id, be16_to_cpu(firmware->soc.model), | |
681 | firmware->soc.major, firmware->soc.minor); | |
682 | else | |
683 | printf("Firmware '%s'\n", firmware->id); | |
684 | ||
685 | /* Loop through each microcode. */ | |
686 | for (i = 0; i < firmware->count; i++) { | |
687 | const struct qe_microcode *ucode = &firmware->microcode[i]; | |
688 | ||
689 | /* Upload a microcode if it's present */ | |
690 | if (ucode->code_offset) | |
691 | qe_upload_microcode(firmware, ucode); | |
692 | ||
693 | /* Program the traps for this processor */ | |
694 | for (j = 0; j < 16; j++) { | |
695 | u32 trap = be32_to_cpu(ucode->traps[j]); | |
696 | ||
697 | if (trap) | |
698 | out_be32(&qe_immr->rsp[i].tibcr[j], trap); | |
699 | } | |
700 | ||
701 | /* Enable traps */ | |
702 | out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); | |
703 | } | |
704 | ||
705 | return 0; | |
706 | } | |
707 | #endif | |
ae42eb03 ZQ |
708 | |
709 | #ifdef CONFIG_U_QE | |
710 | int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr) | |
711 | { | |
712 | unsigned int i; | |
713 | unsigned int j; | |
714 | const struct qe_header *hdr; | |
715 | const u32 *code; | |
716 | #ifdef CONFIG_DEEP_SLEEP | |
717 | #ifdef CONFIG_PPC | |
718 | ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); | |
719 | #else | |
720 | struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; | |
721 | #endif | |
722 | #endif | |
723 | ||
724 | if (!firmware) | |
725 | return -EINVAL; | |
726 | ||
727 | hdr = &firmware->header; | |
728 | ||
729 | /* Check the magic */ | |
730 | if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || | |
731 | (hdr->magic[2] != 'F')) { | |
732 | #ifdef CONFIG_DEEP_SLEEP | |
733 | setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); | |
734 | #endif | |
735 | return -EPERM; | |
736 | } | |
737 | ||
738 | /* | |
739 | * If the microcode calls for it, split the I-RAM. | |
740 | */ | |
741 | if (!firmware->split) { | |
742 | out_be16(&qe_immrr->cp.cercr, | |
743 | in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR); | |
744 | } | |
745 | ||
746 | /* Loop through each microcode. */ | |
747 | for (i = 0; i < firmware->count; i++) { | |
748 | const struct qe_microcode *ucode = &firmware->microcode[i]; | |
749 | ||
750 | /* Upload a microcode if it's present */ | |
751 | if (!ucode->code_offset) | |
752 | return 0; | |
753 | ||
754 | code = (const void *)firmware + be32_to_cpu(ucode->code_offset); | |
755 | ||
756 | /* Use auto-increment */ | |
757 | out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) | | |
758 | QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR); | |
759 | ||
760 | for (i = 0; i < be32_to_cpu(ucode->count); i++) | |
761 | out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i])); | |
762 | ||
763 | /* Program the traps for this processor */ | |
764 | for (j = 0; j < 16; j++) { | |
765 | u32 trap = be32_to_cpu(ucode->traps[j]); | |
766 | ||
767 | if (trap) | |
768 | out_be32(&qe_immrr->rsp[i].tibcr[j], trap); | |
769 | } | |
770 | ||
771 | /* Enable traps */ | |
772 | out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); | |
773 | } | |
774 | ||
775 | return 0; | |
776 | } | |
777 | #endif | |
5632d15c | 778 | |
b8ec2385 TT |
779 | struct qe_firmware_info *qe_get_firmware_info(void) |
780 | { | |
781 | return qe_firmware_uploaded ? &qe_firmware_info : NULL; | |
782 | } | |
783 | ||
09140113 | 784 | static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
b8ec2385 TT |
785 | { |
786 | ulong addr; | |
787 | ||
47e26b1b WD |
788 | if (argc < 3) |
789 | return cmd_usage(cmdtp); | |
b8ec2385 TT |
790 | |
791 | if (strcmp(argv[1], "fw") == 0) { | |
792 | addr = simple_strtoul(argv[2], NULL, 16); | |
793 | ||
794 | if (!addr) { | |
795 | printf("Invalid address\n"); | |
796 | return -EINVAL; | |
797 | } | |
798 | ||
d3a6532c WD |
799 | /* |
800 | * If a length was supplied, compare that with the 'length' | |
801 | * field. | |
802 | */ | |
b8ec2385 TT |
803 | |
804 | if (argc > 3) { | |
805 | ulong length = simple_strtoul(argv[3], NULL, 16); | |
806 | struct qe_firmware *firmware = (void *) addr; | |
807 | ||
808 | if (length != be32_to_cpu(firmware->header.length)) { | |
809 | printf("Length mismatch\n"); | |
810 | return -EINVAL; | |
811 | } | |
812 | } | |
813 | ||
814 | return qe_upload_firmware((const struct qe_firmware *) addr); | |
815 | } | |
816 | ||
47e26b1b | 817 | return cmd_usage(cmdtp); |
b8ec2385 TT |
818 | } |
819 | ||
820 | U_BOOT_CMD( | |
821 | qe, 4, 0, qe_cmd, | |
2fb2604d | 822 | "QUICC Engine commands", |
b8ec2385 | 823 | "fw <addr> [<length>] - Upload firmware binary at address <addr> to " |
a89c33db WD |
824 | "the QE,\n" |
825 | "\twith optional length <length> verification." | |
826 | ); |