blob: 4f0a27892f2e8e19de9f3605b0de94cdaeb1b018 [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
Masahiro Yamadab5bf5cb2016-09-21 11:28:53 +090010#include <common.h>
Timur Tabib8ec2382008-01-07 13:31:19 -060011#include <command.h>
Masahiro Yamada1221ce42016-09-21 11:28:55 +090012#include <linux/errno.h>
Masahiro Yamadab5bf5cb2016-09-21 11:28:53 +090013#include <asm/io.h>
14#include <linux/immap_qe.h>
Qianyu Gong2459afb2016-02-18 13:01:59 +080015#include <fsl_qe.h>
York Sun73fb5832017-03-27 11:41:03 -070016#ifdef CONFIG_ARCH_LS1021A
Zhao Qiang9c7c86f2014-12-15 15:50:49 +080017#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;
Zhao Qiang3bf46e62016-02-05 10:04:16 +080023#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060024static qe_snum_t snums[QE_NUM_OF_SNUM];
Zhao Qiang3bf46e62016-02-05 10:04:16 +080025#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060026
Wolfgang Denk1218abf2007-09-15 20:48:41 +020027DECLARE_GLOBAL_DATA_PTR;
28
Dave Liu7737d5c2006-11-03 12:11:15 -060029void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
30{
Wolfgang Denkd3a65322008-01-10 00:55:14 +010031 u32 cecr;
Dave Liu7737d5c2006-11-03 12:11:15 -060032
33 if (cmd == QE_RESET) {
34 out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG));
35 } else {
36 out_be32(&qe_immr->cp.cecdr, cmd_data);
37 out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
38 ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd));
39 }
40 /* Wait for the QE_CR_FLG to clear */
41 do {
42 cecr = in_be32(&qe_immr->cp.cecr);
43 } while (cecr & QE_CR_FLG);
44
45 return;
46}
47
Zhao Qiang93d33202014-09-25 13:52:25 +080048#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060049uint qe_muram_alloc(uint size, uint align)
50{
Dave Liu7737d5c2006-11-03 12:11:15 -060051 uint retloc;
52 uint align_mask, off;
53 uint savebase;
54
55 align_mask = align - 1;
Simon Glass45bae2e2012-12-13 20:48:50 +000056 savebase = gd->arch.mp_alloc_base;
Dave Liu7737d5c2006-11-03 12:11:15 -060057
Simon Glass45bae2e2012-12-13 20:48:50 +000058 off = gd->arch.mp_alloc_base & align_mask;
59 if (off != 0)
60 gd->arch.mp_alloc_base += (align - off);
Dave Liu7737d5c2006-11-03 12:11:15 -060061
62 if ((off = size & align_mask) != 0)
63 size += (align - off);
64
Simon Glass45bae2e2012-12-13 20:48:50 +000065 if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
66 gd->arch.mp_alloc_base = savebase;
Dave Liu7737d5c2006-11-03 12:11:15 -060067 printf("%s: ran out of ram.\n", __FUNCTION__);
68 }
69
Simon Glass45bae2e2012-12-13 20:48:50 +000070 retloc = gd->arch.mp_alloc_base;
71 gd->arch.mp_alloc_base += size;
Dave Liu7737d5c2006-11-03 12:11:15 -060072
73 memset((void *)&qe_immr->muram[retloc], 0, size);
74
75 __asm__ __volatile__("sync");
76
77 return retloc;
78}
Zhao Qiang93d33202014-09-25 13:52:25 +080079#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060080
81void *qe_muram_addr(uint offset)
82{
83 return (void *)&qe_immr->muram[offset];
84}
85
Zhao Qiang3bf46e62016-02-05 10:04:16 +080086#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060087static void qe_sdma_init(void)
88{
89 volatile sdma_t *p;
90 uint sdma_buffer_base;
91
92 p = (volatile sdma_t *)&qe_immr->sdma;
93
94 /* All of DMA transaction in bus 1 */
95 out_be32(&p->sdaqr, 0);
96 out_be32(&p->sdaqmr, 0);
97
98 /* Allocate 2KB temporary buffer for sdma */
Dave Liuff9658d2007-06-25 10:41:04 +080099 sdma_buffer_base = qe_muram_alloc(2048, 4096);
Dave Liu7737d5c2006-11-03 12:11:15 -0600100 out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
101
102 /* Clear sdma status */
103 out_be32(&p->sdsr, 0x03000000);
104
105 /* Enable global mode on bus 1, and 2KB buffer size */
106 out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
107}
108
Haiying Wang4e7b25e2009-05-20 12:30:35 -0400109/* This table is a list of the serial numbers of the Threads, taken from the
110 * "SNUM Table" chart in the QE Reference Manual. The order is not important,
111 * we just need to know what the SNUMs are for the threads.
112 */
113static u8 thread_snum[] = {
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000114/* Evthreads 16-29 are not supported in MPC8309 */
115#if !defined(CONFIG_MPC8309)
Dave Liu7737d5c2006-11-03 12:11:15 -0600116 0x04, 0x05, 0x0c, 0x0d,
117 0x14, 0x15, 0x1c, 0x1d,
118 0x24, 0x25, 0x2c, 0x2d,
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000119 0x34, 0x35,
120#endif
121 0x88, 0x89, 0x98, 0x99,
122 0xa8, 0xa9, 0xb8, 0xb9,
123 0xc8, 0xc9, 0xd8, 0xd9,
124 0xe8, 0xe9, 0x08, 0x09,
125 0x18, 0x19, 0x28, 0x29,
126 0x38, 0x39, 0x48, 0x49,
127 0x58, 0x59, 0x68, 0x69,
128 0x78, 0x79, 0x80, 0x81
Dave Liu7737d5c2006-11-03 12:11:15 -0600129};
130
131static void qe_snums_init(void)
132{
133 int i;
134
135 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
136 snums[i].state = QE_SNUM_STATE_FREE;
137 snums[i].num = thread_snum[i];
138 }
139}
140
141int qe_get_snum(void)
142{
143 int snum = -EBUSY;
144 int i;
145
146 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
147 if (snums[i].state == QE_SNUM_STATE_FREE) {
148 snums[i].state = QE_SNUM_STATE_USED;
149 snum = snums[i].num;
150 break;
151 }
152 }
153
154 return snum;
155}
156
157void qe_put_snum(u8 snum)
158{
159 int i;
160
161 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
162 if (snums[i].num == snum) {
163 snums[i].state = QE_SNUM_STATE_FREE;
164 break;
165 }
166 }
167}
168
169void qe_init(uint qe_base)
170{
Dave Liu7737d5c2006-11-03 12:11:15 -0600171 /* Init the QE IMMR base */
172 qe_immr = (qe_map_t *)qe_base;
173
Timur Tabif2717b42011-11-22 09:21:25 -0600174#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200175 /*
176 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
177 */
Zhao Qiangdcf1d772014-03-21 16:21:44 +0800178 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400179
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200180 /* enable the microcode in IRAM */
181 out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400182#endif
183
Simon Glass45bae2e2012-12-13 20:48:50 +0000184 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
185 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
Dave Liu7737d5c2006-11-03 12:11:15 -0600186
187 qe_sdma_init();
188 qe_snums_init();
189}
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800190#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600191
Zhao Qiang93d33202014-09-25 13:52:25 +0800192#ifdef CONFIG_U_QE
193void u_qe_init(void)
194{
Zhao Qiangd3e6d302016-02-05 10:04:17 +0800195 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiang93d33202014-09-25 13:52:25 +0800196
Zhao Qiang5632d152014-11-04 13:46:16 +0800197 u_qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Zhao Qiang93d33202014-09-25 13:52:25 +0800198 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
199}
200#endif
201
Zhao Qiangae42eb02015-03-25 17:02:59 +0800202#ifdef CONFIG_U_QE
203void u_qe_resume(void)
204{
205 qe_map_t *qe_immrr;
Zhao Qiangae42eb02015-03-25 17:02:59 +0800206
Zhao Qiangd3e6d302016-02-05 10:04:17 +0800207 qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiangae42eb02015-03-25 17:02:59 +0800208 u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr);
209 out_be32(&qe_immrr->iram.iready, QE_IRAM_READY);
210}
211#endif
212
Dave Liu7737d5c2006-11-03 12:11:15 -0600213void qe_reset(void)
214{
215 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
216 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
217}
218
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800219#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -0600220void qe_assign_page(uint snum, uint para_ram_base)
221{
222 u32 cecr;
223
224 out_be32(&qe_immr->cp.cecdr, para_ram_base);
225 out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
226 | QE_CR_FLG | QE_ASSIGN_PAGE);
227
228 /* Wait for the QE_CR_FLG to clear */
229 do {
230 cecr = in_be32(&qe_immr->cp.cecr);
231 } while (cecr & QE_CR_FLG );
232
233 return;
234}
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800235#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600236
237/*
238 * brg: 0~15 as BRG1~BRG16
239 rate: baud rate
240 * BRG input clock comes from the BRGCLK (internal clock generated from
241 the QE clock, it is one-half of the QE clock), If need the clock source
242 from CLKn pin, we have te change the function.
243 */
244
Simon Glass1206c182012-12-13 20:48:44 +0000245#define BRG_CLK (gd->arch.brg_clk)
Dave Liu7737d5c2006-11-03 12:11:15 -0600246
Zhao Qiang93d33202014-09-25 13:52:25 +0800247#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -0600248int qe_set_brg(uint brg, uint rate)
249{
Dave Liu7737d5c2006-11-03 12:11:15 -0600250 volatile uint *bp;
251 u32 divisor;
252 int div16 = 0;
253
254 if (brg >= QE_NUM_OF_BRGS)
255 return -EINVAL;
256 bp = (uint *)&qe_immr->brg.brgc1;
257 bp += brg;
258
259 divisor = (BRG_CLK / rate);
260 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
261 div16 = 1;
262 divisor /= 16;
263 }
264
265 *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
266 __asm__ __volatile__("sync");
267
268 if (div16) {
269 *bp |= QE_BRGC_DIV16;
270 __asm__ __volatile__("sync");
271 }
272
273 return 0;
274}
Zhao Qiang93d33202014-09-25 13:52:25 +0800275#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600276
277/* Set ethernet MII clock master
278*/
279int qe_set_mii_clk_src(int ucc_num)
280{
281 u32 cmxgcr;
282
283 /* check if the UCC number is in range. */
284 if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
285 printf("%s: ucc num not in ranges\n", __FUNCTION__);
286 return -EINVAL;
287 }
288
289 cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
290 cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
291 cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
292 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
293
294 return 0;
295}
296
Timur Tabib8ec2382008-01-07 13:31:19 -0600297/* Firmware information stored here for qe_get_firmware_info() */
298static struct qe_firmware_info qe_firmware_info;
299
300/*
301 * Set to 1 if QE firmware has been uploaded, and therefore
302 * qe_firmware_info contains valid data.
303 */
304static int qe_firmware_uploaded;
305
306/*
307 * Upload a QE microcode
308 *
309 * This function is a worker function for qe_upload_firmware(). It does
310 * the actual uploading of the microcode.
311 */
312static void qe_upload_microcode(const void *base,
313 const struct qe_microcode *ucode)
314{
315 const u32 *code = base + be32_to_cpu(ucode->code_offset);
316 unsigned int i;
317
318 if (ucode->major || ucode->minor || ucode->revision)
319 printf("QE: uploading microcode '%s' version %u.%u.%u\n",
Zhao Qiange94a8fd2015-05-05 15:53:32 +0800320 (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
321 (u16)ucode->revision);
Timur Tabib8ec2382008-01-07 13:31:19 -0600322 else
Zhao Qiange94a8fd2015-05-05 15:53:32 +0800323 printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
Timur Tabib8ec2382008-01-07 13:31:19 -0600324
325 /* Use auto-increment */
326 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
327 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
328
329 for (i = 0; i < be32_to_cpu(ucode->count); i++)
330 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
331}
332
333/*
334 * Upload a microcode to the I-RAM at a specific address.
335 *
336 * See docs/README.qe_firmware for information on QE microcode uploading.
337 *
338 * Currently, only version 1 is supported, so the 'version' field must be
339 * set to 1.
340 *
341 * The SOC model and revision are not validated, they are only displayed for
342 * informational purposes.
343 *
344 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
345 * all of the microcode structures, minus the CRC.
346 *
347 * 'length' is the size that the structure says it is, including the CRC.
348 */
349int qe_upload_firmware(const struct qe_firmware *firmware)
350{
351 unsigned int i;
352 unsigned int j;
353 u32 crc;
354 size_t calc_size = sizeof(struct qe_firmware);
355 size_t length;
356 const struct qe_header *hdr;
Zhao Qiangca721fb2014-04-30 16:45:31 +0800357#ifdef CONFIG_DEEP_SLEEP
York Sun73fb5832017-03-27 11:41:03 -0700358#ifdef CONFIG_ARCH_LS1021A
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800359 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
360#else
Zhao Qiangca721fb2014-04-30 16:45:31 +0800361 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
362#endif
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800363#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600364 if (!firmware) {
365 printf("Invalid address\n");
366 return -EINVAL;
367 }
368
369 hdr = &firmware->header;
370 length = be32_to_cpu(hdr->length);
371
372 /* Check the magic */
373 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
374 (hdr->magic[2] != 'F')) {
Vijay Rai12eeb132014-07-23 18:33:16 +0530375 printf("QE microcode not found\n");
Zhao Qiangca721fb2014-04-30 16:45:31 +0800376#ifdef CONFIG_DEEP_SLEEP
377 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
378#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600379 return -EPERM;
380 }
381
382 /* Check the version */
383 if (hdr->version != 1) {
384 printf("Unsupported version\n");
385 return -EPERM;
386 }
387
388 /* Validate some of the fields */
Timur Tabi491fb6d2008-03-03 09:58:52 -0600389 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
Timur Tabib8ec2382008-01-07 13:31:19 -0600390 printf("Invalid data\n");
391 return -EINVAL;
392 }
393
394 /* Validate the length and check if there's a CRC */
395 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
396
397 for (i = 0; i < firmware->count; i++)
398 /*
399 * For situations where the second RISC uses the same microcode
400 * as the first, the 'code_offset' and 'count' fields will be
401 * zero, so it's okay to add those.
402 */
403 calc_size += sizeof(u32) *
404 be32_to_cpu(firmware->microcode[i].count);
405
406 /* Validate the length */
407 if (length != calc_size + sizeof(u32)) {
408 printf("Invalid length\n");
409 return -EPERM;
410 }
411
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100412 /*
413 * Validate the CRC. We would normally call crc32_no_comp(), but that
414 * function isn't available unless you turn on JFFS support.
415 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600416 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
417 if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
418 printf("Firmware CRC is invalid\n");
419 return -EIO;
420 }
421
422 /*
423 * If the microcode calls for it, split the I-RAM.
424 */
425 if (!firmware->split) {
426 out_be16(&qe_immr->cp.cercr,
427 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
428 }
429
430 if (firmware->soc.model)
431 printf("Firmware '%s' for %u V%u.%u\n",
432 firmware->id, be16_to_cpu(firmware->soc.model),
433 firmware->soc.major, firmware->soc.minor);
434 else
435 printf("Firmware '%s'\n", firmware->id);
436
437 /*
438 * The QE only supports one microcode per RISC, so clear out all the
439 * saved microcode information and put in the new.
440 */
441 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Zhao Qiang0e0224e2015-05-05 15:53:33 +0800442 strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
Timur Tabib8ec2382008-01-07 13:31:19 -0600443 qe_firmware_info.extended_modes = firmware->extended_modes;
444 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
445 sizeof(firmware->vtraps));
446 qe_firmware_uploaded = 1;
447
448 /* Loop through each microcode. */
449 for (i = 0; i < firmware->count; i++) {
450 const struct qe_microcode *ucode = &firmware->microcode[i];
451
452 /* Upload a microcode if it's present */
453 if (ucode->code_offset)
454 qe_upload_microcode(firmware, ucode);
455
456 /* Program the traps for this processor */
457 for (j = 0; j < 16; j++) {
458 u32 trap = be32_to_cpu(ucode->traps[j]);
459
460 if (trap)
461 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
462 }
463
464 /* Enable traps */
465 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
466 }
467
468 return 0;
469}
470
Zhao Qiang5632d152014-11-04 13:46:16 +0800471#ifdef CONFIG_U_QE
472/*
473 * Upload a microcode to the I-RAM at a specific address.
474 *
475 * See docs/README.qe_firmware for information on QE microcode uploading.
476 *
477 * Currently, only version 1 is supported, so the 'version' field must be
478 * set to 1.
479 *
480 * The SOC model and revision are not validated, they are only displayed for
481 * informational purposes.
482 *
483 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
484 * all of the microcode structures, minus the CRC.
485 *
486 * 'length' is the size that the structure says it is, including the CRC.
487 */
488int u_qe_upload_firmware(const struct qe_firmware *firmware)
489{
490 unsigned int i;
491 unsigned int j;
492 u32 crc;
493 size_t calc_size = sizeof(struct qe_firmware);
494 size_t length;
495 const struct qe_header *hdr;
496#ifdef CONFIG_DEEP_SLEEP
York Sun73fb5832017-03-27 11:41:03 -0700497#ifdef CONFIG_ARCH_LS1021A
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800498 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
499#else
Zhao Qiang5632d152014-11-04 13:46:16 +0800500 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
501#endif
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800502#endif
Zhao Qiang5632d152014-11-04 13:46:16 +0800503 if (!firmware) {
504 printf("Invalid address\n");
505 return -EINVAL;
506 }
507
508 hdr = &firmware->header;
509 length = be32_to_cpu(hdr->length);
510
511 /* Check the magic */
512 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
513 (hdr->magic[2] != 'F')) {
514 printf("Not a microcode\n");
515#ifdef CONFIG_DEEP_SLEEP
516 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
517#endif
518 return -EPERM;
519 }
520
521 /* Check the version */
522 if (hdr->version != 1) {
523 printf("Unsupported version\n");
524 return -EPERM;
525 }
526
527 /* Validate some of the fields */
528 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
529 printf("Invalid data\n");
530 return -EINVAL;
531 }
532
533 /* Validate the length and check if there's a CRC */
534 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
535
536 for (i = 0; i < firmware->count; i++)
537 /*
538 * For situations where the second RISC uses the same microcode
539 * as the first, the 'code_offset' and 'count' fields will be
540 * zero, so it's okay to add those.
541 */
542 calc_size += sizeof(u32) *
543 be32_to_cpu(firmware->microcode[i].count);
544
545 /* Validate the length */
546 if (length != calc_size + sizeof(u32)) {
547 printf("Invalid length\n");
548 return -EPERM;
549 }
550
551 /*
552 * Validate the CRC. We would normally call crc32_no_comp(), but that
553 * function isn't available unless you turn on JFFS support.
554 */
555 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
556 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
557 printf("Firmware CRC is invalid\n");
558 return -EIO;
559 }
560
561 /*
562 * If the microcode calls for it, split the I-RAM.
563 */
564 if (!firmware->split) {
565 out_be16(&qe_immr->cp.cercr,
566 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
567 }
568
569 if (firmware->soc.model)
570 printf("Firmware '%s' for %u V%u.%u\n",
571 firmware->id, be16_to_cpu(firmware->soc.model),
572 firmware->soc.major, firmware->soc.minor);
573 else
574 printf("Firmware '%s'\n", firmware->id);
575
576 /* Loop through each microcode. */
577 for (i = 0; i < firmware->count; i++) {
578 const struct qe_microcode *ucode = &firmware->microcode[i];
579
580 /* Upload a microcode if it's present */
581 if (ucode->code_offset)
582 qe_upload_microcode(firmware, ucode);
583
584 /* Program the traps for this processor */
585 for (j = 0; j < 16; j++) {
586 u32 trap = be32_to_cpu(ucode->traps[j]);
587
588 if (trap)
589 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
590 }
591
592 /* Enable traps */
593 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
594 }
595
596 return 0;
597}
598#endif
599
Zhao Qiangae42eb02015-03-25 17:02:59 +0800600#ifdef CONFIG_U_QE
601int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
602{
603 unsigned int i;
604 unsigned int j;
605 const struct qe_header *hdr;
606 const u32 *code;
607#ifdef CONFIG_DEEP_SLEEP
608#ifdef CONFIG_PPC
609 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
610#else
611 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
612#endif
613#endif
614
615 if (!firmware)
616 return -EINVAL;
617
618 hdr = &firmware->header;
619
620 /* Check the magic */
621 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
622 (hdr->magic[2] != 'F')) {
623#ifdef CONFIG_DEEP_SLEEP
624 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
625#endif
626 return -EPERM;
627 }
628
629 /*
630 * If the microcode calls for it, split the I-RAM.
631 */
632 if (!firmware->split) {
633 out_be16(&qe_immrr->cp.cercr,
634 in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
635 }
636
637 /* Loop through each microcode. */
638 for (i = 0; i < firmware->count; i++) {
639 const struct qe_microcode *ucode = &firmware->microcode[i];
640
641 /* Upload a microcode if it's present */
642 if (!ucode->code_offset)
643 return 0;
644
645 code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
646
647 /* Use auto-increment */
648 out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
649 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
650
651 for (i = 0; i < be32_to_cpu(ucode->count); i++)
652 out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
653
654 /* Program the traps for this processor */
655 for (j = 0; j < 16; j++) {
656 u32 trap = be32_to_cpu(ucode->traps[j]);
657
658 if (trap)
659 out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
660 }
661
662 /* Enable traps */
663 out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
664 }
665
666 return 0;
667}
668#endif
669
Timur Tabib8ec2382008-01-07 13:31:19 -0600670struct qe_firmware_info *qe_get_firmware_info(void)
671{
672 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
673}
674
Wolfgang Denk54841ab2010-06-28 22:00:46 +0200675static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Timur Tabib8ec2382008-01-07 13:31:19 -0600676{
677 ulong addr;
678
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200679 if (argc < 3)
680 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600681
682 if (strcmp(argv[1], "fw") == 0) {
683 addr = simple_strtoul(argv[2], NULL, 16);
684
685 if (!addr) {
686 printf("Invalid address\n");
687 return -EINVAL;
688 }
689
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100690 /*
691 * If a length was supplied, compare that with the 'length'
692 * field.
693 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600694
695 if (argc > 3) {
696 ulong length = simple_strtoul(argv[3], NULL, 16);
697 struct qe_firmware *firmware = (void *) addr;
698
699 if (length != be32_to_cpu(firmware->header.length)) {
700 printf("Length mismatch\n");
701 return -EINVAL;
702 }
703 }
704
705 return qe_upload_firmware((const struct qe_firmware *) addr);
706 }
707
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200708 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600709}
710
711U_BOOT_CMD(
712 qe, 4, 0, qe_cmd,
Peter Tyser2fb26042009-01-27 18:03:12 -0600713 "QUICC Engine commands",
Timur Tabib8ec2382008-01-07 13:31:19 -0600714 "fw <addr> [<length>] - Upload firmware binary at address <addr> to "
Wolfgang Denka89c33d2009-05-24 17:06:54 +0200715 "the QE,\n"
716 "\twith optional length <length> verification."
717);