blob: bc946731a1eb20aa670722a9bdde67efb1d20eee [file] [log] [blame]
Dave Liue732e9c2006-11-03 12:11:15 -06001/*
Haiying Wang0eea38e2009-05-20 12:30:35 -04002 * Copyright (C) 2006-2009 Freescale Semiconductor, Inc.
Dave Liue732e9c2006-11-03 12:11:15 -06003 *
4 * Dave Liu <daveliu@freescale.com>
5 * based on source code of Shlomi Gridish
6 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
Dave Liue732e9c2006-11-03 12:11:15 -06008 */
9
10#include "common.h"
Timur Tabi6d838da2008-01-07 13:31:19 -060011#include <command.h>
Dave Liue732e9c2006-11-03 12:11:15 -060012#include "asm/errno.h"
13#include "asm/io.h"
Zhao Qiang978679d2014-06-03 16:27:07 +080014#include "linux/immap_qe.h"
Dave Liue732e9c2006-11-03 12:11:15 -060015#include "qe.h"
16
Zhao Qiangb59534d2014-04-30 16:45:31 +080017#define MPC85xx_DEVDISR_QE_DISABLE 0x1
18
Dave Liue732e9c2006-11-03 12:11:15 -060019qe_map_t *qe_immr = NULL;
20static qe_snum_t snums[QE_NUM_OF_SNUM];
21
Wolfgang Denkd112a2c2007-09-15 20:48:41 +020022DECLARE_GLOBAL_DATA_PTR;
23
Dave Liue732e9c2006-11-03 12:11:15 -060024void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
25{
Wolfgang Denk545b06a2008-01-10 00:55:14 +010026 u32 cecr;
Dave Liue732e9c2006-11-03 12:11:15 -060027
28 if (cmd == QE_RESET) {
29 out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG));
30 } else {
31 out_be32(&qe_immr->cp.cecdr, cmd_data);
32 out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
33 ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd));
34 }
35 /* Wait for the QE_CR_FLG to clear */
36 do {
37 cecr = in_be32(&qe_immr->cp.cecr);
38 } while (cecr & QE_CR_FLG);
39
40 return;
41}
42
Zhao Qiang5ad93952014-09-25 13:52:25 +080043#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -060044uint qe_muram_alloc(uint size, uint align)
45{
Dave Liue732e9c2006-11-03 12:11:15 -060046 uint retloc;
47 uint align_mask, off;
48 uint savebase;
49
50 align_mask = align - 1;
Simon Glass8518b172012-12-13 20:48:50 +000051 savebase = gd->arch.mp_alloc_base;
Dave Liue732e9c2006-11-03 12:11:15 -060052
Simon Glass8518b172012-12-13 20:48:50 +000053 off = gd->arch.mp_alloc_base & align_mask;
54 if (off != 0)
55 gd->arch.mp_alloc_base += (align - off);
Dave Liue732e9c2006-11-03 12:11:15 -060056
57 if ((off = size & align_mask) != 0)
58 size += (align - off);
59
Simon Glass8518b172012-12-13 20:48:50 +000060 if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
61 gd->arch.mp_alloc_base = savebase;
Dave Liue732e9c2006-11-03 12:11:15 -060062 printf("%s: ran out of ram.\n", __FUNCTION__);
63 }
64
Simon Glass8518b172012-12-13 20:48:50 +000065 retloc = gd->arch.mp_alloc_base;
66 gd->arch.mp_alloc_base += size;
Dave Liue732e9c2006-11-03 12:11:15 -060067
68 memset((void *)&qe_immr->muram[retloc], 0, size);
69
70 __asm__ __volatile__("sync");
71
72 return retloc;
73}
Zhao Qiang5ad93952014-09-25 13:52:25 +080074#endif
Dave Liue732e9c2006-11-03 12:11:15 -060075
76void *qe_muram_addr(uint offset)
77{
78 return (void *)&qe_immr->muram[offset];
79}
80
81static void qe_sdma_init(void)
82{
83 volatile sdma_t *p;
84 uint sdma_buffer_base;
85
86 p = (volatile sdma_t *)&qe_immr->sdma;
87
88 /* All of DMA transaction in bus 1 */
89 out_be32(&p->sdaqr, 0);
90 out_be32(&p->sdaqmr, 0);
91
92 /* Allocate 2KB temporary buffer for sdma */
Dave Liu11da1752007-06-25 10:41:04 +080093 sdma_buffer_base = qe_muram_alloc(2048, 4096);
Dave Liue732e9c2006-11-03 12:11:15 -060094 out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
95
96 /* Clear sdma status */
97 out_be32(&p->sdsr, 0x03000000);
98
99 /* Enable global mode on bus 1, and 2KB buffer size */
100 out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
101}
102
Haiying Wang0eea38e2009-05-20 12:30:35 -0400103/* This table is a list of the serial numbers of the Threads, taken from the
104 * "SNUM Table" chart in the QE Reference Manual. The order is not important,
105 * we just need to know what the SNUMs are for the threads.
106 */
107static u8 thread_snum[] = {
Gerlando Falautofe201cb2012-10-10 22:13:08 +0000108/* Evthreads 16-29 are not supported in MPC8309 */
109#if !defined(CONFIG_MPC8309)
Dave Liue732e9c2006-11-03 12:11:15 -0600110 0x04, 0x05, 0x0c, 0x0d,
111 0x14, 0x15, 0x1c, 0x1d,
112 0x24, 0x25, 0x2c, 0x2d,
Gerlando Falautofe201cb2012-10-10 22:13:08 +0000113 0x34, 0x35,
114#endif
115 0x88, 0x89, 0x98, 0x99,
116 0xa8, 0xa9, 0xb8, 0xb9,
117 0xc8, 0xc9, 0xd8, 0xd9,
118 0xe8, 0xe9, 0x08, 0x09,
119 0x18, 0x19, 0x28, 0x29,
120 0x38, 0x39, 0x48, 0x49,
121 0x58, 0x59, 0x68, 0x69,
122 0x78, 0x79, 0x80, 0x81
Dave Liue732e9c2006-11-03 12:11:15 -0600123};
124
125static void qe_snums_init(void)
126{
127 int i;
128
129 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
130 snums[i].state = QE_SNUM_STATE_FREE;
131 snums[i].num = thread_snum[i];
132 }
133}
134
135int qe_get_snum(void)
136{
137 int snum = -EBUSY;
138 int i;
139
140 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
141 if (snums[i].state == QE_SNUM_STATE_FREE) {
142 snums[i].state = QE_SNUM_STATE_USED;
143 snum = snums[i].num;
144 break;
145 }
146 }
147
148 return snum;
149}
150
151void qe_put_snum(u8 snum)
152{
153 int i;
154
155 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
156 if (snums[i].num == snum) {
157 snums[i].state = QE_SNUM_STATE_FREE;
158 break;
159 }
160 }
161}
162
163void qe_init(uint qe_base)
164{
Dave Liue732e9c2006-11-03 12:11:15 -0600165 /* Init the QE IMMR base */
166 qe_immr = (qe_map_t *)qe_base;
167
Timur Tabi275f4bb2011-11-22 09:21:25 -0600168#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
Wolfgang Denke366f152009-04-05 00:27:57 +0200169 /*
170 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
171 */
Zhao Qiang83a90842014-03-21 16:21:44 +0800172 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Haiying Wangec9d36c2009-03-26 17:01:49 -0400173
Wolfgang Denke366f152009-04-05 00:27:57 +0200174 /* enable the microcode in IRAM */
175 out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
Haiying Wangec9d36c2009-03-26 17:01:49 -0400176#endif
177
Simon Glass8518b172012-12-13 20:48:50 +0000178 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
179 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
Dave Liue732e9c2006-11-03 12:11:15 -0600180
181 qe_sdma_init();
182 qe_snums_init();
183}
184
Zhao Qiang5ad93952014-09-25 13:52:25 +0800185#ifdef CONFIG_U_QE
186void u_qe_init(void)
187{
188 uint qe_base = CONFIG_SYS_IMMR + 0x01400000; /* QE immr base */
189 qe_immr = (qe_map_t *)qe_base;
190
Zhao Qianga985f822014-11-04 13:46:16 +0800191 u_qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Zhao Qiang5ad93952014-09-25 13:52:25 +0800192 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
193}
194#endif
195
Dave Liue732e9c2006-11-03 12:11:15 -0600196void qe_reset(void)
197{
198 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
199 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
200}
201
202void qe_assign_page(uint snum, uint para_ram_base)
203{
204 u32 cecr;
205
206 out_be32(&qe_immr->cp.cecdr, para_ram_base);
207 out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
208 | QE_CR_FLG | QE_ASSIGN_PAGE);
209
210 /* Wait for the QE_CR_FLG to clear */
211 do {
212 cecr = in_be32(&qe_immr->cp.cecr);
213 } while (cecr & QE_CR_FLG );
214
215 return;
216}
217
218/*
219 * brg: 0~15 as BRG1~BRG16
220 rate: baud rate
221 * BRG input clock comes from the BRGCLK (internal clock generated from
222 the QE clock, it is one-half of the QE clock), If need the clock source
223 from CLKn pin, we have te change the function.
224 */
225
Simon Glass34a194f2012-12-13 20:48:44 +0000226#define BRG_CLK (gd->arch.brg_clk)
Dave Liue732e9c2006-11-03 12:11:15 -0600227
Zhao Qiang5ad93952014-09-25 13:52:25 +0800228#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -0600229int qe_set_brg(uint brg, uint rate)
230{
Dave Liue732e9c2006-11-03 12:11:15 -0600231 volatile uint *bp;
232 u32 divisor;
233 int div16 = 0;
234
235 if (brg >= QE_NUM_OF_BRGS)
236 return -EINVAL;
237 bp = (uint *)&qe_immr->brg.brgc1;
238 bp += brg;
239
240 divisor = (BRG_CLK / rate);
241 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
242 div16 = 1;
243 divisor /= 16;
244 }
245
246 *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
247 __asm__ __volatile__("sync");
248
249 if (div16) {
250 *bp |= QE_BRGC_DIV16;
251 __asm__ __volatile__("sync");
252 }
253
254 return 0;
255}
Zhao Qiang5ad93952014-09-25 13:52:25 +0800256#endif
Dave Liue732e9c2006-11-03 12:11:15 -0600257
258/* Set ethernet MII clock master
259*/
260int qe_set_mii_clk_src(int ucc_num)
261{
262 u32 cmxgcr;
263
264 /* check if the UCC number is in range. */
265 if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
266 printf("%s: ucc num not in ranges\n", __FUNCTION__);
267 return -EINVAL;
268 }
269
270 cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
271 cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
272 cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
273 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
274
275 return 0;
276}
277
Timur Tabi6d838da2008-01-07 13:31:19 -0600278/* Firmware information stored here for qe_get_firmware_info() */
279static struct qe_firmware_info qe_firmware_info;
280
281/*
282 * Set to 1 if QE firmware has been uploaded, and therefore
283 * qe_firmware_info contains valid data.
284 */
285static int qe_firmware_uploaded;
286
287/*
288 * Upload a QE microcode
289 *
290 * This function is a worker function for qe_upload_firmware(). It does
291 * the actual uploading of the microcode.
292 */
293static void qe_upload_microcode(const void *base,
294 const struct qe_microcode *ucode)
295{
296 const u32 *code = base + be32_to_cpu(ucode->code_offset);
297 unsigned int i;
298
299 if (ucode->major || ucode->minor || ucode->revision)
300 printf("QE: uploading microcode '%s' version %u.%u.%u\n",
301 ucode->id, ucode->major, ucode->minor, ucode->revision);
302 else
303 printf("QE: uploading microcode '%s'\n", ucode->id);
304
305 /* Use auto-increment */
306 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
307 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
308
309 for (i = 0; i < be32_to_cpu(ucode->count); i++)
310 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
311}
312
313/*
314 * Upload a microcode to the I-RAM at a specific address.
315 *
316 * See docs/README.qe_firmware for information on QE microcode uploading.
317 *
318 * Currently, only version 1 is supported, so the 'version' field must be
319 * set to 1.
320 *
321 * The SOC model and revision are not validated, they are only displayed for
322 * informational purposes.
323 *
324 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
325 * all of the microcode structures, minus the CRC.
326 *
327 * 'length' is the size that the structure says it is, including the CRC.
328 */
329int qe_upload_firmware(const struct qe_firmware *firmware)
330{
331 unsigned int i;
332 unsigned int j;
333 u32 crc;
334 size_t calc_size = sizeof(struct qe_firmware);
335 size_t length;
336 const struct qe_header *hdr;
Zhao Qiangb59534d2014-04-30 16:45:31 +0800337#ifdef CONFIG_DEEP_SLEEP
338 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
339#endif
Timur Tabi6d838da2008-01-07 13:31:19 -0600340 if (!firmware) {
341 printf("Invalid address\n");
342 return -EINVAL;
343 }
344
345 hdr = &firmware->header;
346 length = be32_to_cpu(hdr->length);
347
348 /* Check the magic */
349 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
350 (hdr->magic[2] != 'F')) {
Vijay Raia4792292014-07-23 18:33:16 +0530351 printf("QE microcode not found\n");
Zhao Qiangb59534d2014-04-30 16:45:31 +0800352#ifdef CONFIG_DEEP_SLEEP
353 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
354#endif
Timur Tabi6d838da2008-01-07 13:31:19 -0600355 return -EPERM;
356 }
357
358 /* Check the version */
359 if (hdr->version != 1) {
360 printf("Unsupported version\n");
361 return -EPERM;
362 }
363
364 /* Validate some of the fields */
Timur Tabic6c0fd52008-03-03 09:58:52 -0600365 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
Timur Tabi6d838da2008-01-07 13:31:19 -0600366 printf("Invalid data\n");
367 return -EINVAL;
368 }
369
370 /* Validate the length and check if there's a CRC */
371 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
372
373 for (i = 0; i < firmware->count; i++)
374 /*
375 * For situations where the second RISC uses the same microcode
376 * as the first, the 'code_offset' and 'count' fields will be
377 * zero, so it's okay to add those.
378 */
379 calc_size += sizeof(u32) *
380 be32_to_cpu(firmware->microcode[i].count);
381
382 /* Validate the length */
383 if (length != calc_size + sizeof(u32)) {
384 printf("Invalid length\n");
385 return -EPERM;
386 }
387
Wolfgang Denk545b06a2008-01-10 00:55:14 +0100388 /*
389 * Validate the CRC. We would normally call crc32_no_comp(), but that
390 * function isn't available unless you turn on JFFS support.
391 */
Timur Tabi6d838da2008-01-07 13:31:19 -0600392 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
393 if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
394 printf("Firmware CRC is invalid\n");
395 return -EIO;
396 }
397
398 /*
399 * If the microcode calls for it, split the I-RAM.
400 */
401 if (!firmware->split) {
402 out_be16(&qe_immr->cp.cercr,
403 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
404 }
405
406 if (firmware->soc.model)
407 printf("Firmware '%s' for %u V%u.%u\n",
408 firmware->id, be16_to_cpu(firmware->soc.model),
409 firmware->soc.major, firmware->soc.minor);
410 else
411 printf("Firmware '%s'\n", firmware->id);
412
413 /*
414 * The QE only supports one microcode per RISC, so clear out all the
415 * saved microcode information and put in the new.
416 */
417 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Dave Liu8a7e0a52008-01-14 11:12:01 +0800418 strcpy(qe_firmware_info.id, (char *)firmware->id);
Timur Tabi6d838da2008-01-07 13:31:19 -0600419 qe_firmware_info.extended_modes = firmware->extended_modes;
420 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
421 sizeof(firmware->vtraps));
422 qe_firmware_uploaded = 1;
423
424 /* Loop through each microcode. */
425 for (i = 0; i < firmware->count; i++) {
426 const struct qe_microcode *ucode = &firmware->microcode[i];
427
428 /* Upload a microcode if it's present */
429 if (ucode->code_offset)
430 qe_upload_microcode(firmware, ucode);
431
432 /* Program the traps for this processor */
433 for (j = 0; j < 16; j++) {
434 u32 trap = be32_to_cpu(ucode->traps[j]);
435
436 if (trap)
437 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
438 }
439
440 /* Enable traps */
441 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
442 }
443
444 return 0;
445}
446
Zhao Qianga985f822014-11-04 13:46:16 +0800447#ifdef CONFIG_U_QE
448/*
449 * Upload a microcode to the I-RAM at a specific address.
450 *
451 * See docs/README.qe_firmware for information on QE microcode uploading.
452 *
453 * Currently, only version 1 is supported, so the 'version' field must be
454 * set to 1.
455 *
456 * The SOC model and revision are not validated, they are only displayed for
457 * informational purposes.
458 *
459 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
460 * all of the microcode structures, minus the CRC.
461 *
462 * 'length' is the size that the structure says it is, including the CRC.
463 */
464int u_qe_upload_firmware(const struct qe_firmware *firmware)
465{
466 unsigned int i;
467 unsigned int j;
468 u32 crc;
469 size_t calc_size = sizeof(struct qe_firmware);
470 size_t length;
471 const struct qe_header *hdr;
472#ifdef CONFIG_DEEP_SLEEP
473 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
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 /* Check the magic */
484 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
485 (hdr->magic[2] != 'F')) {
486 printf("Not a microcode\n");
487#ifdef CONFIG_DEEP_SLEEP
488 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
489#endif
490 return -EPERM;
491 }
492
493 /* Check the version */
494 if (hdr->version != 1) {
495 printf("Unsupported version\n");
496 return -EPERM;
497 }
498
499 /* Validate some of the fields */
500 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
501 printf("Invalid data\n");
502 return -EINVAL;
503 }
504
505 /* Validate the length and check if there's a CRC */
506 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
507
508 for (i = 0; i < firmware->count; i++)
509 /*
510 * For situations where the second RISC uses the same microcode
511 * as the first, the 'code_offset' and 'count' fields will be
512 * zero, so it's okay to add those.
513 */
514 calc_size += sizeof(u32) *
515 be32_to_cpu(firmware->microcode[i].count);
516
517 /* Validate the length */
518 if (length != calc_size + sizeof(u32)) {
519 printf("Invalid length\n");
520 return -EPERM;
521 }
522
523 /*
524 * Validate the CRC. We would normally call crc32_no_comp(), but that
525 * function isn't available unless you turn on JFFS support.
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 * If the microcode calls for it, split the I-RAM.
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 /* Loop through each microcode. */
549 for (i = 0; i < firmware->count; i++) {
550 const struct qe_microcode *ucode = &firmware->microcode[i];
551
552 /* Upload a microcode if it's present */
553 if (ucode->code_offset)
554 qe_upload_microcode(firmware, ucode);
555
556 /* Program the traps for this processor */
557 for (j = 0; j < 16; j++) {
558 u32 trap = be32_to_cpu(ucode->traps[j]);
559
560 if (trap)
561 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
562 }
563
564 /* Enable traps */
565 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
566 }
567
568 return 0;
569}
570#endif
571
Timur Tabi6d838da2008-01-07 13:31:19 -0600572struct qe_firmware_info *qe_get_firmware_info(void)
573{
574 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
575}
576
Wolfgang Denk6262d0212010-06-28 22:00:46 +0200577static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Timur Tabi6d838da2008-01-07 13:31:19 -0600578{
579 ulong addr;
580
Wolfgang Denk3b683112010-07-17 01:06:04 +0200581 if (argc < 3)
582 return cmd_usage(cmdtp);
Timur Tabi6d838da2008-01-07 13:31:19 -0600583
584 if (strcmp(argv[1], "fw") == 0) {
585 addr = simple_strtoul(argv[2], NULL, 16);
586
587 if (!addr) {
588 printf("Invalid address\n");
589 return -EINVAL;
590 }
591
Wolfgang Denk545b06a2008-01-10 00:55:14 +0100592 /*
593 * If a length was supplied, compare that with the 'length'
594 * field.
595 */
Timur Tabi6d838da2008-01-07 13:31:19 -0600596
597 if (argc > 3) {
598 ulong length = simple_strtoul(argv[3], NULL, 16);
599 struct qe_firmware *firmware = (void *) addr;
600
601 if (length != be32_to_cpu(firmware->header.length)) {
602 printf("Length mismatch\n");
603 return -EINVAL;
604 }
605 }
606
607 return qe_upload_firmware((const struct qe_firmware *) addr);
608 }
609
Wolfgang Denk3b683112010-07-17 01:06:04 +0200610 return cmd_usage(cmdtp);
Timur Tabi6d838da2008-01-07 13:31:19 -0600611}
612
613U_BOOT_CMD(
614 qe, 4, 0, qe_cmd,
Peter Tyserdfb72b82009-01-27 18:03:12 -0600615 "QUICC Engine commands",
Timur Tabi6d838da2008-01-07 13:31:19 -0600616 "fw <addr> [<length>] - Upload firmware binary at address <addr> to "
Wolfgang Denkc54781c2009-05-24 17:06:54 +0200617 "the QE,\n"
618 "\twith optional length <length> verification."
619);