xref: /rk3399_rockchip-uboot/drivers/qe/qe.c (revision 3bf46e6a6de71a31be05545d59819ca73e367ddc)
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"
152459afb1SQianyu Gong #include <fsl_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;
23*3bf46e6aSZhao Qiang #ifdef CONFIG_QE
247737d5c6SDave Liu static qe_snum_t	snums[QE_NUM_OF_SNUM];
25*3bf46e6aSZhao Qiang #endif
267737d5c6SDave Liu 
271218abf1SWolfgang Denk DECLARE_GLOBAL_DATA_PTR;
281218abf1SWolfgang Denk 
297737d5c6SDave Liu void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
307737d5c6SDave Liu {
317737d5c6SDave Liu 	u32 cecr;
327737d5c6SDave Liu 
337737d5c6SDave Liu 	if (cmd == QE_RESET) {
347737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG));
357737d5c6SDave Liu 	} else {
367737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecdr, cmd_data);
377737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
387737d5c6SDave Liu 			 ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd));
397737d5c6SDave Liu 	}
407737d5c6SDave Liu 	/* Wait for the QE_CR_FLG to clear */
417737d5c6SDave Liu 	do {
427737d5c6SDave Liu 		cecr = in_be32(&qe_immr->cp.cecr);
437737d5c6SDave Liu 	} while (cecr & QE_CR_FLG);
447737d5c6SDave Liu 
457737d5c6SDave Liu 	return;
467737d5c6SDave Liu }
477737d5c6SDave Liu 
4893d33204SZhao Qiang #ifdef CONFIG_QE
497737d5c6SDave Liu uint qe_muram_alloc(uint size, uint align)
507737d5c6SDave Liu {
517737d5c6SDave Liu 	uint	retloc;
527737d5c6SDave Liu 	uint	align_mask, off;
537737d5c6SDave Liu 	uint	savebase;
547737d5c6SDave Liu 
557737d5c6SDave Liu 	align_mask = align - 1;
5645bae2e3SSimon Glass 	savebase = gd->arch.mp_alloc_base;
577737d5c6SDave Liu 
5845bae2e3SSimon Glass 	off = gd->arch.mp_alloc_base & align_mask;
5945bae2e3SSimon Glass 	if (off != 0)
6045bae2e3SSimon Glass 		gd->arch.mp_alloc_base += (align - off);
617737d5c6SDave Liu 
627737d5c6SDave Liu 	if ((off = size & align_mask) != 0)
637737d5c6SDave Liu 		size += (align - off);
647737d5c6SDave Liu 
6545bae2e3SSimon Glass 	if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
6645bae2e3SSimon Glass 		gd->arch.mp_alloc_base = savebase;
677737d5c6SDave Liu 		printf("%s: ran out of ram.\n",  __FUNCTION__);
687737d5c6SDave Liu 	}
697737d5c6SDave Liu 
7045bae2e3SSimon Glass 	retloc = gd->arch.mp_alloc_base;
7145bae2e3SSimon Glass 	gd->arch.mp_alloc_base += size;
727737d5c6SDave Liu 
737737d5c6SDave Liu 	memset((void *)&qe_immr->muram[retloc], 0, size);
747737d5c6SDave Liu 
757737d5c6SDave Liu 	__asm__ __volatile__("sync");
767737d5c6SDave Liu 
777737d5c6SDave Liu 	return retloc;
787737d5c6SDave Liu }
7993d33204SZhao Qiang #endif
807737d5c6SDave Liu 
817737d5c6SDave Liu void *qe_muram_addr(uint offset)
827737d5c6SDave Liu {
837737d5c6SDave Liu 	return (void *)&qe_immr->muram[offset];
847737d5c6SDave Liu }
857737d5c6SDave Liu 
86*3bf46e6aSZhao Qiang #ifdef CONFIG_QE
877737d5c6SDave Liu static void qe_sdma_init(void)
887737d5c6SDave Liu {
897737d5c6SDave Liu 	volatile sdma_t	*p;
907737d5c6SDave Liu 	uint		sdma_buffer_base;
917737d5c6SDave Liu 
927737d5c6SDave Liu 	p = (volatile sdma_t *)&qe_immr->sdma;
937737d5c6SDave Liu 
947737d5c6SDave Liu 	/* All of DMA transaction in bus 1 */
957737d5c6SDave Liu 	out_be32(&p->sdaqr, 0);
967737d5c6SDave Liu 	out_be32(&p->sdaqmr, 0);
977737d5c6SDave Liu 
987737d5c6SDave Liu 	/* Allocate 2KB temporary buffer for sdma */
99ff9658d7SDave Liu 	sdma_buffer_base = qe_muram_alloc(2048, 4096);
1007737d5c6SDave Liu 	out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
1017737d5c6SDave Liu 
1027737d5c6SDave Liu 	/* Clear sdma status */
1037737d5c6SDave Liu 	out_be32(&p->sdsr, 0x03000000);
1047737d5c6SDave Liu 
1057737d5c6SDave Liu 	/* Enable global mode on bus 1, and 2KB buffer size */
1067737d5c6SDave Liu 	out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
1077737d5c6SDave Liu }
1087737d5c6SDave Liu 
1094e7b25e4SHaiying Wang /* This table is a list of the serial numbers of the Threads, taken from the
1104e7b25e4SHaiying Wang  * "SNUM Table" chart in the QE Reference Manual. The order is not important,
1114e7b25e4SHaiying Wang  * we just need to know what the SNUMs are for the threads.
1124e7b25e4SHaiying Wang  */
1134e7b25e4SHaiying Wang static u8 thread_snum[] = {
114a88731a6SGerlando Falauto /* Evthreads 16-29 are not supported in MPC8309 */
115a88731a6SGerlando Falauto #if !defined(CONFIG_MPC8309)
1167737d5c6SDave Liu 	0x04, 0x05, 0x0c, 0x0d,
1177737d5c6SDave Liu 	0x14, 0x15, 0x1c, 0x1d,
1187737d5c6SDave Liu 	0x24, 0x25, 0x2c, 0x2d,
119a88731a6SGerlando Falauto 	0x34, 0x35,
120a88731a6SGerlando Falauto #endif
121a88731a6SGerlando Falauto 	0x88, 0x89, 0x98, 0x99,
122a88731a6SGerlando Falauto 	0xa8, 0xa9, 0xb8, 0xb9,
123a88731a6SGerlando Falauto 	0xc8, 0xc9, 0xd8, 0xd9,
124a88731a6SGerlando Falauto 	0xe8, 0xe9, 0x08, 0x09,
125a88731a6SGerlando Falauto 	0x18, 0x19, 0x28, 0x29,
126a88731a6SGerlando Falauto 	0x38, 0x39, 0x48, 0x49,
127a88731a6SGerlando Falauto 	0x58, 0x59, 0x68, 0x69,
128a88731a6SGerlando Falauto 	0x78, 0x79, 0x80, 0x81
1297737d5c6SDave Liu };
1307737d5c6SDave Liu 
1317737d5c6SDave Liu static void qe_snums_init(void)
1327737d5c6SDave Liu {
1337737d5c6SDave Liu 	int	i;
1347737d5c6SDave Liu 
1357737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1367737d5c6SDave Liu 		snums[i].state = QE_SNUM_STATE_FREE;
1377737d5c6SDave Liu 		snums[i].num   = thread_snum[i];
1387737d5c6SDave Liu 	}
1397737d5c6SDave Liu }
1407737d5c6SDave Liu 
1417737d5c6SDave Liu int qe_get_snum(void)
1427737d5c6SDave Liu {
1437737d5c6SDave Liu 	int	snum = -EBUSY;
1447737d5c6SDave Liu 	int	i;
1457737d5c6SDave Liu 
1467737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1477737d5c6SDave Liu 		if (snums[i].state == QE_SNUM_STATE_FREE) {
1487737d5c6SDave Liu 			snums[i].state = QE_SNUM_STATE_USED;
1497737d5c6SDave Liu 			snum = snums[i].num;
1507737d5c6SDave Liu 			break;
1517737d5c6SDave Liu 		}
1527737d5c6SDave Liu 	}
1537737d5c6SDave Liu 
1547737d5c6SDave Liu 	return snum;
1557737d5c6SDave Liu }
1567737d5c6SDave Liu 
1577737d5c6SDave Liu void qe_put_snum(u8 snum)
1587737d5c6SDave Liu {
1597737d5c6SDave Liu 	int	i;
1607737d5c6SDave Liu 
1617737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1627737d5c6SDave Liu 		if (snums[i].num == snum) {
1637737d5c6SDave Liu 			snums[i].state = QE_SNUM_STATE_FREE;
1647737d5c6SDave Liu 			break;
1657737d5c6SDave Liu 		}
1667737d5c6SDave Liu 	}
1677737d5c6SDave Liu }
1687737d5c6SDave Liu 
1697737d5c6SDave Liu void qe_init(uint qe_base)
1707737d5c6SDave Liu {
1717737d5c6SDave Liu 	/* Init the QE IMMR base */
1727737d5c6SDave Liu 	qe_immr = (qe_map_t *)qe_base;
1737737d5c6SDave Liu 
174f2717b47STimur Tabi #ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
175c0a14aedSWolfgang Denk 	/*
176c0a14aedSWolfgang Denk 	 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
1772d4de6aeSHaiying Wang 	 */
178dcf1d774SZhao Qiang 	qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
1792d4de6aeSHaiying Wang 
1802d4de6aeSHaiying Wang 	/* enable the microcode in IRAM */
1812d4de6aeSHaiying Wang 	out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
1822d4de6aeSHaiying Wang #endif
1832d4de6aeSHaiying Wang 
18445bae2e3SSimon Glass 	gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
18545bae2e3SSimon Glass 	gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
1867737d5c6SDave Liu 
1877737d5c6SDave Liu 	qe_sdma_init();
1887737d5c6SDave Liu 	qe_snums_init();
1897737d5c6SDave Liu }
190*3bf46e6aSZhao Qiang #endif
1917737d5c6SDave Liu 
19293d33204SZhao Qiang #ifdef CONFIG_U_QE
19393d33204SZhao Qiang void u_qe_init(void)
19493d33204SZhao Qiang {
19593d33204SZhao Qiang 	uint qe_base = CONFIG_SYS_IMMR + 0x01400000; /* QE immr base */
19693d33204SZhao Qiang 	qe_immr = (qe_map_t *)qe_base;
19793d33204SZhao Qiang 
1985632d15cSZhao Qiang 	u_qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
19993d33204SZhao Qiang 	out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
20093d33204SZhao Qiang }
20193d33204SZhao Qiang #endif
20293d33204SZhao Qiang 
203ae42eb03SZhao Qiang #ifdef CONFIG_U_QE
204ae42eb03SZhao Qiang void u_qe_resume(void)
205ae42eb03SZhao Qiang {
206ae42eb03SZhao Qiang 	qe_map_t *qe_immrr;
207ae42eb03SZhao Qiang 	uint qe_base = CONFIG_SYS_IMMR + QE_IMMR_OFFSET; /* QE immr base */
208ae42eb03SZhao Qiang 	qe_immrr = (qe_map_t *)qe_base;
209ae42eb03SZhao Qiang 
210ae42eb03SZhao Qiang 	u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr);
211ae42eb03SZhao Qiang 	out_be32(&qe_immrr->iram.iready, QE_IRAM_READY);
212ae42eb03SZhao Qiang }
213ae42eb03SZhao Qiang #endif
214ae42eb03SZhao Qiang 
2157737d5c6SDave Liu void qe_reset(void)
2167737d5c6SDave Liu {
2177737d5c6SDave Liu 	qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
2187737d5c6SDave Liu 			 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
2197737d5c6SDave Liu }
2207737d5c6SDave Liu 
221*3bf46e6aSZhao Qiang #ifdef CONFIG_QE
2227737d5c6SDave Liu void qe_assign_page(uint snum, uint para_ram_base)
2237737d5c6SDave Liu {
2247737d5c6SDave Liu 	u32	cecr;
2257737d5c6SDave Liu 
2267737d5c6SDave Liu 	out_be32(&qe_immr->cp.cecdr, para_ram_base);
2277737d5c6SDave Liu 	out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
2287737d5c6SDave Liu 					 | QE_CR_FLG | QE_ASSIGN_PAGE);
2297737d5c6SDave Liu 
2307737d5c6SDave Liu 	/* Wait for the QE_CR_FLG to clear */
2317737d5c6SDave Liu 	do {
2327737d5c6SDave Liu 		cecr = in_be32(&qe_immr->cp.cecr);
2337737d5c6SDave Liu 	} while (cecr & QE_CR_FLG );
2347737d5c6SDave Liu 
2357737d5c6SDave Liu 	return;
2367737d5c6SDave Liu }
237*3bf46e6aSZhao Qiang #endif
2387737d5c6SDave Liu 
2397737d5c6SDave Liu /*
2407737d5c6SDave Liu  * brg: 0~15 as BRG1~BRG16
2417737d5c6SDave Liu    rate: baud rate
2427737d5c6SDave Liu  * BRG input clock comes from the BRGCLK (internal clock generated from
2437737d5c6SDave Liu    the QE clock, it is one-half of the QE clock), If need the clock source
2447737d5c6SDave Liu    from CLKn pin, we have te change the function.
2457737d5c6SDave Liu  */
2467737d5c6SDave Liu 
2471206c184SSimon Glass #define BRG_CLK		(gd->arch.brg_clk)
2487737d5c6SDave Liu 
24993d33204SZhao Qiang #ifdef CONFIG_QE
2507737d5c6SDave Liu int qe_set_brg(uint brg, uint rate)
2517737d5c6SDave Liu {
2527737d5c6SDave Liu 	volatile uint	*bp;
2537737d5c6SDave Liu 	u32		divisor;
2547737d5c6SDave Liu 	int		div16 = 0;
2557737d5c6SDave Liu 
2567737d5c6SDave Liu 	if (brg >= QE_NUM_OF_BRGS)
2577737d5c6SDave Liu 		return -EINVAL;
2587737d5c6SDave Liu 	bp = (uint *)&qe_immr->brg.brgc1;
2597737d5c6SDave Liu 	bp += brg;
2607737d5c6SDave Liu 
2617737d5c6SDave Liu 	divisor = (BRG_CLK / rate);
2627737d5c6SDave Liu 	if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
2637737d5c6SDave Liu 		div16 = 1;
2647737d5c6SDave Liu 		divisor /= 16;
2657737d5c6SDave Liu 	}
2667737d5c6SDave Liu 
2677737d5c6SDave Liu 	*bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
2687737d5c6SDave Liu 	__asm__ __volatile__("sync");
2697737d5c6SDave Liu 
2707737d5c6SDave Liu 	if (div16) {
2717737d5c6SDave Liu 		*bp |= QE_BRGC_DIV16;
2727737d5c6SDave Liu 		__asm__ __volatile__("sync");
2737737d5c6SDave Liu 	}
2747737d5c6SDave Liu 
2757737d5c6SDave Liu 	return 0;
2767737d5c6SDave Liu }
27793d33204SZhao Qiang #endif
2787737d5c6SDave Liu 
2797737d5c6SDave Liu /* Set ethernet MII clock master
2807737d5c6SDave Liu */
2817737d5c6SDave Liu int qe_set_mii_clk_src(int ucc_num)
2827737d5c6SDave Liu {
2837737d5c6SDave Liu 	u32	cmxgcr;
2847737d5c6SDave Liu 
2857737d5c6SDave Liu 	/* check if the UCC number is in range. */
2867737d5c6SDave Liu 	if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
2877737d5c6SDave Liu 		printf("%s: ucc num not in ranges\n", __FUNCTION__);
2887737d5c6SDave Liu 		return -EINVAL;
2897737d5c6SDave Liu 	}
2907737d5c6SDave Liu 
2917737d5c6SDave Liu 	cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
2927737d5c6SDave Liu 	cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
2937737d5c6SDave Liu 	cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
2947737d5c6SDave Liu 	out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
2957737d5c6SDave Liu 
2967737d5c6SDave Liu 	return 0;
2977737d5c6SDave Liu }
2987737d5c6SDave Liu 
299b8ec2385STimur Tabi /* Firmware information stored here for qe_get_firmware_info() */
300b8ec2385STimur Tabi static struct qe_firmware_info qe_firmware_info;
301b8ec2385STimur Tabi 
302b8ec2385STimur Tabi /*
303b8ec2385STimur Tabi  * Set to 1 if QE firmware has been uploaded, and therefore
304b8ec2385STimur Tabi  * qe_firmware_info contains valid data.
305b8ec2385STimur Tabi  */
306b8ec2385STimur Tabi static int qe_firmware_uploaded;
307b8ec2385STimur Tabi 
308b8ec2385STimur Tabi /*
309b8ec2385STimur Tabi  * Upload a QE microcode
310b8ec2385STimur Tabi  *
311b8ec2385STimur Tabi  * This function is a worker function for qe_upload_firmware().  It does
312b8ec2385STimur Tabi  * the actual uploading of the microcode.
313b8ec2385STimur Tabi  */
314b8ec2385STimur Tabi static void qe_upload_microcode(const void *base,
315b8ec2385STimur Tabi 	const struct qe_microcode *ucode)
316b8ec2385STimur Tabi {
317b8ec2385STimur Tabi 	const u32 *code = base + be32_to_cpu(ucode->code_offset);
318b8ec2385STimur Tabi 	unsigned int i;
319b8ec2385STimur Tabi 
320b8ec2385STimur Tabi 	if (ucode->major || ucode->minor || ucode->revision)
321b8ec2385STimur Tabi 		printf("QE: uploading microcode '%s' version %u.%u.%u\n",
322e94a8fd3SZhao Qiang 		       (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
323e94a8fd3SZhao Qiang 		       (u16)ucode->revision);
324b8ec2385STimur Tabi 	else
325e94a8fd3SZhao Qiang 		printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
326b8ec2385STimur Tabi 
327b8ec2385STimur Tabi 	/* Use auto-increment */
328b8ec2385STimur Tabi 	out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
329b8ec2385STimur Tabi 		QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
330b8ec2385STimur Tabi 
331b8ec2385STimur Tabi 	for (i = 0; i < be32_to_cpu(ucode->count); i++)
332b8ec2385STimur Tabi 		out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
333b8ec2385STimur Tabi }
334b8ec2385STimur Tabi 
335b8ec2385STimur Tabi /*
336b8ec2385STimur Tabi  * Upload a microcode to the I-RAM at a specific address.
337b8ec2385STimur Tabi  *
338b8ec2385STimur Tabi  * See docs/README.qe_firmware for information on QE microcode uploading.
339b8ec2385STimur Tabi  *
340b8ec2385STimur Tabi  * Currently, only version 1 is supported, so the 'version' field must be
341b8ec2385STimur Tabi  * set to 1.
342b8ec2385STimur Tabi  *
343b8ec2385STimur Tabi  * The SOC model and revision are not validated, they are only displayed for
344b8ec2385STimur Tabi  * informational purposes.
345b8ec2385STimur Tabi  *
346b8ec2385STimur Tabi  * 'calc_size' is the calculated size, in bytes, of the firmware structure and
347b8ec2385STimur Tabi  * all of the microcode structures, minus the CRC.
348b8ec2385STimur Tabi  *
349b8ec2385STimur Tabi  * 'length' is the size that the structure says it is, including the CRC.
350b8ec2385STimur Tabi  */
351b8ec2385STimur Tabi int qe_upload_firmware(const struct qe_firmware *firmware)
352b8ec2385STimur Tabi {
353b8ec2385STimur Tabi 	unsigned int i;
354b8ec2385STimur Tabi 	unsigned int j;
355b8ec2385STimur Tabi 	u32 crc;
356b8ec2385STimur Tabi 	size_t calc_size = sizeof(struct qe_firmware);
357b8ec2385STimur Tabi 	size_t length;
358b8ec2385STimur Tabi 	const struct qe_header *hdr;
359ca721fb2SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
3609c7c86f4SZhao Qiang #ifdef CONFIG_LS102XA
3619c7c86f4SZhao Qiang 	struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
3629c7c86f4SZhao Qiang #else
363ca721fb2SZhao Qiang 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
364ca721fb2SZhao Qiang #endif
3659c7c86f4SZhao Qiang #endif
366b8ec2385STimur Tabi 	if (!firmware) {
367b8ec2385STimur Tabi 		printf("Invalid address\n");
368b8ec2385STimur Tabi 		return -EINVAL;
369b8ec2385STimur Tabi 	}
370b8ec2385STimur Tabi 
371b8ec2385STimur Tabi 	hdr = &firmware->header;
372b8ec2385STimur Tabi 	length = be32_to_cpu(hdr->length);
373b8ec2385STimur Tabi 
374b8ec2385STimur Tabi 	/* Check the magic */
375b8ec2385STimur Tabi 	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
376b8ec2385STimur Tabi 	    (hdr->magic[2] != 'F')) {
37712eeb135SVijay Rai 		printf("QE microcode not found\n");
378ca721fb2SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
379ca721fb2SZhao Qiang 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
380ca721fb2SZhao Qiang #endif
381b8ec2385STimur Tabi 		return -EPERM;
382b8ec2385STimur Tabi 	}
383b8ec2385STimur Tabi 
384b8ec2385STimur Tabi 	/* Check the version */
385b8ec2385STimur Tabi 	if (hdr->version != 1) {
386b8ec2385STimur Tabi 		printf("Unsupported version\n");
387b8ec2385STimur Tabi 		return -EPERM;
388b8ec2385STimur Tabi 	}
389b8ec2385STimur Tabi 
390b8ec2385STimur Tabi 	/* Validate some of the fields */
391491fb6deSTimur Tabi 	if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
392b8ec2385STimur Tabi 		printf("Invalid data\n");
393b8ec2385STimur Tabi 		return -EINVAL;
394b8ec2385STimur Tabi 	}
395b8ec2385STimur Tabi 
396b8ec2385STimur Tabi 	/* Validate the length and check if there's a CRC */
397b8ec2385STimur Tabi 	calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
398b8ec2385STimur Tabi 
399b8ec2385STimur Tabi 	for (i = 0; i < firmware->count; i++)
400b8ec2385STimur Tabi 		/*
401b8ec2385STimur Tabi 		 * For situations where the second RISC uses the same microcode
402b8ec2385STimur Tabi 		 * as the first, the 'code_offset' and 'count' fields will be
403b8ec2385STimur Tabi 		 * zero, so it's okay to add those.
404b8ec2385STimur Tabi 		 */
405b8ec2385STimur Tabi 		calc_size += sizeof(u32) *
406b8ec2385STimur Tabi 			be32_to_cpu(firmware->microcode[i].count);
407b8ec2385STimur Tabi 
408b8ec2385STimur Tabi 	/* Validate the length */
409b8ec2385STimur Tabi 	if (length != calc_size + sizeof(u32)) {
410b8ec2385STimur Tabi 		printf("Invalid length\n");
411b8ec2385STimur Tabi 		return -EPERM;
412b8ec2385STimur Tabi 	}
413b8ec2385STimur Tabi 
414b8ec2385STimur Tabi 	/*
415b8ec2385STimur Tabi 	 * Validate the CRC.  We would normally call crc32_no_comp(), but that
416b8ec2385STimur Tabi 	 * function isn't available unless you turn on JFFS support.
417b8ec2385STimur Tabi 	 */
418b8ec2385STimur Tabi 	crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
419b8ec2385STimur Tabi 	if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
420b8ec2385STimur Tabi 		printf("Firmware CRC is invalid\n");
421b8ec2385STimur Tabi 		return -EIO;
422b8ec2385STimur Tabi 	}
423b8ec2385STimur Tabi 
424b8ec2385STimur Tabi 	/*
425b8ec2385STimur Tabi 	 * If the microcode calls for it, split the I-RAM.
426b8ec2385STimur Tabi 	 */
427b8ec2385STimur Tabi 	if (!firmware->split) {
428b8ec2385STimur Tabi 		out_be16(&qe_immr->cp.cercr,
429b8ec2385STimur Tabi 			in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
430b8ec2385STimur Tabi 	}
431b8ec2385STimur Tabi 
432b8ec2385STimur Tabi 	if (firmware->soc.model)
433b8ec2385STimur Tabi 		printf("Firmware '%s' for %u V%u.%u\n",
434b8ec2385STimur Tabi 			firmware->id, be16_to_cpu(firmware->soc.model),
435b8ec2385STimur Tabi 			firmware->soc.major, firmware->soc.minor);
436b8ec2385STimur Tabi 	else
437b8ec2385STimur Tabi 		printf("Firmware '%s'\n", firmware->id);
438b8ec2385STimur Tabi 
439b8ec2385STimur Tabi 	/*
440b8ec2385STimur Tabi 	 * The QE only supports one microcode per RISC, so clear out all the
441b8ec2385STimur Tabi 	 * saved microcode information and put in the new.
442b8ec2385STimur Tabi 	 */
443b8ec2385STimur Tabi 	memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
4440e0224eeSZhao Qiang 	strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
445b8ec2385STimur Tabi 	qe_firmware_info.extended_modes = firmware->extended_modes;
446b8ec2385STimur Tabi 	memcpy(qe_firmware_info.vtraps, firmware->vtraps,
447b8ec2385STimur Tabi 		sizeof(firmware->vtraps));
448b8ec2385STimur Tabi 	qe_firmware_uploaded = 1;
449b8ec2385STimur Tabi 
450b8ec2385STimur Tabi 	/* Loop through each microcode. */
451b8ec2385STimur Tabi 	for (i = 0; i < firmware->count; i++) {
452b8ec2385STimur Tabi 		const struct qe_microcode *ucode = &firmware->microcode[i];
453b8ec2385STimur Tabi 
454b8ec2385STimur Tabi 		/* Upload a microcode if it's present */
455b8ec2385STimur Tabi 		if (ucode->code_offset)
456b8ec2385STimur Tabi 			qe_upload_microcode(firmware, ucode);
457b8ec2385STimur Tabi 
458b8ec2385STimur Tabi 		/* Program the traps for this processor */
459b8ec2385STimur Tabi 		for (j = 0; j < 16; j++) {
460b8ec2385STimur Tabi 			u32 trap = be32_to_cpu(ucode->traps[j]);
461b8ec2385STimur Tabi 
462b8ec2385STimur Tabi 			if (trap)
463b8ec2385STimur Tabi 				out_be32(&qe_immr->rsp[i].tibcr[j], trap);
464b8ec2385STimur Tabi 		}
465b8ec2385STimur Tabi 
466b8ec2385STimur Tabi 		/* Enable traps */
467b8ec2385STimur Tabi 		out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
468b8ec2385STimur Tabi 	}
469b8ec2385STimur Tabi 
470b8ec2385STimur Tabi 	return 0;
471b8ec2385STimur Tabi }
472b8ec2385STimur Tabi 
4735632d15cSZhao Qiang #ifdef CONFIG_U_QE
4745632d15cSZhao Qiang /*
4755632d15cSZhao Qiang  * Upload a microcode to the I-RAM at a specific address.
4765632d15cSZhao Qiang  *
4775632d15cSZhao Qiang  * See docs/README.qe_firmware for information on QE microcode uploading.
4785632d15cSZhao Qiang  *
4795632d15cSZhao Qiang  * Currently, only version 1 is supported, so the 'version' field must be
4805632d15cSZhao Qiang  * set to 1.
4815632d15cSZhao Qiang  *
4825632d15cSZhao Qiang  * The SOC model and revision are not validated, they are only displayed for
4835632d15cSZhao Qiang  * informational purposes.
4845632d15cSZhao Qiang  *
4855632d15cSZhao Qiang  * 'calc_size' is the calculated size, in bytes, of the firmware structure and
4865632d15cSZhao Qiang  * all of the microcode structures, minus the CRC.
4875632d15cSZhao Qiang  *
4885632d15cSZhao Qiang  * 'length' is the size that the structure says it is, including the CRC.
4895632d15cSZhao Qiang  */
4905632d15cSZhao Qiang int u_qe_upload_firmware(const struct qe_firmware *firmware)
4915632d15cSZhao Qiang {
4925632d15cSZhao Qiang 	unsigned int i;
4935632d15cSZhao Qiang 	unsigned int j;
4945632d15cSZhao Qiang 	u32 crc;
4955632d15cSZhao Qiang 	size_t calc_size = sizeof(struct qe_firmware);
4965632d15cSZhao Qiang 	size_t length;
4975632d15cSZhao Qiang 	const struct qe_header *hdr;
4985632d15cSZhao Qiang #ifdef CONFIG_DEEP_SLEEP
4999c7c86f4SZhao Qiang #ifdef CONFIG_LS102XA
5009c7c86f4SZhao Qiang 	struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
5019c7c86f4SZhao Qiang #else
5025632d15cSZhao Qiang 	ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
5035632d15cSZhao Qiang #endif
5049c7c86f4SZhao Qiang #endif
5055632d15cSZhao Qiang 	if (!firmware) {
5065632d15cSZhao Qiang 		printf("Invalid address\n");
5075632d15cSZhao Qiang 		return -EINVAL;
5085632d15cSZhao Qiang 	}
5095632d15cSZhao Qiang 
5105632d15cSZhao Qiang 	hdr = &firmware->header;
5115632d15cSZhao Qiang 	length = be32_to_cpu(hdr->length);
5125632d15cSZhao Qiang 
5135632d15cSZhao Qiang 	/* Check the magic */
5145632d15cSZhao Qiang 	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
5155632d15cSZhao Qiang 	    (hdr->magic[2] != 'F')) {
5165632d15cSZhao Qiang 		printf("Not a microcode\n");
5175632d15cSZhao Qiang #ifdef CONFIG_DEEP_SLEEP
5185632d15cSZhao Qiang 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
5195632d15cSZhao Qiang #endif
5205632d15cSZhao Qiang 		return -EPERM;
5215632d15cSZhao Qiang 	}
5225632d15cSZhao Qiang 
5235632d15cSZhao Qiang 	/* Check the version */
5245632d15cSZhao Qiang 	if (hdr->version != 1) {
5255632d15cSZhao Qiang 		printf("Unsupported version\n");
5265632d15cSZhao Qiang 		return -EPERM;
5275632d15cSZhao Qiang 	}
5285632d15cSZhao Qiang 
5295632d15cSZhao Qiang 	/* Validate some of the fields */
5305632d15cSZhao Qiang 	if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
5315632d15cSZhao Qiang 		printf("Invalid data\n");
5325632d15cSZhao Qiang 		return -EINVAL;
5335632d15cSZhao Qiang 	}
5345632d15cSZhao Qiang 
5355632d15cSZhao Qiang 	/* Validate the length and check if there's a CRC */
5365632d15cSZhao Qiang 	calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
5375632d15cSZhao Qiang 
5385632d15cSZhao Qiang 	for (i = 0; i < firmware->count; i++)
5395632d15cSZhao Qiang 		/*
5405632d15cSZhao Qiang 		 * For situations where the second RISC uses the same microcode
5415632d15cSZhao Qiang 		 * as the first, the 'code_offset' and 'count' fields will be
5425632d15cSZhao Qiang 		 * zero, so it's okay to add those.
5435632d15cSZhao Qiang 		 */
5445632d15cSZhao Qiang 		calc_size += sizeof(u32) *
5455632d15cSZhao Qiang 			be32_to_cpu(firmware->microcode[i].count);
5465632d15cSZhao Qiang 
5475632d15cSZhao Qiang 	/* Validate the length */
5485632d15cSZhao Qiang 	if (length != calc_size + sizeof(u32)) {
5495632d15cSZhao Qiang 		printf("Invalid length\n");
5505632d15cSZhao Qiang 		return -EPERM;
5515632d15cSZhao Qiang 	}
5525632d15cSZhao Qiang 
5535632d15cSZhao Qiang 	/*
5545632d15cSZhao Qiang 	 * Validate the CRC.  We would normally call crc32_no_comp(), but that
5555632d15cSZhao Qiang 	 * function isn't available unless you turn on JFFS support.
5565632d15cSZhao Qiang 	 */
5575632d15cSZhao Qiang 	crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
5585632d15cSZhao Qiang 	if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
5595632d15cSZhao Qiang 		printf("Firmware CRC is invalid\n");
5605632d15cSZhao Qiang 		return -EIO;
5615632d15cSZhao Qiang 	}
5625632d15cSZhao Qiang 
5635632d15cSZhao Qiang 	/*
5645632d15cSZhao Qiang 	 * If the microcode calls for it, split the I-RAM.
5655632d15cSZhao Qiang 	 */
5665632d15cSZhao Qiang 	if (!firmware->split) {
5675632d15cSZhao Qiang 		out_be16(&qe_immr->cp.cercr,
5685632d15cSZhao Qiang 			 in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
5695632d15cSZhao Qiang 	}
5705632d15cSZhao Qiang 
5715632d15cSZhao Qiang 	if (firmware->soc.model)
5725632d15cSZhao Qiang 		printf("Firmware '%s' for %u V%u.%u\n",
5735632d15cSZhao Qiang 		       firmware->id, be16_to_cpu(firmware->soc.model),
5745632d15cSZhao Qiang 		       firmware->soc.major, firmware->soc.minor);
5755632d15cSZhao Qiang 	else
5765632d15cSZhao Qiang 		printf("Firmware '%s'\n", firmware->id);
5775632d15cSZhao Qiang 
5785632d15cSZhao Qiang 	/* Loop through each microcode. */
5795632d15cSZhao Qiang 	for (i = 0; i < firmware->count; i++) {
5805632d15cSZhao Qiang 		const struct qe_microcode *ucode = &firmware->microcode[i];
5815632d15cSZhao Qiang 
5825632d15cSZhao Qiang 		/* Upload a microcode if it's present */
5835632d15cSZhao Qiang 		if (ucode->code_offset)
5845632d15cSZhao Qiang 			qe_upload_microcode(firmware, ucode);
5855632d15cSZhao Qiang 
5865632d15cSZhao Qiang 		/* Program the traps for this processor */
5875632d15cSZhao Qiang 		for (j = 0; j < 16; j++) {
5885632d15cSZhao Qiang 			u32 trap = be32_to_cpu(ucode->traps[j]);
5895632d15cSZhao Qiang 
5905632d15cSZhao Qiang 			if (trap)
5915632d15cSZhao Qiang 				out_be32(&qe_immr->rsp[i].tibcr[j], trap);
5925632d15cSZhao Qiang 		}
5935632d15cSZhao Qiang 
5945632d15cSZhao Qiang 		/* Enable traps */
5955632d15cSZhao Qiang 		out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
5965632d15cSZhao Qiang 	}
5975632d15cSZhao Qiang 
5985632d15cSZhao Qiang 	return 0;
5995632d15cSZhao Qiang }
6005632d15cSZhao Qiang #endif
6015632d15cSZhao Qiang 
602ae42eb03SZhao Qiang #ifdef CONFIG_U_QE
603ae42eb03SZhao Qiang int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
604ae42eb03SZhao Qiang {
605ae42eb03SZhao Qiang 	unsigned int i;
606ae42eb03SZhao Qiang 	unsigned int j;
607ae42eb03SZhao Qiang 	const struct qe_header *hdr;
608ae42eb03SZhao Qiang 	const u32 *code;
609ae42eb03SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
610ae42eb03SZhao Qiang #ifdef CONFIG_PPC
611ae42eb03SZhao Qiang 	ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
612ae42eb03SZhao Qiang #else
613ae42eb03SZhao Qiang 	struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
614ae42eb03SZhao Qiang #endif
615ae42eb03SZhao Qiang #endif
616ae42eb03SZhao Qiang 
617ae42eb03SZhao Qiang 	if (!firmware)
618ae42eb03SZhao Qiang 		return -EINVAL;
619ae42eb03SZhao Qiang 
620ae42eb03SZhao Qiang 	hdr = &firmware->header;
621ae42eb03SZhao Qiang 
622ae42eb03SZhao Qiang 	/* Check the magic */
623ae42eb03SZhao Qiang 	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
624ae42eb03SZhao Qiang 	    (hdr->magic[2] != 'F')) {
625ae42eb03SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
626ae42eb03SZhao Qiang 		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
627ae42eb03SZhao Qiang #endif
628ae42eb03SZhao Qiang 		return -EPERM;
629ae42eb03SZhao Qiang 	}
630ae42eb03SZhao Qiang 
631ae42eb03SZhao Qiang 	/*
632ae42eb03SZhao Qiang 	 * If the microcode calls for it, split the I-RAM.
633ae42eb03SZhao Qiang 	 */
634ae42eb03SZhao Qiang 	if (!firmware->split) {
635ae42eb03SZhao Qiang 		out_be16(&qe_immrr->cp.cercr,
636ae42eb03SZhao Qiang 			 in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
637ae42eb03SZhao Qiang 	}
638ae42eb03SZhao Qiang 
639ae42eb03SZhao Qiang 	/* Loop through each microcode. */
640ae42eb03SZhao Qiang 	for (i = 0; i < firmware->count; i++) {
641ae42eb03SZhao Qiang 		const struct qe_microcode *ucode = &firmware->microcode[i];
642ae42eb03SZhao Qiang 
643ae42eb03SZhao Qiang 		/* Upload a microcode if it's present */
644ae42eb03SZhao Qiang 		if (!ucode->code_offset)
645ae42eb03SZhao Qiang 			return 0;
646ae42eb03SZhao Qiang 
647ae42eb03SZhao Qiang 		code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
648ae42eb03SZhao Qiang 
649ae42eb03SZhao Qiang 		/* Use auto-increment */
650ae42eb03SZhao Qiang 		out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
651ae42eb03SZhao Qiang 			QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
652ae42eb03SZhao Qiang 
653ae42eb03SZhao Qiang 		for (i = 0; i < be32_to_cpu(ucode->count); i++)
654ae42eb03SZhao Qiang 			out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
655ae42eb03SZhao Qiang 
656ae42eb03SZhao Qiang 		/* Program the traps for this processor */
657ae42eb03SZhao Qiang 		for (j = 0; j < 16; j++) {
658ae42eb03SZhao Qiang 			u32 trap = be32_to_cpu(ucode->traps[j]);
659ae42eb03SZhao Qiang 
660ae42eb03SZhao Qiang 			if (trap)
661ae42eb03SZhao Qiang 				out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
662ae42eb03SZhao Qiang 		}
663ae42eb03SZhao Qiang 
664ae42eb03SZhao Qiang 		/* Enable traps */
665ae42eb03SZhao Qiang 		out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
666ae42eb03SZhao Qiang 	}
667ae42eb03SZhao Qiang 
668ae42eb03SZhao Qiang 	return 0;
669ae42eb03SZhao Qiang }
670ae42eb03SZhao Qiang #endif
671ae42eb03SZhao Qiang 
672b8ec2385STimur Tabi struct qe_firmware_info *qe_get_firmware_info(void)
673b8ec2385STimur Tabi {
674b8ec2385STimur Tabi 	return qe_firmware_uploaded ? &qe_firmware_info : NULL;
675b8ec2385STimur Tabi }
676b8ec2385STimur Tabi 
67754841ab5SWolfgang Denk static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
678b8ec2385STimur Tabi {
679b8ec2385STimur Tabi 	ulong addr;
680b8ec2385STimur Tabi 
68147e26b1bSWolfgang Denk 	if (argc < 3)
68247e26b1bSWolfgang Denk 		return cmd_usage(cmdtp);
683b8ec2385STimur Tabi 
684b8ec2385STimur Tabi 	if (strcmp(argv[1], "fw") == 0) {
685b8ec2385STimur Tabi 		addr = simple_strtoul(argv[2], NULL, 16);
686b8ec2385STimur Tabi 
687b8ec2385STimur Tabi 		if (!addr) {
688b8ec2385STimur Tabi 			printf("Invalid address\n");
689b8ec2385STimur Tabi 			return -EINVAL;
690b8ec2385STimur Tabi 		}
691b8ec2385STimur Tabi 
692b8ec2385STimur Tabi 		/*
693b8ec2385STimur Tabi 		 * If a length was supplied, compare that with the 'length'
694b8ec2385STimur Tabi 		 * field.
695b8ec2385STimur Tabi 		 */
696b8ec2385STimur Tabi 
697b8ec2385STimur Tabi 		if (argc > 3) {
698b8ec2385STimur Tabi 			ulong length = simple_strtoul(argv[3], NULL, 16);
699b8ec2385STimur Tabi 			struct qe_firmware *firmware = (void *) addr;
700b8ec2385STimur Tabi 
701b8ec2385STimur Tabi 			if (length != be32_to_cpu(firmware->header.length)) {
702b8ec2385STimur Tabi 				printf("Length mismatch\n");
703b8ec2385STimur Tabi 				return -EINVAL;
704b8ec2385STimur Tabi 			}
705b8ec2385STimur Tabi 		}
706b8ec2385STimur Tabi 
707b8ec2385STimur Tabi 		return qe_upload_firmware((const struct qe_firmware *) addr);
708b8ec2385STimur Tabi 	}
709b8ec2385STimur Tabi 
71047e26b1bSWolfgang Denk 	return cmd_usage(cmdtp);
711b8ec2385STimur Tabi }
712b8ec2385STimur Tabi 
713b8ec2385STimur Tabi U_BOOT_CMD(
714b8ec2385STimur Tabi 	qe, 4, 0, qe_cmd,
7152fb2604dSPeter Tyser 	"QUICC Engine commands",
716b8ec2385STimur Tabi 	"fw <addr> [<length>] - Upload firmware binary at address <addr> to "
717a89c33dbSWolfgang Denk 		"the QE,\n"
718a89c33dbSWolfgang Denk 	"\twith optional length <length> verification."
719b8ec2385STimur Tabi );
720