blob: 9c5fbd1d69474024c3758d9dffa0405ae2370444 [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"
14#include "asm/immap_qe.h"
15#include "qe.h"
16
Zhao Qiangca721fb2014-04-30 16:45:31 +080017#define MPC85xx_DEVDISR_QE_DISABLE 0x1
18
Dave Liu7737d5c2006-11-03 12:11:15 -060019qe_map_t *qe_immr = NULL;
20static qe_snum_t snums[QE_NUM_OF_SNUM];
21
Wolfgang Denk1218abf2007-09-15 20:48:41 +020022DECLARE_GLOBAL_DATA_PTR;
23
Dave Liu7737d5c2006-11-03 12:11:15 -060024void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
25{
Wolfgang Denkd3a65322008-01-10 00:55:14 +010026 u32 cecr;
Dave Liu7737d5c2006-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
43uint qe_muram_alloc(uint size, uint align)
44{
Dave Liu7737d5c2006-11-03 12:11:15 -060045 uint retloc;
46 uint align_mask, off;
47 uint savebase;
48
49 align_mask = align - 1;
Simon Glass45bae2e2012-12-13 20:48:50 +000050 savebase = gd->arch.mp_alloc_base;
Dave Liu7737d5c2006-11-03 12:11:15 -060051
Simon Glass45bae2e2012-12-13 20:48:50 +000052 off = gd->arch.mp_alloc_base & align_mask;
53 if (off != 0)
54 gd->arch.mp_alloc_base += (align - off);
Dave Liu7737d5c2006-11-03 12:11:15 -060055
56 if ((off = size & align_mask) != 0)
57 size += (align - off);
58
Simon Glass45bae2e2012-12-13 20:48:50 +000059 if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
60 gd->arch.mp_alloc_base = savebase;
Dave Liu7737d5c2006-11-03 12:11:15 -060061 printf("%s: ran out of ram.\n", __FUNCTION__);
62 }
63
Simon Glass45bae2e2012-12-13 20:48:50 +000064 retloc = gd->arch.mp_alloc_base;
65 gd->arch.mp_alloc_base += size;
Dave Liu7737d5c2006-11-03 12:11:15 -060066
67 memset((void *)&qe_immr->muram[retloc], 0, size);
68
69 __asm__ __volatile__("sync");
70
71 return retloc;
72}
73
74void *qe_muram_addr(uint offset)
75{
76 return (void *)&qe_immr->muram[offset];
77}
78
79static void qe_sdma_init(void)
80{
81 volatile sdma_t *p;
82 uint sdma_buffer_base;
83
84 p = (volatile sdma_t *)&qe_immr->sdma;
85
86 /* All of DMA transaction in bus 1 */
87 out_be32(&p->sdaqr, 0);
88 out_be32(&p->sdaqmr, 0);
89
90 /* Allocate 2KB temporary buffer for sdma */
Dave Liuff9658d2007-06-25 10:41:04 +080091 sdma_buffer_base = qe_muram_alloc(2048, 4096);
Dave Liu7737d5c2006-11-03 12:11:15 -060092 out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
93
94 /* Clear sdma status */
95 out_be32(&p->sdsr, 0x03000000);
96
97 /* Enable global mode on bus 1, and 2KB buffer size */
98 out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
99}
100
Haiying Wang4e7b25e2009-05-20 12:30:35 -0400101/* This table is a list of the serial numbers of the Threads, taken from the
102 * "SNUM Table" chart in the QE Reference Manual. The order is not important,
103 * we just need to know what the SNUMs are for the threads.
104 */
105static u8 thread_snum[] = {
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000106/* Evthreads 16-29 are not supported in MPC8309 */
107#if !defined(CONFIG_MPC8309)
Dave Liu7737d5c2006-11-03 12:11:15 -0600108 0x04, 0x05, 0x0c, 0x0d,
109 0x14, 0x15, 0x1c, 0x1d,
110 0x24, 0x25, 0x2c, 0x2d,
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000111 0x34, 0x35,
112#endif
113 0x88, 0x89, 0x98, 0x99,
114 0xa8, 0xa9, 0xb8, 0xb9,
115 0xc8, 0xc9, 0xd8, 0xd9,
116 0xe8, 0xe9, 0x08, 0x09,
117 0x18, 0x19, 0x28, 0x29,
118 0x38, 0x39, 0x48, 0x49,
119 0x58, 0x59, 0x68, 0x69,
120 0x78, 0x79, 0x80, 0x81
Dave Liu7737d5c2006-11-03 12:11:15 -0600121};
122
123static void qe_snums_init(void)
124{
125 int i;
126
127 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
128 snums[i].state = QE_SNUM_STATE_FREE;
129 snums[i].num = thread_snum[i];
130 }
131}
132
133int qe_get_snum(void)
134{
135 int snum = -EBUSY;
136 int i;
137
138 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
139 if (snums[i].state == QE_SNUM_STATE_FREE) {
140 snums[i].state = QE_SNUM_STATE_USED;
141 snum = snums[i].num;
142 break;
143 }
144 }
145
146 return snum;
147}
148
149void qe_put_snum(u8 snum)
150{
151 int i;
152
153 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
154 if (snums[i].num == snum) {
155 snums[i].state = QE_SNUM_STATE_FREE;
156 break;
157 }
158 }
159}
160
161void qe_init(uint qe_base)
162{
Dave Liu7737d5c2006-11-03 12:11:15 -0600163 /* Init the QE IMMR base */
164 qe_immr = (qe_map_t *)qe_base;
165
Timur Tabif2717b42011-11-22 09:21:25 -0600166#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200167 /*
168 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
169 */
Zhao Qiangdcf1d772014-03-21 16:21:44 +0800170 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400171
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200172 /* enable the microcode in IRAM */
173 out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400174#endif
175
Simon Glass45bae2e2012-12-13 20:48:50 +0000176 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
177 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
Dave Liu7737d5c2006-11-03 12:11:15 -0600178
179 qe_sdma_init();
180 qe_snums_init();
181}
182
183void qe_reset(void)
184{
185 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
186 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
187}
188
189void qe_assign_page(uint snum, uint para_ram_base)
190{
191 u32 cecr;
192
193 out_be32(&qe_immr->cp.cecdr, para_ram_base);
194 out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
195 | QE_CR_FLG | QE_ASSIGN_PAGE);
196
197 /* Wait for the QE_CR_FLG to clear */
198 do {
199 cecr = in_be32(&qe_immr->cp.cecr);
200 } while (cecr & QE_CR_FLG );
201
202 return;
203}
204
205/*
206 * brg: 0~15 as BRG1~BRG16
207 rate: baud rate
208 * BRG input clock comes from the BRGCLK (internal clock generated from
209 the QE clock, it is one-half of the QE clock), If need the clock source
210 from CLKn pin, we have te change the function.
211 */
212
Simon Glass1206c182012-12-13 20:48:44 +0000213#define BRG_CLK (gd->arch.brg_clk)
Dave Liu7737d5c2006-11-03 12:11:15 -0600214
215int qe_set_brg(uint brg, uint rate)
216{
Dave Liu7737d5c2006-11-03 12:11:15 -0600217 volatile uint *bp;
218 u32 divisor;
219 int div16 = 0;
220
221 if (brg >= QE_NUM_OF_BRGS)
222 return -EINVAL;
223 bp = (uint *)&qe_immr->brg.brgc1;
224 bp += brg;
225
226 divisor = (BRG_CLK / rate);
227 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
228 div16 = 1;
229 divisor /= 16;
230 }
231
232 *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
233 __asm__ __volatile__("sync");
234
235 if (div16) {
236 *bp |= QE_BRGC_DIV16;
237 __asm__ __volatile__("sync");
238 }
239
240 return 0;
241}
242
243/* Set ethernet MII clock master
244*/
245int qe_set_mii_clk_src(int ucc_num)
246{
247 u32 cmxgcr;
248
249 /* check if the UCC number is in range. */
250 if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
251 printf("%s: ucc num not in ranges\n", __FUNCTION__);
252 return -EINVAL;
253 }
254
255 cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
256 cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
257 cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
258 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
259
260 return 0;
261}
262
Timur Tabib8ec2382008-01-07 13:31:19 -0600263/* Firmware information stored here for qe_get_firmware_info() */
264static struct qe_firmware_info qe_firmware_info;
265
266/*
267 * Set to 1 if QE firmware has been uploaded, and therefore
268 * qe_firmware_info contains valid data.
269 */
270static int qe_firmware_uploaded;
271
272/*
273 * Upload a QE microcode
274 *
275 * This function is a worker function for qe_upload_firmware(). It does
276 * the actual uploading of the microcode.
277 */
278static void qe_upload_microcode(const void *base,
279 const struct qe_microcode *ucode)
280{
281 const u32 *code = base + be32_to_cpu(ucode->code_offset);
282 unsigned int i;
283
284 if (ucode->major || ucode->minor || ucode->revision)
285 printf("QE: uploading microcode '%s' version %u.%u.%u\n",
286 ucode->id, ucode->major, ucode->minor, ucode->revision);
287 else
288 printf("QE: uploading microcode '%s'\n", ucode->id);
289
290 /* Use auto-increment */
291 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
292 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
293
294 for (i = 0; i < be32_to_cpu(ucode->count); i++)
295 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
296}
297
298/*
299 * Upload a microcode to the I-RAM at a specific address.
300 *
301 * See docs/README.qe_firmware for information on QE microcode uploading.
302 *
303 * Currently, only version 1 is supported, so the 'version' field must be
304 * set to 1.
305 *
306 * The SOC model and revision are not validated, they are only displayed for
307 * informational purposes.
308 *
309 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
310 * all of the microcode structures, minus the CRC.
311 *
312 * 'length' is the size that the structure says it is, including the CRC.
313 */
314int qe_upload_firmware(const struct qe_firmware *firmware)
315{
316 unsigned int i;
317 unsigned int j;
318 u32 crc;
319 size_t calc_size = sizeof(struct qe_firmware);
320 size_t length;
321 const struct qe_header *hdr;
Zhao Qiangca721fb2014-04-30 16:45:31 +0800322#ifdef CONFIG_DEEP_SLEEP
323 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
324#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600325 if (!firmware) {
326 printf("Invalid address\n");
327 return -EINVAL;
328 }
329
330 hdr = &firmware->header;
331 length = be32_to_cpu(hdr->length);
332
333 /* Check the magic */
334 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
335 (hdr->magic[2] != 'F')) {
336 printf("Not a microcode\n");
Zhao Qiangca721fb2014-04-30 16:45:31 +0800337#ifdef CONFIG_DEEP_SLEEP
338 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
339#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600340 return -EPERM;
341 }
342
343 /* Check the version */
344 if (hdr->version != 1) {
345 printf("Unsupported version\n");
346 return -EPERM;
347 }
348
349 /* Validate some of the fields */
Timur Tabi491fb6d2008-03-03 09:58:52 -0600350 if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
Timur Tabib8ec2382008-01-07 13:31:19 -0600351 printf("Invalid data\n");
352 return -EINVAL;
353 }
354
355 /* Validate the length and check if there's a CRC */
356 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
357
358 for (i = 0; i < firmware->count; i++)
359 /*
360 * For situations where the second RISC uses the same microcode
361 * as the first, the 'code_offset' and 'count' fields will be
362 * zero, so it's okay to add those.
363 */
364 calc_size += sizeof(u32) *
365 be32_to_cpu(firmware->microcode[i].count);
366
367 /* Validate the length */
368 if (length != calc_size + sizeof(u32)) {
369 printf("Invalid length\n");
370 return -EPERM;
371 }
372
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100373 /*
374 * Validate the CRC. We would normally call crc32_no_comp(), but that
375 * function isn't available unless you turn on JFFS support.
376 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600377 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
378 if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
379 printf("Firmware CRC is invalid\n");
380 return -EIO;
381 }
382
383 /*
384 * If the microcode calls for it, split the I-RAM.
385 */
386 if (!firmware->split) {
387 out_be16(&qe_immr->cp.cercr,
388 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
389 }
390
391 if (firmware->soc.model)
392 printf("Firmware '%s' for %u V%u.%u\n",
393 firmware->id, be16_to_cpu(firmware->soc.model),
394 firmware->soc.major, firmware->soc.minor);
395 else
396 printf("Firmware '%s'\n", firmware->id);
397
398 /*
399 * The QE only supports one microcode per RISC, so clear out all the
400 * saved microcode information and put in the new.
401 */
402 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Dave Liu06c428b2008-01-14 11:12:01 +0800403 strcpy(qe_firmware_info.id, (char *)firmware->id);
Timur Tabib8ec2382008-01-07 13:31:19 -0600404 qe_firmware_info.extended_modes = firmware->extended_modes;
405 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
406 sizeof(firmware->vtraps));
407 qe_firmware_uploaded = 1;
408
409 /* Loop through each microcode. */
410 for (i = 0; i < firmware->count; i++) {
411 const struct qe_microcode *ucode = &firmware->microcode[i];
412
413 /* Upload a microcode if it's present */
414 if (ucode->code_offset)
415 qe_upload_microcode(firmware, ucode);
416
417 /* Program the traps for this processor */
418 for (j = 0; j < 16; j++) {
419 u32 trap = be32_to_cpu(ucode->traps[j]);
420
421 if (trap)
422 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
423 }
424
425 /* Enable traps */
426 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
427 }
428
429 return 0;
430}
431
432struct qe_firmware_info *qe_get_firmware_info(void)
433{
434 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
435}
436
Wolfgang Denk54841ab2010-06-28 22:00:46 +0200437static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Timur Tabib8ec2382008-01-07 13:31:19 -0600438{
439 ulong addr;
440
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200441 if (argc < 3)
442 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600443
444 if (strcmp(argv[1], "fw") == 0) {
445 addr = simple_strtoul(argv[2], NULL, 16);
446
447 if (!addr) {
448 printf("Invalid address\n");
449 return -EINVAL;
450 }
451
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100452 /*
453 * If a length was supplied, compare that with the 'length'
454 * field.
455 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600456
457 if (argc > 3) {
458 ulong length = simple_strtoul(argv[3], NULL, 16);
459 struct qe_firmware *firmware = (void *) addr;
460
461 if (length != be32_to_cpu(firmware->header.length)) {
462 printf("Length mismatch\n");
463 return -EINVAL;
464 }
465 }
466
467 return qe_upload_firmware((const struct qe_firmware *) addr);
468 }
469
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200470 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600471}
472
473U_BOOT_CMD(
474 qe, 4, 0, qe_cmd,
Peter Tyser2fb26042009-01-27 18:03:12 -0600475 "QUICC Engine commands",
Timur Tabib8ec2382008-01-07 13:31:19 -0600476 "fw <addr> [<length>] - Upload firmware binary at address <addr> to "
Wolfgang Denka89c33d2009-05-24 17:06:54 +0200477 "the QE,\n"
478 "\twith optional length <length> verification."
479);