blob: 259e4e3e678127dfe894b20850572b8ba09fa008 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dave Liu7737d5c2006-11-03 12:11:15 -06002/*
Haiying Wang4e7b25e2009-05-20 12:30:35 -04003 * Copyright (C) 2006-2009 Freescale Semiconductor, Inc.
Dave Liu7737d5c2006-11-03 12:11:15 -06004 *
5 * Dave Liu <daveliu@freescale.com>
6 * based on source code of Shlomi Gridish
Dave Liu7737d5c2006-11-03 12:11:15 -06007 */
8
Masahiro Yamadab5bf5cb2016-09-21 11:28:53 +09009#include <common.h>
Zhao Qiang5aa03dd2017-05-25 09:47:40 +080010#include <malloc.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>
Rajesh Bhagatc5e66372018-11-05 18:02:28 +000016#include <mmc.h>
Simon Glass3db71102019-11-14 12:57:16 -070017#include <u-boot/crc.h>
Rajesh Bhagatc5e66372018-11-05 18:02:28 +000018
York Sun73fb5832017-03-27 11:41:03 -070019#ifdef CONFIG_ARCH_LS1021A
Zhao Qiang9c7c86f2014-12-15 15:50:49 +080020#include <asm/arch/immap_ls102xa.h>
21#endif
Rajesh Bhagatc5e66372018-11-05 18:02:28 +000022#ifdef CONFIG_ARM64
23#include <asm/armv8/mmu.h>
24#include <asm/arch/cpu.h>
Zhao Qiang5aa03dd2017-05-25 09:47:40 +080025#endif
26
Zhao Qiangca721fb2014-04-30 16:45:31 +080027#define MPC85xx_DEVDISR_QE_DISABLE 0x1
28
Heiko Schocher9bd64442020-05-25 07:27:26 +020029qe_map_t *qe_immr;
Zhao Qiang3bf46e62016-02-05 10:04:16 +080030#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060031static qe_snum_t snums[QE_NUM_OF_SNUM];
Zhao Qiang3bf46e62016-02-05 10:04:16 +080032#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060033
Wolfgang Denk1218abf2007-09-15 20:48:41 +020034DECLARE_GLOBAL_DATA_PTR;
35
Dave Liu7737d5c2006-11-03 12:11:15 -060036void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
37{
Wolfgang Denkd3a65322008-01-10 00:55:14 +010038 u32 cecr;
Dave Liu7737d5c2006-11-03 12:11:15 -060039
40 if (cmd == QE_RESET) {
Heiko Schocher9bd64442020-05-25 07:27:26 +020041 out_be32(&qe_immr->cp.cecr, (u32)(cmd | QE_CR_FLG));
Dave Liu7737d5c2006-11-03 12:11:15 -060042 } else {
43 out_be32(&qe_immr->cp.cecdr, cmd_data);
44 out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
Heiko Schocher9bd64442020-05-25 07:27:26 +020045 ((u32)mcn << QE_CR_PROTOCOL_SHIFT) | cmd));
Dave Liu7737d5c2006-11-03 12:11:15 -060046 }
47 /* Wait for the QE_CR_FLG to clear */
48 do {
49 cecr = in_be32(&qe_immr->cp.cecr);
50 } while (cecr & QE_CR_FLG);
Dave Liu7737d5c2006-11-03 12:11:15 -060051}
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
Heiko Schocher9bd64442020-05-25 07:27:26 +020067 off = size & align_mask;
68 if (off != 0)
Dave Liu7737d5c2006-11-03 12:11:15 -060069 size += (align - off);
70
Simon Glass45bae2e2012-12-13 20:48:50 +000071 if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
72 gd->arch.mp_alloc_base = savebase;
Heiko Schocher9bd64442020-05-25 07:27:26 +020073 printf("%s: ran out of ram.\n", __func__);
Dave Liu7737d5c2006-11-03 12:11:15 -060074 }
75
Simon Glass45bae2e2012-12-13 20:48:50 +000076 retloc = gd->arch.mp_alloc_base;
77 gd->arch.mp_alloc_base += size;
Dave Liu7737d5c2006-11-03 12:11:15 -060078
79 memset((void *)&qe_immr->muram[retloc], 0, size);
80
81 __asm__ __volatile__("sync");
82
83 return retloc;
84}
Zhao Qiang93d33202014-09-25 13:52:25 +080085#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060086
87void *qe_muram_addr(uint offset)
88{
89 return (void *)&qe_immr->muram[offset];
90}
91
Zhao Qiang3bf46e62016-02-05 10:04:16 +080092#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060093static void qe_sdma_init(void)
94{
Heiko Schocher9bd64442020-05-25 07:27:26 +020095 sdma_t *p;
96 uint sdma_buffer_base;
Dave Liu7737d5c2006-11-03 12:11:15 -060097
Heiko Schocher9bd64442020-05-25 07:27:26 +020098 p = (sdma_t *)&qe_immr->sdma;
Dave Liu7737d5c2006-11-03 12:11:15 -060099
100 /* All of DMA transaction in bus 1 */
101 out_be32(&p->sdaqr, 0);
102 out_be32(&p->sdaqmr, 0);
103
104 /* Allocate 2KB temporary buffer for sdma */
Dave Liuff9658d2007-06-25 10:41:04 +0800105 sdma_buffer_base = qe_muram_alloc(2048, 4096);
Dave Liu7737d5c2006-11-03 12:11:15 -0600106 out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
107
108 /* Clear sdma status */
109 out_be32(&p->sdsr, 0x03000000);
110
111 /* Enable global mode on bus 1, and 2KB buffer size */
112 out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
113}
114
Haiying Wang4e7b25e2009-05-20 12:30:35 -0400115/* This table is a list of the serial numbers of the Threads, taken from the
116 * "SNUM Table" chart in the QE Reference Manual. The order is not important,
117 * we just need to know what the SNUMs are for the threads.
118 */
119static u8 thread_snum[] = {
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000120/* Evthreads 16-29 are not supported in MPC8309 */
Mario Six4bc97a32019-01-21 09:17:24 +0100121#if !defined(CONFIG_ARCH_MPC8309)
Dave Liu7737d5c2006-11-03 12:11:15 -0600122 0x04, 0x05, 0x0c, 0x0d,
123 0x14, 0x15, 0x1c, 0x1d,
124 0x24, 0x25, 0x2c, 0x2d,
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000125 0x34, 0x35,
126#endif
127 0x88, 0x89, 0x98, 0x99,
128 0xa8, 0xa9, 0xb8, 0xb9,
129 0xc8, 0xc9, 0xd8, 0xd9,
130 0xe8, 0xe9, 0x08, 0x09,
131 0x18, 0x19, 0x28, 0x29,
132 0x38, 0x39, 0x48, 0x49,
133 0x58, 0x59, 0x68, 0x69,
134 0x78, 0x79, 0x80, 0x81
Dave Liu7737d5c2006-11-03 12:11:15 -0600135};
136
137static void qe_snums_init(void)
138{
139 int i;
140
141 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
142 snums[i].state = QE_SNUM_STATE_FREE;
143 snums[i].num = thread_snum[i];
144 }
145}
146
147int qe_get_snum(void)
148{
149 int snum = -EBUSY;
150 int i;
151
152 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
153 if (snums[i].state == QE_SNUM_STATE_FREE) {
154 snums[i].state = QE_SNUM_STATE_USED;
155 snum = snums[i].num;
156 break;
157 }
158 }
159
160 return snum;
161}
162
163void qe_put_snum(u8 snum)
164{
165 int i;
166
167 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
168 if (snums[i].num == snum) {
169 snums[i].state = QE_SNUM_STATE_FREE;
170 break;
171 }
172 }
173}
174
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000175#ifdef CONFIG_TFABOOT
176void qe_init(uint qe_base)
177{
178 enum boot_src src = get_boot_src();
179
180 /* Init the QE IMMR base */
181 qe_immr = (qe_map_t *)qe_base;
182
183 if (src == BOOT_SOURCE_IFC_NOR) {
184 /*
185 * Upload microcode to IRAM for those SOCs
186 * which do not have ROM in QE.
187 */
188 qe_upload_firmware((const void *)(CONFIG_SYS_QE_FW_ADDR +
189 CONFIG_SYS_FSL_IFC_BASE));
190
191 /* enable the microcode in IRAM */
192 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
193 }
194
195 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
196 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
197
198 qe_sdma_init();
199 qe_snums_init();
200}
201#else
Dave Liu7737d5c2006-11-03 12:11:15 -0600202void qe_init(uint qe_base)
203{
Dave Liu7737d5c2006-11-03 12:11:15 -0600204 /* Init the QE IMMR base */
205 qe_immr = (qe_map_t *)qe_base;
206
Timur Tabif2717b42011-11-22 09:21:25 -0600207#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200208 /*
209 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
210 */
Zhao Qiangdcf1d772014-03-21 16:21:44 +0800211 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400212
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200213 /* enable the microcode in IRAM */
Heiko Schocher9bd64442020-05-25 07:27:26 +0200214 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400215#endif
216
Simon Glass45bae2e2012-12-13 20:48:50 +0000217 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
218 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
Dave Liu7737d5c2006-11-03 12:11:15 -0600219
220 qe_sdma_init();
221 qe_snums_init();
222}
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800223#endif
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000224#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600225
Zhao Qiang93d33202014-09-25 13:52:25 +0800226#ifdef CONFIG_U_QE
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000227#ifdef CONFIG_TFABOOT
228void u_qe_init(void)
229{
230 enum boot_src src = get_boot_src();
231
232 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
233
234 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
235
236 if (src == BOOT_SOURCE_IFC_NOR)
Heiko Schocher9bd64442020-05-25 07:27:26 +0200237 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
238 CONFIG_SYS_FSL_IFC_BASE);
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000239
240 if (src == BOOT_SOURCE_QSPI_NOR)
Heiko Schocher9bd64442020-05-25 07:27:26 +0200241 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
242 CONFIG_SYS_FSL_QSPI_BASE);
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000243
244 if (src == BOOT_SOURCE_SD_MMC) {
245 int dev = CONFIG_SYS_MMC_ENV_DEV;
246 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
247 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
248
249 if (mmc_initialize(gd->bd)) {
250 printf("%s: mmc_initialize() failed\n", __func__);
251 return;
252 }
253 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
254 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
255
256 if (!mmc) {
257 free(addr);
258 printf("\nMMC cannot find device for ucode\n");
259 } else {
260 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
261 dev, blk, cnt);
262 mmc_init(mmc);
263 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
264 addr);
265 }
266 }
267 if (!u_qe_upload_firmware(addr))
268 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
269 if (src == BOOT_SOURCE_SD_MMC)
270 free(addr);
271}
272#else
Zhao Qiang93d33202014-09-25 13:52:25 +0800273void u_qe_init(void)
274{
Zhao Qiangd3e6d302016-02-05 10:04:17 +0800275 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiang93d33202014-09-25 13:52:25 +0800276
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800277 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
278#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
279 int dev = CONFIG_SYS_MMC_ENV_DEV;
280 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
281 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
282
283 if (mmc_initialize(gd->bd)) {
284 printf("%s: mmc_initialize() failed\n", __func__);
285 return;
286 }
287 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
288 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
289
290 if (!mmc) {
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800291 printf("\nMMC cannot find device for ucode\n");
292 } else {
293 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
294 dev, blk, cnt);
295 mmc_init(mmc);
Yinbo Zhuc3ced8a2018-09-25 14:47:06 +0800296 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800297 addr);
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800298 }
299#endif
Zhao Qianga7a81752017-08-14 10:22:43 +0800300 if (!u_qe_upload_firmware(addr))
301 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800302#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
303 free(addr);
304#endif
Zhao Qiang93d33202014-09-25 13:52:25 +0800305}
306#endif
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000307#endif
Zhao Qiang93d33202014-09-25 13:52:25 +0800308
Zhao Qiangae42eb02015-03-25 17:02:59 +0800309#ifdef CONFIG_U_QE
310void u_qe_resume(void)
311{
312 qe_map_t *qe_immrr;
Zhao Qiangae42eb02015-03-25 17:02:59 +0800313
Zhao Qiangd3e6d302016-02-05 10:04:17 +0800314 qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiangae42eb02015-03-25 17:02:59 +0800315 u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr);
316 out_be32(&qe_immrr->iram.iready, QE_IRAM_READY);
317}
318#endif
319
Dave Liu7737d5c2006-11-03 12:11:15 -0600320void qe_reset(void)
321{
322 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
Heiko Schocher9bd64442020-05-25 07:27:26 +0200323 (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
Dave Liu7737d5c2006-11-03 12:11:15 -0600324}
325
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800326#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -0600327void qe_assign_page(uint snum, uint para_ram_base)
328{
329 u32 cecr;
330
331 out_be32(&qe_immr->cp.cecdr, para_ram_base);
Heiko Schocher9bd64442020-05-25 07:27:26 +0200332 out_be32(&qe_immr->cp.cecr, ((u32)snum << QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
Dave Liu7737d5c2006-11-03 12:11:15 -0600333 | QE_CR_FLG | QE_ASSIGN_PAGE);
334
335 /* Wait for the QE_CR_FLG to clear */
336 do {
337 cecr = in_be32(&qe_immr->cp.cecr);
Heiko Schocher9bd64442020-05-25 07:27:26 +0200338 } while (cecr & QE_CR_FLG);
Dave Liu7737d5c2006-11-03 12:11:15 -0600339}
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800340#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600341
342/*
343 * brg: 0~15 as BRG1~BRG16
Heiko Schocher9bd64442020-05-25 07:27:26 +0200344 * rate: baud rate
Dave Liu7737d5c2006-11-03 12:11:15 -0600345 * BRG input clock comes from the BRGCLK (internal clock generated from
Heiko Schocher9bd64442020-05-25 07:27:26 +0200346 * the QE clock, it is one-half of the QE clock), If need the clock source
347 * from CLKn pin, we have te change the function.
Dave Liu7737d5c2006-11-03 12:11:15 -0600348 */
349
Simon Glass1206c182012-12-13 20:48:44 +0000350#define BRG_CLK (gd->arch.brg_clk)
Dave Liu7737d5c2006-11-03 12:11:15 -0600351
Zhao Qiang93d33202014-09-25 13:52:25 +0800352#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -0600353int qe_set_brg(uint brg, uint rate)
354{
Heiko Schocher9bd64442020-05-25 07:27:26 +0200355 uint *bp;
356 u32 divisor;
357 u32 val;
358 int div16 = 0;
Dave Liu7737d5c2006-11-03 12:11:15 -0600359
360 if (brg >= QE_NUM_OF_BRGS)
361 return -EINVAL;
Heiko Schocher9bd64442020-05-25 07:27:26 +0200362
Dave Liu7737d5c2006-11-03 12:11:15 -0600363 bp = (uint *)&qe_immr->brg.brgc1;
364 bp += brg;
365
366 divisor = (BRG_CLK / rate);
367 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
368 div16 = 1;
369 divisor /= 16;
370 }
371
Heiko Schocher9bd64442020-05-25 07:27:26 +0200372 /* CHECK TODO */
373 /*
374 * was
375 * *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
376 * __asm__ __volatile__("sync");
377 */
Dave Liu7737d5c2006-11-03 12:11:15 -0600378
Heiko Schocher9bd64442020-05-25 07:27:26 +0200379 val = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
380 if (div16)
381 val |= QE_BRGC_DIV16;
382
383 out_be32(bp, val);
Dave Liu7737d5c2006-11-03 12:11:15 -0600384
385 return 0;
386}
Zhao Qiang93d33202014-09-25 13:52:25 +0800387#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600388
Heiko Schocher9bd64442020-05-25 07:27:26 +0200389/* Set ethernet MII clock master */
Dave Liu7737d5c2006-11-03 12:11:15 -0600390int qe_set_mii_clk_src(int ucc_num)
391{
392 u32 cmxgcr;
393
394 /* check if the UCC number is in range. */
Heiko Schocher9bd64442020-05-25 07:27:26 +0200395 if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) {
396 printf("%s: ucc num not in ranges\n", __func__);
Dave Liu7737d5c2006-11-03 12:11:15 -0600397 return -EINVAL;
398 }
399
400 cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
401 cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
Heiko Schocher9bd64442020-05-25 07:27:26 +0200402 cmxgcr |= (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
Dave Liu7737d5c2006-11-03 12:11:15 -0600403 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
404
405 return 0;
406}
407
Timur Tabib8ec2382008-01-07 13:31:19 -0600408/* Firmware information stored here for qe_get_firmware_info() */
409static struct qe_firmware_info qe_firmware_info;
410
411/*
412 * Set to 1 if QE firmware has been uploaded, and therefore
413 * qe_firmware_info contains valid data.
414 */
415static int qe_firmware_uploaded;
416
417/*
418 * Upload a QE microcode
419 *
420 * This function is a worker function for qe_upload_firmware(). It does
421 * the actual uploading of the microcode.
422 */
423static void qe_upload_microcode(const void *base,
Heiko Schocher9bd64442020-05-25 07:27:26 +0200424 const struct qe_microcode *ucode)
Timur Tabib8ec2382008-01-07 13:31:19 -0600425{
426 const u32 *code = base + be32_to_cpu(ucode->code_offset);
427 unsigned int i;
428
429 if (ucode->major || ucode->minor || ucode->revision)
430 printf("QE: uploading microcode '%s' version %u.%u.%u\n",
Zhao Qiange94a8fd2015-05-05 15:53:32 +0800431 (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
432 (u16)ucode->revision);
Timur Tabib8ec2382008-01-07 13:31:19 -0600433 else
Zhao Qiange94a8fd2015-05-05 15:53:32 +0800434 printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
Timur Tabib8ec2382008-01-07 13:31:19 -0600435
436 /* Use auto-increment */
437 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
438 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
439
440 for (i = 0; i < be32_to_cpu(ucode->count); i++)
441 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
442}
443
444/*
445 * Upload a microcode to the I-RAM at a specific address.
446 *
Heinrich Schuchardtd76485b2020-04-19 09:19:04 +0200447 * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for
448 * information on QE microcode uploading.
Timur Tabib8ec2382008-01-07 13:31:19 -0600449 *
450 * Currently, only version 1 is supported, so the 'version' field must be
451 * set to 1.
452 *
453 * The SOC model and revision are not validated, they are only displayed for
454 * informational purposes.
455 *
456 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
457 * all of the microcode structures, minus the CRC.
458 *
459 * 'length' is the size that the structure says it is, including the CRC.
460 */
461int qe_upload_firmware(const struct qe_firmware *firmware)
462{
463 unsigned int i;
464 unsigned int j;
465 u32 crc;
466 size_t calc_size = sizeof(struct qe_firmware);
467 size_t length;
468 const struct qe_header *hdr;
Zhao Qiangca721fb2014-04-30 16:45:31 +0800469#ifdef CONFIG_DEEP_SLEEP
York Sun73fb5832017-03-27 11:41:03 -0700470#ifdef CONFIG_ARCH_LS1021A
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800471 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
472#else
Zhao Qiangca721fb2014-04-30 16:45:31 +0800473 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
474#endif
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800475#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600476 if (!firmware) {
477 printf("Invalid address\n");
478 return -EINVAL;
479 }
480
481 hdr = &firmware->header;
482 length = be32_to_cpu(hdr->length);
483
484 /* Check the magic */
485 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
486 (hdr->magic[2] != 'F')) {
Vijay Rai12eeb132014-07-23 18:33:16 +0530487 printf("QE microcode not found\n");
Zhao Qiangca721fb2014-04-30 16:45:31 +0800488#ifdef CONFIG_DEEP_SLEEP
489 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
490#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600491 return -EPERM;
492 }
493
494 /* Check the version */
495 if (hdr->version != 1) {
496 printf("Unsupported version\n");
497 return -EPERM;
498 }
499
500 /* Validate some of the fields */
Heiko Schocher9bd64442020-05-25 07:27:26 +0200501 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
Timur Tabib8ec2382008-01-07 13:31:19 -0600502 printf("Invalid data\n");
503 return -EINVAL;
504 }
505
506 /* Validate the length and check if there's a CRC */
507 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
508
509 for (i = 0; i < firmware->count; i++)
510 /*
511 * For situations where the second RISC uses the same microcode
512 * as the first, the 'code_offset' and 'count' fields will be
513 * zero, so it's okay to add those.
514 */
515 calc_size += sizeof(u32) *
516 be32_to_cpu(firmware->microcode[i].count);
517
518 /* Validate the length */
519 if (length != calc_size + sizeof(u32)) {
520 printf("Invalid length\n");
521 return -EPERM;
522 }
523
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100524 /*
525 * Validate the CRC. We would normally call crc32_no_comp(), but that
526 * function isn't available unless you turn on JFFS support.
527 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600528 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
Heiko Schocher9bd64442020-05-25 07:27:26 +0200529 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
Timur Tabib8ec2382008-01-07 13:31:19 -0600530 printf("Firmware CRC is invalid\n");
531 return -EIO;
532 }
533
534 /*
535 * If the microcode calls for it, split the I-RAM.
536 */
537 if (!firmware->split) {
538 out_be16(&qe_immr->cp.cercr,
Heiko Schocher9bd64442020-05-25 07:27:26 +0200539 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
Timur Tabib8ec2382008-01-07 13:31:19 -0600540 }
541
542 if (firmware->soc.model)
543 printf("Firmware '%s' for %u V%u.%u\n",
Heiko Schocher9bd64442020-05-25 07:27:26 +0200544 firmware->id, be16_to_cpu(firmware->soc.model),
Timur Tabib8ec2382008-01-07 13:31:19 -0600545 firmware->soc.major, firmware->soc.minor);
546 else
547 printf("Firmware '%s'\n", firmware->id);
548
549 /*
550 * The QE only supports one microcode per RISC, so clear out all the
551 * saved microcode information and put in the new.
552 */
553 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Zhao Qiang0e0224e2015-05-05 15:53:33 +0800554 strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
Timur Tabib8ec2382008-01-07 13:31:19 -0600555 qe_firmware_info.extended_modes = firmware->extended_modes;
556 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
Heiko Schocher9bd64442020-05-25 07:27:26 +0200557 sizeof(firmware->vtraps));
Timur Tabib8ec2382008-01-07 13:31:19 -0600558 qe_firmware_uploaded = 1;
559
560 /* Loop through each microcode. */
561 for (i = 0; i < firmware->count; i++) {
562 const struct qe_microcode *ucode = &firmware->microcode[i];
563
564 /* Upload a microcode if it's present */
565 if (ucode->code_offset)
566 qe_upload_microcode(firmware, ucode);
567
568 /* Program the traps for this processor */
569 for (j = 0; j < 16; j++) {
570 u32 trap = be32_to_cpu(ucode->traps[j]);
571
572 if (trap)
573 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
574 }
575
576 /* Enable traps */
577 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
578 }
579
580 return 0;
581}
582
Zhao Qiang5632d152014-11-04 13:46:16 +0800583#ifdef CONFIG_U_QE
584/*
585 * Upload a microcode to the I-RAM at a specific address.
586 *
Heinrich Schuchardtd76485b2020-04-19 09:19:04 +0200587 * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for
588 * information on QE microcode uploading.
Zhao Qiang5632d152014-11-04 13:46:16 +0800589 *
590 * Currently, only version 1 is supported, so the 'version' field must be
591 * set to 1.
592 *
593 * The SOC model and revision are not validated, they are only displayed for
594 * informational purposes.
595 *
596 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
597 * all of the microcode structures, minus the CRC.
598 *
599 * 'length' is the size that the structure says it is, including the CRC.
600 */
601int u_qe_upload_firmware(const struct qe_firmware *firmware)
602{
603 unsigned int i;
604 unsigned int j;
605 u32 crc;
606 size_t calc_size = sizeof(struct qe_firmware);
607 size_t length;
608 const struct qe_header *hdr;
609#ifdef CONFIG_DEEP_SLEEP
York Sun73fb5832017-03-27 11:41:03 -0700610#ifdef CONFIG_ARCH_LS1021A
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800611 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
612#else
Zhao Qiang5632d152014-11-04 13:46:16 +0800613 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
614#endif
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800615#endif
Zhao Qiang5632d152014-11-04 13:46:16 +0800616 if (!firmware) {
617 printf("Invalid address\n");
618 return -EINVAL;
619 }
620
621 hdr = &firmware->header;
622 length = be32_to_cpu(hdr->length);
623
624 /* Check the magic */
625 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
626 (hdr->magic[2] != 'F')) {
627 printf("Not a microcode\n");
628#ifdef CONFIG_DEEP_SLEEP
629 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
630#endif
631 return -EPERM;
632 }
633
634 /* Check the version */
635 if (hdr->version != 1) {
636 printf("Unsupported version\n");
637 return -EPERM;
638 }
639
640 /* Validate some of the fields */
Heiko Schocher9bd64442020-05-25 07:27:26 +0200641 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
Zhao Qiang5632d152014-11-04 13:46:16 +0800642 printf("Invalid data\n");
643 return -EINVAL;
644 }
645
646 /* Validate the length and check if there's a CRC */
647 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
648
649 for (i = 0; i < firmware->count; i++)
650 /*
651 * For situations where the second RISC uses the same microcode
652 * as the first, the 'code_offset' and 'count' fields will be
653 * zero, so it's okay to add those.
654 */
655 calc_size += sizeof(u32) *
656 be32_to_cpu(firmware->microcode[i].count);
657
658 /* Validate the length */
659 if (length != calc_size + sizeof(u32)) {
660 printf("Invalid length\n");
661 return -EPERM;
662 }
663
664 /*
665 * Validate the CRC. We would normally call crc32_no_comp(), but that
666 * function isn't available unless you turn on JFFS support.
667 */
668 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
669 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
670 printf("Firmware CRC is invalid\n");
671 return -EIO;
672 }
673
674 /*
675 * If the microcode calls for it, split the I-RAM.
676 */
677 if (!firmware->split) {
678 out_be16(&qe_immr->cp.cercr,
679 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
680 }
681
682 if (firmware->soc.model)
683 printf("Firmware '%s' for %u V%u.%u\n",
684 firmware->id, be16_to_cpu(firmware->soc.model),
685 firmware->soc.major, firmware->soc.minor);
686 else
687 printf("Firmware '%s'\n", firmware->id);
688
689 /* Loop through each microcode. */
690 for (i = 0; i < firmware->count; i++) {
691 const struct qe_microcode *ucode = &firmware->microcode[i];
692
693 /* Upload a microcode if it's present */
694 if (ucode->code_offset)
695 qe_upload_microcode(firmware, ucode);
696
697 /* Program the traps for this processor */
698 for (j = 0; j < 16; j++) {
699 u32 trap = be32_to_cpu(ucode->traps[j]);
700
701 if (trap)
702 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
703 }
704
705 /* Enable traps */
706 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
707 }
708
709 return 0;
710}
711#endif
712
Zhao Qiangae42eb02015-03-25 17:02:59 +0800713#ifdef CONFIG_U_QE
714int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
715{
716 unsigned int i;
717 unsigned int j;
718 const struct qe_header *hdr;
719 const u32 *code;
720#ifdef CONFIG_DEEP_SLEEP
721#ifdef CONFIG_PPC
722 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
723#else
724 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
725#endif
726#endif
727
728 if (!firmware)
729 return -EINVAL;
730
731 hdr = &firmware->header;
732
733 /* Check the magic */
734 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
735 (hdr->magic[2] != 'F')) {
736#ifdef CONFIG_DEEP_SLEEP
737 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
738#endif
739 return -EPERM;
740 }
741
742 /*
743 * If the microcode calls for it, split the I-RAM.
744 */
745 if (!firmware->split) {
746 out_be16(&qe_immrr->cp.cercr,
747 in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
748 }
749
750 /* Loop through each microcode. */
751 for (i = 0; i < firmware->count; i++) {
752 const struct qe_microcode *ucode = &firmware->microcode[i];
753
754 /* Upload a microcode if it's present */
755 if (!ucode->code_offset)
756 return 0;
757
758 code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
759
760 /* Use auto-increment */
761 out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
762 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
763
764 for (i = 0; i < be32_to_cpu(ucode->count); i++)
765 out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
766
767 /* Program the traps for this processor */
768 for (j = 0; j < 16; j++) {
769 u32 trap = be32_to_cpu(ucode->traps[j]);
770
771 if (trap)
772 out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
773 }
774
775 /* Enable traps */
776 out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
777 }
778
779 return 0;
780}
781#endif
782
Timur Tabib8ec2382008-01-07 13:31:19 -0600783struct qe_firmware_info *qe_get_firmware_info(void)
784{
785 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
786}
787
Simon Glass09140112020-05-10 11:40:03 -0600788static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Timur Tabib8ec2382008-01-07 13:31:19 -0600789{
790 ulong addr;
791
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200792 if (argc < 3)
793 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600794
795 if (strcmp(argv[1], "fw") == 0) {
796 addr = simple_strtoul(argv[2], NULL, 16);
797
798 if (!addr) {
799 printf("Invalid address\n");
800 return -EINVAL;
801 }
802
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100803 /*
804 * If a length was supplied, compare that with the 'length'
805 * field.
806 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600807
808 if (argc > 3) {
809 ulong length = simple_strtoul(argv[3], NULL, 16);
Heiko Schocher9bd64442020-05-25 07:27:26 +0200810 struct qe_firmware *firmware = (void *)addr;
Timur Tabib8ec2382008-01-07 13:31:19 -0600811
812 if (length != be32_to_cpu(firmware->header.length)) {
813 printf("Length mismatch\n");
814 return -EINVAL;
815 }
816 }
817
Heiko Schocher9bd64442020-05-25 07:27:26 +0200818 return qe_upload_firmware((const struct qe_firmware *)addr);
Timur Tabib8ec2382008-01-07 13:31:19 -0600819 }
820
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200821 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600822}
823
824U_BOOT_CMD(
825 qe, 4, 0, qe_cmd,
Peter Tyser2fb26042009-01-27 18:03:12 -0600826 "QUICC Engine commands",
Heiko Schocher9bd64442020-05-25 07:27:26 +0200827 "fw <addr> [<length>] - Upload firmware binary at address <addr> to the QE,\n"
Wolfgang Denka89c33d2009-05-24 17:06:54 +0200828 "\twith optional length <length> verification."
829);