blob: d24651b5ba2b786e2a050cb3d98204d130365d6c [file] [log] [blame]
Dave Liu7737d5c2006-11-03 12:11:15 -06001/*
Haiying Wang4e7b25e2009-05-20 12:30:35 -04002 * Copyright (C) 2006-2009 Freescale Semiconductor, Inc.
Dave Liu7737d5c2006-11-03 12:11:15 -06003 *
4 * Dave Liu <daveliu@freescale.com>
5 * based on source code of Shlomi Gridish
6 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
Dave Liu7737d5c2006-11-03 12:11:15 -06008 */
9
10#include "common.h"
Timur Tabib8ec2382008-01-07 13:31:19 -060011#include <command.h>
Dave Liu7737d5c2006-11-03 12:11:15 -060012#include "asm/errno.h"
13#include "asm/io.h"
Zhao Qiang38d67a4e2014-06-03 16:27:07 +080014#include "linux/immap_qe.h"
Dave Liu7737d5c2006-11-03 12:11:15 -060015#include "qe.h"
Zhao Qiang9c7c86f2014-12-15 15:50:49 +080016#ifdef CONFIG_LS102XA
17#include <asm/arch/immap_ls102xa.h>
18#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060019
Zhao Qiangca721fb2014-04-30 16:45:31 +080020#define MPC85xx_DEVDISR_QE_DISABLE 0x1
21
Dave Liu7737d5c2006-11-03 12:11:15 -060022qe_map_t *qe_immr = NULL;
23static qe_snum_t snums[QE_NUM_OF_SNUM];
24
Wolfgang Denk1218abf2007-09-15 20:48:41 +020025DECLARE_GLOBAL_DATA_PTR;
26
Dave Liu7737d5c2006-11-03 12:11:15 -060027void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
28{
Wolfgang Denkd3a65322008-01-10 00:55:14 +010029 u32 cecr;
Dave Liu7737d5c2006-11-03 12:11:15 -060030
31 if (cmd == QE_RESET) {
32 out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG));
33 } else {
34 out_be32(&qe_immr->cp.cecdr, cmd_data);
35 out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
36 ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd));
37 }
38 /* Wait for the QE_CR_FLG to clear */
39 do {
40 cecr = in_be32(&qe_immr->cp.cecr);
41 } while (cecr & QE_CR_FLG);
42
43 return;
44}
45
Zhao Qiang93d33202014-09-25 13:52:25 +080046#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060047uint qe_muram_alloc(uint size, uint align)
48{
Dave Liu7737d5c2006-11-03 12:11:15 -060049 uint retloc;
50 uint align_mask, off;
51 uint savebase;
52
53 align_mask = align - 1;
Simon Glass45bae2e2012-12-13 20:48:50 +000054 savebase = gd->arch.mp_alloc_base;
Dave Liu7737d5c2006-11-03 12:11:15 -060055
Simon Glass45bae2e2012-12-13 20:48:50 +000056 off = gd->arch.mp_alloc_base & align_mask;
57 if (off != 0)
58 gd->arch.mp_alloc_base += (align - off);
Dave Liu7737d5c2006-11-03 12:11:15 -060059
60 if ((off = size & align_mask) != 0)
61 size += (align - off);
62
Simon Glass45bae2e2012-12-13 20:48:50 +000063 if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
64 gd->arch.mp_alloc_base = savebase;
Dave Liu7737d5c2006-11-03 12:11:15 -060065 printf("%s: ran out of ram.\n", __FUNCTION__);
66 }
67
Simon Glass45bae2e2012-12-13 20:48:50 +000068 retloc = gd->arch.mp_alloc_base;
69 gd->arch.mp_alloc_base += size;
Dave Liu7737d5c2006-11-03 12:11:15 -060070
71 memset((void *)&qe_immr->muram[retloc], 0, size);
72
73 __asm__ __volatile__("sync");
74
75 return retloc;
76}
Zhao Qiang93d33202014-09-25 13:52:25 +080077#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060078
79void *qe_muram_addr(uint offset)
80{
81 return (void *)&qe_immr->muram[offset];
82}
83
84static void qe_sdma_init(void)
85{
86 volatile sdma_t *p;
87 uint sdma_buffer_base;
88
89 p = (volatile sdma_t *)&qe_immr->sdma;
90
91 /* All of DMA transaction in bus 1 */
92 out_be32(&p->sdaqr, 0);
93 out_be32(&p->sdaqmr, 0);
94
95 /* Allocate 2KB temporary buffer for sdma */
Dave Liuff9658d2007-06-25 10:41:04 +080096 sdma_buffer_base = qe_muram_alloc(2048, 4096);
Dave Liu7737d5c2006-11-03 12:11:15 -060097 out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
98
99 /* Clear sdma status */
100 out_be32(&p->sdsr, 0x03000000);
101
102 /* Enable global mode on bus 1, and 2KB buffer size */
103 out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
104}
105
Haiying Wang4e7b25e2009-05-20 12:30:35 -0400106/* This table is a list of the serial numbers of the Threads, taken from the
107 * "SNUM Table" chart in the QE Reference Manual. The order is not important,
108 * we just need to know what the SNUMs are for the threads.
109 */
110static u8 thread_snum[] = {
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000111/* Evthreads 16-29 are not supported in MPC8309 */
112#if !defined(CONFIG_MPC8309)
Dave Liu7737d5c2006-11-03 12:11:15 -0600113 0x04, 0x05, 0x0c, 0x0d,
114 0x14, 0x15, 0x1c, 0x1d,
115 0x24, 0x25, 0x2c, 0x2d,
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000116 0x34, 0x35,
117#endif
118 0x88, 0x89, 0x98, 0x99,
119 0xa8, 0xa9, 0xb8, 0xb9,
120 0xc8, 0xc9, 0xd8, 0xd9,
121 0xe8, 0xe9, 0x08, 0x09,
122 0x18, 0x19, 0x28, 0x29,
123 0x38, 0x39, 0x48, 0x49,
124 0x58, 0x59, 0x68, 0x69,
125 0x78, 0x79, 0x80, 0x81
Dave Liu7737d5c2006-11-03 12:11:15 -0600126};
127
128static void qe_snums_init(void)
129{
130 int i;
131
132 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
133 snums[i].state = QE_SNUM_STATE_FREE;
134 snums[i].num = thread_snum[i];
135 }
136}
137
138int qe_get_snum(void)
139{
140 int snum = -EBUSY;
141 int i;
142
143 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
144 if (snums[i].state == QE_SNUM_STATE_FREE) {
145 snums[i].state = QE_SNUM_STATE_USED;
146 snum = snums[i].num;
147 break;
148 }
149 }
150
151 return snum;
152}
153
154void qe_put_snum(u8 snum)
155{
156 int i;
157
158 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
159 if (snums[i].num == snum) {
160 snums[i].state = QE_SNUM_STATE_FREE;
161 break;
162 }
163 }
164}
165
166void qe_init(uint qe_base)
167{
Dave Liu7737d5c2006-11-03 12:11:15 -0600168 /* Init the QE IMMR base */
169 qe_immr = (qe_map_t *)qe_base;
170
Timur Tabif2717b42011-11-22 09:21:25 -0600171#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200172 /*
173 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
174 */
Zhao Qiangdcf1d772014-03-21 16:21:44 +0800175 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400176
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200177 /* enable the microcode in IRAM */
178 out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400179#endif
180
Simon Glass45bae2e2012-12-13 20:48:50 +0000181 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
182 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
Dave Liu7737d5c2006-11-03 12:11:15 -0600183
184 qe_sdma_init();
185 qe_snums_init();
186}
187
Zhao Qiang93d33202014-09-25 13:52:25 +0800188#ifdef CONFIG_U_QE
189void u_qe_init(void)
190{
191 uint qe_base = CONFIG_SYS_IMMR + 0x01400000; /* QE immr base */
192 qe_immr = (qe_map_t *)qe_base;
193
Zhao Qiang5632d152014-11-04 13:46:16 +0800194 u_qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Zhao Qiang93d33202014-09-25 13:52:25 +0800195 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
196}
197#endif
198
Dave Liu7737d5c2006-11-03 12:11:15 -0600199void qe_reset(void)
200{
201 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
202 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
203}
204
205void qe_assign_page(uint snum, uint para_ram_base)
206{
207 u32 cecr;
208
209 out_be32(&qe_immr->cp.cecdr, para_ram_base);
210 out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
211 | QE_CR_FLG | QE_ASSIGN_PAGE);
212
213 /* Wait for the QE_CR_FLG to clear */
214 do {
215 cecr = in_be32(&qe_immr->cp.cecr);
216 } while (cecr & QE_CR_FLG );
217
218 return;
219}
220
221/*
222 * brg: 0~15 as BRG1~BRG16
223 rate: baud rate
224 * BRG input clock comes from the BRGCLK (internal clock generated from
225 the QE clock, it is one-half of the QE clock), If need the clock source
226 from CLKn pin, we have te change the function.
227 */
228
Simon Glass1206c182012-12-13 20:48:44 +0000229#define BRG_CLK (gd->arch.brg_clk)
Dave Liu7737d5c2006-11-03 12:11:15 -0600230
Zhao Qiang93d33202014-09-25 13:52:25 +0800231#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -0600232int qe_set_brg(uint brg, uint rate)
233{
Dave Liu7737d5c2006-11-03 12:11:15 -0600234 volatile uint *bp;
235 u32 divisor;
236 int div16 = 0;
237
238 if (brg >= QE_NUM_OF_BRGS)
239 return -EINVAL;
240 bp = (uint *)&qe_immr->brg.brgc1;
241 bp += brg;
242
243 divisor = (BRG_CLK / rate);
244 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
245 div16 = 1;
246 divisor /= 16;
247 }
248
249 *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
250 __asm__ __volatile__("sync");
251
252 if (div16) {
253 *bp |= QE_BRGC_DIV16;
254 __asm__ __volatile__("sync");
255 }
256
257 return 0;
258}
Zhao Qiang93d33202014-09-25 13:52:25 +0800259#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600260
261/* Set ethernet MII clock master
262*/
263int qe_set_mii_clk_src(int ucc_num)
264{
265 u32 cmxgcr;
266
267 /* check if the UCC number is in range. */
268 if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
269 printf("%s: ucc num not in ranges\n", __FUNCTION__);
270 return -EINVAL;
271 }
272
273 cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
274 cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
275 cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
276 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
277
278 return 0;
279}
280
Timur Tabib8ec2382008-01-07 13:31:19 -0600281/* Firmware information stored here for qe_get_firmware_info() */
282static struct qe_firmware_info qe_firmware_info;
283
284/*
285 * Set to 1 if QE firmware has been uploaded, and therefore
286 * qe_firmware_info contains valid data.
287 */
288static int qe_firmware_uploaded;
289
290/*
291 * Upload a QE microcode
292 *
293 * This function is a worker function for qe_upload_firmware(). It does
294 * the actual uploading of the microcode.
295 */
296static void qe_upload_microcode(const void *base,
297 const struct qe_microcode *ucode)
298{
299 const u32 *code = base + be32_to_cpu(ucode->code_offset);
300 unsigned int i;
301
302 if (ucode->major || ucode->minor || ucode->revision)
303 printf("QE: uploading microcode '%s' version %u.%u.%u\n",
304 ucode->id, ucode->major, ucode->minor, ucode->revision);
305 else
306 printf("QE: uploading microcode '%s'\n", ucode->id);
307
308 /* Use auto-increment */
309 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
310 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
311
312 for (i = 0; i < be32_to_cpu(ucode->count); i++)
313 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
314}
315
316/*
317 * Upload a microcode to the I-RAM at a specific address.
318 *
319 * See docs/README.qe_firmware for information on QE microcode uploading.
320 *
321 * Currently, only version 1 is supported, so the 'version' field must be
322 * set to 1.
323 *
324 * The SOC model and revision are not validated, they are only displayed for
325 * informational purposes.
326 *
327 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
328 * all of the microcode structures, minus the CRC.
329 *
330 * 'length' is the size that the structure says it is, including the CRC.
331 */
332int qe_upload_firmware(const struct qe_firmware *firmware)
333{
334 unsigned int i;
335 unsigned int j;
336 u32 crc;
337 size_t calc_size = sizeof(struct qe_firmware);
338 size_t length;
339 const struct qe_header *hdr;
Zhao Qiangca721fb2014-04-30 16:45:31 +0800340#ifdef CONFIG_DEEP_SLEEP
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800341#ifdef CONFIG_LS102XA
342 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
343#else
Zhao Qiangca721fb2014-04-30 16:45:31 +0800344 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
345#endif
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800346#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600347 if (!firmware) {
348 printf("Invalid address\n");
349 return -EINVAL;
350 }
351
352 hdr = &firmware->header;
353 length = be32_to_cpu(hdr->length);
354
355 /* Check the magic */
356 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
357 (hdr->magic[2] != 'F')) {
Vijay Rai12eeb132014-07-23 18:33:16 +0530358 printf("QE microcode not found\n");
Zhao Qiangca721fb2014-04-30 16:45:31 +0800359#ifdef CONFIG_DEEP_SLEEP
360 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
361#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600362 return -EPERM;
363 }
364
365 /* Check the version */
366 if (hdr->version != 1) {
367 printf("Unsupported version\n");
368 return -EPERM;
369 }
370
371 /* Validate some of the fields */
Timur Tabi491fb6d2008-03-03 09:58:52 -0600372 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
Timur Tabib8ec2382008-01-07 13:31:19 -0600373 printf("Invalid data\n");
374 return -EINVAL;
375 }
376
377 /* Validate the length and check if there's a CRC */
378 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
379
380 for (i = 0; i < firmware->count; i++)
381 /*
382 * For situations where the second RISC uses the same microcode
383 * as the first, the 'code_offset' and 'count' fields will be
384 * zero, so it's okay to add those.
385 */
386 calc_size += sizeof(u32) *
387 be32_to_cpu(firmware->microcode[i].count);
388
389 /* Validate the length */
390 if (length != calc_size + sizeof(u32)) {
391 printf("Invalid length\n");
392 return -EPERM;
393 }
394
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100395 /*
396 * Validate the CRC. We would normally call crc32_no_comp(), but that
397 * function isn't available unless you turn on JFFS support.
398 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600399 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
400 if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
401 printf("Firmware CRC is invalid\n");
402 return -EIO;
403 }
404
405 /*
406 * If the microcode calls for it, split the I-RAM.
407 */
408 if (!firmware->split) {
409 out_be16(&qe_immr->cp.cercr,
410 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
411 }
412
413 if (firmware->soc.model)
414 printf("Firmware '%s' for %u V%u.%u\n",
415 firmware->id, be16_to_cpu(firmware->soc.model),
416 firmware->soc.major, firmware->soc.minor);
417 else
418 printf("Firmware '%s'\n", firmware->id);
419
420 /*
421 * The QE only supports one microcode per RISC, so clear out all the
422 * saved microcode information and put in the new.
423 */
424 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Dave Liu06c428b2008-01-14 11:12:01 +0800425 strcpy(qe_firmware_info.id, (char *)firmware->id);
Timur Tabib8ec2382008-01-07 13:31:19 -0600426 qe_firmware_info.extended_modes = firmware->extended_modes;
427 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
428 sizeof(firmware->vtraps));
429 qe_firmware_uploaded = 1;
430
431 /* Loop through each microcode. */
432 for (i = 0; i < firmware->count; i++) {
433 const struct qe_microcode *ucode = &firmware->microcode[i];
434
435 /* Upload a microcode if it's present */
436 if (ucode->code_offset)
437 qe_upload_microcode(firmware, ucode);
438
439 /* Program the traps for this processor */
440 for (j = 0; j < 16; j++) {
441 u32 trap = be32_to_cpu(ucode->traps[j]);
442
443 if (trap)
444 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
445 }
446
447 /* Enable traps */
448 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
449 }
450
451 return 0;
452}
453
Zhao Qiang5632d152014-11-04 13:46:16 +0800454#ifdef CONFIG_U_QE
455/*
456 * Upload a microcode to the I-RAM at a specific address.
457 *
458 * See docs/README.qe_firmware for information on QE microcode uploading.
459 *
460 * Currently, only version 1 is supported, so the 'version' field must be
461 * set to 1.
462 *
463 * The SOC model and revision are not validated, they are only displayed for
464 * informational purposes.
465 *
466 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
467 * all of the microcode structures, minus the CRC.
468 *
469 * 'length' is the size that the structure says it is, including the CRC.
470 */
471int u_qe_upload_firmware(const struct qe_firmware *firmware)
472{
473 unsigned int i;
474 unsigned int j;
475 u32 crc;
476 size_t calc_size = sizeof(struct qe_firmware);
477 size_t length;
478 const struct qe_header *hdr;
479#ifdef CONFIG_DEEP_SLEEP
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800480#ifdef CONFIG_LS102XA
481 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
482#else
Zhao Qiang5632d152014-11-04 13:46:16 +0800483 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
484#endif
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800485#endif
Zhao Qiang5632d152014-11-04 13:46:16 +0800486 if (!firmware) {
487 printf("Invalid address\n");
488 return -EINVAL;
489 }
490
491 hdr = &firmware->header;
492 length = be32_to_cpu(hdr->length);
493
494 /* Check the magic */
495 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
496 (hdr->magic[2] != 'F')) {
497 printf("Not a microcode\n");
498#ifdef CONFIG_DEEP_SLEEP
499 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
500#endif
501 return -EPERM;
502 }
503
504 /* Check the version */
505 if (hdr->version != 1) {
506 printf("Unsupported version\n");
507 return -EPERM;
508 }
509
510 /* Validate some of the fields */
511 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
512 printf("Invalid data\n");
513 return -EINVAL;
514 }
515
516 /* Validate the length and check if there's a CRC */
517 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
518
519 for (i = 0; i < firmware->count; i++)
520 /*
521 * For situations where the second RISC uses the same microcode
522 * as the first, the 'code_offset' and 'count' fields will be
523 * zero, so it's okay to add those.
524 */
525 calc_size += sizeof(u32) *
526 be32_to_cpu(firmware->microcode[i].count);
527
528 /* Validate the length */
529 if (length != calc_size + sizeof(u32)) {
530 printf("Invalid length\n");
531 return -EPERM;
532 }
533
534 /*
535 * Validate the CRC. We would normally call crc32_no_comp(), but that
536 * function isn't available unless you turn on JFFS support.
537 */
538 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
539 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
540 printf("Firmware CRC is invalid\n");
541 return -EIO;
542 }
543
544 /*
545 * If the microcode calls for it, split the I-RAM.
546 */
547 if (!firmware->split) {
548 out_be16(&qe_immr->cp.cercr,
549 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
550 }
551
552 if (firmware->soc.model)
553 printf("Firmware '%s' for %u V%u.%u\n",
554 firmware->id, be16_to_cpu(firmware->soc.model),
555 firmware->soc.major, firmware->soc.minor);
556 else
557 printf("Firmware '%s'\n", firmware->id);
558
559 /* Loop through each microcode. */
560 for (i = 0; i < firmware->count; i++) {
561 const struct qe_microcode *ucode = &firmware->microcode[i];
562
563 /* Upload a microcode if it's present */
564 if (ucode->code_offset)
565 qe_upload_microcode(firmware, ucode);
566
567 /* Program the traps for this processor */
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 /* Enable traps */
576 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
577 }
578
579 return 0;
580}
581#endif
582
Timur Tabib8ec2382008-01-07 13:31:19 -0600583struct qe_firmware_info *qe_get_firmware_info(void)
584{
585 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
586}
587
Wolfgang Denk54841ab2010-06-28 22:00:46 +0200588static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Timur Tabib8ec2382008-01-07 13:31:19 -0600589{
590 ulong addr;
591
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200592 if (argc < 3)
593 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600594
595 if (strcmp(argv[1], "fw") == 0) {
596 addr = simple_strtoul(argv[2], NULL, 16);
597
598 if (!addr) {
599 printf("Invalid address\n");
600 return -EINVAL;
601 }
602
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100603 /*
604 * If a length was supplied, compare that with the 'length'
605 * field.
606 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600607
608 if (argc > 3) {
609 ulong length = simple_strtoul(argv[3], NULL, 16);
610 struct qe_firmware *firmware = (void *) addr;
611
612 if (length != be32_to_cpu(firmware->header.length)) {
613 printf("Length mismatch\n");
614 return -EINVAL;
615 }
616 }
617
618 return qe_upload_firmware((const struct qe_firmware *) addr);
619 }
620
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200621 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600622}
623
624U_BOOT_CMD(
625 qe, 4, 0, qe_cmd,
Peter Tyser2fb26042009-01-27 18:03:12 -0600626 "QUICC Engine commands",
Timur Tabib8ec2382008-01-07 13:31:19 -0600627 "fw <addr> [<length>] - Upload firmware binary at address <addr> to "
Wolfgang Denka89c33d2009-05-24 17:06:54 +0200628 "the QE,\n"
629 "\twith optional length <length> verification."
630);