diff options
Diffstat (limited to 'arch/arm/cpu')
-rw-r--r-- | arch/arm/cpu/arm1136/mx31/generic.c | 2 | ||||
-rw-r--r-- | arch/arm/cpu/arm1136/mx31/timer.c | 4 | ||||
-rw-r--r-- | arch/arm/cpu/arm926ejs/davinci/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/cpu/arm926ejs/davinci/am1808_lowlevel.c | 428 | ||||
-rw-r--r-- | arch/arm/cpu/arm926ejs/davinci/cpu.c | 16 | ||||
-rw-r--r-- | arch/arm/cpu/arm926ejs/davinci/ksz8873.c | 68 | ||||
-rw-r--r-- | arch/arm/cpu/arm926ejs/davinci/timer.c | 46 | ||||
-rw-r--r-- | arch/arm/cpu/arm926ejs/mx25/generic.c | 53 | ||||
-rw-r--r-- | arch/arm/cpu/arm926ejs/start.S | 9 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx5/clock.c | 114 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap-common/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap-common/spl.c | 165 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap-common/spl_mmc.c | 150 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap-common/spl_nand.c | 71 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap3/board.c | 50 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap3/config.mk | 30 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap3/lowlevel_init.S | 10 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap3/sdrc.c | 32 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap3/sys_info.c | 2 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap4/board.c | 1 |
20 files changed, 1074 insertions, 186 deletions
diff --git a/arch/arm/cpu/arm1136/mx31/generic.c b/arch/arm/cpu/arm1136/mx31/generic.c index e3a4d1b808..c6def5df9b 100644 --- a/arch/arm/cpu/arm1136/mx31/generic.c +++ b/arch/arm/cpu/arm1136/mx31/generic.c @@ -180,7 +180,7 @@ int print_cpuinfo (void) { u32 srev = get_cpu_rev(); - printf("CPU: Freescale i.MX31 rev %d.%d%s at %d MHz.", + printf("CPU: Freescale i.MX31 rev %d.%d%s at %d MHz.\n", (srev & 0xF0) >> 4, (srev & 0x0F), ((srev & 0x8000) ? " unknown" : ""), mx31_get_mcu_main_clk() / 1000000); diff --git a/arch/arm/cpu/arm1136/mx31/timer.c b/arch/arm/cpu/arm1136/mx31/timer.c index c05a39d084..717a2b72bd 100644 --- a/arch/arm/cpu/arm1136/mx31/timer.c +++ b/arch/arm/cpu/arm1136/mx31/timer.c @@ -173,8 +173,8 @@ void mxc_hw_watchdog_enable(void) #else secs = 64; #endif - writew(readw(&wdog->wcr) | (secs << WDOG_WT_SHIFT) | WDOG_ENABLE, - &wdog->wcr); + setbits_le16(&wdog->wcr, (secs << WDOG_WT_SHIFT) | WDOG_ENABLE + | WDOG_WDZST); } diff --git a/arch/arm/cpu/arm926ejs/davinci/Makefile b/arch/arm/cpu/arm926ejs/davinci/Makefile index 3183e6a656..0310957f89 100644 --- a/arch/arm/cpu/arm926ejs/davinci/Makefile +++ b/arch/arm/cpu/arm926ejs/davinci/Makefile @@ -28,11 +28,12 @@ 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_SOC_DM355) += dm355.o COBJS-$(CONFIG_SOC_DM365) += dm365.o COBJS-$(CONFIG_SOC_DM644X) += dm644x.o COBJS-$(CONFIG_SOC_DM646X) += dm646x.o -COBJS-$(CONFIG_DRIVER_TI_EMAC) += lxt972.o dp83848.o et1011c.o +COBJS-$(CONFIG_DRIVER_TI_EMAC) += lxt972.o dp83848.o et1011c.o ksz8873.o SOBJS = reset.o diff --git a/arch/arm/cpu/arm926ejs/davinci/am1808_lowlevel.c b/arch/arm/cpu/arm926ejs/davinci/am1808_lowlevel.c new file mode 100644 index 0000000000..1ea4a9ffce --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/am1808_lowlevel.c @@ -0,0 +1,428 @@ +/* + * 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/cpu.c b/arch/arm/cpu/arm926ejs/davinci/cpu.c index b705dfd318..02819f6f74 100644 --- a/arch/arm/cpu/arm926ejs/davinci/cpu.c +++ b/arch/arm/cpu/arm926ejs/davinci/cpu.c @@ -115,7 +115,18 @@ int clk_get(enum davinci_clk_ids id) out: return pll_out; } -#endif /* CONFIG_SOC_DA8XX */ +#ifdef CONFIG_DISPLAY_CPUINFO +int print_cpuinfo(void) +{ + printf("Cores: ARM %d MHz", + clk_get(DAVINCI_ARM_CLKID) / 1000000); + printf("\nDDR: %d MHz\n", + /* DDR PHY uses an x2 input clock */ + clk_get(0x10001) / 1000000); + return 0; +} +#endif +#else /* CONFIG_SOC_DA8XX */ #ifdef CONFIG_DISPLAY_CPUINFO @@ -194,7 +205,8 @@ unsigned int davinci_arm_clk_get() return pll_sysclk_mhz(DAVINCI_PLL_CNTRL0_BASE, ARM_PLLDIV) * 1000000; } #endif -#endif +#endif /* CONFIG_DISPLAY_CPUINFO */ +#endif /* !CONFIG_SOC_DA8XX */ /* * Initializes on-chip ethernet controllers. diff --git a/arch/arm/cpu/arm926ejs/davinci/ksz8873.c b/arch/arm/cpu/arm926ejs/davinci/ksz8873.c new file mode 100644 index 0000000000..634eda0a02 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/ksz8873.c @@ -0,0 +1,68 @@ +/* + * Micrel KSZ8873 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2011 Heiko Schocher <hsdenx.de> + * + * based on: + * National Semiconductor DP83848 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * -------------------------------------------------------- + * + * 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 <miiphy.h> +#include <net.h> +#include <asm/arch/emac_defs.h> +#include <asm/io.h> + +int ksz8873_is_phy_connected(int phy_addr) +{ + u_int16_t dummy; + + return davinci_eth_phy_read(phy_addr, MII_PHYSID1, &dummy); +} + +int ksz8873_get_link_speed(int phy_addr) +{ + emac_regs *emac = (emac_regs *)EMAC_BASE_ADDR; + + /* we always have a link to the switch, 100 FD */ + writel((EMAC_MACCONTROL_MIIEN_ENABLE | + EMAC_MACCONTROL_FULLDUPLEX_ENABLE), + &emac->MACCONTROL); + return 1; +} + + +int ksz8873_init_phy(int phy_addr) +{ + return 1; +} + + +int ksz8873_auto_negotiate(int phy_addr) +{ + return dp83848_get_link_speed(phy_addr); +} diff --git a/arch/arm/cpu/arm926ejs/davinci/timer.c b/arch/arm/cpu/arm926ejs/davinci/timer.c index 8b1734c8e1..c7bf7a5ad2 100644 --- a/arch/arm/cpu/arm926ejs/davinci/timer.c +++ b/arch/arm/cpu/arm926ejs/davinci/timer.c @@ -39,23 +39,10 @@ #include <common.h> #include <asm/io.h> +#include <asm/arch/timer_defs.h> DECLARE_GLOBAL_DATA_PTR; -struct davinci_timer { - u_int32_t pid12; - u_int32_t emumgt; - u_int32_t na1; - u_int32_t na2; - u_int32_t tim12; - u_int32_t tim34; - u_int32_t prd12; - u_int32_t prd34; - u_int32_t tcr; - u_int32_t tgcr; - u_int32_t wdtcr; -}; - static struct davinci_timer * const timer = (struct davinci_timer *)CONFIG_SYS_TIMERBASE; @@ -121,3 +108,34 @@ ulong get_tbclk(void) { return CONFIG_SYS_HZ; } + +#ifdef CONFIG_HW_WATCHDOG +static struct davinci_timer * const wdttimer = + (struct davinci_timer *)CONFIG_SYS_WDTTIMERBASE; + +/* + * See prufw2.pdf for using Timer as a WDT + */ +void davinci_hw_watchdog_enable(void) +{ + writel(0x0, &wdttimer->tcr); + writel(0x0, &wdttimer->tgcr); + /* TIMMODE = 2h */ + writel(0x08 | 0x03 | ((TIM_CLK_DIV - 1) << 8), &wdttimer->tgcr); + writel(CONFIG_SYS_WDT_PERIOD_LOW, &wdttimer->prd12); + writel(CONFIG_SYS_WDT_PERIOD_HIGH, &wdttimer->prd34); + writel(2 << 22, &wdttimer->tcr); + writel(0x0, &wdttimer->tim12); + writel(0x0, &wdttimer->tim34); + /* set WDEN bit, WDKEY 0xa5c6 */ + writel(0xa5c64000, &wdttimer->wdtcr); + /* clear counter register */ + writel(0xda7e4000, &wdttimer->wdtcr); +} + +void davinci_hw_watchdog_reset(void) +{ + writel(0xa5c64000, &wdttimer->wdtcr); + writel(0xda7e4000, &wdttimer->wdtcr); +} +#endif diff --git a/arch/arm/cpu/arm926ejs/mx25/generic.c b/arch/arm/cpu/arm926ejs/mx25/generic.c index 76e4b5c397..8e60a262eb 100644 --- a/arch/arm/cpu/arm926ejs/mx25/generic.c +++ b/arch/arm/cpu/arm926ejs/mx25/generic.c @@ -105,13 +105,64 @@ ulong imx_get_perclk (int clk) return lldiv (fref, div); } +u32 get_cpu_rev(void) +{ + u32 srev; + u32 system_rev = 0x25000; + + /* read SREV register from IIM module */ + struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; + srev = readl(&iim->iim_srev); + + switch (srev) { + case 0x00: + system_rev |= CHIP_REV_1_0; + break; + case 0x01: + system_rev |= CHIP_REV_1_1; + break; + default: + system_rev |= 0x8000; + break; + } + + return system_rev; +} + #if defined(CONFIG_DISPLAY_CPUINFO) +static char *get_reset_cause(void) +{ + /* read RCSR register from CCM module */ + struct ccm_regs *ccm = + (struct ccm_regs *)IMX_CCM_BASE; + + u32 cause = readl(&ccm->rcsr) & 0x0f; + + if (cause == 0) + return "POR"; + else if (cause == 1) + return "RST"; + else if ((cause & 2) == 2) + return "WDOG"; + else if ((cause & 4) == 4) + return "SW RESET"; + else if ((cause & 8) == 8) + return "JTAG"; + else + return "unknown reset"; + +} + int print_cpuinfo (void) { char buf[32]; + u32 cpurev = get_cpu_rev(); - printf ("CPU: Freescale i.MX25 at %s MHz\n\n", + printf("CPU: Freescale i.MX25 rev%d.%d%s at %s MHz\n", + (cpurev & 0xF0) >> 4, (cpurev & 0x0F), + ((cpurev & 0x8000) ? " unknown" : ""), strmhz (buf, imx_get_armclk ())); + printf("Reset cause: %s\n\n", get_reset_cause()); return 0; } #endif diff --git a/arch/arm/cpu/arm926ejs/start.S b/arch/arm/cpu/arm926ejs/start.S index d164d6d6ca..5e30745057 100644 --- a/arch/arm/cpu/arm926ejs/start.S +++ b/arch/arm/cpu/arm926ejs/start.S @@ -51,9 +51,18 @@ */ +#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG .globl _start _start: +.globl _NOR_BOOT_CFG +_NOR_BOOT_CFG: + .word CONFIG_SYS_DV_NOR_BOOT_CFG b reset +#else +.globl _start +_start: + b reset +#endif #ifdef CONFIG_SPL_BUILD /* No exception handlers in preloader */ ldr pc, _hang diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c index 00610a0d59..0769a645c3 100644 --- a/arch/arm/cpu/armv7/mx5/clock.c +++ b/arch/arm/cpu/armv7/mx5/clock.c @@ -29,11 +29,13 @@ #include <asm/arch/imx-regs.h> #include <asm/arch/crm_regs.h> #include <asm/arch/clock.h> +#include <div64.h> enum pll_clocks { PLL1_CLOCK = 0, PLL2_CLOCK, PLL3_CLOCK, + PLL4_CLOCK, PLL_CLOCKS, }; @@ -41,25 +43,65 @@ struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = { [PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR, [PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR, [PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR, +#ifdef CONFIG_MX53 + [PLL4_CLOCK] = (struct mxc_pll_reg *)PLL4_BASE_ADDR, +#endif }; struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE; /* - * Calculate the frequency of this pll. + * Calculate the frequency of PLLn. */ -static u32 decode_pll(struct mxc_pll_reg *pll, u32 infreq) +static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq) { - u32 mfi, mfn, mfd, pd; + uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret; + uint64_t refclk, temp; + int32_t mfn_abs; + + ctrl = readl(&pll->ctrl); + + if (ctrl & MXC_DPLLC_CTL_HFSM) { + mfn = __raw_readl(&pll->hfs_mfn); + mfd = __raw_readl(&pll->hfs_mfd); + op = __raw_readl(&pll->hfs_op); + } else { + mfn = __raw_readl(&pll->mfn); + mfd = __raw_readl(&pll->mfd); + op = __raw_readl(&pll->op); + } - mfn = __raw_readl(&pll->mfn); - mfd = __raw_readl(&pll->mfd) + 1; - mfi = __raw_readl(&pll->op); - pd = (mfi & 0xF) + 1; - mfi = (mfi >> 4) & 0xF; - mfi = (mfi >= 5) ? mfi : 5; + mfd &= MXC_DPLLC_MFD_MFD_MASK; + mfn &= MXC_DPLLC_MFN_MFN_MASK; + pdf = op & MXC_DPLLC_OP_PDF_MASK; + mfi = (op & MXC_DPLLC_OP_MFI_MASK) >> MXC_DPLLC_OP_MFI_OFFSET; + + /* 21.2.3 */ + if (mfi < 5) + mfi = 5; + + /* Sign extend */ + if (mfn >= 0x04000000) { + mfn |= 0xfc000000; + mfn_abs = -mfn; + } else + mfn_abs = mfn; + + refclk = infreq * 2; + if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN) + refclk *= 2; + + refclk /= pdf + 1; + temp = refclk * mfn_abs; + do_div(temp, mfd + 1); + ret = refclk * mfi; + + if ((int)mfn < 0) + ret -= temp; + else + ret += temp; - return ((4 * (infreq / 1000) * (mfi * mfd + mfn)) / (mfd * pd)) * 1000; + return ret; } /* @@ -99,18 +141,35 @@ static u32 get_periph_clk(void) } /* + * Get the rate of ahb clock. + */ +static u32 get_ahb_clk(void) +{ + uint32_t freq, div, reg; + + freq = get_periph_clk(); + + reg = __raw_readl(&mxc_ccm->cbcdr); + div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >> + MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1; + + return freq / div; +} + +/* * Get the rate of ipg clock. */ static u32 get_ipg_clk(void) { - u32 ahb_podf, ipg_podf; - - ahb_podf = __raw_readl(&mxc_ccm->cbcdr); - ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >> - MXC_CCM_CBCDR_IPG_PODF_OFFSET; - ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >> - MXC_CCM_CBCDR_AHB_PODF_OFFSET; - return get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1)); + uint32_t freq, reg, div; + + freq = get_ahb_clk(); + + reg = __raw_readl(&mxc_ccm->cbcdr); + div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >> + MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1; + + return freq / div; } /* @@ -237,7 +296,7 @@ unsigned int mxc_get_clock(enum mxc_clock clk) case MXC_ARM_CLK: return get_mcu_main_clk(); case MXC_AHB_CLK: - break; + return get_ahb_clk(); case MXC_IPG_CLK: return get_ipg_clk(); case MXC_IPG_PERCLK: @@ -274,13 +333,20 @@ int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) u32 freq; freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK); - printf("pll1: %dMHz\n", freq / 1000000); + printf("PLL1 %8d MHz\n", freq / 1000000); freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK); - printf("pll2: %dMHz\n", freq / 1000000); + printf("PLL2 %8d MHz\n", freq / 1000000); freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK); - printf("pll3: %dMHz\n", freq / 1000000); - printf("ipg clock : %dHz\n", mxc_get_clock(MXC_IPG_CLK)); - printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK)); + printf("PLL3 %8d MHz\n", freq / 1000000); +#ifdef CONFIG_MX53 + freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK); + printf("PLL4 %8d MHz\n", freq / 1000000); +#endif + + printf("\n"); + printf("AHB %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000); + printf("IPG %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000); + printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000); return 0; } diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile index ea9f8ec491..0b96b4789f 100644 --- a/arch/arm/cpu/armv7/omap-common/Makefile +++ b/arch/arm/cpu/armv7/omap-common/Makefile @@ -33,6 +33,12 @@ COBJS += gpio.o ifdef CONFIG_SPL_BUILD COBJS += spl.o +ifdef CONFIG_SPL_NAND_SUPPORT +COBJS += spl_nand.o +endif +ifdef CONFIG_SPL_MMC_SUPPORT +COBJS += spl_mmc.o +endif endif SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/arch/arm/cpu/armv7/omap-common/spl.c b/arch/arm/cpu/armv7/omap-common/spl.c index d1776522b7..c76fea6188 100644 --- a/arch/arm/cpu/armv7/omap-common/spl.c +++ b/arch/arm/cpu/armv7/omap-common/spl.c @@ -26,6 +26,7 @@ #include <asm/u-boot.h> #include <asm/utils.h> #include <asm/arch/sys_proto.h> +#include <nand.h> #include <mmc.h> #include <fat.h> #include <timestamp_autogenerated.h> @@ -37,14 +38,11 @@ DECLARE_GLOBAL_DATA_PTR; +struct spl_image_info spl_image; + /* Define global data structure pointer to it*/ static gd_t gdata __attribute__ ((section(".data"))); static bd_t bdata __attribute__ ((section(".data"))); -static const char *image_name; -static u8 image_os; -static u32 image_load_addr; -static u32 image_entry_point; -static u32 image_size; inline void hang(void) { @@ -65,154 +63,40 @@ void board_init_f(ulong dummy) relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE); } -#ifdef CONFIG_GENERIC_MMC -int board_mmc_init(bd_t *bis) -{ - switch (omap_boot_device()) { - case BOOT_DEVICE_MMC1: - omap_mmc_init(0); - break; - case BOOT_DEVICE_MMC2: - omap_mmc_init(1); - break; - } - return 0; -} -#endif - -static void parse_image_header(const struct image_header *header) +void spl_parse_image_header(const struct image_header *header) { u32 header_size = sizeof(struct image_header); if (__be32_to_cpu(header->ih_magic) == IH_MAGIC) { - image_size = __be32_to_cpu(header->ih_size) + header_size; - image_entry_point = __be32_to_cpu(header->ih_load); + spl_image.size = __be32_to_cpu(header->ih_size) + header_size; + spl_image.entry_point = __be32_to_cpu(header->ih_load); /* Load including the header */ - image_load_addr = image_entry_point - header_size; - image_os = header->ih_os; - image_name = (const char *)&header->ih_name; + spl_image.load_addr = spl_image.entry_point - header_size; + spl_image.os = header->ih_os; + spl_image.name = (const char *)&header->ih_name; debug("spl: payload image: %s load addr: 0x%x size: %d\n", - image_name, image_load_addr, image_size); + spl_image.name, spl_image.load_addr, spl_image.size); } else { /* Signature not found - assume u-boot.bin */ printf("mkimage signature not found - ih_magic = %x\n", header->ih_magic); puts("Assuming u-boot.bin ..\n"); /* Let's assume U-Boot will not be more than 200 KB */ - image_size = 200 * 1024; - image_entry_point = CONFIG_SYS_TEXT_BASE; - image_load_addr = CONFIG_SYS_TEXT_BASE; - image_os = IH_OS_U_BOOT; - image_name = "U-Boot"; - } -} - -static void mmc_load_image_raw(struct mmc *mmc) -{ - u32 image_size_sectors, err; - const struct image_header *header; - - header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - - sizeof(struct image_header)); - - /* read image header to find the image size & load address */ - err = mmc->block_dev.block_read(0, - CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR, 1, - (void *)header); - - if (err <= 0) - goto end; - - parse_image_header(header); - - /* convert size to sectors - round up */ - image_size_sectors = (image_size + MMCSD_SECTOR_SIZE - 1) / - MMCSD_SECTOR_SIZE; - - /* Read the header too to avoid extra memcpy */ - err = mmc->block_dev.block_read(0, - CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR, - image_size_sectors, (void *)image_load_addr); - -end: - if (err <= 0) { - printf("spl: mmc blk read err - %d\n", err); - hang(); + spl_image.size = 200 * 1024; + spl_image.entry_point = CONFIG_SYS_TEXT_BASE; + spl_image.load_addr = CONFIG_SYS_TEXT_BASE; + spl_image.os = IH_OS_U_BOOT; + spl_image.name = "U-Boot"; } } -static void mmc_load_image_fat(struct mmc *mmc) -{ - s32 err; - struct image_header *header; - - header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - - sizeof(struct image_header)); - - err = fat_register_device(&mmc->block_dev, - CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION); - if (err) { - printf("spl: fat register err - %d\n", err); - hang(); - } - - err = file_fat_read(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, - (u8 *)header, sizeof(struct image_header)); - if (err <= 0) - goto end; - - parse_image_header(header); - - err = file_fat_read(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, - (u8 *)image_load_addr, 0); - -end: - if (err <= 0) { - printf("spl: error reading image %s, err - %d\n", - CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, err); - hang(); - } -} - -static void mmc_load_image(void) -{ - struct mmc *mmc; - int err; - u32 boot_mode; - - mmc_initialize(gd->bd); - /* We register only one device. So, the dev id is always 0 */ - mmc = find_mmc_device(0); - if (!mmc) { - puts("spl: mmc device not found!!\n"); - hang(); - } - - err = mmc_init(mmc); - if (err) { - printf("spl: mmc init failed: err - %d\n", err); - hang(); - } - - boot_mode = omap_boot_mode(); - if (boot_mode == MMCSD_MODE_RAW) { - debug("boot mode - RAW\n"); - mmc_load_image_raw(mmc); - } else if (boot_mode == MMCSD_MODE_FAT) { - debug("boot mode - FAT\n"); - mmc_load_image_fat(mmc); - } else { - puts("spl: wrong MMC boot mode\n"); - hang(); - } -} - -void jump_to_image_no_args(void) +static void jump_to_image_no_args(void) { typedef void (*image_entry_noargs_t)(void)__attribute__ ((noreturn)); image_entry_noargs_t image_entry = - (image_entry_noargs_t) image_entry_point; + (image_entry_noargs_t) spl_image.entry_point; + debug("image entry point: 0x%X\n", spl_image.entry_point); image_entry(); } @@ -228,17 +112,24 @@ void board_init_r(gd_t *id, ulong dummy) boot_device = omap_boot_device(); debug("boot device - %d\n", boot_device); switch (boot_device) { +#ifdef CONFIG_SPL_MMC_SUPPORT case BOOT_DEVICE_MMC1: case BOOT_DEVICE_MMC2: - mmc_load_image(); + spl_mmc_load_image(); break; +#endif +#ifdef CONFIG_SPL_NAND_SUPPORT + case BOOT_DEVICE_NAND: + spl_nand_load_image(); + break; +#endif default: printf("SPL: Un-supported Boot Device - %d!!!\n", boot_device); hang(); break; } - switch (image_os) { + switch (spl_image.os) { case IH_OS_U_BOOT: debug("Jumping to U-Boot\n"); jump_to_image_no_args(); @@ -249,6 +140,7 @@ void board_init_r(gd_t *id, ulong dummy) } } +/* This requires UART clocks to be enabled */ void preloader_console_init(void) { const char *u_boot_rev = U_BOOT_VERSION; @@ -259,7 +151,6 @@ void preloader_console_init(void) gd->flags |= GD_FLG_RELOC; gd->baudrate = CONFIG_BAUDRATE; - setup_clocks_for_console(); serial_init(); /* serial communications setup */ /* Avoid a second "U-Boot" coming from this string */ diff --git a/arch/arm/cpu/armv7/omap-common/spl_mmc.c b/arch/arm/cpu/armv7/omap-common/spl_mmc.c new file mode 100644 index 0000000000..1d1e50c3c4 --- /dev/null +++ b/arch/arm/cpu/armv7/omap-common/spl_mmc.c @@ -0,0 +1,150 @@ +/* + * (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/u-boot.h> +#include <asm/utils.h> +#include <asm/arch/sys_proto.h> +#include <mmc.h> +#include <fat.h> +#include <timestamp_autogenerated.h> +#include <version_autogenerated.h> +#include <asm/omap_common.h> +#include <asm/arch/mmc_host_def.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_GENERIC_MMC +int board_mmc_init(bd_t *bis) +{ + switch (omap_boot_device()) { + case BOOT_DEVICE_MMC1: + omap_mmc_init(0); + break; + case BOOT_DEVICE_MMC2: + omap_mmc_init(1); + break; + } + return 0; +} +#endif + +static void mmc_load_image_raw(struct mmc *mmc) +{ + u32 image_size_sectors, err; + const struct image_header *header; + + header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - + sizeof(struct image_header)); + + /* read image header to find the image size & load address */ + err = mmc->block_dev.block_read(0, + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR, 1, + (void *)header); + + if (err <= 0) + goto end; + + spl_parse_image_header(header); + + /* convert size to sectors - round up */ + image_size_sectors = (spl_image.size + MMCSD_SECTOR_SIZE - 1) / + MMCSD_SECTOR_SIZE; + + /* Read the header too to avoid extra memcpy */ + err = mmc->block_dev.block_read(0, + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR, + image_size_sectors, (void *)spl_image.load_addr); + +end: + if (err <= 0) { + printf("spl: mmc blk read err - %d\n", err); + hang(); + } +} + +static void mmc_load_image_fat(struct mmc *mmc) +{ + s32 err; + struct image_header *header; + + header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - + sizeof(struct image_header)); + + err = fat_register_device(&mmc->block_dev, + CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION); + if (err) { + printf("spl: fat register err - %d\n", err); + hang(); + } + + err = file_fat_read(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, + (u8 *)header, sizeof(struct image_header)); + if (err <= 0) + goto end; + + spl_parse_image_header(header); + + err = file_fat_read(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, + (u8 *)spl_image.load_addr, 0); + +end: + if (err <= 0) { + printf("spl: error reading image %s, err - %d\n", + CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, err); + hang(); + } +} + +void spl_mmc_load_image(void) +{ + struct mmc *mmc; + int err; + u32 boot_mode; + + mmc_initialize(gd->bd); + /* We register only one device. So, the dev id is always 0 */ + mmc = find_mmc_device(0); + if (!mmc) { + puts("spl: mmc device not found!!\n"); + hang(); + } + + err = mmc_init(mmc); + if (err) { + printf("spl: mmc init failed: err - %d\n", err); + hang(); + } + boot_mode = omap_boot_mode(); + if (boot_mode == MMCSD_MODE_RAW) { + debug("boot mode - RAW\n"); + mmc_load_image_raw(mmc); + } else if (boot_mode == MMCSD_MODE_FAT) { + debug("boot mode - FAT\n"); + mmc_load_image_fat(mmc); + } else { + puts("spl: wrong MMC boot mode\n"); + hang(); + } +} diff --git a/arch/arm/cpu/armv7/omap-common/spl_nand.c b/arch/arm/cpu/armv7/omap-common/spl_nand.c new file mode 100644 index 0000000000..af02a59557 --- /dev/null +++ b/arch/arm/cpu/armv7/omap-common/spl_nand.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011 + * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.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 <common.h> +#include <asm/u-boot.h> +#include <asm/utils.h> +#include <asm/arch/sys_proto.h> +#include <nand.h> +#include <timestamp_autogenerated.h> +#include <version_autogenerated.h> +#include <asm/omap_common.h> + + +void spl_nand_load_image(void) +{ + struct image_header *header; + switch (omap_boot_mode()) { + case NAND_MODE_HW_ECC: + debug("spl: nand - using hw ecc\n"); + gpmc_init(); + nand_init(); + break; + default: + puts("spl: ERROR: This bootmode is not implemented - hanging"); + hang(); + } + + /*use CONFIG_SYS_TEXT_BASE as temporary storage area */ + header = (struct image_header *)(CONFIG_SYS_TEXT_BASE); + +#ifdef CONFIG_NAND_ENV_DST + nand_spl_load_image(CONFIG_ENV_OFFSET, + CONFIG_SYS_NAND_PAGE_SIZE, (void *)header); + spl_parse_image_header(header); + nand_spl_load_image(CONFIG_ENV_OFFSET, spl_image.size, + (void *)image_load_addr); +#ifdef CONFIG_ENV_OFFSET_REDUND + nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, + CONFIG_SYS_NAND_PAGE_SIZE, (void *)header); + spl_parse_image_header(header); + nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, spl_image.size, + (void *)image_load_addr); +#endif +#endif + /* Load u-boot */ + nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, + CONFIG_SYS_NAND_PAGE_SIZE, (void *)header); + spl_parse_image_header(header); + nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, + spl_image.size, (void *)spl_image.load_addr); + nand_deselect(); +} diff --git a/arch/arm/cpu/armv7/omap3/board.c b/arch/arm/cpu/armv7/omap3/board.c index 0448bc93ff..1b3ef69a99 100644 --- a/arch/arm/cpu/armv7/omap3/board.c +++ b/arch/arm/cpu/armv7/omap3/board.c @@ -39,6 +39,7 @@ #include <asm/cache.h> #include <asm/armv7.h> #include <asm/arch/gpio.h> +#include <asm/omap_common.h> /* Declarations */ extern omap3_sysinfo sysinfo; @@ -56,6 +57,41 @@ static const struct gpio_bank gpio_bank_34xx[6] = { const struct gpio_bank *const omap_gpio_bank = gpio_bank_34xx; +#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 omap3_boot_device = BOOT_DEVICE_NAND; + +/* auto boot mode detection is not possible for OMAP3 - hard code */ +u32 omap_boot_mode(void) +{ + switch (omap_boot_device()) { + case BOOT_DEVICE_MMC2: + return MMCSD_MODE_RAW; + case BOOT_DEVICE_MMC1: + return MMCSD_MODE_FAT; + break; + case BOOT_DEVICE_NAND: + return NAND_MODE_HW_ECC; + break; + default: + puts("spl: ERROR: unknown device - can't select boot mode\n"); + hang(); + } +} + +u32 omap_boot_device(void) +{ + return omap3_boot_device; +} + +#endif /* CONFIG_SPL_BUILD */ + + /****************************************************************************** * Routine: delay * Description: spinning delay to use before udelay works @@ -197,6 +233,10 @@ void s_init(void) per_clocks_enable(); +#ifdef CONFIG_SPL_BUILD + preloader_console_init(); +#endif + if (!in_sdram) mem_init(); } @@ -245,7 +285,7 @@ void abort(void) { } -#ifdef CONFIG_NAND_OMAP_GPMC +#if defined(CONFIG_NAND_OMAP_GPMC) & !defined(CONFIG_SPL_BUILD) /****************************************************************************** * OMAP3 specific command to switch between NAND HW and SW ecc *****************************************************************************/ @@ -273,7 +313,7 @@ U_BOOT_CMD( "[hw/sw] - Switch between NAND hardware (hw) or software (sw) ecc algorithm" ); -#endif /* CONFIG_NAND_OMAP_GPMC */ +#endif /* CONFIG_NAND_OMAP_GPMC & !CONFIG_SPL_BUILD */ #ifdef CONFIG_DISPLAY_BOARDINFO /** @@ -410,3 +450,9 @@ void enable_caches(void) dcache_enable(); } #endif + +void omap_rev_string(char *omap_rev_string) +{ + sprintf(omap_rev_string, "OMAP3, sorry revision detection" \ + " unimplemented"); +} diff --git a/arch/arm/cpu/armv7/omap3/config.mk b/arch/arm/cpu/armv7/omap3/config.mk new file mode 100644 index 0000000000..b34fa6417b --- /dev/null +++ b/arch/arm/cpu/armv7/omap3/config.mk @@ -0,0 +1,30 @@ +# +# Copyright 2011 Linaro Limited +# See file CREDITS for list of people who contributed to this +# project. +# +# (C) Copyright 2010 +# Texas Instruments, <www.ti.com> +# +# Aneesh V <aneesh@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/omap3/lowlevel_init.S b/arch/arm/cpu/armv7/omap3/lowlevel_init.S index 67e8ceb55a..a308ebdb6a 100644 --- a/arch/arm/cpu/armv7/omap3/lowlevel_init.S +++ b/arch/arm/cpu/armv7/omap3/lowlevel_init.S @@ -35,6 +35,16 @@ _TEXT_BASE: .word CONFIG_SYS_TEXT_BASE /* sdram load addr from config.mk */ +.global save_boot_params +save_boot_params: +#ifdef CONFIG_SPL_BUILD + ldr r4, =omap3_boot_device + ldr r5, [r0, #0x4] + and r5, r5, #0xff + str r5, [r4] +#endif + bx lr + .global omap3_gp_romcode_call omap3_gp_romcode_call: PUSH {r4-r12, lr} @ Save all registers from ROM code! diff --git a/arch/arm/cpu/armv7/omap3/sdrc.c b/arch/arm/cpu/armv7/omap3/sdrc.c index 2a7970b4d0..0dd1955431 100644 --- a/arch/arm/cpu/armv7/omap3/sdrc.c +++ b/arch/arm/cpu/armv7/omap3/sdrc.c @@ -8,6 +8,9 @@ * Copyright (C) 2004-2010 * Texas Instruments Incorporated - http://www.ti.com/ * + * Copyright (C) 2011 + * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de> + * * Author : * Vaibhav Hiremath <hvaibhav@ti.com> * @@ -133,13 +136,40 @@ void do_sdrc_init(u32 cs, u32 early) sdelay(0x20000); } +/* As long as V_MCFG and V_RFR_CTRL is not defined for all OMAP3 boards we need + * to prevent this to be build in non-SPL build */ +#ifdef CONFIG_SPL_BUILD + /* If we use a SPL there is no x-loader nor config header so we have + * to do the job ourselfs + */ + if (cs == CS0) { + sdrc_actim_base0 = (struct sdrc_actim *)SDRC_ACTIM_CTRL0_BASE; + + /* General SDRC config */ + writel(V_MCFG, &sdrc_base->cs[cs].mcfg); + writel(V_RFR_CTRL, &sdrc_base->cs[cs].rfr_ctrl); + + /* AC timings */ + writel(V_ACTIMA_165, &sdrc_actim_base0->ctrla); + writel(V_ACTIMB_165, &sdrc_actim_base0->ctrlb); + + /* Initialize */ + writel(CMD_NOP, &sdrc_base->cs[cs].manual); + writel(CMD_PRECHARGE, &sdrc_base->cs[cs].manual); + writel(CMD_AUTOREFRESH, &sdrc_base->cs[cs].manual); + writel(CMD_AUTOREFRESH, &sdrc_base->cs[cs].manual); + + writel(V_MR, &sdrc_base->cs[cs].mr); + } +#endif + /* * SDRC timings are set up by x-load or config header * We don't need to redo them here. * Older x-loads configure only CS0 * configure CS1 to handle this ommission */ - if (cs) { + if (cs == CS1) { sdrc_actim_base0 = (struct sdrc_actim *)SDRC_ACTIM_CTRL0_BASE; sdrc_actim_base1 = (struct sdrc_actim *)SDRC_ACTIM_CTRL1_BASE; writel(readl(&sdrc_base->cs[CS0].mcfg), diff --git a/arch/arm/cpu/armv7/omap3/sys_info.c b/arch/arm/cpu/armv7/omap3/sys_info.c index bdb151d7f6..22887aec05 100644 --- a/arch/arm/cpu/armv7/omap3/sys_info.c +++ b/arch/arm/cpu/armv7/omap3/sys_info.c @@ -44,13 +44,13 @@ static char *rev_s[CPU_3XX_MAX_REV] = { "UNKNOWN", "UNKNOWN", "3.1.2"}; -#endif /* CONFIG_DISPLAY_CPUINFO */ /* this is the revision table for 37xx CPUs */ static char *rev_s_37xx[CPU_37XX_MAX_REV] = { "1.0", "1.1", "1.2"}; +#endif /* CONFIG_DISPLAY_CPUINFO */ /***************************************************************** * dieid_num_r(void) - read and set die ID diff --git a/arch/arm/cpu/armv7/omap4/board.c b/arch/arm/cpu/armv7/omap4/board.c index 309b244ad2..8584fdd590 100644 --- a/arch/arm/cpu/armv7/omap4/board.c +++ b/arch/arm/cpu/armv7/omap4/board.c @@ -257,6 +257,7 @@ void s_init(void) watchdog_init(); set_mux_conf_regs(); #ifdef CONFIG_SPL_BUILD + setup_clocks_for_console(); preloader_console_init(); do_io_settings(); #endif |