blob: 2825dc6f9aa6c4e630e85e0842207d2ef6fc4a9f [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>
Simon Glass401d1c42020-10-30 21:38:53 -060012#include <asm/global_data.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>
Rajesh Bhagatc5e66372018-11-05 18:02:28 +000017#include <mmc.h>
Simon Glass3db71102019-11-14 12:57:16 -070018#include <u-boot/crc.h>
Rajesh Bhagatc5e66372018-11-05 18:02:28 +000019
York Sun73fb5832017-03-27 11:41:03 -070020#ifdef CONFIG_ARCH_LS1021A
Zhao Qiang9c7c86f2014-12-15 15:50:49 +080021#include <asm/arch/immap_ls102xa.h>
22#endif
Rajesh Bhagatc5e66372018-11-05 18:02:28 +000023#ifdef CONFIG_ARM64
24#include <asm/armv8/mmu.h>
25#include <asm/arch/cpu.h>
Zhao Qiang5aa03dd2017-05-25 09:47:40 +080026#endif
27
Zhao Qiangca721fb2014-04-30 16:45:31 +080028#define MPC85xx_DEVDISR_QE_DISABLE 0x1
29
Heiko Schocher9bd64442020-05-25 07:27:26 +020030qe_map_t *qe_immr;
Zhao Qiang3bf46e62016-02-05 10:04:16 +080031#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060032static qe_snum_t snums[QE_NUM_OF_SNUM];
Zhao Qiang3bf46e62016-02-05 10:04:16 +080033#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060034
Wolfgang Denk1218abf2007-09-15 20:48:41 +020035DECLARE_GLOBAL_DATA_PTR;
36
Dave Liu7737d5c2006-11-03 12:11:15 -060037void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
38{
Wolfgang Denkd3a65322008-01-10 00:55:14 +010039 u32 cecr;
Dave Liu7737d5c2006-11-03 12:11:15 -060040
41 if (cmd == QE_RESET) {
Heiko Schocher9bd64442020-05-25 07:27:26 +020042 out_be32(&qe_immr->cp.cecr, (u32)(cmd | QE_CR_FLG));
Dave Liu7737d5c2006-11-03 12:11:15 -060043 } else {
44 out_be32(&qe_immr->cp.cecdr, cmd_data);
45 out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
Heiko Schocher9bd64442020-05-25 07:27:26 +020046 ((u32)mcn << QE_CR_PROTOCOL_SHIFT) | cmd));
Dave Liu7737d5c2006-11-03 12:11:15 -060047 }
48 /* Wait for the QE_CR_FLG to clear */
49 do {
50 cecr = in_be32(&qe_immr->cp.cecr);
51 } while (cecr & QE_CR_FLG);
Dave Liu7737d5c2006-11-03 12:11:15 -060052}
53
Zhao Qiang93d33202014-09-25 13:52:25 +080054#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060055uint qe_muram_alloc(uint size, uint align)
56{
Dave Liu7737d5c2006-11-03 12:11:15 -060057 uint retloc;
58 uint align_mask, off;
59 uint savebase;
60
61 align_mask = align - 1;
Simon Glass45bae2e2012-12-13 20:48:50 +000062 savebase = gd->arch.mp_alloc_base;
Dave Liu7737d5c2006-11-03 12:11:15 -060063
Simon Glass45bae2e2012-12-13 20:48:50 +000064 off = gd->arch.mp_alloc_base & align_mask;
65 if (off != 0)
66 gd->arch.mp_alloc_base += (align - off);
Dave Liu7737d5c2006-11-03 12:11:15 -060067
Heiko Schocher9bd64442020-05-25 07:27:26 +020068 off = size & align_mask;
69 if (off != 0)
Dave Liu7737d5c2006-11-03 12:11:15 -060070 size += (align - off);
71
Simon Glass45bae2e2012-12-13 20:48:50 +000072 if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
73 gd->arch.mp_alloc_base = savebase;
Heiko Schocher9bd64442020-05-25 07:27:26 +020074 printf("%s: ran out of ram.\n", __func__);
Dave Liu7737d5c2006-11-03 12:11:15 -060075 }
76
Simon Glass45bae2e2012-12-13 20:48:50 +000077 retloc = gd->arch.mp_alloc_base;
78 gd->arch.mp_alloc_base += size;
Dave Liu7737d5c2006-11-03 12:11:15 -060079
80 memset((void *)&qe_immr->muram[retloc], 0, size);
81
82 __asm__ __volatile__("sync");
83
84 return retloc;
85}
Zhao Qiang93d33202014-09-25 13:52:25 +080086#endif
Dave Liu7737d5c2006-11-03 12:11:15 -060087
88void *qe_muram_addr(uint offset)
89{
90 return (void *)&qe_immr->muram[offset];
91}
92
Zhao Qiang3bf46e62016-02-05 10:04:16 +080093#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -060094static void qe_sdma_init(void)
95{
Heiko Schocher9bd64442020-05-25 07:27:26 +020096 sdma_t *p;
97 uint sdma_buffer_base;
Dave Liu7737d5c2006-11-03 12:11:15 -060098
Heiko Schocher9bd64442020-05-25 07:27:26 +020099 p = (sdma_t *)&qe_immr->sdma;
Dave Liu7737d5c2006-11-03 12:11:15 -0600100
101 /* All of DMA transaction in bus 1 */
102 out_be32(&p->sdaqr, 0);
103 out_be32(&p->sdaqmr, 0);
104
105 /* Allocate 2KB temporary buffer for sdma */
Dave Liuff9658d2007-06-25 10:41:04 +0800106 sdma_buffer_base = qe_muram_alloc(2048, 4096);
Dave Liu7737d5c2006-11-03 12:11:15 -0600107 out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
108
109 /* Clear sdma status */
110 out_be32(&p->sdsr, 0x03000000);
111
112 /* Enable global mode on bus 1, and 2KB buffer size */
113 out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
114}
115
Haiying Wang4e7b25e2009-05-20 12:30:35 -0400116/* This table is a list of the serial numbers of the Threads, taken from the
117 * "SNUM Table" chart in the QE Reference Manual. The order is not important,
118 * we just need to know what the SNUMs are for the threads.
119 */
120static u8 thread_snum[] = {
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000121/* Evthreads 16-29 are not supported in 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,
Gerlando Falautoa88731a2012-10-10 22:13:08 +0000126 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
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000174#ifdef CONFIG_TFABOOT
175void qe_init(uint qe_base)
176{
177 enum boot_src src = get_boot_src();
178
179 /* Init the QE IMMR base */
180 qe_immr = (qe_map_t *)qe_base;
181
182 if (src == BOOT_SOURCE_IFC_NOR) {
183 /*
184 * Upload microcode to IRAM for those SOCs
185 * which do not have ROM in QE.
186 */
187 qe_upload_firmware((const void *)(CONFIG_SYS_QE_FW_ADDR +
Tom Rini6e7df1d2023-01-10 11:19:45 -0500188 CFG_SYS_FSL_IFC_BASE));
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000189
190 /* enable the microcode in IRAM */
191 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
192 }
193
194 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
195 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
196
197 qe_sdma_init();
198 qe_snums_init();
199}
200#else
Dave Liu7737d5c2006-11-03 12:11:15 -0600201void qe_init(uint qe_base)
202{
Dave Liu7737d5c2006-11-03 12:11:15 -0600203 /* Init the QE IMMR base */
204 qe_immr = (qe_map_t *)qe_base;
205
Timur Tabif2717b42011-11-22 09:21:25 -0600206#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200207 /*
208 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
209 */
Zhao Qiangdcf1d772014-03-21 16:21:44 +0800210 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400211
Wolfgang Denkc0a14ae2009-04-05 00:27:57 +0200212 /* enable the microcode in IRAM */
Heiko Schocher9bd64442020-05-25 07:27:26 +0200213 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Haiying Wang2d4de6a2009-03-26 17:01:49 -0400214#endif
215
Simon Glass45bae2e2012-12-13 20:48:50 +0000216 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
217 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
Dave Liu7737d5c2006-11-03 12:11:15 -0600218
219 qe_sdma_init();
220 qe_snums_init();
221}
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800222#endif
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000223#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600224
Zhao Qiang93d33202014-09-25 13:52:25 +0800225#ifdef CONFIG_U_QE
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000226#ifdef CONFIG_TFABOOT
227void u_qe_init(void)
228{
229 enum boot_src src = get_boot_src();
230
231 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
232
233 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
234
235 if (src == BOOT_SOURCE_IFC_NOR)
Heiko Schocher9bd64442020-05-25 07:27:26 +0200236 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
Tom Rini6e7df1d2023-01-10 11:19:45 -0500237 CFG_SYS_FSL_IFC_BASE);
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000238
239 if (src == BOOT_SOURCE_QSPI_NOR)
Heiko Schocher9bd64442020-05-25 07:27:26 +0200240 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
Tom Rini6cc04542022-10-28 20:27:13 -0400241 CFG_SYS_FSL_QSPI_BASE);
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000242
243 if (src == BOOT_SOURCE_SD_MMC) {
244 int dev = CONFIG_SYS_MMC_ENV_DEV;
245 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
246 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
247
248 if (mmc_initialize(gd->bd)) {
249 printf("%s: mmc_initialize() failed\n", __func__);
250 return;
251 }
252 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
253 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
254
255 if (!mmc) {
256 free(addr);
257 printf("\nMMC cannot find device for ucode\n");
258 } else {
259 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
260 dev, blk, cnt);
261 mmc_init(mmc);
262 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
263 addr);
264 }
265 }
266 if (!u_qe_upload_firmware(addr))
267 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
268 if (src == BOOT_SOURCE_SD_MMC)
269 free(addr);
270}
271#else
Zhao Qiang93d33202014-09-25 13:52:25 +0800272void u_qe_init(void)
273{
Zhao Qiangd3e6d302016-02-05 10:04:17 +0800274 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiang93d33202014-09-25 13:52:25 +0800275
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800276 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
277#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
278 int dev = CONFIG_SYS_MMC_ENV_DEV;
279 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
280 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
281
282 if (mmc_initialize(gd->bd)) {
283 printf("%s: mmc_initialize() failed\n", __func__);
284 return;
285 }
286 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
287 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
288
289 if (!mmc) {
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800290 printf("\nMMC cannot find device for ucode\n");
291 } else {
292 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
293 dev, blk, cnt);
294 mmc_init(mmc);
Yinbo Zhuc3ced8a2018-09-25 14:47:06 +0800295 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800296 addr);
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800297 }
298#endif
Zhao Qianga7a81752017-08-14 10:22:43 +0800299 if (!u_qe_upload_firmware(addr))
300 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Zhao Qiang5aa03dd2017-05-25 09:47:40 +0800301#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
302 free(addr);
303#endif
Zhao Qiang93d33202014-09-25 13:52:25 +0800304}
305#endif
Rajesh Bhagatc5e66372018-11-05 18:02:28 +0000306#endif
Zhao Qiang93d33202014-09-25 13:52:25 +0800307
Zhao Qiangae42eb02015-03-25 17:02:59 +0800308#ifdef CONFIG_U_QE
309void u_qe_resume(void)
310{
311 qe_map_t *qe_immrr;
Zhao Qiangae42eb02015-03-25 17:02:59 +0800312
Zhao Qiangd3e6d302016-02-05 10:04:17 +0800313 qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiangae42eb02015-03-25 17:02:59 +0800314 u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr);
315 out_be32(&qe_immrr->iram.iready, QE_IRAM_READY);
316}
317#endif
318
Dave Liu7737d5c2006-11-03 12:11:15 -0600319void qe_reset(void)
320{
321 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
Heiko Schocher9bd64442020-05-25 07:27:26 +0200322 (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
Dave Liu7737d5c2006-11-03 12:11:15 -0600323}
324
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800325#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -0600326void qe_assign_page(uint snum, uint para_ram_base)
327{
328 u32 cecr;
329
330 out_be32(&qe_immr->cp.cecdr, para_ram_base);
Heiko Schocher9bd64442020-05-25 07:27:26 +0200331 out_be32(&qe_immr->cp.cecr, ((u32)snum << QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
Dave Liu7737d5c2006-11-03 12:11:15 -0600332 | QE_CR_FLG | QE_ASSIGN_PAGE);
333
334 /* Wait for the QE_CR_FLG to clear */
335 do {
336 cecr = in_be32(&qe_immr->cp.cecr);
Heiko Schocher9bd64442020-05-25 07:27:26 +0200337 } while (cecr & QE_CR_FLG);
Dave Liu7737d5c2006-11-03 12:11:15 -0600338}
Zhao Qiang3bf46e62016-02-05 10:04:16 +0800339#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600340
341/*
342 * brg: 0~15 as BRG1~BRG16
Heiko Schocher9bd64442020-05-25 07:27:26 +0200343 * rate: baud rate
Dave Liu7737d5c2006-11-03 12:11:15 -0600344 * BRG input clock comes from the BRGCLK (internal clock generated from
Heiko Schocher9bd64442020-05-25 07:27:26 +0200345 * the QE clock, it is one-half of the QE clock), If need the clock source
346 * from CLKn pin, we have te change the function.
Dave Liu7737d5c2006-11-03 12:11:15 -0600347 */
348
Simon Glass1206c182012-12-13 20:48:44 +0000349#define BRG_CLK (gd->arch.brg_clk)
Dave Liu7737d5c2006-11-03 12:11:15 -0600350
Zhao Qiang93d33202014-09-25 13:52:25 +0800351#ifdef CONFIG_QE
Dave Liu7737d5c2006-11-03 12:11:15 -0600352int qe_set_brg(uint brg, uint rate)
353{
Heiko Schocher9bd64442020-05-25 07:27:26 +0200354 uint *bp;
355 u32 divisor;
356 u32 val;
357 int div16 = 0;
Dave Liu7737d5c2006-11-03 12:11:15 -0600358
359 if (brg >= QE_NUM_OF_BRGS)
360 return -EINVAL;
Heiko Schocher9bd64442020-05-25 07:27:26 +0200361
Dave Liu7737d5c2006-11-03 12:11:15 -0600362 bp = (uint *)&qe_immr->brg.brgc1;
363 bp += brg;
364
365 divisor = (BRG_CLK / rate);
366 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
367 div16 = 1;
368 divisor /= 16;
369 }
370
Heiko Schocher9bd64442020-05-25 07:27:26 +0200371 /* CHECK TODO */
372 /*
373 * was
374 * *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
375 * __asm__ __volatile__("sync");
376 */
Dave Liu7737d5c2006-11-03 12:11:15 -0600377
Heiko Schocher9bd64442020-05-25 07:27:26 +0200378 val = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
379 if (div16)
380 val |= QE_BRGC_DIV16;
381
382 out_be32(bp, val);
Dave Liu7737d5c2006-11-03 12:11:15 -0600383
384 return 0;
385}
Zhao Qiang93d33202014-09-25 13:52:25 +0800386#endif
Dave Liu7737d5c2006-11-03 12:11:15 -0600387
Heiko Schocher9bd64442020-05-25 07:27:26 +0200388/* Set ethernet MII clock master */
Dave Liu7737d5c2006-11-03 12:11:15 -0600389int qe_set_mii_clk_src(int ucc_num)
390{
391 u32 cmxgcr;
392
393 /* check if the UCC number is in range. */
Heiko Schocher9bd64442020-05-25 07:27:26 +0200394 if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) {
395 printf("%s: ucc num not in ranges\n", __func__);
Dave Liu7737d5c2006-11-03 12:11:15 -0600396 return -EINVAL;
397 }
398
399 cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
400 cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
Heiko Schocher9bd64442020-05-25 07:27:26 +0200401 cmxgcr |= (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
Dave Liu7737d5c2006-11-03 12:11:15 -0600402 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
403
404 return 0;
405}
406
Timur Tabib8ec2382008-01-07 13:31:19 -0600407/* Firmware information stored here for qe_get_firmware_info() */
408static struct qe_firmware_info qe_firmware_info;
409
410/*
411 * Set to 1 if QE firmware has been uploaded, and therefore
412 * qe_firmware_info contains valid data.
413 */
414static int qe_firmware_uploaded;
415
416/*
417 * Upload a QE microcode
418 *
419 * This function is a worker function for qe_upload_firmware(). It does
420 * the actual uploading of the microcode.
421 */
422static void qe_upload_microcode(const void *base,
Heiko Schocher9bd64442020-05-25 07:27:26 +0200423 const struct qe_microcode *ucode)
Timur Tabib8ec2382008-01-07 13:31:19 -0600424{
425 const u32 *code = base + be32_to_cpu(ucode->code_offset);
426 unsigned int i;
427
428 if (ucode->major || ucode->minor || ucode->revision)
429 printf("QE: uploading microcode '%s' version %u.%u.%u\n",
Zhao Qiange94a8fd2015-05-05 15:53:32 +0800430 (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
431 (u16)ucode->revision);
Timur Tabib8ec2382008-01-07 13:31:19 -0600432 else
Zhao Qiange94a8fd2015-05-05 15:53:32 +0800433 printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
Timur Tabib8ec2382008-01-07 13:31:19 -0600434
435 /* Use auto-increment */
436 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
437 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
438
439 for (i = 0; i < be32_to_cpu(ucode->count); i++)
440 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
441}
442
443/*
444 * Upload a microcode to the I-RAM at a specific address.
445 *
Heinrich Schuchardtd76485b2020-04-19 09:19:04 +0200446 * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for
447 * information on QE microcode uploading.
Timur Tabib8ec2382008-01-07 13:31:19 -0600448 *
449 * Currently, only version 1 is supported, so the 'version' field must be
450 * set to 1.
451 *
452 * The SOC model and revision are not validated, they are only displayed for
453 * informational purposes.
454 *
455 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
456 * all of the microcode structures, minus the CRC.
457 *
458 * 'length' is the size that the structure says it is, including the CRC.
459 */
460int qe_upload_firmware(const struct qe_firmware *firmware)
461{
462 unsigned int i;
463 unsigned int j;
464 u32 crc;
465 size_t calc_size = sizeof(struct qe_firmware);
466 size_t length;
467 const struct qe_header *hdr;
Zhao Qiangca721fb2014-04-30 16:45:31 +0800468#ifdef CONFIG_DEEP_SLEEP
York Sun73fb5832017-03-27 11:41:03 -0700469#ifdef CONFIG_ARCH_LS1021A
Tom Rini6cc04542022-10-28 20:27:13 -0400470 struct ccsr_gur __iomem *gur = (void *)CFG_SYS_FSL_GUTS_ADDR;
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800471#else
Tom Rini51552072022-10-28 20:27:12 -0400472 ccsr_gur_t *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
Zhao Qiangca721fb2014-04-30 16:45:31 +0800473#endif
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800474#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600475 if (!firmware) {
476 printf("Invalid address\n");
477 return -EINVAL;
478 }
479
480 hdr = &firmware->header;
481 length = be32_to_cpu(hdr->length);
482
483 /* Check the magic */
484 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
485 (hdr->magic[2] != 'F')) {
Vijay Rai12eeb132014-07-23 18:33:16 +0530486 printf("QE microcode not found\n");
Zhao Qiangca721fb2014-04-30 16:45:31 +0800487#ifdef CONFIG_DEEP_SLEEP
488 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
489#endif
Timur Tabib8ec2382008-01-07 13:31:19 -0600490 return -EPERM;
491 }
492
493 /* Check the version */
494 if (hdr->version != 1) {
495 printf("Unsupported version\n");
496 return -EPERM;
497 }
498
499 /* Validate some of the fields */
Heiko Schocher9bd64442020-05-25 07:27:26 +0200500 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
Timur Tabib8ec2382008-01-07 13:31:19 -0600501 printf("Invalid data\n");
502 return -EINVAL;
503 }
504
505 /* Validate the length and check if there's a CRC */
506 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
507
508 for (i = 0; i < firmware->count; i++)
509 /*
510 * For situations where the second RISC uses the same microcode
511 * as the first, the 'code_offset' and 'count' fields will be
512 * zero, so it's okay to add those.
513 */
514 calc_size += sizeof(u32) *
515 be32_to_cpu(firmware->microcode[i].count);
516
517 /* Validate the length */
518 if (length != calc_size + sizeof(u32)) {
519 printf("Invalid length\n");
520 return -EPERM;
521 }
522
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100523 /*
524 * Validate the CRC. We would normally call crc32_no_comp(), but that
525 * function isn't available unless you turn on JFFS support.
526 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600527 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
Heiko Schocher9bd64442020-05-25 07:27:26 +0200528 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
Timur Tabib8ec2382008-01-07 13:31:19 -0600529 printf("Firmware CRC is invalid\n");
530 return -EIO;
531 }
532
533 /*
534 * If the microcode calls for it, split the I-RAM.
535 */
536 if (!firmware->split) {
537 out_be16(&qe_immr->cp.cercr,
Heiko Schocher9bd64442020-05-25 07:27:26 +0200538 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
Timur Tabib8ec2382008-01-07 13:31:19 -0600539 }
540
541 if (firmware->soc.model)
542 printf("Firmware '%s' for %u V%u.%u\n",
Heiko Schocher9bd64442020-05-25 07:27:26 +0200543 firmware->id, be16_to_cpu(firmware->soc.model),
Timur Tabib8ec2382008-01-07 13:31:19 -0600544 firmware->soc.major, firmware->soc.minor);
545 else
546 printf("Firmware '%s'\n", firmware->id);
547
548 /*
549 * The QE only supports one microcode per RISC, so clear out all the
550 * saved microcode information and put in the new.
551 */
552 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Zhao Qiang0e0224e2015-05-05 15:53:33 +0800553 strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
Timur Tabib8ec2382008-01-07 13:31:19 -0600554 qe_firmware_info.extended_modes = firmware->extended_modes;
555 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
Heiko Schocher9bd64442020-05-25 07:27:26 +0200556 sizeof(firmware->vtraps));
Timur Tabib8ec2382008-01-07 13:31:19 -0600557 qe_firmware_uploaded = 1;
558
559 /* Loop through each microcode. */
560 for (i = 0; i < firmware->count; i++) {
561 const struct qe_microcode *ucode = &firmware->microcode[i];
562
563 /* Upload a microcode if it's present */
564 if (ucode->code_offset)
565 qe_upload_microcode(firmware, ucode);
566
567 /* Program the traps for this processor */
568 for (j = 0; j < 16; j++) {
569 u32 trap = be32_to_cpu(ucode->traps[j]);
570
571 if (trap)
572 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
573 }
574
575 /* Enable traps */
576 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
577 }
578
579 return 0;
580}
581
Zhao Qiang5632d152014-11-04 13:46:16 +0800582#ifdef CONFIG_U_QE
583/*
584 * Upload a microcode to the I-RAM at a specific address.
585 *
Heinrich Schuchardtd76485b2020-04-19 09:19:04 +0200586 * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for
587 * information on QE microcode uploading.
Zhao Qiang5632d152014-11-04 13:46:16 +0800588 *
589 * Currently, only version 1 is supported, so the 'version' field must be
590 * set to 1.
591 *
592 * The SOC model and revision are not validated, they are only displayed for
593 * informational purposes.
594 *
595 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
596 * all of the microcode structures, minus the CRC.
597 *
598 * 'length' is the size that the structure says it is, including the CRC.
599 */
600int u_qe_upload_firmware(const struct qe_firmware *firmware)
601{
602 unsigned int i;
603 unsigned int j;
604 u32 crc;
605 size_t calc_size = sizeof(struct qe_firmware);
606 size_t length;
607 const struct qe_header *hdr;
608#ifdef CONFIG_DEEP_SLEEP
York Sun73fb5832017-03-27 11:41:03 -0700609#ifdef CONFIG_ARCH_LS1021A
Tom Rini6cc04542022-10-28 20:27:13 -0400610 struct ccsr_gur __iomem *gur = (void *)CFG_SYS_FSL_GUTS_ADDR;
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800611#else
Tom Rini51552072022-10-28 20:27:12 -0400612 ccsr_gur_t __iomem *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
Zhao Qiang5632d152014-11-04 13:46:16 +0800613#endif
Zhao Qiang9c7c86f2014-12-15 15:50:49 +0800614#endif
Zhao Qiang5632d152014-11-04 13:46:16 +0800615 if (!firmware) {
616 printf("Invalid address\n");
617 return -EINVAL;
618 }
619
620 hdr = &firmware->header;
621 length = be32_to_cpu(hdr->length);
622
623 /* Check the magic */
624 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
625 (hdr->magic[2] != 'F')) {
626 printf("Not a microcode\n");
627#ifdef CONFIG_DEEP_SLEEP
628 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
629#endif
630 return -EPERM;
631 }
632
633 /* Check the version */
634 if (hdr->version != 1) {
635 printf("Unsupported version\n");
636 return -EPERM;
637 }
638
639 /* Validate some of the fields */
Heiko Schocher9bd64442020-05-25 07:27:26 +0200640 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
Zhao Qiang5632d152014-11-04 13:46:16 +0800641 printf("Invalid data\n");
642 return -EINVAL;
643 }
644
645 /* Validate the length and check if there's a CRC */
646 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
647
648 for (i = 0; i < firmware->count; i++)
649 /*
650 * For situations where the second RISC uses the same microcode
651 * as the first, the 'code_offset' and 'count' fields will be
652 * zero, so it's okay to add those.
653 */
654 calc_size += sizeof(u32) *
655 be32_to_cpu(firmware->microcode[i].count);
656
657 /* Validate the length */
658 if (length != calc_size + sizeof(u32)) {
659 printf("Invalid length\n");
660 return -EPERM;
661 }
662
663 /*
664 * Validate the CRC. We would normally call crc32_no_comp(), but that
665 * function isn't available unless you turn on JFFS support.
666 */
667 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
668 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
669 printf("Firmware CRC is invalid\n");
670 return -EIO;
671 }
672
673 /*
674 * If the microcode calls for it, split the I-RAM.
675 */
676 if (!firmware->split) {
677 out_be16(&qe_immr->cp.cercr,
678 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
679 }
680
681 if (firmware->soc.model)
682 printf("Firmware '%s' for %u V%u.%u\n",
683 firmware->id, be16_to_cpu(firmware->soc.model),
684 firmware->soc.major, firmware->soc.minor);
685 else
686 printf("Firmware '%s'\n", firmware->id);
687
688 /* Loop through each microcode. */
689 for (i = 0; i < firmware->count; i++) {
690 const struct qe_microcode *ucode = &firmware->microcode[i];
691
692 /* Upload a microcode if it's present */
693 if (ucode->code_offset)
694 qe_upload_microcode(firmware, ucode);
695
696 /* Program the traps for this processor */
697 for (j = 0; j < 16; j++) {
698 u32 trap = be32_to_cpu(ucode->traps[j]);
699
700 if (trap)
701 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
702 }
703
704 /* Enable traps */
705 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
706 }
707
708 return 0;
709}
710#endif
711
Zhao Qiangae42eb02015-03-25 17:02:59 +0800712#ifdef CONFIG_U_QE
713int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
714{
715 unsigned int i;
716 unsigned int j;
717 const struct qe_header *hdr;
718 const u32 *code;
719#ifdef CONFIG_DEEP_SLEEP
720#ifdef CONFIG_PPC
Tom Rini51552072022-10-28 20:27:12 -0400721 ccsr_gur_t __iomem *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
Zhao Qiangae42eb02015-03-25 17:02:59 +0800722#else
Tom Rini6cc04542022-10-28 20:27:13 -0400723 struct ccsr_gur __iomem *gur = (void *)CFG_SYS_FSL_GUTS_ADDR;
Zhao Qiangae42eb02015-03-25 17:02:59 +0800724#endif
725#endif
726
727 if (!firmware)
728 return -EINVAL;
729
730 hdr = &firmware->header;
731
732 /* Check the magic */
733 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
734 (hdr->magic[2] != 'F')) {
735#ifdef CONFIG_DEEP_SLEEP
736 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
737#endif
738 return -EPERM;
739 }
740
741 /*
742 * If the microcode calls for it, split the I-RAM.
743 */
744 if (!firmware->split) {
745 out_be16(&qe_immrr->cp.cercr,
746 in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
747 }
748
749 /* Loop through each microcode. */
750 for (i = 0; i < firmware->count; i++) {
751 const struct qe_microcode *ucode = &firmware->microcode[i];
752
753 /* Upload a microcode if it's present */
754 if (!ucode->code_offset)
755 return 0;
756
757 code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
758
759 /* Use auto-increment */
760 out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
761 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
762
763 for (i = 0; i < be32_to_cpu(ucode->count); i++)
764 out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
765
766 /* Program the traps for this processor */
767 for (j = 0; j < 16; j++) {
768 u32 trap = be32_to_cpu(ucode->traps[j]);
769
770 if (trap)
771 out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
772 }
773
774 /* Enable traps */
775 out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
776 }
777
778 return 0;
779}
780#endif
781
Timur Tabib8ec2382008-01-07 13:31:19 -0600782struct qe_firmware_info *qe_get_firmware_info(void)
783{
784 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
785}
786
Simon Glass09140112020-05-10 11:40:03 -0600787static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Timur Tabib8ec2382008-01-07 13:31:19 -0600788{
789 ulong addr;
790
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200791 if (argc < 3)
792 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600793
794 if (strcmp(argv[1], "fw") == 0) {
Simon Glass7e5f4602021-07-24 09:03:29 -0600795 addr = hextoul(argv[2], NULL);
Timur Tabib8ec2382008-01-07 13:31:19 -0600796
797 if (!addr) {
798 printf("Invalid address\n");
799 return -EINVAL;
800 }
801
Wolfgang Denkd3a65322008-01-10 00:55:14 +0100802 /*
803 * If a length was supplied, compare that with the 'length'
804 * field.
805 */
Timur Tabib8ec2382008-01-07 13:31:19 -0600806
807 if (argc > 3) {
Simon Glass7e5f4602021-07-24 09:03:29 -0600808 ulong length = hextoul(argv[3], NULL);
Heiko Schocher9bd64442020-05-25 07:27:26 +0200809 struct qe_firmware *firmware = (void *)addr;
Timur Tabib8ec2382008-01-07 13:31:19 -0600810
811 if (length != be32_to_cpu(firmware->header.length)) {
812 printf("Length mismatch\n");
813 return -EINVAL;
814 }
815 }
816
Heiko Schocher9bd64442020-05-25 07:27:26 +0200817 return qe_upload_firmware((const struct qe_firmware *)addr);
Timur Tabib8ec2382008-01-07 13:31:19 -0600818 }
819
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200820 return cmd_usage(cmdtp);
Timur Tabib8ec2382008-01-07 13:31:19 -0600821}
822
823U_BOOT_CMD(
824 qe, 4, 0, qe_cmd,
Peter Tyser2fb26042009-01-27 18:03:12 -0600825 "QUICC Engine commands",
Heiko Schocher9bd64442020-05-25 07:27:26 +0200826 "fw <addr> [<length>] - Upload firmware binary at address <addr> to the QE,\n"
Wolfgang Denka89c33d2009-05-24 17:06:54 +0200827 "\twith optional length <length> verification."
828);