blob: 24e764dc7c59ea2aa5bc0d3bdb885cb65bb1185a [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>
Zhao Qiang5aa03dd2017-05-25 09:47:40 +080011#include <malloc.h>
Timur Tabib8ec2382008-01-07 13:31:19 -060012#include <command.h>
Masahiro Yamada1221ce42016-09-21 11:28:55 +090013#include <linux/errno.h>
Masahiro Yamadab5bf5cb2016-09-21 11:28:53 +090014#include <asm/io.h>
15#include <linux/immap_qe.h>
Qianyu Gong2459afb2016-02-18 13:01:59 +080016#include <fsl_qe.h>
York Sun73fb5832017-03-27 11:41:03 -070017#ifdef CONFIG_ARCH_LS1021A
Zhao Qiang9c7c86f2014-12-15 15:50:49 +080018#include <asm/arch/immap_ls102xa.h>
19#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060020
Zhao Qiang5aa03dd2017-05-25 09:47:40 +080021#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
22#include <mmc.h>
23#endif
24
Zhao Qiangca721fb2014-04-30 16:45:31 +080025#define MPC85xx_DEVDISR_QE_DISABLE 0x1
26
Dave Liu7737d5c2006-11-03 12:11:15 -060027qe_map_t *qe_immr = NULL;
Zhao Qiang3bf46e62016-02-05 10:04:16 +080028#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060029static qe_snum_t snums[QE_NUM_OF_SNUM];
Zhao Qiang3bf46e62016-02-05 10:04:16 +080030#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060031
Wolfgang Denk1218abf2007-09-15 20:48:41 +020032DECLARE_GLOBAL_DATA_PTR;
33
Dave Liu7737d5c2006-11-03 12:11:15 -060034void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
35{
Wolfgang Denkd3a65322008-01-10 00:55:14 +010036 u32 cecr;
Dave Liu7737d5c2006-11-03 12:11:15 -060037
38 if (cmd == QE_RESET) {
39 out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG));
40 } else {
41 out_be32(&qe_immr->cp.cecdr, cmd_data);
42 out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
43 ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd));
44 }
45 /* Wait for the QE_CR_FLG to clear */
46 do {
47 cecr = in_be32(&qe_immr->cp.cecr);
48 } while (cecr & QE_CR_FLG);
49
50 return;
51}
52
Zhao Qiang93d33202014-09-25 13:52:25 +080053#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060054uint qe_muram_alloc(uint size, uint align)
55{
Dave Liu7737d5c2006-11-03 12:11:15 -060056 uint retloc;
57 uint align_mask, off;
58 uint savebase;
59
60 align_mask = align - 1;
Simon Glass45bae2e2012-12-13 20:48:50 +000061 savebase = gd->arch.mp_alloc_base;
Dave Liu7737d5c2006-11-03 12:11:15 -060062
Simon Glass45bae2e2012-12-13 20:48:50 +000063 off = gd->arch.mp_alloc_base & align_mask;
64 if (off != 0)
65 gd->arch.mp_alloc_base += (align - off);
Dave Liu7737d5c2006-11-03 12:11:15 -060066
67 if ((off = size & align_mask) != 0)
68 size += (align - off);
69
Simon Glass45bae2e2012-12-13 20:48:50 +000070 if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
71 gd->arch.mp_alloc_base = savebase;
Dave Liu7737d5c2006-11-03 12:11:15 -060072 printf("%s: ran out of ram.\n", __FUNCTION__);
73 }
74
Simon Glass45bae2e2012-12-13 20:48:50 +000075 retloc = gd->arch.mp_alloc_base;
76 gd->arch.mp_alloc_base += size;
Dave Liu7737d5c2006-11-03 12:11:15 -060077
78 memset((void *)&qe_immr->muram[retloc], 0, size);
79
80 __asm__ __volatile__("sync");
81
82 return retloc;
83}
Zhao Qiang93d33202014-09-25 13:52:25 +080084#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060085
86void *qe_muram_addr(uint offset)
87{
88 return (void *)&qe_immr->muram[offset];
89}
90
Zhao Qiang3bf46e62016-02-05 10:04:16 +080091#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060092static void qe_sdma_init(void)
93{
94 volatile sdma_t *p;
95 uint sdma_buffer_base;
96
97 p = (volatile sdma_t *)&qe_immr->sdma;
98
99 /* All of DMA transaction in bus 1 */
100 out_be32(&p->sdaqr, 0);
101 out_be32(&p->sdaqmr, 0);
102
103 /* Allocate 2KB temporary buffer for sdma */
Dave Liuff9658d2007-06-25 10:41:04 +0800104 sdma_buffer_base = qe_muram_alloc(2048, 4096);
Dave Liu7737d5c2006-11-03 12:11:15 -0600105 out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
106
107 /* Clear sdma status */
108 out_be32(&p->sdsr, 0x03000000);
109
110 /* Enable global mode on bus 1, and 2KB buffer size */
111 out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
112}
113
Haiying Wang4e7b25e2009-05-20 12:30:35 -0400114/* This table is a list of the serial numbers of the Threads, taken from the
115 * "SNUM Table" chart in the QE Reference Manual. The order is not important,
116 * we just need to know what the SNUMs are for the threads.
117 */
118static u8 thread_snum[] = {
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000119/* Evthreads 16-29 are not supported in MPC8309 */
120#if !defined(CONFIG_MPC8309)
Dave Liu7737d5c2006-11-03 12:11:15 -0600121 0x04, 0x05, 0x0c, 0x0d,
122 0x14, 0x15, 0x1c, 0x1d,
123 0x24, 0x25, 0x2c, 0x2d,
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000124 0x34, 0x35,
125#endif
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
Dave Liu7737d5c2006-11-03 12:11:15 -0600134};
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
174void qe_init(uint qe_base)
175{
Dave Liu7737d5c2006-11-03 12:11:15 -0600176 /* Init the QE IMMR base */
177 qe_immr = (qe_map_t *)qe_base;
178
Timur Tabif2717b42011-11-22 09:21:25 -0600179#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200180 /*
181 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
182 */
Zhao Qiangdcf1d772014-03-21 16:21:44 +0800183 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400184
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200185 /* enable the microcode in IRAM */
186 out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400187#endif
188
Simon Glass45bae2e2012-12-13 20:48:50 +0000189 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
190 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
Dave Liu7737d5c2006-11-03 12:11:15 -0600191
192 qe_sdma_init();
193 qe_snums_init();
194}
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800195#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600196
Zhao Qiang93d33202014-09-25 13:52:25 +0800197#ifdef CONFIG_U_QE
198void u_qe_init(void)
199{
Zhao Qiangd3e6d302016-02-05 10:04:17 +0800200 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiang93d33202014-09-25 13:52:25 +0800201
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800202 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
203#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
204 int dev = CONFIG_SYS_MMC_ENV_DEV;
205 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
206 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
207
208 if (mmc_initialize(gd->bd)) {
209 printf("%s: mmc_initialize() failed\n", __func__);
210 return;
211 }
212 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
213 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
214
215 if (!mmc) {
216 free(addr);
217 printf("\nMMC cannot find device for ucode\n");
218 } else {
219 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
220 dev, blk, cnt);
221 mmc_init(mmc);
222 (void)mmc->block_dev.block_read(&mmc->block_dev, blk, cnt,
223 addr);
224 /* flush cache after read */
225 flush_cache((ulong)addr, cnt * 512);
226 }
227#endif
228 u_qe_upload_firmware(addr);
Zhao Qiang93d33202014-09-25 13:52:25 +0800229 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800230#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
231 free(addr);
232#endif
Zhao Qiang93d33202014-09-25 13:52:25 +0800233}
234#endif
235
Zhao Qiangae42eb02015-03-25 17:02:59 +0800236#ifdef CONFIG_U_QE
237void u_qe_resume(void)
238{
239 qe_map_t *qe_immrr;
Zhao Qiangae42eb02015-03-25 17:02:59 +0800240
Zhao Qiangd3e6d302016-02-05 10:04:17 +0800241 qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiangae42eb02015-03-25 17:02:59 +0800242 u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr);
243 out_be32(&qe_immrr->iram.iready, QE_IRAM_READY);
244}
245#endif
246
Dave Liu7737d5c2006-11-03 12:11:15 -0600247void qe_reset(void)
248{
249 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
250 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
251}
252
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800253#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -0600254void qe_assign_page(uint snum, uint para_ram_base)
255{
256 u32 cecr;
257
258 out_be32(&qe_immr->cp.cecdr, para_ram_base);
259 out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
260 | QE_CR_FLG | QE_ASSIGN_PAGE);
261
262 /* Wait for the QE_CR_FLG to clear */
263 do {
264 cecr = in_be32(&qe_immr->cp.cecr);
265 } while (cecr & QE_CR_FLG );
266
267 return;
268}
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800269#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600270
271/*
272 * brg: 0~15 as BRG1~BRG16
273 rate: baud rate
274 * BRG input clock comes from the BRGCLK (internal clock generated from
275 the QE clock, it is one-half of the QE clock), If need the clock source
276 from CLKn pin, we have te change the function.
277 */
278
Simon Glass1206c182012-12-13 20:48:44 +0000279#define BRG_CLK (gd->arch.brg_clk)
Dave Liu7737d5c2006-11-03 12:11:15 -0600280
Zhao Qiang93d33202014-09-25 13:52:25 +0800281#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -0600282int qe_set_brg(uint brg, uint rate)
283{
Dave Liu7737d5c2006-11-03 12:11:15 -0600284 volatile uint *bp;
285 u32 divisor;
286 int div16 = 0;
287
288 if (brg >= QE_NUM_OF_BRGS)
289 return -EINVAL;
290 bp = (uint *)&qe_immr->brg.brgc1;
291 bp += brg;
292
293 divisor = (BRG_CLK / rate);
294 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
295 div16 = 1;
296 divisor /= 16;
297 }
298
299 *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
300 __asm__ __volatile__("sync");
301
302 if (div16) {
303 *bp |= QE_BRGC_DIV16;
304 __asm__ __volatile__("sync");
305 }
306
307 return 0;
308}
Zhao Qiang93d33202014-09-25 13:52:25 +0800309#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600310
311/* Set ethernet MII clock master
312*/
313int qe_set_mii_clk_src(int ucc_num)
314{
315 u32 cmxgcr;
316
317 /* check if the UCC number is in range. */
318 if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
319 printf("%s: ucc num not in ranges\n", __FUNCTION__);
320 return -EINVAL;
321 }
322
323 cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
324 cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
325 cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
326 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
327
328 return 0;
329}
330
Timur Tabib8ec2382008-01-07 13:31:19 -0600331/* Firmware information stored here for qe_get_firmware_info() */
332static struct qe_firmware_info qe_firmware_info;
333
334/*
335 * Set to 1 if QE firmware has been uploaded, and therefore
336 * qe_firmware_info contains valid data.
337 */
338static int qe_firmware_uploaded;
339
340/*
341 * Upload a QE microcode
342 *
343 * This function is a worker function for qe_upload_firmware(). It does
344 * the actual uploading of the microcode.
345 */
346static void qe_upload_microcode(const void *base,
347 const struct qe_microcode *ucode)
348{
349 const u32 *code = base + be32_to_cpu(ucode->code_offset);
350 unsigned int i;
351
352 if (ucode->major || ucode->minor || ucode->revision)
353 printf("QE: uploading microcode '%s' version %u.%u.%u\n",
Zhao Qiange94a8fd2015-05-05 15:53:32 +0800354 (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
355 (u16)ucode->revision);
Timur Tabib8ec2382008-01-07 13:31:19 -0600356 else
Zhao Qiange94a8fd2015-05-05 15:53:32 +0800357 printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
Timur Tabib8ec2382008-01-07 13:31:19 -0600358
359 /* Use auto-increment */
360 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
361 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
362
363 for (i = 0; i < be32_to_cpu(ucode->count); i++)
364 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
365}
366
367/*
368 * Upload a microcode to the I-RAM at a specific address.
369 *
370 * See docs/README.qe_firmware for information on QE microcode uploading.
371 *
372 * Currently, only version 1 is supported, so the 'version' field must be
373 * set to 1.
374 *
375 * The SOC model and revision are not validated, they are only displayed for
376 * informational purposes.
377 *
378 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
379 * all of the microcode structures, minus the CRC.
380 *
381 * 'length' is the size that the structure says it is, including the CRC.
382 */
383int qe_upload_firmware(const struct qe_firmware *firmware)
384{
385 unsigned int i;
386 unsigned int j;
387 u32 crc;
388 size_t calc_size = sizeof(struct qe_firmware);
389 size_t length;
390 const struct qe_header *hdr;
Zhao Qiangca721fb2014-04-30 16:45:31 +0800391#ifdef CONFIG_DEEP_SLEEP
York Sun73fb5832017-03-27 11:41:03 -0700392#ifdef CONFIG_ARCH_LS1021A
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800393 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
394#else
Zhao Qiangca721fb2014-04-30 16:45:31 +0800395 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
396#endif
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800397#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600398 if (!firmware) {
399 printf("Invalid address\n");
400 return -EINVAL;
401 }
402
403 hdr = &firmware->header;
404 length = be32_to_cpu(hdr->length);
405
406 /* Check the magic */
407 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
408 (hdr->magic[2] != 'F')) {
Vijay Rai12eeb132014-07-23 18:33:16 +0530409 printf("QE microcode not found\n");
Zhao Qiangca721fb2014-04-30 16:45:31 +0800410#ifdef CONFIG_DEEP_SLEEP
411 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
412#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600413 return -EPERM;
414 }
415
416 /* Check the version */
417 if (hdr->version != 1) {
418 printf("Unsupported version\n");
419 return -EPERM;
420 }
421
422 /* Validate some of the fields */
Timur Tabi491fb6d2008-03-03 09:58:52 -0600423 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
Timur Tabib8ec2382008-01-07 13:31:19 -0600424 printf("Invalid data\n");
425 return -EINVAL;
426 }
427
428 /* Validate the length and check if there's a CRC */
429 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
430
431 for (i = 0; i < firmware->count; i++)
432 /*
433 * For situations where the second RISC uses the same microcode
434 * as the first, the 'code_offset' and 'count' fields will be
435 * zero, so it's okay to add those.
436 */
437 calc_size += sizeof(u32) *
438 be32_to_cpu(firmware->microcode[i].count);
439
440 /* Validate the length */
441 if (length != calc_size + sizeof(u32)) {
442 printf("Invalid length\n");
443 return -EPERM;
444 }
445
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100446 /*
447 * Validate the CRC. We would normally call crc32_no_comp(), but that
448 * function isn't available unless you turn on JFFS support.
449 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600450 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
451 if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
452 printf("Firmware CRC is invalid\n");
453 return -EIO;
454 }
455
456 /*
457 * If the microcode calls for it, split the I-RAM.
458 */
459 if (!firmware->split) {
460 out_be16(&qe_immr->cp.cercr,
461 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
462 }
463
464 if (firmware->soc.model)
465 printf("Firmware '%s' for %u V%u.%u\n",
466 firmware->id, be16_to_cpu(firmware->soc.model),
467 firmware->soc.major, firmware->soc.minor);
468 else
469 printf("Firmware '%s'\n", firmware->id);
470
471 /*
472 * The QE only supports one microcode per RISC, so clear out all the
473 * saved microcode information and put in the new.
474 */
475 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Zhao Qiang0e0224e2015-05-05 15:53:33 +0800476 strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
Timur Tabib8ec2382008-01-07 13:31:19 -0600477 qe_firmware_info.extended_modes = firmware->extended_modes;
478 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
479 sizeof(firmware->vtraps));
480 qe_firmware_uploaded = 1;
481
482 /* Loop through each microcode. */
483 for (i = 0; i < firmware->count; i++) {
484 const struct qe_microcode *ucode = &firmware->microcode[i];
485
486 /* Upload a microcode if it's present */
487 if (ucode->code_offset)
488 qe_upload_microcode(firmware, ucode);
489
490 /* Program the traps for this processor */
491 for (j = 0; j < 16; j++) {
492 u32 trap = be32_to_cpu(ucode->traps[j]);
493
494 if (trap)
495 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
496 }
497
498 /* Enable traps */
499 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
500 }
501
502 return 0;
503}
504
Zhao Qiang5632d152014-11-04 13:46:16 +0800505#ifdef CONFIG_U_QE
506/*
507 * Upload a microcode to the I-RAM at a specific address.
508 *
509 * See docs/README.qe_firmware for information on QE microcode uploading.
510 *
511 * Currently, only version 1 is supported, so the 'version' field must be
512 * set to 1.
513 *
514 * The SOC model and revision are not validated, they are only displayed for
515 * informational purposes.
516 *
517 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
518 * all of the microcode structures, minus the CRC.
519 *
520 * 'length' is the size that the structure says it is, including the CRC.
521 */
522int u_qe_upload_firmware(const struct qe_firmware *firmware)
523{
524 unsigned int i;
525 unsigned int j;
526 u32 crc;
527 size_t calc_size = sizeof(struct qe_firmware);
528 size_t length;
529 const struct qe_header *hdr;
530#ifdef CONFIG_DEEP_SLEEP
York Sun73fb5832017-03-27 11:41:03 -0700531#ifdef CONFIG_ARCH_LS1021A
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800532 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
533#else
Zhao Qiang5632d152014-11-04 13:46:16 +0800534 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
535#endif
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800536#endif
Zhao Qiang5632d152014-11-04 13:46:16 +0800537 if (!firmware) {
538 printf("Invalid address\n");
539 return -EINVAL;
540 }
541
542 hdr = &firmware->header;
543 length = be32_to_cpu(hdr->length);
544
545 /* Check the magic */
546 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
547 (hdr->magic[2] != 'F')) {
548 printf("Not a microcode\n");
549#ifdef CONFIG_DEEP_SLEEP
550 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
551#endif
552 return -EPERM;
553 }
554
555 /* Check the version */
556 if (hdr->version != 1) {
557 printf("Unsupported version\n");
558 return -EPERM;
559 }
560
561 /* Validate some of the fields */
562 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
563 printf("Invalid data\n");
564 return -EINVAL;
565 }
566
567 /* Validate the length and check if there's a CRC */
568 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
569
570 for (i = 0; i < firmware->count; i++)
571 /*
572 * For situations where the second RISC uses the same microcode
573 * as the first, the 'code_offset' and 'count' fields will be
574 * zero, so it's okay to add those.
575 */
576 calc_size += sizeof(u32) *
577 be32_to_cpu(firmware->microcode[i].count);
578
579 /* Validate the length */
580 if (length != calc_size + sizeof(u32)) {
581 printf("Invalid length\n");
582 return -EPERM;
583 }
584
585 /*
586 * Validate the CRC. We would normally call crc32_no_comp(), but that
587 * function isn't available unless you turn on JFFS support.
588 */
589 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
590 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
591 printf("Firmware CRC is invalid\n");
592 return -EIO;
593 }
594
595 /*
596 * If the microcode calls for it, split the I-RAM.
597 */
598 if (!firmware->split) {
599 out_be16(&qe_immr->cp.cercr,
600 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
601 }
602
603 if (firmware->soc.model)
604 printf("Firmware '%s' for %u V%u.%u\n",
605 firmware->id, be16_to_cpu(firmware->soc.model),
606 firmware->soc.major, firmware->soc.minor);
607 else
608 printf("Firmware '%s'\n", firmware->id);
609
610 /* Loop through each microcode. */
611 for (i = 0; i < firmware->count; i++) {
612 const struct qe_microcode *ucode = &firmware->microcode[i];
613
614 /* Upload a microcode if it's present */
615 if (ucode->code_offset)
616 qe_upload_microcode(firmware, ucode);
617
618 /* Program the traps for this processor */
619 for (j = 0; j < 16; j++) {
620 u32 trap = be32_to_cpu(ucode->traps[j]);
621
622 if (trap)
623 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
624 }
625
626 /* Enable traps */
627 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
628 }
629
630 return 0;
631}
632#endif
633
Zhao Qiangae42eb02015-03-25 17:02:59 +0800634#ifdef CONFIG_U_QE
635int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
636{
637 unsigned int i;
638 unsigned int j;
639 const struct qe_header *hdr;
640 const u32 *code;
641#ifdef CONFIG_DEEP_SLEEP
642#ifdef CONFIG_PPC
643 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
644#else
645 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
646#endif
647#endif
648
649 if (!firmware)
650 return -EINVAL;
651
652 hdr = &firmware->header;
653
654 /* Check the magic */
655 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
656 (hdr->magic[2] != 'F')) {
657#ifdef CONFIG_DEEP_SLEEP
658 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
659#endif
660 return -EPERM;
661 }
662
663 /*
664 * If the microcode calls for it, split the I-RAM.
665 */
666 if (!firmware->split) {
667 out_be16(&qe_immrr->cp.cercr,
668 in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
669 }
670
671 /* Loop through each microcode. */
672 for (i = 0; i < firmware->count; i++) {
673 const struct qe_microcode *ucode = &firmware->microcode[i];
674
675 /* Upload a microcode if it's present */
676 if (!ucode->code_offset)
677 return 0;
678
679 code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
680
681 /* Use auto-increment */
682 out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
683 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
684
685 for (i = 0; i < be32_to_cpu(ucode->count); i++)
686 out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
687
688 /* Program the traps for this processor */
689 for (j = 0; j < 16; j++) {
690 u32 trap = be32_to_cpu(ucode->traps[j]);
691
692 if (trap)
693 out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
694 }
695
696 /* Enable traps */
697 out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
698 }
699
700 return 0;
701}
702#endif
703
Timur Tabib8ec2382008-01-07 13:31:19 -0600704struct qe_firmware_info *qe_get_firmware_info(void)
705{
706 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
707}
708
Wolfgang Denk54841ab2010-06-28 22:00:46 +0200709static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Timur Tabib8ec2382008-01-07 13:31:19 -0600710{
711 ulong addr;
712
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200713 if (argc < 3)
714 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600715
716 if (strcmp(argv[1], "fw") == 0) {
717 addr = simple_strtoul(argv[2], NULL, 16);
718
719 if (!addr) {
720 printf("Invalid address\n");
721 return -EINVAL;
722 }
723
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100724 /*
725 * If a length was supplied, compare that with the 'length'
726 * field.
727 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600728
729 if (argc > 3) {
730 ulong length = simple_strtoul(argv[3], NULL, 16);
731 struct qe_firmware *firmware = (void *) addr;
732
733 if (length != be32_to_cpu(firmware->header.length)) {
734 printf("Length mismatch\n");
735 return -EINVAL;
736 }
737 }
738
739 return qe_upload_firmware((const struct qe_firmware *) addr);
740 }
741
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200742 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600743}
744
745U_BOOT_CMD(
746 qe, 4, 0, qe_cmd,
Peter Tyser2fb26042009-01-27 18:03:12 -0600747 "QUICC Engine commands",
Timur Tabib8ec2382008-01-07 13:31:19 -0600748 "fw <addr> [<length>] - Upload firmware binary at address <addr> to "
Wolfgang Denka89c33d2009-05-24 17:06:54 +0200749 "the QE,\n"
750 "\twith optional length <length> verification."
751);