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
456int qe_upload_firmware(const struct qe_firmware *firmware)
457{
458 unsigned int i;
459 unsigned int j;
460 u32 crc;
461 size_t calc_size = sizeof(struct qe_firmware);
462 size_t length;
463 const struct qe_header *hdr;
464#ifdef CONFIG_DEEP_SLEEP
465#ifdef CONFIG_ARCH_LS1021A
466 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
467#else
468 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
469#endif
470#endif
471 if (!firmware) {
472 printf("Invalid address\n");
473 return -EINVAL;
474 }
475
476 hdr = &firmware->header;
477 length = be32_to_cpu(hdr->length);
478
479
480 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
481 (hdr->magic[2] != 'F')) {
482 printf("QE microcode not found\n");
483#ifdef CONFIG_DEEP_SLEEP
484 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
485#endif
486 return -EPERM;
487 }
488
489
490 if (hdr->version != 1) {
491 printf("Unsupported version\n");
492 return -EPERM;
493 }
494
495
496 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
497 printf("Invalid data\n");
498 return -EINVAL;
499 }
500
501
502 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
503
504 for (i = 0; i < firmware->count; i++)
505
506
507
508
509
510 calc_size += sizeof(u32) *
511 be32_to_cpu(firmware->microcode[i].count);
512
513
514 if (length != calc_size + sizeof(u32)) {
515 printf("Invalid length\n");
516 return -EPERM;
517 }
518
519
520
521
522
523 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
524 if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
525 printf("Firmware CRC is invalid\n");
526 return -EIO;
527 }
528
529
530
531
532 if (!firmware->split) {
533 out_be16(&qe_immr->cp.cercr,
534 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
535 }
536
537 if (firmware->soc.model)
538 printf("Firmware '%s' for %u V%u.%u\n",
539 firmware->id, be16_to_cpu(firmware->soc.model),
540 firmware->soc.major, firmware->soc.minor);
541 else
542 printf("Firmware '%s'\n", firmware->id);
543
544
545
546
547
548 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
549 strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
550 qe_firmware_info.extended_modes = firmware->extended_modes;
551 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
552 sizeof(firmware->vtraps));
553 qe_firmware_uploaded = 1;
554
555
556 for (i = 0; i < firmware->count; i++) {
557 const struct qe_microcode *ucode = &firmware->microcode[i];
558
559
560 if (ucode->code_offset)
561 qe_upload_microcode(firmware, ucode);
562
563
564 for (j = 0; j < 16; j++) {
565 u32 trap = be32_to_cpu(ucode->traps[j]);
566
567 if (trap)
568 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
569 }
570
571
572 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
573 }
574
575 return 0;
576}
577
578#ifdef CONFIG_U_QE
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595int u_qe_upload_firmware(const struct qe_firmware *firmware)
596{
597 unsigned int i;
598 unsigned int j;
599 u32 crc;
600 size_t calc_size = sizeof(struct qe_firmware);
601 size_t length;
602 const struct qe_header *hdr;
603#ifdef CONFIG_DEEP_SLEEP
604#ifdef CONFIG_ARCH_LS1021A
605 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
606#else
607 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
608#endif
609#endif
610 if (!firmware) {
611 printf("Invalid address\n");
612 return -EINVAL;
613 }
614
615 hdr = &firmware->header;
616 length = be32_to_cpu(hdr->length);
617
618
619 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
620 (hdr->magic[2] != 'F')) {
621 printf("Not a microcode\n");
622#ifdef CONFIG_DEEP_SLEEP
623 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
624#endif
625 return -EPERM;
626 }
627
628
629 if (hdr->version != 1) {
630 printf("Unsupported version\n");
631 return -EPERM;
632 }
633
634
635 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
636 printf("Invalid data\n");
637 return -EINVAL;
638 }
639
640
641 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
642
643 for (i = 0; i < firmware->count; i++)
644
645
646
647
648
649 calc_size += sizeof(u32) *
650 be32_to_cpu(firmware->microcode[i].count);
651
652
653 if (length != calc_size + sizeof(u32)) {
654 printf("Invalid length\n");
655 return -EPERM;
656 }
657
658
659
660
661
662 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
663 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
664 printf("Firmware CRC is invalid\n");
665 return -EIO;
666 }
667
668
669
670
671 if (!firmware->split) {
672 out_be16(&qe_immr->cp.cercr,
673 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
674 }
675
676 if (firmware->soc.model)
677 printf("Firmware '%s' for %u V%u.%u\n",
678 firmware->id, be16_to_cpu(firmware->soc.model),
679 firmware->soc.major, firmware->soc.minor);
680 else
681 printf("Firmware '%s'\n", firmware->id);
682
683
684 for (i = 0; i < firmware->count; i++) {
685 const struct qe_microcode *ucode = &firmware->microcode[i];
686
687
688 if (ucode->code_offset)
689 qe_upload_microcode(firmware, ucode);
690
691
692 for (j = 0; j < 16; j++) {
693 u32 trap = be32_to_cpu(ucode->traps[j]);
694
695 if (trap)
696 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
697 }
698
699
700 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
701 }
702
703 return 0;
704}
705#endif
706
707#ifdef CONFIG_U_QE
708int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
709{
710 unsigned int i;
711 unsigned int j;
712 const struct qe_header *hdr;
713 const u32 *code;
714#ifdef CONFIG_DEEP_SLEEP
715#ifdef CONFIG_PPC
716 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
717#else
718 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
719#endif
720#endif
721
722 if (!firmware)
723 return -EINVAL;
724
725 hdr = &firmware->header;
726
727
728 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
729 (hdr->magic[2] != 'F')) {
730#ifdef CONFIG_DEEP_SLEEP
731 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
732#endif
733 return -EPERM;
734 }
735
736
737
738
739 if (!firmware->split) {
740 out_be16(&qe_immrr->cp.cercr,
741 in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
742 }
743
744
745 for (i = 0; i < firmware->count; i++) {
746 const struct qe_microcode *ucode = &firmware->microcode[i];
747
748
749 if (!ucode->code_offset)
750 return 0;
751
752 code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
753
754
755 out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
756 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
757
758 for (i = 0; i < be32_to_cpu(ucode->count); i++)
759 out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
760
761
762 for (j = 0; j < 16; j++) {
763 u32 trap = be32_to_cpu(ucode->traps[j]);
764
765 if (trap)
766 out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
767 }
768
769
770 out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
771 }
772
773 return 0;
774}
775#endif
776
777struct qe_firmware_info *qe_get_firmware_info(void)
778{
779 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
780}
781
782static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
783{
784 ulong addr;
785
786 if (argc < 3)
787 return cmd_usage(cmdtp);
788
789 if (strcmp(argv[1], "fw") == 0) {
790 addr = simple_strtoul(argv[2], NULL, 16);
791
792 if (!addr) {
793 printf("Invalid address\n");
794 return -EINVAL;
795 }
796
797
798
799
800
801
802 if (argc > 3) {
803 ulong length = simple_strtoul(argv[3], NULL, 16);
804 struct qe_firmware *firmware = (void *) addr;
805
806 if (length != be32_to_cpu(firmware->header.length)) {
807 printf("Length mismatch\n");
808 return -EINVAL;
809 }
810 }
811
812 return qe_upload_firmware((const struct qe_firmware *) addr);
813 }
814
815 return cmd_usage(cmdtp);
816}
817
818U_BOOT_CMD(
819 qe, 4, 0, qe_cmd,
820 "QUICC Engine commands",
821 "fw <addr> [<length>] - Upload firmware binary at address <addr> to "
822 "the QE,\n"
823 "\twith optional length <length> verification."
824);
825