blob: 2825dc6f9aa6c4e630e85e0842207d2ef6fc4a9f [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
Masahiro Yamadaadae2ec2016-09-21 11:28:53 +09009#include <common.h>
Zhao Qiang82cd8c62017-05-25 09:47:40 +080010#include <malloc.h>
Timur Tabi6d838da2008-01-07 13:31:19 -060011#include <command.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060012#include <asm/global_data.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090013#include <linux/errno.h>
Masahiro Yamadaadae2ec2016-09-21 11:28:53 +090014#include <asm/io.h>
15#include <linux/immap_qe.h>
Qianyu Gongae6a7582016-02-18 13:01:59 +080016#include <fsl_qe.h>
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +000017#include <mmc.h>
Simon Glass48b6c6b2019-11-14 12:57:16 -070018#include <u-boot/crc.h>
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +000019
York Sunc4f047c2017-03-27 11:41:03 -070020#ifdef CONFIG_ARCH_LS1021A
Zhao Qiangdf412c62014-12-15 15:50:49 +080021#include <asm/arch/immap_ls102xa.h>
22#endif
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +000023#ifdef CONFIG_ARM64
24#include <asm/armv8/mmu.h>
25#include <asm/arch/cpu.h>
Zhao Qiang82cd8c62017-05-25 09:47:40 +080026#endif
27
Zhao Qiangb59534d2014-04-30 16:45:31 +080028#define MPC85xx_DEVDISR_QE_DISABLE 0x1
29
Heiko Schocherbaf84a92020-05-25 07:27:26 +020030qe_map_t *qe_immr;
Zhao Qiang3ae22202016-02-05 10:04:16 +080031#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -060032static qe_snum_t snums[QE_NUM_OF_SNUM];
Zhao Qiang3ae22202016-02-05 10:04:16 +080033#endif
Dave Liue732e9c2006-11-03 12:11:15 -060034
Wolfgang Denkd112a2c2007-09-15 20:48:41 +020035DECLARE_GLOBAL_DATA_PTR;
36
Dave Liue732e9c2006-11-03 12:11:15 -060037void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
38{
Wolfgang Denk545b06a2008-01-10 00:55:14 +010039 u32 cecr;
Dave Liue732e9c2006-11-03 12:11:15 -060040
41 if (cmd == QE_RESET) {
Heiko Schocherbaf84a92020-05-25 07:27:26 +020042 out_be32(&qe_immr->cp.cecr, (u32)(cmd | QE_CR_FLG));
Dave Liue732e9c2006-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 Schocherbaf84a92020-05-25 07:27:26 +020046 ((u32)mcn << QE_CR_PROTOCOL_SHIFT) | cmd));
Dave Liue732e9c2006-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 Liue732e9c2006-11-03 12:11:15 -060052}
53
Zhao Qiang5ad93952014-09-25 13:52:25 +080054#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -060055uint qe_muram_alloc(uint size, uint align)
56{
Dave Liue732e9c2006-11-03 12:11:15 -060057 uint retloc;
58 uint align_mask, off;
59 uint savebase;
60
61 align_mask = align - 1;
Simon Glass8518b172012-12-13 20:48:50 +000062 savebase = gd->arch.mp_alloc_base;
Dave Liue732e9c2006-11-03 12:11:15 -060063
Simon Glass8518b172012-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 Liue732e9c2006-11-03 12:11:15 -060067
Heiko Schocherbaf84a92020-05-25 07:27:26 +020068 off = size & align_mask;
69 if (off != 0)
Dave Liue732e9c2006-11-03 12:11:15 -060070 size += (align - off);
71
Simon Glass8518b172012-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 Schocherbaf84a92020-05-25 07:27:26 +020074 printf("%s: ran out of ram.\n", __func__);
Dave Liue732e9c2006-11-03 12:11:15 -060075 }
76
Simon Glass8518b172012-12-13 20:48:50 +000077 retloc = gd->arch.mp_alloc_base;
78 gd->arch.mp_alloc_base += size;
Dave Liue732e9c2006-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 Qiang5ad93952014-09-25 13:52:25 +080086#endif
Dave Liue732e9c2006-11-03 12:11:15 -060087
88void *qe_muram_addr(uint offset)
89{
90 return (void *)&qe_immr->muram[offset];
91}
92
Zhao Qiang3ae22202016-02-05 10:04:16 +080093#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -060094static void qe_sdma_init(void)
95{
Heiko Schocherbaf84a92020-05-25 07:27:26 +020096 sdma_t *p;
97 uint sdma_buffer_base;
Dave Liue732e9c2006-11-03 12:11:15 -060098
Heiko Schocherbaf84a92020-05-25 07:27:26 +020099 p = (sdma_t *)&qe_immr->sdma;
Dave Liue732e9c2006-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 Liu11da1752007-06-25 10:41:04 +0800106 sdma_buffer_base = qe_muram_alloc(2048, 4096);
Dave Liue732e9c2006-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 Wang0eea38e2009-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 Falautofe201cb2012-10-10 22:13:08 +0000121/* Evthreads 16-29 are not supported in MPC8309 */
Dave Liue732e9c2006-11-03 12:11:15 -0600122 0x04, 0x05, 0x0c, 0x0d,
123 0x14, 0x15, 0x1c, 0x1d,
124 0x24, 0x25, 0x2c, 0x2d,
Gerlando Falautofe201cb2012-10-10 22:13:08 +0000125 0x34, 0x35,
Gerlando Falautofe201cb2012-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 Liue732e9c2006-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 Bhagat4fb459e2018-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 Rini364d0022023-01-10 11:19:45 -0500188 CFG_SYS_FSL_IFC_BASE));
Rajesh Bhagat4fb459e2018-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 Liue732e9c2006-11-03 12:11:15 -0600201void qe_init(uint qe_base)
202{
Dave Liue732e9c2006-11-03 12:11:15 -0600203 /* Init the QE IMMR base */
204 qe_immr = (qe_map_t *)qe_base;
205
Timur Tabi275f4bb2011-11-22 09:21:25 -0600206#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
Wolfgang Denke366f152009-04-05 00:27:57 +0200207 /*
208 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
209 */
Zhao Qiang83a90842014-03-21 16:21:44 +0800210 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Haiying Wangec9d36c2009-03-26 17:01:49 -0400211
Wolfgang Denke366f152009-04-05 00:27:57 +0200212 /* enable the microcode in IRAM */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200213 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Haiying Wangec9d36c2009-03-26 17:01:49 -0400214#endif
215
Simon Glass8518b172012-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 Liue732e9c2006-11-03 12:11:15 -0600218
219 qe_sdma_init();
220 qe_snums_init();
221}
Zhao Qiang3ae22202016-02-05 10:04:16 +0800222#endif
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000223#endif
Dave Liue732e9c2006-11-03 12:11:15 -0600224
Zhao Qiang5ad93952014-09-25 13:52:25 +0800225#ifdef CONFIG_U_QE
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000226#ifdef CONFIG_TFABOOT
Zhao Qiang5ad93952014-09-25 13:52:25 +0800227void u_qe_init(void)
228{
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000229 enum boot_src src = get_boot_src();
230
Zhao Qiang0be9be82016-02-05 10:04:17 +0800231 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiang5ad93952014-09-25 13:52:25 +0800232
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800233 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000234
235 if (src == BOOT_SOURCE_IFC_NOR)
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200236 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
Tom Rini364d0022023-01-10 11:19:45 -0500237 CFG_SYS_FSL_IFC_BASE);
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000238
239 if (src == BOOT_SOURCE_QSPI_NOR)
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200240 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
Tom Rini376b88a2022-10-28 20:27:13 -0400241 CFG_SYS_FSL_QSPI_BASE);
Rajesh Bhagat4fb459e2018-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
272void u_qe_init(void)
273{
274 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
275
276 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800277#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 Qiang82cd8c62017-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 Zhu45c20bd2018-09-25 14:47:06 +0800295 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800296 addr);
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800297 }
298#endif
Zhao Qiang10640212017-08-14 10:22:43 +0800299 if (!u_qe_upload_firmware(addr))
300 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800301#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
302 free(addr);
303#endif
Zhao Qiang5ad93952014-09-25 13:52:25 +0800304}
305#endif
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000306#endif
Zhao Qiang5ad93952014-09-25 13:52:25 +0800307
Zhao Qiangcfd76712015-03-25 17:02:59 +0800308#ifdef CONFIG_U_QE
309void u_qe_resume(void)
310{
311 qe_map_t *qe_immrr;
Zhao Qiangcfd76712015-03-25 17:02:59 +0800312
Zhao Qiang0be9be82016-02-05 10:04:17 +0800313 qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiangcfd76712015-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 Liue732e9c2006-11-03 12:11:15 -0600319void qe_reset(void)
320{
321 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200322 (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
Dave Liue732e9c2006-11-03 12:11:15 -0600323}
324
Zhao Qiang3ae22202016-02-05 10:04:16 +0800325#ifdef CONFIG_QE
Dave Liue732e9c2006-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 Schocherbaf84a92020-05-25 07:27:26 +0200331 out_be32(&qe_immr->cp.cecr, ((u32)snum << QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
Dave Liue732e9c2006-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 Schocherbaf84a92020-05-25 07:27:26 +0200337 } while (cecr & QE_CR_FLG);
Dave Liue732e9c2006-11-03 12:11:15 -0600338}
Zhao Qiang3ae22202016-02-05 10:04:16 +0800339#endif
Dave Liue732e9c2006-11-03 12:11:15 -0600340
341/*
342 * brg: 0~15 as BRG1~BRG16
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200343 * rate: baud rate
Dave Liue732e9c2006-11-03 12:11:15 -0600344 * BRG input clock comes from the BRGCLK (internal clock generated from
Heiko Schocherbaf84a92020-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 Liue732e9c2006-11-03 12:11:15 -0600347 */
348
Simon Glass34a194f2012-12-13 20:48:44 +0000349#define BRG_CLK (gd->arch.brg_clk)
Dave Liue732e9c2006-11-03 12:11:15 -0600350
Zhao Qiang5ad93952014-09-25 13:52:25 +0800351#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -0600352int qe_set_brg(uint brg, uint rate)
353{
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200354 uint *bp;
355 u32 divisor;
356 u32 val;
357 int div16 = 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600358
359 if (brg >= QE_NUM_OF_BRGS)
360 return -EINVAL;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200361
Dave Liue732e9c2006-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 Schocherbaf84a92020-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 Liue732e9c2006-11-03 12:11:15 -0600377
Heiko Schocherbaf84a92020-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 Liue732e9c2006-11-03 12:11:15 -0600383
384 return 0;
385}
Zhao Qiang5ad93952014-09-25 13:52:25 +0800386#endif
Dave Liue732e9c2006-11-03 12:11:15 -0600387
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200388/* Set ethernet MII clock master */
Dave Liue732e9c2006-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 Schocherbaf84a92020-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 Liue732e9c2006-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 Schocherbaf84a92020-05-25 07:27:26 +0200401 cmxgcr |= (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
Dave Liue732e9c2006-11-03 12:11:15 -0600402 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
403
404 return 0;
405}
406
Timur Tabi6d838da2008-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 Schocherbaf84a92020-05-25 07:27:26 +0200423 const struct qe_microcode *ucode)
Timur Tabi6d838da2008-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 Qiang7879a492015-05-05 15:53:32 +0800430 (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
431 (u16)ucode->revision);
Timur Tabi6d838da2008-01-07 13:31:19 -0600432 else
Zhao Qiang7879a492015-05-05 15:53:32 +0800433 printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
Timur Tabi6d838da2008-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 Schuchardtb0289282020-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 Tabi6d838da2008-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 Qiangb59534d2014-04-30 16:45:31 +0800468#ifdef CONFIG_DEEP_SLEEP
York Sunc4f047c2017-03-27 11:41:03 -0700469#ifdef CONFIG_ARCH_LS1021A
Tom Rini376b88a2022-10-28 20:27:13 -0400470 struct ccsr_gur __iomem *gur = (void *)CFG_SYS_FSL_GUTS_ADDR;
Zhao Qiangdf412c62014-12-15 15:50:49 +0800471#else
Tom Rinid5c3bf22022-10-28 20:27:12 -0400472 ccsr_gur_t *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
Zhao Qiangb59534d2014-04-30 16:45:31 +0800473#endif
Zhao Qiangdf412c62014-12-15 15:50:49 +0800474#endif
Timur Tabi6d838da2008-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 Raia4792292014-07-23 18:33:16 +0530486 printf("QE microcode not found\n");
Zhao Qiangb59534d2014-04-30 16:45:31 +0800487#ifdef CONFIG_DEEP_SLEEP
488 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
489#endif
Timur Tabi6d838da2008-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 Schocherbaf84a92020-05-25 07:27:26 +0200500 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
Timur Tabi6d838da2008-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 Denk545b06a2008-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 Tabi6d838da2008-01-07 13:31:19 -0600527 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200528 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
Timur Tabi6d838da2008-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 Schocherbaf84a92020-05-25 07:27:26 +0200538 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
Timur Tabi6d838da2008-01-07 13:31:19 -0600539 }
540
541 if (firmware->soc.model)
542 printf("Firmware '%s' for %u V%u.%u\n",
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200543 firmware->id, be16_to_cpu(firmware->soc.model),
Timur Tabi6d838da2008-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 Qiangd64f1a42015-05-05 15:53:33 +0800553 strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
Timur Tabi6d838da2008-01-07 13:31:19 -0600554 qe_firmware_info.extended_modes = firmware->extended_modes;
555 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200556 sizeof(firmware->vtraps));
Timur Tabi6d838da2008-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 Qianga985f822014-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 Schuchardtb0289282020-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 Qianga985f822014-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 Sunc4f047c2017-03-27 11:41:03 -0700609#ifdef CONFIG_ARCH_LS1021A
Tom Rini376b88a2022-10-28 20:27:13 -0400610 struct ccsr_gur __iomem *gur = (void *)CFG_SYS_FSL_GUTS_ADDR;
Zhao Qiangdf412c62014-12-15 15:50:49 +0800611#else
Tom Rinid5c3bf22022-10-28 20:27:12 -0400612 ccsr_gur_t __iomem *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
Zhao Qianga985f822014-11-04 13:46:16 +0800613#endif
Zhao Qiangdf412c62014-12-15 15:50:49 +0800614#endif
Zhao Qianga985f822014-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 Schocherbaf84a92020-05-25 07:27:26 +0200640 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
Zhao Qianga985f822014-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 Qiangcfd76712015-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 Rinid5c3bf22022-10-28 20:27:12 -0400721 ccsr_gur_t __iomem *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
Zhao Qiangcfd76712015-03-25 17:02:59 +0800722#else
Tom Rini376b88a2022-10-28 20:27:13 -0400723 struct ccsr_gur __iomem *gur = (void *)CFG_SYS_FSL_GUTS_ADDR;
Zhao Qiangcfd76712015-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 Tabi6d838da2008-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 Glassed38aef2020-05-10 11:40:03 -0600787static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Timur Tabi6d838da2008-01-07 13:31:19 -0600788{
789 ulong addr;
790
Wolfgang Denk3b683112010-07-17 01:06:04 +0200791 if (argc < 3)
792 return cmd_usage(cmdtp);
Timur Tabi6d838da2008-01-07 13:31:19 -0600793
794 if (strcmp(argv[1], "fw") == 0) {
Simon Glass3ff49ec2021-07-24 09:03:29 -0600795 addr = hextoul(argv[2], NULL);
Timur Tabi6d838da2008-01-07 13:31:19 -0600796
797 if (!addr) {
798 printf("Invalid address\n");
799 return -EINVAL;
800 }
801
Wolfgang Denk545b06a2008-01-10 00:55:14 +0100802 /*
803 * If a length was supplied, compare that with the 'length'
804 * field.
805 */
Timur Tabi6d838da2008-01-07 13:31:19 -0600806
807 if (argc > 3) {
Simon Glass3ff49ec2021-07-24 09:03:29 -0600808 ulong length = hextoul(argv[3], NULL);
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200809 struct qe_firmware *firmware = (void *)addr;
Timur Tabi6d838da2008-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 Schocherbaf84a92020-05-25 07:27:26 +0200817 return qe_upload_firmware((const struct qe_firmware *)addr);
Timur Tabi6d838da2008-01-07 13:31:19 -0600818 }
819
Wolfgang Denk3b683112010-07-17 01:06:04 +0200820 return cmd_usage(cmdtp);
Timur Tabi6d838da2008-01-07 13:31:19 -0600821}
822
823U_BOOT_CMD(
824 qe, 4, 0, qe_cmd,
Peter Tyserdfb72b82009-01-27 18:03:12 -0600825 "QUICC Engine commands",
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200826 "fw <addr> [<length>] - Upload firmware binary at address <addr> to the QE,\n"
Wolfgang Denkc54781c2009-05-24 17:06:54 +0200827 "\twith optional length <length> verification."
828);