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;
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
53#ifdef CONFIG_QE
54uint qe_muram_alloc(uint size, uint align)
55{
56 uint retloc;
57 uint align_mask, off;
58 uint savebase;
59
60 align_mask = align - 1;
61 savebase = gd->arch.mp_alloc_base;
62
63 off = gd->arch.mp_alloc_base & align_mask;
64 if (off != 0)
65 gd->arch.mp_alloc_base += (align - off);
66
67 off = size & align_mask;
68 if (off != 0)
69 size += (align - off);
70
71 if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
72 gd->arch.mp_alloc_base = savebase;
73 printf("%s: ran out of ram.\n", __func__);
74 }
75
76 retloc = gd->arch.mp_alloc_base;
77 gd->arch.mp_alloc_base += size;
78
79 memset((void *)&qe_immr->muram[retloc], 0, size);
80
81 __asm__ __volatile__("sync");
82
83 return retloc;
84}
85#endif
86
87void *qe_muram_addr(uint offset)
88{
89 return (void *)&qe_immr->muram[offset];
90}
91
92#ifdef CONFIG_QE
93static void qe_sdma_init(void)
94{
95 sdma_t *p;
96 uint sdma_buffer_base;
97
98 p = (sdma_t *)&qe_immr->sdma;
99
100
101 out_be32(&p->sdaqr, 0);
102 out_be32(&p->sdaqmr, 0);
103
104
105 sdma_buffer_base = qe_muram_alloc(2048, 4096);
106 out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
107
108
109 out_be32(&p->sdsr, 0x03000000);
110
111
112 out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
113}
114
115
116
117
118
119static u8 thread_snum[] = {
120
121#if !defined(CONFIG_ARCH_MPC8309)
122 0x04, 0x05, 0x0c, 0x0d,
123 0x14, 0x15, 0x1c, 0x1d,
124 0x24, 0x25, 0x2c, 0x2d,
125 0x34, 0x35,
126#endif
127 0x88, 0x89, 0x98, 0x99,
128 0xa8, 0xa9, 0xb8, 0xb9,
129 0xc8, 0xc9, 0xd8, 0xd9,
130 0xe8, 0xe9, 0x08, 0x09,
131 0x18, 0x19, 0x28, 0x29,
132 0x38, 0x39, 0x48, 0x49,
133 0x58, 0x59, 0x68, 0x69,
134 0x78, 0x79, 0x80, 0x81
135};
136
137static void qe_snums_init(void)
138{
139 int i;
140
141 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
142 snums[i].state = QE_SNUM_STATE_FREE;
143 snums[i].num = thread_snum[i];
144 }
145}
146
147int qe_get_snum(void)
148{
149 int snum = -EBUSY;
150 int i;
151
152 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
153 if (snums[i].state == QE_SNUM_STATE_FREE) {
154 snums[i].state = QE_SNUM_STATE_USED;
155 snum = snums[i].num;
156 break;
157 }
158 }
159
160 return snum;
161}
162
163void qe_put_snum(u8 snum)
164{
165 int i;
166
167 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
168 if (snums[i].num == snum) {
169 snums[i].state = QE_SNUM_STATE_FREE;
170 break;
171 }
172 }
173}
174
175#ifdef CONFIG_TFABOOT
176void qe_init(uint qe_base)
177{
178 enum boot_src src = get_boot_src();
179
180
181 qe_immr = (qe_map_t *)qe_base;
182
183 if (src == BOOT_SOURCE_IFC_NOR) {
184
185
186
187
188 qe_upload_firmware((const void *)(CONFIG_SYS_QE_FW_ADDR +
189 CONFIG_SYS_FSL_IFC_BASE));
190
191
192 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
193 }
194
195 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
196 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
197
198 qe_sdma_init();
199 qe_snums_init();
200}
201#else
202void qe_init(uint qe_base)
203{
204
205 qe_immr = (qe_map_t *)qe_base;
206
207#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
208
209
210
211 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
212
213
214 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
215#endif
216
217 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
218 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
219
220 qe_sdma_init();
221 qe_snums_init();
222}
223#endif
224#endif
225
226#ifdef CONFIG_U_QE
227#ifdef CONFIG_TFABOOT
228void u_qe_init(void)
229{
230 enum boot_src src = get_boot_src();
231
232 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
233
234 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
235
236 if (src == BOOT_SOURCE_IFC_NOR)
237 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
238 CONFIG_SYS_FSL_IFC_BASE);
239
240 if (src == BOOT_SOURCE_QSPI_NOR)
241 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
242 CONFIG_SYS_FSL_QSPI_BASE);
243
244 if (src == BOOT_SOURCE_SD_MMC) {
245 int dev = CONFIG_SYS_MMC_ENV_DEV;
246 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
247 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
248
249 if (mmc_initialize(gd->bd)) {
250 printf("%s: mmc_initialize() failed\n", __func__);
251 return;
252 }
253 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
254 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
255
256 if (!mmc) {
257 free(addr);
258 printf("\nMMC cannot find device for ucode\n");
259 } else {
260 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
261 dev, blk, cnt);
262 mmc_init(mmc);
263 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
264 addr);
265 }
266 }
267 if (!u_qe_upload_firmware(addr))
268 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
269 if (src == BOOT_SOURCE_SD_MMC)
270 free(addr);
271}
272#else
273void u_qe_init(void)
274{
275 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
276
277 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
278#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
279 int dev = CONFIG_SYS_MMC_ENV_DEV;
280 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
281 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
282
283 if (mmc_initialize(gd->bd)) {
284 printf("%s: mmc_initialize() failed\n", __func__);
285 return;
286 }
287 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
288 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
289
290 if (!mmc) {
291 free(addr);
292 printf("\nMMC cannot find device for ucode\n");
293 } else {
294 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
295 dev, blk, cnt);
296 mmc_init(mmc);
297 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
298 addr);
299 }
300#endif
301 if (!u_qe_upload_firmware(addr))
302 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
303#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
304 free(addr);
305#endif
306}
307#endif
308#endif
309
310#ifdef CONFIG_U_QE
311void u_qe_resume(void)
312{
313 qe_map_t *qe_immrr;
314
315 qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
316 u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr);
317 out_be32(&qe_immrr->iram.iready, QE_IRAM_READY);
318}
319#endif
320
321void qe_reset(void)
322{
323 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
324 (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
325}
326
327#ifdef CONFIG_QE
328void qe_assign_page(uint snum, uint para_ram_base)
329{
330 u32 cecr;
331
332 out_be32(&qe_immr->cp.cecdr, para_ram_base);
333 out_be32(&qe_immr->cp.cecr, ((u32)snum << QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
334 | QE_CR_FLG | QE_ASSIGN_PAGE);
335
336
337 do {
338 cecr = in_be32(&qe_immr->cp.cecr);
339 } while (cecr & QE_CR_FLG);
340}
341#endif
342
343
344
345
346
347
348
349
350
351#define BRG_CLK (gd->arch.brg_clk)
352
353#ifdef CONFIG_QE
354int qe_set_brg(uint brg, uint rate)
355{
356 uint *bp;
357 u32 divisor;
358 u32 val;
359 int div16 = 0;
360
361 if (brg >= QE_NUM_OF_BRGS)
362 return -EINVAL;
363
364 bp = (uint *)&qe_immr->brg.brgc1;
365 bp += brg;
366
367 divisor = (BRG_CLK / rate);
368 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
369 div16 = 1;
370 divisor /= 16;
371 }
372
373
374
375
376
377
378
379
380 val = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
381 if (div16)
382 val |= QE_BRGC_DIV16;
383
384 out_be32(bp, val);
385
386 return 0;
387}
388#endif
389
390
391int qe_set_mii_clk_src(int ucc_num)
392{
393 u32 cmxgcr;
394
395
396 if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) {
397 printf("%s: ucc num not in ranges\n", __func__);
398 return -EINVAL;
399 }
400
401 cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
402 cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
403 cmxgcr |= (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
404 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
405
406 return 0;
407}
408
409
410static struct qe_firmware_info qe_firmware_info;
411
412
413
414
415
416static int qe_firmware_uploaded;
417
418
419
420
421
422
423
424static void qe_upload_microcode(const void *base,
425 const struct qe_microcode *ucode)
426{
427 const u32 *code = base + be32_to_cpu(ucode->code_offset);
428 unsigned int i;
429
430 if (ucode->major || ucode->minor || ucode->revision)
431 printf("QE: uploading microcode '%s' version %u.%u.%u\n",
432 (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
433 (u16)ucode->revision);
434 else
435 printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
436
437
438 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
439 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
440
441 for (i = 0; i < be32_to_cpu(ucode->count); i++)
442 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
443}
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462int qe_upload_firmware(const struct qe_firmware *firmware)
463{
464 unsigned int i;
465 unsigned int j;
466 u32 crc;
467 size_t calc_size = sizeof(struct qe_firmware);
468 size_t length;
469 const struct qe_header *hdr;
470#ifdef CONFIG_DEEP_SLEEP
471#ifdef CONFIG_ARCH_LS1021A
472 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
473#else
474 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
475#endif
476#endif
477 if (!firmware) {
478 printf("Invalid address\n");
479 return -EINVAL;
480 }
481
482 hdr = &firmware->header;
483 length = be32_to_cpu(hdr->length);
484
485
486 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
487 (hdr->magic[2] != 'F')) {
488 printf("QE microcode not found\n");
489#ifdef CONFIG_DEEP_SLEEP
490 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
491#endif
492 return -EPERM;
493 }
494
495
496 if (hdr->version != 1) {
497 printf("Unsupported version\n");
498 return -EPERM;
499 }
500
501
502 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
503 printf("Invalid data\n");
504 return -EINVAL;
505 }
506
507
508 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
509
510 for (i = 0; i < firmware->count; i++)
511
512
513
514
515
516 calc_size += sizeof(u32) *
517 be32_to_cpu(firmware->microcode[i].count);
518
519
520 if (length != calc_size + sizeof(u32)) {
521 printf("Invalid length\n");
522 return -EPERM;
523 }
524
525
526
527
528
529 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
530 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
531 printf("Firmware CRC is invalid\n");
532 return -EIO;
533 }
534
535
536
537
538 if (!firmware->split) {
539 out_be16(&qe_immr->cp.cercr,
540 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
541 }
542
543 if (firmware->soc.model)
544 printf("Firmware '%s' for %u V%u.%u\n",
545 firmware->id, be16_to_cpu(firmware->soc.model),
546 firmware->soc.major, firmware->soc.minor);
547 else
548 printf("Firmware '%s'\n", firmware->id);
549
550
551
552
553
554 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
555 strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
556 qe_firmware_info.extended_modes = firmware->extended_modes;
557 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
558 sizeof(firmware->vtraps));
559 qe_firmware_uploaded = 1;
560
561
562 for (i = 0; i < firmware->count; i++) {
563 const struct qe_microcode *ucode = &firmware->microcode[i];
564
565
566 if (ucode->code_offset)
567 qe_upload_microcode(firmware, ucode);
568
569
570 for (j = 0; j < 16; j++) {
571 u32 trap = be32_to_cpu(ucode->traps[j]);
572
573 if (trap)
574 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
575 }
576
577
578 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
579 }
580
581 return 0;
582}
583
584#ifdef CONFIG_U_QE
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602int u_qe_upload_firmware(const struct qe_firmware *firmware)
603{
604 unsigned int i;
605 unsigned int j;
606 u32 crc;
607 size_t calc_size = sizeof(struct qe_firmware);
608 size_t length;
609 const struct qe_header *hdr;
610#ifdef CONFIG_DEEP_SLEEP
611#ifdef CONFIG_ARCH_LS1021A
612 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
613#else
614 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
615#endif
616#endif
617 if (!firmware) {
618 printf("Invalid address\n");
619 return -EINVAL;
620 }
621
622 hdr = &firmware->header;
623 length = be32_to_cpu(hdr->length);
624
625
626 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
627 (hdr->magic[2] != 'F')) {
628 printf("Not a microcode\n");
629#ifdef CONFIG_DEEP_SLEEP
630 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
631#endif
632 return -EPERM;
633 }
634
635
636 if (hdr->version != 1) {
637 printf("Unsupported version\n");
638 return -EPERM;
639 }
640
641
642 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
643 printf("Invalid data\n");
644 return -EINVAL;
645 }
646
647
648 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
649
650 for (i = 0; i < firmware->count; i++)
651
652
653
654
655
656 calc_size += sizeof(u32) *
657 be32_to_cpu(firmware->microcode[i].count);
658
659
660 if (length != calc_size + sizeof(u32)) {
661 printf("Invalid length\n");
662 return -EPERM;
663 }
664
665
666
667
668
669 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
670 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
671 printf("Firmware CRC is invalid\n");
672 return -EIO;
673 }
674
675
676
677
678 if (!firmware->split) {
679 out_be16(&qe_immr->cp.cercr,
680 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
681 }
682
683 if (firmware->soc.model)
684 printf("Firmware '%s' for %u V%u.%u\n",
685 firmware->id, be16_to_cpu(firmware->soc.model),
686 firmware->soc.major, firmware->soc.minor);
687 else
688 printf("Firmware '%s'\n", firmware->id);
689
690
691 for (i = 0; i < firmware->count; i++) {
692 const struct qe_microcode *ucode = &firmware->microcode[i];
693
694
695 if (ucode->code_offset)
696 qe_upload_microcode(firmware, ucode);
697
698
699 for (j = 0; j < 16; j++) {
700 u32 trap = be32_to_cpu(ucode->traps[j]);
701
702 if (trap)
703 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
704 }
705
706
707 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
708 }
709
710 return 0;
711}
712#endif
713
714#ifdef CONFIG_U_QE
715int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
716{
717 unsigned int i;
718 unsigned int j;
719 const struct qe_header *hdr;
720 const u32 *code;
721#ifdef CONFIG_DEEP_SLEEP
722#ifdef CONFIG_PPC
723 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
724#else
725 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
726#endif
727#endif
728
729 if (!firmware)
730 return -EINVAL;
731
732 hdr = &firmware->header;
733
734
735 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
736 (hdr->magic[2] != 'F')) {
737#ifdef CONFIG_DEEP_SLEEP
738 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
739#endif
740 return -EPERM;
741 }
742
743
744
745
746 if (!firmware->split) {
747 out_be16(&qe_immrr->cp.cercr,
748 in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
749 }
750
751
752 for (i = 0; i < firmware->count; i++) {
753 const struct qe_microcode *ucode = &firmware->microcode[i];
754
755
756 if (!ucode->code_offset)
757 return 0;
758
759 code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
760
761
762 out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
763 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
764
765 for (i = 0; i < be32_to_cpu(ucode->count); i++)
766 out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
767
768
769 for (j = 0; j < 16; j++) {
770 u32 trap = be32_to_cpu(ucode->traps[j]);
771
772 if (trap)
773 out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
774 }
775
776
777 out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
778 }
779
780 return 0;
781}
782#endif
783
784struct qe_firmware_info *qe_get_firmware_info(void)
785{
786 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
787}
788
789static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
790{
791 ulong addr;
792
793 if (argc < 3)
794 return cmd_usage(cmdtp);
795
796 if (strcmp(argv[1], "fw") == 0) {
797 addr = simple_strtoul(argv[2], NULL, 16);
798
799 if (!addr) {
800 printf("Invalid address\n");
801 return -EINVAL;
802 }
803
804
805
806
807
808
809 if (argc > 3) {
810 ulong length = simple_strtoul(argv[3], NULL, 16);
811 struct qe_firmware *firmware = (void *)addr;
812
813 if (length != be32_to_cpu(firmware->header.length)) {
814 printf("Length mismatch\n");
815 return -EINVAL;
816 }
817 }
818
819 return qe_upload_firmware((const struct qe_firmware *)addr);
820 }
821
822 return cmd_usage(cmdtp);
823}
824
825U_BOOT_CMD(
826 qe, 4, 0, qe_cmd,
827 "QUICC Engine commands",
828 "fw <addr> [<length>] - Upload firmware binary at address <addr> to the QE,\n"
829 "\twith optional length <length> verification."
830);
831