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