xref: /rk3399_rockchip-uboot/drivers/qe/qe.c (revision ae42eb035e86f2fca98adc5f5b59543a49797877)
17737d5c6SDave Liu /*
24e7b25e4SHaiying Wang  * Copyright (C) 2006-2009 Freescale Semiconductor, Inc.
37737d5c6SDave Liu  *
47737d5c6SDave Liu  * Dave Liu <daveliu@freescale.com>
57737d5c6SDave Liu  * based on source code of Shlomi Gridish
67737d5c6SDave Liu  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
87737d5c6SDave Liu  */
97737d5c6SDave Liu 
107737d5c6SDave Liu #include "common.h"
11b8ec2385STimur Tabi #include <command.h>
127737d5c6SDave Liu #include "asm/errno.h"
137737d5c6SDave Liu #include "asm/io.h"
1438d67a4eSZhao Qiang #include "linux/immap_qe.h"
157737d5c6SDave Liu #include "qe.h"
169c7c86f4SZhao Qiang #ifdef CONFIG_LS102XA
179c7c86f4SZhao Qiang #include <asm/arch/immap_ls102xa.h>
189c7c86f4SZhao Qiang #endif
197737d5c6SDave Liu 
20ca721fb2SZhao Qiang #define MPC85xx_DEVDISR_QE_DISABLE	0x1
21ca721fb2SZhao Qiang 
227737d5c6SDave Liu qe_map_t		*qe_immr = NULL;
237737d5c6SDave Liu static qe_snum_t	snums[QE_NUM_OF_SNUM];
247737d5c6SDave Liu 
251218abf1SWolfgang Denk DECLARE_GLOBAL_DATA_PTR;
261218abf1SWolfgang Denk 
277737d5c6SDave Liu void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
287737d5c6SDave Liu {
297737d5c6SDave Liu 	u32 cecr;
307737d5c6SDave Liu 
317737d5c6SDave Liu 	if (cmd == QE_RESET) {
327737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG));
337737d5c6SDave Liu 	} else {
347737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecdr, cmd_data);
357737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
367737d5c6SDave Liu 			 ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd));
377737d5c6SDave Liu 	}
387737d5c6SDave Liu 	/* Wait for the QE_CR_FLG to clear */
397737d5c6SDave Liu 	do {
407737d5c6SDave Liu 		cecr = in_be32(&qe_immr->cp.cecr);
417737d5c6SDave Liu 	} while (cecr & QE_CR_FLG);
427737d5c6SDave Liu 
437737d5c6SDave Liu 	return;
447737d5c6SDave Liu }
457737d5c6SDave Liu 
4693d33204SZhao Qiang #ifdef CONFIG_QE
477737d5c6SDave Liu uint qe_muram_alloc(uint size, uint align)
487737d5c6SDave Liu {
497737d5c6SDave Liu 	uint	retloc;
507737d5c6SDave Liu 	uint	align_mask, off;
517737d5c6SDave Liu 	uint	savebase;
527737d5c6SDave Liu 
537737d5c6SDave Liu 	align_mask = align - 1;
5445bae2e3SSimon Glass 	savebase = gd->arch.mp_alloc_base;
557737d5c6SDave Liu 
5645bae2e3SSimon Glass 	off = gd->arch.mp_alloc_base & align_mask;
5745bae2e3SSimon Glass 	if (off != 0)
5845bae2e3SSimon Glass 		gd->arch.mp_alloc_base += (align - off);
597737d5c6SDave Liu 
607737d5c6SDave Liu 	if ((off = size & align_mask) != 0)
617737d5c6SDave Liu 		size += (align - off);
627737d5c6SDave Liu 
6345bae2e3SSimon Glass 	if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
6445bae2e3SSimon Glass 		gd->arch.mp_alloc_base = savebase;
657737d5c6SDave Liu 		printf("%s: ran out of ram.\n",  __FUNCTION__);
667737d5c6SDave Liu 	}
677737d5c6SDave Liu 
6845bae2e3SSimon Glass 	retloc = gd->arch.mp_alloc_base;
6945bae2e3SSimon Glass 	gd->arch.mp_alloc_base += size;
707737d5c6SDave Liu 
717737d5c6SDave Liu 	memset((void *)&qe_immr->muram[retloc], 0, size);
727737d5c6SDave Liu 
737737d5c6SDave Liu 	__asm__ __volatile__("sync");
747737d5c6SDave Liu 
757737d5c6SDave Liu 	return retloc;
767737d5c6SDave Liu }
7793d33204SZhao Qiang #endif
787737d5c6SDave Liu 
797737d5c6SDave Liu void *qe_muram_addr(uint offset)
807737d5c6SDave Liu {
817737d5c6SDave Liu 	return (void *)&qe_immr->muram[offset];
827737d5c6SDave Liu }
837737d5c6SDave Liu 
847737d5c6SDave Liu static void qe_sdma_init(void)
857737d5c6SDave Liu {
867737d5c6SDave Liu 	volatile sdma_t	*p;
877737d5c6SDave Liu 	uint		sdma_buffer_base;
887737d5c6SDave Liu 
897737d5c6SDave Liu 	p = (volatile sdma_t *)&qe_immr->sdma;
907737d5c6SDave Liu 
917737d5c6SDave Liu 	/* All of DMA transaction in bus 1 */
927737d5c6SDave Liu 	out_be32(&p->sdaqr, 0);
937737d5c6SDave Liu 	out_be32(&p->sdaqmr, 0);
947737d5c6SDave Liu 
957737d5c6SDave Liu 	/* Allocate 2KB temporary buffer for sdma */
96ff9658d7SDave Liu 	sdma_buffer_base = qe_muram_alloc(2048, 4096);
977737d5c6SDave Liu 	out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
987737d5c6SDave Liu 
997737d5c6SDave Liu 	/* Clear sdma status */
1007737d5c6SDave Liu 	out_be32(&p->sdsr, 0x03000000);
1017737d5c6SDave Liu 
1027737d5c6SDave Liu 	/* Enable global mode on bus 1, and 2KB buffer size */
1037737d5c6SDave Liu 	out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
1047737d5c6SDave Liu }
1057737d5c6SDave Liu 
1064e7b25e4SHaiying Wang /* This table is a list of the serial numbers of the Threads, taken from the
1074e7b25e4SHaiying Wang  * "SNUM Table" chart in the QE Reference Manual. The order is not important,
1084e7b25e4SHaiying Wang  * we just need to know what the SNUMs are for the threads.
1094e7b25e4SHaiying Wang  */
1104e7b25e4SHaiying Wang static u8 thread_snum[] = {
111a88731a6SGerlando Falauto /* Evthreads 16-29 are not supported in MPC8309 */
112a88731a6SGerlando Falauto #if !defined(CONFIG_MPC8309)
1137737d5c6SDave Liu 	0x04, 0x05, 0x0c, 0x0d,
1147737d5c6SDave Liu 	0x14, 0x15, 0x1c, 0x1d,
1157737d5c6SDave Liu 	0x24, 0x25, 0x2c, 0x2d,
116a88731a6SGerlando Falauto 	0x34, 0x35,
117a88731a6SGerlando Falauto #endif
118a88731a6SGerlando Falauto 	0x88, 0x89, 0x98, 0x99,
119a88731a6SGerlando Falauto 	0xa8, 0xa9, 0xb8, 0xb9,
120a88731a6SGerlando Falauto 	0xc8, 0xc9, 0xd8, 0xd9,
121a88731a6SGerlando Falauto 	0xe8, 0xe9, 0x08, 0x09,
122a88731a6SGerlando Falauto 	0x18, 0x19, 0x28, 0x29,
123a88731a6SGerlando Falauto 	0x38, 0x39, 0x48, 0x49,
124a88731a6SGerlando Falauto 	0x58, 0x59, 0x68, 0x69,
125a88731a6SGerlando Falauto 	0x78, 0x79, 0x80, 0x81
1267737d5c6SDave Liu };
1277737d5c6SDave Liu 
1287737d5c6SDave Liu static void qe_snums_init(void)
1297737d5c6SDave Liu {
1307737d5c6SDave Liu 	int	i;
1317737d5c6SDave Liu 
1327737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1337737d5c6SDave Liu 		snums[i].state = QE_SNUM_STATE_FREE;
1347737d5c6SDave Liu 		snums[i].num   = thread_snum[i];
1357737d5c6SDave Liu 	}
1367737d5c6SDave Liu }
1377737d5c6SDave Liu 
1387737d5c6SDave Liu int qe_get_snum(void)
1397737d5c6SDave Liu {
1407737d5c6SDave Liu 	int	snum = -EBUSY;
1417737d5c6SDave Liu 	int	i;
1427737d5c6SDave Liu 
1437737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1447737d5c6SDave Liu 		if (snums[i].state == QE_SNUM_STATE_FREE) {
1457737d5c6SDave Liu 			snums[i].state = QE_SNUM_STATE_USED;
1467737d5c6SDave Liu 			snum = snums[i].num;
1477737d5c6SDave Liu 			break;
1487737d5c6SDave Liu 		}
1497737d5c6SDave Liu 	}
1507737d5c6SDave Liu 
1517737d5c6SDave Liu 	return snum;
1527737d5c6SDave Liu }
1537737d5c6SDave Liu 
1547737d5c6SDave Liu void qe_put_snum(u8 snum)
1557737d5c6SDave Liu {
1567737d5c6SDave Liu 	int	i;
1577737d5c6SDave Liu 
1587737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1597737d5c6SDave Liu 		if (snums[i].num == snum) {
1607737d5c6SDave Liu 			snums[i].state = QE_SNUM_STATE_FREE;
1617737d5c6SDave Liu 			break;
1627737d5c6SDave Liu 		}
1637737d5c6SDave Liu 	}
1647737d5c6SDave Liu }
1657737d5c6SDave Liu 
1667737d5c6SDave Liu void qe_init(uint qe_base)
1677737d5c6SDave Liu {
1687737d5c6SDave Liu 	/* Init the QE IMMR base */
1697737d5c6SDave Liu 	qe_immr = (qe_map_t *)qe_base;
1707737d5c6SDave Liu 
171f2717b47STimur Tabi #ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
172c0a14aedSWolfgang Denk 	/*
173c0a14aedSWolfgang Denk 	 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
1742d4de6aeSHaiying Wang 	 */
175dcf1d774SZhao Qiang 	qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
1762d4de6aeSHaiying Wang 
1772d4de6aeSHaiying Wang 	/* enable the microcode in IRAM */
1782d4de6aeSHaiying Wang 	out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
1792d4de6aeSHaiying Wang #endif
1802d4de6aeSHaiying Wang 
18145bae2e3SSimon Glass 	gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
18245bae2e3SSimon Glass 	gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
1837737d5c6SDave Liu 
1847737d5c6SDave Liu 	qe_sdma_init();
1857737d5c6SDave Liu 	qe_snums_init();
1867737d5c6SDave Liu }
1877737d5c6SDave Liu 
18893d33204SZhao Qiang #ifdef CONFIG_U_QE
18993d33204SZhao Qiang void u_qe_init(void)
19093d33204SZhao Qiang {
19193d33204SZhao Qiang 	uint qe_base = CONFIG_SYS_IMMR + 0x01400000; /* QE immr base */
19293d33204SZhao Qiang 	qe_immr = (qe_map_t *)qe_base;
19393d33204SZhao Qiang 
1945632d15cSZhao Qiang 	u_qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
19593d33204SZhao Qiang 	out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
19693d33204SZhao Qiang }
19793d33204SZhao Qiang #endif
19893d33204SZhao Qiang 
199*ae42eb03SZhao Qiang #ifdef CONFIG_U_QE
200*ae42eb03SZhao Qiang void u_qe_resume(void)
201*ae42eb03SZhao Qiang {
202*ae42eb03SZhao Qiang 	qe_map_t *qe_immrr;
203*ae42eb03SZhao Qiang 	uint qe_base = CONFIG_SYS_IMMR + QE_IMMR_OFFSET; /* QE immr base */
204*ae42eb03SZhao Qiang 	qe_immrr = (qe_map_t *)qe_base;
205*ae42eb03SZhao Qiang 
206*ae42eb03SZhao Qiang 	u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr);
207*ae42eb03SZhao Qiang 	out_be32(&qe_immrr->iram.iready, QE_IRAM_READY);
208*ae42eb03SZhao Qiang }
209*ae42eb03SZhao Qiang #endif
210*ae42eb03SZhao Qiang 
2117737d5c6SDave Liu void qe_reset(void)
2127737d5c6SDave Liu {
2137737d5c6SDave Liu 	qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
2147737d5c6SDave Liu 			 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
2157737d5c6SDave Liu }
2167737d5c6SDave Liu 
2177737d5c6SDave Liu void qe_assign_page(uint snum, uint para_ram_base)
2187737d5c6SDave Liu {
2197737d5c6SDave Liu 	u32	cecr;
2207737d5c6SDave Liu 
2217737d5c6SDave Liu 	out_be32(&qe_immr->cp.cecdr, para_ram_base);
2227737d5c6SDave Liu 	out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
2237737d5c6SDave Liu 					 | QE_CR_FLG | QE_ASSIGN_PAGE);
2247737d5c6SDave Liu 
2257737d5c6SDave Liu 	/* Wait for the QE_CR_FLG to clear */
2267737d5c6SDave Liu 	do {
2277737d5c6SDave Liu 		cecr = in_be32(&qe_immr->cp.cecr);
2287737d5c6SDave Liu 	} while (cecr & QE_CR_FLG );
2297737d5c6SDave Liu 
2307737d5c6SDave Liu 	return;
2317737d5c6SDave Liu }
2327737d5c6SDave Liu 
2337737d5c6SDave Liu /*
2347737d5c6SDave Liu  * brg: 0~15 as BRG1~BRG16
2357737d5c6SDave Liu    rate: baud rate
2367737d5c6SDave Liu  * BRG input clock comes from the BRGCLK (internal clock generated from
2377737d5c6SDave Liu    the QE clock, it is one-half of the QE clock), If need the clock source
2387737d5c6SDave Liu    from CLKn pin, we have te change the function.
2397737d5c6SDave Liu  */
2407737d5c6SDave Liu 
2411206c184SSimon Glass #define BRG_CLK		(gd->arch.brg_clk)
2427737d5c6SDave Liu 
24393d33204SZhao Qiang #ifdef CONFIG_QE
2447737d5c6SDave Liu int qe_set_brg(uint brg, uint rate)
2457737d5c6SDave Liu {
2467737d5c6SDave Liu 	volatile uint	*bp;
2477737d5c6SDave Liu 	u32		divisor;
2487737d5c6SDave Liu 	int		div16 = 0;
2497737d5c6SDave Liu 
2507737d5c6SDave Liu 	if (brg >= QE_NUM_OF_BRGS)
2517737d5c6SDave Liu 		return -EINVAL;
2527737d5c6SDave Liu 	bp = (uint *)&qe_immr->brg.brgc1;
2537737d5c6SDave Liu 	bp += brg;
2547737d5c6SDave Liu 
2557737d5c6SDave Liu 	divisor = (BRG_CLK / rate);
2567737d5c6SDave Liu 	if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
2577737d5c6SDave Liu 		div16 = 1;
2587737d5c6SDave Liu 		divisor /= 16;
2597737d5c6SDave Liu 	}
2607737d5c6SDave Liu 
2617737d5c6SDave Liu 	*bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
2627737d5c6SDave Liu 	__asm__ __volatile__("sync");
2637737d5c6SDave Liu 
2647737d5c6SDave Liu 	if (div16) {
2657737d5c6SDave Liu 		*bp |= QE_BRGC_DIV16;
2667737d5c6SDave Liu 		__asm__ __volatile__("sync");
2677737d5c6SDave Liu 	}
2687737d5c6SDave Liu 
2697737d5c6SDave Liu 	return 0;
2707737d5c6SDave Liu }
27193d33204SZhao Qiang #endif
2727737d5c6SDave Liu 
2737737d5c6SDave Liu /* Set ethernet MII clock master
2747737d5c6SDave Liu */
2757737d5c6SDave Liu int qe_set_mii_clk_src(int ucc_num)
2767737d5c6SDave Liu {
2777737d5c6SDave Liu 	u32	cmxgcr;
2787737d5c6SDave Liu 
2797737d5c6SDave Liu 	/* check if the UCC number is in range. */
2807737d5c6SDave Liu 	if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
2817737d5c6SDave Liu 		printf("%s: ucc num not in ranges\n", __FUNCTION__);
2827737d5c6SDave Liu 		return -EINVAL;
2837737d5c6SDave Liu 	}
2847737d5c6SDave Liu 
2857737d5c6SDave Liu 	cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
2867737d5c6SDave Liu 	cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
2877737d5c6SDave Liu 	cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
2887737d5c6SDave Liu 	out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
2897737d5c6SDave Liu 
2907737d5c6SDave Liu 	return 0;
2917737d5c6SDave Liu }
2927737d5c6SDave Liu 
293b8ec2385STimur Tabi /* Firmware information stored here for qe_get_firmware_info() */
294b8ec2385STimur Tabi static struct qe_firmware_info qe_firmware_info;
295b8ec2385STimur Tabi 
296b8ec2385STimur Tabi /*
297b8ec2385STimur Tabi  * Set to 1 if QE firmware has been uploaded, and therefore
298b8ec2385STimur Tabi  * qe_firmware_info contains valid data.
299b8ec2385STimur Tabi  */
300b8ec2385STimur Tabi static int qe_firmware_uploaded;
301b8ec2385STimur Tabi 
302b8ec2385STimur Tabi /*
303b8ec2385STimur Tabi  * Upload a QE microcode
304b8ec2385STimur Tabi  *
305b8ec2385STimur Tabi  * This function is a worker function for qe_upload_firmware().  It does
306b8ec2385STimur Tabi  * the actual uploading of the microcode.
307b8ec2385STimur Tabi  */
308b8ec2385STimur Tabi static void qe_upload_microcode(const void *base,
309b8ec2385STimur Tabi 	const struct qe_microcode *ucode)
310b8ec2385STimur Tabi {
311b8ec2385STimur Tabi 	const u32 *code = base + be32_to_cpu(ucode->code_offset);
312b8ec2385STimur Tabi 	unsigned int i;
313b8ec2385STimur Tabi 
314b8ec2385STimur Tabi 	if (ucode->major || ucode->minor || ucode->revision)
315b8ec2385STimur Tabi 		printf("QE: uploading microcode '%s' version %u.%u.%u\n",
316b8ec2385STimur Tabi 			ucode->id, ucode->major, ucode->minor, ucode->revision);
317b8ec2385STimur Tabi 	else
318b8ec2385STimur Tabi 		printf("QE: uploading microcode '%s'\n", ucode->id);
319b8ec2385STimur Tabi 
320b8ec2385STimur Tabi 	/* Use auto-increment */
321b8ec2385STimur Tabi 	out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
322b8ec2385STimur Tabi 		QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
323b8ec2385STimur Tabi 
324b8ec2385STimur Tabi 	for (i = 0; i < be32_to_cpu(ucode->count); i++)
325b8ec2385STimur Tabi 		out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
326b8ec2385STimur Tabi }
327b8ec2385STimur Tabi 
328b8ec2385STimur Tabi /*
329b8ec2385STimur Tabi  * Upload a microcode to the I-RAM at a specific address.
330b8ec2385STimur Tabi  *
331b8ec2385STimur Tabi  * See docs/README.qe_firmware for information on QE microcode uploading.
332b8ec2385STimur Tabi  *
333b8ec2385STimur Tabi  * Currently, only version 1 is supported, so the 'version' field must be
334b8ec2385STimur Tabi  * set to 1.
335b8ec2385STimur Tabi  *
336b8ec2385STimur Tabi  * The SOC model and revision are not validated, they are only displayed for
337b8ec2385STimur Tabi  * informational purposes.
338b8ec2385STimur Tabi  *
339b8ec2385STimur Tabi  * 'calc_size' is the calculated size, in bytes, of the firmware structure and
340b8ec2385STimur Tabi  * all of the microcode structures, minus the CRC.
341b8ec2385STimur Tabi  *
342b8ec2385STimur Tabi  * 'length' is the size that the structure says it is, including the CRC.
343b8ec2385STimur Tabi  */
344b8ec2385STimur Tabi int qe_upload_firmware(const struct qe_firmware *firmware)
345b8ec2385STimur Tabi {
346b8ec2385STimur Tabi 	unsigned int i;
347b8ec2385STimur Tabi 	unsigned int j;
348b8ec2385STimur Tabi 	u32 crc;
349b8ec2385STimur Tabi 	size_t calc_size = sizeof(struct qe_firmware);
350b8ec2385STimur Tabi 	size_t length;
351b8ec2385STimur Tabi 	const struct qe_header *hdr;
352ca721fb2SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
3539c7c86f4SZhao Qiang #ifdef CONFIG_LS102XA
3549c7c86f4SZhao Qiang 	struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
3559c7c86f4SZhao Qiang #else
356ca721fb2SZhao Qiang 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
357ca721fb2SZhao Qiang #endif
3589c7c86f4SZhao Qiang #endif
359b8ec2385STimur Tabi 	if (!firmware) {
360b8ec2385STimur Tabi 		printf("Invalid address\n");
361b8ec2385STimur Tabi 		return -EINVAL;
362b8ec2385STimur Tabi 	}
363b8ec2385STimur Tabi 
364b8ec2385STimur Tabi 	hdr = &firmware->header;
365b8ec2385STimur Tabi 	length = be32_to_cpu(hdr->length);
366b8ec2385STimur Tabi 
367b8ec2385STimur Tabi 	/* Check the magic */
368b8ec2385STimur Tabi 	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
369b8ec2385STimur Tabi 	    (hdr->magic[2] != 'F')) {
37012eeb135SVijay Rai 		printf("QE microcode not found\n");
371ca721fb2SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
372ca721fb2SZhao Qiang 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
373ca721fb2SZhao Qiang #endif
374b8ec2385STimur Tabi 		return -EPERM;
375b8ec2385STimur Tabi 	}
376b8ec2385STimur Tabi 
377b8ec2385STimur Tabi 	/* Check the version */
378b8ec2385STimur Tabi 	if (hdr->version != 1) {
379b8ec2385STimur Tabi 		printf("Unsupported version\n");
380b8ec2385STimur Tabi 		return -EPERM;
381b8ec2385STimur Tabi 	}
382b8ec2385STimur Tabi 
383b8ec2385STimur Tabi 	/* Validate some of the fields */
384491fb6deSTimur Tabi 	if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
385b8ec2385STimur Tabi 		printf("Invalid data\n");
386b8ec2385STimur Tabi 		return -EINVAL;
387b8ec2385STimur Tabi 	}
388b8ec2385STimur Tabi 
389b8ec2385STimur Tabi 	/* Validate the length and check if there's a CRC */
390b8ec2385STimur Tabi 	calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
391b8ec2385STimur Tabi 
392b8ec2385STimur Tabi 	for (i = 0; i < firmware->count; i++)
393b8ec2385STimur Tabi 		/*
394b8ec2385STimur Tabi 		 * For situations where the second RISC uses the same microcode
395b8ec2385STimur Tabi 		 * as the first, the 'code_offset' and 'count' fields will be
396b8ec2385STimur Tabi 		 * zero, so it's okay to add those.
397b8ec2385STimur Tabi 		 */
398b8ec2385STimur Tabi 		calc_size += sizeof(u32) *
399b8ec2385STimur Tabi 			be32_to_cpu(firmware->microcode[i].count);
400b8ec2385STimur Tabi 
401b8ec2385STimur Tabi 	/* Validate the length */
402b8ec2385STimur Tabi 	if (length != calc_size + sizeof(u32)) {
403b8ec2385STimur Tabi 		printf("Invalid length\n");
404b8ec2385STimur Tabi 		return -EPERM;
405b8ec2385STimur Tabi 	}
406b8ec2385STimur Tabi 
407b8ec2385STimur Tabi 	/*
408b8ec2385STimur Tabi 	 * Validate the CRC.  We would normally call crc32_no_comp(), but that
409b8ec2385STimur Tabi 	 * function isn't available unless you turn on JFFS support.
410b8ec2385STimur Tabi 	 */
411b8ec2385STimur Tabi 	crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
412b8ec2385STimur Tabi 	if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
413b8ec2385STimur Tabi 		printf("Firmware CRC is invalid\n");
414b8ec2385STimur Tabi 		return -EIO;
415b8ec2385STimur Tabi 	}
416b8ec2385STimur Tabi 
417b8ec2385STimur Tabi 	/*
418b8ec2385STimur Tabi 	 * If the microcode calls for it, split the I-RAM.
419b8ec2385STimur Tabi 	 */
420b8ec2385STimur Tabi 	if (!firmware->split) {
421b8ec2385STimur Tabi 		out_be16(&qe_immr->cp.cercr,
422b8ec2385STimur Tabi 			in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
423b8ec2385STimur Tabi 	}
424b8ec2385STimur Tabi 
425b8ec2385STimur Tabi 	if (firmware->soc.model)
426b8ec2385STimur Tabi 		printf("Firmware '%s' for %u V%u.%u\n",
427b8ec2385STimur Tabi 			firmware->id, be16_to_cpu(firmware->soc.model),
428b8ec2385STimur Tabi 			firmware->soc.major, firmware->soc.minor);
429b8ec2385STimur Tabi 	else
430b8ec2385STimur Tabi 		printf("Firmware '%s'\n", firmware->id);
431b8ec2385STimur Tabi 
432b8ec2385STimur Tabi 	/*
433b8ec2385STimur Tabi 	 * The QE only supports one microcode per RISC, so clear out all the
434b8ec2385STimur Tabi 	 * saved microcode information and put in the new.
435b8ec2385STimur Tabi 	 */
436b8ec2385STimur Tabi 	memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
43706c428bcSDave Liu 	strcpy(qe_firmware_info.id, (char *)firmware->id);
438b8ec2385STimur Tabi 	qe_firmware_info.extended_modes = firmware->extended_modes;
439b8ec2385STimur Tabi 	memcpy(qe_firmware_info.vtraps, firmware->vtraps,
440b8ec2385STimur Tabi 		sizeof(firmware->vtraps));
441b8ec2385STimur Tabi 	qe_firmware_uploaded = 1;
442b8ec2385STimur Tabi 
443b8ec2385STimur Tabi 	/* Loop through each microcode. */
444b8ec2385STimur Tabi 	for (i = 0; i < firmware->count; i++) {
445b8ec2385STimur Tabi 		const struct qe_microcode *ucode = &firmware->microcode[i];
446b8ec2385STimur Tabi 
447b8ec2385STimur Tabi 		/* Upload a microcode if it's present */
448b8ec2385STimur Tabi 		if (ucode->code_offset)
449b8ec2385STimur Tabi 			qe_upload_microcode(firmware, ucode);
450b8ec2385STimur Tabi 
451b8ec2385STimur Tabi 		/* Program the traps for this processor */
452b8ec2385STimur Tabi 		for (j = 0; j < 16; j++) {
453b8ec2385STimur Tabi 			u32 trap = be32_to_cpu(ucode->traps[j]);
454b8ec2385STimur Tabi 
455b8ec2385STimur Tabi 			if (trap)
456b8ec2385STimur Tabi 				out_be32(&qe_immr->rsp[i].tibcr[j], trap);
457b8ec2385STimur Tabi 		}
458b8ec2385STimur Tabi 
459b8ec2385STimur Tabi 		/* Enable traps */
460b8ec2385STimur Tabi 		out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
461b8ec2385STimur Tabi 	}
462b8ec2385STimur Tabi 
463b8ec2385STimur Tabi 	return 0;
464b8ec2385STimur Tabi }
465b8ec2385STimur Tabi 
4665632d15cSZhao Qiang #ifdef CONFIG_U_QE
4675632d15cSZhao Qiang /*
4685632d15cSZhao Qiang  * Upload a microcode to the I-RAM at a specific address.
4695632d15cSZhao Qiang  *
4705632d15cSZhao Qiang  * See docs/README.qe_firmware for information on QE microcode uploading.
4715632d15cSZhao Qiang  *
4725632d15cSZhao Qiang  * Currently, only version 1 is supported, so the 'version' field must be
4735632d15cSZhao Qiang  * set to 1.
4745632d15cSZhao Qiang  *
4755632d15cSZhao Qiang  * The SOC model and revision are not validated, they are only displayed for
4765632d15cSZhao Qiang  * informational purposes.
4775632d15cSZhao Qiang  *
4785632d15cSZhao Qiang  * 'calc_size' is the calculated size, in bytes, of the firmware structure and
4795632d15cSZhao Qiang  * all of the microcode structures, minus the CRC.
4805632d15cSZhao Qiang  *
4815632d15cSZhao Qiang  * 'length' is the size that the structure says it is, including the CRC.
4825632d15cSZhao Qiang  */
4835632d15cSZhao Qiang int u_qe_upload_firmware(const struct qe_firmware *firmware)
4845632d15cSZhao Qiang {
4855632d15cSZhao Qiang 	unsigned int i;
4865632d15cSZhao Qiang 	unsigned int j;
4875632d15cSZhao Qiang 	u32 crc;
4885632d15cSZhao Qiang 	size_t calc_size = sizeof(struct qe_firmware);
4895632d15cSZhao Qiang 	size_t length;
4905632d15cSZhao Qiang 	const struct qe_header *hdr;
4915632d15cSZhao Qiang #ifdef CONFIG_DEEP_SLEEP
4929c7c86f4SZhao Qiang #ifdef CONFIG_LS102XA
4939c7c86f4SZhao Qiang 	struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
4949c7c86f4SZhao Qiang #else
4955632d15cSZhao Qiang 	ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
4965632d15cSZhao Qiang #endif
4979c7c86f4SZhao Qiang #endif
4985632d15cSZhao Qiang 	if (!firmware) {
4995632d15cSZhao Qiang 		printf("Invalid address\n");
5005632d15cSZhao Qiang 		return -EINVAL;
5015632d15cSZhao Qiang 	}
5025632d15cSZhao Qiang 
5035632d15cSZhao Qiang 	hdr = &firmware->header;
5045632d15cSZhao Qiang 	length = be32_to_cpu(hdr->length);
5055632d15cSZhao Qiang 
5065632d15cSZhao Qiang 	/* Check the magic */
5075632d15cSZhao Qiang 	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
5085632d15cSZhao Qiang 	    (hdr->magic[2] != 'F')) {
5095632d15cSZhao Qiang 		printf("Not a microcode\n");
5105632d15cSZhao Qiang #ifdef CONFIG_DEEP_SLEEP
5115632d15cSZhao Qiang 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
5125632d15cSZhao Qiang #endif
5135632d15cSZhao Qiang 		return -EPERM;
5145632d15cSZhao Qiang 	}
5155632d15cSZhao Qiang 
5165632d15cSZhao Qiang 	/* Check the version */
5175632d15cSZhao Qiang 	if (hdr->version != 1) {
5185632d15cSZhao Qiang 		printf("Unsupported version\n");
5195632d15cSZhao Qiang 		return -EPERM;
5205632d15cSZhao Qiang 	}
5215632d15cSZhao Qiang 
5225632d15cSZhao Qiang 	/* Validate some of the fields */
5235632d15cSZhao Qiang 	if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
5245632d15cSZhao Qiang 		printf("Invalid data\n");
5255632d15cSZhao Qiang 		return -EINVAL;
5265632d15cSZhao Qiang 	}
5275632d15cSZhao Qiang 
5285632d15cSZhao Qiang 	/* Validate the length and check if there's a CRC */
5295632d15cSZhao Qiang 	calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
5305632d15cSZhao Qiang 
5315632d15cSZhao Qiang 	for (i = 0; i < firmware->count; i++)
5325632d15cSZhao Qiang 		/*
5335632d15cSZhao Qiang 		 * For situations where the second RISC uses the same microcode
5345632d15cSZhao Qiang 		 * as the first, the 'code_offset' and 'count' fields will be
5355632d15cSZhao Qiang 		 * zero, so it's okay to add those.
5365632d15cSZhao Qiang 		 */
5375632d15cSZhao Qiang 		calc_size += sizeof(u32) *
5385632d15cSZhao Qiang 			be32_to_cpu(firmware->microcode[i].count);
5395632d15cSZhao Qiang 
5405632d15cSZhao Qiang 	/* Validate the length */
5415632d15cSZhao Qiang 	if (length != calc_size + sizeof(u32)) {
5425632d15cSZhao Qiang 		printf("Invalid length\n");
5435632d15cSZhao Qiang 		return -EPERM;
5445632d15cSZhao Qiang 	}
5455632d15cSZhao Qiang 
5465632d15cSZhao Qiang 	/*
5475632d15cSZhao Qiang 	 * Validate the CRC.  We would normally call crc32_no_comp(), but that
5485632d15cSZhao Qiang 	 * function isn't available unless you turn on JFFS support.
5495632d15cSZhao Qiang 	 */
5505632d15cSZhao Qiang 	crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
5515632d15cSZhao Qiang 	if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
5525632d15cSZhao Qiang 		printf("Firmware CRC is invalid\n");
5535632d15cSZhao Qiang 		return -EIO;
5545632d15cSZhao Qiang 	}
5555632d15cSZhao Qiang 
5565632d15cSZhao Qiang 	/*
5575632d15cSZhao Qiang 	 * If the microcode calls for it, split the I-RAM.
5585632d15cSZhao Qiang 	 */
5595632d15cSZhao Qiang 	if (!firmware->split) {
5605632d15cSZhao Qiang 		out_be16(&qe_immr->cp.cercr,
5615632d15cSZhao Qiang 			 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
5625632d15cSZhao Qiang 	}
5635632d15cSZhao Qiang 
5645632d15cSZhao Qiang 	if (firmware->soc.model)
5655632d15cSZhao Qiang 		printf("Firmware '%s' for %u V%u.%u\n",
5665632d15cSZhao Qiang 		       firmware->id, be16_to_cpu(firmware->soc.model),
5675632d15cSZhao Qiang 		       firmware->soc.major, firmware->soc.minor);
5685632d15cSZhao Qiang 	else
5695632d15cSZhao Qiang 		printf("Firmware '%s'\n", firmware->id);
5705632d15cSZhao Qiang 
5715632d15cSZhao Qiang 	/* Loop through each microcode. */
5725632d15cSZhao Qiang 	for (i = 0; i < firmware->count; i++) {
5735632d15cSZhao Qiang 		const struct qe_microcode *ucode = &firmware->microcode[i];
5745632d15cSZhao Qiang 
5755632d15cSZhao Qiang 		/* Upload a microcode if it's present */
5765632d15cSZhao Qiang 		if (ucode->code_offset)
5775632d15cSZhao Qiang 			qe_upload_microcode(firmware, ucode);
5785632d15cSZhao Qiang 
5795632d15cSZhao Qiang 		/* Program the traps for this processor */
5805632d15cSZhao Qiang 		for (j = 0; j < 16; j++) {
5815632d15cSZhao Qiang 			u32 trap = be32_to_cpu(ucode->traps[j]);
5825632d15cSZhao Qiang 
5835632d15cSZhao Qiang 			if (trap)
5845632d15cSZhao Qiang 				out_be32(&qe_immr->rsp[i].tibcr[j], trap);
5855632d15cSZhao Qiang 		}
5865632d15cSZhao Qiang 
5875632d15cSZhao Qiang 		/* Enable traps */
5885632d15cSZhao Qiang 		out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
5895632d15cSZhao Qiang 	}
5905632d15cSZhao Qiang 
5915632d15cSZhao Qiang 	return 0;
5925632d15cSZhao Qiang }
5935632d15cSZhao Qiang #endif
5945632d15cSZhao Qiang 
595*ae42eb03SZhao Qiang #ifdef CONFIG_U_QE
596*ae42eb03SZhao Qiang int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
597*ae42eb03SZhao Qiang {
598*ae42eb03SZhao Qiang 	unsigned int i;
599*ae42eb03SZhao Qiang 	unsigned int j;
600*ae42eb03SZhao Qiang 	const struct qe_header *hdr;
601*ae42eb03SZhao Qiang 	const u32 *code;
602*ae42eb03SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
603*ae42eb03SZhao Qiang #ifdef CONFIG_PPC
604*ae42eb03SZhao Qiang 	ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
605*ae42eb03SZhao Qiang #else
606*ae42eb03SZhao Qiang 	struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
607*ae42eb03SZhao Qiang #endif
608*ae42eb03SZhao Qiang #endif
609*ae42eb03SZhao Qiang 
610*ae42eb03SZhao Qiang 	if (!firmware)
611*ae42eb03SZhao Qiang 		return -EINVAL;
612*ae42eb03SZhao Qiang 
613*ae42eb03SZhao Qiang 	hdr = &firmware->header;
614*ae42eb03SZhao Qiang 
615*ae42eb03SZhao Qiang 	/* Check the magic */
616*ae42eb03SZhao Qiang 	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
617*ae42eb03SZhao Qiang 	    (hdr->magic[2] != 'F')) {
618*ae42eb03SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
619*ae42eb03SZhao Qiang 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
620*ae42eb03SZhao Qiang #endif
621*ae42eb03SZhao Qiang 		return -EPERM;
622*ae42eb03SZhao Qiang 	}
623*ae42eb03SZhao Qiang 
624*ae42eb03SZhao Qiang 	/*
625*ae42eb03SZhao Qiang 	 * If the microcode calls for it, split the I-RAM.
626*ae42eb03SZhao Qiang 	 */
627*ae42eb03SZhao Qiang 	if (!firmware->split) {
628*ae42eb03SZhao Qiang 		out_be16(&qe_immrr->cp.cercr,
629*ae42eb03SZhao Qiang 			 in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
630*ae42eb03SZhao Qiang 	}
631*ae42eb03SZhao Qiang 
632*ae42eb03SZhao Qiang 	/* Loop through each microcode. */
633*ae42eb03SZhao Qiang 	for (i = 0; i < firmware->count; i++) {
634*ae42eb03SZhao Qiang 		const struct qe_microcode *ucode = &firmware->microcode[i];
635*ae42eb03SZhao Qiang 
636*ae42eb03SZhao Qiang 		/* Upload a microcode if it's present */
637*ae42eb03SZhao Qiang 		if (!ucode->code_offset)
638*ae42eb03SZhao Qiang 			return 0;
639*ae42eb03SZhao Qiang 
640*ae42eb03SZhao Qiang 		code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
641*ae42eb03SZhao Qiang 
642*ae42eb03SZhao Qiang 		/* Use auto-increment */
643*ae42eb03SZhao Qiang 		out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
644*ae42eb03SZhao Qiang 			QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
645*ae42eb03SZhao Qiang 
646*ae42eb03SZhao Qiang 		for (i = 0; i < be32_to_cpu(ucode->count); i++)
647*ae42eb03SZhao Qiang 			out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
648*ae42eb03SZhao Qiang 
649*ae42eb03SZhao Qiang 		/* Program the traps for this processor */
650*ae42eb03SZhao Qiang 		for (j = 0; j < 16; j++) {
651*ae42eb03SZhao Qiang 			u32 trap = be32_to_cpu(ucode->traps[j]);
652*ae42eb03SZhao Qiang 
653*ae42eb03SZhao Qiang 			if (trap)
654*ae42eb03SZhao Qiang 				out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
655*ae42eb03SZhao Qiang 		}
656*ae42eb03SZhao Qiang 
657*ae42eb03SZhao Qiang 		/* Enable traps */
658*ae42eb03SZhao Qiang 		out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
659*ae42eb03SZhao Qiang 	}
660*ae42eb03SZhao Qiang 
661*ae42eb03SZhao Qiang 	return 0;
662*ae42eb03SZhao Qiang }
663*ae42eb03SZhao Qiang #endif
664*ae42eb03SZhao Qiang 
665b8ec2385STimur Tabi struct qe_firmware_info *qe_get_firmware_info(void)
666b8ec2385STimur Tabi {
667b8ec2385STimur Tabi 	return qe_firmware_uploaded ? &qe_firmware_info : NULL;
668b8ec2385STimur Tabi }
669b8ec2385STimur Tabi 
67054841ab5SWolfgang Denk static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
671b8ec2385STimur Tabi {
672b8ec2385STimur Tabi 	ulong addr;
673b8ec2385STimur Tabi 
67447e26b1bSWolfgang Denk 	if (argc < 3)
67547e26b1bSWolfgang Denk 		return cmd_usage(cmdtp);
676b8ec2385STimur Tabi 
677b8ec2385STimur Tabi 	if (strcmp(argv[1], "fw") == 0) {
678b8ec2385STimur Tabi 		addr = simple_strtoul(argv[2], NULL, 16);
679b8ec2385STimur Tabi 
680b8ec2385STimur Tabi 		if (!addr) {
681b8ec2385STimur Tabi 			printf("Invalid address\n");
682b8ec2385STimur Tabi 			return -EINVAL;
683b8ec2385STimur Tabi 		}
684b8ec2385STimur Tabi 
685b8ec2385STimur Tabi 		/*
686b8ec2385STimur Tabi 		 * If a length was supplied, compare that with the 'length'
687b8ec2385STimur Tabi 		 * field.
688b8ec2385STimur Tabi 		 */
689b8ec2385STimur Tabi 
690b8ec2385STimur Tabi 		if (argc > 3) {
691b8ec2385STimur Tabi 			ulong length = simple_strtoul(argv[3], NULL, 16);
692b8ec2385STimur Tabi 			struct qe_firmware *firmware = (void *) addr;
693b8ec2385STimur Tabi 
694b8ec2385STimur Tabi 			if (length != be32_to_cpu(firmware->header.length)) {
695b8ec2385STimur Tabi 				printf("Length mismatch\n");
696b8ec2385STimur Tabi 				return -EINVAL;
697b8ec2385STimur Tabi 			}
698b8ec2385STimur Tabi 		}
699b8ec2385STimur Tabi 
700b8ec2385STimur Tabi 		return qe_upload_firmware((const struct qe_firmware *) addr);
701b8ec2385STimur Tabi 	}
702b8ec2385STimur Tabi 
70347e26b1bSWolfgang Denk 	return cmd_usage(cmdtp);
704b8ec2385STimur Tabi }
705b8ec2385STimur Tabi 
706b8ec2385STimur Tabi U_BOOT_CMD(
707b8ec2385STimur Tabi 	qe, 4, 0, qe_cmd,
7082fb2604dSPeter Tyser 	"QUICC Engine commands",
709b8ec2385STimur Tabi 	"fw <addr> [<length>] - Upload firmware binary at address <addr> to "
710a89c33dbSWolfgang Denk 		"the QE,\n"
711a89c33dbSWolfgang Denk 	"\twith optional length <length> verification."
712b8ec2385STimur Tabi );
713