blob: 1a829b5a4cf379907a2be3326f335b704b9b28d4 [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>
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 */
Mario Sixb2e701c2019-01-21 09:17:24 +0100121#if !defined(CONFIG_ARCH_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,
126#endif
127 0x88, 0x89, 0x98, 0x99,
128 0xa8, 0xa9, 0xb8, 0xb9,
129 0xc8, 0xc9, 0xd8, 0xd9,
130 0xe8, 0xe9, 0x08, 0x09,
131 0x18, 0x19, 0x28, 0x29,
132 0x38, 0x39, 0x48, 0x49,
133 0x58, 0x59, 0x68, 0x69,
134 0x78, 0x79, 0x80, 0x81
Dave Liue732e9c2006-11-03 12:11:15 -0600135};
136
137static void qe_snums_init(void)
138{
139 int i;
140
141 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
142 snums[i].state = QE_SNUM_STATE_FREE;
143 snums[i].num = thread_snum[i];
144 }
145}
146
147int qe_get_snum(void)
148{
149 int snum = -EBUSY;
150 int i;
151
152 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
153 if (snums[i].state == QE_SNUM_STATE_FREE) {
154 snums[i].state = QE_SNUM_STATE_USED;
155 snum = snums[i].num;
156 break;
157 }
158 }
159
160 return snum;
161}
162
163void qe_put_snum(u8 snum)
164{
165 int i;
166
167 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
168 if (snums[i].num == snum) {
169 snums[i].state = QE_SNUM_STATE_FREE;
170 break;
171 }
172 }
173}
174
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000175#ifdef CONFIG_TFABOOT
176void qe_init(uint qe_base)
177{
178 enum boot_src src = get_boot_src();
179
180 /* Init the QE IMMR base */
181 qe_immr = (qe_map_t *)qe_base;
182
183 if (src == BOOT_SOURCE_IFC_NOR) {
184 /*
185 * Upload microcode to IRAM for those SOCs
186 * which do not have ROM in QE.
187 */
188 qe_upload_firmware((const void *)(CONFIG_SYS_QE_FW_ADDR +
189 CONFIG_SYS_FSL_IFC_BASE));
190
191 /* enable the microcode in IRAM */
192 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
193 }
194
195 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
196 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
197
198 qe_sdma_init();
199 qe_snums_init();
200}
201#else
Dave Liue732e9c2006-11-03 12:11:15 -0600202void qe_init(uint qe_base)
203{
Dave Liue732e9c2006-11-03 12:11:15 -0600204 /* Init the QE IMMR base */
205 qe_immr = (qe_map_t *)qe_base;
206
Timur Tabi275f4bb2011-11-22 09:21:25 -0600207#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
Wolfgang Denke366f152009-04-05 00:27:57 +0200208 /*
209 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
210 */
Zhao Qiang83a90842014-03-21 16:21:44 +0800211 qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
Haiying Wangec9d36c2009-03-26 17:01:49 -0400212
Wolfgang Denke366f152009-04-05 00:27:57 +0200213 /* enable the microcode in IRAM */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200214 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Haiying Wangec9d36c2009-03-26 17:01:49 -0400215#endif
216
Simon Glass8518b172012-12-13 20:48:50 +0000217 gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
218 gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
Dave Liue732e9c2006-11-03 12:11:15 -0600219
220 qe_sdma_init();
221 qe_snums_init();
222}
Zhao Qiang3ae22202016-02-05 10:04:16 +0800223#endif
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000224#endif
Dave Liue732e9c2006-11-03 12:11:15 -0600225
Zhao Qiang5ad93952014-09-25 13:52:25 +0800226#ifdef CONFIG_U_QE
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000227#ifdef CONFIG_TFABOOT
Zhao Qiang5ad93952014-09-25 13:52:25 +0800228void u_qe_init(void)
229{
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000230 enum boot_src src = get_boot_src();
231
Zhao Qiang0be9be82016-02-05 10:04:17 +0800232 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiang5ad93952014-09-25 13:52:25 +0800233
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800234 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000235
236 if (src == BOOT_SOURCE_IFC_NOR)
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200237 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
238 CONFIG_SYS_FSL_IFC_BASE);
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000239
240 if (src == BOOT_SOURCE_QSPI_NOR)
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200241 addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
242 CONFIG_SYS_FSL_QSPI_BASE);
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000243
244 if (src == BOOT_SOURCE_SD_MMC) {
245 int dev = CONFIG_SYS_MMC_ENV_DEV;
246 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
247 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
248
249 if (mmc_initialize(gd->bd)) {
250 printf("%s: mmc_initialize() failed\n", __func__);
251 return;
252 }
253 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
254 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
255
256 if (!mmc) {
257 free(addr);
258 printf("\nMMC cannot find device for ucode\n");
259 } else {
260 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
261 dev, blk, cnt);
262 mmc_init(mmc);
263 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
264 addr);
265 }
266 }
267 if (!u_qe_upload_firmware(addr))
268 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
269 if (src == BOOT_SOURCE_SD_MMC)
270 free(addr);
271}
272#else
273void u_qe_init(void)
274{
275 qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
276
277 void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800278#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
279 int dev = CONFIG_SYS_MMC_ENV_DEV;
280 u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
281 u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
282
283 if (mmc_initialize(gd->bd)) {
284 printf("%s: mmc_initialize() failed\n", __func__);
285 return;
286 }
287 addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
288 struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
289
290 if (!mmc) {
291 free(addr);
292 printf("\nMMC cannot find device for ucode\n");
293 } else {
294 printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
295 dev, blk, cnt);
296 mmc_init(mmc);
Yinbo Zhu45c20bd2018-09-25 14:47:06 +0800297 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800298 addr);
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800299 }
300#endif
Zhao Qiang10640212017-08-14 10:22:43 +0800301 if (!u_qe_upload_firmware(addr))
302 out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
Zhao Qiang82cd8c62017-05-25 09:47:40 +0800303#ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
304 free(addr);
305#endif
Zhao Qiang5ad93952014-09-25 13:52:25 +0800306}
307#endif
Rajesh Bhagat4fb459e2018-11-05 18:02:28 +0000308#endif
Zhao Qiang5ad93952014-09-25 13:52:25 +0800309
Zhao Qiangcfd76712015-03-25 17:02:59 +0800310#ifdef CONFIG_U_QE
311void u_qe_resume(void)
312{
313 qe_map_t *qe_immrr;
Zhao Qiangcfd76712015-03-25 17:02:59 +0800314
Zhao Qiang0be9be82016-02-05 10:04:17 +0800315 qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
Zhao Qiangcfd76712015-03-25 17:02:59 +0800316 u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr);
317 out_be32(&qe_immrr->iram.iready, QE_IRAM_READY);
318}
319#endif
320
Dave Liue732e9c2006-11-03 12:11:15 -0600321void qe_reset(void)
322{
323 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200324 (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
Dave Liue732e9c2006-11-03 12:11:15 -0600325}
326
Zhao Qiang3ae22202016-02-05 10:04:16 +0800327#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -0600328void qe_assign_page(uint snum, uint para_ram_base)
329{
330 u32 cecr;
331
332 out_be32(&qe_immr->cp.cecdr, para_ram_base);
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200333 out_be32(&qe_immr->cp.cecr, ((u32)snum << QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
Dave Liue732e9c2006-11-03 12:11:15 -0600334 | QE_CR_FLG | QE_ASSIGN_PAGE);
335
336 /* Wait for the QE_CR_FLG to clear */
337 do {
338 cecr = in_be32(&qe_immr->cp.cecr);
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200339 } while (cecr & QE_CR_FLG);
Dave Liue732e9c2006-11-03 12:11:15 -0600340}
Zhao Qiang3ae22202016-02-05 10:04:16 +0800341#endif
Dave Liue732e9c2006-11-03 12:11:15 -0600342
343/*
344 * brg: 0~15 as BRG1~BRG16
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200345 * rate: baud rate
Dave Liue732e9c2006-11-03 12:11:15 -0600346 * BRG input clock comes from the BRGCLK (internal clock generated from
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200347 * the QE clock, it is one-half of the QE clock), If need the clock source
348 * from CLKn pin, we have te change the function.
Dave Liue732e9c2006-11-03 12:11:15 -0600349 */
350
Simon Glass34a194f2012-12-13 20:48:44 +0000351#define BRG_CLK (gd->arch.brg_clk)
Dave Liue732e9c2006-11-03 12:11:15 -0600352
Zhao Qiang5ad93952014-09-25 13:52:25 +0800353#ifdef CONFIG_QE
Dave Liue732e9c2006-11-03 12:11:15 -0600354int qe_set_brg(uint brg, uint rate)
355{
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200356 uint *bp;
357 u32 divisor;
358 u32 val;
359 int div16 = 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600360
361 if (brg >= QE_NUM_OF_BRGS)
362 return -EINVAL;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200363
Dave Liue732e9c2006-11-03 12:11:15 -0600364 bp = (uint *)&qe_immr->brg.brgc1;
365 bp += brg;
366
367 divisor = (BRG_CLK / rate);
368 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
369 div16 = 1;
370 divisor /= 16;
371 }
372
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200373 /* CHECK TODO */
374 /*
375 * was
376 * *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
377 * __asm__ __volatile__("sync");
378 */
Dave Liue732e9c2006-11-03 12:11:15 -0600379
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200380 val = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
381 if (div16)
382 val |= QE_BRGC_DIV16;
383
384 out_be32(bp, val);
Dave Liue732e9c2006-11-03 12:11:15 -0600385
386 return 0;
387}
Zhao Qiang5ad93952014-09-25 13:52:25 +0800388#endif
Dave Liue732e9c2006-11-03 12:11:15 -0600389
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200390/* Set ethernet MII clock master */
Dave Liue732e9c2006-11-03 12:11:15 -0600391int qe_set_mii_clk_src(int ucc_num)
392{
393 u32 cmxgcr;
394
395 /* check if the UCC number is in range. */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200396 if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) {
397 printf("%s: ucc num not in ranges\n", __func__);
Dave Liue732e9c2006-11-03 12:11:15 -0600398 return -EINVAL;
399 }
400
401 cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
402 cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200403 cmxgcr |= (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
Dave Liue732e9c2006-11-03 12:11:15 -0600404 out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
405
406 return 0;
407}
408
Timur Tabi6d838da2008-01-07 13:31:19 -0600409/* Firmware information stored here for qe_get_firmware_info() */
410static struct qe_firmware_info qe_firmware_info;
411
412/*
413 * Set to 1 if QE firmware has been uploaded, and therefore
414 * qe_firmware_info contains valid data.
415 */
416static int qe_firmware_uploaded;
417
418/*
419 * Upload a QE microcode
420 *
421 * This function is a worker function for qe_upload_firmware(). It does
422 * the actual uploading of the microcode.
423 */
424static void qe_upload_microcode(const void *base,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200425 const struct qe_microcode *ucode)
Timur Tabi6d838da2008-01-07 13:31:19 -0600426{
427 const u32 *code = base + be32_to_cpu(ucode->code_offset);
428 unsigned int i;
429
430 if (ucode->major || ucode->minor || ucode->revision)
431 printf("QE: uploading microcode '%s' version %u.%u.%u\n",
Zhao Qiang7879a492015-05-05 15:53:32 +0800432 (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
433 (u16)ucode->revision);
Timur Tabi6d838da2008-01-07 13:31:19 -0600434 else
Zhao Qiang7879a492015-05-05 15:53:32 +0800435 printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
Timur Tabi6d838da2008-01-07 13:31:19 -0600436
437 /* Use auto-increment */
438 out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
439 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
440
441 for (i = 0; i < be32_to_cpu(ucode->count); i++)
442 out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
443}
444
445/*
446 * Upload a microcode to the I-RAM at a specific address.
447 *
Heinrich Schuchardtb0289282020-04-19 09:19:04 +0200448 * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for
449 * information on QE microcode uploading.
Timur Tabi6d838da2008-01-07 13:31:19 -0600450 *
451 * Currently, only version 1 is supported, so the 'version' field must be
452 * set to 1.
453 *
454 * The SOC model and revision are not validated, they are only displayed for
455 * informational purposes.
456 *
457 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
458 * all of the microcode structures, minus the CRC.
459 *
460 * 'length' is the size that the structure says it is, including the CRC.
461 */
462int qe_upload_firmware(const struct qe_firmware *firmware)
463{
464 unsigned int i;
465 unsigned int j;
466 u32 crc;
467 size_t calc_size = sizeof(struct qe_firmware);
468 size_t length;
469 const struct qe_header *hdr;
Zhao Qiangb59534d2014-04-30 16:45:31 +0800470#ifdef CONFIG_DEEP_SLEEP
York Sunc4f047c2017-03-27 11:41:03 -0700471#ifdef CONFIG_ARCH_LS1021A
Zhao Qiangdf412c62014-12-15 15:50:49 +0800472 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
473#else
Zhao Qiangb59534d2014-04-30 16:45:31 +0800474 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
475#endif
Zhao Qiangdf412c62014-12-15 15:50:49 +0800476#endif
Timur Tabi6d838da2008-01-07 13:31:19 -0600477 if (!firmware) {
478 printf("Invalid address\n");
479 return -EINVAL;
480 }
481
482 hdr = &firmware->header;
483 length = be32_to_cpu(hdr->length);
484
485 /* Check the magic */
486 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
487 (hdr->magic[2] != 'F')) {
Vijay Raia4792292014-07-23 18:33:16 +0530488 printf("QE microcode not found\n");
Zhao Qiangb59534d2014-04-30 16:45:31 +0800489#ifdef CONFIG_DEEP_SLEEP
490 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
491#endif
Timur Tabi6d838da2008-01-07 13:31:19 -0600492 return -EPERM;
493 }
494
495 /* Check the version */
496 if (hdr->version != 1) {
497 printf("Unsupported version\n");
498 return -EPERM;
499 }
500
501 /* Validate some of the fields */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200502 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
Timur Tabi6d838da2008-01-07 13:31:19 -0600503 printf("Invalid data\n");
504 return -EINVAL;
505 }
506
507 /* Validate the length and check if there's a CRC */
508 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
509
510 for (i = 0; i < firmware->count; i++)
511 /*
512 * For situations where the second RISC uses the same microcode
513 * as the first, the 'code_offset' and 'count' fields will be
514 * zero, so it's okay to add those.
515 */
516 calc_size += sizeof(u32) *
517 be32_to_cpu(firmware->microcode[i].count);
518
519 /* Validate the length */
520 if (length != calc_size + sizeof(u32)) {
521 printf("Invalid length\n");
522 return -EPERM;
523 }
524
Wolfgang Denk545b06a2008-01-10 00:55:14 +0100525 /*
526 * Validate the CRC. We would normally call crc32_no_comp(), but that
527 * function isn't available unless you turn on JFFS support.
528 */
Timur Tabi6d838da2008-01-07 13:31:19 -0600529 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200530 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
Timur Tabi6d838da2008-01-07 13:31:19 -0600531 printf("Firmware CRC is invalid\n");
532 return -EIO;
533 }
534
535 /*
536 * If the microcode calls for it, split the I-RAM.
537 */
538 if (!firmware->split) {
539 out_be16(&qe_immr->cp.cercr,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200540 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
Timur Tabi6d838da2008-01-07 13:31:19 -0600541 }
542
543 if (firmware->soc.model)
544 printf("Firmware '%s' for %u V%u.%u\n",
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200545 firmware->id, be16_to_cpu(firmware->soc.model),
Timur Tabi6d838da2008-01-07 13:31:19 -0600546 firmware->soc.major, firmware->soc.minor);
547 else
548 printf("Firmware '%s'\n", firmware->id);
549
550 /*
551 * The QE only supports one microcode per RISC, so clear out all the
552 * saved microcode information and put in the new.
553 */
554 memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
Zhao Qiangd64f1a42015-05-05 15:53:33 +0800555 strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
Timur Tabi6d838da2008-01-07 13:31:19 -0600556 qe_firmware_info.extended_modes = firmware->extended_modes;
557 memcpy(qe_firmware_info.vtraps, firmware->vtraps,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200558 sizeof(firmware->vtraps));
Timur Tabi6d838da2008-01-07 13:31:19 -0600559 qe_firmware_uploaded = 1;
560
561 /* Loop through each microcode. */
562 for (i = 0; i < firmware->count; i++) {
563 const struct qe_microcode *ucode = &firmware->microcode[i];
564
565 /* Upload a microcode if it's present */
566 if (ucode->code_offset)
567 qe_upload_microcode(firmware, ucode);
568
569 /* Program the traps for this processor */
570 for (j = 0; j < 16; j++) {
571 u32 trap = be32_to_cpu(ucode->traps[j]);
572
573 if (trap)
574 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
575 }
576
577 /* Enable traps */
578 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
579 }
580
581 return 0;
582}
583
Zhao Qianga985f822014-11-04 13:46:16 +0800584#ifdef CONFIG_U_QE
585/*
586 * Upload a microcode to the I-RAM at a specific address.
587 *
Heinrich Schuchardtb0289282020-04-19 09:19:04 +0200588 * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for
589 * information on QE microcode uploading.
Zhao Qianga985f822014-11-04 13:46:16 +0800590 *
591 * Currently, only version 1 is supported, so the 'version' field must be
592 * set to 1.
593 *
594 * The SOC model and revision are not validated, they are only displayed for
595 * informational purposes.
596 *
597 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
598 * all of the microcode structures, minus the CRC.
599 *
600 * 'length' is the size that the structure says it is, including the CRC.
601 */
602int u_qe_upload_firmware(const struct qe_firmware *firmware)
603{
604 unsigned int i;
605 unsigned int j;
606 u32 crc;
607 size_t calc_size = sizeof(struct qe_firmware);
608 size_t length;
609 const struct qe_header *hdr;
610#ifdef CONFIG_DEEP_SLEEP
York Sunc4f047c2017-03-27 11:41:03 -0700611#ifdef CONFIG_ARCH_LS1021A
Zhao Qiangdf412c62014-12-15 15:50:49 +0800612 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
613#else
Zhao Qianga985f822014-11-04 13:46:16 +0800614 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
615#endif
Zhao Qiangdf412c62014-12-15 15:50:49 +0800616#endif
Zhao Qianga985f822014-11-04 13:46:16 +0800617 if (!firmware) {
618 printf("Invalid address\n");
619 return -EINVAL;
620 }
621
622 hdr = &firmware->header;
623 length = be32_to_cpu(hdr->length);
624
625 /* Check the magic */
626 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
627 (hdr->magic[2] != 'F')) {
628 printf("Not a microcode\n");
629#ifdef CONFIG_DEEP_SLEEP
630 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
631#endif
632 return -EPERM;
633 }
634
635 /* Check the version */
636 if (hdr->version != 1) {
637 printf("Unsupported version\n");
638 return -EPERM;
639 }
640
641 /* Validate some of the fields */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200642 if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
Zhao Qianga985f822014-11-04 13:46:16 +0800643 printf("Invalid data\n");
644 return -EINVAL;
645 }
646
647 /* Validate the length and check if there's a CRC */
648 calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
649
650 for (i = 0; i < firmware->count; i++)
651 /*
652 * For situations where the second RISC uses the same microcode
653 * as the first, the 'code_offset' and 'count' fields will be
654 * zero, so it's okay to add those.
655 */
656 calc_size += sizeof(u32) *
657 be32_to_cpu(firmware->microcode[i].count);
658
659 /* Validate the length */
660 if (length != calc_size + sizeof(u32)) {
661 printf("Invalid length\n");
662 return -EPERM;
663 }
664
665 /*
666 * Validate the CRC. We would normally call crc32_no_comp(), but that
667 * function isn't available unless you turn on JFFS support.
668 */
669 crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
670 if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
671 printf("Firmware CRC is invalid\n");
672 return -EIO;
673 }
674
675 /*
676 * If the microcode calls for it, split the I-RAM.
677 */
678 if (!firmware->split) {
679 out_be16(&qe_immr->cp.cercr,
680 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
681 }
682
683 if (firmware->soc.model)
684 printf("Firmware '%s' for %u V%u.%u\n",
685 firmware->id, be16_to_cpu(firmware->soc.model),
686 firmware->soc.major, firmware->soc.minor);
687 else
688 printf("Firmware '%s'\n", firmware->id);
689
690 /* Loop through each microcode. */
691 for (i = 0; i < firmware->count; i++) {
692 const struct qe_microcode *ucode = &firmware->microcode[i];
693
694 /* Upload a microcode if it's present */
695 if (ucode->code_offset)
696 qe_upload_microcode(firmware, ucode);
697
698 /* Program the traps for this processor */
699 for (j = 0; j < 16; j++) {
700 u32 trap = be32_to_cpu(ucode->traps[j]);
701
702 if (trap)
703 out_be32(&qe_immr->rsp[i].tibcr[j], trap);
704 }
705
706 /* Enable traps */
707 out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
708 }
709
710 return 0;
711}
712#endif
713
Zhao Qiangcfd76712015-03-25 17:02:59 +0800714#ifdef CONFIG_U_QE
715int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
716{
717 unsigned int i;
718 unsigned int j;
719 const struct qe_header *hdr;
720 const u32 *code;
721#ifdef CONFIG_DEEP_SLEEP
722#ifdef CONFIG_PPC
723 ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
724#else
725 struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
726#endif
727#endif
728
729 if (!firmware)
730 return -EINVAL;
731
732 hdr = &firmware->header;
733
734 /* Check the magic */
735 if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
736 (hdr->magic[2] != 'F')) {
737#ifdef CONFIG_DEEP_SLEEP
738 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
739#endif
740 return -EPERM;
741 }
742
743 /*
744 * If the microcode calls for it, split the I-RAM.
745 */
746 if (!firmware->split) {
747 out_be16(&qe_immrr->cp.cercr,
748 in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
749 }
750
751 /* Loop through each microcode. */
752 for (i = 0; i < firmware->count; i++) {
753 const struct qe_microcode *ucode = &firmware->microcode[i];
754
755 /* Upload a microcode if it's present */
756 if (!ucode->code_offset)
757 return 0;
758
759 code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
760
761 /* Use auto-increment */
762 out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
763 QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
764
765 for (i = 0; i < be32_to_cpu(ucode->count); i++)
766 out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
767
768 /* Program the traps for this processor */
769 for (j = 0; j < 16; j++) {
770 u32 trap = be32_to_cpu(ucode->traps[j]);
771
772 if (trap)
773 out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
774 }
775
776 /* Enable traps */
777 out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
778 }
779
780 return 0;
781}
782#endif
783
Timur Tabi6d838da2008-01-07 13:31:19 -0600784struct qe_firmware_info *qe_get_firmware_info(void)
785{
786 return qe_firmware_uploaded ? &qe_firmware_info : NULL;
787}
788
Simon Glassed38aef2020-05-10 11:40:03 -0600789static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Timur Tabi6d838da2008-01-07 13:31:19 -0600790{
791 ulong addr;
792
Wolfgang Denk3b683112010-07-17 01:06:04 +0200793 if (argc < 3)
794 return cmd_usage(cmdtp);
Timur Tabi6d838da2008-01-07 13:31:19 -0600795
796 if (strcmp(argv[1], "fw") == 0) {
797 addr = simple_strtoul(argv[2], NULL, 16);
798
799 if (!addr) {
800 printf("Invalid address\n");
801 return -EINVAL;
802 }
803
Wolfgang Denk545b06a2008-01-10 00:55:14 +0100804 /*
805 * If a length was supplied, compare that with the 'length'
806 * field.
807 */
Timur Tabi6d838da2008-01-07 13:31:19 -0600808
809 if (argc > 3) {
810 ulong length = simple_strtoul(argv[3], NULL, 16);
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200811 struct qe_firmware *firmware = (void *)addr;
Timur Tabi6d838da2008-01-07 13:31:19 -0600812
813 if (length != be32_to_cpu(firmware->header.length)) {
814 printf("Length mismatch\n");
815 return -EINVAL;
816 }
817 }
818
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200819 return qe_upload_firmware((const struct qe_firmware *)addr);
Timur Tabi6d838da2008-01-07 13:31:19 -0600820 }
821
Wolfgang Denk3b683112010-07-17 01:06:04 +0200822 return cmd_usage(cmdtp);
Timur Tabi6d838da2008-01-07 13:31:19 -0600823}
824
825U_BOOT_CMD(
826 qe, 4, 0, qe_cmd,
Peter Tyserdfb72b82009-01-27 18:03:12 -0600827 "QUICC Engine commands",
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200828 "fw <addr> [<length>] - Upload firmware binary at address <addr> to the QE,\n"
Wolfgang Denkc54781c2009-05-24 17:06:54 +0200829 "\twith optional length <length> verification."
830);