diff options
Diffstat (limited to 'arch/arm/cpu')
34 files changed, 4475 insertions, 2767 deletions
| diff --git a/arch/arm/cpu/arm1136/mx31/generic.c b/arch/arm/cpu/arm1136/mx31/generic.c index 4f27e250b..f45828141 100644 --- a/arch/arm/cpu/arm1136/mx31/generic.c +++ b/arch/arm/cpu/arm1136/mx31/generic.c @@ -27,8 +27,6 @@  #include <asm/io.h>  #include <asm/arch/sys_proto.h> -#define IOMUXGPR	(IOMUXC_BASE + 0x008) -  static u32 mx31_decode_pll(u32 reg, u32 infreq)  {  	u32 mfi = GET_PLL_MFI(reg); @@ -89,7 +87,7 @@ static u32 mx31_get_hsp_clk(void)  void mx31_dump_clocks(void)  {  	u32 cpufreq = mx31_get_mcu_main_clk(); -	printf("mx31 cpu clock: %dMHz\n",cpufreq / 1000000); +	printf("mx31 cpu clock: %dMHz\n", cpufreq / 1000000);  	printf("ipg clock     : %dHz\n", mx31_get_ipg_clk());  	printf("hsp clock     : %dHz\n", mx31_get_hsp_clk());  } @@ -146,14 +144,15 @@ void mx31_set_pad(enum iomux_pins pin, u32 config)  void mx31_set_gpr(enum iomux_gp_func gp, char en)  {  	u32 l; +	struct iomuxc_regs *iomuxc = (struct iomuxc_regs *)IOMUXC_BASE; -	l = readl(IOMUXGPR); +	l = readl(&iomuxc->gpr);  	if (en)  		l |= gp;  	else  		l &= ~gp; -	writel(l, IOMUXGPR); +	writel(l, &iomuxc->gpr);  }  void mxc_setup_weimcs(int cs, const struct mxc_weimcs *weimcs) @@ -216,7 +215,7 @@ static char *get_reset_cause(void)  }  #if defined(CONFIG_DISPLAY_CPUINFO) -int print_cpuinfo (void) +int print_cpuinfo(void)  {  	u32 srev = get_cpu_rev(); diff --git a/arch/arm/cpu/arm920t/a320/timer.c b/arch/arm/cpu/arm920t/a320/timer.c index 443d31d22..4bfcef237 100644 --- a/arch/arm/cpu/arm920t/a320/timer.c +++ b/arch/arm/cpu/arm920t/a320/timer.c @@ -18,20 +18,35 @@   */  #include <common.h> +#include <div64.h>  #include <asm/io.h>  #include <faraday/ftpmu010.h>  #include <faraday/fttmr010.h> -static ulong timestamp; -static ulong lastdec; - -static struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE; +DECLARE_GLOBAL_DATA_PTR;  #define TIMER_CLOCK	32768  #define TIMER_LOAD_VAL	0xffffffff +static inline unsigned long long tick_to_time(unsigned long long tick) +{ +	tick *= CONFIG_SYS_HZ; +	do_div(tick, gd->timer_rate_hz); + +	return tick; +} + +static inline unsigned long long usec_to_tick(unsigned long long usec) +{ +	usec *= gd->timer_rate_hz; +	do_div(usec, 1000000); + +	return usec; +} +  int timer_init(void)  { +	struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;  	unsigned int cr;  	debug("%s()\n", __func__); @@ -59,106 +74,57 @@ int timer_init(void)  	cr |= FTTMR010_TM3_ENABLE;  	writel(cr, &tmr->cr); -	/* init the timestamp and lastdec value */ -	reset_timer_masked(); +	gd->timer_rate_hz = TIMER_CLOCK; +	gd->tbu = gd->tbl = 0;  	return 0;  }  /* - * timer without interrupts - */ - -/* - * reset time - */ -void reset_timer_masked(void) -{ -	/* capure current decrementer value time */ -	lastdec = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ); -	timestamp = 0;		/* start "advancing" time stamp from 0 */ - -	debug("%s(): lastdec = %lx\n", __func__, lastdec); -} - -/* - * return timer ticks + * Get the current 64 bit timer tick count   */ -ulong get_timer_masked(void) +unsigned long long get_ticks(void)  { -	/* current tick value */ -	ulong now = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ); - -	debug("%s(): now = %lx, lastdec = %lx\n", __func__, now, lastdec); - -	if (lastdec >= now) { -		/* -		 * normal mode (non roll) -		 * move stamp fordward with absoulte diff ticks -		 */ -		timestamp += lastdec - now; -	} else { -		/* -		 * we have overflow of the count down timer -		 * -		 * nts = ts + ld + (TLV - now) -		 * ts=old stamp, ld=time that passed before passing through -1 -		 * (TLV-now) amount of time after passing though -1 -		 * nts = new "advancing time stamp"...it could also roll and -		 * cause problems. -		 */ -		timestamp += lastdec + TIMER_LOAD_VAL - now; -	} - -	lastdec = now; - -	debug("%s() returns %lx\n", __func__, timestamp); +	struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE; +	ulong now = TIMER_LOAD_VAL - readl(&tmr->timer3_counter); -	return timestamp; +	/* increment tbu if tbl has rolled over */ +	if (now < gd->tbl) +		gd->tbu++; +	gd->tbl = now; +	return (((unsigned long long)gd->tbu) << 32) | gd->tbl;  } -/* - * return difference between timer ticks and base - */ -ulong get_timer(ulong base) -{ -	debug("%s(%lx)\n", __func__, base); -	return get_timer_masked() - base; -} - -/* delay x useconds AND preserve advance timestamp value */  void __udelay(unsigned long usec)  { -	long tmo = usec * (TIMER_CLOCK / 1000) / 1000; -	unsigned long now, last = readl(&tmr->timer3_counter); +	unsigned long long start; +	ulong tmo; -	debug("%s(%lu)\n", __func__, usec); -	while (tmo > 0) { -		now = readl(&tmr->timer3_counter); -		if (now > last) /* count down timer overflow */ -			tmo -= TIMER_LOAD_VAL + last - now; -		else -			tmo -= last - now; -		last = now; -	} +	start = get_ticks();		/* get current timestamp */ +	tmo = usec_to_tick(usec);	/* convert usecs to ticks */ +	while ((get_ticks() - start) < tmo) +		;			/* loop till time has passed */  }  /* - * This function is derived from PowerPC code (read timebase as long long). - * On ARM it just returns the timer value. + * get_timer(base) can be used to check for timeouts or + * to measure elasped time relative to an event: + * + * ulong start_time = get_timer(0) sets start_time to the current + * time value. + * get_timer(start_time) returns the time elapsed since then. + * + * The time is used in CONFIG_SYS_HZ units!   */ -unsigned long long get_ticks(void) +ulong get_timer(ulong base)  { -	debug("%s()\n", __func__); -	return get_timer(0); +	return tick_to_time(get_ticks()) - base;  }  /* - * This function is derived from PowerPC code (timebase clock frequency). - * On ARM it returns the number of timer ticks per second. + * Return the number of timer ticks per second.   */  ulong get_tbclk(void)  { -	debug("%s()\n", __func__); -	return CONFIG_SYS_HZ; +	return gd->timer_rate_hz;  } diff --git a/arch/arm/cpu/arm926ejs/Makefile b/arch/arm/cpu/arm926ejs/Makefile index 930e0d1bf..a56ff08c9 100644 --- a/arch/arm/cpu/arm926ejs/Makefile +++ b/arch/arm/cpu/arm926ejs/Makefile @@ -28,6 +28,12 @@ LIB	= $(obj)lib$(CPU).o  START	= start.o  COBJS	= cpu.o +ifdef	CONFIG_SPL_BUILD +ifdef	CONFIG_SPL_NO_CPU_SUPPORT_CODE +START	:= +endif +endif +  SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))  START	:= $(addprefix $(obj),$(START)) diff --git a/arch/arm/cpu/arm926ejs/davinci/Makefile b/arch/arm/cpu/arm926ejs/davinci/Makefile index 98c7e55c4..aeb058acd 100644 --- a/arch/arm/cpu/arm926ejs/davinci/Makefile +++ b/arch/arm/cpu/arm926ejs/davinci/Makefile @@ -28,7 +28,7 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)lib$(SOC).o  COBJS-y				+= cpu.o timer.o psc.o -COBJS-$(CONFIG_AM18018_LOWLEVEL)       += am1808_lowlevel.o +COBJS-$(CONFIG_DA850_LOWLEVEL)	+= da850_lowlevel.o  COBJS-$(CONFIG_SOC_DM355)	+= dm355.o  COBJS-$(CONFIG_SOC_DM365)	+= dm365.o  COBJS-$(CONFIG_SOC_DM644X)	+= dm644x.o diff --git a/arch/arm/cpu/arm926ejs/davinci/am1808_lowlevel.c b/arch/arm/cpu/arm926ejs/davinci/am1808_lowlevel.c deleted file mode 100644 index 1ea4a9ffc..000000000 --- a/arch/arm/cpu/arm926ejs/davinci/am1808_lowlevel.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * SoC-specific lowlevel code for AM1808 and similar chips - * - * Copyright (C) 2011 - * Heiko Schocher, DENX Software Engineering, hs@denx.de. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include <common.h> -#include <nand.h> -#include <ns16550.h> -#include <post.h> -#include <asm/arch/am1808_lowlevel.h> -#include <asm/arch/hardware.h> -#include <asm/arch/ddr2_defs.h> -#include <asm/arch/emif_defs.h> - -void am1808_waitloop(unsigned long loopcnt) -{ -	unsigned long	i; - -	for (i = 0; i < loopcnt; i++) -		asm("   NOP"); -} - -int am1808_pll_init(struct davinci_pllc_regs *reg, unsigned long pllmult) -{ -	if (reg == davinci_pllc0_regs) -		/* Unlock PLL registers. */ -		clrbits_le32(&davinci_syscfg_regs->cfgchip0, 0x00000010); - -	/* -	 * Set PLLENSRC '0',bit 5, PLL Enable(PLLEN) selection is controlled -	 * through MMR -	 */ -	clrbits_le32(®->pllctl, 0x00000020); -	/* PLLCTL.EXTCLKSRC bit 9 should be left at 0 for Freon */ -	clrbits_le32(®->pllctl, 0x00000200); - -	/* Set PLLEN=0 => PLL BYPASS MODE */ -	clrbits_le32(®->pllctl, 0x00000001); - -	am1808_waitloop(150); - -	if (reg == davinci_pllc0_regs) { -		/* -		 * Select the Clock Mode bit 8 as External Clock or On Chip -		 * Oscilator -		 */ -		dv_maskbits(®->pllctl, 0xFFFFFEFF); -		setbits_le32(®->pllctl, (CONFIG_SYS_DV_CLKMODE << 8)); -	} - -	/* Clear PLLRST bit to reset the PLL */ -	clrbits_le32(®->pllctl, 0x00000008); - -	/* Disable the PLL output */ -	setbits_le32(®->pllctl, 0x00000010); - -	/* PLL initialization sequence */ -	/* -	 * Power up the PLL- PWRDN bit set to 0 to bring the PLL out of -	 * power down bit -	 */ -	clrbits_le32(®->pllctl, 0x00000002); - -	/* Enable the PLL from Disable Mode PLLDIS bit to 0 */ -	clrbits_le32(®->pllctl, 0x00000010); - -	/* Program the required multiplier value in PLLM */ -	writel(pllmult, ®->pllm); - -	/* program the postdiv */ -	if (reg == davinci_pllc0_regs) -		writel((0x8000 | CONFIG_SYS_AM1808_PLL0_POSTDIV), -			®->postdiv); -	else -		writel((0x8000 | CONFIG_SYS_AM1808_PLL1_POSTDIV), -			®->postdiv); - -	/* -	 * Check for the GOSTAT bit in PLLSTAT to clear to 0 to indicate that -	 * no GO operation is currently in progress -	 */ -	while ((readl(®->pllstat) & 0x1) == 1) -		; - -	if (reg == davinci_pllc0_regs) { -		writel(CONFIG_SYS_AM1808_PLL0_PLLDIV1, ®->plldiv1); -		writel(CONFIG_SYS_AM1808_PLL0_PLLDIV2, ®->plldiv2); -		writel(CONFIG_SYS_AM1808_PLL0_PLLDIV3, ®->plldiv3); -		writel(CONFIG_SYS_AM1808_PLL0_PLLDIV4, ®->plldiv4); -		writel(CONFIG_SYS_AM1808_PLL0_PLLDIV5, ®->plldiv5); -		writel(CONFIG_SYS_AM1808_PLL0_PLLDIV6, ®->plldiv6); -		writel(CONFIG_SYS_AM1808_PLL0_PLLDIV7, ®->plldiv7); -	} else { -		writel(CONFIG_SYS_AM1808_PLL1_PLLDIV1, ®->plldiv1); -		writel(CONFIG_SYS_AM1808_PLL1_PLLDIV2, ®->plldiv2); -		writel(CONFIG_SYS_AM1808_PLL1_PLLDIV3, ®->plldiv3); -	} - -	/* -	 * Set the GOSET bit in PLLCMD to 1 to initiate a new divider -	 * transition. -	 */ -	setbits_le32(®->pllcmd, 0x01); - -	/* -	 * Wait for the GOSTAT bit in PLLSTAT to clear to 0 -	 * (completion of phase alignment). -	 */ -	while ((readl(®->pllstat) & 0x1) == 1) -		; - -	/* Wait for PLL to reset properly. See PLL spec for PLL reset time */ -	am1808_waitloop(200); - -	/* Set the PLLRST bit in PLLCTL to 1 to bring the PLL out of reset */ -	setbits_le32(®->pllctl, 0x00000008); - -	/* Wait for PLL to lock. See PLL spec for PLL lock time */ -	am1808_waitloop(2400); - -	/* -	 * Set the PLLEN bit in PLLCTL to 1 to remove the PLL from bypass -	 * mode -	 */ -	setbits_le32(®->pllctl, 0x00000001); - - -	/* -	 * clear EMIFA and EMIFB clock source settings, let them -	 * run off SYSCLK -	 */ -	if (reg == davinci_pllc0_regs) -		dv_maskbits(&davinci_syscfg_regs->cfgchip3, 0xFFFFFFF8); - -	return 0; -} - -void am1808_lpc_transition(unsigned char pscnum, unsigned char module, -		unsigned char domain, unsigned char state) -{ -	struct davinci_psc_regs	*reg; -	dv_reg_p mdstat, mdctl; - -	if (pscnum == 0) { -		reg = davinci_psc0_regs; -		mdstat = ®->psc0.mdstat[module]; -		mdctl = ®->psc0.mdctl[module]; -	} else { -		reg = davinci_psc1_regs; -		mdstat = ®->psc1.mdstat[module]; -		mdctl = ®->psc1.mdctl[module]; -	} - -	/* Wait for any outstanding transition to complete */ -	while ((readl(®->ptstat) & (0x00000001 << domain))) -		; - -	/* If we are already in that state, just return */ -	if ((readl(mdstat) & 0x1F) == state) -		return; - -	/* Perform transition */ -	writel((readl(mdctl) & 0xFFFFFFE0) | state, mdctl); -	setbits_le32(®->ptcmd, (0x00000001 << domain)); - -	/* Wait for transition to complete */ -	while (readl(®->ptstat) & (0x00000001 << domain)) -		; - -	/* Wait and verify the state */ -	while ((readl(mdstat) & 0x1F) != state) -		; -} - -int am1808_ddr_setup(unsigned int freq) -{ -	unsigned long	tmp; - -	/* Enable the Clock to DDR2/mDDR */ -	am1808_lpc_transition(1, 6, 0, PSC_ENABLE); - -	tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); -	if ((tmp & VTP_POWERDWN) == VTP_POWERDWN) { -		/* Begin VTP Calibration */ -		clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_POWERDWN); -		clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_LOCK); -		setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); -		clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); -		setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); - -		/* Polling READY bit to see when VTP calibration is done */ -		tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); -		while ((tmp & VTP_READY) != VTP_READY) -			tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); - -		setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_LOCK); -		setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_POWERDWN); - -		setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_IOPWRDWN); -	} - -	writel(CONFIG_SYS_AM1808_DDR2_DDRPHYCR, &dv_ddr2_regs_ctrl->ddrphycr); -	clrbits_le32(&davinci_syscfg1_regs->ddr_slew, -		(1 << DDR_SLEW_CMOSEN_BIT)); - -	setbits_le32(&dv_ddr2_regs_ctrl->sdbcr, DV_DDR_BOOTUNLOCK); - -	writel((CONFIG_SYS_AM1808_DDR2_SDBCR & ~0xf0000000) | -		(readl(&dv_ddr2_regs_ctrl->sdbcr) & 0xf0000000), /*rsv Bytes*/ -		&dv_ddr2_regs_ctrl->sdbcr); -	writel(CONFIG_SYS_AM1808_DDR2_SDBCR2, &dv_ddr2_regs_ctrl->sdbcr2); - -	writel(CONFIG_SYS_AM1808_DDR2_SDTIMR, &dv_ddr2_regs_ctrl->sdtimr); -	writel(CONFIG_SYS_AM1808_DDR2_SDTIMR2, &dv_ddr2_regs_ctrl->sdtimr2); - -	clrbits_le32(&dv_ddr2_regs_ctrl->sdbcr, -		(1 << DV_DDR_SDCR_TIMUNLOCK_SHIFT)); - -	/* -	 * LPMODEN and MCLKSTOPEN must be set! -	 * Without this bits set, PSC don;t switch states !! -	 */ -	writel(CONFIG_SYS_AM1808_DDR2_SDRCR | -		(1 << DV_DDR_SRCR_LPMODEN_SHIFT) | -		(1 << DV_DDR_SRCR_MCLKSTOPEN_SHIFT), -		&dv_ddr2_regs_ctrl->sdrcr); - -	/* SyncReset the Clock to EMIF3A SDRAM */ -	am1808_lpc_transition(1, 6, 0, PSC_SYNCRESET); -	/* Enable the Clock to EMIF3A SDRAM */ -	am1808_lpc_transition(1, 6, 0, PSC_ENABLE); - -	/* disable self refresh */ -	clrbits_le32(&dv_ddr2_regs_ctrl->sdrcr, 0xc0000000); -	writel(0x30, &dv_ddr2_regs_ctrl->pbbpr); - -	return 0; -} - -static void am1808_set_mdctl(dv_reg_p mdctl) -{ -	if ((readl(mdctl) & 0x1F) != PSC_ENABLE) -		writel(((readl(mdctl) & 0xFFFFFFE0) | PSC_ENABLE), mdctl); -} - -void am1808_psc_init(void) -{ -	struct davinci_psc_regs	*reg; -	int i; - -	/* PSC 0 domain 0 init */ -	reg = davinci_psc0_regs; -	while ((readl(®->ptstat) & 0x00000001)) -		; - -	for (i = 3; i <= 4 ; i++) -		am1808_set_mdctl(®->psc0.mdctl[i]); - -	for (i = 7; i <= 12 ; i++) -		am1808_set_mdctl(®->psc0.mdctl[i]); - -	/* Do Always-On Power Domain Transitions */ -	setbits_le32(®->ptcmd, 0x00000001); -	while (readl(®->ptstat) & 0x00000001) -		; - -	/* PSC1, domain 1 init */ -	reg = davinci_psc1_regs; -	while ((readl(®->ptstat) & 0x00000001)) -		; - -	am1808_set_mdctl(®->psc1.mdctl[3]); -	am1808_set_mdctl(®->psc1.mdctl[6]); - -	/* UART1 + UART2 */ -	for (i = 12 ; i <= 13 ; i++) -		am1808_set_mdctl(®->psc1.mdctl[i]); - -	am1808_set_mdctl(®->psc1.mdctl[26]); -	am1808_set_mdctl(®->psc1.mdctl[31]); - -	/* Do Always-On Power Domain Transitions */ -	setbits_le32(®->ptcmd, 0x00000001); -	while (readl(®->ptstat) & 0x00000001) -		; -} - -void am1808_pinmux_ctl(unsigned long offset, unsigned long mask, -	unsigned long value) -{ -	clrbits_le32(&davinci_syscfg_regs->pinmux[offset], mask); -	setbits_le32(&davinci_syscfg_regs->pinmux[offset], (mask & value)); -} - -__attribute__((weak)) -void board_gpio_init(void) -{ -	return; -} - -#if defined(CONFIG_NAND_SPL) -void nand_boot(void) -{ -	__attribute__((noreturn)) void (*uboot)(void); - -	/* copy image from NOR to RAM */ -	memcpy((void *)CONFIG_SYS_NAND_U_BOOT_DST, -		(void *)CONFIG_SYS_NAND_U_BOOT_OFFS, -		CONFIG_SYS_NAND_U_BOOT_SIZE); - -	/* and jump to it ... */ -	uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; -	(*uboot)(); -} -#endif - -#if defined(CONFIG_NAND_SPL) -void board_init_f(ulong bootflag) -#else -int arch_cpu_init(void) -#endif -{ -	/* -	 * copied from arch/arm/cpu/arm926ejs/start.S -	 * -	 * flush v4 I/D caches -	 */ -	asm("mov	r0, #0"); -	asm("mcr	p15, 0, r0, c7, c7, 0");	/* flush v3/v4 cache */ -	asm("mcr	p15, 0, r0, c8, c7, 0");	/* flush v4 TLB */ - -	/* -	 * disable MMU stuff and caches -	 */ -	asm("mrc	p15, 0, r0, c1, c0, 0"); -	/* clear bits 13, 9:8 (--V- --RS) */ -	asm("bic	r0, r0, #0x00002300"); -	/* clear bits 7, 2:0 (B--- -CAM) */ -	asm("bic	r0, r0, #0x00000087"); -	/* set bit 2 (A) Align */ -	asm("orr	r0, r0, #0x00000002"); -	/* set bit 12 (I) I-Cache */ -	asm("orr	r0, r0, #0x00001000"); -	asm("mcr	p15, 0, r0, c1, c0, 0"); - -	/* Unlock kick registers */ -	writel(0x83e70b13, &davinci_syscfg_regs->kick0); -	writel(0x95a4f1e0, &davinci_syscfg_regs->kick1); - -	dv_maskbits(&davinci_syscfg_regs->suspsrc, -		((1 << 27) | (1 << 22) | (1 << 20) | (1 << 5) |	(1 << 16))); - -	/* System PSC setup - enable all */ -	am1808_psc_init(); - -	/* Setup Pinmux */ -	am1808_pinmux_ctl(0, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX0); -	am1808_pinmux_ctl(1, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX1); -	am1808_pinmux_ctl(2, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX2); -	am1808_pinmux_ctl(3, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX3); -	am1808_pinmux_ctl(4, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX4); -	am1808_pinmux_ctl(5, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX5); -	am1808_pinmux_ctl(6, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX6); -	am1808_pinmux_ctl(7, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX7); -	am1808_pinmux_ctl(8, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX8); -	am1808_pinmux_ctl(9, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX9); -	am1808_pinmux_ctl(10, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX10); -	am1808_pinmux_ctl(11, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX11); -	am1808_pinmux_ctl(12, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX12); -	am1808_pinmux_ctl(13, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX13); -	am1808_pinmux_ctl(14, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX14); -	am1808_pinmux_ctl(15, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX15); -	am1808_pinmux_ctl(16, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX16); -	am1808_pinmux_ctl(17, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX17); -	am1808_pinmux_ctl(18, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX18); -	am1808_pinmux_ctl(19, 0xFFFFFFFF, CONFIG_SYS_AM1808_PINMUX19); - -	/* PLL setup */ -	am1808_pll_init(davinci_pllc0_regs, CONFIG_SYS_AM1808_PLL0_PLLM); -	am1808_pll_init(davinci_pllc1_regs, CONFIG_SYS_AM1808_PLL1_PLLM); - -	/* GPIO setup */ -	board_gpio_init(); - -	/* setup CSn config */ -	writel(CONFIG_SYS_AM1808_CS2CFG, &davinci_emif_regs->ab1cr); -	writel(CONFIG_SYS_AM1808_CS3CFG, &davinci_emif_regs->ab2cr); - -	am1808_lpc_transition(1, 13, 0, PSC_ENABLE); -	NS16550_init((NS16550_t)(CONFIG_SYS_NS16550_COM1), -			CONFIG_SYS_NS16550_CLK / 16 / CONFIG_BAUDRATE); - -	/* -	 * Fix Power and Emulation Management Register -	 * see sprufw3a.pdf page 37 Table 24 -	 */ -	writel(readl((CONFIG_SYS_NS16550_COM1 + 0x30)) | 0x00006001, -		(CONFIG_SYS_NS16550_COM1 + 0x30)); -#if defined(CONFIG_NAND_SPL) -	puts("ddr init\n"); -	am1808_ddr_setup(132); - -	puts("boot u-boot ...\n"); - -	nand_boot(); -#else -	am1808_ddr_setup(132); -	return 0; -#endif -} diff --git a/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c b/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c new file mode 100644 index 000000000..c7ec70f8c --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c @@ -0,0 +1,311 @@ +/* + * SoC-specific lowlevel code for DA850 + * + * Copyright (C) 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <common.h> +#include <nand.h> +#include <ns16550.h> +#include <post.h> +#include <asm/arch/da850_lowlevel.h> +#include <asm/arch/hardware.h> +#include <asm/arch/ddr2_defs.h> +#include <asm/arch/emif_defs.h> +#include <asm/arch/pll_defs.h> + +void da850_waitloop(unsigned long loopcnt) +{ +	unsigned long	i; + +	for (i = 0; i < loopcnt; i++) +		asm("   NOP"); +} + +int da850_pll_init(struct davinci_pllc_regs *reg, unsigned long pllmult) +{ +	if (reg == davinci_pllc0_regs) +		/* Unlock PLL registers. */ +		clrbits_le32(&davinci_syscfg_regs->cfgchip0, PLL_MASTER_LOCK); + +	/* +	 * Set PLLENSRC '0',bit 5, PLL Enable(PLLEN) selection is controlled +	 * through MMR +	 */ +	clrbits_le32(®->pllctl, PLLCTL_PLLENSRC); +	/* PLLCTL.EXTCLKSRC bit 9 should be left at 0 for Freon */ +	clrbits_le32(®->pllctl, PLLCTL_EXTCLKSRC); + +	/* Set PLLEN=0 => PLL BYPASS MODE */ +	clrbits_le32(®->pllctl, PLLCTL_PLLEN); + +	da850_waitloop(150); + +	if (reg == davinci_pllc0_regs) { +		/* +		 * Select the Clock Mode bit 8 as External Clock or On Chip +		 * Oscilator +		 */ +		dv_maskbits(®->pllctl, ~PLLCTL_RES_9); +		setbits_le32(®->pllctl, +			(CONFIG_SYS_DV_CLKMODE << PLLCTL_CLOCK_MODE_SHIFT)); +	} + +	/* Clear PLLRST bit to reset the PLL */ +	clrbits_le32(®->pllctl, PLLCTL_PLLRST); + +	/* Disable the PLL output */ +	setbits_le32(®->pllctl, PLLCTL_PLLDIS); + +	/* PLL initialization sequence */ +	/* +	 * Power up the PLL- PWRDN bit set to 0 to bring the PLL out of +	 * power down bit +	 */ +	clrbits_le32(®->pllctl, PLLCTL_PLLPWRDN); + +	/* Enable the PLL from Disable Mode PLLDIS bit to 0 */ +	clrbits_le32(®->pllctl, PLLCTL_PLLDIS); + +	/* Program the required multiplier value in PLLM */ +	writel(pllmult, ®->pllm); + +	/* program the postdiv */ +	if (reg == davinci_pllc0_regs) +		writel((PLL_POSTDEN | CONFIG_SYS_DA850_PLL0_POSTDIV), +			®->postdiv); +	else +		writel((PLL_POSTDEN | CONFIG_SYS_DA850_PLL1_POSTDIV), +			®->postdiv); + +	/* +	 * Check for the GOSTAT bit in PLLSTAT to clear to 0 to indicate that +	 * no GO operation is currently in progress +	 */ +	while ((readl(®->pllstat) & PLLCMD_GOSTAT) == PLLCMD_GOSTAT) +		; + +	if (reg == davinci_pllc0_regs) { +		writel(CONFIG_SYS_DA850_PLL0_PLLDIV1, ®->plldiv1); +		writel(CONFIG_SYS_DA850_PLL0_PLLDIV2, ®->plldiv2); +		writel(CONFIG_SYS_DA850_PLL0_PLLDIV3, ®->plldiv3); +		writel(CONFIG_SYS_DA850_PLL0_PLLDIV4, ®->plldiv4); +		writel(CONFIG_SYS_DA850_PLL0_PLLDIV5, ®->plldiv5); +		writel(CONFIG_SYS_DA850_PLL0_PLLDIV6, ®->plldiv6); +		writel(CONFIG_SYS_DA850_PLL0_PLLDIV7, ®->plldiv7); +	} else { +		writel(CONFIG_SYS_DA850_PLL1_PLLDIV1, ®->plldiv1); +		writel(CONFIG_SYS_DA850_PLL1_PLLDIV2, ®->plldiv2); +		writel(CONFIG_SYS_DA850_PLL1_PLLDIV3, ®->plldiv3); +	} + +	/* +	 * Set the GOSET bit in PLLCMD to 1 to initiate a new divider +	 * transition. +	 */ +	setbits_le32(®->pllcmd, PLLCMD_GOSTAT); + +	/* +	 * Wait for the GOSTAT bit in PLLSTAT to clear to 0 +	 * (completion of phase alignment). +	 */ +	while ((readl(®->pllstat) & PLLCMD_GOSTAT) == PLLCMD_GOSTAT) +		; + +	/* Wait for PLL to reset properly. See PLL spec for PLL reset time */ +	da850_waitloop(200); + +	/* Set the PLLRST bit in PLLCTL to 1 to bring the PLL out of reset */ +	setbits_le32(®->pllctl, PLLCTL_PLLRST); + +	/* Wait for PLL to lock. See PLL spec for PLL lock time */ +	da850_waitloop(2400); + +	/* +	 * Set the PLLEN bit in PLLCTL to 1 to remove the PLL from bypass +	 * mode +	 */ +	setbits_le32(®->pllctl, PLLCTL_PLLEN); + + +	/* +	 * clear EMIFA and EMIFB clock source settings, let them +	 * run off SYSCLK +	 */ +	if (reg == davinci_pllc0_regs) +		dv_maskbits(&davinci_syscfg_regs->cfgchip3, +			~(PLL_SCSCFG3_DIV45PENA | PLL_SCSCFG3_EMA_CLKSRC)); + +	return 0; +} + +int da850_ddr_setup(void) +{ +	unsigned long	tmp; + +	/* Enable the Clock to DDR2/mDDR */ +	lpsc_on(DAVINCI_LPSC_DDR_EMIF); + +	tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); +	if ((tmp & VTP_POWERDWN) == VTP_POWERDWN) { +		/* Begin VTP Calibration */ +		clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_POWERDWN); +		clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_LOCK); +		setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); +		clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); +		setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); + +		/* Polling READY bit to see when VTP calibration is done */ +		tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); +		while ((tmp & VTP_READY) != VTP_READY) +			tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); + +		setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_LOCK); +		setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_POWERDWN); + +		setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_IOPWRDWN); +	} + +	writel(CONFIG_SYS_DA850_DDR2_DDRPHYCR, &dv_ddr2_regs_ctrl->ddrphycr); +	clrbits_le32(&davinci_syscfg1_regs->ddr_slew, +		(1 << DDR_SLEW_CMOSEN_BIT)); + +	/* +	 * SDRAM Configuration Register (SDCR): +	 * First set the BOOTUNLOCK bit to make configuration bits +	 * writeable. +	 */ +	setbits_le32(&dv_ddr2_regs_ctrl->sdbcr, DV_DDR_BOOTUNLOCK); + +	/* +	 * Write the new value of these bits and clear BOOTUNLOCK. +	 * At the same time, set the TIMUNLOCK bit to allow changing +	 * the timing registers +	 */ +	tmp = CONFIG_SYS_DA850_DDR2_SDBCR; +	tmp &= ~DV_DDR_BOOTUNLOCK; +	tmp |= DV_DDR_TIMUNLOCK; +	writel(tmp, &dv_ddr2_regs_ctrl->sdbcr); + +	/* write memory configuration and timing */ +	writel(CONFIG_SYS_DA850_DDR2_SDBCR2, &dv_ddr2_regs_ctrl->sdbcr2); +	writel(CONFIG_SYS_DA850_DDR2_SDTIMR, &dv_ddr2_regs_ctrl->sdtimr); +	writel(CONFIG_SYS_DA850_DDR2_SDTIMR2, &dv_ddr2_regs_ctrl->sdtimr2); + +	/* clear the TIMUNLOCK bit and write the value of the CL field */ +	tmp &= ~DV_DDR_TIMUNLOCK; +	writel(tmp, &dv_ddr2_regs_ctrl->sdbcr); + +	/* +	 * LPMODEN and MCLKSTOPEN must be set! +	 * Without this bits set, PSC don;t switch states !! +	 */ +	writel(CONFIG_SYS_DA850_DDR2_SDRCR | +		(1 << DV_DDR_SRCR_LPMODEN_SHIFT) | +		(1 << DV_DDR_SRCR_MCLKSTOPEN_SHIFT), +		&dv_ddr2_regs_ctrl->sdrcr); + +	/* SyncReset the Clock to EMIF3A SDRAM */ +	lpsc_syncreset(DAVINCI_LPSC_DDR_EMIF); +	/* Enable the Clock to EMIF3A SDRAM */ +	lpsc_on(DAVINCI_LPSC_DDR_EMIF); + +	/* disable self refresh */ +	clrbits_le32(&dv_ddr2_regs_ctrl->sdrcr, +		DV_DDR_SDRCR_LPMODEN | DV_DDR_SDRCR_LPMODEN); +	writel(CONFIG_SYS_DA850_DDR2_PBBPR, &dv_ddr2_regs_ctrl->pbbpr); + +	return 0; +} + +void da850_pinmux_ctl(unsigned long offset, unsigned long mask, +	unsigned long value) +{ +	clrbits_le32(&davinci_syscfg_regs->pinmux[offset], mask); +	setbits_le32(&davinci_syscfg_regs->pinmux[offset], (mask & value)); +} + +__attribute__((weak)) +void board_gpio_init(void) +{ +	return; +} + +int arch_cpu_init(void) +{ +	/* Unlock kick registers */ +	writel(DV_SYSCFG_KICK0_UNLOCK, &davinci_syscfg_regs->kick0); +	writel(DV_SYSCFG_KICK1_UNLOCK, &davinci_syscfg_regs->kick1); + +	dv_maskbits(&davinci_syscfg_regs->suspsrc, +		CONFIG_SYS_DA850_SYSCFG_SUSPSRC); + +	/* Setup Pinmux */ +	da850_pinmux_ctl(0, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX0); +	da850_pinmux_ctl(1, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX1); +	da850_pinmux_ctl(2, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX2); +	da850_pinmux_ctl(3, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX3); +	da850_pinmux_ctl(4, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX4); +	da850_pinmux_ctl(5, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX5); +	da850_pinmux_ctl(6, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX6); +	da850_pinmux_ctl(7, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX7); +	da850_pinmux_ctl(8, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX8); +	da850_pinmux_ctl(9, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX9); +	da850_pinmux_ctl(10, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX10); +	da850_pinmux_ctl(11, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX11); +	da850_pinmux_ctl(12, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX12); +	da850_pinmux_ctl(13, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX13); +	da850_pinmux_ctl(14, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX14); +	da850_pinmux_ctl(15, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX15); +	da850_pinmux_ctl(16, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX16); +	da850_pinmux_ctl(17, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX17); +	da850_pinmux_ctl(18, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX18); +	da850_pinmux_ctl(19, 0xFFFFFFFF, CONFIG_SYS_DA850_PINMUX19); + +	/* PLL setup */ +	da850_pll_init(davinci_pllc0_regs, CONFIG_SYS_DA850_PLL0_PLLM); +	da850_pll_init(davinci_pllc1_regs, CONFIG_SYS_DA850_PLL1_PLLM); + +	/* GPIO setup */ +	board_gpio_init(); + +	/* setup CSn config */ +#if defined(CONFIG_SYS_DA850_CS2CFG) +	writel(CONFIG_SYS_DA850_CS2CFG, &davinci_emif_regs->ab1cr); +#endif +#if defined(CONFIG_SYS_DA850_CS3CFG) +	writel(CONFIG_SYS_DA850_CS3CFG, &davinci_emif_regs->ab2cr); +#endif + +	lpsc_on(CONFIG_SYS_DA850_LPSC_UART); +	NS16550_init((NS16550_t)(CONFIG_SYS_NS16550_COM1), +			CONFIG_SYS_NS16550_CLK / 16 / CONFIG_BAUDRATE); + +	/* +	 * Fix Power and Emulation Management Register +	 * see sprufw3a.pdf page 37 Table 24 +	 */ +	writel((DAVINCI_UART_PWREMU_MGMT_FREE | DAVINCI_UART_PWREMU_MGMT_URRST | +		DAVINCI_UART_PWREMU_MGMT_UTRST), +	       &davinci_uart2_ctrl_regs->pwremu_mgmt); + +	da850_ddr_setup(); +	return 0; +} diff --git a/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c b/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c index 3772e64cc..6e998ded9 100644 --- a/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c +++ b/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c @@ -45,7 +45,8 @@ int dm365_pll1_init(unsigned long pllmult, unsigned long prediv)  	clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLPWRDN);  	clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_RES_9); -	setbits_le32(&dv_pll0_regs->pllctl, clksrc << 8); +	setbits_le32(&dv_pll0_regs->pllctl, +		clksrc << PLLCTL_CLOCK_MODE_SHIFT);  	/*  	 * Set PLLENSRC '0', PLL Enable(PLLEN) selection is controlled @@ -82,7 +83,7 @@ int dm365_pll1_init(unsigned long pllmult, unsigned long prediv)  	writel(PLLSECCTL_STOPMODE | PLLSECCTL_TINITZ, &dv_pll0_regs->secctl);  	/* Program the PostDiv for PLL1 */ -	writel(0x8000, &dv_pll0_regs->postdiv); +	writel(PLL_POSTDEN, &dv_pll0_regs->postdiv);  	/* Post divider setting for PLL1 */  	writel(CONFIG_SYS_DM36x_PLL1_PLLDIV1, &dv_pll0_regs->plldiv1); @@ -126,7 +127,8 @@ int dm365_pll2_init(unsigned long pllm, unsigned long prediv)  	 * VDB has input on MXI pin  	 */  	clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_RES_9); -	setbits_le32(&dv_pll1_regs->pllctl, clksrc << 8); +	setbits_le32(&dv_pll1_regs->pllctl, +		clksrc << PLLCTL_CLOCK_MODE_SHIFT);  	/*  	 * Set PLLENSRC '0', PLL Enable(PLLEN) selection is controlled @@ -151,7 +153,7 @@ int dm365_pll2_init(unsigned long pllm, unsigned long prediv)  	writel(pllm, &dv_pll1_regs->pllm);  	writel(prediv, &dv_pll1_regs->prediv); -	writel(0x8000, &dv_pll1_regs->postdiv); +	writel(PLL_POSTDEN, &dv_pll1_regs->postdiv);  	/* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 1 */  	writel(PLLSECCTL_STOPMODE | PLLSECCTL_TENABLEDIV | PLLSECCTL_TENABLE | @@ -261,21 +263,23 @@ void dm365_vpss_sync_reset(void)  		VPSS_CLK_CTL_VPSS_CLKMD);  	/* LPSC SyncReset DDR Clock Enable */ -	writel(((readl(&dv_psc_regs->mdctl[47]) & ~PSC_MD_STATE_MSK) | -		PSC_SYNCRESET), &dv_psc_regs->mdctl[47]); +	writel(((readl(&dv_psc_regs->mdctl[DAVINCI_LPSC_VPSSMASTER]) & +		~PSC_MD_STATE_MSK) | PSC_SYNCRESET), +		&dv_psc_regs->mdctl[DAVINCI_LPSC_VPSSMASTER]);  	writel((1 << PdNum), &dv_psc_regs->ptcmd);  	while (!(((readl(&dv_psc_regs->ptstat) >> PdNum) & PSC_GOSTAT) == 0))  		; -	while (!((readl(&dv_psc_regs->mdstat[47]) &  PSC_MD_STATE_MSK) == -		PSC_SYNCRESET)) +	while (!((readl(&dv_psc_regs->mdstat[DAVINCI_LPSC_VPSSMASTER]) & +		PSC_MD_STATE_MSK) == PSC_SYNCRESET))  		;  }  void dm365_por_reset(void)  { -	if (readl(&dv_pll0_regs->rstype) & 3) +	if (readl(&dv_pll0_regs->rstype) & +		(PLL_RSTYPE_POR | PLL_RSTYPE_XWRST))  		dm365_vpss_sync_reset();  } @@ -291,19 +295,20 @@ void dm365_psc_init(void)  	for (lpscgroup = lpscmin; lpscgroup <= lpscmax; lpscgroup++) {  		if (lpscgroup == 0) { -			lpsc_start = 0; /* Enabling LPSC 3 to 28 SCR first */ -			lpsc_end   = 28; +			/* Enabling LPSC 3 to 28 SCR first */ +			lpsc_start = DAVINCI_LPSC_VPSSMSTR; +			lpsc_end   = DAVINCI_LPSC_TIMER1;  		} else if (lpscgroup == 1) { /* Skip locked LPSCs [29-37] */ -			lpsc_start = 38; -			lpsc_end   = 47; +			lpsc_start = DAVINCI_LPSC_CFG5; +			lpsc_end   = DAVINCI_LPSC_VPSSMASTER;  		} else { -			lpsc_start = 50; -			lpsc_end   = 51; +			lpsc_start = DAVINCI_LPSC_MJCP; +			lpsc_end   = DAVINCI_LPSC_HDVICP;  		}  		/* NEXT=0x3, Enable LPSC's */  		for (i = lpsc_start; i <= lpsc_end; i++) -			setbits_le32(&dv_psc_regs->mdctl[i], 0x3); +			setbits_le32(&dv_psc_regs->mdctl[i], PSC_ENABLE);  		/*  		 * Program goctl to start transition sequence for LPSCs @@ -322,7 +327,7 @@ void dm365_psc_init(void)  		/* Wait for MODSTAT = ENABLE from LPSC's */  		for (i = lpsc_start; i <= lpsc_end; i++)  			while (!((readl(&dv_psc_regs->mdstat[i]) & -				PSC_MD_STATE_MSK) == 0x3)) +				PSC_MD_STATE_MSK) == PSC_ENABLE))  				;  	}  } @@ -332,7 +337,7 @@ static void dm365_emif_init(void)  	writel(CONFIG_SYS_DM36x_AWCCR, &davinci_emif_regs->awccr);  	writel(CONFIG_SYS_DM36x_AB1CR, &davinci_emif_regs->ab1cr); -	setbits_le32(&davinci_emif_regs->nandfcr, 1); +	setbits_le32(&davinci_emif_regs->nandfcr, DAVINCI_NANDFCR_CS2NAND);  	writel(CONFIG_SYS_DM36x_AB2CR, &davinci_emif_regs->ab2cr); @@ -361,31 +366,12 @@ int post_log(char *format, ...)  void dm36x_lowlevel_init(ulong bootflag)  { -	/* -	 * copied from arch/arm/cpu/arm926ejs/start.S -	 * -	 * flush v4 I/D caches -	 */ -	asm("mov	r0, #0"); -	asm("mcr	p15, 0, r0, c7, c7, 0");	/* flush v3/v4 cache */ -	asm("mcr	p15, 0, r0, c8, c7, 0");	/* flush v4 TLB */ - -	/* -	 * disable MMU stuff and caches -	 */ -	asm("mrc	p15, 0, r0, c1, c0, 0"); -	/* clear bits 13, 9:8 (--V- --RS) */ -	asm("bic	r0, r0, #0x00002300"); -	/* clear bits 7, 2:0 (B--- -CAM) */ -	asm("bic	r0, r0, #0x00000087"); -	/* set bit 2 (A) Align */ -	asm("orr	r0, r0, #0x00000002"); -	/* set bit 12 (I) I-Cache */ -	asm("orr	r0, r0, #0x00001000"); -	asm("mcr	p15, 0, r0, c1, c0, 0"); +	struct davinci_uart_ctrl_regs *davinci_uart_ctrl_regs = +		(struct davinci_uart_ctrl_regs *)(CONFIG_SYS_NS16550_COM1 + +		DAVINCI_UART_CTRL_BASE);  	/* Mask all interrupts */ -	writel(0x04, &dv_aintc_regs->intctl); +	writel(DV_AINTC_INTCTL_IDMODE, &dv_aintc_regs->intctl);  	writel(0x0, &dv_aintc_regs->eabase);  	writel(0x0, &dv_aintc_regs->eint0);  	writel(0x0, &dv_aintc_regs->eint1); @@ -422,7 +408,10 @@ void dm36x_lowlevel_init(ulong bootflag)  	 * Fix Power and Emulation Management Register  	 * see sprufh2.pdf page 38 Table 22  	 */ -	writel(0x0000e003, (CONFIG_SYS_NS16550_COM1 + 0x30)); +	writel((DAVINCI_UART_PWREMU_MGMT_FREE | DAVINCI_UART_PWREMU_MGMT_URRST | +		DAVINCI_UART_PWREMU_MGMT_UTRST), +	       &davinci_uart_ctrl_regs->pwremu_mgmt); +  	puts("ddr init\n");  	dm365_ddr_setup(); diff --git a/arch/arm/cpu/arm926ejs/mx28/Makefile b/arch/arm/cpu/arm926ejs/mx28/Makefile new file mode 100644 index 000000000..7845310cf --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx28/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 $(TOPDIR)/config.mk + +LIB	= $(obj)lib$(SOC).o + +COBJS	= clock.o mx28.o iomux.o timer.o + +SRCS	:= $(START:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) +START	:= $(addprefix $(obj),$(START)) + +all:	$(obj).depend $(LIB) + +$(LIB):	$(OBJS) +	$(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/mx28/clock.c b/arch/arm/cpu/arm926ejs/mx28/clock.c new file mode 100644 index 000000000..f69850600 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx28/clock.c @@ -0,0 +1,355 @@ +/* + * Freescale i.MX28 clock setup code + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> + +/* The PLL frequency is always 480MHz, see section 10.2 in iMX28 datasheet. */ +#define	PLL_FREQ_KHZ	480000 +#define	PLL_FREQ_COEF	18 +/* The XTAL frequency is always 24MHz, see section 10.2 in iMX28 datasheet. */ +#define	XTAL_FREQ_KHZ	24000 + +#define	PLL_FREQ_MHZ	(PLL_FREQ_KHZ / 1000) +#define	XTAL_FREQ_MHZ	(XTAL_FREQ_KHZ / 1000) + +static uint32_t mx28_get_pclk(void) +{ +	struct mx28_clkctrl_regs *clkctrl_regs = +		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; + +	uint32_t clkctrl, clkseq, clkfrac; +	uint32_t frac, div; + +	clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu); + +	/* No support of fractional divider calculation */ +	if (clkctrl & +		(CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) { +		return 0; +	} + +	clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); + +	/* XTAL Path */ +	if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) { +		div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >> +			CLKCTRL_CPU_DIV_XTAL_OFFSET; +		return XTAL_FREQ_MHZ / div; +	} + +	/* REF Path */ +	clkfrac = readl(&clkctrl_regs->hw_clkctrl_frac0); +	frac = clkfrac & CLKCTRL_FRAC0_CPUFRAC_MASK; +	div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK; +	return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; +} + +static uint32_t mx28_get_hclk(void) +{ +	struct mx28_clkctrl_regs *clkctrl_regs = +		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; + +	uint32_t div; +	uint32_t clkctrl; + +	clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus); + +	/* No support of fractional divider calculation */ +	if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN) +		return 0; + +	div = clkctrl & CLKCTRL_HBUS_DIV_MASK; +	return mx28_get_pclk() / div; +} + +static uint32_t mx28_get_emiclk(void) +{ +	struct mx28_clkctrl_regs *clkctrl_regs = +		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; + +	uint32_t frac, div; +	uint32_t clkctrl, clkseq, clkfrac; + +	clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); +	clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi); + +	/* XTAL Path */ +	if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) { +		div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >> +			CLKCTRL_EMI_DIV_XTAL_OFFSET; +		return XTAL_FREQ_MHZ / div; +	} + +	clkfrac = readl(&clkctrl_regs->hw_clkctrl_frac0); + +	/* REF Path */ +	frac = (clkfrac & CLKCTRL_FRAC0_EMIFRAC_MASK) >> +		CLKCTRL_FRAC0_EMIFRAC_OFFSET; +	div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK; +	return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; +} + +static uint32_t mx28_get_gpmiclk(void) +{ +	struct mx28_clkctrl_regs *clkctrl_regs = +		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; + +	uint32_t frac, div; +	uint32_t clkctrl, clkseq, clkfrac; + +	clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); +	clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi); + +	/* XTAL Path */ +	if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) { +		div = clkctrl & CLKCTRL_GPMI_DIV_MASK; +		return XTAL_FREQ_MHZ / div; +	} + +	clkfrac = readl(&clkctrl_regs->hw_clkctrl_frac1); + +	/* REF Path */ +	frac = (clkfrac & CLKCTRL_FRAC1_GPMIFRAC_MASK) >> +		CLKCTRL_FRAC1_GPMIFRAC_OFFSET; +	div = clkctrl & CLKCTRL_GPMI_DIV_MASK; +	return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; +} + +/* + * Set IO clock frequency, in kHz + */ +void mx28_set_ioclk(enum mxs_ioclock io, uint32_t freq) +{ +	struct mx28_clkctrl_regs *clkctrl_regs = +		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; +	uint32_t div; + +	if (freq == 0) +		return; + +	if (io > MXC_IOCLK1) +		return; + +	div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq; + +	if (div < 18) +		div = 18; + +	if (div > 35) +		div = 35; + +	if (io == MXC_IOCLK0) { +		writel(CLKCTRL_FRAC0_CLKGATEIO0, +			&clkctrl_regs->hw_clkctrl_frac0_set); +		clrsetbits_le32(&clkctrl_regs->hw_clkctrl_frac0, +				CLKCTRL_FRAC0_IO0FRAC_MASK, +				div << CLKCTRL_FRAC0_IO0FRAC_OFFSET); +		writel(CLKCTRL_FRAC0_CLKGATEIO0, +			&clkctrl_regs->hw_clkctrl_frac0_clr); +	} else { +		writel(CLKCTRL_FRAC0_CLKGATEIO1, +			&clkctrl_regs->hw_clkctrl_frac0_set); +		clrsetbits_le32(&clkctrl_regs->hw_clkctrl_frac0, +				CLKCTRL_FRAC0_IO1FRAC_MASK, +				div << CLKCTRL_FRAC0_IO1FRAC_OFFSET); +		writel(CLKCTRL_FRAC0_CLKGATEIO1, +			&clkctrl_regs->hw_clkctrl_frac0_clr); +	} +} + +/* + * Get IO clock, returns IO clock in kHz + */ +static uint32_t mx28_get_ioclk(enum mxs_ioclock io) +{ +	struct mx28_clkctrl_regs *clkctrl_regs = +		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; +	uint32_t tmp, ret; + +	if (io > MXC_IOCLK1) +		return 0; + +	tmp = readl(&clkctrl_regs->hw_clkctrl_frac0); + +	if (io == MXC_IOCLK0) +		ret = (tmp & CLKCTRL_FRAC0_IO0FRAC_MASK) >> +			CLKCTRL_FRAC0_IO0FRAC_OFFSET; +	else +		ret = (tmp & CLKCTRL_FRAC0_IO1FRAC_MASK) >> +			CLKCTRL_FRAC0_IO1FRAC_OFFSET; + +	return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret; +} + +/* + * Configure SSP clock frequency, in kHz + */ +void mx28_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal) +{ +	struct mx28_clkctrl_regs *clkctrl_regs = +		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; +	uint32_t clk, clkreg; + +	if (ssp > MXC_SSPCLK3) +		return; + +	clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) + +			(ssp * sizeof(struct mx28_register)); + +	clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE); +	while (readl(clkreg) & CLKCTRL_SSP_CLKGATE) +		; + +	if (xtal) +		clk = XTAL_FREQ_KHZ; +	else +		clk = mx28_get_ioclk(ssp >> 1); + +	if (freq > clk) +		return; + +	/* Calculate the divider and cap it if necessary */ +	clk /= freq; +	if (clk > CLKCTRL_SSP_DIV_MASK) +		clk = CLKCTRL_SSP_DIV_MASK; + +	clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk); +	while (readl(clkreg) & CLKCTRL_SSP_BUSY) +		; + +	if (xtal) +		writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp, +			&clkctrl_regs->hw_clkctrl_clkseq_set); +	else +		writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp, +			&clkctrl_regs->hw_clkctrl_clkseq_clr); +} + +/* + * Return SSP frequency, in kHz + */ +static uint32_t mx28_get_sspclk(enum mxs_sspclock ssp) +{ +	struct mx28_clkctrl_regs *clkctrl_regs = +		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; +	uint32_t clkreg; +	uint32_t clk, tmp; + +	if (ssp > MXC_SSPCLK3) +		return 0; + +	tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq); +	if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp)) +		return XTAL_FREQ_KHZ; + +	clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) + +			(ssp * sizeof(struct mx28_register)); + +	tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK; + +	if (tmp == 0) +		return 0; + +	clk = mx28_get_ioclk(ssp >> 1); + +	return clk / tmp; +} + +/* + * Set SSP/MMC bus frequency, in kHz) + */ +void mx28_set_ssp_busclock(unsigned int bus, uint32_t freq) +{ +	struct mx28_ssp_regs *ssp_regs; +	const uint32_t sspclk = mx28_get_sspclk(bus); +	uint32_t reg; +	uint32_t divide, rate, tgtclk; + +	ssp_regs = (struct mx28_ssp_regs *)(MXS_SSP0_BASE + (bus * 0x2000)); + +	/* +	 * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)), +	 * CLOCK_DIVIDE has to be an even value from 2 to 254, and +	 * CLOCK_RATE could be any integer from 0 to 255. +	 */ +	for (divide = 2; divide < 254; divide += 2) { +		rate = sspclk / freq / divide; +		if (rate <= 256) +			break; +	} + +	tgtclk = sspclk / divide / rate; +	while (tgtclk > freq) { +		rate++; +		tgtclk = sspclk / divide / rate; +	} +	if (rate > 256) +		rate = 256; + +	/* Always set timeout the maximum */ +	reg = SSP_TIMING_TIMEOUT_MASK | +		(divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) | +		((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET); +	writel(reg, &ssp_regs->hw_ssp_timing); + +	debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n", +		bus, tgtclk, freq); +} + +uint32_t mxc_get_clock(enum mxc_clock clk) +{ +	switch (clk) { +	case MXC_ARM_CLK: +		return mx28_get_pclk() * 1000000; +	case MXC_GPMI_CLK: +		return mx28_get_gpmiclk() * 1000000; +	case MXC_AHB_CLK: +	case MXC_IPG_CLK: +		return mx28_get_hclk() * 1000000; +	case MXC_EMI_CLK: +		return mx28_get_emiclk(); +	case MXC_IO0_CLK: +		return mx28_get_ioclk(MXC_IOCLK0); +	case MXC_IO1_CLK: +		return mx28_get_ioclk(MXC_IOCLK1); +	case MXC_SSP0_CLK: +		return mx28_get_sspclk(MXC_SSPCLK0); +	case MXC_SSP1_CLK: +		return mx28_get_sspclk(MXC_SSPCLK1); +	case MXC_SSP2_CLK: +		return mx28_get_sspclk(MXC_SSPCLK2); +	case MXC_SSP3_CLK: +		return mx28_get_sspclk(MXC_SSPCLK3); +	} + +	return 0; +} diff --git a/arch/arm/cpu/arm926ejs/mx28/iomux.c b/arch/arm/cpu/arm926ejs/mx28/iomux.c new file mode 100644 index 000000000..9ea411f22 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx28/iomux.c @@ -0,0 +1,109 @@ +/* + * Copyright 2004-2006,2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> + * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH, + *                       <armlinux@phytec.de> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <common.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/iomux.h> +#include <asm/arch/imx-regs.h> + +#if	defined(CONFIG_MX23) +#define	DRIVE_OFFSET	0x200 +#define	PULL_OFFSET	0x400 +#elif	defined(CONFIG_MX28) +#define	DRIVE_OFFSET	0x300 +#define	PULL_OFFSET	0x600 +#else +#error "Please select CONFIG_MX23 or CONFIG_MX28" +#endif + +/* + * configures a single pad in the iomuxer + */ +int mxs_iomux_setup_pad(iomux_cfg_t pad) +{ +	u32 reg, ofs, bp, bm; +	void *iomux_base = (void *)MXS_PINCTRL_BASE; +	struct mx28_register *mxs_reg; + +	/* muxsel */ +	ofs = 0x100; +	ofs += PAD_BANK(pad) * 0x20 + PAD_PIN(pad) / 16 * 0x10; +	bp = PAD_PIN(pad) % 16 * 2; +	bm = 0x3 << bp; +	reg = readl(iomux_base + ofs); +	reg &= ~bm; +	reg |= PAD_MUXSEL(pad) << bp; +	writel(reg, iomux_base + ofs); + +	/* drive */ +	ofs = DRIVE_OFFSET; +	ofs += PAD_BANK(pad) * 0x40 + PAD_PIN(pad) / 8 * 0x10; +	/* mA */ +	if (PAD_MA_VALID(pad)) { +		bp = PAD_PIN(pad) % 8 * 4; +		bm = 0x3 << bp; +		reg = readl(iomux_base + ofs); +		reg &= ~bm; +		reg |= PAD_MA(pad) << bp; +		writel(reg, iomux_base + ofs); +	} +	/* vol */ +	if (PAD_VOL_VALID(pad)) { +		bp = PAD_PIN(pad) % 8 * 4 + 2; +		mxs_reg = (struct mx28_register *)(iomux_base + ofs); +		if (PAD_VOL(pad)) +			writel(1 << bp, &mxs_reg->reg_set); +		else +			writel(1 << bp, &mxs_reg->reg_clr); +	} + +	/* pull */ +	if (PAD_PULL_VALID(pad)) { +		ofs = PULL_OFFSET; +		ofs += PAD_BANK(pad) * 0x10; +		bp = PAD_PIN(pad); +		mxs_reg = (struct mx28_register *)(iomux_base + ofs); +		if (PAD_PULL(pad)) +			writel(1 << bp, &mxs_reg->reg_set); +		else +			writel(1 << bp, &mxs_reg->reg_clr); +	} + +	return 0; +} + +int mxs_iomux_setup_multiple_pads(const iomux_cfg_t *pad_list, unsigned count) +{ +	const iomux_cfg_t *p = pad_list; +	int i; +	int ret; + +	for (i = 0; i < count; i++) { +		ret = mxs_iomux_setup_pad(*p); +		if (ret) +			return ret; +		p++; +	} + +	return 0; +} diff --git a/arch/arm/cpu/arm926ejs/mx28/mx28.c b/arch/arm/cpu/arm926ejs/mx28/mx28.c new file mode 100644 index 000000000..088c019b7 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx28/mx28.c @@ -0,0 +1,221 @@ +/* + * Freescale i.MX28 common code + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/gpio.h> +#include <asm/arch/iomux.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* 1 second delay should be plenty of time for block reset. */ +#define	RESET_MAX_TIMEOUT	1000000 + +#define	MX28_BLOCK_SFTRST	(1 << 31) +#define	MX28_BLOCK_CLKGATE	(1 << 30) + +/* Lowlevel init isn't used on i.MX28, so just have a dummy here */ +inline void lowlevel_init(void) {} + +void reset_cpu(ulong ignored) __attribute__((noreturn)); + +void reset_cpu(ulong ignored) +{ + +	struct mx28_rtc_regs *rtc_regs = +		(struct mx28_rtc_regs *)MXS_RTC_BASE; + +	/* Wait 1 uS before doing the actual watchdog reset */ +	writel(1, &rtc_regs->hw_rtc_watchdog); +	writel(RTC_CTRL_WATCHDOGEN, &rtc_regs->hw_rtc_ctrl_set); + +	/* Endless loop, reset will exit from here */ +	for (;;) +		; +} + +int mx28_wait_mask_set(struct mx28_register *reg, uint32_t mask, int timeout) +{ +	while (--timeout) { +		if ((readl(®->reg) & mask) == mask) +			break; +		udelay(1); +	} + +	return !timeout; +} + +int mx28_wait_mask_clr(struct mx28_register *reg, uint32_t mask, int timeout) +{ +	while (--timeout) { +		if ((readl(®->reg) & mask) == 0) +			break; +		udelay(1); +	} + +	return !timeout; +} + +int mx28_reset_block(struct mx28_register *reg) +{ +	/* Clear SFTRST */ +	writel(MX28_BLOCK_SFTRST, ®->reg_clr); + +	if (mx28_wait_mask_clr(reg, MX28_BLOCK_SFTRST, RESET_MAX_TIMEOUT)) +		return 1; + +	/* Clear CLKGATE */ +	writel(MX28_BLOCK_CLKGATE, ®->reg_clr); + +	/* Set SFTRST */ +	writel(MX28_BLOCK_SFTRST, ®->reg_set); + +	/* Wait for CLKGATE being set */ +	if (mx28_wait_mask_set(reg, MX28_BLOCK_CLKGATE, RESET_MAX_TIMEOUT)) +		return 1; + +	/* Clear SFTRST */ +	writel(MX28_BLOCK_SFTRST, ®->reg_clr); + +	if (mx28_wait_mask_clr(reg, MX28_BLOCK_SFTRST, RESET_MAX_TIMEOUT)) +		return 1; + +	/* Clear CLKGATE */ +	writel(MX28_BLOCK_CLKGATE, ®->reg_clr); + +	if (mx28_wait_mask_clr(reg, MX28_BLOCK_CLKGATE, RESET_MAX_TIMEOUT)) +		return 1; + +	return 0; +} + +void mx28_fixup_vt(uint32_t start_addr) +{ +	uint32_t *vt = (uint32_t *)0x20; +	int i; + +	for (i = 0; i < 8; i++) +		vt[i] = start_addr + (4 * i); +} + +#ifdef	CONFIG_ARCH_MISC_INIT +int arch_misc_init(void) +{ +	mx28_fixup_vt(gd->relocaddr); +	return 0; +} +#endif + +#ifdef	CONFIG_ARCH_CPU_INIT +int arch_cpu_init(void) +{ +	struct mx28_clkctrl_regs *clkctrl_regs = +		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; +	extern uint32_t _start; + +	mx28_fixup_vt((uint32_t)&_start); + +	/* +	 * Enable NAND clock +	 */ +	/* Clear bypass bit */ +	writel(CLKCTRL_CLKSEQ_BYPASS_GPMI, +		&clkctrl_regs->hw_clkctrl_clkseq_set); + +	/* Set GPMI clock to ref_gpmi / 12 */ +	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_gpmi, +		CLKCTRL_GPMI_CLKGATE | CLKCTRL_GPMI_DIV_MASK, 1); + +	udelay(1000); + +	/* +	 * Configure GPIO unit +	 */ +	mxs_gpio_init(); + +	return 0; +} +#endif + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ +	printf("Freescale i.MX28 family\n"); +	return 0; +} +#endif + +int do_mx28_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	printf("CPU:   %3d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000); +	printf("BUS:   %3d MHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000000); +	printf("EMI:   %3d MHz\n", mxc_get_clock(MXC_EMI_CLK)); +	printf("GPMI:  %3d MHz\n", mxc_get_clock(MXC_GPMI_CLK) / 1000000); +	return 0; +} + +/* + * Initializes on-chip ethernet controllers. + */ +#ifdef	CONFIG_CMD_NET +int cpu_eth_init(bd_t *bis) +{ +	struct mx28_clkctrl_regs *clkctrl_regs = +		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; + +	/* Turn on ENET clocks */ +	clrbits_le32(&clkctrl_regs->hw_clkctrl_enet, +		CLKCTRL_ENET_SLEEP | CLKCTRL_ENET_DISABLE); + +	/* Set up ENET PLL for 50 MHz */ +	/* Power on ENET PLL */ +	writel(CLKCTRL_PLL2CTRL0_POWER, +		&clkctrl_regs->hw_clkctrl_pll2ctrl0_set); + +	udelay(10); + +	/* Gate on ENET PLL */ +	writel(CLKCTRL_PLL2CTRL0_CLKGATE, +		&clkctrl_regs->hw_clkctrl_pll2ctrl0_clr); + +	/* Enable pad output */ +	setbits_le32(&clkctrl_regs->hw_clkctrl_enet, CLKCTRL_ENET_CLK_OUT_EN); + +	return 0; +} +#endif + +U_BOOT_CMD( +	clocks,	CONFIG_SYS_MAXARGS, 1, do_mx28_showclocks, +	"display clocks", +	"" +); diff --git a/arch/arm/cpu/arm926ejs/mx28/timer.c b/arch/arm/cpu/arm926ejs/mx28/timer.c new file mode 100644 index 000000000..dbc904d08 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx28/timer.c @@ -0,0 +1,141 @@ +/* + * Freescale i.MX28 timer driver + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * (C) Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> + +/* Maximum fixed count */ +#define TIMER_LOAD_VAL	0xffffffff + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp (gd->tbl) +#define lastdec (gd->lastinc) + +/* + * This driver uses 1kHz clock source. + */ +#define	MX28_INCREMENTER_HZ		1000 + +static inline unsigned long tick_to_time(unsigned long tick) +{ +	return tick / (MX28_INCREMENTER_HZ / CONFIG_SYS_HZ); +} + +static inline unsigned long time_to_tick(unsigned long time) +{ +	return time * (MX28_INCREMENTER_HZ / CONFIG_SYS_HZ); +} + +/* Calculate how many ticks happen in "us" microseconds */ +static inline unsigned long us_to_tick(unsigned long us) +{ +	return (us * MX28_INCREMENTER_HZ) / 1000000; +} + +int timer_init(void) +{ +	struct mx28_timrot_regs *timrot_regs = +		(struct mx28_timrot_regs *)MXS_TIMROT_BASE; + +	/* Reset Timers and Rotary Encoder module */ +	mx28_reset_block(&timrot_regs->hw_timrot_rotctrl_reg); + +	/* Set fixed_count to 0 */ +	writel(0, &timrot_regs->hw_timrot_fixed_count0); + +	/* Set UPDATE bit and 1Khz frequency */ +	writel(TIMROT_TIMCTRLn_UPDATE | TIMROT_TIMCTRLn_RELOAD | +		TIMROT_TIMCTRLn_SELECT_1KHZ_XTAL, +		&timrot_regs->hw_timrot_timctrl0); + +	/* Set fixed_count to maximal value */ +	writel(TIMER_LOAD_VAL, &timrot_regs->hw_timrot_fixed_count0); + +	return 0; +} + +ulong get_timer(ulong base) +{ +	struct mx28_timrot_regs *timrot_regs = +		(struct mx28_timrot_regs *)MXS_TIMROT_BASE; + +	/* Current tick value */ +	uint32_t now = readl(&timrot_regs->hw_timrot_running_count0); + +	if (lastdec >= now) { +		/* +		 * normal mode (non roll) +		 * move stamp forward with absolut diff ticks +		 */ +		timestamp += (lastdec - now); +	} else { +		/* we have rollover of decrementer */ +		timestamp += (TIMER_LOAD_VAL - now) + lastdec; + +	} +	lastdec = now; + +	return tick_to_time(timestamp) - base; +} + +/* We use the HW_DIGCTL_MICROSECONDS register for sub-millisecond timer. */ +#define	MX28_HW_DIGCTL_MICROSECONDS	0x8001c0c0 + +void __udelay(unsigned long usec) +{ +	uint32_t old, new, incr; +	uint32_t counter = 0; + +	old = readl(MX28_HW_DIGCTL_MICROSECONDS); + +	while (counter < usec) { +		new = readl(MX28_HW_DIGCTL_MICROSECONDS); + +		/* Check if the timer wrapped. */ +		if (new < old) { +			incr = 0xffffffff - old; +			incr += new; +		} else { +			incr = new - old; +		} + +		/* +		 * Check if we are close to the maximum time and the counter +		 * would wrap if incremented. If that's the case, break out +		 * from the loop as the requested delay time passed. +		 */ +		if (counter + incr < counter) +			break; + +		counter += incr; +		old = new; +	} +} diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile index 1dee81f22..a68461126 100644 --- a/arch/arm/cpu/armv7/omap-common/Makefile +++ b/arch/arm/cpu/armv7/omap-common/Makefile @@ -33,6 +33,13 @@ ifdef CONFIG_OMAP  COBJS	+= gpio.o  endif +ifneq ($(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) +COBJS	+= hwinit-common.o +COBJS	+= clocks-common.o +COBJS	+= emif-common.o +SOBJS	+= lowlevel_init.o +endif +  ifdef CONFIG_SPL_BUILD  COBJS	+= spl.o  ifdef CONFIG_SPL_NAND_SUPPORT @@ -43,6 +50,12 @@ COBJS	+= spl_mmc.o  endif  endif +ifndef CONFIG_SPL_BUILD +ifneq ($(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) +COBJS	+= mem-common.o +endif +endif +  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/arch/arm/cpu/armv7/omap-common/clocks-common.c b/arch/arm/cpu/armv7/omap-common/clocks-common.c new file mode 100644 index 000000000..f64a10bfc --- /dev/null +++ b/arch/arm/cpu/armv7/omap-common/clocks-common.c @@ -0,0 +1,609 @@ +/* + * + * Clock initialization for OMAP4 + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * + * Aneesh V <aneesh@ti.com> + * + * Based on previous work by: + *	Santosh Shilimkar <santosh.shilimkar@ti.com> + *	Rajendra Nayak <rnayak@ti.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/omap_common.h> +#include <asm/gpio.h> +#include <asm/arch/clocks.h> +#include <asm/arch/sys_proto.h> +#include <asm/utils.h> +#include <asm/omap_gpio.h> + +#ifndef CONFIG_SPL_BUILD +/* + * printing to console doesn't work unless + * this code is executed from SPL + */ +#define printf(fmt, args...) +#define puts(s) +#endif + +static inline u32 __get_sys_clk_index(void) +{ +	u32 ind; +	/* +	 * For ES1 the ROM code calibration of sys clock is not reliable +	 * due to hw issue. So, use hard-coded value. If this value is not +	 * correct for any board over-ride this function in board file +	 * From ES2.0 onwards you will get this information from +	 * CM_SYS_CLKSEL +	 */ +	if (omap_revision() == OMAP4430_ES1_0) +		ind = OMAP_SYS_CLK_IND_38_4_MHZ; +	else { +		/* SYS_CLKSEL - 1 to match the dpll param array indices */ +		ind = (readl(&prcm->cm_sys_clksel) & +			CM_SYS_CLKSEL_SYS_CLKSEL_MASK) - 1; +	} +	return ind; +} + +u32 get_sys_clk_index(void) +	__attribute__ ((weak, alias("__get_sys_clk_index"))); + +u32 get_sys_clk_freq(void) +{ +	u8 index = get_sys_clk_index(); +	return sys_clk_array[index]; +} + +static inline void do_bypass_dpll(u32 *const base) +{ +	struct dpll_regs *dpll_regs = (struct dpll_regs *)base; + +	clrsetbits_le32(&dpll_regs->cm_clkmode_dpll, +			CM_CLKMODE_DPLL_DPLL_EN_MASK, +			DPLL_EN_FAST_RELOCK_BYPASS << +			CM_CLKMODE_DPLL_EN_SHIFT); +} + +static inline void wait_for_bypass(u32 *const base) +{ +	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; + +	if (!wait_on_value(ST_DPLL_CLK_MASK, 0, &dpll_regs->cm_idlest_dpll, +				LDELAY)) { +		printf("Bypassing DPLL failed %p\n", base); +	} +} + +static inline void do_lock_dpll(u32 *const base) +{ +	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; + +	clrsetbits_le32(&dpll_regs->cm_clkmode_dpll, +		      CM_CLKMODE_DPLL_DPLL_EN_MASK, +		      DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT); +} + +static inline void wait_for_lock(u32 *const base) +{ +	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; + +	if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK, +		&dpll_regs->cm_idlest_dpll, LDELAY)) { +		printf("DPLL locking failed for %p\n", base); +		hang(); +	} +} + +inline u32 check_for_lock(u32 *const base) +{ +	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; +	u32 lock = readl(&dpll_regs->cm_idlest_dpll) & ST_DPLL_CLK_MASK; + +	return lock; +} + +static void do_setup_dpll(u32 *const base, const struct dpll_params *params, +				u8 lock, char *dpll) +{ +	u32 temp, M, N; +	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; + +	temp = readl(&dpll_regs->cm_clksel_dpll); + +	if (check_for_lock(base)) { +		/* +		 * The Dpll has already been locked by rom code using CH. +		 * Check if M,N are matching with Ideal nominal opp values. +		 * If matches, skip the rest otherwise relock. +		 */ +		M = (temp & CM_CLKSEL_DPLL_M_MASK) >> CM_CLKSEL_DPLL_M_SHIFT; +		N = (temp & CM_CLKSEL_DPLL_N_MASK) >> CM_CLKSEL_DPLL_N_SHIFT; +		if ((M != (params->m)) || (N != (params->n))) { +			debug("\n %s Dpll locked, but not for ideal M = %d," +				"N = %d values, current values are M = %d," +				"N= %d" , dpll, params->m, params->n, +				M, N); +		} else { +			/* Dpll locked with ideal values for nominal opps. */ +			debug("\n %s Dpll already locked with ideal" +						"nominal opp values", dpll); +			goto setup_post_dividers; +		} +	} + +	bypass_dpll(base); + +	/* Set M & N */ +	temp &= ~CM_CLKSEL_DPLL_M_MASK; +	temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK; + +	temp &= ~CM_CLKSEL_DPLL_N_MASK; +	temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK; + +	writel(temp, &dpll_regs->cm_clksel_dpll); + +	/* Lock */ +	if (lock) +		do_lock_dpll(base); + +setup_post_dividers: +	setup_post_dividers(base, params); + +	/* Wait till the DPLL locks */ +	if (lock) +		wait_for_lock(base); +} + +u32 omap_ddr_clk(void) +{ +	u32 ddr_clk, sys_clk_khz, omap_rev, divider; +	const struct dpll_params *core_dpll_params; + +	omap_rev = omap_revision(); +	sys_clk_khz = get_sys_clk_freq() / 1000; + +	core_dpll_params = get_core_dpll_params(); + +	debug("sys_clk %d\n ", sys_clk_khz * 1000); + +	/* Find Core DPLL locked frequency first */ +	ddr_clk = sys_clk_khz * 2 * core_dpll_params->m / +			(core_dpll_params->n + 1); + +	if (omap_rev < OMAP5430_ES1_0) { +		/* +		 * DDR frequency is PHY_ROOT_CLK/2 +		 * PHY_ROOT_CLK = Fdpll/2/M2 +		 */ +		divider = 4; +	} else { +		/* +		 * DDR frequency is PHY_ROOT_CLK +		 * PHY_ROOT_CLK = Fdpll/2/M2 +		 */ +		divider = 2; +	} + +	ddr_clk = ddr_clk / divider / core_dpll_params->m2; +	ddr_clk *= 1000;	/* convert to Hz */ +	debug("ddr_clk %d\n ", ddr_clk); + +	return ddr_clk; +} + +/* + * Lock MPU dpll + * + * Resulting MPU frequencies: + * 4430 ES1.0	: 600 MHz + * 4430 ES2.x	: 792 MHz (OPP Turbo) + * 4460		: 920 MHz (OPP Turbo) - DCC disabled + */ +void configure_mpu_dpll(void) +{ +	const struct dpll_params *params; +	struct dpll_regs *mpu_dpll_regs; +	u32 omap_rev; +	omap_rev = omap_revision(); + +	/* +	 * DCC and clock divider settings for 4460. +	 * DCC is required, if more than a certain frequency is required. +	 * For, 4460 > 1GHZ. +	 *     5430 > 1.4GHZ. +	 */ +	if ((omap_rev >= OMAP4460_ES1_0) && (omap_rev < OMAP5430_ES1_0)) { +		mpu_dpll_regs = +			(struct dpll_regs *)&prcm->cm_clkmode_dpll_mpu; +		bypass_dpll(&prcm->cm_clkmode_dpll_mpu); +		clrbits_le32(&prcm->cm_mpu_mpu_clkctrl, +			MPU_CLKCTRL_CLKSEL_EMIF_DIV_MODE_MASK); +		setbits_le32(&prcm->cm_mpu_mpu_clkctrl, +			MPU_CLKCTRL_CLKSEL_ABE_DIV_MODE_MASK); +		clrbits_le32(&mpu_dpll_regs->cm_clksel_dpll, +			CM_CLKSEL_DCC_EN_MASK); +	} + +	params = get_mpu_dpll_params(); + +	do_setup_dpll(&prcm->cm_clkmode_dpll_mpu, params, DPLL_LOCK, "mpu"); +	debug("MPU DPLL locked\n"); +} + +static void setup_dplls(void) +{ +	u32 sysclk_ind, temp; +	const struct dpll_params *params; +	debug("setup_dplls\n"); + +	sysclk_ind = get_sys_clk_index(); + +	/* CORE dpll */ +	params = get_core_dpll_params();	/* default - safest */ +	/* +	 * Do not lock the core DPLL now. Just set it up. +	 * Core DPLL will be locked after setting up EMIF +	 * using the FREQ_UPDATE method(freq_update_core()) +	 */ +	do_setup_dpll(&prcm->cm_clkmode_dpll_core, params, DPLL_NO_LOCK, +								"core"); +	/* Set the ratios for CORE_CLK, L3_CLK, L4_CLK */ +	temp = (CLKSEL_CORE_X2_DIV_1 << CLKSEL_CORE_SHIFT) | +	    (CLKSEL_L3_CORE_DIV_2 << CLKSEL_L3_SHIFT) | +	    (CLKSEL_L4_L3_DIV_2 << CLKSEL_L4_SHIFT); +	writel(temp, &prcm->cm_clksel_core); +	debug("Core DPLL configured\n"); + +	/* lock PER dpll */ +	params = get_per_dpll_params(); +	do_setup_dpll(&prcm->cm_clkmode_dpll_per, +			params, DPLL_LOCK, "per"); +	debug("PER DPLL locked\n"); + +	/* MPU dpll */ +	configure_mpu_dpll(); +} + +#ifdef CONFIG_SYS_CLOCKS_ENABLE_ALL +static void setup_non_essential_dplls(void) +{ +	u32 sys_clk_khz, abe_ref_clk; +	u32 sysclk_ind, sd_div, num, den; +	const struct dpll_params *params; + +	sysclk_ind = get_sys_clk_index(); +	sys_clk_khz = get_sys_clk_freq() / 1000; + +	/* IVA */ +	clrsetbits_le32(&prcm->cm_bypclk_dpll_iva, +		CM_BYPCLK_DPLL_IVA_CLKSEL_MASK, DPLL_IVA_CLKSEL_CORE_X2_DIV_2); + +	params = get_iva_dpll_params(); +	do_setup_dpll(&prcm->cm_clkmode_dpll_iva, params, DPLL_LOCK, "iva"); + +	/* +	 * USB: +	 * USB dpll is J-type. Need to set DPLL_SD_DIV for jitter correction +	 * DPLL_SD_DIV = CEILING ([DPLL_MULT/(DPLL_DIV+1)]* CLKINP / 250) +	 *      - where CLKINP is sys_clk in MHz +	 * Use CLKINP in KHz and adjust the denominator accordingly so +	 * that we have enough accuracy and at the same time no overflow +	 */ +	params = get_usb_dpll_params(); +	num = params->m * sys_clk_khz; +	den = (params->n + 1) * 250 * 1000; +	num += den - 1; +	sd_div = num / den; +	clrsetbits_le32(&prcm->cm_clksel_dpll_usb, +			CM_CLKSEL_DPLL_DPLL_SD_DIV_MASK, +			sd_div << CM_CLKSEL_DPLL_DPLL_SD_DIV_SHIFT); + +	/* Now setup the dpll with the regular function */ +	do_setup_dpll(&prcm->cm_clkmode_dpll_usb, params, DPLL_LOCK, "usb"); + +	/* Configure ABE dpll */ +	params = get_abe_dpll_params(); +#ifdef CONFIG_SYS_OMAP_ABE_SYSCK +	abe_ref_clk = CM_ABE_PLL_REF_CLKSEL_CLKSEL_SYSCLK; +#else +	abe_ref_clk = CM_ABE_PLL_REF_CLKSEL_CLKSEL_32KCLK; +	/* +	 * We need to enable some additional options to achieve +	 * 196.608MHz from 32768 Hz +	 */ +	setbits_le32(&prcm->cm_clkmode_dpll_abe, +			CM_CLKMODE_DPLL_DRIFTGUARD_EN_MASK| +			CM_CLKMODE_DPLL_RELOCK_RAMP_EN_MASK| +			CM_CLKMODE_DPLL_LPMODE_EN_MASK| +			CM_CLKMODE_DPLL_REGM4XEN_MASK); +	/* Spend 4 REFCLK cycles at each stage */ +	clrsetbits_le32(&prcm->cm_clkmode_dpll_abe, +			CM_CLKMODE_DPLL_RAMP_RATE_MASK, +			1 << CM_CLKMODE_DPLL_RAMP_RATE_SHIFT); +#endif + +	/* Select the right reference clk */ +	clrsetbits_le32(&prcm->cm_abe_pll_ref_clksel, +			CM_ABE_PLL_REF_CLKSEL_CLKSEL_MASK, +			abe_ref_clk << CM_ABE_PLL_REF_CLKSEL_CLKSEL_SHIFT); +	/* Lock the dpll */ +	do_setup_dpll(&prcm->cm_clkmode_dpll_abe, params, DPLL_LOCK, "abe"); +} +#endif + +void do_scale_tps62361(u32 reg, u32 volt_mv) +{ +	u32 temp, step; + +	step = volt_mv - TPS62361_BASE_VOLT_MV; +	step /= 10; + +	/* +	 * Select SET1 in TPS62361: +	 * VSEL1 is grounded on board. So the following selects +	 * VSEL1 = 0 and VSEL0 = 1 +	 */ +	gpio_direction_output(TPS62361_VSEL0_GPIO, 0); +	gpio_set_value(TPS62361_VSEL0_GPIO, 1); + +	temp = TPS62361_I2C_SLAVE_ADDR | +	    (reg << PRM_VC_VAL_BYPASS_REGADDR_SHIFT) | +	    (step << PRM_VC_VAL_BYPASS_DATA_SHIFT) | +	    PRM_VC_VAL_BYPASS_VALID_BIT; +	debug("do_scale_tps62361: volt - %d step - 0x%x\n", volt_mv, step); + +	writel(temp, &prcm->prm_vc_val_bypass); +	if (!wait_on_value(PRM_VC_VAL_BYPASS_VALID_BIT, 0, +				&prcm->prm_vc_val_bypass, LDELAY)) { +		puts("Scaling voltage failed for vdd_mpu from TPS\n"); +	} +} + +void do_scale_vcore(u32 vcore_reg, u32 volt_mv) +{ +	u32 temp, offset_code; +	u32 step = 12660; /* 12.66 mV represented in uV */ +	u32 offset = volt_mv; + +	/* convert to uV for better accuracy in the calculations */ +	offset *= 1000; + +	if (omap_revision() == OMAP4430_ES1_0) +		offset -= PHOENIX_SMPS_BASE_VOLT_STD_MODE_UV; +	else +		offset -= PHOENIX_SMPS_BASE_VOLT_STD_MODE_WITH_OFFSET_UV; + +	offset_code = (offset + step - 1) / step; +	/* The code starts at 1 not 0 */ +	offset_code++; + +	debug("do_scale_vcore: volt - %d offset_code - 0x%x\n", volt_mv, +		offset_code); + +	temp = SMPS_I2C_SLAVE_ADDR | +	    (vcore_reg << PRM_VC_VAL_BYPASS_REGADDR_SHIFT) | +	    (offset_code << PRM_VC_VAL_BYPASS_DATA_SHIFT) | +	    PRM_VC_VAL_BYPASS_VALID_BIT; +	writel(temp, &prcm->prm_vc_val_bypass); +	if (!wait_on_value(PRM_VC_VAL_BYPASS_VALID_BIT, 0, +				&prcm->prm_vc_val_bypass, LDELAY)) { +		printf("Scaling voltage failed for 0x%x\n", vcore_reg); +	} +} + +static inline void enable_clock_domain(u32 *const clkctrl_reg, u32 enable_mode) +{ +	clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK, +			enable_mode << CD_CLKCTRL_CLKTRCTRL_SHIFT); +	debug("Enable clock domain - %p\n", clkctrl_reg); +} + +static inline void wait_for_clk_enable(u32 *clkctrl_addr) +{ +	u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED; +	u32 bound = LDELAY; + +	while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) || +		(idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) { + +		clkctrl = readl(clkctrl_addr); +		idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >> +			 MODULE_CLKCTRL_IDLEST_SHIFT; +		if (--bound == 0) { +			printf("Clock enable failed for 0x%p idlest 0x%x\n", +				clkctrl_addr, clkctrl); +			return; +		} +	} +} + +static inline void enable_clock_module(u32 *const clkctrl_addr, u32 enable_mode, +				u32 wait_for_enable) +{ +	clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK, +			enable_mode << MODULE_CLKCTRL_MODULEMODE_SHIFT); +	debug("Enable clock module - %p\n", clkctrl_addr); +	if (wait_for_enable) +		wait_for_clk_enable(clkctrl_addr); +} + +void freq_update_core(void) +{ +	u32 freq_config1 = 0; +	const struct dpll_params *core_dpll_params; + +	core_dpll_params = get_core_dpll_params(); +	/* Put EMIF clock domain in sw wakeup mode */ +	enable_clock_domain(&prcm->cm_memif_clkstctrl, +				CD_CLKCTRL_CLKTRCTRL_SW_WKUP); +	wait_for_clk_enable(&prcm->cm_memif_emif_1_clkctrl); +	wait_for_clk_enable(&prcm->cm_memif_emif_2_clkctrl); + +	freq_config1 = SHADOW_FREQ_CONFIG1_FREQ_UPDATE_MASK | +	    SHADOW_FREQ_CONFIG1_DLL_RESET_MASK; + +	freq_config1 |= (DPLL_EN_LOCK << SHADOW_FREQ_CONFIG1_DPLL_EN_SHIFT) & +				SHADOW_FREQ_CONFIG1_DPLL_EN_MASK; + +	freq_config1 |= (core_dpll_params->m2 << +			SHADOW_FREQ_CONFIG1_M2_DIV_SHIFT) & +			SHADOW_FREQ_CONFIG1_M2_DIV_MASK; + +	writel(freq_config1, &prcm->cm_shadow_freq_config1); +	if (!wait_on_value(SHADOW_FREQ_CONFIG1_FREQ_UPDATE_MASK, 0, +				&prcm->cm_shadow_freq_config1, LDELAY)) { +		puts("FREQ UPDATE procedure failed!!"); +		hang(); +	} + +	/* Put EMIF clock domain back in hw auto mode */ +	enable_clock_domain(&prcm->cm_memif_clkstctrl, +				CD_CLKCTRL_CLKTRCTRL_HW_AUTO); +	wait_for_clk_enable(&prcm->cm_memif_emif_1_clkctrl); +	wait_for_clk_enable(&prcm->cm_memif_emif_2_clkctrl); +} + +void bypass_dpll(u32 *const base) +{ +	do_bypass_dpll(base); +	wait_for_bypass(base); +} + +void lock_dpll(u32 *const base) +{ +	do_lock_dpll(base); +	wait_for_lock(base); +} + +void setup_clocks_for_console(void) +{ +	/* Do not add any spl_debug prints in this function */ +	clrsetbits_le32(&prcm->cm_l4per_clkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK, +			CD_CLKCTRL_CLKTRCTRL_SW_WKUP << +			CD_CLKCTRL_CLKTRCTRL_SHIFT); + +	/* Enable all UARTs - console will be on one of them */ +	clrsetbits_le32(&prcm->cm_l4per_uart1_clkctrl, +			MODULE_CLKCTRL_MODULEMODE_MASK, +			MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << +			MODULE_CLKCTRL_MODULEMODE_SHIFT); + +	clrsetbits_le32(&prcm->cm_l4per_uart2_clkctrl, +			MODULE_CLKCTRL_MODULEMODE_MASK, +			MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << +			MODULE_CLKCTRL_MODULEMODE_SHIFT); + +	clrsetbits_le32(&prcm->cm_l4per_uart3_clkctrl, +			MODULE_CLKCTRL_MODULEMODE_MASK, +			MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << +			MODULE_CLKCTRL_MODULEMODE_SHIFT); + +	clrsetbits_le32(&prcm->cm_l4per_uart3_clkctrl, +			MODULE_CLKCTRL_MODULEMODE_MASK, +			MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << +			MODULE_CLKCTRL_MODULEMODE_SHIFT); + +	clrsetbits_le32(&prcm->cm_l4per_clkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK, +			CD_CLKCTRL_CLKTRCTRL_HW_AUTO << +			CD_CLKCTRL_CLKTRCTRL_SHIFT); +} + +void setup_sri2c(void) +{ +	u32 sys_clk_khz, cycles_hi, cycles_low, temp; + +	sys_clk_khz = get_sys_clk_freq() / 1000; + +	/* +	 * Setup the dedicated I2C controller for Voltage Control +	 * I2C clk - high period 40% low period 60% +	 */ +	cycles_hi = sys_clk_khz * 4 / PRM_VC_I2C_CHANNEL_FREQ_KHZ / 10; +	cycles_low = sys_clk_khz * 6 / PRM_VC_I2C_CHANNEL_FREQ_KHZ / 10; +	/* values to be set in register - less by 5 & 7 respectively */ +	cycles_hi -= 5; +	cycles_low -= 7; +	temp = (cycles_hi << PRM_VC_CFG_I2C_CLK_SCLH_SHIFT) | +	       (cycles_low << PRM_VC_CFG_I2C_CLK_SCLL_SHIFT); +	writel(temp, &prcm->prm_vc_cfg_i2c_clk); + +	/* Disable high speed mode and all advanced features */ +	writel(0x0, &prcm->prm_vc_cfg_i2c_mode); +} + +void do_enable_clocks(u32 *const *clk_domains, +			    u32 *const *clk_modules_hw_auto, +			    u32 *const *clk_modules_explicit_en, +			    u8 wait_for_enable) +{ +	u32 i, max = 100; + +	/* Put the clock domains in SW_WKUP mode */ +	for (i = 0; (i < max) && clk_domains[i]; i++) { +		enable_clock_domain(clk_domains[i], +				    CD_CLKCTRL_CLKTRCTRL_SW_WKUP); +	} + +	/* Clock modules that need to be put in HW_AUTO */ +	for (i = 0; (i < max) && clk_modules_hw_auto[i]; i++) { +		enable_clock_module(clk_modules_hw_auto[i], +				    MODULE_CLKCTRL_MODULEMODE_HW_AUTO, +				    wait_for_enable); +	}; + +	/* Clock modules that need to be put in SW_EXPLICIT_EN mode */ +	for (i = 0; (i < max) && clk_modules_explicit_en[i]; i++) { +		enable_clock_module(clk_modules_explicit_en[i], +				    MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN, +				    wait_for_enable); +	}; + +	/* Put the clock domains in HW_AUTO mode now */ +	for (i = 0; (i < max) && clk_domains[i]; i++) { +		enable_clock_domain(clk_domains[i], +				    CD_CLKCTRL_CLKTRCTRL_HW_AUTO); +	} +} + +void prcm_init(void) +{ +	switch (omap_hw_init_context()) { +	case OMAP_INIT_CONTEXT_SPL: +	case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR: +	case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH: +		enable_basic_clocks(); +		scale_vcores(); +		setup_dplls(); +#ifdef CONFIG_SYS_CLOCKS_ENABLE_ALL +		setup_non_essential_dplls(); +		enable_non_essential_clocks(); +#endif +		break; +	default: +		break; +	} + +	if (OMAP_INIT_CONTEXT_SPL != omap_hw_init_context()) +		enable_basic_uboot_clocks(); +} diff --git a/arch/arm/cpu/armv7/omap-common/emif-common.c b/arch/arm/cpu/armv7/omap-common/emif-common.c new file mode 100644 index 000000000..ce03b5ce0 --- /dev/null +++ b/arch/arm/cpu/armv7/omap-common/emif-common.c @@ -0,0 +1,1140 @@ +/* + * EMIF programming + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * + * Aneesh V <aneesh@ti.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/emif.h> +#include <asm/arch/clocks.h> +#include <asm/arch/sys_proto.h> +#include <asm/omap_common.h> +#include <asm/utils.h> + +inline u32 emif_num(u32 base) +{ +	if (base == EMIF1_BASE) +		return 1; +	else if (base == EMIF2_BASE) +		return 2; +	else +		return 0; +} + + +static inline u32 get_mr(u32 base, u32 cs, u32 mr_addr) +{ +	u32 mr; +	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; + +	mr_addr |= cs << EMIF_REG_CS_SHIFT; +	writel(mr_addr, &emif->emif_lpddr2_mode_reg_cfg); +	if (omap_revision() == OMAP4430_ES2_0) +		mr = readl(&emif->emif_lpddr2_mode_reg_data_es2); +	else +		mr = readl(&emif->emif_lpddr2_mode_reg_data); +	debug("get_mr: EMIF%d cs %d mr %08x val 0x%x\n", emif_num(base), +	      cs, mr_addr, mr); +	return mr; +} + +static inline void set_mr(u32 base, u32 cs, u32 mr_addr, u32 mr_val) +{ +	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; + +	mr_addr |= cs << EMIF_REG_CS_SHIFT; +	writel(mr_addr, &emif->emif_lpddr2_mode_reg_cfg); +	writel(mr_val, &emif->emif_lpddr2_mode_reg_data); +} + +void emif_reset_phy(u32 base) +{ +	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; +	u32 iodft; + +	iodft = readl(&emif->emif_iodft_tlgc); +	iodft |= EMIF_REG_RESET_PHY_MASK; +	writel(iodft, &emif->emif_iodft_tlgc); +} + +static void do_lpddr2_init(u32 base, u32 cs) +{ +	u32 mr_addr; + +	/* Wait till device auto initialization is complete */ +	while (get_mr(base, cs, LPDDR2_MR0) & LPDDR2_MR0_DAI_MASK) +		; +	set_mr(base, cs, LPDDR2_MR10, MR10_ZQ_ZQINIT); +	/* +	 * tZQINIT = 1 us +	 * Enough loops assuming a maximum of 2GHz +	 */ +	sdelay(2000); +	set_mr(base, cs, LPDDR2_MR1, MR1_BL_8_BT_SEQ_WRAP_EN_NWR_3); +	set_mr(base, cs, LPDDR2_MR16, MR16_REF_FULL_ARRAY); +	/* +	 * Enable refresh along with writing MR2 +	 * Encoding of RL in MR2 is (RL - 2) +	 */ +	mr_addr = LPDDR2_MR2 | EMIF_REG_REFRESH_EN_MASK; +	set_mr(base, cs, mr_addr, RL_FINAL - 2); +} + +static void lpddr2_init(u32 base, const struct emif_regs *regs) +{ +	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; + +	/* Not NVM */ +	clrbits_le32(&emif->emif_lpddr2_nvm_config, EMIF_REG_CS1NVMEN_MASK); + +	/* +	 * Keep REG_INITREF_DIS = 1 to prevent re-initialization of SDRAM +	 * when EMIF_SDRAM_CONFIG register is written +	 */ +	setbits_le32(&emif->emif_sdram_ref_ctrl, EMIF_REG_INITREF_DIS_MASK); + +	/* +	 * Set the SDRAM_CONFIG and PHY_CTRL for the +	 * un-locked frequency & default RL +	 */ +	writel(regs->sdram_config_init, &emif->emif_sdram_config); +	writel(regs->emif_ddr_phy_ctlr_1_init, &emif->emif_ddr_phy_ctrl_1); + +	do_lpddr2_init(base, CS0); +	if (regs->sdram_config & EMIF_REG_EBANK_MASK) +		do_lpddr2_init(base, CS1); + +	writel(regs->sdram_config, &emif->emif_sdram_config); +	writel(regs->emif_ddr_phy_ctlr_1, &emif->emif_ddr_phy_ctrl_1); + +	/* Enable refresh now */ +	clrbits_le32(&emif->emif_sdram_ref_ctrl, EMIF_REG_INITREF_DIS_MASK); + +} + +void emif_update_timings(u32 base, const struct emif_regs *regs) +{ +	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; + +	writel(regs->ref_ctrl, &emif->emif_sdram_ref_ctrl_shdw); +	writel(regs->sdram_tim1, &emif->emif_sdram_tim_1_shdw); +	writel(regs->sdram_tim2, &emif->emif_sdram_tim_2_shdw); +	writel(regs->sdram_tim3, &emif->emif_sdram_tim_3_shdw); +	if (omap_revision() == OMAP4430_ES1_0) { +		/* ES1 bug EMIF should be in force idle during freq_update */ +		writel(0, &emif->emif_pwr_mgmt_ctrl); +	} else { +		writel(EMIF_PWR_MGMT_CTRL, &emif->emif_pwr_mgmt_ctrl); +		writel(EMIF_PWR_MGMT_CTRL_SHDW, &emif->emif_pwr_mgmt_ctrl_shdw); +	} +	writel(regs->read_idle_ctrl, &emif->emif_read_idlectrl_shdw); +	writel(regs->zq_config, &emif->emif_zq_config); +	writel(regs->temp_alert_config, &emif->emif_temp_alert_config); +	writel(regs->emif_ddr_phy_ctlr_1, &emif->emif_ddr_phy_ctrl_1_shdw); + +	if (omap_revision() == OMAP5430_ES1_0) { +		writel(EMIF_L3_CONFIG_VAL_SYS_10_MPU_5_LL_0, +			&emif->emif_l3_config); +	} else if (omap_revision() >= OMAP4460_ES1_0) { +		writel(EMIF_L3_CONFIG_VAL_SYS_10_MPU_3_LL_0, +			&emif->emif_l3_config); +	} else { +		writel(EMIF_L3_CONFIG_VAL_SYS_10_LL_0, +			&emif->emif_l3_config); +	} +} + +#ifndef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS +#define print_timing_reg(reg) debug(#reg" - 0x%08x\n", (reg)) + +/* + * Organization and refresh requirements for LPDDR2 devices of different + * types and densities. Derived from JESD209-2 section 2.4 + */ +const struct lpddr2_addressing addressing_table[] = { +	/* Banks tREFIx10     rowx32,rowx16      colx32,colx16	density */ +	{BANKS4, T_REFI_15_6, {ROW_12, ROW_12}, {COL_7, COL_8} },/*64M */ +	{BANKS4, T_REFI_15_6, {ROW_12, ROW_12}, {COL_8, COL_9} },/*128M */ +	{BANKS4, T_REFI_7_8, {ROW_13, ROW_13}, {COL_8, COL_9} },/*256M */ +	{BANKS4, T_REFI_7_8, {ROW_13, ROW_13}, {COL_9, COL_10} },/*512M */ +	{BANKS8, T_REFI_7_8, {ROW_13, ROW_13}, {COL_9, COL_10} },/*1GS4 */ +	{BANKS8, T_REFI_3_9, {ROW_14, ROW_14}, {COL_9, COL_10} },/*2GS4 */ +	{BANKS8, T_REFI_3_9, {ROW_14, ROW_14}, {COL_10, COL_11} },/*4G */ +	{BANKS8, T_REFI_3_9, {ROW_15, ROW_15}, {COL_10, COL_11} },/*8G */ +	{BANKS4, T_REFI_7_8, {ROW_14, ROW_14}, {COL_9, COL_10} },/*1GS2 */ +	{BANKS4, T_REFI_3_9, {ROW_15, ROW_15}, {COL_9, COL_10} },/*2GS2 */ +}; + +static const u32 lpddr2_density_2_size_in_mbytes[] = { +	8,			/* 64Mb */ +	16,			/* 128Mb */ +	32,			/* 256Mb */ +	64,			/* 512Mb */ +	128,			/* 1Gb   */ +	256,			/* 2Gb   */ +	512,			/* 4Gb   */ +	1024,			/* 8Gb   */ +	2048,			/* 16Gb  */ +	4096			/* 32Gb  */ +}; + +/* + * Calculate the period of DDR clock from frequency value and set the + * denominator and numerator in global variables for easy access later + */ +static void set_ddr_clk_period(u32 freq) +{ +	/* +	 * period = 1/freq +	 * period_in_ns = 10^9/freq +	 */ +	*T_num = 1000000000; +	*T_den = freq; +	cancel_out(T_num, T_den, 200); + +} + +/* + * Convert time in nano seconds to number of cycles of DDR clock + */ +static inline u32 ns_2_cycles(u32 ns) +{ +	return ((ns * (*T_den)) + (*T_num) - 1) / (*T_num); +} + +/* + * ns_2_cycles with the difference that the time passed is 2 times the actual + * value(to avoid fractions). The cycles returned is for the original value of + * the timing parameter + */ +static inline u32 ns_x2_2_cycles(u32 ns) +{ +	return ((ns * (*T_den)) + (*T_num) * 2 - 1) / ((*T_num) * 2); +} + +/* + * Find addressing table index based on the device's type(S2 or S4) and + * density + */ +s8 addressing_table_index(u8 type, u8 density, u8 width) +{ +	u8 index; +	if ((density > LPDDR2_DENSITY_8Gb) || (width == LPDDR2_IO_WIDTH_8)) +		return -1; + +	/* +	 * Look at the way ADDR_TABLE_INDEX* values have been defined +	 * in emif.h compared to LPDDR2_DENSITY_* values +	 * The table is layed out in the increasing order of density +	 * (ignoring type). The exceptions 1GS2 and 2GS2 have been placed +	 * at the end +	 */ +	if ((type == LPDDR2_TYPE_S2) && (density == LPDDR2_DENSITY_1Gb)) +		index = ADDR_TABLE_INDEX1GS2; +	else if ((type == LPDDR2_TYPE_S2) && (density == LPDDR2_DENSITY_2Gb)) +		index = ADDR_TABLE_INDEX2GS2; +	else +		index = density; + +	debug("emif: addressing table index %d\n", index); + +	return index; +} + +/* + * Find the the right timing table from the array of timing + * tables of the device using DDR clock frequency + */ +static const struct lpddr2_ac_timings *get_timings_table(const struct +			lpddr2_ac_timings const *const *device_timings, +			u32 freq) +{ +	u32 i, temp, freq_nearest; +	const struct lpddr2_ac_timings *timings = 0; + +	emif_assert(freq <= MAX_LPDDR2_FREQ); +	emif_assert(device_timings); + +	/* +	 * Start with the maximum allowed frequency - that is always safe +	 */ +	freq_nearest = MAX_LPDDR2_FREQ; +	/* +	 * Find the timings table that has the max frequency value: +	 *   i.  Above or equal to the DDR frequency - safe +	 *   ii. The lowest that satisfies condition (i) - optimal +	 */ +	for (i = 0; (i < MAX_NUM_SPEEDBINS) && device_timings[i]; i++) { +		temp = device_timings[i]->max_freq; +		if ((temp >= freq) && (temp <= freq_nearest)) { +			freq_nearest = temp; +			timings = device_timings[i]; +		} +	} +	debug("emif: timings table: %d\n", freq_nearest); +	return timings; +} + +/* + * Finds the value of emif_sdram_config_reg + * All parameters are programmed based on the device on CS0. + * If there is a device on CS1, it will be same as that on CS0 or + * it will be NVM. We don't support NVM yet. + * If cs1_device pointer is NULL it is assumed that there is no device + * on CS1 + */ +static u32 get_sdram_config_reg(const struct lpddr2_device_details *cs0_device, +				const struct lpddr2_device_details *cs1_device, +				const struct lpddr2_addressing *addressing, +				u8 RL) +{ +	u32 config_reg = 0; + +	config_reg |=  (cs0_device->type + 4) << EMIF_REG_SDRAM_TYPE_SHIFT; +	config_reg |=  EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING << +			EMIF_REG_IBANK_POS_SHIFT; + +	config_reg |= cs0_device->io_width << EMIF_REG_NARROW_MODE_SHIFT; + +	config_reg |= RL << EMIF_REG_CL_SHIFT; + +	config_reg |= addressing->row_sz[cs0_device->io_width] << +			EMIF_REG_ROWSIZE_SHIFT; + +	config_reg |= addressing->num_banks << EMIF_REG_IBANK_SHIFT; + +	config_reg |= (cs1_device ? EBANK_CS1_EN : EBANK_CS1_DIS) << +			EMIF_REG_EBANK_SHIFT; + +	config_reg |= addressing->col_sz[cs0_device->io_width] << +			EMIF_REG_PAGESIZE_SHIFT; + +	return config_reg; +} + +static u32 get_sdram_ref_ctrl(u32 freq, +			      const struct lpddr2_addressing *addressing) +{ +	u32 ref_ctrl = 0, val = 0, freq_khz; +	freq_khz = freq / 1000; +	/* +	 * refresh rate to be set is 'tREFI * freq in MHz +	 * division by 10000 to account for khz and x10 in t_REFI_us_x10 +	 */ +	val = addressing->t_REFI_us_x10 * freq_khz / 10000; +	ref_ctrl |= val << EMIF_REG_REFRESH_RATE_SHIFT; + +	return ref_ctrl; +} + +static u32 get_sdram_tim_1_reg(const struct lpddr2_ac_timings *timings, +			       const struct lpddr2_min_tck *min_tck, +			       const struct lpddr2_addressing *addressing) +{ +	u32 tim1 = 0, val = 0; +	val = max(min_tck->tWTR, ns_x2_2_cycles(timings->tWTRx2)) - 1; +	tim1 |= val << EMIF_REG_T_WTR_SHIFT; + +	if (addressing->num_banks == BANKS8) +		val = (timings->tFAW * (*T_den) + 4 * (*T_num) - 1) / +							(4 * (*T_num)) - 1; +	else +		val = max(min_tck->tRRD, ns_2_cycles(timings->tRRD)) - 1; + +	tim1 |= val << EMIF_REG_T_RRD_SHIFT; + +	val = ns_2_cycles(timings->tRASmin + timings->tRPab) - 1; +	tim1 |= val << EMIF_REG_T_RC_SHIFT; + +	val = max(min_tck->tRAS_MIN, ns_2_cycles(timings->tRASmin)) - 1; +	tim1 |= val << EMIF_REG_T_RAS_SHIFT; + +	val = max(min_tck->tWR, ns_2_cycles(timings->tWR)) - 1; +	tim1 |= val << EMIF_REG_T_WR_SHIFT; + +	val = max(min_tck->tRCD, ns_2_cycles(timings->tRCD)) - 1; +	tim1 |= val << EMIF_REG_T_RCD_SHIFT; + +	val = max(min_tck->tRP_AB, ns_2_cycles(timings->tRPab)) - 1; +	tim1 |= val << EMIF_REG_T_RP_SHIFT; + +	return tim1; +} + +static u32 get_sdram_tim_2_reg(const struct lpddr2_ac_timings *timings, +			       const struct lpddr2_min_tck *min_tck) +{ +	u32 tim2 = 0, val = 0; +	val = max(min_tck->tCKE, timings->tCKE) - 1; +	tim2 |= val << EMIF_REG_T_CKE_SHIFT; + +	val = max(min_tck->tRTP, ns_x2_2_cycles(timings->tRTPx2)) - 1; +	tim2 |= val << EMIF_REG_T_RTP_SHIFT; + +	/* +	 * tXSRD = tRFCab + 10 ns. XSRD and XSNR should have the +	 * same value +	 */ +	val = ns_2_cycles(timings->tXSR) - 1; +	tim2 |= val << EMIF_REG_T_XSRD_SHIFT; +	tim2 |= val << EMIF_REG_T_XSNR_SHIFT; + +	val = max(min_tck->tXP, ns_x2_2_cycles(timings->tXPx2)) - 1; +	tim2 |= val << EMIF_REG_T_XP_SHIFT; + +	return tim2; +} + +static u32 get_sdram_tim_3_reg(const struct lpddr2_ac_timings *timings, +			       const struct lpddr2_min_tck *min_tck, +			       const struct lpddr2_addressing *addressing) +{ +	u32 tim3 = 0, val = 0; +	val = min(timings->tRASmax * 10 / addressing->t_REFI_us_x10 - 1, 0xF); +	tim3 |= val << EMIF_REG_T_RAS_MAX_SHIFT; + +	val = ns_2_cycles(timings->tRFCab) - 1; +	tim3 |= val << EMIF_REG_T_RFC_SHIFT; + +	val = ns_x2_2_cycles(timings->tDQSCKMAXx2) - 1; +	tim3 |= val << EMIF_REG_T_TDQSCKMAX_SHIFT; + +	val = ns_2_cycles(timings->tZQCS) - 1; +	tim3 |= val << EMIF_REG_ZQ_ZQCS_SHIFT; + +	val = max(min_tck->tCKESR, ns_2_cycles(timings->tCKESR)) - 1; +	tim3 |= val << EMIF_REG_T_CKESR_SHIFT; + +	return tim3; +} + +static u32 get_zq_config_reg(const struct lpddr2_device_details *cs1_device, +			     const struct lpddr2_addressing *addressing, +			     u8 volt_ramp) +{ +	u32 zq = 0, val = 0; +	if (volt_ramp) +		val = +		    EMIF_ZQCS_INTERVAL_DVFS_IN_US * 10 / +		    addressing->t_REFI_us_x10; +	else +		val = +		    EMIF_ZQCS_INTERVAL_NORMAL_IN_US * 10 / +		    addressing->t_REFI_us_x10; +	zq |= val << EMIF_REG_ZQ_REFINTERVAL_SHIFT; + +	zq |= (REG_ZQ_ZQCL_MULT - 1) << EMIF_REG_ZQ_ZQCL_MULT_SHIFT; + +	zq |= (REG_ZQ_ZQINIT_MULT - 1) << EMIF_REG_ZQ_ZQINIT_MULT_SHIFT; + +	zq |= REG_ZQ_SFEXITEN_ENABLE << EMIF_REG_ZQ_SFEXITEN_SHIFT; + +	/* +	 * Assuming that two chipselects have a single calibration resistor +	 * If there are indeed two calibration resistors, then this flag should +	 * be enabled to take advantage of dual calibration feature. +	 * This data should ideally come from board files. But considering +	 * that none of the boards today have calibration resistors per CS, +	 * it would be an unnecessary overhead. +	 */ +	zq |= REG_ZQ_DUALCALEN_DISABLE << EMIF_REG_ZQ_DUALCALEN_SHIFT; + +	zq |= REG_ZQ_CS0EN_ENABLE << EMIF_REG_ZQ_CS0EN_SHIFT; + +	zq |= (cs1_device ? 1 : 0) << EMIF_REG_ZQ_CS1EN_SHIFT; + +	return zq; +} + +static u32 get_temp_alert_config(const struct lpddr2_device_details *cs1_device, +				 const struct lpddr2_addressing *addressing, +				 u8 is_derated) +{ +	u32 alert = 0, interval; +	interval = +	    TEMP_ALERT_POLL_INTERVAL_MS * 10000 / addressing->t_REFI_us_x10; +	if (is_derated) +		interval *= 4; +	alert |= interval << EMIF_REG_TA_REFINTERVAL_SHIFT; + +	alert |= TEMP_ALERT_CONFIG_DEVCT_1 << EMIF_REG_TA_DEVCNT_SHIFT; + +	alert |= TEMP_ALERT_CONFIG_DEVWDT_32 << EMIF_REG_TA_DEVWDT_SHIFT; + +	alert |= 1 << EMIF_REG_TA_SFEXITEN_SHIFT; + +	alert |= 1 << EMIF_REG_TA_CS0EN_SHIFT; + +	alert |= (cs1_device ? 1 : 0) << EMIF_REG_TA_CS1EN_SHIFT; + +	return alert; +} + +static u32 get_read_idle_ctrl_reg(u8 volt_ramp) +{ +	u32 idle = 0, val = 0; +	if (volt_ramp) +		val = ns_2_cycles(READ_IDLE_INTERVAL_DVFS) / 64 - 1; +	else +		/*Maximum value in normal conditions - suggested by hw team */ +		val = 0x1FF; +	idle |= val << EMIF_REG_READ_IDLE_INTERVAL_SHIFT; + +	idle |= EMIF_REG_READ_IDLE_LEN_VAL << EMIF_REG_READ_IDLE_LEN_SHIFT; + +	return idle; +} + +static u32 get_ddr_phy_ctrl_1(u32 freq, u8 RL) +{ +	u32 phy = 0, val = 0; + +	phy |= (RL + 2) << EMIF_REG_READ_LATENCY_SHIFT; + +	if (freq <= 100000000) +		val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS; +	else if (freq <= 200000000) +		val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ; +	else +		val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ; +	phy |= val << EMIF_REG_DLL_SLAVE_DLY_CTRL_SHIFT; + +	/* Other fields are constant magic values. Hardcode them together */ +	phy |= EMIF_DDR_PHY_CTRL_1_BASE_VAL << +		EMIF_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHIFT; + +	return phy; +} + +static u32 get_emif_mem_size(struct emif_device_details *devices) +{ +	u32 size_mbytes = 0, temp; + +	if (!devices) +		return 0; + +	if (devices->cs0_device_details) { +		temp = devices->cs0_device_details->density; +		size_mbytes += lpddr2_density_2_size_in_mbytes[temp]; +	} + +	if (devices->cs1_device_details) { +		temp = devices->cs1_device_details->density; +		size_mbytes += lpddr2_density_2_size_in_mbytes[temp]; +	} +	/* convert to bytes */ +	return size_mbytes << 20; +} + +/* Gets the encoding corresponding to a given DMM section size */ +u32 get_dmm_section_size_map(u32 section_size) +{ +	/* +	 * Section size mapping: +	 * 0x0: 16-MiB section +	 * 0x1: 32-MiB section +	 * 0x2: 64-MiB section +	 * 0x3: 128-MiB section +	 * 0x4: 256-MiB section +	 * 0x5: 512-MiB section +	 * 0x6: 1-GiB section +	 * 0x7: 2-GiB section +	 */ +	section_size >>= 24; /* divide by 16 MB */ +	return log_2_n_round_down(section_size); +} + +static void emif_calculate_regs( +		const struct emif_device_details *emif_dev_details, +		u32 freq, struct emif_regs *regs) +{ +	u32 temp, sys_freq; +	const struct lpddr2_addressing *addressing; +	const struct lpddr2_ac_timings *timings; +	const struct lpddr2_min_tck *min_tck; +	const struct lpddr2_device_details *cs0_dev_details = +					emif_dev_details->cs0_device_details; +	const struct lpddr2_device_details *cs1_dev_details = +					emif_dev_details->cs1_device_details; +	const struct lpddr2_device_timings *cs0_dev_timings = +					emif_dev_details->cs0_device_timings; + +	emif_assert(emif_dev_details); +	emif_assert(regs); +	/* +	 * You can not have a device on CS1 without one on CS0 +	 * So configuring EMIF without a device on CS0 doesn't +	 * make sense +	 */ +	emif_assert(cs0_dev_details); +	emif_assert(cs0_dev_details->type != LPDDR2_TYPE_NVM); +	/* +	 * If there is a device on CS1 it should be same type as CS0 +	 * (or NVM. But NVM is not supported in this driver yet) +	 */ +	emif_assert((cs1_dev_details == NULL) || +		    (cs1_dev_details->type == LPDDR2_TYPE_NVM) || +		    (cs0_dev_details->type == cs1_dev_details->type)); +	emif_assert(freq <= MAX_LPDDR2_FREQ); + +	set_ddr_clk_period(freq); + +	/* +	 * The device on CS0 is used for all timing calculations +	 * There is only one set of registers for timings per EMIF. So, if the +	 * second CS(CS1) has a device, it should have the same timings as the +	 * device on CS0 +	 */ +	timings = get_timings_table(cs0_dev_timings->ac_timings, freq); +	emif_assert(timings); +	min_tck = cs0_dev_timings->min_tck; + +	temp = addressing_table_index(cs0_dev_details->type, +				      cs0_dev_details->density, +				      cs0_dev_details->io_width); + +	emif_assert((temp >= 0)); +	addressing = &(addressing_table[temp]); +	emif_assert(addressing); + +	sys_freq = get_sys_clk_freq(); + +	regs->sdram_config_init = get_sdram_config_reg(cs0_dev_details, +							cs1_dev_details, +							addressing, RL_BOOT); + +	regs->sdram_config = get_sdram_config_reg(cs0_dev_details, +						cs1_dev_details, +						addressing, RL_FINAL); + +	regs->ref_ctrl = get_sdram_ref_ctrl(freq, addressing); + +	regs->sdram_tim1 = get_sdram_tim_1_reg(timings, min_tck, addressing); + +	regs->sdram_tim2 = get_sdram_tim_2_reg(timings, min_tck); + +	regs->sdram_tim3 = get_sdram_tim_3_reg(timings, min_tck, addressing); + +	regs->read_idle_ctrl = get_read_idle_ctrl_reg(LPDDR2_VOLTAGE_STABLE); + +	regs->temp_alert_config = +	    get_temp_alert_config(cs1_dev_details, addressing, 0); + +	regs->zq_config = get_zq_config_reg(cs1_dev_details, addressing, +					    LPDDR2_VOLTAGE_STABLE); + +	regs->emif_ddr_phy_ctlr_1_init = +			get_ddr_phy_ctrl_1(sys_freq / 2, RL_BOOT); + +	regs->emif_ddr_phy_ctlr_1 = +			get_ddr_phy_ctrl_1(freq, RL_FINAL); + +	regs->freq = freq; + +	print_timing_reg(regs->sdram_config_init); +	print_timing_reg(regs->sdram_config); +	print_timing_reg(regs->ref_ctrl); +	print_timing_reg(regs->sdram_tim1); +	print_timing_reg(regs->sdram_tim2); +	print_timing_reg(regs->sdram_tim3); +	print_timing_reg(regs->read_idle_ctrl); +	print_timing_reg(regs->temp_alert_config); +	print_timing_reg(regs->zq_config); +	print_timing_reg(regs->emif_ddr_phy_ctlr_1); +	print_timing_reg(regs->emif_ddr_phy_ctlr_1_init); +} +#endif /* CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS */ + +#ifdef CONFIG_SYS_AUTOMATIC_SDRAM_DETECTION +const char *get_lpddr2_type(u8 type_id) +{ +	switch (type_id) { +	case LPDDR2_TYPE_S4: +		return "LPDDR2-S4"; +	case LPDDR2_TYPE_S2: +		return "LPDDR2-S2"; +	default: +		return NULL; +	} +} + +const char *get_lpddr2_io_width(u8 width_id) +{ +	switch (width_id) { +	case LPDDR2_IO_WIDTH_8: +		return "x8"; +	case LPDDR2_IO_WIDTH_16: +		return "x16"; +	case LPDDR2_IO_WIDTH_32: +		return "x32"; +	default: +		return NULL; +	} +} + +const char *get_lpddr2_manufacturer(u32 manufacturer) +{ +	switch (manufacturer) { +	case LPDDR2_MANUFACTURER_SAMSUNG: +		return "Samsung"; +	case LPDDR2_MANUFACTURER_QIMONDA: +		return "Qimonda"; +	case LPDDR2_MANUFACTURER_ELPIDA: +		return "Elpida"; +	case LPDDR2_MANUFACTURER_ETRON: +		return "Etron"; +	case LPDDR2_MANUFACTURER_NANYA: +		return "Nanya"; +	case LPDDR2_MANUFACTURER_HYNIX: +		return "Hynix"; +	case LPDDR2_MANUFACTURER_MOSEL: +		return "Mosel"; +	case LPDDR2_MANUFACTURER_WINBOND: +		return "Winbond"; +	case LPDDR2_MANUFACTURER_ESMT: +		return "ESMT"; +	case LPDDR2_MANUFACTURER_SPANSION: +		return "Spansion"; +	case LPDDR2_MANUFACTURER_SST: +		return "SST"; +	case LPDDR2_MANUFACTURER_ZMOS: +		return "ZMOS"; +	case LPDDR2_MANUFACTURER_INTEL: +		return "Intel"; +	case LPDDR2_MANUFACTURER_NUMONYX: +		return "Numonyx"; +	case LPDDR2_MANUFACTURER_MICRON: +		return "Micron"; +	default: +		return NULL; +	} +} + +static void display_sdram_details(u32 emif_nr, u32 cs, +				  struct lpddr2_device_details *device) +{ +	const char *mfg_str; +	const char *type_str; +	char density_str[10]; +	u32 density; + +	debug("EMIF%d CS%d\t", emif_nr, cs); + +	if (!device) { +		debug("None\n"); +		return; +	} + +	mfg_str = get_lpddr2_manufacturer(device->manufacturer); +	type_str = get_lpddr2_type(device->type); + +	density = lpddr2_density_2_size_in_mbytes[device->density]; +	if ((density / 1024 * 1024) == density) { +		density /= 1024; +		sprintf(density_str, "%d GB", density); +	} else +		sprintf(density_str, "%d MB", density); +	if (mfg_str && type_str) +		debug("%s\t\t%s\t%s\n", mfg_str, type_str, density_str); +} + +static u8 is_lpddr2_sdram_present(u32 base, u32 cs, +				  struct lpddr2_device_details *lpddr2_device) +{ +	u32 mr = 0, temp; + +	mr = get_mr(base, cs, LPDDR2_MR0); +	if (mr > 0xFF) { +		/* Mode register value bigger than 8 bit */ +		return 0; +	} + +	temp = (mr & LPDDR2_MR0_DI_MASK) >> LPDDR2_MR0_DI_SHIFT; +	if (temp) { +		/* Not SDRAM */ +		return 0; +	} +	temp = (mr & LPDDR2_MR0_DNVI_MASK) >> LPDDR2_MR0_DNVI_SHIFT; + +	if (temp) { +		/* DNV supported - But DNV is only supported for NVM */ +		return 0; +	} + +	mr = get_mr(base, cs, LPDDR2_MR4); +	if (mr > 0xFF) { +		/* Mode register value bigger than 8 bit */ +		return 0; +	} + +	mr = get_mr(base, cs, LPDDR2_MR5); +	if (mr >= 0xFF) { +		/* Mode register value bigger than 8 bit */ +		return 0; +	} + +	if (!get_lpddr2_manufacturer(mr)) { +		/* Manufacturer not identified */ +		return 0; +	} +	lpddr2_device->manufacturer = mr; + +	mr = get_mr(base, cs, LPDDR2_MR6); +	if (mr >= 0xFF) { +		/* Mode register value bigger than 8 bit */ +		return 0; +	} + +	mr = get_mr(base, cs, LPDDR2_MR7); +	if (mr >= 0xFF) { +		/* Mode register value bigger than 8 bit */ +		return 0; +	} + +	mr = get_mr(base, cs, LPDDR2_MR8); +	if (mr >= 0xFF) { +		/* Mode register value bigger than 8 bit */ +		return 0; +	} + +	temp = (mr & MR8_TYPE_MASK) >> MR8_TYPE_SHIFT; +	if (!get_lpddr2_type(temp)) { +		/* Not SDRAM */ +		return 0; +	} +	lpddr2_device->type = temp; + +	temp = (mr & MR8_DENSITY_MASK) >> MR8_DENSITY_SHIFT; +	if (temp > LPDDR2_DENSITY_32Gb) { +		/* Density not supported */ +		return 0; +	} +	lpddr2_device->density = temp; + +	temp = (mr & MR8_IO_WIDTH_MASK) >> MR8_IO_WIDTH_SHIFT; +	if (!get_lpddr2_io_width(temp)) { +		/* IO width unsupported value */ +		return 0; +	} +	lpddr2_device->io_width = temp; + +	/* +	 * If all the above tests pass we should +	 * have a device on this chip-select +	 */ +	return 1; +} + +struct lpddr2_device_details *emif_get_device_details(u32 emif_nr, u8 cs, +			struct lpddr2_device_details *lpddr2_dev_details) +{ +	u32 phy; +	u32 base = (emif_nr == 1) ? EMIF1_BASE : EMIF2_BASE; + +	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; + +	if (!lpddr2_dev_details) +		return NULL; + +	/* Do the minimum init for mode register accesses */ +	if (!running_from_sdram()) { +		phy = get_ddr_phy_ctrl_1(get_sys_clk_freq() / 2, RL_BOOT); +		writel(phy, &emif->emif_ddr_phy_ctrl_1); +	} + +	if (!(is_lpddr2_sdram_present(base, cs, lpddr2_dev_details))) +		return NULL; + +	display_sdram_details(emif_num(base), cs, lpddr2_dev_details); + +	return lpddr2_dev_details; +} +#endif /* CONFIG_SYS_AUTOMATIC_SDRAM_DETECTION */ + +static void do_sdram_init(u32 base) +{ +	const struct emif_regs *regs; +	u32 in_sdram, emif_nr; + +	debug(">>do_sdram_init() %x\n", base); + +	in_sdram = running_from_sdram(); +	emif_nr = (base == EMIF1_BASE) ? 1 : 2; + +#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS +	emif_get_reg_dump(emif_nr, ®s); +	if (!regs) { +		debug("EMIF: reg dump not provided\n"); +		return; +	} +#else +	/* +	 * The user has not provided the register values. We need to +	 * calculate it based on the timings and the DDR frequency +	 */ +	struct emif_device_details dev_details; +	struct emif_regs calculated_regs; + +	/* +	 * Get device details: +	 * - Discovered if CONFIG_SYS_AUTOMATIC_SDRAM_DETECTION is set +	 * - Obtained from user otherwise +	 */ +	struct lpddr2_device_details cs0_dev_details, cs1_dev_details; +	emif_reset_phy(base); +	dev_details.cs0_device_details = emif_get_device_details(base, CS0, +						&cs0_dev_details); +	dev_details.cs1_device_details = emif_get_device_details(base, CS1, +						&cs1_dev_details); +	emif_reset_phy(base); + +	/* Return if no devices on this EMIF */ +	if (!dev_details.cs0_device_details && +	    !dev_details.cs1_device_details) { +		emif_sizes[emif_nr - 1] = 0; +		return; +	} + +	if (!in_sdram) +		emif_sizes[emif_nr - 1] = get_emif_mem_size(&dev_details); + +	/* +	 * Get device timings: +	 * - Default timings specified by JESD209-2 if +	 *   CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS is set +	 * - Obtained from user otherwise +	 */ +	emif_get_device_timings(emif_nr, &dev_details.cs0_device_timings, +				&dev_details.cs1_device_timings); + +	/* Calculate the register values */ +	emif_calculate_regs(&dev_details, omap_ddr_clk(), &calculated_regs); +	regs = &calculated_regs; +#endif /* CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS */ + +	/* +	 * Initializing the LPDDR2 device can not happen from SDRAM. +	 * Changing the timing registers in EMIF can happen(going from one +	 * OPP to another) +	 */ +	if (!in_sdram) +		lpddr2_init(base, regs); + +	/* Write to the shadow registers */ +	emif_update_timings(base, regs); + +	debug("<<do_sdram_init() %x\n", base); +} + +void emif_post_init_config(u32 base) +{ +	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; +	u32 omap_rev = omap_revision(); + +	if (omap_rev == OMAP5430_ES1_0) +		return; + +	/* reset phy on ES2.0 */ +	if (omap_rev == OMAP4430_ES2_0) +		emif_reset_phy(base); + +	/* Put EMIF back in smart idle on ES1.0 */ +	if (omap_rev == OMAP4430_ES1_0) +		writel(0x80000000, &emif->emif_pwr_mgmt_ctrl); +} + +void dmm_init(u32 base) +{ +	const struct dmm_lisa_map_regs *lisa_map_regs; + +#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS +	emif_get_dmm_regs(&lisa_map_regs); +#else +	u32 emif1_size, emif2_size, mapped_size, section_map = 0; +	u32 section_cnt, sys_addr; +	struct dmm_lisa_map_regs lis_map_regs_calculated = {0}; + +	mapped_size = 0; +	section_cnt = 3; +	sys_addr = CONFIG_SYS_SDRAM_BASE; +	emif1_size = emif_sizes[0]; +	emif2_size = emif_sizes[1]; +	debug("emif1_size 0x%x emif2_size 0x%x\n", emif1_size, emif2_size); + +	if (!emif1_size && !emif2_size) +		return; + +	/* symmetric interleaved section */ +	if (emif1_size && emif2_size) { +		mapped_size = min(emif1_size, emif2_size); +		section_map = DMM_LISA_MAP_INTERLEAVED_BASE_VAL; +		section_map |= 0 << EMIF_SDRC_ADDR_SHIFT; +		/* only MSB */ +		section_map |= (sys_addr >> 24) << +				EMIF_SYS_ADDR_SHIFT; +		section_map |= get_dmm_section_size_map(mapped_size * 2) +				<< EMIF_SYS_SIZE_SHIFT; +		lis_map_regs_calculated.dmm_lisa_map_3 = section_map; +		emif1_size -= mapped_size; +		emif2_size -= mapped_size; +		sys_addr += (mapped_size * 2); +		section_cnt--; +	} + +	/* +	 * Single EMIF section(we can have a maximum of 1 single EMIF +	 * section- either EMIF1 or EMIF2 or none, but not both) +	 */ +	if (emif1_size) { +		section_map = DMM_LISA_MAP_EMIF1_ONLY_BASE_VAL; +		section_map |= get_dmm_section_size_map(emif1_size) +				<< EMIF_SYS_SIZE_SHIFT; +		/* only MSB */ +		section_map |= (mapped_size >> 24) << +				EMIF_SDRC_ADDR_SHIFT; +		/* only MSB */ +		section_map |= (sys_addr >> 24) << EMIF_SYS_ADDR_SHIFT; +		section_cnt--; +	} +	if (emif2_size) { +		section_map = DMM_LISA_MAP_EMIF2_ONLY_BASE_VAL; +		section_map |= get_dmm_section_size_map(emif2_size) << +				EMIF_SYS_SIZE_SHIFT; +		/* only MSB */ +		section_map |= mapped_size >> 24 << EMIF_SDRC_ADDR_SHIFT; +		/* only MSB */ +		section_map |= sys_addr >> 24 << EMIF_SYS_ADDR_SHIFT; +		section_cnt--; +	} + +	if (section_cnt == 2) { +		/* Only 1 section - either symmetric or single EMIF */ +		lis_map_regs_calculated.dmm_lisa_map_3 = section_map; +		lis_map_regs_calculated.dmm_lisa_map_2 = 0; +		lis_map_regs_calculated.dmm_lisa_map_1 = 0; +	} else { +		/* 2 sections - 1 symmetric, 1 single EMIF */ +		lis_map_regs_calculated.dmm_lisa_map_2 = section_map; +		lis_map_regs_calculated.dmm_lisa_map_1 = 0; +	} + +	/* TRAP for invalid TILER mappings in section 0 */ +	lis_map_regs_calculated.dmm_lisa_map_0 = DMM_LISA_MAP_0_INVAL_ADDR_TRAP; + +	lisa_map_regs = &lis_map_regs_calculated; +#endif +	struct dmm_lisa_map_regs *hw_lisa_map_regs = +	    (struct dmm_lisa_map_regs *)base; + +	writel(0, &hw_lisa_map_regs->dmm_lisa_map_3); +	writel(0, &hw_lisa_map_regs->dmm_lisa_map_2); +	writel(0, &hw_lisa_map_regs->dmm_lisa_map_1); +	writel(0, &hw_lisa_map_regs->dmm_lisa_map_0); + +	writel(lisa_map_regs->dmm_lisa_map_3, +		&hw_lisa_map_regs->dmm_lisa_map_3); +	writel(lisa_map_regs->dmm_lisa_map_2, +		&hw_lisa_map_regs->dmm_lisa_map_2); +	writel(lisa_map_regs->dmm_lisa_map_1, +		&hw_lisa_map_regs->dmm_lisa_map_1); +	writel(lisa_map_regs->dmm_lisa_map_0, +		&hw_lisa_map_regs->dmm_lisa_map_0); + +	if (omap_revision() >= OMAP4460_ES1_0) { +		hw_lisa_map_regs = +		    (struct dmm_lisa_map_regs *)MA_BASE; + +		writel(lisa_map_regs->dmm_lisa_map_3, +			&hw_lisa_map_regs->dmm_lisa_map_3); +		writel(lisa_map_regs->dmm_lisa_map_2, +			&hw_lisa_map_regs->dmm_lisa_map_2); +		writel(lisa_map_regs->dmm_lisa_map_1, +			&hw_lisa_map_regs->dmm_lisa_map_1); +		writel(lisa_map_regs->dmm_lisa_map_0, +			&hw_lisa_map_regs->dmm_lisa_map_0); +	} +} + +/* + * SDRAM initialization: + * SDRAM initialization has two parts: + * 1. Configuring the SDRAM device + * 2. Update the AC timings related parameters in the EMIF module + * (1) should be done only once and should not be done while we are + * running from SDRAM. + * (2) can and should be done more than once if OPP changes. + * Particularly, this may be needed when we boot without SPL and + * and using Configuration Header(CH). ROM code supports only at 50% OPP + * at boot (low power boot). So u-boot has to switch to OPP100 and update + * the frequency. So, + * Doing (1) and (2) makes sense - first time initialization + * Doing (2) and not (1) makes sense - OPP change (when using CH) + * Doing (1) and not (2) doen't make sense + * See do_sdram_init() for the details + */ +void sdram_init(void) +{ +	u32 in_sdram, size_prog, size_detect; + +	debug(">>sdram_init()\n"); + +	if (omap_hw_init_context() == OMAP_INIT_CONTEXT_UBOOT_AFTER_SPL) +		return; + +	in_sdram = running_from_sdram(); +	debug("in_sdram = %d\n", in_sdram); + +	if (!in_sdram) +		bypass_dpll(&prcm->cm_clkmode_dpll_core); + + +	do_sdram_init(EMIF1_BASE); +	do_sdram_init(EMIF2_BASE); + +	if (!in_sdram) { +		dmm_init(DMM_BASE); +		emif_post_init_config(EMIF1_BASE); +		emif_post_init_config(EMIF2_BASE); +	} + +	/* for the shadow registers to take effect */ +	freq_update_core(); + +	/* Do some testing after the init */ +	if (!in_sdram) { +		size_prog = omap_sdram_size(); +		size_detect = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, +						size_prog); +		/* Compare with the size programmed */ +		if (size_detect != size_prog) { +			printf("SDRAM: identified size not same as expected" +				" size identified: %x expected: %x\n", +				size_detect, +				size_prog); +		} else +			debug("get_ram_size() successful"); +	} + +	debug("<<sdram_init()\n"); +} diff --git a/arch/arm/cpu/armv7/omap-common/hwinit-common.c b/arch/arm/cpu/armv7/omap-common/hwinit-common.c new file mode 100644 index 000000000..f65705db1 --- /dev/null +++ b/arch/arm/cpu/armv7/omap-common/hwinit-common.c @@ -0,0 +1,267 @@ +/* + * + * Common functions for OMAP4/5 based boards + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * + * Author : + *	Aneesh V	<aneesh@ti.com> + *	Steve Sakoman	<steve@sakoman.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/arch/sys_proto.h> +#include <asm/sizes.h> +#include <asm/emif.h> +#include <asm/omap_common.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * This is used to verify if the configuration header + * was executed by rom code prior to control of transfer + * to the bootloader. SPL is responsible for saving and + * passing the boot_params pointer to the u-boot. + */ +struct omap_boot_parameters boot_params __attribute__ ((section(".data"))); + +#ifdef CONFIG_SPL_BUILD +/* + * We use static variables because global data is not ready yet. + * Initialized data is available in SPL right from the beginning. + * We would not typically need to save these parameters in regular + * U-Boot. This is needed only in SPL at the moment. + */ +u32 omap_bootmode = MMCSD_MODE_FAT; + +u32 omap_boot_device(void) +{ +	return (u32) (boot_params.omap_bootdevice); +} + +u32 omap_boot_mode(void) +{ +	return omap_bootmode; +} +#endif + +void do_set_mux(u32 base, struct pad_conf_entry const *array, int size) +{ +	int i; +	struct pad_conf_entry *pad = (struct pad_conf_entry *) array; + +	for (i = 0; i < size; i++, pad++) +		writew(pad->val, base + pad->offset); +} + +static void set_mux_conf_regs(void) +{ +	switch (omap_hw_init_context()) { +	case OMAP_INIT_CONTEXT_SPL: +		set_muxconf_regs_essential(); +		break; +	case OMAP_INIT_CONTEXT_UBOOT_AFTER_SPL: +#ifdef CONFIG_SYS_ENABLE_PADS_ALL +		set_muxconf_regs_non_essential(); +#endif +		break; +	case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR: +	case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH: +		set_muxconf_regs_essential(); +#ifdef CONFIG_SYS_ENABLE_PADS_ALL +		set_muxconf_regs_non_essential(); +#endif +		break; +	} +} + +u32 cortex_rev(void) +{ + +	unsigned int rev; + +	/* Read Main ID Register (MIDR) */ +	asm ("mrc p15, 0, %0, c0, c0, 0" : "=r" (rev)); + +	return rev; +} + +void omap_rev_string(char *omap_rev_string) +{ +	u32 omap_rev = omap_revision(); +	u32 omap_variant = (omap_rev & 0xFFFF0000) >> 16; +	u32 major_rev = (omap_rev & 0x00000F00) >> 8; +	u32 minor_rev = (omap_rev & 0x000000F0) >> 4; + +	sprintf(omap_rev_string, "OMAP%x ES%x.%x", omap_variant, major_rev, +		minor_rev); +} + +#ifdef CONFIG_SPL_BUILD +static void init_boot_params(void) +{ +	boot_params_ptr = (u32 *) &boot_params; +} +#endif + +/* + * Routine: s_init + * Description: Does early system init of watchdog, muxing,  andclocks + * Watchdog disable is done always. For the rest what gets done + * depends on the boot mode in which this function is executed + *   1. s_init of SPL running from SRAM + *   2. s_init of U-Boot running from FLASH + *   3. s_init of U-Boot loaded to SDRAM by SPL + *   4. s_init of U-Boot loaded to SDRAM by ROM code using the + *	Configuration Header feature + * Please have a look at the respective functions to see what gets + * done in each of these cases + * This function is called with SRAM stack. + */ +void s_init(void) +{ +	init_omap_revision(); +	watchdog_init(); +	set_mux_conf_regs(); +#ifdef CONFIG_SPL_BUILD +	setup_clocks_for_console(); +	preloader_console_init(); +	do_io_settings(); +#endif +	prcm_init(); +#ifdef CONFIG_SPL_BUILD +	/* For regular u-boot sdram_init() is called from dram_init() */ +	sdram_init(); +	init_boot_params(); +#endif +} + +/* + * Routine: wait_for_command_complete + * Description: Wait for posting to finish on watchdog + */ +void wait_for_command_complete(struct watchdog *wd_base) +{ +	int pending = 1; +	do { +		pending = readl(&wd_base->wwps); +	} while (pending); +} + +/* + * Routine: watchdog_init + * Description: Shut down watch dogs + */ +void watchdog_init(void) +{ +	struct watchdog *wd2_base = (struct watchdog *)WDT2_BASE; + +	writel(WD_UNLOCK1, &wd2_base->wspr); +	wait_for_command_complete(wd2_base); +	writel(WD_UNLOCK2, &wd2_base->wspr); +} + + +/* + * This function finds the SDRAM size available in the system + * based on DMM section configurations + * This is needed because the size of memory installed may be + * different on different versions of the board + */ +u32 omap_sdram_size(void) +{ +	u32 section, i, total_size = 0, size, addr; + +	for (i = 0; i < 4; i++) { +		section	= __raw_readl(DMM_BASE + i*4); +		addr = section & EMIF_SYS_ADDR_MASK; +		/* See if the address is valid */ +		if ((addr >= DRAM_ADDR_SPACE_START) && +		    (addr < DRAM_ADDR_SPACE_END)) { +			size = ((section & EMIF_SYS_SIZE_MASK) >> +				   EMIF_SYS_SIZE_SHIFT); +			size = 1 << size; +			size *= SZ_16M; +			total_size += size; +		} +	} + +	return total_size; +} + + +/* + * Routine: dram_init + * Description: sets uboots idea of sdram size + */ +int dram_init(void) +{ +	sdram_init(); +	gd->ram_size = omap_sdram_size(); +	return 0; +} + +/* + * Print board information + */ +int checkboard(void) +{ +	puts(sysinfo.board_string); +	return 0; +} + +/* +* This function is called by start_armboot. You can reliably use static +* data. Any boot-time function that require static data should be +* called from here +*/ +int arch_cpu_init(void) +{ +	return 0; +} + +/* + *  get_device_type(): tell if GP/HS/EMU/TST + */ +u32 get_device_type(void) +{ +	return 0; +} + +/* + * Print CPU information + */ +int print_cpuinfo(void) +{ +	char rev_string_buffer[50]; + +	omap_rev_string(rev_string_buffer); +	printf("CPU  : %s\n", rev_string_buffer); + +	return 0; +} +#ifndef CONFIG_SYS_DCACHE_OFF +void enable_caches(void) +{ +	/* Enable D-cache. I-cache is already enabled in start.S */ +	dcache_enable(); +} +#endif diff --git a/arch/arm/cpu/armv7/omap4/lowlevel_init.S b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S index 91525ecd4..35f38acf5 100644 --- a/arch/arm/cpu/armv7/omap4/lowlevel_init.S +++ b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S @@ -26,8 +26,8 @@   * MA 02111-1307 USA   */ -#include <asm/arch/omap4.h> -#ifdef CONFIG_SPL_BUILD +#include <asm/arch/omap.h> +  .global save_boot_params  save_boot_params:  	/* @@ -43,21 +43,40 @@ save_boot_params:  	cmp	r2, r0  	blt	1f -	/* Store the boot device in omap4_boot_device */ -	ldr     r2, [r0, #BOOT_DEVICE_OFFSET]	@ r1 <- value of boot device +	/* +	 * store the boot params passed from rom code or saved +	 * and passed by SPL +	 */ +	cmp	r0, #0 +	beq	1f +	ldr	r1, =boot_params +	str	r0, [r1] +#ifdef CONFIG_SPL_BUILD +	/* Store the boot device in omap_boot_device */ +	ldrb	r2, [r0, #BOOT_DEVICE_OFFSET]	@ r1 <- value of boot device  	and	r2, #BOOT_DEVICE_MASK -	ldr	r3, =omap4_boot_device -	str     r2, [r3]			@ omap4_boot_device <- r1 +	ldr	r3, =boot_params +	strb	r2, [r3, #BOOT_DEVICE_OFFSET]	@ omap_boot_device <- r1 -	/* Store the boot mode (raw/FAT) in omap4_boot_mode */ +	/* boot mode is passed only for devices that can raw/fat mode */ +	cmp	r2, #2 +	blt	2f +	cmp	r2, #7 +	bgt	2f +	/* Store the boot mode (raw/FAT) in omap_boot_mode */  	ldr	r2, [r0, #DEV_DESC_PTR_OFFSET]	@ get the device descriptor ptr  	ldr	r2, [r2, #DEV_DATA_PTR_OFFSET]	@ get the pDeviceData ptr  	ldr	r2, [r2, #BOOT_MODE_OFFSET]	@ get the boot mode -	ldr	r3, =omap4_boot_mode +	ldr	r3, =omap_bootmode  	str	r2, [r3] +#endif +2: +	ldrb	r2, [r0, #CH_FLAGS_OFFSET] +	ldr	r3, =boot_params +	strb	r2, [r3, #CH_FLAGS_OFFSET]  1:  	bx	lr -#endif +  .globl lowlevel_init  lowlevel_init: diff --git a/arch/arm/cpu/armv7/omap4/mem.c b/arch/arm/cpu/armv7/omap-common/mem-common.c index 878f0e304..878f0e304 100644 --- a/arch/arm/cpu/armv7/omap4/mem.c +++ b/arch/arm/cpu/armv7/omap-common/mem-common.c diff --git a/arch/arm/cpu/armv7/omap-common/spl.c b/arch/arm/cpu/armv7/omap-common/spl.c index 2c59d2b36..d6d7d65ec 100644 --- a/arch/arm/cpu/armv7/omap-common/spl.c +++ b/arch/arm/cpu/armv7/omap-common/spl.c @@ -38,6 +38,7 @@  DECLARE_GLOBAL_DATA_PTR; +u32* boot_params_ptr = NULL;  struct spl_image_info spl_image;  /* Define global data structure pointer to it*/ @@ -92,12 +93,16 @@ void spl_parse_image_header(const struct image_header *header)  static void jump_to_image_no_args(void)  { -	typedef void (*image_entry_noargs_t)(void)__attribute__ ((noreturn)); +	typedef void (*image_entry_noargs_t)(u32 *)__attribute__ ((noreturn));  	image_entry_noargs_t image_entry =  			(image_entry_noargs_t) spl_image.entry_point;  	debug("image entry point: 0x%X\n", spl_image.entry_point); -	image_entry(); +	/* Pass the saved boot_params from rom code */ +#if defined(CONFIG_VIRTIO) || defined(CONFIG_ZEBU) +	image_entry = 0x80100000; +#endif +	image_entry((u32 *)&boot_params_ptr);  }  void jump_to_image_no_args(void) __attribute__ ((noreturn)); diff --git a/arch/arm/cpu/armv7/omap4/Makefile b/arch/arm/cpu/armv7/omap4/Makefile index e7ee0b8c0..83160a28f 100644 --- a/arch/arm/cpu/armv7/omap4/Makefile +++ b/arch/arm/cpu/armv7/omap4/Makefile @@ -25,17 +25,10 @@ include $(TOPDIR)/config.mk  LIB	=  $(obj)lib$(SOC).o -SOBJS	+= lowlevel_init.o - -COBJS	+= board.o +COBJS	+= sdram_elpida.o +COBJS	+= hwinit.o  COBJS	+= clocks.o  COBJS	+= emif.o -COBJS	+= sdram_elpida.o - -ifndef CONFIG_SPL_BUILD -COBJS	+= mem.o -COBJS	+= sys_info.o -endif  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS)) diff --git a/arch/arm/cpu/armv7/omap4/board.c b/arch/arm/cpu/armv7/omap4/board.c deleted file mode 100644 index 2497e3e72..000000000 --- a/arch/arm/cpu/armv7/omap4/board.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * - * Common functions for OMAP4 based boards - * - * (C) Copyright 2010 - * Texas Instruments, <www.ti.com> - * - * Author : - *	Aneesh V	<aneesh@ti.com> - *	Steve Sakoman	<steve@sakoman.com> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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 <common.h> -#include <asm/armv7.h> -#include <asm/arch/cpu.h> -#include <asm/arch/sys_proto.h> -#include <asm/sizes.h> -#include <asm/arch/emif.h> -#include <asm/arch/gpio.h> -#include "omap4_mux_data.h" - -DECLARE_GLOBAL_DATA_PTR; - -u32 *const omap4_revision = (u32 *)OMAP4_SRAM_SCRATCH_OMAP4_REV; - -static const struct gpio_bank gpio_bank_44xx[6] = { -	{ (void *)OMAP44XX_GPIO1_BASE, METHOD_GPIO_24XX }, -	{ (void *)OMAP44XX_GPIO2_BASE, METHOD_GPIO_24XX }, -	{ (void *)OMAP44XX_GPIO3_BASE, METHOD_GPIO_24XX }, -	{ (void *)OMAP44XX_GPIO4_BASE, METHOD_GPIO_24XX }, -	{ (void *)OMAP44XX_GPIO5_BASE, METHOD_GPIO_24XX }, -	{ (void *)OMAP44XX_GPIO6_BASE, METHOD_GPIO_24XX }, -}; - -const struct gpio_bank *const omap_gpio_bank = gpio_bank_44xx; - -#ifdef CONFIG_SPL_BUILD -/* - * We use static variables because global data is not ready yet. - * Initialized data is available in SPL right from the beginning. - * We would not typically need to save these parameters in regular - * U-Boot. This is needed only in SPL at the moment. - */ -u32 omap4_boot_device = BOOT_DEVICE_MMC1; -u32 omap4_boot_mode = MMCSD_MODE_FAT; - -u32 omap_boot_device(void) -{ -	return omap4_boot_device; -} - -u32 omap_boot_mode(void) -{ -	return omap4_boot_mode; -} - -/* - * Some tuning of IOs for optimal power and performance - */ -static void do_io_settings(void) -{ -	u32 lpddr2io; -	struct control_lpddr2io_regs *lpddr2io_regs = -		(struct control_lpddr2io_regs *)LPDDR2_IO_REGS_BASE; -	struct omap4_sys_ctrl_regs *const ctrl = -		(struct omap4_sys_ctrl_regs *)SYSCTRL_GENERAL_CORE_BASE; - -	u32 omap4_rev = omap_revision(); - -	if (omap4_rev == OMAP4430_ES1_0) -		lpddr2io = CONTROL_LPDDR2IO_SLEW_125PS_DRV8_PULL_DOWN; -	else if (omap4_rev == OMAP4430_ES2_0) -		lpddr2io = CONTROL_LPDDR2IO_SLEW_325PS_DRV8_GATE_KEEPER; -	else -		lpddr2io = CONTROL_LPDDR2IO_SLEW_315PS_DRV12_PULL_DOWN; - -	/* EMIF1 */ -	writel(lpddr2io, &lpddr2io_regs->control_lpddr2io1_0); -	writel(lpddr2io, &lpddr2io_regs->control_lpddr2io1_1); -	/* No pull for GR10 as per hw team's recommendation */ -	writel(lpddr2io & ~LPDDR2IO_GR10_WD_MASK, -		&lpddr2io_regs->control_lpddr2io1_2); -	writel(CONTROL_LPDDR2IO_3_VAL, &lpddr2io_regs->control_lpddr2io1_3); - -	/* EMIF2 */ -	writel(lpddr2io, &lpddr2io_regs->control_lpddr2io2_0); -	writel(lpddr2io, &lpddr2io_regs->control_lpddr2io2_1); -	/* No pull for GR10 as per hw team's recommendation */ -	writel(lpddr2io & ~LPDDR2IO_GR10_WD_MASK, -		&lpddr2io_regs->control_lpddr2io2_2); -	writel(CONTROL_LPDDR2IO_3_VAL, &lpddr2io_regs->control_lpddr2io2_3); - -	/* -	 * Some of these settings (TRIM values) come from eFuse and are -	 * in turn programmed in the eFuse at manufacturing time after -	 * calibration of the device. Do the software over-ride only if -	 * the device is not correctly trimmed -	 */ -	if (!(readl(&ctrl->control_std_fuse_opp_bgap) & 0xFFFF)) { - -		writel(LDOSRAM_VOLT_CTRL_OVERRIDE, -			&ctrl->control_ldosram_iva_voltage_ctrl); - -		writel(LDOSRAM_VOLT_CTRL_OVERRIDE, -			&ctrl->control_ldosram_mpu_voltage_ctrl); - -		writel(LDOSRAM_VOLT_CTRL_OVERRIDE, -			&ctrl->control_ldosram_core_voltage_ctrl); -	} - -	if (!readl(&ctrl->control_efuse_1)) -		writel(CONTROL_EFUSE_1_OVERRIDE, &ctrl->control_efuse_1); - -	if (!readl(&ctrl->control_efuse_2)) -		writel(CONTROL_EFUSE_2_OVERRIDE, &ctrl->control_efuse_2); -} -#endif - -void do_set_mux(u32 base, struct pad_conf_entry const *array, int size) -{ -	int i; -	struct pad_conf_entry *pad = (struct pad_conf_entry *) array; - -	for (i = 0; i < size; i++, pad++) -		writew(pad->val, base + pad->offset); -} - -static void set_muxconf_regs_essential(void) -{ -	do_set_mux(CONTROL_PADCONF_CORE, core_padconf_array_essential, -		   sizeof(core_padconf_array_essential) / -		   sizeof(struct pad_conf_entry)); - -	do_set_mux(CONTROL_PADCONF_WKUP, wkup_padconf_array_essential, -		   sizeof(wkup_padconf_array_essential) / -		   sizeof(struct pad_conf_entry)); - -	if (omap_revision() >= OMAP4460_ES1_0) -		do_set_mux(CONTROL_PADCONF_WKUP, -				 wkup_padconf_array_essential_4460, -				 sizeof(wkup_padconf_array_essential_4460) / -				 sizeof(struct pad_conf_entry)); -} - -static void set_mux_conf_regs(void) -{ -	switch (omap4_hw_init_context()) { -	case OMAP_INIT_CONTEXT_SPL: -		set_muxconf_regs_essential(); -		break; -	case OMAP_INIT_CONTEXT_UBOOT_AFTER_SPL: -		set_muxconf_regs_non_essential(); -		break; -	case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR: -	case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH: -		set_muxconf_regs_essential(); -		set_muxconf_regs_non_essential(); -		break; -	} -} - -static u32 cortex_a9_rev(void) -{ - -	unsigned int rev; - -	/* Read Main ID Register (MIDR) */ -	asm ("mrc p15, 0, %0, c0, c0, 0" : "=r" (rev)); - -	return rev; -} - -static void init_omap4_revision(void) -{ -	/* -	 * For some of the ES2/ES1 boards ID_CODE is not reliable: -	 * Also, ES1 and ES2 have different ARM revisions -	 * So use ARM revision for identification -	 */ -	unsigned int arm_rev = cortex_a9_rev(); - -	switch (arm_rev) { -	case MIDR_CORTEX_A9_R0P1: -		*omap4_revision = OMAP4430_ES1_0; -		break; -	case MIDR_CORTEX_A9_R1P2: -		switch (readl(CONTROL_ID_CODE)) { -		case OMAP4430_CONTROL_ID_CODE_ES2_0: -			*omap4_revision = OMAP4430_ES2_0; -			break; -		case OMAP4430_CONTROL_ID_CODE_ES2_1: -			*omap4_revision = OMAP4430_ES2_1; -			break; -		case OMAP4430_CONTROL_ID_CODE_ES2_2: -			*omap4_revision = OMAP4430_ES2_2; -			break; -		default: -			*omap4_revision = OMAP4430_ES2_0; -			break; -		} -		break; -	case MIDR_CORTEX_A9_R1P3: -		*omap4_revision = OMAP4430_ES2_3; -		break; -	case MIDR_CORTEX_A9_R2P10: -		switch (readl(CONTROL_ID_CODE)) { -		case OMAP4460_CONTROL_ID_CODE_ES1_0: -			*omap4_revision = OMAP4460_ES1_0; -			break; -		case OMAP4460_CONTROL_ID_CODE_ES1_1: -			*omap4_revision = OMAP4460_ES1_1; -			break; -		default: -			*omap4_revision = OMAP4460_ES1_0; -			break; -		} -		break; -	default: -		*omap4_revision = OMAP4430_SILICON_ID_INVALID; -		break; -	} -} - -void omap_rev_string(char *omap4_rev_string) -{ -	u32 omap4_rev = omap_revision(); -	u32 omap4_variant = (omap4_rev & 0xFFFF0000) >> 16; -	u32 major_rev = (omap4_rev & 0x00000F00) >> 8; -	u32 minor_rev = (omap4_rev & 0x000000F0) >> 4; - -	sprintf(omap4_rev_string, "OMAP%x ES%x.%x", omap4_variant, major_rev, -		minor_rev); -} - -/* - * Routine: s_init - * Description: Does early system init of watchdog, muxing,  andclocks - * Watchdog disable is done always. For the rest what gets done - * depends on the boot mode in which this function is executed - *   1. s_init of SPL running from SRAM - *   2. s_init of U-Boot running from FLASH - *   3. s_init of U-Boot loaded to SDRAM by SPL - *   4. s_init of U-Boot loaded to SDRAM by ROM code using the - *	Configuration Header feature - * Please have a look at the respective functions to see what gets - * done in each of these cases - * This function is called with SRAM stack. - */ -void s_init(void) -{ -	init_omap4_revision(); -	watchdog_init(); -	set_mux_conf_regs(); -#ifdef CONFIG_SPL_BUILD -	setup_clocks_for_console(); -	preloader_console_init(); -	do_io_settings(); -#endif -	prcm_init(); -#ifdef CONFIG_SPL_BUILD -	/* For regular u-boot sdram_init() is called from dram_init() */ -	sdram_init(); -#endif -} - -/* - * Routine: wait_for_command_complete - * Description: Wait for posting to finish on watchdog - */ -void wait_for_command_complete(struct watchdog *wd_base) -{ -	int pending = 1; -	do { -		pending = readl(&wd_base->wwps); -	} while (pending); -} - -/* - * Routine: watchdog_init - * Description: Shut down watch dogs - */ -void watchdog_init(void) -{ -	struct watchdog *wd2_base = (struct watchdog *)WDT2_BASE; - -	writel(WD_UNLOCK1, &wd2_base->wspr); -	wait_for_command_complete(wd2_base); -	writel(WD_UNLOCK2, &wd2_base->wspr); -} - - -/* - * This function finds the SDRAM size available in the system - * based on DMM section configurations - * This is needed because the size of memory installed may be - * different on different versions of the board - */ -u32 omap4_sdram_size(void) -{ -	u32 section, i, total_size = 0, size, addr; -	for (i = 0; i < 4; i++) { -		section	= __raw_readl(OMAP44XX_DMM_LISA_MAP_BASE + i*4); -		addr = section & OMAP44XX_SYS_ADDR_MASK; -		/* See if the address is valid */ -		if ((addr >= OMAP44XX_DRAM_ADDR_SPACE_START) && -		    (addr < OMAP44XX_DRAM_ADDR_SPACE_END)) { -			size	= ((section & OMAP44XX_SYS_SIZE_MASK) >> -				   OMAP44XX_SYS_SIZE_SHIFT); -			size	= 1 << size; -			size	*= SZ_16M; -			total_size += size; -		} -	} -	return total_size; -} - - -/* - * Routine: dram_init - * Description: sets uboots idea of sdram size - */ -int dram_init(void) -{ -	sdram_init(); -	gd->ram_size = omap4_sdram_size(); - -	return 0; -} - -/* - * Print board information - */ -int checkboard(void) -{ -	puts(sysinfo.board_string); -	return 0; -} - -/* -* This function is called by start_armboot. You can reliably use static -* data. Any boot-time function that require static data should be -* called from here -*/ -int arch_cpu_init(void) -{ -	return 0; -} - -#ifndef CONFIG_SYS_L2CACHE_OFF -void v7_outer_cache_enable(void) -{ -	set_pl310_ctrl_reg(1); -} - -void v7_outer_cache_disable(void) -{ -	set_pl310_ctrl_reg(0); -} -#endif - -#ifndef CONFIG_SYS_DCACHE_OFF -void enable_caches(void) -{ -	/* Enable D-cache. I-cache is already enabled in start.S */ -	dcache_enable(); -} -#endif diff --git a/arch/arm/cpu/armv7/omap4/clocks.c b/arch/arm/cpu/armv7/omap4/clocks.c index 095ba39ae..0886f9243 100644 --- a/arch/arm/cpu/armv7/omap4/clocks.c +++ b/arch/arm/cpu/armv7/omap4/clocks.c @@ -50,7 +50,7 @@  struct omap4_prcm_regs *const prcm = (struct omap4_prcm_regs *)0x4A004100; -static const u32 sys_clk_array[8] = { +const u32 sys_clk_array[8] = {  	12000000,	       /* 12 MHz */  	13000000,	       /* 13 MHz */  	16800000,	       /* 16.8 MHz */ @@ -79,14 +79,14 @@ static const struct dpll_params mpu_dpll_params_1840mhz[NUM_SYS_CLKS] = {  };  /* dpll locked at 1584 MHz - MPU clk at 792 MHz(OPP Turbo 4430) */ -static const struct dpll_params mpu_dpll_params_1584mhz[NUM_SYS_CLKS] = { -	{66, 0, 1, -1, -1, -1, -1, -1},		/* 12 MHz   */ -	{792, 12, 1, -1, -1, -1, -1, -1},	/* 13 MHz   */ -	{330, 6, 1, -1, -1, -1, -1, -1},	/* 16.8 MHz */ -	{165, 3, 1, -1, -1, -1, -1, -1},	/* 19.2 MHz */ -	{396, 12, 1, -1, -1, -1, -1, -1},	/* 26 MHz   */ -	{88, 2, 1, -1, -1, -1, -1, -1},		/* 27 MHz   */ -	{165, 7, 1, -1, -1, -1, -1, -1}		/* 38.4 MHz */ +static const struct dpll_params mpu_dpll_params_1600mhz[NUM_SYS_CLKS] = { +	{200, 2, 1, -1, -1, -1, -1, -1},	/* 12 MHz   */ +	{800, 12, 1, -1, -1, -1, -1, -1},	/* 13 MHz   */ +	{619, 12, 1, -1, -1, -1, -1, -1},	/* 16.8 MHz */ +	{125, 2, 1, -1, -1, -1, -1, -1},	/* 19.2 MHz */ +	{400, 12, 1, -1, -1, -1, -1, -1},	/* 26 MHz   */ +	{800, 26, 1, -1, -1, -1, -1, -1},	/* 27 MHz   */ +	{125, 5, 1, -1, -1, -1, -1, -1}		/* 38.4 MHz */  };  /* dpll locked at 1200 MHz - MPU clk at 600 MHz */ @@ -168,7 +168,6 @@ static const struct dpll_params abe_dpll_params_32k_196608khz = {  	750, 0, 1, 1, -1, -1, -1, -1  }; -  static const struct dpll_params usb_dpll_params_1920mhz[NUM_SYS_CLKS] = {  	{80, 0, 2, -1, -1, -1, -1, -1},		/* 12 MHz   */  	{960, 12, 2, -1, -1, -1, -1, -1},	/* 13 MHz   */ @@ -179,98 +178,10 @@ static const struct dpll_params usb_dpll_params_1920mhz[NUM_SYS_CLKS] = {  	{25, 0, 2, -1, -1, -1, -1, -1}		/* 38.4 MHz */  }; -static inline u32 __get_sys_clk_index(void) -{ -	u32 ind; -	/* -	 * For ES1 the ROM code calibration of sys clock is not reliable -	 * due to hw issue. So, use hard-coded value. If this value is not -	 * correct for any board over-ride this function in board file -	 * From ES2.0 onwards you will get this information from -	 * CM_SYS_CLKSEL -	 */ -	if (omap_revision() == OMAP4430_ES1_0) -		ind = OMAP_SYS_CLK_IND_38_4_MHZ; -	else { -		/* SYS_CLKSEL - 1 to match the dpll param array indices */ -		ind = (readl(&prcm->cm_sys_clksel) & -			CM_SYS_CLKSEL_SYS_CLKSEL_MASK) - 1; -	} -	return ind; -} - -u32 get_sys_clk_index(void) -	__attribute__ ((weak, alias("__get_sys_clk_index"))); - -u32 get_sys_clk_freq(void) -{ -	u8 index = get_sys_clk_index(); -	return sys_clk_array[index]; -} - -static inline void do_bypass_dpll(u32 *const base) -{ -	struct dpll_regs *dpll_regs = (struct dpll_regs *)base; - -	clrsetbits_le32(&dpll_regs->cm_clkmode_dpll, -			CM_CLKMODE_DPLL_DPLL_EN_MASK, -			DPLL_EN_FAST_RELOCK_BYPASS << -			CM_CLKMODE_DPLL_EN_SHIFT); -} - -static inline void wait_for_bypass(u32 *const base) -{ -	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; - -	if (!wait_on_value(ST_DPLL_CLK_MASK, 0, &dpll_regs->cm_idlest_dpll, -				LDELAY)) { -		printf("Bypassing DPLL failed %p\n", base); -	} -} - -static inline void do_lock_dpll(u32 *const base) -{ -	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; - -	clrsetbits_le32(&dpll_regs->cm_clkmode_dpll, -		      CM_CLKMODE_DPLL_DPLL_EN_MASK, -		      DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT); -} - -static inline void wait_for_lock(u32 *const base) -{ -	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; - -	if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK, -		&dpll_regs->cm_idlest_dpll, LDELAY)) { -		printf("DPLL locking failed for %p\n", base); -		hang(); -	} -} - -static void do_setup_dpll(u32 *const base, const struct dpll_params *params, -				u8 lock) +void setup_post_dividers(u32 *const base, const struct dpll_params *params)  { -	u32 temp;  	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; -	bypass_dpll(base); - -	/* Set M & N */ -	temp = readl(&dpll_regs->cm_clksel_dpll); - -	temp &= ~CM_CLKSEL_DPLL_M_MASK; -	temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK; - -	temp &= ~CM_CLKSEL_DPLL_N_MASK; -	temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK; - -	writel(temp, &dpll_regs->cm_clksel_dpll); - -	/* Lock */ -	if (lock) -		do_lock_dpll(base); -  	/* Setup post-dividers */  	if (params->m2 >= 0)  		writel(params->m2, &dpll_regs->cm_div_m2_dpll); @@ -284,10 +195,29 @@ static void do_setup_dpll(u32 *const base, const struct dpll_params *params,  		writel(params->m6, &dpll_regs->cm_div_m6_dpll);  	if (params->m7 >= 0)  		writel(params->m7, &dpll_regs->cm_div_m7_dpll); +} -	/* Wait till the DPLL locks */ -	if (lock) -		wait_for_lock(base); +/* + * Lock MPU dpll + * + * Resulting MPU frequencies: + * 4430 ES1.0	: 600 MHz + * 4430 ES2.x	: 792 MHz (OPP Turbo) + * 4460		: 920 MHz (OPP Turbo) - DCC disabled + */ +const struct dpll_params *get_mpu_dpll_params(void) +{ +	u32 omap_rev, sysclk_ind; + +	omap_rev = omap_revision(); +	sysclk_ind = get_sys_clk_index(); + +	if (omap_rev == OMAP4430_ES1_0) +		return &mpu_dpll_params_1200mhz[sysclk_ind]; +	else if (omap_rev < OMAP4460_ES1_0) +		return &mpu_dpll_params_1600mhz[sysclk_ind]; +	else +		return &mpu_dpll_params_1840mhz[sysclk_ind];  }  const struct dpll_params *get_core_dpll_params(void) @@ -306,228 +236,33 @@ const struct dpll_params *get_core_dpll_params(void)  	}  } -u32 omap4_ddr_clk(void) -{ -	u32 ddr_clk, sys_clk_khz; -	const struct dpll_params *core_dpll_params; - -	sys_clk_khz = get_sys_clk_freq() / 1000; -	core_dpll_params = get_core_dpll_params(); - -	debug("sys_clk %d\n ", sys_clk_khz * 1000); - -	/* Find Core DPLL locked frequency first */ -	ddr_clk = sys_clk_khz * 2 * core_dpll_params->m / -			(core_dpll_params->n + 1); -	/* -	 * DDR frequency is PHY_ROOT_CLK/2 -	 * PHY_ROOT_CLK = Fdpll/2/M2 -	 */ -	ddr_clk = ddr_clk / 4 / core_dpll_params->m2; - -	ddr_clk *= 1000;	/* convert to Hz */ -	debug("ddr_clk %d\n ", ddr_clk); - -	return ddr_clk; +const struct dpll_params *get_per_dpll_params(void) +{ +	u32 sysclk_ind = get_sys_clk_index(); +	return &per_dpll_params_1536mhz[sysclk_ind];  } -/* - * Lock MPU dpll - * - * Resulting MPU frequencies: - * 4430 ES1.0	: 600 MHz - * 4430 ES2.x	: 792 MHz (OPP Turbo) - * 4460		: 920 MHz (OPP Turbo) - DCC disabled - */ -void configure_mpu_dpll(void) +const struct dpll_params *get_iva_dpll_params(void)  { -	const struct dpll_params *params; -	struct dpll_regs *mpu_dpll_regs; -	u32 omap4_rev, sysclk_ind; - -	omap4_rev = omap_revision(); -	sysclk_ind = get_sys_clk_index(); - -	if (omap4_rev == OMAP4430_ES1_0) -		params = &mpu_dpll_params_1200mhz[sysclk_ind]; -	else if (omap4_rev < OMAP4460_ES1_0) -		params = &mpu_dpll_params_1584mhz[sysclk_ind]; -	else -		params = &mpu_dpll_params_1840mhz[sysclk_ind]; - -	/* DCC and clock divider settings for 4460 */ -	if (omap4_rev >= OMAP4460_ES1_0) { -		mpu_dpll_regs = -			(struct dpll_regs *)&prcm->cm_clkmode_dpll_mpu; -		bypass_dpll(&prcm->cm_clkmode_dpll_mpu); -		clrbits_le32(&prcm->cm_mpu_mpu_clkctrl, -			MPU_CLKCTRL_CLKSEL_EMIF_DIV_MODE_MASK); -		setbits_le32(&prcm->cm_mpu_mpu_clkctrl, -			MPU_CLKCTRL_CLKSEL_ABE_DIV_MODE_MASK); -		clrbits_le32(&mpu_dpll_regs->cm_clksel_dpll, -			CM_CLKSEL_DCC_EN_MASK); -	} - -	do_setup_dpll(&prcm->cm_clkmode_dpll_mpu, params, DPLL_LOCK); -	debug("MPU DPLL locked\n"); +	u32 sysclk_ind = get_sys_clk_index(); +	return &iva_dpll_params_1862mhz[sysclk_ind];  } -static void setup_dplls(void) +const struct dpll_params *get_usb_dpll_params(void)  { -	u32 sysclk_ind, temp; -	const struct dpll_params *params; -	debug("setup_dplls\n"); - -	sysclk_ind = get_sys_clk_index(); - -	/* CORE dpll */ -	params = get_core_dpll_params();	/* default - safest */ -	/* -	 * Do not lock the core DPLL now. Just set it up. -	 * Core DPLL will be locked after setting up EMIF -	 * using the FREQ_UPDATE method(freq_update_core()) -	 */ -	do_setup_dpll(&prcm->cm_clkmode_dpll_core, params, DPLL_NO_LOCK); -	/* Set the ratios for CORE_CLK, L3_CLK, L4_CLK */ -	temp = (CLKSEL_CORE_X2_DIV_1 << CLKSEL_CORE_SHIFT) | -	    (CLKSEL_L3_CORE_DIV_2 << CLKSEL_L3_SHIFT) | -	    (CLKSEL_L4_L3_DIV_2 << CLKSEL_L4_SHIFT); -	writel(temp, &prcm->cm_clksel_core); -	debug("Core DPLL configured\n"); - -	/* lock PER dpll */ -	do_setup_dpll(&prcm->cm_clkmode_dpll_per, -			&per_dpll_params_1536mhz[sysclk_ind], DPLL_LOCK); -	debug("PER DPLL locked\n"); - -	/* MPU dpll */ -	configure_mpu_dpll(); +	u32 sysclk_ind = get_sys_clk_index(); +	return &usb_dpll_params_1920mhz[sysclk_ind];  } -static void setup_non_essential_dplls(void) +const struct dpll_params *get_abe_dpll_params(void)  { -	u32 sys_clk_khz, abe_ref_clk; -	u32 sysclk_ind, sd_div, num, den; -	const struct dpll_params *params; - -	sysclk_ind = get_sys_clk_index(); -	sys_clk_khz = get_sys_clk_freq() / 1000; - -	/* IVA */ -	clrsetbits_le32(&prcm->cm_bypclk_dpll_iva, -		CM_BYPCLK_DPLL_IVA_CLKSEL_MASK, DPLL_IVA_CLKSEL_CORE_X2_DIV_2); - -	do_setup_dpll(&prcm->cm_clkmode_dpll_iva, -			&iva_dpll_params_1862mhz[sysclk_ind], DPLL_LOCK); - -	/* -	 * USB: -	 * USB dpll is J-type. Need to set DPLL_SD_DIV for jitter correction -	 * DPLL_SD_DIV = CEILING ([DPLL_MULT/(DPLL_DIV+1)]* CLKINP / 250) -	 *      - where CLKINP is sys_clk in MHz -	 * Use CLKINP in KHz and adjust the denominator accordingly so -	 * that we have enough accuracy and at the same time no overflow -	 */ -	params = &usb_dpll_params_1920mhz[sysclk_ind]; -	num = params->m * sys_clk_khz; -	den = (params->n + 1) * 250 * 1000; -	num += den - 1; -	sd_div = num / den; -	clrsetbits_le32(&prcm->cm_clksel_dpll_usb, -			CM_CLKSEL_DPLL_DPLL_SD_DIV_MASK, -			sd_div << CM_CLKSEL_DPLL_DPLL_SD_DIV_SHIFT); - -	/* Now setup the dpll with the regular function */ -	do_setup_dpll(&prcm->cm_clkmode_dpll_usb, params, DPLL_LOCK); - -#ifdef CONFIG_SYS_OMAP4_ABE_SYSCK -	params = &abe_dpll_params_sysclk_196608khz[sysclk_ind]; -	abe_ref_clk = CM_ABE_PLL_REF_CLKSEL_CLKSEL_SYSCLK; +#ifdef CONFIG_SYS_OMAP_ABE_SYSCK +	u32 sysclk_ind = get_sys_clk_index(); +	return &abe_dpll_params_sysclk_196608khz[sysclk_ind];  #else -	params = &abe_dpll_params_32k_196608khz; -	abe_ref_clk = CM_ABE_PLL_REF_CLKSEL_CLKSEL_32KCLK; -	/* -	 * We need to enable some additional options to achieve -	 * 196.608MHz from 32768 Hz -	 */ -	setbits_le32(&prcm->cm_clkmode_dpll_abe, -			CM_CLKMODE_DPLL_DRIFTGUARD_EN_MASK| -			CM_CLKMODE_DPLL_RELOCK_RAMP_EN_MASK| -			CM_CLKMODE_DPLL_LPMODE_EN_MASK| -			CM_CLKMODE_DPLL_REGM4XEN_MASK); -	/* Spend 4 REFCLK cycles at each stage */ -	clrsetbits_le32(&prcm->cm_clkmode_dpll_abe, -			CM_CLKMODE_DPLL_RAMP_RATE_MASK, -			1 << CM_CLKMODE_DPLL_RAMP_RATE_SHIFT); +	return &abe_dpll_params_32k_196608khz;  #endif - -	/* Select the right reference clk */ -	clrsetbits_le32(&prcm->cm_abe_pll_ref_clksel, -			CM_ABE_PLL_REF_CLKSEL_CLKSEL_MASK, -			abe_ref_clk << CM_ABE_PLL_REF_CLKSEL_CLKSEL_SHIFT); -	/* Lock the dpll */ -	do_setup_dpll(&prcm->cm_clkmode_dpll_abe, params, DPLL_LOCK); -} - -static void do_scale_tps62361(u32 reg, u32 volt_mv) -{ -	u32 temp, step; - -	step = volt_mv - TPS62361_BASE_VOLT_MV; -	step /= 10; - -	/* -	 * Select SET1 in TPS62361: -	 * VSEL1 is grounded on board. So the following selects -	 * VSEL1 = 0 and VSEL0 = 1 -	 */ -	gpio_direction_output(TPS62361_VSEL0_GPIO, 0); -	gpio_set_value(TPS62361_VSEL0_GPIO, 1); - -	temp = TPS62361_I2C_SLAVE_ADDR | -	    (reg << PRM_VC_VAL_BYPASS_REGADDR_SHIFT) | -	    (step << PRM_VC_VAL_BYPASS_DATA_SHIFT) | -	    PRM_VC_VAL_BYPASS_VALID_BIT; -	debug("do_scale_tps62361: volt - %d step - 0x%x\n", volt_mv, step); - -	writel(temp, &prcm->prm_vc_val_bypass); -	if (!wait_on_value(PRM_VC_VAL_BYPASS_VALID_BIT, 0, -				&prcm->prm_vc_val_bypass, LDELAY)) { -		puts("Scaling voltage failed for vdd_mpu from TPS\n"); -	} -} - -static void do_scale_vcore(u32 vcore_reg, u32 volt_mv) -{ -	u32 temp, offset_code; -	u32 step = 12660; /* 12.66 mV represented in uV */ -	u32 offset = volt_mv; - -	/* convert to uV for better accuracy in the calculations */ -	offset *= 1000; - -	if (omap_revision() == OMAP4430_ES1_0) -		offset -= PHOENIX_SMPS_BASE_VOLT_STD_MODE_UV; -	else -		offset -= PHOENIX_SMPS_BASE_VOLT_STD_MODE_WITH_OFFSET_UV; - -	offset_code = (offset + step - 1) / step; -	/* The code starts at 1 not 0 */ -	offset_code++; - -	debug("do_scale_vcore: volt - %d offset_code - 0x%x\n", volt_mv, -		offset_code); - -	temp = SMPS_I2C_SLAVE_ADDR | -	    (vcore_reg << PRM_VC_VAL_BYPASS_REGADDR_SHIFT) | -	    (offset_code << PRM_VC_VAL_BYPASS_DATA_SHIFT) | -	    PRM_VC_VAL_BYPASS_VALID_BIT; -	writel(temp, &prcm->prm_vc_val_bypass); -	if (!wait_on_value(PRM_VC_VAL_BYPASS_VALID_BIT, 0, -				&prcm->prm_vc_val_bypass, LDELAY)) { -		printf("Scaling voltage failed for 0x%x\n", vcore_reg); -	}  }  /* @@ -536,32 +271,16 @@ static void do_scale_vcore(u32 vcore_reg, u32 volt_mv)   * enabled in bootloader. Voltage initialization in the kernel will set   * these to the nominal values after enabling Smart-Reflex   */ -static void scale_vcores(void) +void scale_vcores(void)  { -	u32 volt, sys_clk_khz, cycles_hi, cycles_low, temp, omap4_rev; +	u32 volt, omap_rev; -	sys_clk_khz = get_sys_clk_freq() / 1000; +	setup_sri2c(); -	/* -	 * Setup the dedicated I2C controller for Voltage Control -	 * I2C clk - high period 40% low period 60% -	 */ -	cycles_hi = sys_clk_khz * 4 / PRM_VC_I2C_CHANNEL_FREQ_KHZ / 10; -	cycles_low = sys_clk_khz * 6 / PRM_VC_I2C_CHANNEL_FREQ_KHZ / 10; -	/* values to be set in register - less by 5 & 7 respectively */ -	cycles_hi -= 5; -	cycles_low -= 7; -	temp = (cycles_hi << PRM_VC_CFG_I2C_CLK_SCLH_SHIFT) | -	       (cycles_low << PRM_VC_CFG_I2C_CLK_SCLL_SHIFT); -	writel(temp, &prcm->prm_vc_cfg_i2c_clk); - -	/* Disable high speed mode and all advanced features */ -	writel(0x0, &prcm->prm_vc_cfg_i2c_mode); - -	omap4_rev = omap_revision(); +	omap_rev = omap_revision();  	/* TPS - supplies vdd_mpu on 4460 */ -	if (omap4_rev >= OMAP4460_ES1_0) { -		volt = 1430; +	if (omap_rev >= OMAP4460_ES1_0) { +		volt = 1313;  		do_scale_tps62361(TPS62361_REG_ADDR_SET1, volt);  	} @@ -576,8 +295,8 @@ static void scale_vcores(void)  	 *  	 * 4460 : supplies vdd_core  	 */ -	if (omap4_rev < OMAP4460_ES1_0) { -		volt = 1417; +	if (omap_rev < OMAP4460_ES1_0) { +		volt = 1325;  		do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt);  	} else {  		volt = 1200; @@ -593,55 +312,18 @@ static void scale_vcores(void)  	 * 4430 : supplies vdd_core  	 * 4460 : not connected  	 */ -	if (omap4_rev < OMAP4460_ES1_0) { +	if (omap_rev < OMAP4460_ES1_0) {  		volt = 1200;  		do_scale_vcore(SMPS_REG_ADDR_VCORE3, volt);  	}  } -static inline void enable_clock_domain(u32 *const clkctrl_reg, u32 enable_mode) -{ -	clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK, -			enable_mode << CD_CLKCTRL_CLKTRCTRL_SHIFT); -	debug("Enable clock domain - %p\n", clkctrl_reg); -} - -static inline void wait_for_clk_enable(u32 *clkctrl_addr) -{ -	u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED; -	u32 bound = LDELAY; - -	while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) || -		(idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) { - -		clkctrl = readl(clkctrl_addr); -		idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >> -			 MODULE_CLKCTRL_IDLEST_SHIFT; -		if (--bound == 0) { -			printf("Clock enable failed for 0x%p idlest 0x%x\n", -				clkctrl_addr, clkctrl); -			return; -		} -	} -} - -static inline void enable_clock_module(u32 *const clkctrl_addr, u32 enable_mode, -				u32 wait_for_enable) -{ -	clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK, -			enable_mode << MODULE_CLKCTRL_MODULEMODE_SHIFT); -	debug("Enable clock module - %p\n", clkctrl_addr); -	if (wait_for_enable) -		wait_for_clk_enable(clkctrl_addr); -} -  /*   * Enable essential clock domains, modules and   * do some additional special settings needed   */ -static void enable_basic_clocks(void) +void enable_basic_clocks(void)  { -	u32 i, max = 100, wait_for_enable = 1;  	u32 *const clk_domains_essential[] = {  		&prcm->cm_l4per_clkstctrl,  		&prcm->cm_l3init_clkstctrl, @@ -651,30 +333,23 @@ static void enable_basic_clocks(void)  	};  	u32 *const clk_modules_hw_auto_essential[] = { +		&prcm->cm_memif_emif_1_clkctrl, +		&prcm->cm_memif_emif_2_clkctrl, +		&prcm->cm_l4cfg_l4_cfg_clkctrl,  		&prcm->cm_wkup_gpio1_clkctrl,  		&prcm->cm_l4per_gpio2_clkctrl,  		&prcm->cm_l4per_gpio3_clkctrl,  		&prcm->cm_l4per_gpio4_clkctrl,  		&prcm->cm_l4per_gpio5_clkctrl,  		&prcm->cm_l4per_gpio6_clkctrl, -		&prcm->cm_memif_emif_1_clkctrl, -		&prcm->cm_memif_emif_2_clkctrl, -		&prcm->cm_l3init_hsusbotg_clkctrl, -		&prcm->cm_l3init_usbphy_clkctrl, -		&prcm->cm_l4cfg_l4_cfg_clkctrl,  		0  	};  	u32 *const clk_modules_explicit_en_essential[] = { -		&prcm->cm_l4per_gptimer2_clkctrl, +		&prcm->cm_wkup_gptimer1_clkctrl,  		&prcm->cm_l3init_hsmmc1_clkctrl,  		&prcm->cm_l3init_hsmmc2_clkctrl, -		&prcm->cm_l4per_mcspi1_clkctrl, -		&prcm->cm_wkup_gptimer1_clkctrl, -		&prcm->cm_l4per_i2c1_clkctrl, -		&prcm->cm_l4per_i2c2_clkctrl, -		&prcm->cm_l4per_i2c3_clkctrl, -		&prcm->cm_l4per_i2c4_clkctrl, +		&prcm->cm_l4per_gptimer2_clkctrl,  		&prcm->cm_wkup_wdtimer2_clkctrl,  		&prcm->cm_l4per_uart3_clkctrl,  		0 @@ -698,40 +373,45 @@ static void enable_basic_clocks(void)  	setbits_le32(&prcm->cm_l3init_usbphy_clkctrl,  			USBPHY_CLKCTRL_OPTFCLKEN_PHY_48M_MASK); -	/* Put the clock domains in SW_WKUP mode */ -	for (i = 0; (i < max) && clk_domains_essential[i]; i++) { -		enable_clock_domain(clk_domains_essential[i], -				    CD_CLKCTRL_CLKTRCTRL_SW_WKUP); -	} +	do_enable_clocks(clk_domains_essential, +			 clk_modules_hw_auto_essential, +			 clk_modules_explicit_en_essential, +			 1); +} -	/* Clock modules that need to be put in HW_AUTO */ -	for (i = 0; (i < max) && clk_modules_hw_auto_essential[i]; i++) { -		enable_clock_module(clk_modules_hw_auto_essential[i], -				    MODULE_CLKCTRL_MODULEMODE_HW_AUTO, -				    wait_for_enable); +void enable_basic_uboot_clocks(void) +{ +	u32 *const clk_domains_essential[] = { +		0 +	}; + +	u32 *const clk_modules_hw_auto_essential[] = { +		&prcm->cm_l3init_hsusbotg_clkctrl, +		&prcm->cm_l3init_usbphy_clkctrl, +		0  	}; -	/* Clock modules that need to be put in SW_EXPLICIT_EN mode */ -	for (i = 0; (i < max) && clk_modules_explicit_en_essential[i]; i++) { -		enable_clock_module(clk_modules_explicit_en_essential[i], -				    MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN, -				    wait_for_enable); +	u32 *const clk_modules_explicit_en_essential[] = { +		&prcm->cm_l4per_mcspi1_clkctrl, +		&prcm->cm_l4per_i2c1_clkctrl, +		&prcm->cm_l4per_i2c2_clkctrl, +		&prcm->cm_l4per_i2c3_clkctrl, +		&prcm->cm_l4per_i2c4_clkctrl, +		0  	}; -	/* Put the clock domains in HW_AUTO mode now */ -	for (i = 0; (i < max) && clk_domains_essential[i]; i++) { -		enable_clock_domain(clk_domains_essential[i], -				    CD_CLKCTRL_CLKTRCTRL_HW_AUTO); -	} +	do_enable_clocks(clk_domains_essential, +			 clk_modules_hw_auto_essential, +			 clk_modules_explicit_en_essential, +			 1);  }  /*   * Enable non-essential clock domains, modules and   * do some additional special settings needed   */ -static void enable_non_essential_clocks(void) +void enable_non_essential_clocks(void)  { -	u32 i, max = 100, wait_for_enable = 0;  	u32 *const clk_domains_non_essential[] = {  		&prcm->cm_mpu_m3_clkstctrl,  		&prcm->cm_ivahd_clkstctrl, @@ -807,135 +487,13 @@ static void enable_non_essential_clocks(void)  	/* Enable all optional functional clocks of DSS */  	setbits_le32(&prcm->cm_dss_dss_clkctrl, DSS_CLKCTRL_OPTFCLKEN_MASK); - -	/* Put the clock domains in SW_WKUP mode */ -	for (i = 0; (i < max) && clk_domains_non_essential[i]; i++) { -		enable_clock_domain(clk_domains_non_essential[i], -				    CD_CLKCTRL_CLKTRCTRL_SW_WKUP); -	} - -	/* Clock modules that need to be put in HW_AUTO */ -	for (i = 0; (i < max) && clk_modules_hw_auto_non_essential[i]; i++) { -		enable_clock_module(clk_modules_hw_auto_non_essential[i], -				    MODULE_CLKCTRL_MODULEMODE_HW_AUTO, -				    wait_for_enable); -	}; - -	/* Clock modules that need to be put in SW_EXPLICIT_EN mode */ -	for (i = 0; (i < max) && clk_modules_explicit_en_non_essential[i]; -	     i++) { -		enable_clock_module(clk_modules_explicit_en_non_essential[i], -				    MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN, -				    wait_for_enable); -	}; - -	/* Put the clock domains in HW_AUTO mode now */ -	for (i = 0; (i < max) && clk_domains_non_essential[i]; i++) { -		enable_clock_domain(clk_domains_non_essential[i], -				    CD_CLKCTRL_CLKTRCTRL_HW_AUTO); -	} +	do_enable_clocks(clk_domains_non_essential, +			 clk_modules_hw_auto_non_essential, +			 clk_modules_explicit_en_non_essential, +			 0);  	/* Put camera module in no sleep mode */  	clrsetbits_le32(&prcm->cm_cam_clkstctrl, MODULE_CLKCTRL_MODULEMODE_MASK,  			CD_CLKCTRL_CLKTRCTRL_NO_SLEEP <<  			MODULE_CLKCTRL_MODULEMODE_SHIFT);  } - - -void freq_update_core(void) -{ -	u32 freq_config1 = 0; -	const struct dpll_params *core_dpll_params; - -	core_dpll_params = get_core_dpll_params(); -	/* Put EMIF clock domain in sw wakeup mode */ -	enable_clock_domain(&prcm->cm_memif_clkstctrl, -				CD_CLKCTRL_CLKTRCTRL_SW_WKUP); -	wait_for_clk_enable(&prcm->cm_memif_emif_1_clkctrl); -	wait_for_clk_enable(&prcm->cm_memif_emif_2_clkctrl); - -	freq_config1 = SHADOW_FREQ_CONFIG1_FREQ_UPDATE_MASK | -	    SHADOW_FREQ_CONFIG1_DLL_RESET_MASK; - -	freq_config1 |= (DPLL_EN_LOCK << SHADOW_FREQ_CONFIG1_DPLL_EN_SHIFT) & -				SHADOW_FREQ_CONFIG1_DPLL_EN_MASK; - -	freq_config1 |= (core_dpll_params->m2 << -			SHADOW_FREQ_CONFIG1_M2_DIV_SHIFT) & -			SHADOW_FREQ_CONFIG1_M2_DIV_MASK; - -	writel(freq_config1, &prcm->cm_shadow_freq_config1); -	if (!wait_on_value(SHADOW_FREQ_CONFIG1_FREQ_UPDATE_MASK, 0, -				&prcm->cm_shadow_freq_config1, LDELAY)) { -		puts("FREQ UPDATE procedure failed!!"); -		hang(); -	} - -	/* Put EMIF clock domain back in hw auto mode */ -	enable_clock_domain(&prcm->cm_memif_clkstctrl, -				CD_CLKCTRL_CLKTRCTRL_HW_AUTO); -	wait_for_clk_enable(&prcm->cm_memif_emif_1_clkctrl); -	wait_for_clk_enable(&prcm->cm_memif_emif_2_clkctrl); -} - -void bypass_dpll(u32 *const base) -{ -	do_bypass_dpll(base); -	wait_for_bypass(base); -} - -void lock_dpll(u32 *const base) -{ -	do_lock_dpll(base); -	wait_for_lock(base); -} - -void setup_clocks_for_console(void) -{ -	/* Do not add any spl_debug prints in this function */ -	clrsetbits_le32(&prcm->cm_l4per_clkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK, -			CD_CLKCTRL_CLKTRCTRL_SW_WKUP << -			CD_CLKCTRL_CLKTRCTRL_SHIFT); - -	/* Enable all UARTs - console will be on one of them */ -	clrsetbits_le32(&prcm->cm_l4per_uart1_clkctrl, -			MODULE_CLKCTRL_MODULEMODE_MASK, -			MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << -			MODULE_CLKCTRL_MODULEMODE_SHIFT); - -	clrsetbits_le32(&prcm->cm_l4per_uart2_clkctrl, -			MODULE_CLKCTRL_MODULEMODE_MASK, -			MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << -			MODULE_CLKCTRL_MODULEMODE_SHIFT); - -	clrsetbits_le32(&prcm->cm_l4per_uart3_clkctrl, -			MODULE_CLKCTRL_MODULEMODE_MASK, -			MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << -			MODULE_CLKCTRL_MODULEMODE_SHIFT); - -	clrsetbits_le32(&prcm->cm_l4per_uart3_clkctrl, -			MODULE_CLKCTRL_MODULEMODE_MASK, -			MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << -			MODULE_CLKCTRL_MODULEMODE_SHIFT); - -	clrsetbits_le32(&prcm->cm_l4per_clkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK, -			CD_CLKCTRL_CLKTRCTRL_HW_AUTO << -			CD_CLKCTRL_CLKTRCTRL_SHIFT); -} - -void prcm_init(void) -{ -	switch (omap4_hw_init_context()) { -	case OMAP_INIT_CONTEXT_SPL: -	case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR: -	case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH: -		enable_basic_clocks(); -		scale_vcores(); -		setup_dplls(); -		setup_non_essential_dplls(); -		enable_non_essential_clocks(); -		break; -	default: -		break; -	} -} diff --git a/arch/arm/cpu/armv7/omap4/emif.c b/arch/arm/cpu/armv7/omap4/emif.c index 988b2050f..ca4823dd7 100644 --- a/arch/arm/cpu/armv7/omap4/emif.c +++ b/arch/arm/cpu/armv7/omap4/emif.c @@ -26,645 +26,15 @@   */  #include <common.h> -#include <asm/arch/emif.h> -#include <asm/arch/clocks.h> +#include <asm/emif.h>  #include <asm/arch/sys_proto.h> -#include <asm/omap_common.h>  #include <asm/utils.h> -static inline u32 emif_num(u32 base) -{ -	if (base == OMAP44XX_EMIF1) -		return 1; -	else if (base == OMAP44XX_EMIF2) -		return 2; -	else -		return 0; -} - -static inline u32 get_mr(u32 base, u32 cs, u32 mr_addr) -{ -	u32 mr; -	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; - -	mr_addr |= cs << OMAP44XX_REG_CS_SHIFT; -	writel(mr_addr, &emif->emif_lpddr2_mode_reg_cfg); -	if (omap_revision() == OMAP4430_ES2_0) -		mr = readl(&emif->emif_lpddr2_mode_reg_data_es2); -	else -		mr = readl(&emif->emif_lpddr2_mode_reg_data); -	debug("get_mr: EMIF%d cs %d mr %08x val 0x%x\n", emif_num(base), -	      cs, mr_addr, mr); -	return mr; -} - -static inline void set_mr(u32 base, u32 cs, u32 mr_addr, u32 mr_val) -{ -	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; - -	mr_addr |= cs << OMAP44XX_REG_CS_SHIFT; -	writel(mr_addr, &emif->emif_lpddr2_mode_reg_cfg); -	writel(mr_val, &emif->emif_lpddr2_mode_reg_data); -} - -void emif_reset_phy(u32 base) -{ -	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; -	u32 iodft; - -	iodft = readl(&emif->emif_iodft_tlgc); -	iodft |= OMAP44XX_REG_RESET_PHY_MASK; -	writel(iodft, &emif->emif_iodft_tlgc); -} - -static void do_lpddr2_init(u32 base, u32 cs) -{ -	u32 mr_addr; - -	/* Wait till device auto initialization is complete */ -	while (get_mr(base, cs, LPDDR2_MR0) & LPDDR2_MR0_DAI_MASK) -		; -	set_mr(base, cs, LPDDR2_MR10, MR10_ZQ_ZQINIT); -	/* -	 * tZQINIT = 1 us -	 * Enough loops assuming a maximum of 2GHz -	 */ -	sdelay(2000); -	set_mr(base, cs, LPDDR2_MR1, MR1_BL_8_BT_SEQ_WRAP_EN_NWR_3); -	set_mr(base, cs, LPDDR2_MR16, MR16_REF_FULL_ARRAY); -	/* -	 * Enable refresh along with writing MR2 -	 * Encoding of RL in MR2 is (RL - 2) -	 */ -	mr_addr = LPDDR2_MR2 | OMAP44XX_REG_REFRESH_EN_MASK; -	set_mr(base, cs, mr_addr, RL_FINAL - 2); -} - -static void lpddr2_init(u32 base, const struct emif_regs *regs) -{ -	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; - -	/* Not NVM */ -	clrbits_le32(&emif->emif_lpddr2_nvm_config, OMAP44XX_REG_CS1NVMEN_MASK); - -	/* -	 * Keep REG_INITREF_DIS = 1 to prevent re-initialization of SDRAM -	 * when EMIF_SDRAM_CONFIG register is written -	 */ -	setbits_le32(&emif->emif_sdram_ref_ctrl, OMAP44XX_REG_INITREF_DIS_MASK); - -	/* -	 * Set the SDRAM_CONFIG and PHY_CTRL for the -	 * un-locked frequency & default RL -	 */ -	writel(regs->sdram_config_init, &emif->emif_sdram_config); -	writel(regs->emif_ddr_phy_ctlr_1_init, &emif->emif_ddr_phy_ctrl_1); - -	do_lpddr2_init(base, CS0); -	if (regs->sdram_config & OMAP44XX_REG_EBANK_MASK) -		do_lpddr2_init(base, CS1); - -	writel(regs->sdram_config, &emif->emif_sdram_config); -	writel(regs->emif_ddr_phy_ctlr_1, &emif->emif_ddr_phy_ctrl_1); - -	/* Enable refresh now */ -	clrbits_le32(&emif->emif_sdram_ref_ctrl, OMAP44XX_REG_INITREF_DIS_MASK); - -} - -static void emif_update_timings(u32 base, const struct emif_regs *regs) -{ -	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; - -	writel(regs->ref_ctrl, &emif->emif_sdram_ref_ctrl_shdw); -	writel(regs->sdram_tim1, &emif->emif_sdram_tim_1_shdw); -	writel(regs->sdram_tim2, &emif->emif_sdram_tim_2_shdw); -	writel(regs->sdram_tim3, &emif->emif_sdram_tim_3_shdw); -	if (omap_revision() == OMAP4430_ES1_0) { -		/* ES1 bug EMIF should be in force idle during freq_update */ -		writel(0, &emif->emif_pwr_mgmt_ctrl); -	} else { -		writel(EMIF_PWR_MGMT_CTRL, &emif->emif_pwr_mgmt_ctrl); -		writel(EMIF_PWR_MGMT_CTRL_SHDW, &emif->emif_pwr_mgmt_ctrl_shdw); -	} -	writel(regs->read_idle_ctrl, &emif->emif_read_idlectrl_shdw); -	writel(regs->zq_config, &emif->emif_zq_config); -	writel(regs->temp_alert_config, &emif->emif_temp_alert_config); -	writel(regs->emif_ddr_phy_ctlr_1, &emif->emif_ddr_phy_ctrl_1_shdw); - -	if (omap_revision() >= OMAP4460_ES1_0) { -		writel(EMIF_L3_CONFIG_VAL_SYS_10_MPU_3_LL_0, -			&emif->emif_l3_config); -	} else { -		writel(EMIF_L3_CONFIG_VAL_SYS_10_LL_0, -			&emif->emif_l3_config); -	} -} -  #ifndef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS -#define print_timing_reg(reg) debug(#reg" - 0x%08x\n", (reg)) - -static u32 *const T_num = (u32 *)OMAP4_SRAM_SCRATCH_EMIF_T_NUM; -static u32 *const T_den = (u32 *)OMAP4_SRAM_SCRATCH_EMIF_T_DEN; -static u32 *const emif_sizes = (u32 *)OMAP4_SRAM_SCRATCH_EMIF_SIZE; - -/* - * Organization and refresh requirements for LPDDR2 devices of different - * types and densities. Derived from JESD209-2 section 2.4 - */ -const struct lpddr2_addressing addressing_table[] = { -	/* Banks tREFIx10     rowx32,rowx16      colx32,colx16	density */ -	{BANKS4, T_REFI_15_6, {ROW_12, ROW_12}, {COL_7, COL_8} },/*64M */ -	{BANKS4, T_REFI_15_6, {ROW_12, ROW_12}, {COL_8, COL_9} },/*128M */ -	{BANKS4, T_REFI_7_8, {ROW_13, ROW_13}, {COL_8, COL_9} },/*256M */ -	{BANKS4, T_REFI_7_8, {ROW_13, ROW_13}, {COL_9, COL_10} },/*512M */ -	{BANKS8, T_REFI_7_8, {ROW_13, ROW_13}, {COL_9, COL_10} },/*1GS4 */ -	{BANKS8, T_REFI_3_9, {ROW_14, ROW_14}, {COL_9, COL_10} },/*2GS4 */ -	{BANKS8, T_REFI_3_9, {ROW_14, ROW_14}, {COL_10, COL_11} },/*4G */ -	{BANKS8, T_REFI_3_9, {ROW_15, ROW_15}, {COL_10, COL_11} },/*8G */ -	{BANKS4, T_REFI_7_8, {ROW_14, ROW_14}, {COL_9, COL_10} },/*1GS2 */ -	{BANKS4, T_REFI_3_9, {ROW_15, ROW_15}, {COL_9, COL_10} },/*2GS2 */ -}; - -static const u32 lpddr2_density_2_size_in_mbytes[] = { -	8,			/* 64Mb */ -	16,			/* 128Mb */ -	32,			/* 256Mb */ -	64,			/* 512Mb */ -	128,			/* 1Gb   */ -	256,			/* 2Gb   */ -	512,			/* 4Gb   */ -	1024,			/* 8Gb   */ -	2048,			/* 16Gb  */ -	4096			/* 32Gb  */ -}; - -/* - * Calculate the period of DDR clock from frequency value and set the - * denominator and numerator in global variables for easy access later - */ -static void set_ddr_clk_period(u32 freq) -{ -	/* -	 * period = 1/freq -	 * period_in_ns = 10^9/freq -	 */ -	*T_num = 1000000000; -	*T_den = freq; -	cancel_out(T_num, T_den, 200); - -} - -/* - * Convert time in nano seconds to number of cycles of DDR clock - */ -static inline u32 ns_2_cycles(u32 ns) -{ -	return ((ns * (*T_den)) + (*T_num) - 1) / (*T_num); -} - -/* - * ns_2_cycles with the difference that the time passed is 2 times the actual - * value(to avoid fractions). The cycles returned is for the original value of - * the timing parameter - */ -static inline u32 ns_x2_2_cycles(u32 ns) -{ -	return ((ns * (*T_den)) + (*T_num) * 2 - 1) / ((*T_num) * 2); -} - -/* - * Find addressing table index based on the device's type(S2 or S4) and - * density - */ -s8 addressing_table_index(u8 type, u8 density, u8 width) -{ -	u8 index; -	if ((density > LPDDR2_DENSITY_8Gb) || (width == LPDDR2_IO_WIDTH_8)) -		return -1; - -	/* -	 * Look at the way ADDR_TABLE_INDEX* values have been defined -	 * in emif.h compared to LPDDR2_DENSITY_* values -	 * The table is layed out in the increasing order of density -	 * (ignoring type). The exceptions 1GS2 and 2GS2 have been placed -	 * at the end -	 */ -	if ((type == LPDDR2_TYPE_S2) && (density == LPDDR2_DENSITY_1Gb)) -		index = ADDR_TABLE_INDEX1GS2; -	else if ((type == LPDDR2_TYPE_S2) && (density == LPDDR2_DENSITY_2Gb)) -		index = ADDR_TABLE_INDEX2GS2; -	else -		index = density; - -	debug("emif: addressing table index %d\n", index); - -	return index; -} - -/* - * Find the the right timing table from the array of timing - * tables of the device using DDR clock frequency - */ -static const struct lpddr2_ac_timings *get_timings_table(const struct -			lpddr2_ac_timings const *const *device_timings, -			u32 freq) -{ -	u32 i, temp, freq_nearest; -	const struct lpddr2_ac_timings *timings = 0; - -	emif_assert(freq <= MAX_LPDDR2_FREQ); -	emif_assert(device_timings); - -	/* -	 * Start with the maximum allowed frequency - that is always safe -	 */ -	freq_nearest = MAX_LPDDR2_FREQ; -	/* -	 * Find the timings table that has the max frequency value: -	 *   i.  Above or equal to the DDR frequency - safe -	 *   ii. The lowest that satisfies condition (i) - optimal -	 */ -	for (i = 0; (i < MAX_NUM_SPEEDBINS) && device_timings[i]; i++) { -		temp = device_timings[i]->max_freq; -		if ((temp >= freq) && (temp <= freq_nearest)) { -			freq_nearest = temp; -			timings = device_timings[i]; -		} -	} -	debug("emif: timings table: %d\n", freq_nearest); -	return timings; -} - -/* - * Finds the value of emif_sdram_config_reg - * All parameters are programmed based on the device on CS0. - * If there is a device on CS1, it will be same as that on CS0 or - * it will be NVM. We don't support NVM yet. - * If cs1_device pointer is NULL it is assumed that there is no device - * on CS1 - */ -static u32 get_sdram_config_reg(const struct lpddr2_device_details *cs0_device, -				const struct lpddr2_device_details *cs1_device, -				const struct lpddr2_addressing *addressing, -				u8 RL) -{ -	u32 config_reg = 0; - -	config_reg |=  (cs0_device->type + 4) << OMAP44XX_REG_SDRAM_TYPE_SHIFT; -	config_reg |=  EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING << -			OMAP44XX_REG_IBANK_POS_SHIFT; - -	config_reg |= cs0_device->io_width << OMAP44XX_REG_NARROW_MODE_SHIFT; - -	config_reg |= RL << OMAP44XX_REG_CL_SHIFT; - -	config_reg |= addressing->row_sz[cs0_device->io_width] << -			OMAP44XX_REG_ROWSIZE_SHIFT; - -	config_reg |= addressing->num_banks << OMAP44XX_REG_IBANK_SHIFT; - -	config_reg |= (cs1_device ? EBANK_CS1_EN : EBANK_CS1_DIS) << -			OMAP44XX_REG_EBANK_SHIFT; - -	config_reg |= addressing->col_sz[cs0_device->io_width] << -			OMAP44XX_REG_PAGESIZE_SHIFT; - -	return config_reg; -} - -static u32 get_sdram_ref_ctrl(u32 freq, -			      const struct lpddr2_addressing *addressing) -{ -	u32 ref_ctrl = 0, val = 0, freq_khz; -	freq_khz = freq / 1000; -	/* -	 * refresh rate to be set is 'tREFI * freq in MHz -	 * division by 10000 to account for khz and x10 in t_REFI_us_x10 -	 */ -	val = addressing->t_REFI_us_x10 * freq_khz / 10000; -	ref_ctrl |= val << OMAP44XX_REG_REFRESH_RATE_SHIFT; - -	return ref_ctrl; -} - -static u32 get_sdram_tim_1_reg(const struct lpddr2_ac_timings *timings, -			       const struct lpddr2_min_tck *min_tck, -			       const struct lpddr2_addressing *addressing) -{ -	u32 tim1 = 0, val = 0; -	val = max(min_tck->tWTR, ns_x2_2_cycles(timings->tWTRx2)) - 1; -	tim1 |= val << OMAP44XX_REG_T_WTR_SHIFT; - -	if (addressing->num_banks == BANKS8) -		val = (timings->tFAW * (*T_den) + 4 * (*T_num) - 1) / -							(4 * (*T_num)) - 1; -	else -		val = max(min_tck->tRRD, ns_2_cycles(timings->tRRD)) - 1; - -	tim1 |= val << OMAP44XX_REG_T_RRD_SHIFT; - -	val = ns_2_cycles(timings->tRASmin + timings->tRPab) - 1; -	tim1 |= val << OMAP44XX_REG_T_RC_SHIFT; - -	val = max(min_tck->tRAS_MIN, ns_2_cycles(timings->tRASmin)) - 1; -	tim1 |= val << OMAP44XX_REG_T_RAS_SHIFT; - -	val = max(min_tck->tWR, ns_2_cycles(timings->tWR)) - 1; -	tim1 |= val << OMAP44XX_REG_T_WR_SHIFT; - -	val = max(min_tck->tRCD, ns_2_cycles(timings->tRCD)) - 1; -	tim1 |= val << OMAP44XX_REG_T_RCD_SHIFT; - -	val = max(min_tck->tRP_AB, ns_2_cycles(timings->tRPab)) - 1; -	tim1 |= val << OMAP44XX_REG_T_RP_SHIFT; - -	return tim1; -} - -static u32 get_sdram_tim_2_reg(const struct lpddr2_ac_timings *timings, -			       const struct lpddr2_min_tck *min_tck) -{ -	u32 tim2 = 0, val = 0; -	val = max(min_tck->tCKE, timings->tCKE) - 1; -	tim2 |= val << OMAP44XX_REG_T_CKE_SHIFT; - -	val = max(min_tck->tRTP, ns_x2_2_cycles(timings->tRTPx2)) - 1; -	tim2 |= val << OMAP44XX_REG_T_RTP_SHIFT; - -	/* -	 * tXSRD = tRFCab + 10 ns. XSRD and XSNR should have the -	 * same value -	 */ -	val = ns_2_cycles(timings->tXSR) - 1; -	tim2 |= val << OMAP44XX_REG_T_XSRD_SHIFT; -	tim2 |= val << OMAP44XX_REG_T_XSNR_SHIFT; - -	val = max(min_tck->tXP, ns_x2_2_cycles(timings->tXPx2)) - 1; -	tim2 |= val << OMAP44XX_REG_T_XP_SHIFT; - -	return tim2; -} - -static u32 get_sdram_tim_3_reg(const struct lpddr2_ac_timings *timings, -			       const struct lpddr2_min_tck *min_tck, -			       const struct lpddr2_addressing *addressing) -{ -	u32 tim3 = 0, val = 0; -	val = min(timings->tRASmax * 10 / addressing->t_REFI_us_x10 - 1, 0xF); -	tim3 |= val << OMAP44XX_REG_T_RAS_MAX_SHIFT; - -	val = ns_2_cycles(timings->tRFCab) - 1; -	tim3 |= val << OMAP44XX_REG_T_RFC_SHIFT; - -	val = ns_x2_2_cycles(timings->tDQSCKMAXx2) - 1; -	tim3 |= val << OMAP44XX_REG_T_TDQSCKMAX_SHIFT; - -	val = ns_2_cycles(timings->tZQCS) - 1; -	tim3 |= val << OMAP44XX_REG_ZQ_ZQCS_SHIFT; - -	val = max(min_tck->tCKESR, ns_2_cycles(timings->tCKESR)) - 1; -	tim3 |= val << OMAP44XX_REG_T_CKESR_SHIFT; - -	return tim3; -} - -static u32 get_zq_config_reg(const struct lpddr2_device_details *cs1_device, -			     const struct lpddr2_addressing *addressing, -			     u8 volt_ramp) -{ -	u32 zq = 0, val = 0; -	if (volt_ramp) -		val = -		    EMIF_ZQCS_INTERVAL_DVFS_IN_US * 10 / -		    addressing->t_REFI_us_x10; -	else -		val = -		    EMIF_ZQCS_INTERVAL_NORMAL_IN_US * 10 / -		    addressing->t_REFI_us_x10; -	zq |= val << OMAP44XX_REG_ZQ_REFINTERVAL_SHIFT; - -	zq |= (REG_ZQ_ZQCL_MULT - 1) << OMAP44XX_REG_ZQ_ZQCL_MULT_SHIFT; - -	zq |= (REG_ZQ_ZQINIT_MULT - 1) << OMAP44XX_REG_ZQ_ZQINIT_MULT_SHIFT; - -	zq |= REG_ZQ_SFEXITEN_ENABLE << OMAP44XX_REG_ZQ_SFEXITEN_SHIFT; - -	/* -	 * Assuming that two chipselects have a single calibration resistor -	 * If there are indeed two calibration resistors, then this flag should -	 * be enabled to take advantage of dual calibration feature. -	 * This data should ideally come from board files. But considering -	 * that none of the boards today have calibration resistors per CS, -	 * it would be an unnecessary overhead. -	 */ -	zq |= REG_ZQ_DUALCALEN_DISABLE << OMAP44XX_REG_ZQ_DUALCALEN_SHIFT; - -	zq |= REG_ZQ_CS0EN_ENABLE << OMAP44XX_REG_ZQ_CS0EN_SHIFT; - -	zq |= (cs1_device ? 1 : 0) << OMAP44XX_REG_ZQ_CS1EN_SHIFT; - -	return zq; -} - -static u32 get_temp_alert_config(const struct lpddr2_device_details *cs1_device, -				 const struct lpddr2_addressing *addressing, -				 u8 is_derated) -{ -	u32 alert = 0, interval; -	interval = -	    TEMP_ALERT_POLL_INTERVAL_MS * 10000 / addressing->t_REFI_us_x10; -	if (is_derated) -		interval *= 4; -	alert |= interval << OMAP44XX_REG_TA_REFINTERVAL_SHIFT; - -	alert |= TEMP_ALERT_CONFIG_DEVCT_1 << OMAP44XX_REG_TA_DEVCNT_SHIFT; - -	alert |= TEMP_ALERT_CONFIG_DEVWDT_32 << OMAP44XX_REG_TA_DEVWDT_SHIFT; - -	alert |= 1 << OMAP44XX_REG_TA_SFEXITEN_SHIFT; - -	alert |= 1 << OMAP44XX_REG_TA_CS0EN_SHIFT; - -	alert |= (cs1_device ? 1 : 0) << OMAP44XX_REG_TA_CS1EN_SHIFT; - -	return alert; -} - -static u32 get_read_idle_ctrl_reg(u8 volt_ramp) -{ -	u32 idle = 0, val = 0; -	if (volt_ramp) -		val = ns_2_cycles(READ_IDLE_INTERVAL_DVFS) / 64 - 1; -	else -		/*Maximum value in normal conditions - suggested by hw team */ -		val = 0x1FF; -	idle |= val << OMAP44XX_REG_READ_IDLE_INTERVAL_SHIFT; - -	idle |= EMIF_REG_READ_IDLE_LEN_VAL << OMAP44XX_REG_READ_IDLE_LEN_SHIFT; - -	return idle; -} - -static u32 get_ddr_phy_ctrl_1(u32 freq, u8 RL) -{ -	u32 phy = 0, val = 0; - -	phy |= (RL + 2) << OMAP44XX_REG_READ_LATENCY_SHIFT; - -	if (freq <= 100000000) -		val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS; -	else if (freq <= 200000000) -		val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ; -	else -		val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ; -	phy |= val << OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_SHIFT; - -	/* Other fields are constant magic values. Hardcode them together */ -	phy |= EMIF_DDR_PHY_CTRL_1_BASE_VAL << -		OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHIFT; - -	return phy; -} - -static u32 get_emif_mem_size(struct emif_device_details *devices) -{ -	u32 size_mbytes = 0, temp; - -	if (!devices) -		return 0; - -	if (devices->cs0_device_details) { -		temp = devices->cs0_device_details->density; -		size_mbytes += lpddr2_density_2_size_in_mbytes[temp]; -	} - -	if (devices->cs1_device_details) { -		temp = devices->cs1_device_details->density; -		size_mbytes += lpddr2_density_2_size_in_mbytes[temp]; -	} -	/* convert to bytes */ -	return size_mbytes << 20; -} - -/* Gets the encoding corresponding to a given DMM section size */ -u32 get_dmm_section_size_map(u32 section_size) -{ -	/* -	 * Section size mapping: -	 * 0x0: 16-MiB section -	 * 0x1: 32-MiB section -	 * 0x2: 64-MiB section -	 * 0x3: 128-MiB section -	 * 0x4: 256-MiB section -	 * 0x5: 512-MiB section -	 * 0x6: 1-GiB section -	 * 0x7: 2-GiB section -	 */ -	section_size >>= 24; /* divide by 16 MB */ -	return log_2_n_round_down(section_size); -} - -static void emif_calculate_regs( -		const struct emif_device_details *emif_dev_details, -		u32 freq, struct emif_regs *regs) -{ -	u32 temp, sys_freq; -	const struct lpddr2_addressing *addressing; -	const struct lpddr2_ac_timings *timings; -	const struct lpddr2_min_tck *min_tck; -	const struct lpddr2_device_details *cs0_dev_details = -					emif_dev_details->cs0_device_details; -	const struct lpddr2_device_details *cs1_dev_details = -					emif_dev_details->cs1_device_details; -	const struct lpddr2_device_timings *cs0_dev_timings = -					emif_dev_details->cs0_device_timings; - -	emif_assert(emif_dev_details); -	emif_assert(regs); -	/* -	 * You can not have a device on CS1 without one on CS0 -	 * So configuring EMIF without a device on CS0 doesn't -	 * make sense -	 */ -	emif_assert(cs0_dev_details); -	emif_assert(cs0_dev_details->type != LPDDR2_TYPE_NVM); -	/* -	 * If there is a device on CS1 it should be same type as CS0 -	 * (or NVM. But NVM is not supported in this driver yet) -	 */ -	emif_assert((cs1_dev_details == NULL) || -		    (cs1_dev_details->type == LPDDR2_TYPE_NVM) || -		    (cs0_dev_details->type == cs1_dev_details->type)); -	emif_assert(freq <= MAX_LPDDR2_FREQ); - -	set_ddr_clk_period(freq); - -	/* -	 * The device on CS0 is used for all timing calculations -	 * There is only one set of registers for timings per EMIF. So, if the -	 * second CS(CS1) has a device, it should have the same timings as the -	 * device on CS0 -	 */ -	timings = get_timings_table(cs0_dev_timings->ac_timings, freq); -	emif_assert(timings); -	min_tck = cs0_dev_timings->min_tck; - -	temp = addressing_table_index(cs0_dev_details->type, -				      cs0_dev_details->density, -				      cs0_dev_details->io_width); - -	emif_assert((temp >= 0)); -	addressing = &(addressing_table[temp]); -	emif_assert(addressing); - -	sys_freq = get_sys_clk_freq(); - -	regs->sdram_config_init = get_sdram_config_reg(cs0_dev_details, -							cs1_dev_details, -							addressing, RL_BOOT); - -	regs->sdram_config = get_sdram_config_reg(cs0_dev_details, -						cs1_dev_details, -						addressing, RL_FINAL); - -	regs->ref_ctrl = get_sdram_ref_ctrl(freq, addressing); - -	regs->sdram_tim1 = get_sdram_tim_1_reg(timings, min_tck, addressing); - -	regs->sdram_tim2 = get_sdram_tim_2_reg(timings, min_tck); - -	regs->sdram_tim3 = get_sdram_tim_3_reg(timings, min_tck, addressing); - -	regs->read_idle_ctrl = get_read_idle_ctrl_reg(LPDDR2_VOLTAGE_STABLE); - -	regs->temp_alert_config = -	    get_temp_alert_config(cs1_dev_details, addressing, 0); - -	regs->zq_config = get_zq_config_reg(cs1_dev_details, addressing, -					    LPDDR2_VOLTAGE_STABLE); - -	regs->emif_ddr_phy_ctlr_1_init = -			get_ddr_phy_ctrl_1(sys_freq / 2, RL_BOOT); - -	regs->emif_ddr_phy_ctlr_1 = -			get_ddr_phy_ctrl_1(freq, RL_FINAL); - -	regs->freq = freq; - -	print_timing_reg(regs->sdram_config_init); -	print_timing_reg(regs->sdram_config); -	print_timing_reg(regs->ref_ctrl); -	print_timing_reg(regs->sdram_tim1); -	print_timing_reg(regs->sdram_tim2); -	print_timing_reg(regs->sdram_tim3); -	print_timing_reg(regs->read_idle_ctrl); -	print_timing_reg(regs->temp_alert_config); -	print_timing_reg(regs->zq_config); -	print_timing_reg(regs->emif_ddr_phy_ctlr_1); -	print_timing_reg(regs->emif_ddr_phy_ctlr_1_init); -} -#endif /* CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS */ +u32 *const T_num = (u32 *)OMAP4_SRAM_SCRATCH_EMIF_T_NUM; +u32 *const T_den = (u32 *)OMAP4_SRAM_SCRATCH_EMIF_T_DEN; +u32 *const emif_sizes = (u32 *)OMAP4_SRAM_SCRATCH_EMIF_SIZE; +#endif  #ifdef CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS  /* Base AC Timing values specified by JESD209-2 for 400MHz operation */ @@ -691,30 +61,6 @@ static const struct lpddr2_ac_timings timings_jedec_400_mhz = {  	.tFAW = 50  }; -/* Base AC Timing values specified by JESD209-2 for 333 MHz operation */ -static const struct lpddr2_ac_timings timings_jedec_333_mhz = { -	.max_freq = 333000000, -	.RL = 5, -	.tRPab = 21, -	.tRCD = 18, -	.tWR = 15, -	.tRASmin = 42, -	.tRRD = 10, -	.tWTRx2 = 15, -	.tXSR = 140, -	.tXPx2 = 15, -	.tRFCab = 130, -	.tRTPx2 = 15, -	.tCKE = 3, -	.tCKESR = 15, -	.tZQCS = 90, -	.tZQCL = 360, -	.tZQINIT = 1000, -	.tDQSCKMAXx2 = 11, -	.tRASmax = 70, -	.tFAW = 50 -}; -  /* Base AC Timing values specified by JESD209-2 for 200 MHz operation */  static const struct lpddr2_ac_timings timings_jedec_200_mhz = {  	.max_freq = 200000000, @@ -764,7 +110,6 @@ static const struct lpddr2_min_tck min_tck_jedec = {  static const struct lpddr2_ac_timings const*  			jedec_ac_timings[MAX_NUM_SPEEDBINS] = {  	&timings_jedec_200_mhz, -	&timings_jedec_333_mhz,  	&timings_jedec_400_mhz  }; @@ -782,473 +127,3 @@ void emif_get_device_timings(u32 emif_nr,  	*cs1_device_timings = &jedec_default_timings;  }  #endif /* CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS */ - -#ifdef CONFIG_SYS_AUTOMATIC_SDRAM_DETECTION -const char *get_lpddr2_type(u8 type_id) -{ -	switch (type_id) { -	case LPDDR2_TYPE_S4: -		return "LPDDR2-S4"; -	case LPDDR2_TYPE_S2: -		return "LPDDR2-S2"; -	default: -		return NULL; -	} -} - -const char *get_lpddr2_io_width(u8 width_id) -{ -	switch (width_id) { -	case LPDDR2_IO_WIDTH_8: -		return "x8"; -	case LPDDR2_IO_WIDTH_16: -		return "x16"; -	case LPDDR2_IO_WIDTH_32: -		return "x32"; -	default: -		return NULL; -	} -} - -const char *get_lpddr2_manufacturer(u32 manufacturer) -{ -	switch (manufacturer) { -	case LPDDR2_MANUFACTURER_SAMSUNG: -		return "Samsung"; -	case LPDDR2_MANUFACTURER_QIMONDA: -		return "Qimonda"; -	case LPDDR2_MANUFACTURER_ELPIDA: -		return "Elpida"; -	case LPDDR2_MANUFACTURER_ETRON: -		return "Etron"; -	case LPDDR2_MANUFACTURER_NANYA: -		return "Nanya"; -	case LPDDR2_MANUFACTURER_HYNIX: -		return "Hynix"; -	case LPDDR2_MANUFACTURER_MOSEL: -		return "Mosel"; -	case LPDDR2_MANUFACTURER_WINBOND: -		return "Winbond"; -	case LPDDR2_MANUFACTURER_ESMT: -		return "ESMT"; -	case LPDDR2_MANUFACTURER_SPANSION: -		return "Spansion"; -	case LPDDR2_MANUFACTURER_SST: -		return "SST"; -	case LPDDR2_MANUFACTURER_ZMOS: -		return "ZMOS"; -	case LPDDR2_MANUFACTURER_INTEL: -		return "Intel"; -	case LPDDR2_MANUFACTURER_NUMONYX: -		return "Numonyx"; -	case LPDDR2_MANUFACTURER_MICRON: -		return "Micron"; -	default: -		return NULL; -	} -} - -static void display_sdram_details(u32 emif_nr, u32 cs, -				  struct lpddr2_device_details *device) -{ -	const char *mfg_str; -	const char *type_str; -	char density_str[10]; -	u32 density; - -	debug("EMIF%d CS%d\t", emif_nr, cs); - -	if (!device) { -		debug("None\n"); -		return; -	} - -	mfg_str = get_lpddr2_manufacturer(device->manufacturer); -	type_str = get_lpddr2_type(device->type); - -	density = lpddr2_density_2_size_in_mbytes[device->density]; -	if ((density / 1024 * 1024) == density) { -		density /= 1024; -		sprintf(density_str, "%d GB", density); -	} else -		sprintf(density_str, "%d MB", density); -	if (mfg_str && type_str) -		debug("%s\t\t%s\t%s\n", mfg_str, type_str, density_str); -} - -static u8 is_lpddr2_sdram_present(u32 base, u32 cs, -				  struct lpddr2_device_details *lpddr2_device) -{ -	u32 mr = 0, temp; - -	mr = get_mr(base, cs, LPDDR2_MR0); -	if (mr > 0xFF) { -		/* Mode register value bigger than 8 bit */ -		return 0; -	} - -	temp = (mr & LPDDR2_MR0_DI_MASK) >> LPDDR2_MR0_DI_SHIFT; -	if (temp) { -		/* Not SDRAM */ -		return 0; -	} -	temp = (mr & LPDDR2_MR0_DNVI_MASK) >> LPDDR2_MR0_DNVI_SHIFT; - -	if (temp) { -		/* DNV supported - But DNV is only supported for NVM */ -		return 0; -	} - -	mr = get_mr(base, cs, LPDDR2_MR4); -	if (mr > 0xFF) { -		/* Mode register value bigger than 8 bit */ -		return 0; -	} - -	mr = get_mr(base, cs, LPDDR2_MR5); -	if (mr >= 0xFF) { -		/* Mode register value bigger than 8 bit */ -		return 0; -	} - -	if (!get_lpddr2_manufacturer(mr)) { -		/* Manufacturer not identified */ -		return 0; -	} -	lpddr2_device->manufacturer = mr; - -	mr = get_mr(base, cs, LPDDR2_MR6); -	if (mr >= 0xFF) { -		/* Mode register value bigger than 8 bit */ -		return 0; -	} - -	mr = get_mr(base, cs, LPDDR2_MR7); -	if (mr >= 0xFF) { -		/* Mode register value bigger than 8 bit */ -		return 0; -	} - -	mr = get_mr(base, cs, LPDDR2_MR8); -	if (mr >= 0xFF) { -		/* Mode register value bigger than 8 bit */ -		return 0; -	} - -	temp = (mr & MR8_TYPE_MASK) >> MR8_TYPE_SHIFT; -	if (!get_lpddr2_type(temp)) { -		/* Not SDRAM */ -		return 0; -	} -	lpddr2_device->type = temp; - -	temp = (mr & MR8_DENSITY_MASK) >> MR8_DENSITY_SHIFT; -	if (temp > LPDDR2_DENSITY_32Gb) { -		/* Density not supported */ -		return 0; -	} -	lpddr2_device->density = temp; - -	temp = (mr & MR8_IO_WIDTH_MASK) >> MR8_IO_WIDTH_SHIFT; -	if (!get_lpddr2_io_width(temp)) { -		/* IO width unsupported value */ -		return 0; -	} -	lpddr2_device->io_width = temp; - -	/* -	 * If all the above tests pass we should -	 * have a device on this chip-select -	 */ -	return 1; -} - -struct lpddr2_device_details *emif_get_device_details(u32 emif_nr, u8 cs, -			struct lpddr2_device_details *lpddr2_dev_details) -{ -	u32 phy; -	u32 base = (emif_nr == 1) ? OMAP44XX_EMIF1 : OMAP44XX_EMIF2; -	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; - -	if (!lpddr2_dev_details) -		return NULL; - -	/* Do the minimum init for mode register accesses */ -	if (!running_from_sdram()) { -		phy = get_ddr_phy_ctrl_1(get_sys_clk_freq() / 2, RL_BOOT); -		writel(phy, &emif->emif_ddr_phy_ctrl_1); -	} - -	if (!(is_lpddr2_sdram_present(base, cs, lpddr2_dev_details))) -		return NULL; - -	display_sdram_details(emif_num(base), cs, lpddr2_dev_details); - -	return lpddr2_dev_details; -} -#endif /* CONFIG_SYS_AUTOMATIC_SDRAM_DETECTION */ - -static void do_sdram_init(u32 base) -{ -	const struct emif_regs *regs; -	u32 in_sdram, emif_nr; - -	debug(">>do_sdram_init() %x\n", base); - -	in_sdram = running_from_sdram(); -	emif_nr = (base == OMAP44XX_EMIF1) ? 1 : 2; - -#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS -	emif_get_reg_dump(emif_nr, ®s); -	if (!regs) { -		debug("EMIF: reg dump not provided\n"); -		return; -	} -#else -	/* -	 * The user has not provided the register values. We need to -	 * calculate it based on the timings and the DDR frequency -	 */ -	struct emif_device_details dev_details; -	struct emif_regs calculated_regs; - -	/* -	 * Get device details: -	 * - Discovered if CONFIG_SYS_AUTOMATIC_SDRAM_DETECTION is set -	 * - Obtained from user otherwise -	 */ -	struct lpddr2_device_details cs0_dev_details, cs1_dev_details; -	emif_reset_phy(base); -	dev_details.cs0_device_details = emif_get_device_details(base, CS0, -						&cs0_dev_details); -	dev_details.cs1_device_details = emif_get_device_details(base, CS1, -						&cs1_dev_details); -	emif_reset_phy(base); - -	/* Return if no devices on this EMIF */ -	if (!dev_details.cs0_device_details && -	    !dev_details.cs1_device_details) { -		emif_sizes[emif_nr - 1] = 0; -		return; -	} - -	if (!in_sdram) -		emif_sizes[emif_nr - 1] = get_emif_mem_size(&dev_details); - -	/* -	 * Get device timings: -	 * - Default timings specified by JESD209-2 if -	 *   CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS is set -	 * - Obtained from user otherwise -	 */ -	emif_get_device_timings(emif_nr, &dev_details.cs0_device_timings, -				&dev_details.cs1_device_timings); - -	/* Calculate the register values */ -	emif_calculate_regs(&dev_details, omap4_ddr_clk(), &calculated_regs); -	regs = &calculated_regs; -#endif /* CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS */ - -	/* -	 * Initializing the LPDDR2 device can not happen from SDRAM. -	 * Changing the timing registers in EMIF can happen(going from one -	 * OPP to another) -	 */ -	if (!in_sdram) -		lpddr2_init(base, regs); - -	/* Write to the shadow registers */ -	emif_update_timings(base, regs); - -	debug("<<do_sdram_init() %x\n", base); -} - -static void emif_post_init_config(u32 base) -{ -	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; -	u32 omap4_rev = omap_revision(); - -	/* reset phy on ES2.0 */ -	if (omap4_rev == OMAP4430_ES2_0) -		emif_reset_phy(base); - -	/* Put EMIF back in smart idle on ES1.0 */ -	if (omap4_rev == OMAP4430_ES1_0) -		writel(0x80000000, &emif->emif_pwr_mgmt_ctrl); -} - -static void dmm_init(u32 base) -{ -	const struct dmm_lisa_map_regs *lisa_map_regs; - -#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS -	emif_get_dmm_regs(&lisa_map_regs); -#else -	u32 emif1_size, emif2_size, mapped_size, section_map = 0; -	u32 section_cnt, sys_addr; -	struct dmm_lisa_map_regs lis_map_regs_calculated = {0}; - -	mapped_size = 0; -	section_cnt = 3; -	sys_addr = CONFIG_SYS_SDRAM_BASE; -	emif1_size = emif_sizes[0]; -	emif2_size = emif_sizes[1]; -	debug("emif1_size 0x%x emif2_size 0x%x\n", emif1_size, emif2_size); - -	if (!emif1_size && !emif2_size) -		return; - -	/* symmetric interleaved section */ -	if (emif1_size && emif2_size) { -		mapped_size = min(emif1_size, emif2_size); -		section_map = DMM_LISA_MAP_INTERLEAVED_BASE_VAL; -		section_map |= 0 << OMAP44XX_SDRC_ADDR_SHIFT; -		/* only MSB */ -		section_map |= (sys_addr >> 24) << -				OMAP44XX_SYS_ADDR_SHIFT; -		section_map |= get_dmm_section_size_map(mapped_size * 2) -				<< OMAP44XX_SYS_SIZE_SHIFT; -		lis_map_regs_calculated.dmm_lisa_map_3 = section_map; -		emif1_size -= mapped_size; -		emif2_size -= mapped_size; -		sys_addr += (mapped_size * 2); -		section_cnt--; -	} - -	/* -	 * Single EMIF section(we can have a maximum of 1 single EMIF -	 * section- either EMIF1 or EMIF2 or none, but not both) -	 */ -	if (emif1_size) { -		section_map = DMM_LISA_MAP_EMIF1_ONLY_BASE_VAL; -		section_map |= get_dmm_section_size_map(emif1_size) -				<< OMAP44XX_SYS_SIZE_SHIFT; -		/* only MSB */ -		section_map |= (mapped_size >> 24) << -				OMAP44XX_SDRC_ADDR_SHIFT; -		/* only MSB */ -		section_map |= (sys_addr >> 24) << OMAP44XX_SYS_ADDR_SHIFT; -		section_cnt--; -	} -	if (emif2_size) { -		section_map = DMM_LISA_MAP_EMIF2_ONLY_BASE_VAL; -		section_map |= get_dmm_section_size_map(emif2_size) << -				OMAP44XX_SYS_SIZE_SHIFT; -		/* only MSB */ -		section_map |= mapped_size >> 24 << OMAP44XX_SDRC_ADDR_SHIFT; -		/* only MSB */ -		section_map |= sys_addr >> 24 << OMAP44XX_SYS_ADDR_SHIFT; -		section_cnt--; -	} - -	if (section_cnt == 2) { -		/* Only 1 section - either symmetric or single EMIF */ -		lis_map_regs_calculated.dmm_lisa_map_3 = section_map; -		lis_map_regs_calculated.dmm_lisa_map_2 = 0; -		lis_map_regs_calculated.dmm_lisa_map_1 = 0; -	} else { -		/* 2 sections - 1 symmetric, 1 single EMIF */ -		lis_map_regs_calculated.dmm_lisa_map_2 = section_map; -		lis_map_regs_calculated.dmm_lisa_map_1 = 0; -	} - -	/* TRAP for invalid TILER mappings in section 0 */ -	lis_map_regs_calculated.dmm_lisa_map_0 = DMM_LISA_MAP_0_INVAL_ADDR_TRAP; - -	lisa_map_regs = &lis_map_regs_calculated; -#endif -	struct dmm_lisa_map_regs *hw_lisa_map_regs = -	    (struct dmm_lisa_map_regs *)base; - -	writel(0, &hw_lisa_map_regs->dmm_lisa_map_3); -	writel(0, &hw_lisa_map_regs->dmm_lisa_map_2); -	writel(0, &hw_lisa_map_regs->dmm_lisa_map_1); -	writel(0, &hw_lisa_map_regs->dmm_lisa_map_0); - -	writel(lisa_map_regs->dmm_lisa_map_3, -		&hw_lisa_map_regs->dmm_lisa_map_3); -	writel(lisa_map_regs->dmm_lisa_map_2, -		&hw_lisa_map_regs->dmm_lisa_map_2); -	writel(lisa_map_regs->dmm_lisa_map_1, -		&hw_lisa_map_regs->dmm_lisa_map_1); -	writel(lisa_map_regs->dmm_lisa_map_0, -		&hw_lisa_map_regs->dmm_lisa_map_0); - -	if (omap_revision() >= OMAP4460_ES1_0) { -		hw_lisa_map_regs = -		    (struct dmm_lisa_map_regs *)OMAP44XX_MA_LISA_MAP_BASE; - -		writel(lisa_map_regs->dmm_lisa_map_3, -			&hw_lisa_map_regs->dmm_lisa_map_3); -		writel(lisa_map_regs->dmm_lisa_map_2, -			&hw_lisa_map_regs->dmm_lisa_map_2); -		writel(lisa_map_regs->dmm_lisa_map_1, -			&hw_lisa_map_regs->dmm_lisa_map_1); -		writel(lisa_map_regs->dmm_lisa_map_0, -			&hw_lisa_map_regs->dmm_lisa_map_0); -	} -} - -/* - * SDRAM initialization: - * SDRAM initialization has two parts: - * 1. Configuring the SDRAM device - * 2. Update the AC timings related parameters in the EMIF module - * (1) should be done only once and should not be done while we are - * running from SDRAM. - * (2) can and should be done more than once if OPP changes. - * Particularly, this may be needed when we boot without SPL and - * and using Configuration Header(CH). ROM code supports only at 50% OPP - * at boot (low power boot). So u-boot has to switch to OPP100 and update - * the frequency. So, - * Doing (1) and (2) makes sense - first time initialization - * Doing (2) and not (1) makes sense - OPP change (when using CH) - * Doing (1) and not (2) doen't make sense - * See do_sdram_init() for the details - */ -void sdram_init(void) -{ -	u32 in_sdram, size_prog, size_detect; - -	debug(">>sdram_init()\n"); - -	if (omap4_hw_init_context() == OMAP_INIT_CONTEXT_UBOOT_AFTER_SPL) -		return; - -	in_sdram = running_from_sdram(); -	debug("in_sdram = %d\n", in_sdram); - -	if (!in_sdram) { -		bypass_dpll(&prcm->cm_clkmode_dpll_core); -	} - -	do_sdram_init(OMAP44XX_EMIF1); -	do_sdram_init(OMAP44XX_EMIF2); - -	if (!in_sdram) { -		dmm_init(OMAP44XX_DMM_LISA_MAP_BASE); -		emif_post_init_config(OMAP44XX_EMIF1); -		emif_post_init_config(OMAP44XX_EMIF2); - -	} - -	/* for the shadow registers to take effect */ -	freq_update_core(); - -	/* Do some testing after the init */ -	if (!in_sdram) { -		size_prog = omap4_sdram_size(); -		size_detect = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, -						size_prog); -		/* Compare with the size programmed */ -		if (size_detect != size_prog) { -			printf("SDRAM: identified size not same as expected" -				" size identified: %x expected: %x\n", -				size_detect, -				size_prog); -		} else -			debug("get_ram_size() successful"); -	} - -	debug("<<sdram_init()\n"); -} diff --git a/arch/arm/cpu/armv7/omap4/hwinit.c b/arch/arm/cpu/armv7/omap4/hwinit.c new file mode 100644 index 000000000..52c9b1901 --- /dev/null +++ b/arch/arm/cpu/armv7/omap4/hwinit.c @@ -0,0 +1,167 @@ +/* + * + * Common functions for OMAP4 based boards + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * + * Author : + *	Aneesh V	<aneesh@ti.com> + *	Steve Sakoman	<steve@sakoman.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/armv7.h> +#include <asm/arch/cpu.h> +#include <asm/arch/sys_proto.h> +#include <asm/sizes.h> +#include <asm/emif.h> +#include <asm/arch/gpio.h> + +DECLARE_GLOBAL_DATA_PTR; + +u32 *const omap4_revision = (u32 *)OMAP4_SRAM_SCRATCH_OMAP4_REV; + +static const struct gpio_bank gpio_bank_44xx[6] = { +	{ (void *)OMAP44XX_GPIO1_BASE, METHOD_GPIO_24XX }, +	{ (void *)OMAP44XX_GPIO2_BASE, METHOD_GPIO_24XX }, +	{ (void *)OMAP44XX_GPIO3_BASE, METHOD_GPIO_24XX }, +	{ (void *)OMAP44XX_GPIO4_BASE, METHOD_GPIO_24XX }, +	{ (void *)OMAP44XX_GPIO5_BASE, METHOD_GPIO_24XX }, +	{ (void *)OMAP44XX_GPIO6_BASE, METHOD_GPIO_24XX }, +}; + +const struct gpio_bank *const omap_gpio_bank = gpio_bank_44xx; + +#ifdef CONFIG_SPL_BUILD +/* + * Some tuning of IOs for optimal power and performance + */ +void do_io_settings(void) +{ +	u32 lpddr2io; +	struct control_lpddr2io_regs *lpddr2io_regs = +		(struct control_lpddr2io_regs *)LPDDR2_IO_REGS_BASE; +	struct omap4_sys_ctrl_regs *const ctrl = +		(struct omap4_sys_ctrl_regs *)SYSCTRL_GENERAL_CORE_BASE; + +	u32 omap4_rev = omap_revision(); + +	if (omap4_rev == OMAP4430_ES1_0) +		lpddr2io = CONTROL_LPDDR2IO_SLEW_125PS_DRV8_PULL_DOWN; +	else if (omap4_rev == OMAP4430_ES2_0) +		lpddr2io = CONTROL_LPDDR2IO_SLEW_325PS_DRV8_GATE_KEEPER; +	else +		lpddr2io = CONTROL_LPDDR2IO_SLEW_315PS_DRV12_PULL_DOWN; + +	/* EMIF1 */ +	writel(lpddr2io, &lpddr2io_regs->control_lpddr2io1_0); +	writel(lpddr2io, &lpddr2io_regs->control_lpddr2io1_1); +	/* No pull for GR10 as per hw team's recommendation */ +	writel(lpddr2io & ~LPDDR2IO_GR10_WD_MASK, +		&lpddr2io_regs->control_lpddr2io1_2); +	writel(CONTROL_LPDDR2IO_3_VAL, &lpddr2io_regs->control_lpddr2io1_3); + +	/* EMIF2 */ +	writel(lpddr2io, &lpddr2io_regs->control_lpddr2io2_0); +	writel(lpddr2io, &lpddr2io_regs->control_lpddr2io2_1); +	/* No pull for GR10 as per hw team's recommendation */ +	writel(lpddr2io & ~LPDDR2IO_GR10_WD_MASK, +		&lpddr2io_regs->control_lpddr2io2_2); +	writel(CONTROL_LPDDR2IO_3_VAL, &lpddr2io_regs->control_lpddr2io2_3); + +	/* +	 * Some of these settings (TRIM values) come from eFuse and are +	 * in turn programmed in the eFuse at manufacturing time after +	 * calibration of the device. Do the software over-ride only if +	 * the device is not correctly trimmed +	 */ +	if (!(readl(&ctrl->control_std_fuse_opp_bgap) & 0xFFFF)) { + +		writel(LDOSRAM_VOLT_CTRL_OVERRIDE, +			&ctrl->control_ldosram_iva_voltage_ctrl); + +		writel(LDOSRAM_VOLT_CTRL_OVERRIDE, +			&ctrl->control_ldosram_mpu_voltage_ctrl); + +		writel(LDOSRAM_VOLT_CTRL_OVERRIDE, +			&ctrl->control_ldosram_core_voltage_ctrl); +	} + +	if (!readl(&ctrl->control_efuse_1)) +		writel(CONTROL_EFUSE_1_OVERRIDE, &ctrl->control_efuse_1); + +	if (!readl(&ctrl->control_efuse_2)) +		writel(CONTROL_EFUSE_2_OVERRIDE, &ctrl->control_efuse_2); +} +#endif + +void init_omap_revision(void) +{ +	/* +	 * For some of the ES2/ES1 boards ID_CODE is not reliable: +	 * Also, ES1 and ES2 have different ARM revisions +	 * So use ARM revision for identification +	 */ +	unsigned int arm_rev = cortex_rev(); + +	switch (arm_rev) { +	case MIDR_CORTEX_A9_R0P1: +		*omap4_revision = OMAP4430_ES1_0; +		break; +	case MIDR_CORTEX_A9_R1P2: +		switch (readl(CONTROL_ID_CODE)) { +		case OMAP4_CONTROL_ID_CODE_ES2_0: +			*omap4_revision = OMAP4430_ES2_0; +			break; +		case OMAP4_CONTROL_ID_CODE_ES2_1: +			*omap4_revision = OMAP4430_ES2_1; +			break; +		case OMAP4_CONTROL_ID_CODE_ES2_2: +			*omap4_revision = OMAP4430_ES2_2; +			break; +		default: +			*omap4_revision = OMAP4430_ES2_0; +			break; +		} +		break; +	case MIDR_CORTEX_A9_R1P3: +		*omap4_revision = OMAP4430_ES2_3; +		break; +	case MIDR_CORTEX_A9_R2P10: +		*omap4_revision = OMAP4460_ES1_0; +		break; +	default: +		*omap4_revision = OMAP4430_SILICON_ID_INVALID; +		break; +	} +} + +#ifndef CONFIG_SYS_L2CACHE_OFF +void v7_outer_cache_enable(void) +{ +	set_pl310_ctrl_reg(1); +} + +void v7_outer_cache_disable(void) +{ +	set_pl310_ctrl_reg(0); +} +#endif diff --git a/arch/arm/cpu/armv7/omap4/omap4_mux_data.h b/arch/arm/cpu/armv7/omap4/omap4_mux_data.h deleted file mode 100644 index b9403910c..000000000 --- a/arch/arm/cpu/armv7/omap4/omap4_mux_data.h +++ /dev/null @@ -1,83 +0,0 @@ - /* - * (C) Copyright 2010 - * Texas Instruments Incorporated, <www.ti.com> - * - *	Balaji Krishnamoorthy	<balajitk@ti.com> - *	Aneesh V		<aneesh@ti.com> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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 - */ -#ifndef _OMAP4_MUX_DATA_H_ -#define _OMAP4_MUX_DATA_H_ - -#include <asm/arch/mux_omap4.h> - -const struct pad_conf_entry core_padconf_array_essential[] = { - -{GPMC_AD0, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat0 */ -{GPMC_AD1, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat1 */ -{GPMC_AD2, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat2 */ -{GPMC_AD3, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat3 */ -{GPMC_AD4, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat4 */ -{GPMC_AD5, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat5 */ -{GPMC_AD6, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat6 */ -{GPMC_AD7, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat7 */ -{GPMC_NOE, (PTU | IEN | OFF_EN | OFF_OUT_PTD | M1)},	 /* sdmmc2_clk */ -{GPMC_NWE, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_cmd */ -{SDMMC1_CLK, (PTU | OFF_EN | OFF_OUT_PTD | M0)},	 /* sdmmc1_clk */ -{SDMMC1_CMD, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_cmd */ -{SDMMC1_DAT0, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat0 */ -{SDMMC1_DAT1, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat1 */ -{SDMMC1_DAT2, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat2 */ -{SDMMC1_DAT3, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat3 */ -{SDMMC1_DAT4, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat4 */ -{SDMMC1_DAT5, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat5 */ -{SDMMC1_DAT6, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat6 */ -{SDMMC1_DAT7, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat7 */ -{I2C1_SCL, (PTU | IEN | M0)},				/* i2c1_scl */ -{I2C1_SDA, (PTU | IEN | M0)},				/* i2c1_sda */ -{I2C2_SCL, (PTU | IEN | M0)},				/* i2c2_scl */ -{I2C2_SDA, (PTU | IEN | M0)},				/* i2c2_sda */ -{I2C3_SCL, (PTU | IEN | M0)},				/* i2c3_scl */ -{I2C3_SDA, (PTU | IEN | M0)},				/* i2c3_sda */ -{I2C4_SCL, (PTU | IEN | M0)},				/* i2c4_scl */ -{I2C4_SDA, (PTU | IEN | M0)},				/* i2c4_sda */ -{UART3_CTS_RCTX, (PTU | IEN | M0)},			/* uart3_tx */ -{UART3_RTS_SD, (M0)},					/* uart3_rts_sd */ -{UART3_RX_IRRX, (IEN | M0)},				/* uart3_rx */ -{UART3_TX_IRTX, (M0)}					/* uart3_tx */ - -}; - -const struct pad_conf_entry wkup_padconf_array_essential[] = { - -{PAD1_SR_SCL, (PTU | IEN | M0)}, /* sr_scl */ -{PAD0_SR_SDA, (PTU | IEN | M0)}, /* sr_sda */ -{PAD1_SYS_32K, (IEN | M0)}	 /* sys_32k */ - -}; - -const struct pad_conf_entry wkup_padconf_array_essential_4460[] = { - -{PAD1_FREF_CLK4_REQ, (M3)},	 /* gpio_wk7, TPS */ - -}; - - -#endif  /* _OMAP4_MUX_DATA_H_ */ diff --git a/arch/arm/cpu/armv7/omap4/sdram_elpida.c b/arch/arm/cpu/armv7/omap4/sdram_elpida.c index edc5326c3..a5ec7d3dc 100644 --- a/arch/arm/cpu/armv7/omap4/sdram_elpida.c +++ b/arch/arm/cpu/armv7/omap4/sdram_elpida.c @@ -26,7 +26,7 @@   * MA 02111-1307 USA   */ -#include <asm/arch/emif.h> +#include <asm/emif.h>  #include <asm/arch/sys_proto.h>  /* diff --git a/arch/arm/cpu/armv7/omap4/sys_info.c b/arch/arm/cpu/armv7/omap4/sys_info.c deleted file mode 100644 index b9e57659f..000000000 --- a/arch/arm/cpu/armv7/omap4/sys_info.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * (C) Copyright 2010 - * Texas Instruments, <www.ti.com> - * - * Author : - *	Aneesh V	<aneesh@ti.com> - *	Steve Sakoman	<steve@sakoman.com> - * - * 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 <common.h> -#include <asm/arch/sys_proto.h> - -/* - *  get_device_type(): tell if GP/HS/EMU/TST - */ -u32 get_device_type(void) -{ -	return 0; -} - -/* - * get_board_rev() - get board revision - */ -u32 get_board_rev(void) -{ -	return 0x20; -} - -/* - * Print CPU information - */ -int print_cpuinfo(void) -{ - -	puts("CPU  : OMAP4430\n"); - -	return 0; -} diff --git a/arch/arm/cpu/armv7/omap5/Makefile b/arch/arm/cpu/armv7/omap5/Makefile new file mode 100644 index 000000000..f8ca9ac36 --- /dev/null +++ b/arch/arm/cpu/armv7/omap5/Makefile @@ -0,0 +1,48 @@ +# +# (C) Copyright 2000-2010 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 $(TOPDIR)/config.mk + +LIB	=  $(obj)lib$(SOC).o + +COBJS	+= hwinit.o +COBJS	+= clocks.o +COBJS	+= emif.o +COBJS	+= sdram_elpida.o + +SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS)) + +all:	 $(obj).depend $(LIB) + +$(LIB):	$(OBJS) +	$(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/armv7/omap5/clocks.c b/arch/arm/cpu/armv7/omap5/clocks.c new file mode 100644 index 000000000..dd882a202 --- /dev/null +++ b/arch/arm/cpu/armv7/omap5/clocks.c @@ -0,0 +1,432 @@ +/* + * + * Clock initialization for OMAP5 + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * + * Aneesh V <aneesh@ti.com> + * Sricharan R <r.sricharan@ti.com> + * + * Based on previous work by: + *	Santosh Shilimkar <santosh.shilimkar@ti.com> + *	Rajendra Nayak <rnayak@ti.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/omap_common.h> +#include <asm/arch/clocks.h> +#include <asm/arch/sys_proto.h> +#include <asm/utils.h> +#include <asm/omap_gpio.h> + +#ifndef CONFIG_SPL_BUILD +/* + * printing to console doesn't work unless + * this code is executed from SPL + */ +#define printf(fmt, args...) +#define puts(s) +#endif + +struct omap5_prcm_regs *const prcm = (struct omap5_prcm_regs *)0x4A004100; + +const u32 sys_clk_array[8] = { +	12000000,	       /* 12 MHz */ +	0,		       /* NA */ +	16800000,	       /* 16.8 MHz */ +	19200000,	       /* 19.2 MHz */ +	26000000,	       /* 26 MHz */ +	0,		       /* NA */ +	38400000,	       /* 38.4 MHz */ +}; + +static const struct dpll_params mpu_dpll_params_1_5ghz[NUM_SYS_CLKS] = { +	{125, 0, 1, -1, -1, -1, -1, -1, -1, -1},	/* 12 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 13 MHz   */ +	{625, 6, 1, -1, -1, -1, -1, -1, -1, -1},	/* 16.8 MHz */ +	{625, 7, 1, -1, -1, -1, -1, -1, -1, -1},	/* 19.2 MHz */ +	{750, 12, 1, -1, -1, -1, -1, -1, -1, -1},	/* 26 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 27 MHz   */ +	{625, 15, 1, -1, -1, -1, -1, -1, -1, -1}	/* 38.4 MHz */ +}; + +static const struct dpll_params mpu_dpll_params_2ghz[NUM_SYS_CLKS] = { +	{500, 2, 1, -1, -1, -1, -1, -1, -1, -1},	/* 12 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 13 MHz   */ +	{2024, 16, 1, -1, -1, -1, -1, -1, -1, -1},	/* 16.8 MHz */ +	{625, 5, 1, -1, -1, -1, -1, -1, -1, -1},	/* 19.2 MHz */ +	{1000, 12, 1, -1, -1, -1, -1, -1, -1, -1},	/* 26 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 27 MHz   */ +	{625, 11, 1, -1, -1, -1, -1, -1, -1, -1}	/* 38.4 MHz */ +}; + +static const struct dpll_params mpu_dpll_params_1100mhz[NUM_SYS_CLKS] = { +	{275, 2, 1, -1, -1, -1, -1, -1, -1, -1},	/* 12 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 13 MHz   */ +	{1375, 20, 1, -1, -1, -1, -1, -1, -1, -1},	/* 16.8 MHz */ +	{1375, 23, 1, -1, -1, -1, -1, -1, -1, -1},	/* 19.2 MHz */ +	{550, 12, 1, -1, -1, -1, -1, -1, -1, -1},	/* 26 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 27 MHz   */ +	{1375, 47, 1, -1, -1, -1, -1, -1, -1, -1}	/* 38.4 MHz */ +}; + +static const struct dpll_params mpu_dpll_params_550mhz[NUM_SYS_CLKS] = { +	{275, 2, 2, -1, -1, -1, -1, -1, -1, -1},	/* 12 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 13 MHz   */ +	{1375, 20, 2, -1, -1, -1, -1, -1, -1, -1},	/* 16.8 MHz */ +	{1375, 23, 2, -1, -1, -1, -1, -1, -1, -1},	/* 19.2 MHz */ +	{550, 12, 2, -1, -1, -1, -1, -1, -1, -1},	/* 26 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 27 MHz   */ +	{1375, 47, 2, -1, -1, -1, -1, -1, -1, -1}	/* 38.4 MHz */ +}; + +static const struct dpll_params +			core_dpll_params_2128mhz_ddr532[NUM_SYS_CLKS] = { +	{266, 2, 1, 5, 8, 4, 62, 5, 5, 7},		/* 12 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 13 MHz   */ +	{570, 8, 1, 5, 8, 4, 62, 5, 5, 7},		/* 16.8 MHz */ +	{665, 11, 1, 5, 8, 4, 62, 5, 5, 7},		/* 19.2 MHz */ +	{532, 12, 1, 5, 8, 4, 62, 5, 5, 7},		/* 26 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 27 MHz   */ +	{665, 23, 1, 5, 8, 4, 62, 5, 5, 7}		/* 38.4 MHz */ +}; + +static const struct dpll_params +			core_dpll_params_2128mhz_ddr266[NUM_SYS_CLKS] = { +	{266, 2, 2, 5, 8, 4, 62, 5, 5, 7},		/* 12 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 13 MHz   */ +	{570, 8, 2, 5, 8, 4, 62, 5, 5, 7},		/* 16.8 MHz */ +	{665, 11, 2, 5, 8, 4, 62, 5, 5, 7},		/* 19.2 MHz */ +	{532, 12, 2, 5, 8, 4, 62, 5, 5, 7},		/* 26 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 27 MHz   */ +	{665, 23, 2, 5, 8, 4, 62, 5, 5, 7}		/* 38.4 MHz */ +}; + +static const struct dpll_params per_dpll_params_768mhz[NUM_SYS_CLKS] = { +	{32, 0, 4, 3, 6, 4, -1, 2, -1, -1},		/* 12 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 13 MHz   */ +	{160, 6, 4, 3, 6, 4, -1, 2, -1, -1},		/* 16.8 MHz */ +	{20, 0, 4, 3, 6, 4, -1, 2, -1, -1},		/* 19.2 MHz */ +	{192, 12, 4, 3, 6, 4, -1, 2, -1, -1},		/* 26 MHz   */ +	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 27 MHz   */ +	{10, 0, 4, 3, 6, 4, -1, 2, -1, -1}		/* 38.4 MHz */ +}; + +static const struct dpll_params iva_dpll_params_2330mhz[NUM_SYS_CLKS] = { +	{931, 11, -1, -1, 4, 7, -1, -1},	/* 12 MHz   */ +	{931, 12, -1, -1, 4, 7, -1, -1},	/* 13 MHz   */ +	{665, 11, -1, -1, 4, 7, -1, -1},	/* 16.8 MHz */ +	{727, 14, -1, -1, 4, 7, -1, -1},	/* 19.2 MHz */ +	{931, 25, -1, -1, 4, 7, -1, -1},	/* 26 MHz   */ +	{931, 26, -1, -1, 4, 7, -1, -1},	/* 27 MHz   */ +	{412, 16, -1, -1, 4, 7, -1, -1}		/* 38.4 MHz */ +}; + +/* ABE M & N values with sys_clk as source */ +static const struct dpll_params +		abe_dpll_params_sysclk_196608khz[NUM_SYS_CLKS] = { +	{49, 5, 1, 1, -1, -1, -1, -1},	/* 12 MHz   */ +	{68, 8, 1, 1, -1, -1, -1, -1},	/* 13 MHz   */ +	{35, 5, 1, 1, -1, -1, -1, -1},	/* 16.8 MHz */ +	{46, 8, 1, 1, -1, -1, -1, -1},	/* 19.2 MHz */ +	{34, 8, 1, 1, -1, -1, -1, -1},	/* 26 MHz   */ +	{29, 7, 1, 1, -1, -1, -1, -1},	/* 27 MHz   */ +	{64, 24, 1, 1, -1, -1, -1, -1}	/* 38.4 MHz */ +}; + +/* ABE M & N values with 32K clock as source */ +static const struct dpll_params abe_dpll_params_32k_196608khz = { +	750, 0, 1, 1, -1, -1, -1, -1 +}; + +static const struct dpll_params usb_dpll_params_1920mhz[NUM_SYS_CLKS] = { +	{80, 0, 2, -1, -1, -1, -1, -1},		/* 12 MHz   */ +	{960, 12, 2, -1, -1, -1, -1, -1},	/* 13 MHz   */ +	{400, 6, 2, -1, -1, -1, -1, -1},	/* 16.8 MHz */ +	{50, 0, 2, -1, -1, -1, -1, -1},		/* 19.2 MHz */ +	{480, 12, 2, -1, -1, -1, -1, -1},	/* 26 MHz   */ +	{320, 8, 2, -1, -1, -1, -1, -1},	/* 27 MHz   */ +	{25, 0, 2, -1, -1, -1, -1, -1}		/* 38.4 MHz */ +}; + +void setup_post_dividers(u32 *const base, const struct dpll_params *params) +{ +	struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; + +	/* Setup post-dividers */ +	if (params->m2 >= 0) +		writel(params->m2, &dpll_regs->cm_div_m2_dpll); +	if (params->m3 >= 0) +		writel(params->m3, &dpll_regs->cm_div_m3_dpll); +	if (params->h11 >= 0) +		writel(params->h11, &dpll_regs->cm_div_h11_dpll); +	if (params->h12 >= 0) +		writel(params->h12, &dpll_regs->cm_div_h12_dpll); +	if (params->h13 >= 0) +		writel(params->h13, &dpll_regs->cm_div_h13_dpll); +	if (params->h14 >= 0) +		writel(params->h14, &dpll_regs->cm_div_h14_dpll); +	if (params->h22 >= 0) +		writel(params->h22, &dpll_regs->cm_div_h22_dpll); +	if (params->h23 >= 0) +		writel(params->h23, &dpll_regs->cm_div_h23_dpll); +} + +const struct dpll_params *get_mpu_dpll_params(void) +{ +	u32 sysclk_ind = get_sys_clk_index(); +	return &mpu_dpll_params_1100mhz[sysclk_ind]; +} + +const struct dpll_params *get_core_dpll_params(void) +{ +	u32 sysclk_ind = get_sys_clk_index(); + +	/* Configuring the DDR to be at 532mhz */ +	return &core_dpll_params_2128mhz_ddr266[sysclk_ind]; + +} + +const struct dpll_params *get_per_dpll_params(void) +{ +	u32 sysclk_ind = get_sys_clk_index(); +	return &per_dpll_params_768mhz[sysclk_ind]; +} + +const struct dpll_params *get_iva_dpll_params(void) +{ +	u32 sysclk_ind = get_sys_clk_index(); +	return &iva_dpll_params_2330mhz[sysclk_ind]; +} + +const struct dpll_params *get_usb_dpll_params(void) +{ +	u32 sysclk_ind = get_sys_clk_index(); +	return &usb_dpll_params_1920mhz[sysclk_ind]; +} + +const struct dpll_params *get_abe_dpll_params(void) +{ +#ifdef CONFIG_SYS_OMAP_ABE_SYSCK +	u32 sysclk_ind = get_sys_clk_index(); +	return &abe_dpll_params_sysclk_196608khz[sysclk_ind]; +#else +	return &abe_dpll_params_32k_196608khz; +#endif +} + +/* + * Setup the voltages for vdd_mpu, vdd_core, and vdd_iva + * We set the maximum voltages allowed here because Smart-Reflex is not + * enabled in bootloader. Voltage initialization in the kernel will set + * these to the nominal values after enabling Smart-Reflex + */ +void scale_vcores(void) +{ +	u32 volt; + +	setup_sri2c(); + +	/* Enable 1.22V from TPS for vdd_mpu */ +	volt = 1220; +	do_scale_tps62361(TPS62361_REG_ADDR_SET1, volt); + +	/* VCORE 1 - for vdd_core */ +	volt = 1000; +	do_scale_vcore(SMPS_REG_ADDR_VCORE1, volt); + +	/* VCORE 2 - for vdd_MM */ +	volt = 1125; +	do_scale_vcore(SMPS_REG_ADDR_VCORE2, volt); +} + +/* + * Enable essential clock domains, modules and + * do some additional special settings needed + */ +void enable_basic_clocks(void) +{ +	u32 *const clk_domains_essential[] = { +		&prcm->cm_l4per_clkstctrl, +		&prcm->cm_l3init_clkstctrl, +		&prcm->cm_memif_clkstctrl, +		&prcm->cm_l4cfg_clkstctrl, +		0 +	}; + +	u32 *const clk_modules_hw_auto_essential[] = { +		&prcm->cm_memif_emif_1_clkctrl, +		&prcm->cm_memif_emif_2_clkctrl, +		&prcm->cm_l4cfg_l4_cfg_clkctrl, +		&prcm->cm_wkup_gpio1_clkctrl, +		&prcm->cm_l4per_gpio2_clkctrl, +		&prcm->cm_l4per_gpio3_clkctrl, +		&prcm->cm_l4per_gpio4_clkctrl, +		&prcm->cm_l4per_gpio5_clkctrl, +		&prcm->cm_l4per_gpio6_clkctrl, +		0 +	}; + +	u32 *const clk_modules_explicit_en_essential[] = { +		&prcm->cm_wkup_gptimer1_clkctrl, +		&prcm->cm_l3init_hsmmc1_clkctrl, +		&prcm->cm_l3init_hsmmc2_clkctrl, +		&prcm->cm_l4per_gptimer2_clkctrl, +		&prcm->cm_wkup_wdtimer2_clkctrl, +		&prcm->cm_l4per_uart3_clkctrl, +		&prcm->cm_l4per_i2c1_clkctrl, +		0 +	}; + +	/* Enable optional additional functional clock for GPIO4 */ +	setbits_le32(&prcm->cm_l4per_gpio4_clkctrl, +			GPIO4_CLKCTRL_OPTFCLKEN_MASK); + +	/* Enable 96 MHz clock for MMC1 & MMC2 */ +	setbits_le32(&prcm->cm_l3init_hsmmc1_clkctrl, +			HSMMC_CLKCTRL_CLKSEL_MASK); +	setbits_le32(&prcm->cm_l3init_hsmmc2_clkctrl, +			HSMMC_CLKCTRL_CLKSEL_MASK); + +	/* Select 32KHz clock as the source of GPTIMER1 */ +	setbits_le32(&prcm->cm_wkup_gptimer1_clkctrl, +			GPTIMER1_CLKCTRL_CLKSEL_MASK); + +	do_enable_clocks(clk_domains_essential, +			 clk_modules_hw_auto_essential, +			 clk_modules_explicit_en_essential, +			 1); +} + +void enable_basic_uboot_clocks(void) +{ +	u32 *const clk_domains_essential[] = { +		0 +	}; + +	u32 *const clk_modules_hw_auto_essential[] = { +		0 +	}; + +	u32 *const clk_modules_explicit_en_essential[] = { +		&prcm->cm_l4per_mcspi1_clkctrl, +		&prcm->cm_l4per_i2c2_clkctrl, +		&prcm->cm_l4per_i2c3_clkctrl, +		&prcm->cm_l4per_i2c4_clkctrl, +		0 +	}; + +	do_enable_clocks(clk_domains_essential, +			 clk_modules_hw_auto_essential, +			 clk_modules_explicit_en_essential, +			 1); +} + +/* + * Enable non-essential clock domains, modules and + * do some additional special settings needed + */ +void enable_non_essential_clocks(void) +{ +	u32 *const clk_domains_non_essential[] = { +		&prcm->cm_mpu_m3_clkstctrl, +		&prcm->cm_ivahd_clkstctrl, +		&prcm->cm_dsp_clkstctrl, +		&prcm->cm_dss_clkstctrl, +		&prcm->cm_sgx_clkstctrl, +		&prcm->cm1_abe_clkstctrl, +		&prcm->cm_c2c_clkstctrl, +		&prcm->cm_cam_clkstctrl, +		&prcm->cm_dss_clkstctrl, +		&prcm->cm_sdma_clkstctrl, +		0 +	}; + +	u32 *const clk_modules_hw_auto_non_essential[] = { +		&prcm->cm_mpu_m3_mpu_m3_clkctrl, +		&prcm->cm_ivahd_ivahd_clkctrl, +		&prcm->cm_ivahd_sl2_clkctrl, +		&prcm->cm_dsp_dsp_clkctrl, +		&prcm->cm_l3_2_gpmc_clkctrl, +		&prcm->cm_l3instr_l3_3_clkctrl, +		&prcm->cm_l3instr_l3_instr_clkctrl, +		&prcm->cm_l3instr_intrconn_wp1_clkctrl, +		&prcm->cm_l3init_hsi_clkctrl, +		&prcm->cm_l3init_hsusbtll_clkctrl, +		0 +	}; + +	u32 *const clk_modules_explicit_en_non_essential[] = { +		&prcm->cm1_abe_aess_clkctrl, +		&prcm->cm1_abe_pdm_clkctrl, +		&prcm->cm1_abe_dmic_clkctrl, +		&prcm->cm1_abe_mcasp_clkctrl, +		&prcm->cm1_abe_mcbsp1_clkctrl, +		&prcm->cm1_abe_mcbsp2_clkctrl, +		&prcm->cm1_abe_mcbsp3_clkctrl, +		&prcm->cm1_abe_slimbus_clkctrl, +		&prcm->cm1_abe_timer5_clkctrl, +		&prcm->cm1_abe_timer6_clkctrl, +		&prcm->cm1_abe_timer7_clkctrl, +		&prcm->cm1_abe_timer8_clkctrl, +		&prcm->cm1_abe_wdt3_clkctrl, +		&prcm->cm_l4per_gptimer9_clkctrl, +		&prcm->cm_l4per_gptimer10_clkctrl, +		&prcm->cm_l4per_gptimer11_clkctrl, +		&prcm->cm_l4per_gptimer3_clkctrl, +		&prcm->cm_l4per_gptimer4_clkctrl, +		&prcm->cm_l4per_hdq1w_clkctrl, +		&prcm->cm_l4per_mcspi2_clkctrl, +		&prcm->cm_l4per_mcspi3_clkctrl, +		&prcm->cm_l4per_mcspi4_clkctrl, +		&prcm->cm_l4per_mmcsd3_clkctrl, +		&prcm->cm_l4per_mmcsd4_clkctrl, +		&prcm->cm_l4per_mmcsd5_clkctrl, +		&prcm->cm_l4per_uart1_clkctrl, +		&prcm->cm_l4per_uart2_clkctrl, +		&prcm->cm_l4per_uart4_clkctrl, +		&prcm->cm_wkup_keyboard_clkctrl, +		&prcm->cm_wkup_wdtimer2_clkctrl, +		&prcm->cm_cam_iss_clkctrl, +		&prcm->cm_cam_fdif_clkctrl, +		&prcm->cm_dss_dss_clkctrl, +		&prcm->cm_sgx_sgx_clkctrl, +		&prcm->cm_l3init_hsusbhost_clkctrl, +		&prcm->cm_l3init_fsusb_clkctrl, +		0 +	}; + +	/* Enable optional functional clock for ISS */ +	setbits_le32(&prcm->cm_cam_iss_clkctrl, ISS_CLKCTRL_OPTFCLKEN_MASK); + +	/* Enable all optional functional clocks of DSS */ +	setbits_le32(&prcm->cm_dss_dss_clkctrl, DSS_CLKCTRL_OPTFCLKEN_MASK); + +	do_enable_clocks(clk_domains_non_essential, +			 clk_modules_hw_auto_non_essential, +			 clk_modules_explicit_en_non_essential, +			 0); + +	/* Put camera module in no sleep mode */ +	clrsetbits_le32(&prcm->cm_cam_clkstctrl, MODULE_CLKCTRL_MODULEMODE_MASK, +			CD_CLKCTRL_CLKTRCTRL_NO_SLEEP << +			MODULE_CLKCTRL_MODULEMODE_SHIFT); +} diff --git a/arch/arm/cpu/armv7/omap5/config.mk b/arch/arm/cpu/armv7/omap5/config.mk new file mode 100644 index 000000000..639f69904 --- /dev/null +++ b/arch/arm/cpu/armv7/omap5/config.mk @@ -0,0 +1,28 @@ +# +# Copyright 2011 Linaro Limited +# See file CREDITS for list of people who contributed to this +# project. +# +# Aneesh V <annesh@ti.com> +# +# 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 +# + +ifdef CONFIG_SPL_BUILD +ALL-y	+= $(OBJTREE)/MLO +else +ALL-y	+= $(obj)u-boot.img +endif diff --git a/arch/arm/cpu/armv7/omap5/emif.c b/arch/arm/cpu/armv7/omap5/emif.c new file mode 100644 index 000000000..8019ffe3d --- /dev/null +++ b/arch/arm/cpu/armv7/omap5/emif.c @@ -0,0 +1,105 @@ +/* + * EMIF programming + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * + * Aneesh V <aneesh@ti.com> for OMAP4 + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/emif.h> +#include <asm/arch/sys_proto.h> +#include <asm/utils.h> + +#ifndef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS +#define print_timing_reg(reg) debug(#reg" - 0x%08x\n", (reg)) +static u32 *const T_num = (u32 *)OMAP5_SRAM_SCRATCH_EMIF_T_NUM; +static u32 *const T_den = (u32 *)OMAP5_SRAM_SCRATCH_EMIF_T_DEN; +static u32 *const emif_sizes = (u32 *)OMAP5_SRAM_SCRATCH_EMIF_SIZE; +#endif + +#ifdef CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS +/* Base AC Timing values specified by JESD209-2 for 532MHz operation */ +static const struct lpddr2_ac_timings timings_jedec_532_mhz = { +	.max_freq = 532000000, +	.RL = 8, +	.tRPab = 21, +	.tRCD = 18, +	.tWR = 15, +	.tRASmin = 42, +	.tRRD = 10, +	.tWTRx2 = 15, +	.tXSR = 140, +	.tXPx2 = 15, +	.tRFCab = 130, +	.tRTPx2 = 15, +	.tCKE = 3, +	.tCKESR = 15, +	.tZQCS = 90, +	.tZQCL = 360, +	.tZQINIT = 1000, +	.tDQSCKMAXx2 = 11, +	.tRASmax = 70, +	.tFAW = 50 +}; + +/* + * Min tCK values specified by JESD209-2 + * Min tCK specifies the minimum duration of some AC timing parameters in terms + * of the number of cycles. If the calculated number of cycles based on the + * absolute time value is less than the min tCK value, min tCK value should + * be used instead. This typically happens at low frequencies. + */ +static const struct lpddr2_min_tck min_tck_jedec = { +	.tRL = 3, +	.tRP_AB = 3, +	.tRCD = 3, +	.tWR = 3, +	.tRAS_MIN = 3, +	.tRRD = 2, +	.tWTR = 2, +	.tXP = 2, +	.tRTP = 2, +	.tCKE = 3, +	.tCKESR = 3, +	.tFAW = 8 +}; + +static const struct lpddr2_ac_timings const* +			jedec_ac_timings[MAX_NUM_SPEEDBINS] = { +	&timings_jedec_532_mhz +}; + +static const struct lpddr2_device_timings jedec_default_timings = { +	.ac_timings = jedec_ac_timings, +	.min_tck = &min_tck_jedec +}; + +void emif_get_device_timings(u32 emif_nr, +		const struct lpddr2_device_timings **cs0_device_timings, +		const struct lpddr2_device_timings **cs1_device_timings) +{ +	/* Assume Identical devices on EMIF1 & EMIF2 */ +	*cs0_device_timings = &jedec_default_timings; +	*cs1_device_timings = NULL; +} +#endif /* CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS */ diff --git a/arch/arm/cpu/armv7/omap5/hwinit.c b/arch/arm/cpu/armv7/omap5/hwinit.c new file mode 100644 index 000000000..fa8e390c1 --- /dev/null +++ b/arch/arm/cpu/armv7/omap5/hwinit.c @@ -0,0 +1,78 @@ +/* + * + * Functions for omap5 based boards. + * + * (C) Copyright 2011 + * Texas Instruments, <www.ti.com> + * + * Author : + *	Aneesh V	<aneesh@ti.com> + *	Steve Sakoman	<steve@sakoman.com> + *	Sricharan	<r.sricharan@ti.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/armv7.h> +#include <asm/arch/cpu.h> +#include <asm/arch/sys_proto.h> +#include <asm/sizes.h> +#include <asm/utils.h> +#include <asm/arch/gpio.h> + +DECLARE_GLOBAL_DATA_PTR; + +u32 *const omap5_revision = (u32 *)OMAP5_SRAM_SCRATCH_OMAP5_REV; + +static struct gpio_bank gpio_bank_54xx[6] = { +	{ (void *)OMAP54XX_GPIO1_BASE, METHOD_GPIO_24XX }, +	{ (void *)OMAP54XX_GPIO2_BASE, METHOD_GPIO_24XX }, +	{ (void *)OMAP54XX_GPIO3_BASE, METHOD_GPIO_24XX }, +	{ (void *)OMAP54XX_GPIO4_BASE, METHOD_GPIO_24XX }, +	{ (void *)OMAP54XX_GPIO5_BASE, METHOD_GPIO_24XX }, +	{ (void *)OMAP54XX_GPIO6_BASE, METHOD_GPIO_24XX }, +}; + +const struct gpio_bank *const omap_gpio_bank = gpio_bank_54xx; + +#ifdef CONFIG_SPL_BUILD +/* + * Some tuning of IOs for optimal power and performance + */ +void do_io_settings(void) +{ +} +#endif + +void init_omap_revision(void) +{ +	/* +	 * For some of the ES2/ES1 boards ID_CODE is not reliable: +	 * Also, ES1 and ES2 have different ARM revisions +	 * So use ARM revision for identification +	 */ +	unsigned int rev = cortex_rev(); + +	switch (rev) { +	case MIDR_CORTEX_A15_R0P0: +		*omap5_revision = OMAP5430_ES1_0; +	default: +		*omap5_revision = OMAP5430_SILICON_ID_INVALID; +	} +} diff --git a/arch/arm/cpu/armv7/omap5/sdram_elpida.c b/arch/arm/cpu/armv7/omap5/sdram_elpida.c new file mode 100644 index 000000000..ad198e6d1 --- /dev/null +++ b/arch/arm/cpu/armv7/omap5/sdram_elpida.c @@ -0,0 +1,178 @@ +/* + * Timing and Organization details of the Elpida parts used in OMAP5 + * EVM + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * + * Aneesh V <aneesh@ti.com> + * Sricharan R <r.sricharan@ti.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <asm/emif.h> +#include <asm/arch/sys_proto.h> + +/* + * This file provides details of the LPDDR2 SDRAM parts used on OMAP5 + * EVM. Since the parts used and geometry are identical for + * evm for a given OMAP5 revision, this information is kept + * here instead of being in board directory. However the key functions + * exported are weakly linked so that they can be over-ridden in the board + * directory if there is a OMAP5 board in the future that uses a different + * memory device or geometry. + * + * For any new board with different memory devices over-ride one or more + * of the following functions as per the CONFIG flags you intend to enable: + * - emif_get_reg_dump() + * - emif_get_dmm_regs() + * - emif_get_device_details() + * - emif_get_device_timings() + */ + +#ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS + +const struct emif_regs emif_regs_elpida_532_mhz_1cs = { +	.sdram_config_init		= 0x80801aB2, +	.sdram_config			= 0x808022B2, +	.ref_ctrl			= 0x0000081A, +	.sdram_tim1			= 0x772F6873, +	.sdram_tim2			= 0x304A129A, +	.sdram_tim3			= 0x02F7E45F, +	.read_idle_ctrl			= 0x00050000, +	.zq_config			= 0x000B3215, +	.temp_alert_config		= 0x08000A05, +	.emif_ddr_phy_ctlr_1_init	= 0x0E38200D, +	.emif_ddr_phy_ctlr_1		= 0x0E38200D +}; + +const struct dmm_lisa_map_regs lisa_map_4G_x_1_x_2 = { +	.dmm_lisa_map_0 = 0xFF020100, +	.dmm_lisa_map_1 = 0, +	.dmm_lisa_map_2 = 0, +	.dmm_lisa_map_3 = 0x80640300 +}; + +static void emif_get_reg_dump_sdp(u32 emif_nr, const struct emif_regs **regs) +{ +	*regs = &emif_regs_elpida_532_mhz_1cs; +} +void emif_get_reg_dump(u32 emif_nr, const struct emif_regs **regs) +	__attribute__((weak, alias("emif_get_reg_dump_sdp"))); + +static void emif_get_dmm_regs_sdp(const struct dmm_lisa_map_regs +						**dmm_lisa_regs) +{ +	*dmm_lisa_regs = &lisa_map_4G_x_1_x_2; +} + +void emif_get_dmm_regs(const struct dmm_lisa_map_regs **dmm_lisa_regs) +	__attribute__((weak, alias("emif_get_dmm_regs_sdp"))); + +#else + +static const struct lpddr2_device_details elpida_4G_S4_details = { +	.type		= LPDDR2_TYPE_S4, +	.density	= LPDDR2_DENSITY_4Gb, +	.io_width	= LPDDR2_IO_WIDTH_32, +	.manufacturer	= LPDDR2_MANUFACTURER_ELPIDA +}; + +static void emif_get_device_details_sdp(u32 emif_nr, +		struct lpddr2_device_details *cs0_device_details, +		struct lpddr2_device_details *cs1_device_details) +{ +	/* EMIF1 & EMIF2 have identical configuration */ +	*cs0_device_details = elpida_4G_S4_details; + +	/* Nothing is conected on cs1 */ +	cs1_device_details = NULL; +} + +void emif_get_device_details(u32 emif_nr, +		struct lpddr2_device_details *cs0_device_details, +		struct lpddr2_device_details *cs1_device_details) +	__attribute__((weak, alias("emif_get_device_details_sdp"))); + +#endif /* CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS */ + +#ifndef CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS +static const struct lpddr2_ac_timings timings_jedec_532_mhz = { +	.max_freq	= 532000000, +	.RL		= 8, +	.tRPab		= 21, +	.tRCD		= 18, +	.tWR		= 15, +	.tRASmin	= 42, +	.tRRD		= 10, +	.tWTRx2		= 15, +	.tXSR		= 140, +	.tXPx2		= 15, +	.tRFCab		= 130, +	.tRTPx2		= 15, +	.tCKE		= 3, +	.tCKESR		= 15, +	.tZQCS		= 90, +	.tZQCL		= 360, +	.tZQINIT	= 1000, +	.tDQSCKMAXx2	= 11, +	.tRASmax	= 70, +	.tFAW		= 50 +}; + +static const struct lpddr2_min_tck min_tck_elpida = { +	.tRL		= 3, +	.tRP_AB		= 3, +	.tRCD		= 3, +	.tWR		= 3, +	.tRAS_MIN	= 3, +	.tRRD		= 2, +	.tWTR		= 2, +	.tXP		= 2, +	.tRTP		= 2, +	.tCKE		= 3, +	.tCKESR		= 3, +	.tFAW		= 8 +}; + +static const struct lpddr2_ac_timings *elpida_ac_timings[MAX_NUM_SPEEDBINS] = { +	&timings_jedec_532_mhz +}; + +static const struct lpddr2_device_timings elpida_4G_S4_timings = { +	.ac_timings	= elpida_ac_timings, +	.min_tck	= &min_tck_elpida, +}; + +void emif_get_device_timings_sdp(u32 emif_nr, +		const struct lpddr2_device_timings **cs0_device_timings, +		const struct lpddr2_device_timings **cs1_device_timings) +{ +	/* Identical devices on EMIF1 & EMIF2 */ +	*cs0_device_timings = &elpida_4G_S4_timings; +	*cs1_device_timings = NULL; +} + +void emif_get_device_timings(u32 emif_nr, +		const struct lpddr2_device_timings **cs0_device_timings, +		const struct lpddr2_device_timings **cs1_device_timings) +	__attribute__((weak, alias("emif_get_device_timings_sdp"))); + +#endif /* CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS */ diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index ff95b84f5..58d279e00 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -82,7 +82,6 @@ int pwm_config(int pwm_id, int duty_ns, int period_ns)  	unsigned long period;  	unsigned long tcon;  	unsigned long tcnt; -	unsigned long timer_rate_hz;  	unsigned long tcmp;  	/* @@ -100,7 +99,6 @@ int pwm_config(int pwm_id, int duty_ns, int period_ns)  	/* Check to see if we are changing the clock rate of the PWM */  	tin_rate = pwm_calc_tin(pwm_id, period); -	timer_rate_hz = tin_rate;  	tin_ns = NS_IN_HZ / tin_rate;  	tcnt = period_ns / tin_ns; |