diff options
| author | lars <lars@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-04-12 18:17:26 +0000 | 
|---|---|---|
| committer | lars <lars@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-04-12 18:17:26 +0000 | 
| commit | 28dec42aa353b7bcc7248ffe333e56d777a35835 (patch) | |
| tree | 507db9e61d7632c134b60a5f8b53d266f2bd1254 /package/uboot-xburst/files/cpu/mips/jz4740.c | |
| parent | abe312efd5fbeee4423d991b0f690a267f098714 (diff) | |
[package] Add uboot for xburst package
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@20832 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/uboot-xburst/files/cpu/mips/jz4740.c')
| -rw-r--r-- | package/uboot-xburst/files/cpu/mips/jz4740.c | 559 | 
1 files changed, 559 insertions, 0 deletions
diff --git a/package/uboot-xburst/files/cpu/mips/jz4740.c b/package/uboot-xburst/files/cpu/mips/jz4740.c new file mode 100644 index 000000000..5ae57971d --- /dev/null +++ b/package/uboot-xburst/files/cpu/mips/jz4740.c @@ -0,0 +1,559 @@ +/* + * Jz4740 common routines + * + *  Copyright (c) 2006 + *  Ingenic Semiconductor, <jlwei@ingenic.cn> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> + +#ifdef CONFIG_JZ4740 +#include <common.h> +#include <command.h> +#include <asm/jz4740.h> + +extern void board_early_init(void); + +/* PLL output clock = EXTAL * NF / (NR * NO) + * + * NF = FD + 2, NR = RD + 2 + * NO = 1 (if OD = 0), NO = 2 (if OD = 1 or 2), NO = 4 (if OD = 3) + */ +void pll_init(void) +{ +	register unsigned int cfcr, plcr1; +	int n2FR[33] = { +		0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, +		7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, +		9 +	}; +	int div[5] = {1, 3, 3, 3, 3}; /* divisors of I:S:P:L:M */ +	int nf, pllout2; + +	cfcr = CPM_CPCCR_CLKOEN | +		CPM_CPCCR_PCS | +		(n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) | +		(n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) | +		(n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) | +		(n2FR[div[3]] << CPM_CPCCR_MDIV_BIT) | +		(n2FR[div[4]] << CPM_CPCCR_LDIV_BIT); + +	pllout2 = (cfcr & CPM_CPCCR_PCS) ? CONFIG_SYS_CPU_SPEED : (CONFIG_SYS_CPU_SPEED / 2); + +	/* Init USB Host clock, pllout2 must be n*48MHz */ +	REG_CPM_UHCCDR = pllout2 / 48000000 - 1; + +	nf = CONFIG_SYS_CPU_SPEED * 2 / CONFIG_SYS_EXTAL; +	plcr1 = ((nf - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */ +		(0 << CPM_CPPCR_PLLN_BIT) |	/* RD=0, NR=2 */ +		(0 << CPM_CPPCR_PLLOD_BIT) |    /* OD=0, NO=1 */ +		(0x20 << CPM_CPPCR_PLLST_BIT) | /* PLL stable time */ +		CPM_CPPCR_PLLEN;                /* enable PLL */ + +	/* init PLL */ +	REG_CPM_CPCCR = cfcr; +	REG_CPM_CPPCR = plcr1; +} + +void pll_add_test(int new_freq) +{ +	register unsigned int cfcr, plcr1; +	int n2FR[33] = { +		0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, +		7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, +		9 +	}; +	int div[5] = {1, 4, 4, 4, 4}; /* divisors of I:S:P:M:L */ +	int nf, pllout2; + +	cfcr = CPM_CPCCR_CLKOEN | +		(n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) | +		(n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) | +		(n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) | +		(n2FR[div[3]] << CPM_CPCCR_MDIV_BIT) | +		(n2FR[div[4]] << CPM_CPCCR_LDIV_BIT); + +	pllout2 = (cfcr & CPM_CPCCR_PCS) ? new_freq : (new_freq / 2); + +	/* Init UHC clock */ +	REG_CPM_UHCCDR = pllout2 / 48000000 - 1; + +	/* nf = new_freq * 2 / CONFIG_SYS_EXTAL; */ +	nf = new_freq / 1000000; /* step length is 1M */ +	plcr1 = ((nf - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */ +		(10 << CPM_CPPCR_PLLN_BIT) |	/* RD=0, NR=2 */ +		(0 << CPM_CPPCR_PLLOD_BIT) |    /* OD=0, NO=1 */ +		(0x20 << CPM_CPPCR_PLLST_BIT) | /* PLL stable time */ +		CPM_CPPCR_PLLEN;                /* enable PLL */ + +	/* init PLL */ +	REG_CPM_CPCCR = cfcr; +	REG_CPM_CPPCR = plcr1; +} + +void calc_clocks_add_test(void) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	unsigned int pllout; +	unsigned int div[10] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + +	pllout = __cpm_get_pllout(); + +	gd->cpu_clk = pllout / div[__cpm_get_cdiv()]; +	gd->sys_clk = pllout / div[__cpm_get_hdiv()]; +	gd->per_clk = pllout / div[__cpm_get_pdiv()]; +	gd->mem_clk = pllout / div[__cpm_get_mdiv()]; +	gd->dev_clk = CONFIG_SYS_EXTAL; +} + +void sdram_add_test(int new_freq) +{ +	register unsigned int dmcr, sdmode, tmp, cpu_clk, mem_clk, ns; + +	unsigned int cas_latency_sdmr[2] = { +		EMC_SDMR_CAS_2, +		EMC_SDMR_CAS_3, +	}; + +	unsigned int cas_latency_dmcr[2] = { +		1 << EMC_DMCR_TCL_BIT,	/* CAS latency is 2 */ +		2 << EMC_DMCR_TCL_BIT	/* CAS latency is 3 */ +	}; + +	int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + +	cpu_clk = new_freq; +	mem_clk = cpu_clk * div[__cpm_get_cdiv()] / div[__cpm_get_mdiv()]; + +	REG_EMC_RTCSR = EMC_RTCSR_CKS_DISABLE; +	REG_EMC_RTCOR = 0; +	REG_EMC_RTCNT = 0; + +	/* Basic DMCR register value. */ +	dmcr = ((SDRAM_ROW-11)<<EMC_DMCR_RA_BIT) | +		((SDRAM_COL-8)<<EMC_DMCR_CA_BIT) | +		(SDRAM_BANK4<<EMC_DMCR_BA_BIT) | +		(SDRAM_BW16<<EMC_DMCR_BW_BIT) | +		EMC_DMCR_EPIN | +		cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]; + +	/* SDRAM timimg parameters */ +	ns = 1000000000 / mem_clk; + +#if 0 +	tmp = SDRAM_TRAS/ns; +	if (tmp < 4) tmp = 4; +	if (tmp > 11) tmp = 11; +	dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT); + +	tmp = SDRAM_RCD/ns; +	if (tmp > 3) tmp = 3; +	dmcr |= (tmp << EMC_DMCR_RCD_BIT); + +	tmp = SDRAM_TPC/ns; +	if (tmp > 7) tmp = 7; +	dmcr |= (tmp << EMC_DMCR_TPC_BIT); + +	tmp = SDRAM_TRWL/ns; +	if (tmp > 3) tmp = 3; +	dmcr |= (tmp << EMC_DMCR_TRWL_BIT); + +	tmp = (SDRAM_TRAS + SDRAM_TPC)/ns; +	if (tmp > 14) tmp = 14; +	dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT); +#else +	dmcr |= 0xfffc; +#endif + +	/* First, precharge phase */ +	REG_EMC_DMCR = dmcr; + +	/* Set refresh registers */ +	tmp = SDRAM_TREF/ns; +	tmp = tmp/64 + 1; +	if (tmp > 0xff) tmp = 0xff; + +	REG_EMC_RTCOR = tmp; +	REG_EMC_RTCSR = EMC_RTCSR_CKS_64;	/* Divisor is 64, CKO/64 */ + +	/* SDRAM mode values */ +	sdmode = EMC_SDMR_BT_SEQ |  +		 EMC_SDMR_OM_NORMAL | +		 EMC_SDMR_BL_4 |  +		 cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)]; + +	/* precharge all chip-selects */ +	REG8(EMC_SDMR0|sdmode) = 0; + +	/* wait for precharge, > 200us */ +	tmp = (cpu_clk / 1000000) * 200; +	while (tmp--); + +	/* enable refresh and set SDRAM mode */ +	REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET; + +	/* write sdram mode register for each chip-select */ +	REG8(EMC_SDMR0|sdmode) = 0; + +	/* everything is ok now */ +} + +void sdram_init(void) +{ +	register unsigned int dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns; + +	unsigned int cas_latency_sdmr[2] = { +		EMC_SDMR_CAS_2, +		EMC_SDMR_CAS_3, +	}; + +	unsigned int cas_latency_dmcr[2] = { +		1 << EMC_DMCR_TCL_BIT,	/* CAS latency is 2 */ +		2 << EMC_DMCR_TCL_BIT	/* CAS latency is 3 */ +	}; + +	int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + +	cpu_clk = CONFIG_SYS_CPU_SPEED; +	mem_clk = cpu_clk * div[__cpm_get_cdiv()] / div[__cpm_get_mdiv()]; + +	REG_EMC_BCR = 0;	/* Disable bus release */ +	REG_EMC_RTCSR = 0;	/* Disable clock for counting */ + +	/* Fault DMCR value for mode register setting*/ +#define SDRAM_ROW0    11 +#define SDRAM_COL0     8 +#define SDRAM_BANK40   0 + +	dmcr0 = ((SDRAM_ROW0-11)<<EMC_DMCR_RA_BIT) | +		((SDRAM_COL0-8)<<EMC_DMCR_CA_BIT) | +		(SDRAM_BANK40<<EMC_DMCR_BA_BIT) | +		(SDRAM_BW16<<EMC_DMCR_BW_BIT) | +		EMC_DMCR_EPIN | +		cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]; + +	/* Basic DMCR value */ +	dmcr = ((SDRAM_ROW-11)<<EMC_DMCR_RA_BIT) | +		((SDRAM_COL-8)<<EMC_DMCR_CA_BIT) | +		(SDRAM_BANK4<<EMC_DMCR_BA_BIT) | +		(SDRAM_BW16<<EMC_DMCR_BW_BIT) | +		EMC_DMCR_EPIN | +		cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]; + +	/* SDRAM timimg */ +	ns = 1000000000 / mem_clk; +	tmp = SDRAM_TRAS/ns; +	if (tmp < 4) tmp = 4; +	if (tmp > 11) tmp = 11; +	dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT); +	tmp = SDRAM_RCD/ns; +	if (tmp > 3) tmp = 3; +	dmcr |= (tmp << EMC_DMCR_RCD_BIT); +	tmp = SDRAM_TPC/ns; +	if (tmp > 7) tmp = 7; +	dmcr |= (tmp << EMC_DMCR_TPC_BIT); +	tmp = SDRAM_TRWL/ns; +	if (tmp > 3) tmp = 3; +	dmcr |= (tmp << EMC_DMCR_TRWL_BIT); +	tmp = (SDRAM_TRAS + SDRAM_TPC)/ns; +	if (tmp > 14) tmp = 14; +	dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT); + +	/* SDRAM mode value */ +	sdmode = EMC_SDMR_BT_SEQ |  +		 EMC_SDMR_OM_NORMAL | +		 EMC_SDMR_BL_4 |  +		 cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)]; + +	/* Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0 */ +	REG_EMC_DMCR = dmcr; +	REG8(EMC_SDMR0|sdmode) = 0; + +	/* Wait for precharge, > 200us */ +	tmp = (cpu_clk / 1000000) * 1000; +	while (tmp--); + +	/* Stage 2. Enable auto-refresh */ +	REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH; + +	tmp = SDRAM_TREF/ns; +	tmp = tmp/64 + 1; +	if (tmp > 0xff) tmp = 0xff; +	REG_EMC_RTCOR = tmp; +	REG_EMC_RTCNT = 0; +	REG_EMC_RTCSR = EMC_RTCSR_CKS_64;	/* Divisor is 64, CKO/64 */ + +	/* Wait for number of auto-refresh cycles */ +	tmp = (cpu_clk / 1000000) * 1000; +	while (tmp--); + + 	/* Stage 3. Mode Register Set */ +	REG_EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET; +	REG8(EMC_SDMR0|sdmode) = 0; + +        /* Set back to basic DMCR value */ +	REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET; + +	/* everything is ok now */ +} + +#ifndef CONFIG_NAND_SPL + +static void calc_clocks(void) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	unsigned int pllout; +	unsigned int div[10] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + +	pllout = __cpm_get_pllout(); + +	gd->cpu_clk = pllout / div[__cpm_get_cdiv()]; +	gd->sys_clk = pllout / div[__cpm_get_hdiv()]; +	gd->per_clk = pllout / div[__cpm_get_pdiv()]; +	gd->mem_clk = pllout / div[__cpm_get_mdiv()]; +	gd->dev_clk = CONFIG_SYS_EXTAL; +} + +static void rtc_init(void) +{ +	unsigned long rtcsta; + +	while ( !__rtc_write_ready()) ; +	__rtc_enable_alarm();	/* enable alarm */ + +	while ( !__rtc_write_ready()) +		; +	REG_RTC_RGR   = 0x00007fff; /* type value */ + +	while ( !__rtc_write_ready()) +		; +	REG_RTC_HWFCR = 0x0000ffe0; /* Power on delay 2s */ + +	while ( !__rtc_write_ready()) +		; +	REG_RTC_HRCR  = 0x00000fe0; /* reset delay 125ms */ +#if 0 +	while ( !__rtc_write_ready()) +		; +	rtcsta = REG_RTC_HWRSR; +	while ( !__rtc_write_ready()) +		; +	if (rtcsta & 0x33) { +		if (rtcsta & 0x10) { +			while ( !__rtc_write_ready()) +				; +			REG_RTC_RSR = 0x0; +		} +		while ( !__rtc_write_ready()) +			; +		REG_RTC_HWRSR = 0x0; +	} +#endif +} + +/* + * jz4740 board init routine + */ +int jz_board_init(void) +{ +	board_early_init();  /* init gpio, pll etc. */ +#ifndef CONFIG_NAND_U_BOOT +	pll_init();          /* init PLL */ +	sdram_init();        /* init sdram memory */ +#endif +	calc_clocks();       /* calc the clocks */ +	rtc_init();		/* init rtc on any reset: */ +	return 0; +} + +/* U-Boot common routines */ +phys_size_t initdram(int board_type) +{ +	u32 dmcr; +	u32 rows, cols, dw, banks; +	ulong size; + +	dmcr = REG_EMC_DMCR; +	rows = 11 + ((dmcr & EMC_DMCR_RA_MASK) >> EMC_DMCR_RA_BIT); +	cols = 8 + ((dmcr & EMC_DMCR_CA_MASK) >> EMC_DMCR_CA_BIT); +	dw = (dmcr & EMC_DMCR_BW) ? 2 : 4; +	banks = (dmcr & EMC_DMCR_BA) ? 4 : 2; + +	size = (1 << (rows + cols)) * dw * banks; + +	return size; +} + +/* + * Timer routines  + */ + +#define TIMER_CHAN  0 +#define TIMER_FDATA 0xffff  /* Timer full data value */ +#define TIMER_HZ    CONFIG_SYS_HZ + +#define READ_TIMER  REG_TCU_TCNT(TIMER_CHAN)  /* macro to read the 16 bit timer */ + +static ulong timestamp; +static ulong lastdec; + +void	reset_timer_masked	(void); +ulong	get_timer_masked	(void); +void	udelay_masked		(unsigned long usec); + +/* + * timer without interrupts + */ + +int timer_init(void) +{ +	REG_TCU_TCSR(TIMER_CHAN) = TCU_TCSR_PRESCALE256 | TCU_TCSR_EXT_EN; +	REG_TCU_TCNT(TIMER_CHAN) = 0; +	REG_TCU_TDHR(TIMER_CHAN) = 0; +	REG_TCU_TDFR(TIMER_CHAN) = TIMER_FDATA; + +	REG_TCU_TMSR = (1 << TIMER_CHAN) | (1 << (TIMER_CHAN + 16)); /* mask irqs */ +	REG_TCU_TSCR = (1 << TIMER_CHAN); /* enable timer clock */ +	REG_TCU_TESR = (1 << TIMER_CHAN); /* start counting up */ + +	lastdec = 0; +	timestamp = 0; + +	return 0; +} + +void reset_timer(void) +{ +	reset_timer_masked (); +} + +ulong get_timer(ulong base) +{ +	return get_timer_masked () - base; +} + +void set_timer(ulong t) +{ +	timestamp = t; +} + +void udelay (unsigned long usec) +{ +	ulong tmo,tmp; + +	/* normalize */ +	if (usec >= 1000) { +		tmo = usec / 1000; +		tmo *= TIMER_HZ; +		tmo /= 1000; +	} +	else { +		if (usec >= 1) { +			tmo = usec * TIMER_HZ; +			tmo /= (1000*1000); +		} +		else +			tmo = 1; +	} + +	/* check for rollover during this delay */ +	tmp = get_timer (0); +	if ((tmp + tmo) < tmp ) +		reset_timer_masked();  /* timer would roll over */ +	else +		tmo += tmp; + +	while (get_timer_masked () < tmo); +} + +void reset_timer_masked (void) +{ +	/* reset time */ +	lastdec = READ_TIMER; +	timestamp = 0; +} + +ulong get_timer_masked (void) +{ +	ulong now = READ_TIMER; + +	if (lastdec <= now) { +		/* normal mode */ +		timestamp += (now - lastdec); +	} else { +		/* we have an overflow ... */ +		timestamp += TIMER_FDATA + now - lastdec; +	} +	lastdec = now; + +	return timestamp; +} + +void udelay_masked (unsigned long usec) +{ +	ulong tmo; +	ulong endtime; +	signed long diff; + +	/* normalize */ +	if (usec >= 1000) { +		tmo = usec / 1000; +		tmo *= TIMER_HZ; +		tmo /= 1000; +	} else { +		if (usec > 1) { +			tmo = usec * TIMER_HZ; +			tmo /= (1000*1000); +		} else { +			tmo = 1; +		} +	} + +	endtime = get_timer_masked () + tmo; + +	do { +		ulong now = get_timer_masked (); +		diff = endtime - now; +	} while (diff >= 0); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On MIPS it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ +	return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On MIPS it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ +	return TIMER_HZ; +} + +#endif /* CONFIG_NAND_SPL */ + +/* End of timer routine. */ + +#endif  | 
