blob: 736dd8558b60414344654e629c1992448b1619db [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dave Liue732e9c2006-11-03 12:11:15 -06002/*
Haiying Wang0eea38e2009-05-20 12:30:35 -04003 * Copyright (C) 2006-2009 Freescale Semiconductor, Inc.
Dave Liue732e9c2006-11-03 12:11:15 -06004 *
5 * Dave Liu <daveliu@freescale.com>
6 * based on source code of Shlomi Gridish
Dave Liue732e9c2006-11-03 12:11:15 -06007 */
8
Zhao Qiang82cd8c62017-05-25 09:47:40 +08009#include <malloc.h>
Timur Tabi6d838da2008-01-07 13:31:19 -060010#include <command.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060011#include <asm/global_data.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090012#include <linux/errno.h>
Masahiro Yamadaadae2ec2016-09-21 11:28:53 +090013#include <asm/io.h>
14#include <linux/immap_qe.h>
Qianyu Gongae6a7582016-02-18 13:01:59 +080015#include <fsl_qe.h>
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +000016#include <mmc.h>
Simon Glass48b6c6b2019-11-14 12:57:16 -070017#include <u-boot/crc.h>
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +000018
York Sunc4f047c2017-03-27 11:41:03 -070019#ifdef CONFIG_ARCH_LS1021A
Zhao Qiangdf412c62014-12-15 15:50:49 +080020#include <asm/arch/immap_ls102xa.h>
21#endif
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +000022#ifdef CONFIG_ARM64
23#include <asm/armv8/mmu.h>
24#include <asm/arch/cpu.h>
Zhao Qiang82cd8c62017-05-25 09:47:40 +080025#endif
26
Zhao Qiangb59534d2014-04-30 16:45:31 +080027#define MPC85xx_DEVDISR_QE_DISABLE 0x1
28
Heiko Schocherbaf84a92020-05-25 07:27:26 +020029qe_map_t *qe_immr;
Zhao Qiang3ae22202016-02-05 10:04:16 +080030#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -060031static qe_snum_t snums[QE_NUM_OF_SNUM];
Zhao Qiang3ae22202016-02-05 10:04:16 +080032#endif
Dave Liue732e9c2006-11-03 12:11:15 -060033
Wolfgang Denkd112a2c2007-09-15 20:48:41 +020034DECLARE_GLOBAL_DATA_PTR;
35
Dave Liue732e9c2006-11-03 12:11:15 -060036void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
37{
Wolfgang Denk545b06a2008-01-10 00:55:14 +010038 u32 cecr;
Dave Liue732e9c2006-11-03 12:11:15 -060039
40 if (cmd == QE_RESET) {
Heiko Schocherbaf84a92020-05-25 07:27:26 +020041 out_be32(&qe_immr->cp.cecr, (u32)(cmd | QE_CR_FLG));
Dave Liue732e9c2006-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 Schocherbaf84a92020-05-25 07:27:26 +020045 ((u32)mcn << QE_CR_PROTOCOL_SHIFT) | cmd));
Dave Liue732e9c2006-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 Liue732e9c2006-11-03 12:11:15 -060051}
52
Zhao Qiang5ad93952014-09-25 13:52:25 +080053#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -060054uint qe_muram_alloc(uint size, uint align)
55{
Dave Liue732e9c2006-11-03 12:11:15 -060056 uint retloc;
57 uint align_mask, off;
58 uint savebase;
59
60 align_mask = align - 1;
Simon Glass8518b172012-12-13 20:48:50 +000061 savebase = gd->arch.mp_alloc_base;
Dave Liue732e9c2006-11-03 12:11:15 -060062
Simon Glass8518b172012-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 Liue732e9c2006-11-03 12:11:15 -060066
Heiko Schocherbaf84a92020-05-25 07:27:26 +020067 off = size & align_mask;
68 if (off != 0)
Dave Liue732e9c2006-11-03 12:11:15 -060069 size += (align - off);
70
Simon Glass8518b172012-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 Schocherbaf84a92020-05-25 07:27:26 +020073 printf("%s: ran out of ram.\n", __func__);
Dave Liue732e9c2006-11-03 12:11:15 -060074 }
75
Simon Glass8518b172012-12-13 20:48:50 +000076 retloc = gd->arch.mp_alloc_base;
77 gd->arch.mp_alloc_base += size;
Dave Liue732e9c2006-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 Qiang5ad93952014-09-25 13:52:25 +080085#endif
Dave Liue732e9c2006-11-03 12:11:15 -060086
87void *qe_muram_addr(uint offset)
88{
89 return (void *)&qe_immr->muram[offset];
90}
91
Zhao Qiang3ae22202016-02-05 10:04:16 +080092#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -060093static void qe_sdma_init(void)
94{
Heiko Schocherbaf84a92020-05-25 07:27:26 +020095 sdma_t *p;
96 uint sdma_buffer_base;
Dave Liue732e9c2006-11-03 12:11:15 -060097
Heiko Schocherbaf84a92020-05-25 07:27:26 +020098 p = (sdma_t *)&qe_immr->sdma;
Dave Liue732e9c2006-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 Liu11da1752007-06-25 10:41:04 +0800105 sdma_buffer_base = qe_muram_alloc(2048, 4096);
Dave Liue732e9c2006-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 Wang0eea38e2009-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 Falautofe201cb2012-10-10 22:13:08 +0000120/* Evthreads 16-29 are not supported in MPC8309 */
Dave Liue732e9c2006-11-03 12:11:15 -0600121 0x04, 0x05, 0x0c, 0x0d,
122 0x14, 0x15, 0x1c, 0x1d,
123 0x24, 0x25, 0x2c, 0x2d,
Gerlando Falautofe201cb2012-10-10 22:13:08 +0000124 0x34, 0x35,
Gerlando Falautofe201cb2012-10-10 22:13:08 +0000125 0x88, 0x89, 0x98, 0x99,
126 0xa8, 0xa9, 0xb8, 0xb9,
127 0xc8, 0xc9, 0xd8, 0xd9,
128 0xe8, 0xe9, 0x08, 0x09,
129 0x18, 0x19, 0x28, 0x29,
130 0x38, 0x39, 0x48, 0x49,
131 0x58, 0x59, 0x68, 0x69,
132 0x78, 0x79, 0x80, 0x81
Dave Liue732e9c2006-11-03 12:11:15 -0600133};
134
135static void qe_snums_init(void)
136{
137 int i;
138
139 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
140 snums[i].state = QE_SNUM_STATE_FREE;
141 snums[i].num = thread_snum[i];
142 }
143}
144
145int qe_get_snum(void)
146{
147 int snum = -EBUSY;
148 int i;
149
150 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
151 if (snums[i].state == QE_SNUM_STATE_FREE) {
152 snums[i].state = QE_SNUM_STATE_USED;
153 snum = snums[i].num;
154 break;
155 }
156 }
157
158 return snum;
159}
160
161void qe_put_snum(u8 snum)
162{
163 int i;
164
165 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
166 if (snums[i].num == snum) {
167 snums[i].state = QE_SNUM_STATE_FREE;
168 break;
169 }
170 }
171}
172
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000173#ifdef CONFIG_TFABOOT
174void qe_init(uint qe_base)
175{
176 enum boot_src src = get_boot_src();
177
178 /* Init the QE IMMR base */
179 qe_immr = (qe_map_t *)qe_base;
180
181 if (src == BOOT_SOURCE_IFC_NOR) {
182 /*
183 * Upload microcode to IRAM for those SOCs
184 * which do not have ROM in QE.
185 */
186 qe_upload_firmware((const void *)(CONFIG_SYS_QE_FW_ADDR +
Tom Rini364d0022023-01-10 11:19:45 -0500187 CFG_SYS_FSL_IFC_BASE));
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000188
189 /* enable the microcode in IRAM */
190 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
191 }
192
193 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
194 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
195
196 qe_sdma_init();
197 qe_snums_init();
198}
199#else
Dave Liue732e9c2006-11-03 12:11:15 -0600200void qe_init(uint qe_base)
201{
Dave Liue732e9c2006-11-03 12:11:15 -0600202 /* Init the QE IMMR base */
203 qe_immr = (qe_map_t *)qe_base;
204
Timur Tabi275f4bb2011-11-22 09:21:25 -0600205#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
Wolfgang Denke366f152009-04-05 00:27:57 +0200206 /*
207 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
208 */
Zhao Qiang83a90842014-03-21 16:21:44 +0800209 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Haiying Wangec9d36c2009-03-26 17:01:49 -0400210
Wolfgang Denke366f152009-04-05 00:27:57 +0200211 /* enable the microcode in IRAM */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200212 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Haiying Wangec9d36c2009-03-26 17:01:49 -0400213#endif
214
Simon Glass8518b172012-12-13 20:48:50 +0000215 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
216 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
Dave Liue732e9c2006-11-03 12:11:15 -0600217
218 qe_sdma_init();
219 qe_snums_init();
220}
Zhao Qiang3ae22202016-02-05 10:04:16 +0800221#endif
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000222#endif
Dave Liue732e9c2006-11-03 12:11:15 -0600223
Zhao Qiang5ad93952014-09-25 13:52:25 +0800224#ifdef CONFIG_U_QE
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000225#ifdef CONFIG_TFABOOT
Zhao Qiang5ad93952014-09-25 13:52:25 +0800226void u_qe_init(void)
227{
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000228 enum boot_src src = get_boot_src();
229
Zhao Qiang0be9be82016-02-05 10:04:17 +0800230 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiang5ad93952014-09-25 13:52:25 +0800231
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800232 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000233
234 if (src == BOOT_SOURCE_IFC_NOR)
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200235 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
Tom Rini364d0022023-01-10 11:19:45 -0500236 CFG_SYS_FSL_IFC_BASE);
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000237
238 if (src == BOOT_SOURCE_QSPI_NOR)
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200239 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
Tom Rini376b88a2022-10-28 20:27:13 -0400240 CFG_SYS_FSL_QSPI_BASE);
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000241
242 if (src == BOOT_SOURCE_SD_MMC) {
243 int dev = CONFIG_SYS_MMC_ENV_DEV;
244 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
245 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
246
247 if (mmc_initialize(gd->bd)) {
248 printf("%s: mmc_initialize() failed\n", __func__);
249 return;
250 }
251 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
252 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
253
254 if (!mmc) {
255 free(addr);
256 printf("\nMMC cannot find device for ucode\n");
257 } else {
258 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
259 dev, blk, cnt);
260 mmc_init(mmc);
261 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
262 addr);
263 }
264 }
265 if (!u_qe_upload_firmware(addr))
266 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
267 if (src == BOOT_SOURCE_SD_MMC)
268 free(addr);
269}
270#else
271void u_qe_init(void)
272{
273 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
274
275 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800276#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
277 int dev = CONFIG_SYS_MMC_ENV_DEV;
278 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
279 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
280
281 if (mmc_initialize(gd->bd)) {
282 printf("%s: mmc_initialize() failed\n", __func__);
283 return;
284 }
285 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
286 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
287
288 if (!mmc) {
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800289 printf("\nMMC cannot find device for ucode\n");
290 } else {
291 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
292 dev, blk, cnt);
293 mmc_init(mmc);
Yinbo Zhu45c20bd2018-09-25 14:47:06 +0800294 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800295 addr);
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800296 }
297#endif
Zhao Qiang10640212017-08-14 10:22:43 +0800298 if (!u_qe_upload_firmware(addr))
299 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800300#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
301 free(addr);
302#endif
Zhao Qiang5ad93952014-09-25 13:52:25 +0800303}
304#endif
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000305#endif
Zhao Qiang5ad93952014-09-25 13:52:25 +0800306
Zhao Qiangcfd76712015-03-25 17:02:59 +0800307#ifdef CONFIG_U_QE
308void u_qe_resume(void)
309{
310 qe_map_t *qe_immrr;
Zhao Qiangcfd76712015-03-25 17:02:59 +0800311
Zhao Qiang0be9be82016-02-05 10:04:17 +0800312 qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiangcfd76712015-03-25 17:02:59 +0800313 u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr);
314 out_be32(&qe_immrr->iram.iready, QE_IRAM_READY);
315}
316#endif
317
Dave Liue732e9c2006-11-03 12:11:15 -0600318void qe_reset(void)
319{
320 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200321 (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
Dave Liue732e9c2006-11-03 12:11:15 -0600322}
323
Zhao Qiang3ae22202016-02-05 10:04:16 +0800324#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -0600325void qe_assign_page(uint snum, uint para_ram_base)
326{
327 u32 cecr;
328
329 out_be32(&qe_immr->cp.cecdr, para_ram_base);
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200330 out_be32(&qe_immr->cp.cecr, ((u32)snum << QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
Dave Liue732e9c2006-11-03 12:11:15 -0600331 | QE_CR_FLG | QE_ASSIGN_PAGE);
332
333 /* Wait for the QE_CR_FLG to clear */
334 do {
335 cecr = in_be32(&qe_immr->cp.cecr);
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200336 } while (cecr & QE_CR_FLG);
Dave Liue732e9c2006-11-03 12:11:15 -0600337}
Zhao Qiang3ae22202016-02-05 10:04:16 +0800338#endif
Dave Liue732e9c2006-11-03 12:11:15 -0600339
340/*
341 * brg: 0~15 as BRG1~BRG16
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200342 * rate: baud rate
Dave Liue732e9c2006-11-03 12:11:15 -0600343 * BRG input clock comes from the BRGCLK (internal clock generated from
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200344 * the QE clock, it is one-half of the QE clock), If need the clock source
345 * from CLKn pin, we have te change the function.
Dave Liue732e9c2006-11-03 12:11:15 -0600346 */
347
Simon Glass34a194f2012-12-13 20:48:44 +0000348#define BRG_CLK (gd->arch.brg_clk)
Dave Liue732e9c2006-11-03 12:11:15 -0600349
Zhao Qiang5ad93952014-09-25 13:52:25 +0800350#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -0600351int qe_set_brg(uint brg, uint rate)
352{
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200353 uint *bp;
354 u32 divisor;
355 u32 val;
356 int div16 = 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600357
358 if (brg >= QE_NUM_OF_BRGS)
359 return -EINVAL;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200360
Dave Liue732e9c2006-11-03 12:11:15 -0600361 bp = (uint *)&qe_immr->brg.brgc1;
362 bp += brg;
363
364 divisor = (BRG_CLK / rate);
365 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
366 div16 = 1;
367 divisor /= 16;
368 }
369
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200370 /* CHECK TODO */
371 /*
372 * was
373 * *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
374 * __asm__ __volatile__("sync");
375 */
Dave Liue732e9c2006-11-03 12:11:15 -0600376
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200377 val = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
378 if (div16)
379 val |= QE_BRGC_DIV16;
380
381 out_be32(bp, val);
Dave Liue732e9c2006-11-03 12:11:15 -0600382
383 return 0;
384}
Zhao Qiang5ad93952014-09-25 13:52:25 +0800385#endif
Dave Liue732e9c2006-11-03 12:11:15 -0600386
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200387/* Set ethernet MII clock master */
Dave Liue732e9c2006-11-03 12:11:15 -0600388int qe_set_mii_clk_src(int ucc_num)
389{
390 u32 cmxgcr;
391
392 /* check if the UCC number is in range. */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200393 if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) {
394 printf("%s: ucc num not in ranges\n", __func__);
Dave Liue732e9c2006-11-03 12:11:15 -0600395 return -EINVAL;
396 }
397
398 cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
399 cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200400 cmxgcr |= (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
Dave Liue732e9c2006-11-03 12:11:15 -0600401 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
402
403 return 0;
404}
405
Timur Tabi6d838da2008-01-07 13:31:19 -0600406/* Firmware information stored here for qe_get_firmware_info() */
407static struct qe_firmware_info qe_firmware_info;
408
409/*
410 * Set to 1 if QE firmware has been uploaded, and therefore
411 * qe_firmware_info contains valid data.
412 */
413static int qe_firmware_uploaded;
414
415/*
416 * Upload a QE microcode
417 *
418 * This function is a worker function for qe_upload_firmware(). It does
419 * the actual uploading of the microcode.
420 */
421static void qe_upload_microcode(const void *base,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200422 const struct qe_microcode *ucode)
Timur Tabi6d838da2008-01-07 13:31:19 -0600423{
424 const u32 *code = base + be32_to_cpu(ucode->code_offset);
425 unsigned int i;
426
427 if (ucode->major || ucode->minor || ucode->revision)
428 printf("QE: uploading microcode '%s' version %u.%u.%u\n",
Zhao Qiang7879a492015-05-05 15:53:32 +0800429 (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
430 (u16)ucode->revision);
Timur Tabi6d838da2008-01-07 13:31:19 -0600431 else
Zhao Qiang7879a492015-05-05 15:53:32 +0800432 printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
Timur Tabi6d838da2008-01-07 13:31:19 -0600433
434 /* Use auto-increment */
435 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
436 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
437
438 for (i = 0; i < be32_to_cpu(ucode->count); i++)
439 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
440}
441
442/*
443 * Upload a microcode to the I-RAM at a specific address.
444 *
Heinrich Schuchardtb0289282020-04-19 09:19:04 +0200445 * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for
446 * information on QE microcode uploading.
Timur Tabi6d838da2008-01-07 13:31:19 -0600447 *
448 * Currently, only version 1 is supported, so the 'version' field must be
449 * set to 1.
450 *
451 * The SOC model and revision are not validated, they are only displayed for
452 * informational purposes.
453 *
454 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
455 * all of the microcode structures, minus the CRC.
456 *
457 * 'length' is the size that the structure says it is, including the CRC.
458 */
459int qe_upload_firmware(const struct qe_firmware *firmware)
460{
461 unsigned int i;
462 unsigned int j;
463 u32 crc;
464 size_t calc_size = sizeof(struct qe_firmware);
465 size_t length;
466 const struct qe_header *hdr;
Zhao Qiangb59534d2014-04-30 16:45:31 +0800467#ifdef CONFIG_DEEP_SLEEP
York Sunc4f047c2017-03-27 11:41:03 -0700468#ifdef CONFIG_ARCH_LS1021A
Tom Rini376b88a2022-10-28 20:27:13 -0400469 struct ccsr_gur __iomem *gur = (void *)CFG_SYS_FSL_GUTS_ADDR;
Zhao Qiangdf412c62014-12-15 15:50:49 +0800470#else
Tom Rinid5c3bf22022-10-28 20:27:12 -0400471 ccsr_gur_t *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
Zhao Qiangb59534d2014-04-30 16:45:31 +0800472#endif
Zhao Qiangdf412c62014-12-15 15:50:49 +0800473#endif
Timur Tabi6d838da2008-01-07 13:31:19 -0600474 if (!firmware) {
475 printf("Invalid address\n");
476 return -EINVAL;
477 }
478
479 hdr = &firmware->header;
480 length = be32_to_cpu(hdr->length);
481
482 /* Check the magic */
483 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
484 (hdr->magic[2] != 'F')) {
Vijay Raia4792292014-07-23 18:33:16 +0530485 printf("QE microcode not found\n");
Zhao Qiangb59534d2014-04-30 16:45:31 +0800486#ifdef CONFIG_DEEP_SLEEP
487 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
488#endif
Timur Tabi6d838da2008-01-07 13:31:19 -0600489 return -EPERM;
490 }
491
492 /* Check the version */
493 if (hdr->version != 1) {
494 printf("Unsupported version\n");
495 return -EPERM;
496 }
497
498 /* Validate some of the fields */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200499 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
Timur Tabi6d838da2008-01-07 13:31:19 -0600500 printf("Invalid data\n");
501 return -EINVAL;
502 }
503
504 /* Validate the length and check if there's a CRC */
505 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
506
507 for (i = 0; i < firmware->count; i++)
508 /*
509 * For situations where the second RISC uses the same microcode
510 * as the first, the 'code_offset' and 'count' fields will be
511 * zero, so it's okay to add those.
512 */
513 calc_size += sizeof(u32) *
514 be32_to_cpu(firmware->microcode[i].count);
515
516 /* Validate the length */
517 if (length != calc_size + sizeof(u32)) {
518 printf("Invalid length\n");
519 return -EPERM;
520 }
521
Wolfgang Denk545b06a2008-01-10 00:55:14 +0100522 /*
523 * Validate the CRC. We would normally call crc32_no_comp(), but that
524 * function isn't available unless you turn on JFFS support.
525 */
Timur Tabi6d838da2008-01-07 13:31:19 -0600526 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200527 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
Timur Tabi6d838da2008-01-07 13:31:19 -0600528 printf("Firmware CRC is invalid\n");
529 return -EIO;
530 }
531
532 /*
533 * If the microcode calls for it, split the I-RAM.
534 */
535 if (!firmware->split) {
536 out_be16(&qe_immr->cp.cercr,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200537 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
Timur Tabi6d838da2008-01-07 13:31:19 -0600538 }
539
540 if (firmware->soc.model)
541 printf("Firmware '%s' for %u V%u.%u\n",
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200542 firmware->id, be16_to_cpu(firmware->soc.model),
Timur Tabi6d838da2008-01-07 13:31:19 -0600543 firmware->soc.major, firmware->soc.minor);
544 else
545 printf("Firmware '%s'\n", firmware->id);
546
547 /*
548 * The QE only supports one microcode per RISC, so clear out all the
549 * saved microcode information and put in the new.
550 */
551 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Zhao Qiangd64f1a42015-05-05 15:53:33 +0800552 strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
Timur Tabi6d838da2008-01-07 13:31:19 -0600553 qe_firmware_info.extended_modes = firmware->extended_modes;
554 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200555 sizeof(firmware->vtraps));
Timur Tabi6d838da2008-01-07 13:31:19 -0600556 qe_firmware_uploaded = 1;
557
558 /* Loop through each microcode. */
559 for (i = 0; i < firmware->count; i++) {
560 const struct qe_microcode *ucode = &firmware->microcode[i];
561
562 /* Upload a microcode if it's present */
563 if (ucode->code_offset)
564 qe_upload_microcode(firmware, ucode);
565
566 /* Program the traps for this processor */
567 for (j = 0; j < 16; j++) {
568 u32 trap = be32_to_cpu(ucode->traps[j]);
569
570 if (trap)
571 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
572 }
573
574 /* Enable traps */
575 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
576 }
577
578 return 0;
579}
580
Zhao Qianga985f822014-11-04 13:46:16 +0800581#ifdef CONFIG_U_QE
582/*
583 * Upload a microcode to the I-RAM at a specific address.
584 *
Heinrich Schuchardtb0289282020-04-19 09:19:04 +0200585 * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for
586 * information on QE microcode uploading.
Zhao Qianga985f822014-11-04 13:46:16 +0800587 *
588 * Currently, only version 1 is supported, so the 'version' field must be
589 * set to 1.
590 *
591 * The SOC model and revision are not validated, they are only displayed for
592 * informational purposes.
593 *
594 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
595 * all of the microcode structures, minus the CRC.
596 *
597 * 'length' is the size that the structure says it is, including the CRC.
598 */
599int u_qe_upload_firmware(const struct qe_firmware *firmware)
600{
601 unsigned int i;
602 unsigned int j;
603 u32 crc;
604 size_t calc_size = sizeof(struct qe_firmware);
605 size_t length;
606 const struct qe_header *hdr;
607#ifdef CONFIG_DEEP_SLEEP
York Sunc4f047c2017-03-27 11:41:03 -0700608#ifdef CONFIG_ARCH_LS1021A
Tom Rini376b88a2022-10-28 20:27:13 -0400609 struct ccsr_gur __iomem *gur = (void *)CFG_SYS_FSL_GUTS_ADDR;
Zhao Qiangdf412c62014-12-15 15:50:49 +0800610#else
Tom Rinid5c3bf22022-10-28 20:27:12 -0400611 ccsr_gur_t __iomem *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
Zhao Qianga985f822014-11-04 13:46:16 +0800612#endif
Zhao Qiangdf412c62014-12-15 15:50:49 +0800613#endif
Zhao Qianga985f822014-11-04 13:46:16 +0800614 if (!firmware) {
615 printf("Invalid address\n");
616 return -EINVAL;
617 }
618
619 hdr = &firmware->header;
620 length = be32_to_cpu(hdr->length);
621
622 /* Check the magic */
623 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
624 (hdr->magic[2] != 'F')) {
625 printf("Not a microcode\n");
626#ifdef CONFIG_DEEP_SLEEP
627 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
628#endif
629 return -EPERM;
630 }
631
632 /* Check the version */
633 if (hdr->version != 1) {
634 printf("Unsupported version\n");
635 return -EPERM;
636 }
637
638 /* Validate some of the fields */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200639 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
Zhao Qianga985f822014-11-04 13:46:16 +0800640 printf("Invalid data\n");
641 return -EINVAL;
642 }
643
644 /* Validate the length and check if there's a CRC */
645 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
646
647 for (i = 0; i < firmware->count; i++)
648 /*
649 * For situations where the second RISC uses the same microcode
650 * as the first, the 'code_offset' and 'count' fields will be
651 * zero, so it's okay to add those.
652 */
653 calc_size += sizeof(u32) *
654 be32_to_cpu(firmware->microcode[i].count);
655
656 /* Validate the length */
657 if (length != calc_size + sizeof(u32)) {
658 printf("Invalid length\n");
659 return -EPERM;
660 }
661
662 /*
663 * Validate the CRC. We would normally call crc32_no_comp(), but that
664 * function isn't available unless you turn on JFFS support.
665 */
666 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
667 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
668 printf("Firmware CRC is invalid\n");
669 return -EIO;
670 }
671
672 /*
673 * If the microcode calls for it, split the I-RAM.
674 */
675 if (!firmware->split) {
676 out_be16(&qe_immr->cp.cercr,
677 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
678 }
679
680 if (firmware->soc.model)
681 printf("Firmware '%s' for %u V%u.%u\n",
682 firmware->id, be16_to_cpu(firmware->soc.model),
683 firmware->soc.major, firmware->soc.minor);
684 else
685 printf("Firmware '%s'\n", firmware->id);
686
687 /* Loop through each microcode. */
688 for (i = 0; i < firmware->count; i++) {
689 const struct qe_microcode *ucode = &firmware->microcode[i];
690
691 /* Upload a microcode if it's present */
692 if (ucode->code_offset)
693 qe_upload_microcode(firmware, ucode);
694
695 /* Program the traps for this processor */
696 for (j = 0; j < 16; j++) {
697 u32 trap = be32_to_cpu(ucode->traps[j]);
698
699 if (trap)
700 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
701 }
702
703 /* Enable traps */
704 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
705 }
706
707 return 0;
708}
709#endif
710
Zhao Qiangcfd76712015-03-25 17:02:59 +0800711#ifdef CONFIG_U_QE
712int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
713{
714 unsigned int i;
715 unsigned int j;
716 const struct qe_header *hdr;
717 const u32 *code;
718#ifdef CONFIG_DEEP_SLEEP
719#ifdef CONFIG_PPC
Tom Rinid5c3bf22022-10-28 20:27:12 -0400720 ccsr_gur_t __iomem *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
Zhao Qiangcfd76712015-03-25 17:02:59 +0800721#else
Tom Rini376b88a2022-10-28 20:27:13 -0400722 struct ccsr_gur __iomem *gur = (void *)CFG_SYS_FSL_GUTS_ADDR;
Zhao Qiangcfd76712015-03-25 17:02:59 +0800723#endif
724#endif
725
726 if (!firmware)
727 return -EINVAL;
728
729 hdr = &firmware->header;
730
731 /* Check the magic */
732 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
733 (hdr->magic[2] != 'F')) {
734#ifdef CONFIG_DEEP_SLEEP
735 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
736#endif
737 return -EPERM;
738 }
739
740 /*
741 * If the microcode calls for it, split the I-RAM.
742 */
743 if (!firmware->split) {
744 out_be16(&qe_immrr->cp.cercr,
745 in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
746 }
747
748 /* Loop through each microcode. */
749 for (i = 0; i < firmware->count; i++) {
750 const struct qe_microcode *ucode = &firmware->microcode[i];
751
752 /* Upload a microcode if it's present */
753 if (!ucode->code_offset)
754 return 0;
755
756 code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
757
758 /* Use auto-increment */
759 out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
760 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
761
762 for (i = 0; i < be32_to_cpu(ucode->count); i++)
763 out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
764
765 /* Program the traps for this processor */
766 for (j = 0; j < 16; j++) {
767 u32 trap = be32_to_cpu(ucode->traps[j]);
768
769 if (trap)
770 out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
771 }
772
773 /* Enable traps */
774 out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
775 }
776
777 return 0;
778}
779#endif
780
Timur Tabi6d838da2008-01-07 13:31:19 -0600781struct qe_firmware_info *qe_get_firmware_info(void)
782{
783 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
784}
785
Simon Glassed38aef2020-05-10 11:40:03 -0600786static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Timur Tabi6d838da2008-01-07 13:31:19 -0600787{
788 ulong addr;
789
Wolfgang Denk3b683112010-07-17 01:06:04 +0200790 if (argc < 3)
791 return cmd_usage(cmdtp);
Timur Tabi6d838da2008-01-07 13:31:19 -0600792
793 if (strcmp(argv[1], "fw") == 0) {
Simon Glass3ff49ec2021-07-24 09:03:29 -0600794 addr = hextoul(argv[2], NULL);
Timur Tabi6d838da2008-01-07 13:31:19 -0600795
796 if (!addr) {
797 printf("Invalid address\n");
798 return -EINVAL;
799 }
800
Wolfgang Denk545b06a2008-01-10 00:55:14 +0100801 /*
802 * If a length was supplied, compare that with the 'length'
803 * field.
804 */
Timur Tabi6d838da2008-01-07 13:31:19 -0600805
806 if (argc > 3) {
Simon Glass3ff49ec2021-07-24 09:03:29 -0600807 ulong length = hextoul(argv[3], NULL);
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200808 struct qe_firmware *firmware = (void *)addr;
Timur Tabi6d838da2008-01-07 13:31:19 -0600809
810 if (length != be32_to_cpu(firmware->header.length)) {
811 printf("Length mismatch\n");
812 return -EINVAL;
813 }
814 }
815
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200816 return qe_upload_firmware((const struct qe_firmware *)addr);
Timur Tabi6d838da2008-01-07 13:31:19 -0600817 }
818
Wolfgang Denk3b683112010-07-17 01:06:04 +0200819 return cmd_usage(cmdtp);
Timur Tabi6d838da2008-01-07 13:31:19 -0600820}
821
822U_BOOT_CMD(
823 qe, 4, 0, qe_cmd,
Peter Tyserdfb72b82009-01-27 18:03:12 -0600824 "QUICC Engine commands",
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200825 "fw <addr> [<length>] - Upload firmware binary at address <addr> to the QE,\n"
Wolfgang Denkc54781c2009-05-24 17:06:54 +0200826 "\twith optional length <length> verification."
827);