xref: /rk3399_rockchip-uboot/drivers/qe/qe.c (revision 1206c18403ff25814673a4dbfa071ae06bbefaef)
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  *
77737d5c6SDave Liu  * This program is free software; you can redistribute it and/or
87737d5c6SDave Liu  * modify it under the terms of the GNU General Public License as
97737d5c6SDave Liu  * published by the Free Software Foundation; either version 2 of
107737d5c6SDave Liu  * the License, or (at your option) any later version.
117737d5c6SDave Liu  *
127737d5c6SDave Liu  * This program is distributed in the hope that it will be useful,
137737d5c6SDave Liu  * but WITHOUT ANY WARRANTY; without even the implied warranty of
147737d5c6SDave Liu  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
157737d5c6SDave Liu  * GNU General Public License for more details.
167737d5c6SDave Liu  *
177737d5c6SDave Liu  * You should have received a copy of the GNU General Public License
187737d5c6SDave Liu  * along with this program; if not, write to the Free Software
197737d5c6SDave Liu  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
207737d5c6SDave Liu  * MA 02111-1307 USA
217737d5c6SDave Liu  */
227737d5c6SDave Liu 
237737d5c6SDave Liu #include "common.h"
24b8ec2385STimur Tabi #include <command.h>
257737d5c6SDave Liu #include "asm/errno.h"
267737d5c6SDave Liu #include "asm/io.h"
277737d5c6SDave Liu #include "asm/immap_qe.h"
287737d5c6SDave Liu #include "qe.h"
297737d5c6SDave Liu 
307737d5c6SDave Liu qe_map_t		*qe_immr = NULL;
317737d5c6SDave Liu static qe_snum_t	snums[QE_NUM_OF_SNUM];
327737d5c6SDave Liu 
331218abf1SWolfgang Denk DECLARE_GLOBAL_DATA_PTR;
341218abf1SWolfgang Denk 
357737d5c6SDave Liu void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
367737d5c6SDave Liu {
377737d5c6SDave Liu 	u32 cecr;
387737d5c6SDave Liu 
397737d5c6SDave Liu 	if (cmd == QE_RESET) {
407737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG));
417737d5c6SDave Liu 	} else {
427737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecdr, cmd_data);
437737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
447737d5c6SDave Liu 			 ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd));
457737d5c6SDave Liu 	}
467737d5c6SDave Liu 	/* Wait for the QE_CR_FLG to clear */
477737d5c6SDave Liu 	do {
487737d5c6SDave Liu 		cecr = in_be32(&qe_immr->cp.cecr);
497737d5c6SDave Liu 	} while (cecr & QE_CR_FLG);
507737d5c6SDave Liu 
517737d5c6SDave Liu 	return;
527737d5c6SDave Liu }
537737d5c6SDave Liu 
547737d5c6SDave Liu uint qe_muram_alloc(uint size, uint align)
557737d5c6SDave Liu {
567737d5c6SDave Liu 	uint	retloc;
577737d5c6SDave Liu 	uint	align_mask, off;
587737d5c6SDave Liu 	uint	savebase;
597737d5c6SDave Liu 
607737d5c6SDave Liu 	align_mask = align - 1;
617737d5c6SDave Liu 	savebase = gd->mp_alloc_base;
627737d5c6SDave Liu 
637737d5c6SDave Liu 	if ((off = (gd->mp_alloc_base & align_mask)) != 0)
647737d5c6SDave Liu 		gd->mp_alloc_base += (align - off);
657737d5c6SDave Liu 
667737d5c6SDave Liu 	if ((off = size & align_mask) != 0)
677737d5c6SDave Liu 		size += (align - off);
687737d5c6SDave Liu 
697737d5c6SDave Liu 	if ((gd->mp_alloc_base + size) >= gd->mp_alloc_top) {
707737d5c6SDave Liu 		gd->mp_alloc_base = savebase;
717737d5c6SDave Liu 		printf("%s: ran out of ram.\n",  __FUNCTION__);
727737d5c6SDave Liu 	}
737737d5c6SDave Liu 
747737d5c6SDave Liu 	retloc = gd->mp_alloc_base;
757737d5c6SDave Liu 	gd->mp_alloc_base += size;
767737d5c6SDave Liu 
777737d5c6SDave Liu 	memset((void *)&qe_immr->muram[retloc], 0, size);
787737d5c6SDave Liu 
797737d5c6SDave Liu 	__asm__ __volatile__("sync");
807737d5c6SDave Liu 
817737d5c6SDave Liu 	return retloc;
827737d5c6SDave Liu }
837737d5c6SDave Liu 
847737d5c6SDave Liu void *qe_muram_addr(uint offset)
857737d5c6SDave Liu {
867737d5c6SDave Liu 	return (void *)&qe_immr->muram[offset];
877737d5c6SDave Liu }
887737d5c6SDave Liu 
897737d5c6SDave Liu static void qe_sdma_init(void)
907737d5c6SDave Liu {
917737d5c6SDave Liu 	volatile sdma_t	*p;
927737d5c6SDave Liu 	uint		sdma_buffer_base;
937737d5c6SDave Liu 
947737d5c6SDave Liu 	p = (volatile sdma_t *)&qe_immr->sdma;
957737d5c6SDave Liu 
967737d5c6SDave Liu 	/* All of DMA transaction in bus 1 */
977737d5c6SDave Liu 	out_be32(&p->sdaqr, 0);
987737d5c6SDave Liu 	out_be32(&p->sdaqmr, 0);
997737d5c6SDave Liu 
1007737d5c6SDave Liu 	/* Allocate 2KB temporary buffer for sdma */
101ff9658d7SDave Liu 	sdma_buffer_base = qe_muram_alloc(2048, 4096);
1027737d5c6SDave Liu 	out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
1037737d5c6SDave Liu 
1047737d5c6SDave Liu 	/* Clear sdma status */
1057737d5c6SDave Liu 	out_be32(&p->sdsr, 0x03000000);
1067737d5c6SDave Liu 
1077737d5c6SDave Liu 	/* Enable global mode on bus 1, and 2KB buffer size */
1087737d5c6SDave Liu 	out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
1097737d5c6SDave Liu }
1107737d5c6SDave Liu 
1114e7b25e4SHaiying Wang /* This table is a list of the serial numbers of the Threads, taken from the
1124e7b25e4SHaiying Wang  * "SNUM Table" chart in the QE Reference Manual. The order is not important,
1134e7b25e4SHaiying Wang  * we just need to know what the SNUMs are for the threads.
1144e7b25e4SHaiying Wang  */
1154e7b25e4SHaiying Wang static u8 thread_snum[] = {
116a88731a6SGerlando Falauto /* Evthreads 16-29 are not supported in MPC8309 */
117a88731a6SGerlando Falauto #if !defined(CONFIG_MPC8309)
1187737d5c6SDave Liu 	0x04, 0x05, 0x0c, 0x0d,
1197737d5c6SDave Liu 	0x14, 0x15, 0x1c, 0x1d,
1207737d5c6SDave Liu 	0x24, 0x25, 0x2c, 0x2d,
121a88731a6SGerlando Falauto 	0x34, 0x35,
122a88731a6SGerlando Falauto #endif
123a88731a6SGerlando Falauto 	0x88, 0x89, 0x98, 0x99,
124a88731a6SGerlando Falauto 	0xa8, 0xa9, 0xb8, 0xb9,
125a88731a6SGerlando Falauto 	0xc8, 0xc9, 0xd8, 0xd9,
126a88731a6SGerlando Falauto 	0xe8, 0xe9, 0x08, 0x09,
127a88731a6SGerlando Falauto 	0x18, 0x19, 0x28, 0x29,
128a88731a6SGerlando Falauto 	0x38, 0x39, 0x48, 0x49,
129a88731a6SGerlando Falauto 	0x58, 0x59, 0x68, 0x69,
130a88731a6SGerlando Falauto 	0x78, 0x79, 0x80, 0x81
1317737d5c6SDave Liu };
1327737d5c6SDave Liu 
1337737d5c6SDave Liu static void qe_snums_init(void)
1347737d5c6SDave Liu {
1357737d5c6SDave Liu 	int	i;
1367737d5c6SDave Liu 
1377737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1387737d5c6SDave Liu 		snums[i].state = QE_SNUM_STATE_FREE;
1397737d5c6SDave Liu 		snums[i].num   = thread_snum[i];
1407737d5c6SDave Liu 	}
1417737d5c6SDave Liu }
1427737d5c6SDave Liu 
1437737d5c6SDave Liu int qe_get_snum(void)
1447737d5c6SDave Liu {
1457737d5c6SDave Liu 	int	snum = -EBUSY;
1467737d5c6SDave Liu 	int	i;
1477737d5c6SDave Liu 
1487737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1497737d5c6SDave Liu 		if (snums[i].state == QE_SNUM_STATE_FREE) {
1507737d5c6SDave Liu 			snums[i].state = QE_SNUM_STATE_USED;
1517737d5c6SDave Liu 			snum = snums[i].num;
1527737d5c6SDave Liu 			break;
1537737d5c6SDave Liu 		}
1547737d5c6SDave Liu 	}
1557737d5c6SDave Liu 
1567737d5c6SDave Liu 	return snum;
1577737d5c6SDave Liu }
1587737d5c6SDave Liu 
1597737d5c6SDave Liu void qe_put_snum(u8 snum)
1607737d5c6SDave Liu {
1617737d5c6SDave Liu 	int	i;
1627737d5c6SDave Liu 
1637737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1647737d5c6SDave Liu 		if (snums[i].num == snum) {
1657737d5c6SDave Liu 			snums[i].state = QE_SNUM_STATE_FREE;
1667737d5c6SDave Liu 			break;
1677737d5c6SDave Liu 		}
1687737d5c6SDave Liu 	}
1697737d5c6SDave Liu }
1707737d5c6SDave Liu 
1717737d5c6SDave Liu void qe_init(uint qe_base)
1727737d5c6SDave Liu {
1737737d5c6SDave Liu 	/* Init the QE IMMR base */
1747737d5c6SDave Liu 	qe_immr = (qe_map_t *)qe_base;
1757737d5c6SDave Liu 
176f2717b47STimur Tabi #ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
177c0a14aedSWolfgang Denk 	/*
178c0a14aedSWolfgang Denk 	 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
1792d4de6aeSHaiying Wang 	 */
180f2717b47STimur Tabi 	qe_upload_firmware((const void *)CONFIG_SYS_QE_FMAN_FW_ADDR);
1812d4de6aeSHaiying Wang 
1822d4de6aeSHaiying Wang 	/* enable the microcode in IRAM */
1832d4de6aeSHaiying Wang 	out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
1842d4de6aeSHaiying Wang #endif
1852d4de6aeSHaiying Wang 
1867737d5c6SDave Liu 	gd->mp_alloc_base = QE_DATAONLY_BASE;
1877737d5c6SDave Liu 	gd->mp_alloc_top = gd->mp_alloc_base + QE_DATAONLY_SIZE;
1887737d5c6SDave Liu 
1897737d5c6SDave Liu 	qe_sdma_init();
1907737d5c6SDave Liu 	qe_snums_init();
1917737d5c6SDave Liu }
1927737d5c6SDave Liu 
1937737d5c6SDave Liu void qe_reset(void)
1947737d5c6SDave Liu {
1957737d5c6SDave Liu 	qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
1967737d5c6SDave Liu 			 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
1977737d5c6SDave Liu }
1987737d5c6SDave Liu 
1997737d5c6SDave Liu void qe_assign_page(uint snum, uint para_ram_base)
2007737d5c6SDave Liu {
2017737d5c6SDave Liu 	u32	cecr;
2027737d5c6SDave Liu 
2037737d5c6SDave Liu 	out_be32(&qe_immr->cp.cecdr, para_ram_base);
2047737d5c6SDave Liu 	out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
2057737d5c6SDave Liu 					 | QE_CR_FLG | QE_ASSIGN_PAGE);
2067737d5c6SDave Liu 
2077737d5c6SDave Liu 	/* Wait for the QE_CR_FLG to clear */
2087737d5c6SDave Liu 	do {
2097737d5c6SDave Liu 		cecr = in_be32(&qe_immr->cp.cecr);
2107737d5c6SDave Liu 	} while (cecr & QE_CR_FLG );
2117737d5c6SDave Liu 
2127737d5c6SDave Liu 	return;
2137737d5c6SDave Liu }
2147737d5c6SDave Liu 
2157737d5c6SDave Liu /*
2167737d5c6SDave Liu  * brg: 0~15 as BRG1~BRG16
2177737d5c6SDave Liu    rate: baud rate
2187737d5c6SDave Liu  * BRG input clock comes from the BRGCLK (internal clock generated from
2197737d5c6SDave Liu    the QE clock, it is one-half of the QE clock), If need the clock source
2207737d5c6SDave Liu    from CLKn pin, we have te change the function.
2217737d5c6SDave Liu  */
2227737d5c6SDave Liu 
223*1206c184SSimon Glass #define BRG_CLK		(gd->arch.brg_clk)
2247737d5c6SDave Liu 
2257737d5c6SDave Liu int qe_set_brg(uint brg, uint rate)
2267737d5c6SDave Liu {
2277737d5c6SDave Liu 	volatile uint	*bp;
2287737d5c6SDave Liu 	u32		divisor;
2297737d5c6SDave Liu 	int		div16 = 0;
2307737d5c6SDave Liu 
2317737d5c6SDave Liu 	if (brg >= QE_NUM_OF_BRGS)
2327737d5c6SDave Liu 		return -EINVAL;
2337737d5c6SDave Liu 	bp = (uint *)&qe_immr->brg.brgc1;
2347737d5c6SDave Liu 	bp += brg;
2357737d5c6SDave Liu 
2367737d5c6SDave Liu 	divisor = (BRG_CLK / rate);
2377737d5c6SDave Liu 	if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
2387737d5c6SDave Liu 		div16 = 1;
2397737d5c6SDave Liu 		divisor /= 16;
2407737d5c6SDave Liu 	}
2417737d5c6SDave Liu 
2427737d5c6SDave Liu 	*bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
2437737d5c6SDave Liu 	__asm__ __volatile__("sync");
2447737d5c6SDave Liu 
2457737d5c6SDave Liu 	if (div16) {
2467737d5c6SDave Liu 		*bp |= QE_BRGC_DIV16;
2477737d5c6SDave Liu 		__asm__ __volatile__("sync");
2487737d5c6SDave Liu 	}
2497737d5c6SDave Liu 
2507737d5c6SDave Liu 	return 0;
2517737d5c6SDave Liu }
2527737d5c6SDave Liu 
2537737d5c6SDave Liu /* Set ethernet MII clock master
2547737d5c6SDave Liu */
2557737d5c6SDave Liu int qe_set_mii_clk_src(int ucc_num)
2567737d5c6SDave Liu {
2577737d5c6SDave Liu 	u32	cmxgcr;
2587737d5c6SDave Liu 
2597737d5c6SDave Liu 	/* check if the UCC number is in range. */
2607737d5c6SDave Liu 	if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
2617737d5c6SDave Liu 		printf("%s: ucc num not in ranges\n", __FUNCTION__);
2627737d5c6SDave Liu 		return -EINVAL;
2637737d5c6SDave Liu 	}
2647737d5c6SDave Liu 
2657737d5c6SDave Liu 	cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
2667737d5c6SDave Liu 	cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
2677737d5c6SDave Liu 	cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
2687737d5c6SDave Liu 	out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
2697737d5c6SDave Liu 
2707737d5c6SDave Liu 	return 0;
2717737d5c6SDave Liu }
2727737d5c6SDave Liu 
273b8ec2385STimur Tabi /* Firmware information stored here for qe_get_firmware_info() */
274b8ec2385STimur Tabi static struct qe_firmware_info qe_firmware_info;
275b8ec2385STimur Tabi 
276b8ec2385STimur Tabi /*
277b8ec2385STimur Tabi  * Set to 1 if QE firmware has been uploaded, and therefore
278b8ec2385STimur Tabi  * qe_firmware_info contains valid data.
279b8ec2385STimur Tabi  */
280b8ec2385STimur Tabi static int qe_firmware_uploaded;
281b8ec2385STimur Tabi 
282b8ec2385STimur Tabi /*
283b8ec2385STimur Tabi  * Upload a QE microcode
284b8ec2385STimur Tabi  *
285b8ec2385STimur Tabi  * This function is a worker function for qe_upload_firmware().  It does
286b8ec2385STimur Tabi  * the actual uploading of the microcode.
287b8ec2385STimur Tabi  */
288b8ec2385STimur Tabi static void qe_upload_microcode(const void *base,
289b8ec2385STimur Tabi 	const struct qe_microcode *ucode)
290b8ec2385STimur Tabi {
291b8ec2385STimur Tabi 	const u32 *code = base + be32_to_cpu(ucode->code_offset);
292b8ec2385STimur Tabi 	unsigned int i;
293b8ec2385STimur Tabi 
294b8ec2385STimur Tabi 	if (ucode->major || ucode->minor || ucode->revision)
295b8ec2385STimur Tabi 		printf("QE: uploading microcode '%s' version %u.%u.%u\n",
296b8ec2385STimur Tabi 			ucode->id, ucode->major, ucode->minor, ucode->revision);
297b8ec2385STimur Tabi 	else
298b8ec2385STimur Tabi 		printf("QE: uploading microcode '%s'\n", ucode->id);
299b8ec2385STimur Tabi 
300b8ec2385STimur Tabi 	/* Use auto-increment */
301b8ec2385STimur Tabi 	out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
302b8ec2385STimur Tabi 		QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
303b8ec2385STimur Tabi 
304b8ec2385STimur Tabi 	for (i = 0; i < be32_to_cpu(ucode->count); i++)
305b8ec2385STimur Tabi 		out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
306b8ec2385STimur Tabi }
307b8ec2385STimur Tabi 
308b8ec2385STimur Tabi /*
309b8ec2385STimur Tabi  * Upload a microcode to the I-RAM at a specific address.
310b8ec2385STimur Tabi  *
311b8ec2385STimur Tabi  * See docs/README.qe_firmware for information on QE microcode uploading.
312b8ec2385STimur Tabi  *
313b8ec2385STimur Tabi  * Currently, only version 1 is supported, so the 'version' field must be
314b8ec2385STimur Tabi  * set to 1.
315b8ec2385STimur Tabi  *
316b8ec2385STimur Tabi  * The SOC model and revision are not validated, they are only displayed for
317b8ec2385STimur Tabi  * informational purposes.
318b8ec2385STimur Tabi  *
319b8ec2385STimur Tabi  * 'calc_size' is the calculated size, in bytes, of the firmware structure and
320b8ec2385STimur Tabi  * all of the microcode structures, minus the CRC.
321b8ec2385STimur Tabi  *
322b8ec2385STimur Tabi  * 'length' is the size that the structure says it is, including the CRC.
323b8ec2385STimur Tabi  */
324b8ec2385STimur Tabi int qe_upload_firmware(const struct qe_firmware *firmware)
325b8ec2385STimur Tabi {
326b8ec2385STimur Tabi 	unsigned int i;
327b8ec2385STimur Tabi 	unsigned int j;
328b8ec2385STimur Tabi 	u32 crc;
329b8ec2385STimur Tabi 	size_t calc_size = sizeof(struct qe_firmware);
330b8ec2385STimur Tabi 	size_t length;
331b8ec2385STimur Tabi 	const struct qe_header *hdr;
332b8ec2385STimur Tabi 
333b8ec2385STimur Tabi 	if (!firmware) {
334b8ec2385STimur Tabi 		printf("Invalid address\n");
335b8ec2385STimur Tabi 		return -EINVAL;
336b8ec2385STimur Tabi 	}
337b8ec2385STimur Tabi 
338b8ec2385STimur Tabi 	hdr = &firmware->header;
339b8ec2385STimur Tabi 	length = be32_to_cpu(hdr->length);
340b8ec2385STimur Tabi 
341b8ec2385STimur Tabi 	/* Check the magic */
342b8ec2385STimur Tabi 	if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
343b8ec2385STimur Tabi 	    (hdr->magic[2] != 'F')) {
344b8ec2385STimur Tabi 		printf("Not a microcode\n");
345b8ec2385STimur Tabi 		return -EPERM;
346b8ec2385STimur Tabi 	}
347b8ec2385STimur Tabi 
348b8ec2385STimur Tabi 	/* Check the version */
349b8ec2385STimur Tabi 	if (hdr->version != 1) {
350b8ec2385STimur Tabi 		printf("Unsupported version\n");
351b8ec2385STimur Tabi 		return -EPERM;
352b8ec2385STimur Tabi 	}
353b8ec2385STimur Tabi 
354b8ec2385STimur Tabi 	/* Validate some of the fields */
355491fb6deSTimur Tabi 	if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
356b8ec2385STimur Tabi 		printf("Invalid data\n");
357b8ec2385STimur Tabi 		return -EINVAL;
358b8ec2385STimur Tabi 	}
359b8ec2385STimur Tabi 
360b8ec2385STimur Tabi 	/* Validate the length and check if there's a CRC */
361b8ec2385STimur Tabi 	calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
362b8ec2385STimur Tabi 
363b8ec2385STimur Tabi 	for (i = 0; i < firmware->count; i++)
364b8ec2385STimur Tabi 		/*
365b8ec2385STimur Tabi 		 * For situations where the second RISC uses the same microcode
366b8ec2385STimur Tabi 		 * as the first, the 'code_offset' and 'count' fields will be
367b8ec2385STimur Tabi 		 * zero, so it's okay to add those.
368b8ec2385STimur Tabi 		 */
369b8ec2385STimur Tabi 		calc_size += sizeof(u32) *
370b8ec2385STimur Tabi 			be32_to_cpu(firmware->microcode[i].count);
371b8ec2385STimur Tabi 
372b8ec2385STimur Tabi 	/* Validate the length */
373b8ec2385STimur Tabi 	if (length != calc_size + sizeof(u32)) {
374b8ec2385STimur Tabi 		printf("Invalid length\n");
375b8ec2385STimur Tabi 		return -EPERM;
376b8ec2385STimur Tabi 	}
377b8ec2385STimur Tabi 
378b8ec2385STimur Tabi 	/*
379b8ec2385STimur Tabi 	 * Validate the CRC.  We would normally call crc32_no_comp(), but that
380b8ec2385STimur Tabi 	 * function isn't available unless you turn on JFFS support.
381b8ec2385STimur Tabi 	 */
382b8ec2385STimur Tabi 	crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
383b8ec2385STimur Tabi 	if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
384b8ec2385STimur Tabi 		printf("Firmware CRC is invalid\n");
385b8ec2385STimur Tabi 		return -EIO;
386b8ec2385STimur Tabi 	}
387b8ec2385STimur Tabi 
388b8ec2385STimur Tabi 	/*
389b8ec2385STimur Tabi 	 * If the microcode calls for it, split the I-RAM.
390b8ec2385STimur Tabi 	 */
391b8ec2385STimur Tabi 	if (!firmware->split) {
392b8ec2385STimur Tabi 		out_be16(&qe_immr->cp.cercr,
393b8ec2385STimur Tabi 			in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
394b8ec2385STimur Tabi 	}
395b8ec2385STimur Tabi 
396b8ec2385STimur Tabi 	if (firmware->soc.model)
397b8ec2385STimur Tabi 		printf("Firmware '%s' for %u V%u.%u\n",
398b8ec2385STimur Tabi 			firmware->id, be16_to_cpu(firmware->soc.model),
399b8ec2385STimur Tabi 			firmware->soc.major, firmware->soc.minor);
400b8ec2385STimur Tabi 	else
401b8ec2385STimur Tabi 		printf("Firmware '%s'\n", firmware->id);
402b8ec2385STimur Tabi 
403b8ec2385STimur Tabi 	/*
404b8ec2385STimur Tabi 	 * The QE only supports one microcode per RISC, so clear out all the
405b8ec2385STimur Tabi 	 * saved microcode information and put in the new.
406b8ec2385STimur Tabi 	 */
407b8ec2385STimur Tabi 	memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
40806c428bcSDave Liu 	strcpy(qe_firmware_info.id, (char *)firmware->id);
409b8ec2385STimur Tabi 	qe_firmware_info.extended_modes = firmware->extended_modes;
410b8ec2385STimur Tabi 	memcpy(qe_firmware_info.vtraps, firmware->vtraps,
411b8ec2385STimur Tabi 		sizeof(firmware->vtraps));
412b8ec2385STimur Tabi 	qe_firmware_uploaded = 1;
413b8ec2385STimur Tabi 
414b8ec2385STimur Tabi 	/* Loop through each microcode. */
415b8ec2385STimur Tabi 	for (i = 0; i < firmware->count; i++) {
416b8ec2385STimur Tabi 		const struct qe_microcode *ucode = &firmware->microcode[i];
417b8ec2385STimur Tabi 
418b8ec2385STimur Tabi 		/* Upload a microcode if it's present */
419b8ec2385STimur Tabi 		if (ucode->code_offset)
420b8ec2385STimur Tabi 			qe_upload_microcode(firmware, ucode);
421b8ec2385STimur Tabi 
422b8ec2385STimur Tabi 		/* Program the traps for this processor */
423b8ec2385STimur Tabi 		for (j = 0; j < 16; j++) {
424b8ec2385STimur Tabi 			u32 trap = be32_to_cpu(ucode->traps[j]);
425b8ec2385STimur Tabi 
426b8ec2385STimur Tabi 			if (trap)
427b8ec2385STimur Tabi 				out_be32(&qe_immr->rsp[i].tibcr[j], trap);
428b8ec2385STimur Tabi 		}
429b8ec2385STimur Tabi 
430b8ec2385STimur Tabi 		/* Enable traps */
431b8ec2385STimur Tabi 		out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
432b8ec2385STimur Tabi 	}
433b8ec2385STimur Tabi 
434b8ec2385STimur Tabi 	return 0;
435b8ec2385STimur Tabi }
436b8ec2385STimur Tabi 
437b8ec2385STimur Tabi struct qe_firmware_info *qe_get_firmware_info(void)
438b8ec2385STimur Tabi {
439b8ec2385STimur Tabi 	return qe_firmware_uploaded ? &qe_firmware_info : NULL;
440b8ec2385STimur Tabi }
441b8ec2385STimur Tabi 
44254841ab5SWolfgang Denk static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
443b8ec2385STimur Tabi {
444b8ec2385STimur Tabi 	ulong addr;
445b8ec2385STimur Tabi 
44647e26b1bSWolfgang Denk 	if (argc < 3)
44747e26b1bSWolfgang Denk 		return cmd_usage(cmdtp);
448b8ec2385STimur Tabi 
449b8ec2385STimur Tabi 	if (strcmp(argv[1], "fw") == 0) {
450b8ec2385STimur Tabi 		addr = simple_strtoul(argv[2], NULL, 16);
451b8ec2385STimur Tabi 
452b8ec2385STimur Tabi 		if (!addr) {
453b8ec2385STimur Tabi 			printf("Invalid address\n");
454b8ec2385STimur Tabi 			return -EINVAL;
455b8ec2385STimur Tabi 		}
456b8ec2385STimur Tabi 
457b8ec2385STimur Tabi 		/*
458b8ec2385STimur Tabi 		 * If a length was supplied, compare that with the 'length'
459b8ec2385STimur Tabi 		 * field.
460b8ec2385STimur Tabi 		 */
461b8ec2385STimur Tabi 
462b8ec2385STimur Tabi 		if (argc > 3) {
463b8ec2385STimur Tabi 			ulong length = simple_strtoul(argv[3], NULL, 16);
464b8ec2385STimur Tabi 			struct qe_firmware *firmware = (void *) addr;
465b8ec2385STimur Tabi 
466b8ec2385STimur Tabi 			if (length != be32_to_cpu(firmware->header.length)) {
467b8ec2385STimur Tabi 				printf("Length mismatch\n");
468b8ec2385STimur Tabi 				return -EINVAL;
469b8ec2385STimur Tabi 			}
470b8ec2385STimur Tabi 		}
471b8ec2385STimur Tabi 
472b8ec2385STimur Tabi 		return qe_upload_firmware((const struct qe_firmware *) addr);
473b8ec2385STimur Tabi 	}
474b8ec2385STimur Tabi 
47547e26b1bSWolfgang Denk 	return cmd_usage(cmdtp);
476b8ec2385STimur Tabi }
477b8ec2385STimur Tabi 
478b8ec2385STimur Tabi U_BOOT_CMD(
479b8ec2385STimur Tabi 	qe, 4, 0, qe_cmd,
4802fb2604dSPeter Tyser 	"QUICC Engine commands",
481b8ec2385STimur Tabi 	"fw <addr> [<length>] - Upload firmware binary at address <addr> to "
482a89c33dbSWolfgang Denk 		"the QE,\n"
483a89c33dbSWolfgang Denk 	"\twith optional length <length> verification."
484b8ec2385STimur Tabi );
485