xref: /rk3399_rockchip-uboot/drivers/qe/qe.c (revision ff9658d7049bf8c8e8e0a05dbe5e9f7e91aa5a5d)
17737d5c6SDave Liu /*
27737d5c6SDave Liu  * Copyright (C) 2006 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"
247737d5c6SDave Liu #include "asm/errno.h"
257737d5c6SDave Liu #include "asm/io.h"
267737d5c6SDave Liu #include "asm/immap_qe.h"
277737d5c6SDave Liu #include "qe.h"
287737d5c6SDave Liu 
297737d5c6SDave Liu #if defined(CONFIG_QE)
307737d5c6SDave Liu qe_map_t		*qe_immr = NULL;
317737d5c6SDave Liu static qe_snum_t	snums[QE_NUM_OF_SNUM];
327737d5c6SDave Liu 
337737d5c6SDave Liu void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
347737d5c6SDave Liu {
357737d5c6SDave Liu 	u32           cecr;
367737d5c6SDave Liu 
377737d5c6SDave Liu 	if (cmd == QE_RESET) {
387737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG));
397737d5c6SDave Liu 	} else {
407737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecdr, cmd_data);
417737d5c6SDave Liu 		out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
427737d5c6SDave Liu 			 ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd));
437737d5c6SDave Liu 	}
447737d5c6SDave Liu 	/* Wait for the QE_CR_FLG to clear */
457737d5c6SDave Liu 	do {
467737d5c6SDave Liu 		cecr = in_be32(&qe_immr->cp.cecr);
477737d5c6SDave Liu 	} while (cecr & QE_CR_FLG);
487737d5c6SDave Liu 
497737d5c6SDave Liu 	return;
507737d5c6SDave Liu }
517737d5c6SDave Liu 
527737d5c6SDave Liu uint qe_muram_alloc(uint size, uint align)
537737d5c6SDave Liu {
547737d5c6SDave Liu 	DECLARE_GLOBAL_DATA_PTR;
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 */
101*ff9658d7SDave 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 
1117737d5c6SDave Liu static u8 thread_snum[QE_NUM_OF_SNUM] = {
1127737d5c6SDave Liu 	0x04, 0x05, 0x0c, 0x0d,
1137737d5c6SDave Liu 	0x14, 0x15, 0x1c, 0x1d,
1147737d5c6SDave Liu 	0x24, 0x25, 0x2c, 0x2d,
1157737d5c6SDave Liu 	0x34, 0x35, 0x88, 0x89,
1167737d5c6SDave Liu 	0x98, 0x99, 0xa8, 0xa9,
1177737d5c6SDave Liu 	0xb8, 0xb9, 0xc8, 0xc9,
1187737d5c6SDave Liu 	0xd8, 0xd9, 0xe8, 0xe9
1197737d5c6SDave Liu };
1207737d5c6SDave Liu 
1217737d5c6SDave Liu static void qe_snums_init(void)
1227737d5c6SDave Liu {
1237737d5c6SDave Liu 	int	i;
1247737d5c6SDave Liu 
1257737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1267737d5c6SDave Liu 		snums[i].state = QE_SNUM_STATE_FREE;
1277737d5c6SDave Liu 		snums[i].num   = thread_snum[i];
1287737d5c6SDave Liu 	}
1297737d5c6SDave Liu }
1307737d5c6SDave Liu 
1317737d5c6SDave Liu int qe_get_snum(void)
1327737d5c6SDave Liu {
1337737d5c6SDave Liu 	int	snum = -EBUSY;
1347737d5c6SDave Liu 	int	i;
1357737d5c6SDave Liu 
1367737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1377737d5c6SDave Liu 		if (snums[i].state == QE_SNUM_STATE_FREE) {
1387737d5c6SDave Liu 			snums[i].state = QE_SNUM_STATE_USED;
1397737d5c6SDave Liu 			snum = snums[i].num;
1407737d5c6SDave Liu 			break;
1417737d5c6SDave Liu 		}
1427737d5c6SDave Liu 	}
1437737d5c6SDave Liu 
1447737d5c6SDave Liu 	return snum;
1457737d5c6SDave Liu }
1467737d5c6SDave Liu 
1477737d5c6SDave Liu void qe_put_snum(u8 snum)
1487737d5c6SDave Liu {
1497737d5c6SDave Liu 	int	i;
1507737d5c6SDave Liu 
1517737d5c6SDave Liu 	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1527737d5c6SDave Liu 		if (snums[i].num == snum) {
1537737d5c6SDave Liu 			snums[i].state = QE_SNUM_STATE_FREE;
1547737d5c6SDave Liu 			break;
1557737d5c6SDave Liu 		}
1567737d5c6SDave Liu 	}
1577737d5c6SDave Liu }
1587737d5c6SDave Liu 
1597737d5c6SDave Liu void qe_init(uint qe_base)
1607737d5c6SDave Liu {
1617737d5c6SDave Liu 	DECLARE_GLOBAL_DATA_PTR;
1627737d5c6SDave Liu 
1637737d5c6SDave Liu 	/* Init the QE IMMR base */
1647737d5c6SDave Liu 	qe_immr = (qe_map_t *)qe_base;
1657737d5c6SDave Liu 
1667737d5c6SDave Liu 	gd->mp_alloc_base = QE_DATAONLY_BASE;
1677737d5c6SDave Liu 	gd->mp_alloc_top = gd->mp_alloc_base + QE_DATAONLY_SIZE;
1687737d5c6SDave Liu 
1697737d5c6SDave Liu 	qe_sdma_init();
1707737d5c6SDave Liu 	qe_snums_init();
1717737d5c6SDave Liu }
1727737d5c6SDave Liu 
1737737d5c6SDave Liu void qe_reset(void)
1747737d5c6SDave Liu {
1757737d5c6SDave Liu 	qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
1767737d5c6SDave Liu 			 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
1777737d5c6SDave Liu }
1787737d5c6SDave Liu 
1797737d5c6SDave Liu void qe_assign_page(uint snum, uint para_ram_base)
1807737d5c6SDave Liu {
1817737d5c6SDave Liu 	u32	cecr;
1827737d5c6SDave Liu 
1837737d5c6SDave Liu 	out_be32(&qe_immr->cp.cecdr, para_ram_base);
1847737d5c6SDave Liu 	out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
1857737d5c6SDave Liu 					 | QE_CR_FLG | QE_ASSIGN_PAGE);
1867737d5c6SDave Liu 
1877737d5c6SDave Liu 	/* Wait for the QE_CR_FLG to clear */
1887737d5c6SDave Liu 	do {
1897737d5c6SDave Liu 		cecr = in_be32(&qe_immr->cp.cecr);
1907737d5c6SDave Liu 	} while (cecr & QE_CR_FLG );
1917737d5c6SDave Liu 
1927737d5c6SDave Liu 	return;
1937737d5c6SDave Liu }
1947737d5c6SDave Liu 
1957737d5c6SDave Liu /*
1967737d5c6SDave Liu  * brg: 0~15 as BRG1~BRG16
1977737d5c6SDave Liu    rate: baud rate
1987737d5c6SDave Liu  * BRG input clock comes from the BRGCLK (internal clock generated from
1997737d5c6SDave Liu    the QE clock, it is one-half of the QE clock), If need the clock source
2007737d5c6SDave Liu    from CLKn pin, we have te change the function.
2017737d5c6SDave Liu  */
2027737d5c6SDave Liu 
2037737d5c6SDave Liu #define BRG_CLK		(gd->brg_clk)
2047737d5c6SDave Liu 
2057737d5c6SDave Liu int qe_set_brg(uint brg, uint rate)
2067737d5c6SDave Liu {
2077737d5c6SDave Liu 	DECLARE_GLOBAL_DATA_PTR;
2087737d5c6SDave Liu 	volatile uint	*bp;
2097737d5c6SDave Liu 	u32		divisor;
2107737d5c6SDave Liu 	int		div16 = 0;
2117737d5c6SDave Liu 
2127737d5c6SDave Liu 	if (brg >= QE_NUM_OF_BRGS)
2137737d5c6SDave Liu 		return -EINVAL;
2147737d5c6SDave Liu 	bp = (uint *)&qe_immr->brg.brgc1;
2157737d5c6SDave Liu 	bp += brg;
2167737d5c6SDave Liu 
2177737d5c6SDave Liu 	divisor = (BRG_CLK / rate);
2187737d5c6SDave Liu 	if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
2197737d5c6SDave Liu 		div16 = 1;
2207737d5c6SDave Liu 		divisor /= 16;
2217737d5c6SDave Liu 	}
2227737d5c6SDave Liu 
2237737d5c6SDave Liu 	*bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
2247737d5c6SDave Liu 	__asm__ __volatile__("sync");
2257737d5c6SDave Liu 
2267737d5c6SDave Liu 	if (div16) {
2277737d5c6SDave Liu 		*bp |= QE_BRGC_DIV16;
2287737d5c6SDave Liu 		__asm__ __volatile__("sync");
2297737d5c6SDave Liu 	}
2307737d5c6SDave Liu 
2317737d5c6SDave Liu 	return 0;
2327737d5c6SDave Liu }
2337737d5c6SDave Liu 
2347737d5c6SDave Liu /* Set ethernet MII clock master
2357737d5c6SDave Liu */
2367737d5c6SDave Liu int qe_set_mii_clk_src(int ucc_num)
2377737d5c6SDave Liu {
2387737d5c6SDave Liu 	u32	cmxgcr;
2397737d5c6SDave Liu 
2407737d5c6SDave Liu 	/* check if the UCC number is in range. */
2417737d5c6SDave Liu 	if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
2427737d5c6SDave Liu 		printf("%s: ucc num not in ranges\n", __FUNCTION__);
2437737d5c6SDave Liu 		return -EINVAL;
2447737d5c6SDave Liu 	}
2457737d5c6SDave Liu 
2467737d5c6SDave Liu 	cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
2477737d5c6SDave Liu 	cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
2487737d5c6SDave Liu 	cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
2497737d5c6SDave Liu 	out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
2507737d5c6SDave Liu 
2517737d5c6SDave Liu 	return 0;
2527737d5c6SDave Liu }
2537737d5c6SDave Liu 
2547737d5c6SDave Liu #endif /* CONFIG_QE */
255