1
2
3
4
5
6
7
8
9#include <common.h>
10#include <malloc.h>
11#include <command.h>
12#include <linux/errno.h>
13#include <asm/io.h>
14#include <linux/immap_qe.h>
15#include <fsl_qe.h>
16#include <mmc.h>
17#include <u-boot/crc.h>
18
19#ifdef CONFIG_ARCH_LS1021A
20#include <asm/arch/immap_ls102xa.h>
21#endif
22#ifdef CONFIG_ARM64
23#include <asm/armv8/mmu.h>
24#include <asm/arch/cpu.h>
25#endif
26
27#define MPC85xx_DEVDISR_QE_DISABLE 0x1
28
29qe_map_t *qe_immr = NULL;
30#ifdef CONFIG_QE
31static qe_snum_t snums[QE_NUM_OF_SNUM];
32#endif
33
34DECLARE_GLOBAL_DATA_PTR;
35
36void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
37{
38 u32 cecr;
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
48 do {
49 cecr = in_be32(&qe_immr->cp.cecr);
50 } while (cecr & QE_CR_FLG);
51
52 return;
53}
54
55#ifdef CONFIG_QE
56uint qe_muram_alloc(uint size, uint align)
57{
58 uint retloc;
59 uint align_mask, off;
60 uint savebase;
61
62 align_mask = align - 1;
63 savebase = gd->arch.mp_alloc_base;
64
65 off = gd->arch.mp_alloc_base & align_mask;
66 if (off != 0)
67 gd->arch.mp_alloc_base += (align - off);
68
69 if ((off = size & align_mask) != 0)
70 size += (align - off);
71
72 if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
73 gd->arch.mp_alloc_base = savebase;
74 printf("%s: ran out of ram.\n", __FUNCTION__);
75 }
76
77 retloc = gd->arch.mp_alloc_base;
78 gd->arch.mp_alloc_base += size;
79
80 memset((void *)&qe_immr->muram[retloc], 0, size);
81
82 __asm__ __volatile__("sync");
83
84 return retloc;
85}
86#endif
87
88void *qe_muram_addr(uint offset)
89{
90 return (void *)&qe_immr->muram[offset];
91}
92
93#ifdef CONFIG_QE
94static 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
102 out_be32(&p->sdaqr, 0);
103 out_be32(&p->sdaqmr, 0);
104
105
106 sdma_buffer_base = qe_muram_alloc(2048, 4096);
107 out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
108
109
110 out_be32(&p->sdsr, 0x03000000);
111
112
113 out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
114}
115
116
117
118
119
120static u8 thread_snum[] = {
121
122#if !defined(CONFIG_ARCH_MPC8309)
123 0x04, 0x05, 0x0c, 0x0d,
124 0x14, 0x15, 0x1c, 0x1d,
125 0x24, 0x25, 0x2c, 0x2d,
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
136};
137
138static 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
148int 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
164void 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
176#ifdef CONFIG_TFABOOT
177void qe_init(uint qe_base)
178{
179 enum boot_src src = get_boot_src();
180
181
182 qe_immr = (qe_map_t *)qe_base;
183
184 if (src == BOOT_SOURCE_IFC_NOR) {
185
186
187
188
189 qe_upload_firmware((const void *)(CONFIG_SYS_QE_FW_ADDR +
190 CONFIG_SYS_FSL_IFC_BASE));
191
192
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
203void qe_init(uint qe_base)
204{
205
206 qe_immr = (qe_map_t *)qe_base;
207
208#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
209
210
211
212 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
213
214
215 out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
216#endif
217
218 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
219 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
220
221 qe_sdma_init();
222 qe_snums_init();
223}
224#endif
225#endif
226
227#ifdef CONFIG_U_QE
228#ifdef CONFIG_TFABOOT
229void 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
272void u_qe_init(void)
273{
274 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
275
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);
296 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
297 addr);
298 }
299#endif
300 if (!u_qe_upload_firmware(addr))
301 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
302#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
303 free(addr);
304#endif
305}
306#endif
307#endif
308
309#ifdef CONFIG_U_QE
310void u_qe_resume(void)
311{
312 qe_map_t *qe_immrr;
313
314 qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
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
320void qe_reset(void)
321{
322 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
323 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
324}
325
326#ifdef CONFIG_QE
327void 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
336 do {
337 cecr = in_be32(&qe_immr->cp.cecr);
338 } while (cecr & QE_CR_FLG );
339
340 return;
341}
342#endif
343
344
345
346
347
348
349
350
351
352#define BRG_CLK (gd->arch.brg_clk)
353
354#ifdef CONFIG_QE
355int qe_set_brg(uint brg, uint rate)
356{
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}
382#endif
383
384
385
386int qe_set_mii_clk_src(int ucc_num)
387{
388 u32 cmxgcr;
389
390
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
404
405static struct qe_firmware_info qe_firmware_info;
406
407
408
409
410
411static int qe_firmware_uploaded;
412
413
414
415
416
417
418
419static 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",
427 (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
428 (u16)ucode->revision);
429 else
430 printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
431
432
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
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457int 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;
465#ifdef CONFIG_DEEP_SLEEP
466#ifdef CONFIG_ARCH_LS1021A
467 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
468#else
469 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
470#endif
471#endif
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
481 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
482 (hdr->magic[2] != 'F')) {
483 printf("QE microcode not found\n");
484#ifdef CONFIG_DEEP_SLEEP
485 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
486#endif
487 return -EPERM;
488 }
489
490
491 if (hdr->version != 1) {
492 printf("Unsupported version\n");
493 return -EPERM;
494 }
495
496
497 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
498 printf("Invalid data\n");
499 return -EINVAL;
500 }
501
502
503 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
504
505 for (i = 0; i < firmware->count; i++)
506
507
508
509
510
511 calc_size += sizeof(u32) *
512 be32_to_cpu(firmware->microcode[i].count);
513
514
515 if (length != calc_size + sizeof(u32)) {
516 printf("Invalid length\n");
517 return -EPERM;
518 }
519
520
521
522
523
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
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
547
548
549 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
550 strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
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
557 for (i = 0; i < firmware->count; i++) {
558 const struct qe_microcode *ucode = &firmware->microcode[i];
559
560
561 if (ucode->code_offset)
562 qe_upload_microcode(firmware, ucode);
563
564
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
573 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
574 }
575
576 return 0;
577}
578
579#ifdef CONFIG_U_QE
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597int 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
606#ifdef CONFIG_ARCH_LS1021A
607 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
608#else
609 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
610#endif
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
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
631 if (hdr->version != 1) {
632 printf("Unsupported version\n");
633 return -EPERM;
634 }
635
636
637 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
638 printf("Invalid data\n");
639 return -EINVAL;
640 }
641
642
643 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
644
645 for (i = 0; i < firmware->count; i++)
646
647
648
649
650
651 calc_size += sizeof(u32) *
652 be32_to_cpu(firmware->microcode[i].count);
653
654
655 if (length != calc_size + sizeof(u32)) {
656 printf("Invalid length\n");
657 return -EPERM;
658 }
659
660
661
662
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
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
686 for (i = 0; i < firmware->count; i++) {
687 const struct qe_microcode *ucode = &firmware->microcode[i];
688
689
690 if (ucode->code_offset)
691 qe_upload_microcode(firmware, ucode);
692
693
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
702 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
703 }
704
705 return 0;
706}
707#endif
708
709#ifdef CONFIG_U_QE
710int 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
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
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
747 for (i = 0; i < firmware->count; i++) {
748 const struct qe_microcode *ucode = &firmware->microcode[i];
749
750
751 if (!ucode->code_offset)
752 return 0;
753
754 code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
755
756
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
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
772 out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
773 }
774
775 return 0;
776}
777#endif
778
779struct qe_firmware_info *qe_get_firmware_info(void)
780{
781 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
782}
783
784static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
785{
786 ulong addr;
787
788 if (argc < 3)
789 return cmd_usage(cmdtp);
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
799
800
801
802
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
817 return cmd_usage(cmdtp);
818}
819
820U_BOOT_CMD(
821 qe, 4, 0, qe_cmd,
822 "QUICC Engine commands",
823 "fw <addr> [<length>] - Upload firmware binary at address <addr> to "
824 "the QE,\n"
825 "\twith optional length <length> verification."
826);
827