diff options
Diffstat (limited to 'arch/arm/cpu')
24 files changed, 2578 insertions, 189 deletions
diff --git a/arch/arm/cpu/arm1136/cpu.c b/arch/arm/cpu/arm1136/cpu.c index ade7f46800..2b91631735 100644 --- a/arch/arm/cpu/arm1136/cpu.c +++ b/arch/arm/cpu/arm1136/cpu.c @@ -71,6 +71,7 @@ static void cache_flush(void) { unsigned long i = 0; + asm ("mcr p15, 0, %0, c7, c10, 0": :"r" (i)); /* clean entire data cache */ asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); /* invalidate both caches and flush btb */ asm ("mcr p15, 0, %0, c7, c10, 4": :"r" (i)); /* mem barrier to sync things */ } diff --git a/arch/arm/cpu/arm1136/start.S b/arch/arm/cpu/arm1136/start.S index 957f4389b2..922d01cb70 100644 --- a/arch/arm/cpu/arm1136/start.S +++ b/arch/arm/cpu/arm1136/start.S @@ -226,8 +226,8 @@ cpu_init_crit: * flush v4 I/D caches */ mov r0, #0 - mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ - mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + mcr p15, 0, r0, c7, c7, 0 /* Invalidate I+D+BTB caches */ + mcr p15, 0, r0, c8, c7, 0 /* Invalidate Unified TLB */ /* * disable MMU stuff and caches diff --git a/arch/arm/cpu/arm1176/cpu.c b/arch/arm/cpu/arm1176/cpu.c index befa0cdcc4..c0fd114e16 100644 --- a/arch/arm/cpu/arm1176/cpu.c +++ b/arch/arm/cpu/arm1176/cpu.c @@ -33,9 +33,6 @@ #include <common.h> #include <command.h> -#ifdef CONFIG_S3C64XX -#include <asm/arch/s3c6400.h> -#endif #include <asm/system.h> static void cache_flush (void); diff --git a/arch/arm/cpu/arm1176/start.S b/arch/arm/cpu/arm1176/start.S index e2b6c9b08d..a540edbfbf 100644 --- a/arch/arm/cpu/arm1176/start.S +++ b/arch/arm/cpu/arm1176/start.S @@ -1,5 +1,5 @@ /* - * armboot - Startup Code for S3C6400/ARM1176 CPU-core + * armboot - Startup Code for ARM1176 CPU-core * * Copyright (c) 2007 Samsung Electronics * @@ -35,9 +35,6 @@ #ifdef CONFIG_ENABLE_MMU #include <asm/proc/domain.h> #endif -#ifdef CONFIG_S3C64XX -#include <asm/arch/s3c6400.h> -#endif #if !defined(CONFIG_ENABLE_MMU) && !defined(CONFIG_SYS_PHY_UBOOT_BASE) #define CONFIG_SYS_PHY_UBOOT_BASE CONFIG_SYS_UBOOT_BASE @@ -172,14 +169,10 @@ cpu_init_crit: bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) orr r0, r0, #0x00000002 @ set bit 2 (A) Align orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache + /* Prepare to disable the MMU */ - adr r1, mmu_disable_phys - /* We presume we're within the first 1024 bytes */ - and r1, r1, #0x3fc - ldr r2, _TEXT_PHY_BASE - ldr r3, =0xfff00000 - and r2, r2, r3 - orr r2, r2, r1 + adr r2, mmu_disable_phys + sub r2, r2, #(CONFIG_SYS_PHY_UBOOT_BASE - TEXT_BASE) b mmu_disable .align 5 @@ -189,14 +182,30 @@ mmu_disable: nop nop mov pc, r2 +mmu_disable_phys: + +#ifdef CONFIG_DISABLE_TCM + /* + * Disable the TCMs + */ + mrc p15, 0, r0, c0, c0, 2 /* Return TCM details */ + cmp r0, #0 + beq skip_tcmdisable + mov r1, #0 + mov r2, #1 + tst r0, r2 + mcrne p15, 0, r1, c9, c1, 1 /* Disable Instruction TCM if present*/ + tst r0, r2, LSL #16 + mcrne p15, 0, r1, c9, c1, 0 /* Disable Data TCM if present*/ +skip_tcmdisable: +#endif #endif -mmu_disable_phys: -#ifdef CONFIG_S3C64XX +#ifdef CONFIG_PERIPORT_REMAP /* Peri port setup */ - ldr r0, =0x70000000 - orr r0, r0, #0x13 - mcr p15,0,r0,c15,c2,4 @ 256M (0x70000000 - 0x7fffffff) + ldr r0, =CONFIG_PERIPORT_BASE + orr r0, r0, #CONFIG_PERIPORT_SIZE + mcr p15,0,r0,c15,c2,4 #endif /* @@ -204,7 +213,25 @@ mmu_disable_phys: */ bl lowlevel_init /* go setup pll,mux,memory */ -after_copy: +#ifndef CONFIG_SKIP_RELOCATE_UBOOT +relocate: /* relocate U-Boot to RAM */ + adr r0, _start /* r0 <- current position of code */ + ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ + cmp r0, r1 /* don't reloc during debug */ + beq stack_setup + + ldr r2, _armboot_start + ldr r3, _bss_start + sub r2, r3, r2 /* r2 <- size of armboot */ + add r2, r0, r2 /* r2 <- source end address */ + +copy_loop: + ldmia r0!, {r3-r10} /* copy from source address [r0] */ + stmia r1!, {r3-r10} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop +#endif /* CONFIG_SKIP_RELOCATE_UBOOT */ + #ifdef CONFIG_ENABLE_MMU enable_mmu: /* enable domain access */ @@ -240,9 +267,9 @@ mmu_enable: nop nop mov pc, r2 +skip_hw_init: #endif -skip_hw_init: /* Set up the stack */ stack_setup: ldr r0, =CONFIG_SYS_UBOOT_BASE /* base of copy in DRAM */ @@ -310,6 +337,8 @@ phy_last_jump: mov r0, #0 mov pc, r9 #endif + + /* ************************************************************************* * diff --git a/arch/arm/cpu/arm1176/tnetv107x/Makefile b/arch/arm/cpu/arm1176/tnetv107x/Makefile new file mode 100644 index 0000000000..fe9d8a0dcd --- /dev/null +++ b/arch/arm/cpu/arm1176/tnetv107x/Makefile @@ -0,0 +1,44 @@ +# +# 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).a + +COBJS += aemif.o clock.o init.o mux.o timer.o wdt.o +SOBJS += lowlevel_init.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) + +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm1176/tnetv107x/aemif.c b/arch/arm/cpu/arm1176/tnetv107x/aemif.c new file mode 100644 index 0000000000..172f583bc0 --- /dev/null +++ b/arch/arm/cpu/arm1176/tnetv107x/aemif.c @@ -0,0 +1,93 @@ +/* + * TNETV107X: Asynchronous EMIF Configuration + * + * 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 <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/mux.h> + +#define ASYNC_EMIF_BASE TNETV107X_ASYNC_EMIF_CNTRL_BASE +#define ASYNC_EMIF_CONFIG(cs) (ASYNC_EMIF_BASE+0x10+(cs)*4) +#define ASYNC_EMIF_ONENAND_CONTROL (ASYNC_EMIF_BASE+0x5c) +#define ASYNC_EMIF_NAND_CONTROL (ASYNC_EMIF_BASE+0x60) +#define ASYNC_EMIF_WAITCYCLE_CONFIG (ASYNC_EMIF_BASE+0x4) + +#define CONFIG_SELECT_STROBE(v) ((v) ? 1 << 31 : 0) +#define CONFIG_EXTEND_WAIT(v) ((v) ? 1 << 30 : 0) +#define CONFIG_WR_SETUP(v) (((v) & 0x0f) << 26) +#define CONFIG_WR_STROBE(v) (((v) & 0x3f) << 20) +#define CONFIG_WR_HOLD(v) (((v) & 0x07) << 17) +#define CONFIG_RD_SETUP(v) (((v) & 0x0f) << 13) +#define CONFIG_RD_STROBE(v) (((v) & 0x3f) << 7) +#define CONFIG_RD_HOLD(v) (((v) & 0x07) << 4) +#define CONFIG_TURN_AROUND(v) (((v) & 0x03) << 2) +#define CONFIG_WIDTH(v) (((v) & 0x03) << 0) + +#define NUM_CS 4 + +#define set_config_field(reg, field, val) \ + do { \ + if (val != -1) { \ + reg &= ~CONFIG_##field(0xffffffff); \ + reg |= CONFIG_##field(val); \ + } \ + } while (0) + +void configure_async_emif(int cs, struct async_emif_config *cfg) +{ + unsigned long tmp; + + if (cfg->mode == ASYNC_EMIF_MODE_NAND) { + tmp = __raw_readl(ASYNC_EMIF_NAND_CONTROL); + tmp |= (1 << cs); + __raw_writel(tmp, ASYNC_EMIF_NAND_CONTROL); + + } else if (cfg->mode == ASYNC_EMIF_MODE_ONENAND) { + tmp = __raw_readl(ASYNC_EMIF_ONENAND_CONTROL); + tmp |= (1 << cs); + __raw_writel(tmp, ASYNC_EMIF_ONENAND_CONTROL); + } + + tmp = __raw_readl(ASYNC_EMIF_CONFIG(cs)); + + set_config_field(tmp, SELECT_STROBE, cfg->select_strobe); + set_config_field(tmp, EXTEND_WAIT, cfg->extend_wait); + set_config_field(tmp, WR_SETUP, cfg->wr_setup); + set_config_field(tmp, WR_STROBE, cfg->wr_strobe); + set_config_field(tmp, WR_HOLD, cfg->wr_hold); + set_config_field(tmp, RD_SETUP, cfg->rd_setup); + set_config_field(tmp, RD_STROBE, cfg->rd_strobe); + set_config_field(tmp, RD_HOLD, cfg->rd_hold); + set_config_field(tmp, TURN_AROUND, cfg->turn_around); + set_config_field(tmp, WIDTH, cfg->width); + + __raw_writel(tmp, ASYNC_EMIF_CONFIG(cs)); +} + +void init_async_emif(int num_cs, struct async_emif_config *config) +{ + int cs; + + clk_enable(TNETV107X_LPSC_AEMIF); + + for (cs = 0; cs < num_cs; cs++) + configure_async_emif(cs, config + cs); +} diff --git a/arch/arm/cpu/arm1176/tnetv107x/clock.c b/arch/arm/cpu/arm1176/tnetv107x/clock.c new file mode 100644 index 0000000000..e26fec1f95 --- /dev/null +++ b/arch/arm/cpu/arm1176/tnetv107x/clock.c @@ -0,0 +1,451 @@ +/* + * TNETV107X: Clock management APIs + * + * 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 <asm-generic/errno.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/arch/clock.h> + +#define CLOCK_BASE TNETV107X_CLOCK_CONTROL_BASE +#define PSC_BASE TNETV107X_PSC_BASE + +#define BIT(x) (1 << (x)) + +#define MAX_PREDIV 64 +#define MAX_POSTDIV 8 +#define MAX_MULT 512 +#define MAX_DIV (MAX_PREDIV * MAX_POSTDIV) + +/* LPSC registers */ +#define PSC_PTCMD 0x120 +#define PSC_PTSTAT 0x128 +#define PSC_MDSTAT(n) (0x800 + (n) * 4) +#define PSC_MDCTL(n) (0xA00 + (n) * 4) + +#define PSC_MDCTL_LRSTZ BIT(8) + +#define psc_reg_read(reg) __raw_readl((u32 *)(PSC_BASE + (reg))) +#define psc_reg_write(reg, val) __raw_writel(val, (u32 *)(PSC_BASE + (reg))) + +/* SSPLL registers */ +struct sspll_regs { + u32 modes; + u32 postdiv; + u32 prediv; + u32 mult_factor; + u32 divider_range; + u32 bw_divider; + u32 spr_amount; + u32 spr_rate_div; + u32 diag; +}; + +/* SSPLL base addresses */ +static struct sspll_regs *sspll_regs[] = { + (struct sspll_regs *)(CLOCK_BASE + 0x040), + (struct sspll_regs *)(CLOCK_BASE + 0x080), + (struct sspll_regs *)(CLOCK_BASE + 0x0c0), +}; + +#define sspll_reg(pll, reg) (&(sspll_regs[pll]->reg)) +#define sspll_reg_read(pll, reg) __raw_readl(sspll_reg(pll, reg)) +#define sspll_reg_write(pll, reg, val) __raw_writel(val, sspll_reg(pll, reg)) + + +/* PLL Control Registers */ +struct pllctl_regs { + u32 ctl; /* 00 */ + u32 ocsel; /* 04 */ + u32 secctl; /* 08 */ + u32 __pad0; + u32 mult; /* 10 */ + u32 prediv; /* 14 */ + u32 div1; /* 18 */ + u32 div2; /* 1c */ + u32 div3; /* 20 */ + u32 oscdiv1; /* 24 */ + u32 postdiv; /* 28 */ + u32 bpdiv; /* 2c */ + u32 wakeup; /* 30 */ + u32 __pad1; + u32 cmd; /* 38 */ + u32 stat; /* 3c */ + u32 alnctl; /* 40 */ + u32 dchange; /* 44 */ + u32 cken; /* 48 */ + u32 ckstat; /* 4c */ + u32 systat; /* 50 */ + u32 ckctl; /* 54 */ + u32 __pad2[2]; + u32 div4; /* 60 */ + u32 div5; /* 64 */ + u32 div6; /* 68 */ + u32 div7; /* 6c */ + u32 div8; /* 70 */ +}; + +struct lpsc_map { + int pll, div; +}; + +static struct pllctl_regs *pllctl_regs[] = { + (struct pllctl_regs *)(CLOCK_BASE + 0x700), + (struct pllctl_regs *)(CLOCK_BASE + 0x300), + (struct pllctl_regs *)(CLOCK_BASE + 0x500), +}; + +#define pllctl_reg(pll, reg) (&(pllctl_regs[pll]->reg)) +#define pllctl_reg_read(pll, reg) __raw_readl(pllctl_reg(pll, reg)) +#define pllctl_reg_write(pll, reg, val) __raw_writel(val, pllctl_reg(pll, reg)) + +#define pllctl_reg_rmw(pll, reg, mask, val) \ + pllctl_reg_write(pll, reg, \ + (pllctl_reg_read(pll, reg) & ~(mask)) | val) + +#define pllctl_reg_setbits(pll, reg, mask) \ + pllctl_reg_rmw(pll, reg, 0, mask) + +#define pllctl_reg_clrbits(pll, reg, mask) \ + pllctl_reg_rmw(pll, reg, mask, 0) + +/* PLLCTL Bits */ +#define PLLCTL_CLKMODE BIT(8) +#define PLLCTL_PLLSELB BIT(7) +#define PLLCTL_PLLENSRC BIT(5) +#define PLLCTL_PLLDIS BIT(4) +#define PLLCTL_PLLRST BIT(3) +#define PLLCTL_PLLPWRDN BIT(1) +#define PLLCTL_PLLEN BIT(0) + +#define PLLDIV_ENABLE BIT(15) + +static int pll_div_offset[] = { +#define div_offset(reg) offsetof(struct pllctl_regs, reg) + div_offset(div1), div_offset(div2), div_offset(div3), + div_offset(div4), div_offset(div5), div_offset(div6), + div_offset(div7), div_offset(div8), +}; + +static unsigned long pll_bypass_mask[] = { 1, 4, 2 }; +static unsigned long pll_div_mask[] = { 0x01ff, 0x00ff, 0x00ff }; + +/* Mappings from PLL+DIV to subsystem clocks */ +#define sys_arm1176_clk {SYS_PLL, 0} +#define sys_dsp_clk {SYS_PLL, 1} +#define sys_ddr_clk {SYS_PLL, 2} +#define sys_full_clk {SYS_PLL, 3} +#define sys_lcd_clk {SYS_PLL, 4} +#define sys_vlynq_ref_clk {SYS_PLL, 5} +#define sys_tsc_clk {SYS_PLL, 6} +#define sys_half_clk {SYS_PLL, 7} + +#define eth_clk_5 {ETH_PLL, 0} +#define eth_clk_50 {ETH_PLL, 1} +#define eth_clk_125 {ETH_PLL, 2} +#define eth_clk_250 {ETH_PLL, 3} +#define eth_clk_25 {ETH_PLL, 4} + +#define tdm_clk {TDM_PLL, 0} +#define tdm_extra_clk {TDM_PLL, 1} +#define tdm1_clk {TDM_PLL, 2} + +/* Optimization barrier */ +#define barrier() \ + __asm__ __volatile__("mov r0, r0\n" : : : "memory"); + +static const struct lpsc_map lpsc_clk_map[] = { + [TNETV107X_LPSC_ARM] = sys_arm1176_clk, + [TNETV107X_LPSC_GEM] = sys_dsp_clk, + [TNETV107X_LPSC_DDR2_PHY] = sys_ddr_clk, + [TNETV107X_LPSC_TPCC] = sys_full_clk, + [TNETV107X_LPSC_TPTC0] = sys_full_clk, + [TNETV107X_LPSC_TPTC1] = sys_full_clk, + [TNETV107X_LPSC_RAM] = sys_full_clk, + [TNETV107X_LPSC_MBX_LITE] = sys_arm1176_clk, + [TNETV107X_LPSC_LCD] = sys_lcd_clk, + [TNETV107X_LPSC_ETHSS] = eth_clk_125, + [TNETV107X_LPSC_AEMIF] = sys_full_clk, + [TNETV107X_LPSC_CHIP_CFG] = sys_half_clk, + [TNETV107X_LPSC_TSC] = sys_tsc_clk, + [TNETV107X_LPSC_ROM] = sys_half_clk, + [TNETV107X_LPSC_UART2] = sys_half_clk, + [TNETV107X_LPSC_PKTSEC] = sys_half_clk, + [TNETV107X_LPSC_SECCTL] = sys_half_clk, + [TNETV107X_LPSC_KEYMGR] = sys_half_clk, + [TNETV107X_LPSC_KEYPAD] = sys_half_clk, + [TNETV107X_LPSC_GPIO] = sys_half_clk, + [TNETV107X_LPSC_MDIO] = sys_half_clk, + [TNETV107X_LPSC_SDIO0] = sys_half_clk, + [TNETV107X_LPSC_UART0] = sys_half_clk, + [TNETV107X_LPSC_UART1] = sys_half_clk, + [TNETV107X_LPSC_TIMER0] = sys_half_clk, + [TNETV107X_LPSC_TIMER1] = sys_half_clk, + [TNETV107X_LPSC_WDT_ARM] = sys_half_clk, + [TNETV107X_LPSC_WDT_DSP] = sys_half_clk, + [TNETV107X_LPSC_SSP] = sys_half_clk, + [TNETV107X_LPSC_TDM0] = tdm_clk, + [TNETV107X_LPSC_VLYNQ] = sys_vlynq_ref_clk, + [TNETV107X_LPSC_MCDMA] = sys_half_clk, + [TNETV107X_LPSC_USB0] = sys_half_clk, + [TNETV107X_LPSC_TDM1] = tdm1_clk, + [TNETV107X_LPSC_DEBUGSS] = sys_half_clk, + [TNETV107X_LPSC_ETHSS_RGMII] = eth_clk_250, + [TNETV107X_LPSC_SYSTEM] = sys_half_clk, + [TNETV107X_LPSC_IMCOP] = sys_dsp_clk, + [TNETV107X_LPSC_SPARE] = sys_half_clk, + [TNETV107X_LPSC_SDIO1] = sys_half_clk, + [TNETV107X_LPSC_USB1] = sys_half_clk, + [TNETV107X_LPSC_USBSS] = sys_half_clk, + [TNETV107X_LPSC_DDR2_EMIF1_VRST] = sys_ddr_clk, + [TNETV107X_LPSC_DDR2_EMIF2_VCTL_RST] = sys_ddr_clk, +}; + +static const unsigned long pll_ext_freq[] = { + [SYS_PLL] = CONFIG_PLL_SYS_EXT_FREQ, + [ETH_PLL] = CONFIG_PLL_ETH_EXT_FREQ, + [TDM_PLL] = CONFIG_PLL_TDM_EXT_FREQ, +}; + +static unsigned long pll_freq_get(int pll) +{ + unsigned long mult = 1, prediv = 1, postdiv = 1; + unsigned long ref = CONFIG_SYS_INT_OSC_FREQ; + unsigned long ret; + u32 bypass; + + bypass = __raw_readl((u32 *)(CLOCK_BASE)); + if (!(bypass & pll_bypass_mask[pll])) { + mult = sspll_reg_read(pll, mult_factor); + prediv = sspll_reg_read(pll, prediv) + 1; + postdiv = sspll_reg_read(pll, postdiv) + 1; + } + + if (pllctl_reg_read(pll, ctl) & PLLCTL_CLKMODE) + ref = pll_ext_freq[pll]; + + if (!(pllctl_reg_read(pll, ctl) & PLLCTL_PLLEN)) + return ref; + + ret = (unsigned long)(ref + ((unsigned long long)ref * mult) / 256); + ret /= (prediv * postdiv); + + return ret; +} + +static unsigned long __pll_div_freq_get(int pll, unsigned int fpll, + int div) +{ + int divider = 1; + unsigned long divreg; + + divreg = __raw_readl((void *)pllctl_regs[pll] + pll_div_offset[div]); + + if (divreg & PLLDIV_ENABLE) + divider = (divreg & pll_div_mask[pll]) + 1; + + return fpll / divider; +} + +static unsigned long pll_div_freq_get(int pll, int div) +{ + unsigned int fpll = pll_freq_get(pll); + + return __pll_div_freq_get(pll, fpll, div); +} + +static void __pll_div_freq_set(int pll, unsigned int fpll, int div, + unsigned long hz) +{ + int divider = (fpll / hz - 1); + + divider &= pll_div_mask[pll]; + divider |= PLLDIV_ENABLE; + + __raw_writel(divider, (void *)pllctl_regs[pll] + pll_div_offset[div]); + pllctl_reg_setbits(pll, alnctl, (1 << div)); + pllctl_reg_setbits(pll, dchange, (1 << div)); +} + +static unsigned long pll_div_freq_set(int pll, int div, unsigned long hz) +{ + unsigned int fpll = pll_freq_get(pll); + + __pll_div_freq_set(pll, fpll, div, hz); + + pllctl_reg_write(pll, cmd, 1); + + /* Wait until new divider takes effect */ + while (pllctl_reg_read(pll, stat) & 0x01); + + return __pll_div_freq_get(pll, fpll, div); +} + +unsigned long clk_get_rate(unsigned int clk) +{ + return pll_div_freq_get(lpsc_clk_map[clk].pll, lpsc_clk_map[clk].div); +} + +unsigned long clk_round_rate(unsigned int clk, unsigned long hz) +{ + unsigned long fpll, divider, pll; + + pll = lpsc_clk_map[clk].pll; + fpll = pll_freq_get(pll); + divider = (fpll / hz - 1); + divider &= pll_div_mask[pll]; + + return fpll / (divider + 1); +} + +int clk_set_rate(unsigned int clk, unsigned long _hz) +{ + unsigned long hz; + + hz = clk_round_rate(clk, _hz); + if (hz != _hz) + return -EINVAL; /* Cannot set to target freq */ + + pll_div_freq_set(lpsc_clk_map[clk].pll, lpsc_clk_map[clk].div, hz); + return 0; +} + +void lpsc_control(int mod, unsigned long state, int lrstz) +{ + u32 mdctl; + + mdctl = psc_reg_read(PSC_MDCTL(mod)); + mdctl &= ~0x1f; + mdctl |= state; + + if (lrstz == 0) + mdctl &= ~PSC_MDCTL_LRSTZ; + else if (lrstz == 1) + mdctl |= PSC_MDCTL_LRSTZ; + + psc_reg_write(PSC_MDCTL(mod), mdctl); + + psc_reg_write(PSC_PTCMD, 1); + + /* wait for power domain transition to end */ + while (psc_reg_read(PSC_PTSTAT) & 1); + + /* Wait for module state change */ + while ((psc_reg_read(PSC_MDSTAT(mod)) & 0x1f) != state); +} + +int lpsc_status(unsigned int id) +{ + return psc_reg_read(PSC_MDSTAT(id)) & 0x1f; +} + +static void init_pll(const struct pll_init_data *data) +{ + unsigned long fpll; + unsigned long best_pre = 0, best_post = 0, best_mult = 0; + unsigned long div, prediv, postdiv, mult; + unsigned long delta, actual; + long best_delta = -1; + int i; + u32 tmp; + + if (data->pll == SYS_PLL) + return; /* cannot reconfigure system pll on the fly */ + + tmp = pllctl_reg_read(data->pll, ctl); + if (data->internal_osc) { + tmp &= ~PLLCTL_CLKMODE; + fpll = CONFIG_SYS_INT_OSC_FREQ; + } else { + tmp |= PLLCTL_CLKMODE; + fpll = pll_ext_freq[data->pll]; + } + pllctl_reg_write(data->pll, ctl, tmp); + + mult = data->pll_freq / fpll; + for (mult = MAX(mult, 1); mult <= MAX_MULT; mult++) { + div = (fpll * mult) / data->pll_freq; + if (div < 1 || div > MAX_DIV) + continue; + + for (postdiv = 1; postdiv <= min(div, MAX_POSTDIV); postdiv++) { + prediv = div / postdiv; + if (prediv < 1 || prediv > MAX_PREDIV) + continue; + + actual = (fpll / prediv) * (mult / postdiv); + delta = (actual - data->pll_freq); + if (delta < 0) + delta = -delta; + if ((delta < best_delta) || (best_delta == -1)) { + best_delta = delta; + best_mult = mult; + best_pre = prediv; + best_post = postdiv; + if (delta == 0) + goto done; + } + } + } +done: + + if (best_delta == -1) { + printf("pll cannot derive %lu from %lu\n", + data->pll_freq, fpll); + return; + } + + fpll = fpll * best_mult; + fpll /= best_pre * best_post; + + pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLENSRC); + pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLEN); + + pllctl_reg_setbits(data->pll, ctl, PLLCTL_PLLRST); + + pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLPWRDN); + pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLDIS); + + sspll_reg_write(data->pll, mult_factor, (best_mult - 1) << 8); + sspll_reg_write(data->pll, prediv, best_pre - 1); + sspll_reg_write(data->pll, postdiv, best_post - 1); + + for (i = 0; i < 10; i++) + if (data->div_freq[i]) + __pll_div_freq_set(data->pll, fpll, i, + data->div_freq[i]); + + pllctl_reg_write(data->pll, cmd, 1); + + /* Wait until pll "go" operation completes */ + while (pllctl_reg_read(data->pll, stat) & 0x01); + + pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLRST); + pllctl_reg_setbits(data->pll, ctl, PLLCTL_PLLEN); +} + +void init_plls(int num_pll, struct pll_init_data *config) +{ + int i; + + for (i = 0; i < num_pll; i++) + init_pll(&config[i]); +} diff --git a/arch/arm/cpu/arm1176/tnetv107x/init.c b/arch/arm/cpu/arm1176/tnetv107x/init.c new file mode 100644 index 0000000000..ce3a025503 --- /dev/null +++ b/arch/arm/cpu/arm1176/tnetv107x/init.c @@ -0,0 +1,37 @@ +/* + * TNETV107X: Architecture initialization + * + * 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 <asm/io.h> + +void chip_configuration_unlock(void) +{ + __raw_writel(TNETV107X_KICK0_MAGIC, TNETV107X_KICK0); + __raw_writel(TNETV107X_KICK1_MAGIC, TNETV107X_KICK1); +} + +int arch_cpu_init(void) +{ + icache_enable(); + chip_configuration_unlock(); + + return 0; +} diff --git a/arch/arm/cpu/arm1176/tnetv107x/lowlevel_init.S b/arch/arm/cpu/arm1176/tnetv107x/lowlevel_init.S new file mode 100644 index 0000000000..3ee32ef96e --- /dev/null +++ b/arch/arm/cpu/arm1176/tnetv107x/lowlevel_init.S @@ -0,0 +1,25 @@ +/* + * TNETV107X: Low-level pre-relocation initialization + * + * 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. + */ + +.globl lowlevel_init +lowlevel_init: + /* nothing for now, maybe needed for more exotic boot modes */ + mov pc, lr diff --git a/arch/arm/cpu/arm1176/tnetv107x/mux.c b/arch/arm/cpu/arm1176/tnetv107x/mux.c new file mode 100644 index 0000000000..ccc53141fd --- /dev/null +++ b/arch/arm/cpu/arm1176/tnetv107x/mux.c @@ -0,0 +1,334 @@ +/* + * TNETV107X: Pinmux configuration + * + * 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 <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/mux.h> + +#define MUX_MODE_1 0x00 +#define MUX_MODE_2 0x04 +#define MUX_MODE_3 0x0c +#define MUX_MODE_4 0x1c + +#define MUX_DEBUG 0 + +static const struct pin_config pin_table[] = { + /* reg shift mode */ + TNETV107X_MUX_CFG(0, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(0, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(0, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(0, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(0, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(0, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(0, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(0, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(0, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(0, 20, MUX_MODE_2), + TNETV107X_MUX_CFG(0, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(0, 25, MUX_MODE_2), + TNETV107X_MUX_CFG(1, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(1, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(1, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(1, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(1, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(1, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(1, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(1, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(1, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(1, 20, MUX_MODE_2), + TNETV107X_MUX_CFG(1, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(1, 25, MUX_MODE_2), + TNETV107X_MUX_CFG(2, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(2, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(2, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(2, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(2, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(2, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(2, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(2, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(2, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(2, 20, MUX_MODE_2), + TNETV107X_MUX_CFG(2, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(2, 25, MUX_MODE_2), + TNETV107X_MUX_CFG(3, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(3, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(3, 0, MUX_MODE_4), + TNETV107X_MUX_CFG(3, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(3, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(3, 5, MUX_MODE_4), + TNETV107X_MUX_CFG(3, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(3, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(3, 10, MUX_MODE_4), + TNETV107X_MUX_CFG(3, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(3, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(3, 15, MUX_MODE_4), + TNETV107X_MUX_CFG(3, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(3, 20, MUX_MODE_2), + TNETV107X_MUX_CFG(3, 20, MUX_MODE_4), + TNETV107X_MUX_CFG(3, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(3, 25, MUX_MODE_2), + TNETV107X_MUX_CFG(3, 25, MUX_MODE_4), + TNETV107X_MUX_CFG(4, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(4, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(4, 0, MUX_MODE_4), + TNETV107X_MUX_CFG(4, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(4, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(4, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(4, 15, MUX_MODE_4), + TNETV107X_MUX_CFG(4, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(4, 20, MUX_MODE_3), + TNETV107X_MUX_CFG(4, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(4, 25, MUX_MODE_4), + TNETV107X_MUX_CFG(5, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(5, 0, MUX_MODE_4), + TNETV107X_MUX_CFG(5, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(5, 5, MUX_MODE_4), + TNETV107X_MUX_CFG(5, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(5, 10, MUX_MODE_4), + TNETV107X_MUX_CFG(5, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(5, 15, MUX_MODE_4), + TNETV107X_MUX_CFG(5, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(5, 20, MUX_MODE_4), + TNETV107X_MUX_CFG(5, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(5, 25, MUX_MODE_4), + TNETV107X_MUX_CFG(6, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(6, 0, MUX_MODE_4), + TNETV107X_MUX_CFG(6, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(6, 5, MUX_MODE_4), + TNETV107X_MUX_CFG(6, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(6, 10, MUX_MODE_4), + TNETV107X_MUX_CFG(6, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(6, 15, MUX_MODE_4), + TNETV107X_MUX_CFG(6, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(6, 20, MUX_MODE_4), + TNETV107X_MUX_CFG(6, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(6, 25, MUX_MODE_4), + TNETV107X_MUX_CFG(7, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(7, 0, MUX_MODE_4), + TNETV107X_MUX_CFG(7, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(7, 5, MUX_MODE_4), + TNETV107X_MUX_CFG(7, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(7, 10, MUX_MODE_4), + TNETV107X_MUX_CFG(7, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(7, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(7, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(7, 20, MUX_MODE_2), + TNETV107X_MUX_CFG(7, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(7, 25, MUX_MODE_2), + TNETV107X_MUX_CFG(8, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(8, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(8, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(8, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(8, 5, MUX_MODE_4), + TNETV107X_MUX_CFG(8, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(8, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(9, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(9, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(9, 0, MUX_MODE_4), + TNETV107X_MUX_CFG(9, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(9, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(9, 5, MUX_MODE_4), + TNETV107X_MUX_CFG(9, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(9, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(9, 10, MUX_MODE_4), + TNETV107X_MUX_CFG(9, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(9, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(9, 15, MUX_MODE_4), + TNETV107X_MUX_CFG(9, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(9, 20, MUX_MODE_2), + TNETV107X_MUX_CFG(9, 20, MUX_MODE_4), + TNETV107X_MUX_CFG(10, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(10, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(10, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(10, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(10, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(10, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(10, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(10, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(10, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(10, 20, MUX_MODE_2), + TNETV107X_MUX_CFG(10, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(10, 25, MUX_MODE_2), + TNETV107X_MUX_CFG(11, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(11, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(12, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(12, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(12, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(12, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(12, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(12, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(13, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(13, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(13, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(13, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(14, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(14, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(14, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(14, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(14, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(14, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(15, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(15, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(15, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(15, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(15, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(15, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(15, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(15, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(16, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(16, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(16, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(16, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(16, 10, MUX_MODE_3), + TNETV107X_MUX_CFG(16, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(16, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(17, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(17, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(17, 0, MUX_MODE_3), + TNETV107X_MUX_CFG(17, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(17, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(17, 5, MUX_MODE_3), + TNETV107X_MUX_CFG(17, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(17, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(17, 10, MUX_MODE_3), + TNETV107X_MUX_CFG(17, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(17, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(17, 15, MUX_MODE_3), + TNETV107X_MUX_CFG(18, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(18, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(18, 0, MUX_MODE_3), + TNETV107X_MUX_CFG(18, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(18, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(18, 5, MUX_MODE_3), + TNETV107X_MUX_CFG(18, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(18, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(18, 10, MUX_MODE_3), + TNETV107X_MUX_CFG(18, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(18, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(18, 15, MUX_MODE_3), + TNETV107X_MUX_CFG(19, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(19, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(19, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(19, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(19, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(19, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(20, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(20, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(20, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(20, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(20, 15, MUX_MODE_3), + TNETV107X_MUX_CFG(20, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(20, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(21, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(21, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(21, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(21, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(21, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(21, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(22, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(22, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(22, 5, MUX_MODE_3), + TNETV107X_MUX_CFG(22, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(22, 10, MUX_MODE_3), + TNETV107X_MUX_CFG(22, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(22, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(22, 15, MUX_MODE_3), + TNETV107X_MUX_CFG(22, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(22, 20, MUX_MODE_3), + TNETV107X_MUX_CFG(22, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(22, 25, MUX_MODE_3), + TNETV107X_MUX_CFG(23, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(23, 0, MUX_MODE_3), + TNETV107X_MUX_CFG(23, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(23, 5, MUX_MODE_3), + TNETV107X_MUX_CFG(23, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(23, 10, MUX_MODE_3), + TNETV107X_MUX_CFG(24, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(24, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(24, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(24, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(24, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(24, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(24, 10, MUX_MODE_3), + TNETV107X_MUX_CFG(24, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(24, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(24, 15, MUX_MODE_3), + TNETV107X_MUX_CFG(24, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(24, 20, MUX_MODE_2), + TNETV107X_MUX_CFG(24, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(24, 25, MUX_MODE_2), + TNETV107X_MUX_CFG(25, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(25, 0, MUX_MODE_2), + TNETV107X_MUX_CFG(25, 0, MUX_MODE_3), + TNETV107X_MUX_CFG(25, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(25, 5, MUX_MODE_2), + TNETV107X_MUX_CFG(25, 5, MUX_MODE_3), + TNETV107X_MUX_CFG(25, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(25, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(25, 10, MUX_MODE_3), + TNETV107X_MUX_CFG(25, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(25, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(25, 15, MUX_MODE_3), + TNETV107X_MUX_CFG(25, 15, MUX_MODE_4), + TNETV107X_MUX_CFG(26, 0, MUX_MODE_1), + TNETV107X_MUX_CFG(26, 5, MUX_MODE_1), + TNETV107X_MUX_CFG(26, 10, MUX_MODE_1), + TNETV107X_MUX_CFG(26, 10, MUX_MODE_2), + TNETV107X_MUX_CFG(26, 15, MUX_MODE_1), + TNETV107X_MUX_CFG(26, 15, MUX_MODE_2), + TNETV107X_MUX_CFG(26, 20, MUX_MODE_1), + TNETV107X_MUX_CFG(26, 20, MUX_MODE_2), + TNETV107X_MUX_CFG(26, 25, MUX_MODE_1), + TNETV107X_MUX_CFG(26, 25, MUX_MODE_2), +}; + +const int pin_table_size = sizeof(pin_table) / sizeof(pin_table[0]); + +int mux_select_pin(short index) +{ + const struct pin_config *cfg; + unsigned long mask, mode, reg; + + if (index >= pin_table_size) + return 0; + + cfg = &pin_table[index]; + + mask = 0x1f << cfg->mask_offset; + mode = cfg->mode << cfg->mask_offset; + + reg = __raw_readl(TNETV107X_PINMUX(cfg->reg_index)); + reg = (reg & ~mask) | mode; + __raw_writel(reg, TNETV107X_PINMUX(cfg->reg_index)); + + return 1; +} + +int mux_select_pins(const short *pins) +{ + int i, ret = 1; + + for (i = 0; pins[i] >= 0; i++) + ret &= mux_select_pin(pins[i]); + + return ret; +} diff --git a/arch/arm/cpu/arm1176/tnetv107x/timer.c b/arch/arm/cpu/arm1176/tnetv107x/timer.c new file mode 100644 index 0000000000..a7a400d1e1 --- /dev/null +++ b/arch/arm/cpu/arm1176/tnetv107x/timer.c @@ -0,0 +1,122 @@ +/* + * TNETV107X: Timer implementation + * + * 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 <asm/io.h> +#include <asm/arch/clock.h> + +struct timer_regs { + u_int32_t pid12; + u_int32_t pad[3]; + 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; +}; + +#define regs ((struct timer_regs *)CONFIG_SYS_TIMERBASE) + +#define TIMER_LOAD_VAL (CONFIG_SYS_HZ_CLOCK / CONFIG_SYS_HZ) +#define TIM_CLK_DIV 16 + +static ulong timestamp; +static ulong lastinc; + +int timer_init(void) +{ + clk_enable(TNETV107X_LPSC_TIMER0); + + lastinc = timestamp = 0; + + /* We are using timer34 in unchained 32-bit mode, full speed */ + __raw_writel(0x0, ®s->tcr); + __raw_writel(0x0, ®s->tgcr); + __raw_writel(0x06 | ((TIM_CLK_DIV - 1) << 8), ®s->tgcr); + __raw_writel(0x0, ®s->tim34); + __raw_writel(TIMER_LOAD_VAL, ®s->prd34); + __raw_writel(2 << 22, ®s->tcr); + + return 0; +} + +void reset_timer(void) +{ + lastinc = timestamp = 0; + + __raw_writel(0, ®s->tcr); + __raw_writel(0, ®s->tim34); + __raw_writel(2 << 22, ®s->tcr); +} + +static ulong get_timer_raw(void) +{ + ulong now = __raw_readl(®s->tim34); + + if (now >= lastinc) + timestamp += now - lastinc; + else + timestamp += now + TIMER_LOAD_VAL - lastinc; + + lastinc = now; + + return timestamp; +} + +ulong get_timer(ulong base) +{ + return (get_timer_raw() / (TIMER_LOAD_VAL / TIM_CLK_DIV)) - base; +} + +void set_timer(ulong t) +{ + timestamp = t; +} + +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +void __udelay(unsigned long usec) +{ + ulong tmo; + ulong endtime; + signed long diff; + + tmo = CONFIG_SYS_HZ_CLOCK / 1000; + tmo *= usec; + tmo /= (1000 * TIM_CLK_DIV); + + endtime = get_timer_raw() + tmo; + + do { + ulong now = get_timer_raw(); + diff = endtime - now; + } while (diff >= 0); +} + +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/arm1176/tnetv107x/wdt.c b/arch/arm/cpu/arm1176/tnetv107x/wdt.c new file mode 100644 index 0000000000..18aadb0c65 --- /dev/null +++ b/arch/arm/cpu/arm1176/tnetv107x/wdt.c @@ -0,0 +1,180 @@ +/* + * TNETV107X: Watchdog timer implementation (for reset) + * + * 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 <asm/io.h> +#include <asm/arch/clock.h> + +#define MAX_DIV 0xFFFE0001 + +struct wdt_regs { + u32 kick_lock; +#define KICK_LOCK_1 0x5555 +#define KICK_LOCK_2 0xaaaa + u32 kick; + + u32 change_lock; +#define CHANGE_LOCK_1 0x6666 +#define CHANGE_LOCK_2 0xbbbb + u32 change; + + u32 disable_lock; +#define DISABLE_LOCK_1 0x7777 +#define DISABLE_LOCK_2 0xcccc +#define DISABLE_LOCK_3 0xdddd + u32 disable; + + u32 prescale_lock; +#define PRESCALE_LOCK_1 0x5a5a +#define PRESCALE_LOCK_2 0xa5a5 + u32 prescale; +}; + +static struct wdt_regs* regs = (struct wdt_regs *)TNETV107X_WDT0_ARM_BASE; + +#define wdt_reg_read(reg) __raw_readl(®s->reg) +#define wdt_reg_write(reg, val) __raw_writel((val), ®s->reg) + +static int write_prescale_reg(unsigned long prescale_value) +{ + wdt_reg_write(prescale_lock, PRESCALE_LOCK_1); + if ((wdt_reg_read(prescale_lock) & 0x3) != 0x1) + return -1; + + wdt_reg_write(prescale_lock, PRESCALE_LOCK_2); + if ((wdt_reg_read(prescale_lock) & 0x3) != 0x3) + return -1; + + wdt_reg_write(prescale, prescale_value); + + return 0; +} + +static int write_change_reg(unsigned long initial_timer_value) +{ + wdt_reg_write(change_lock, CHANGE_LOCK_1); + if ((wdt_reg_read(change_lock) & 0x3) != 0x1) + return -1; + + wdt_reg_write(change_lock, CHANGE_LOCK_2); + if ((wdt_reg_read(change_lock) & 0x3) != 0x3) + return -1; + + wdt_reg_write(change, initial_timer_value); + + return 0; +} + +static int wdt_control(unsigned long disable_value) +{ + wdt_reg_write(disable_lock, DISABLE_LOCK_1); + if ((wdt_reg_read(disable_lock) & 0x3) != 0x1) + return -1; + + wdt_reg_write(disable_lock, DISABLE_LOCK_2); + if ((wdt_reg_read(disable_lock) & 0x3) != 0x2) + return -1; + + wdt_reg_write(disable_lock, DISABLE_LOCK_3); + if ((wdt_reg_read(disable_lock) & 0x3) != 0x3) + return -1; + + wdt_reg_write(disable, disable_value); + return 0; +} + +static int wdt_set_period(unsigned long msec) +{ + unsigned long change_value, count_value; + unsigned long prescale_value = 1; + unsigned long refclk_khz, maxdiv; + int ret; + + refclk_khz = clk_get_rate(TNETV107X_LPSC_WDT_ARM); + maxdiv = (MAX_DIV / refclk_khz); + + if ((!msec) || (msec > maxdiv)) + return -1; + + count_value = refclk_khz * msec; + if (count_value > 0xffff) { + change_value = count_value / 0xffff + 1; + prescale_value = count_value / change_value; + } else { + change_value = count_value; + } + + ret = write_prescale_reg(prescale_value - 1); + if (ret) + return ret; + + ret = write_change_reg(change_value); + if (ret) + return ret; + + return 0; +} + +unsigned long last_wdt = -1; + +int wdt_start(unsigned long msecs) +{ + int ret; + ret = wdt_control(0); + if (ret) + return ret; + ret = wdt_set_period(msecs); + if (ret) + return ret; + ret = wdt_control(1); + if (ret) + return ret; + ret = wdt_kick(); + last_wdt = msecs; + return ret; +} + +int wdt_stop(void) +{ + last_wdt = -1; + return wdt_control(0); +} + +int wdt_kick(void) +{ + wdt_reg_write(kick_lock, KICK_LOCK_1); + if ((wdt_reg_read(kick_lock) & 0x3) != 0x1) + return -1; + + wdt_reg_write(kick_lock, KICK_LOCK_2); + if ((wdt_reg_read(kick_lock) & 0x3) != 0x3) + return -1; + + wdt_reg_write(kick, 1); + return 0; +} + +void reset_cpu(ulong addr) +{ + clk_enable(TNETV107X_LPSC_WDT_ARM); + wdt_start(1); + wdt_kick(); +} diff --git a/arch/arm/cpu/arm926ejs/orion5x/Makefile b/arch/arm/cpu/arm926ejs/orion5x/Makefile new file mode 100644 index 0000000000..11f4141bff --- /dev/null +++ b/arch/arm/cpu/arm926ejs/orion5x/Makefile @@ -0,0 +1,55 @@ +# +# Copyright (C) 2010 Albert ARIBAUD <albert.aribaud@free.fr> +# +# Based on original Kirkwood support which is +# (C) Copyright 2009 +# Marvell Semiconductor <www.marvell.com> +# Written-by: Prafulla Wadaskar <prafulla@marvell.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., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).a + +COBJS-y = cpu.o +COBJS-y += dram.o +COBJS-y += timer.o + +ifndef CONFIG_SKIP_LOWLEVEL_INIT +SOBJS := lowlevel_init.o +endif + +SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/orion5x/cpu.c b/arch/arm/cpu/arm926ejs/orion5x/cpu.c new file mode 100644 index 0000000000..c2f5253b05 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/orion5x/cpu.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.aribaud@free.fr> + * + * Based on original Kirkwood support which is + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <netdev.h> +#include <asm/cache.h> +#include <u-boot/md5.h> +#include <asm/arch/orion5x.h> +#include <hush.h> + +#define BUFLEN 16 + +void reset_cpu(unsigned long ignored) +{ + struct orion5x_cpu_registers *cpureg = + (struct orion5x_cpu_registers *)ORION5X_CPU_REG_BASE; + + writel(readl(&cpureg->rstoutn_mask) | (1 << 2), + &cpureg->rstoutn_mask); + writel(readl(&cpureg->sys_soft_rst) | 1, + &cpureg->sys_soft_rst); + while (1) + ; +} + +/* + * Window Size + * Used with the Base register to set the address window size and location. + * Must be programmed from LSB to MSB as sequence of ones followed by + * sequence of zeros. The number of ones specifies the size of the window in + * 64 KByte granularity (e.g., a value of 0x00FF specifies 256 = 16 MByte). + * NOTE: A value of 0x0 specifies 64-KByte size. + */ +unsigned int orion5x_winctrl_calcsize(unsigned int sizeval) +{ + int i; + unsigned int j = 0; + u32 val = sizeval >> 1; + + for (i = 0; val > 0x10000; i++) { + j |= (1 << i); + val = val >> 1; + } + return 0x0000ffff & j; +} + +/* + * orion5x_config_adr_windows - Configure address Windows + * + * There are 8 address windows supported by Orion5x Soc to addess different + * devices. Each window can be configured for size, BAR and remap addr + * Below configuration is standard for most of the cases + * + * If remap function not used, remap_lo must be set as base + * + * Reference Documentation: + * Mbus-L to Mbus Bridge Registers Configuration. + * (Sec 25.1 and 25.3 of Datasheet) + */ +int orion5x_config_adr_windows(void) +{ + struct orion5x_win_registers *winregs = + (struct orion5x_win_registers *)ORION5X_CPU_WIN_BASE; + + /* Window 0: PCIE MEM address space */ + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_DEFSZ_PCIE_MEM, + ORION5X_TARGET_PCIE, ORION5X_ATTR_PCIE_MEM, + ORION5X_WIN_ENABLE), &winregs[0].ctrl); + writel(ORION5X_DEFADR_PCIE_MEM, &winregs[0].base); + writel(ORION5X_DEFADR_PCIE_MEM_REMAP_LO, &winregs[0].remap_lo); + writel(ORION5X_DEFADR_PCIE_MEM_REMAP_HI, &winregs[0].remap_hi); + + /* Window 1: PCIE IO address space */ + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_DEFSZ_PCIE_IO, + ORION5X_TARGET_PCIE, ORION5X_ATTR_PCIE_IO, + ORION5X_WIN_ENABLE), &winregs[1].ctrl); + writel(ORION5X_DEFADR_PCIE_IO, &winregs[1].base); + writel(ORION5X_DEFADR_PCIE_IO_REMAP_LO, &winregs[1].remap_lo); + writel(ORION5X_DEFADR_PCIE_IO_REMAP_HI, &winregs[1].remap_hi); + + /* Window 2: PCI MEM address space */ + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_DEFSZ_PCI_MEM, + ORION5X_TARGET_PCI, ORION5X_ATTR_PCI_MEM, + ORION5X_WIN_ENABLE), &winregs[2].ctrl); + writel(ORION5X_DEFADR_PCI_MEM, &winregs[2].base); + + /* Window 3: PCI IO address space */ + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_DEFSZ_PCI_IO, + ORION5X_TARGET_PCI, ORION5X_ATTR_PCI_IO, + ORION5X_WIN_ENABLE), &winregs[3].ctrl); + writel(ORION5X_DEFADR_PCI_IO, &winregs[3].base); + + /* Window 4: DEV_CS0 address space */ + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_DEFSZ_DEV_CS0, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS0, + ORION5X_WIN_ENABLE), &winregs[4].ctrl); + writel(ORION5X_DEFADR_DEV_CS0, &winregs[4].base); + + /* Window 5: DEV_CS1 address space */ + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_DEFSZ_DEV_CS1, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS1, + ORION5X_WIN_ENABLE), &winregs[5].ctrl); + writel(ORION5X_DEFADR_DEV_CS1, &winregs[5].base); + + /* Window 6: DEV_CS2 address space */ + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_DEFSZ_DEV_CS2, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS2, + ORION5X_WIN_ENABLE), &winregs[6].ctrl); + writel(ORION5X_DEFADR_DEV_CS2, &winregs[6].base); + + /* Window 7: BOOT Memory address space */ + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_DEFSZ_BOOTROM, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_BOOTROM, + ORION5X_WIN_ENABLE), &winregs[7].ctrl); + writel(ORION5X_DEFADR_BOOTROM, &winregs[7].base); + + return 0; +} + +/* + * Orion5x identification is done through PCIE space. + */ + +u32 orion5x_device_id(void) +{ + return readl(PCIE_DEV_ID_OFF) >> 16; +} + +u32 orion5x_device_rev(void) +{ + return readl(PCIE_DEV_REV_OFF) & 0xff; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) + +/* Display device and revision IDs. + * This function must cover all known device/revision + * combinations, not only the one for which u-boot is + * compiled; this way, one can identify actual HW in + * case of a mismatch. + */ +int print_cpuinfo(void) +{ + char dev_str[] = "0x0000"; + char rev_str[] = "0x00"; + char *dev_name = NULL; + char *rev_name = NULL; + + u32 dev = orion5x_device_id(); + u32 rev = orion5x_device_rev(); + + if (dev == MV88F5181_DEV_ID) { + dev_name = "MV88F5181"; + if (rev == MV88F5181_REV_B1) + rev_name = "B1"; + else if (rev == MV88F5181L_REV_A1) { + dev_name = "MV88F5181L"; + rev_name = "A1"; + } else if (rev == MV88F5181L_REV_A0) { + dev_name = "MV88F5181L"; + rev_name = "A0"; + } + } else if (dev == MV88F5182_DEV_ID) { + dev_name = "MV88F5182"; + if (rev == MV88F5182_REV_A2) + rev_name = "A2"; + } else if (dev == MV88F5281_DEV_ID) { + dev_name = "MV88F5281"; + if (rev == MV88F5281_REV_D2) + rev_name = "D2"; + else if (rev == MV88F5281_REV_D1) + rev_name = "D1"; + else if (rev == MV88F5281_REV_D0) + rev_name = "D0"; + } else if (dev == MV88F6183_DEV_ID) { + dev_name = "MV88F6183"; + if (rev == MV88F6183_REV_B0) + rev_name = "B0"; + } + if (dev_name == NULL) { + sprintf(dev_str, "0x%04x", dev); + dev_name = dev_str; + } + if (rev_name == NULL) { + sprintf(rev_str, "0x%02x", rev); + rev_name = rev_str; + } + + printf("SoC: Orion5x %s-%s\n", dev_name, rev_name); + + return 0; +} +#endif /* CONFIG_DISPLAY_CPUINFO */ + +#ifdef CONFIG_ARCH_CPU_INIT +int arch_cpu_init(void) +{ + /* Enable and invalidate L2 cache in write through mode */ + invalidate_l2_cache(); + + orion5x_config_adr_windows(); + + return 0; +} +#endif /* CONFIG_ARCH_CPU_INIT */ + +/* + * SOC specific misc init + */ +#if defined(CONFIG_ARCH_MISC_INIT) +int arch_misc_init(void) +{ + u32 temp; + + /*CPU streaming & write allocate */ + temp = readfr_extra_feature_reg(); + temp &= ~(1 << 28); /* disable wr alloc */ + writefr_extra_feature_reg(temp); + + temp = readfr_extra_feature_reg(); + temp &= ~(1 << 29); /* streaming disabled */ + writefr_extra_feature_reg(temp); + + /* L2Cache settings */ + temp = readfr_extra_feature_reg(); + /* Disable L2C pre fetch - Set bit 24 */ + temp |= (1 << 24); + /* enable L2C - Set bit 22 */ + temp |= (1 << 22); + writefr_extra_feature_reg(temp); + + icache_enable(); + /* Change reset vector to address 0x0 */ + temp = get_cr(); + set_cr(temp & ~CR_V); + + /* Set CPIOs and MPPs - values provided by board + include file */ + writel(ORION5X_MPP_BASE+0x00, ORION5X_MPP0_7); + writel(ORION5X_MPP_BASE+0x04, ORION5X_MPP8_15); + writel(ORION5X_MPP_BASE+0x50, ORION5X_MPP16_23); + writel(ORION5X_GPIO_BASE+0x04, ORION5X_GPIO_OUT_ENABLE); + + return 0; +} +#endif /* CONFIG_ARCH_MISC_INIT */ diff --git a/arch/arm/cpu/arm926ejs/orion5x/dram.c b/arch/arm/cpu/arm926ejs/orion5x/dram.c new file mode 100644 index 0000000000..c719798a66 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/orion5x/dram.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.aribaud@free.fr> + * + * Based on original Kirkwood support which is + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <config.h> +#include <asm/arch/orion5x.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * orion5x_sdram_bar - reads SDRAM Base Address Register + */ +u32 orion5x_sdram_bar(enum memory_bank bank) +{ + struct orion5x_ddr_addr_decode_registers *winregs = + (struct orion5x_ddr_addr_decode_registers *) + ORION5X_CPU_WIN_BASE; + + u32 result = 0; + u32 enable = 0x01 & winregs[bank].size; + + if ((!enable) || (bank > BANK3)) + return 0; + + result = winregs[bank].base; + return result; +} + +int dram_init(void) +{ + int i; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + gd->bd->bi_dram[i].start = orion5x_sdram_bar(i); + gd->bd->bi_dram[i].size = get_ram_size( + (volatile long *) (gd->bd->bi_dram[i].start), + CONFIG_MAX_RAM_BANK_SIZE); + } + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/orion5x/lowlevel_init.S b/arch/arm/cpu/arm926ejs/orion5x/lowlevel_init.S new file mode 100644 index 0000000000..b0e15f6e23 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/orion5x/lowlevel_init.S @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.aribaud@free.fr> + * + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <config.h> +#include "asm/arch/orion5x.h" + +/* + * Configuration values for SDRAM access setup + */ + +#define SDRAM_CONFIG 0x3148400 +#define SDRAM_MODE 0x62 +#define SDRAM_CONTROL 0x4041000 +#define SDRAM_TIME_CTRL_LOW 0x11602220 +#define SDRAM_TIME_CTRL_HI 0x40c +#define SDRAM_OPEN_PAGE_EN 0x0 +/* DDR 1 2x 32M NANYA NT5DS16M16CS-6K ==> 64MB */ +#define SDRAM_BANK0_SIZE 0x3ff0001 +#define SDRAM_ADDR_CTRL 0x10 + +#define SDRAM_OP_NOP 0x05 +#define SDRAM_OP_SETMODE 0x03 + +#define SDRAM_PAD_CTRL_WR_EN 0x80000000 +#define SDRAM_PAD_CTRL_TUNE_EN 0x00010000 +#define SDRAM_PAD_CTRL_DRVN_MASK 0x0000003f +#define SDRAM_PAD_CTRL_DRVP_MASK 0x00000fc0 + +/* + * For Guideline MEM-3 - Drive Strength value + */ + +#define DDR1_PAD_STRENGTH_DEFAULT 0x00001000 +#define SDRAM_PAD_CTRL_DRV_STR_MASK 0x00003000 + +/* + * For Guideline MEM-4 - DQS Reference Delay Tuning + */ + +#define MSAR_ARMDDRCLCK_MASK 0x000000f0 +#define MSAR_ARMDDRCLCK_H_MASK 0x00000100 + +#define MSAR_ARMDDRCLCK_333_167 0x00000000 +#define MSAR_ARMDDRCLCK_500_167 0x00000030 +#define MSAR_ARMDDRCLCK_667_167 0x00000060 +#define MSAR_ARMDDRCLCK_400_200_1 0x000001E0 +#define MSAR_ARMDDRCLCK_400_200 0x00000010 +#define MSAR_ARMDDRCLCK_600_200 0x00000050 +#define MSAR_ARMDDRCLCK_800_200 0x00000070 + +#define FTDLL_DDR1_166MHZ 0x0047F001 + +#define FTDLL_DDR1_200MHZ 0x0044D001 + +/* + * Low-level init happens right after start.S has switched to SVC32, + * flushed and disabled caches and disabled MMU. We're still running + * from the boot chip select, so the first thing we should do is set + * up RAM for us to relocate into. + */ + +.globl lowlevel_init + +lowlevel_init: + + /* Use 'r4 as the base for internal register accesses */ + ldr r4, =ORION5X_REGS_PHY_BASE + + /* move internal registers from the default 0xD0000000 + * to their intended location, defined by SoC */ + ldr r3, =0xD0000000 + add r3, r3, #0x20000 + str r4, [r3, #0x80] + + /* Use R3 as the base for DRAM registers */ + add r3, r4, #0x01000 + + /*DDR SDRAM Initialization Control */ + ldr r6, =0x00000001 + str r6, [r3, #0x480] + + /* Use R3 as the base for PCI registers */ + add r3, r4, #0x31000 + + /* Disable arbiter */ + ldr r6, =0x00000030 + str r6, [r3, #0xd00] + + /* Use R3 as the base for DRAM registers */ + add r3, r4, #0x01000 + + /* set all dram windows to 0 */ + mov r6, #0 + str r6, [r3, #0x504] + str r6, [r3, #0x50C] + str r6, [r3, #0x514] + str r6, [r3, #0x51C] + + /* 1) Configure SDRAM */ + ldr r6, =SDRAM_CONFIG + str r6, [r3, #0x400] + + /* 2) Set SDRAM Control reg */ + ldr r6, =SDRAM_CONTROL + str r6, [r3, #0x404] + + /* 3) Write SDRAM address control register */ + ldr r6, =SDRAM_ADDR_CTRL + str r6, [r3, #0x410] + + /* 4) Write SDRAM bank 0 size register */ + ldr r6, =SDRAM_BANK0_SIZE + str r6, [r3, #0x504] + /* keep other banks disabled */ + + /* 5) Write SDRAM open pages control register */ + ldr r6, =SDRAM_OPEN_PAGE_EN + str r6, [r3, #0x414] + + /* 6) Write SDRAM timing Low register */ + ldr r6, =SDRAM_TIME_CTRL_LOW + str r6, [r3, #0x408] + + /* 7) Write SDRAM timing High register */ + ldr r6, =SDRAM_TIME_CTRL_HI + str r6, [r3, #0x40C] + + /* 8) Write SDRAM mode register */ + /* The CPU must not attempt to change the SDRAM Mode register setting */ + /* prior to DRAM controller completion of the DRAM initialization */ + /* sequence. To guarantee this restriction, it is recommended that */ + /* the CPU sets the SDRAM Operation register to NOP command, performs */ + /* read polling until the register is back in Normal operation value, */ + /* and then sets SDRAM Mode register to its new value. */ + + /* 8.1 write 'nop' to SDRAM operation */ + ldr r6, =SDRAM_OP_NOP + str r6, [r3, #0x418] + + /* 8.2 poll SDRAM operation until back in 'normal' mode. */ +1: + ldr r6, [r3, #0x418] + cmp r6, #0 + bne 1b + + /* 8.3 Now its safe to write new value to SDRAM Mode register */ + ldr r6, =SDRAM_MODE + str r6, [r3, #0x41C] + + /* 8.4 Set new mode */ + ldr r6, =SDRAM_OP_SETMODE + str r6, [r3, #0x418] + + /* 8.5 poll SDRAM operation until back in 'normal' mode. */ +2: + ldr r6, [r3, #0x418] + cmp r6, #0 + bne 2b + + /* DDR SDRAM Address/Control Pads Calibration */ + ldr r6, [r3, #0x4C0] + + /* Set Bit [31] to make the register writable */ + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C0] + + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + bic r6, r6, #SDRAM_PAD_CTRL_TUNE_EN + bic r6, r6, #SDRAM_PAD_CTRL_DRVN_MASK + bic r6, r6, #SDRAM_PAD_CTRL_DRVP_MASK + + /* Get the final N locked value of driving strength [22:17] */ + mov r1, r6 + mov r1, r1, LSL #9 + mov r1, r1, LSR #26 /* r1[5:0]<DrvN> = r3[22:17]<LockN> */ + orr r1, r1, r1, LSL #6 /* r1[11:6]<DrvP> = r1[5:0]<DrvN> */ + + /* Write to both <DrvN> bits [5:0] and <DrvP> bits [11:6] */ + orr r6, r6, r1 + str r6, [r3, #0x4C0] + + /* DDR SDRAM Data Pads Calibration */ + ldr r6, [r3, #0x4C4] + + /* Set Bit [31] to make the register writable */ + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C4] + + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + bic r6, r6, #SDRAM_PAD_CTRL_TUNE_EN + bic r6, r6, #SDRAM_PAD_CTRL_DRVN_MASK + bic r6, r6, #SDRAM_PAD_CTRL_DRVP_MASK + + /* Get the final N locked value of driving strength [22:17] */ + mov r1, r6 + mov r1, r1, LSL #9 + mov r1, r1, LSR #26 + orr r1, r1, r1, LSL #6 /* r1[5:0] = r3[22:17]<LockN> */ + + /* Write to both <DrvN> bits [5:0] and <DrvP> bits [11:6] */ + orr r6, r6, r1 + + str r6, [r3, #0x4C4] + + /* Implement Guideline (GL# MEM-3) Drive Strength Value */ + /* Relevant for: 88F5181-A1/B0/B1 and 88F5281-A0/B0 */ + + ldr r1, =DDR1_PAD_STRENGTH_DEFAULT + + /* Enable writes to DDR SDRAM Addr/Ctrl Pads Calibration register */ + ldr r6, [r3, #0x4C0] + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C0] + + /* Correct strength and disable writes again */ + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + bic r6, r6, #SDRAM_PAD_CTRL_DRV_STR_MASK + orr r6, r6, r1 + str r6, [r3, #0x4C0] + + /* Enable writes to DDR SDRAM Data Pads Calibration register */ + ldr r6, [r3, #0x4C4] + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C4] + + /* Correct strength and disable writes again */ + bic r6, r6, #SDRAM_PAD_CTRL_DRV_STR_MASK + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + orr r6, r6, r1 + str r6, [r3, #0x4C4] + + /* Implement Guideline (GL# MEM-4) DQS Reference Delay Tuning */ + /* Relevant for: 88F5181-A1/B0/B1 and 88F5281-A0/B0 */ + + /* Get the "sample on reset" register for the DDR frequancy */ + ldr r3, =0x10000 + ldr r6, [r3, #0x010] + ldr r1, =MSAR_ARMDDRCLCK_MASK + and r1, r6, r1 + + ldr r6, =FTDLL_DDR1_166MHZ + cmp r1, #MSAR_ARMDDRCLCK_333_167 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_500_167 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_667_167 + beq 3f + + ldr r6, =FTDLL_DDR1_200MHZ + cmp r1, #MSAR_ARMDDRCLCK_400_200_1 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_400_200 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_600_200 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_800_200 + beq 3f + + ldr r6, =0 + +3: + /* Use R3 as the base for DRAM registers */ + add r3, r4, #0x01000 + + ldr r2, [r3, #0x484] + orr r2, r2, r6 + str r2, [r3, #0x484] + + /* Return to U-boot via saved link register */ + mov pc, lr diff --git a/arch/arm/cpu/arm926ejs/orion5x/timer.c b/arch/arm/cpu/arm926ejs/orion5x/timer.c new file mode 100644 index 0000000000..115448fa3f --- /dev/null +++ b/arch/arm/cpu/arm926ejs/orion5x/timer.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.aribaud@free.fr> + * + * Based on original Kirkwood support which is + * Copyright (C) Marvell International Ltd. and its affiliates + * Written-by: Prafulla Wadaskar <prafulla@marvell.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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/arch/orion5x.h> + +#define UBOOT_CNTR 0 /* counter to use for uboot timer */ + +/* Timer reload and current value registers */ +struct orion5x_tmr_val { + u32 reload; /* Timer reload reg */ + u32 val; /* Timer value reg */ +}; + +/* Timer registers */ +struct orion5x_tmr_registers { + u32 ctrl; /* Timer control reg */ + u32 pad[3]; + struct orion5x_tmr_val tmr[2]; + u32 wdt_reload; + u32 wdt_val; +}; + +struct orion5x_tmr_registers *orion5x_tmr_regs = + (struct orion5x_tmr_registers *)ORION5X_TIMER_BASE; + +/* + * ARM Timers Registers Map + */ +#define CNTMR_CTRL_REG (&orion5x_tmr_regs->ctrl) +#define CNTMR_RELOAD_REG(tmrnum) (&orion5x_tmr_regs->tmr[tmrnum].reload) +#define CNTMR_VAL_REG(tmrnum) (&orion5x_tmr_regs->tmr[tmrnum].val) + +/* + * ARM Timers Control Register + * CPU_TIMERS_CTRL_REG (CTCR) + */ +#define CTCR_ARM_TIMER_EN_OFFS(cntr) (cntr * 2) +#define CTCR_ARM_TIMER_EN_MASK(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS) +#define CTCR_ARM_TIMER_EN(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS(cntr)) +#define CTCR_ARM_TIMER_DIS(cntr) (0 << CTCR_ARM_TIMER_EN_OFFS(cntr)) + +#define CTCR_ARM_TIMER_AUTO_OFFS(cntr) ((cntr * 2) + 1) +#define CTCR_ARM_TIMER_AUTO_MASK(cntr) (1 << 1) +#define CTCR_ARM_TIMER_AUTO_EN(cntr) (1 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) +#define CTCR_ARM_TIMER_AUTO_DIS(cntr) (0 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) + +/* + * ARM Timer\Watchdog Reload Register + * CNTMR_RELOAD_REG (TRR) + */ +#define TRG_ARM_TIMER_REL_OFFS 0 +#define TRG_ARM_TIMER_REL_MASK 0xffffffff + +/* + * ARM Timer\Watchdog Register + * CNTMR_VAL_REG (TVRG) + */ +#define TVR_ARM_TIMER_OFFS 0 +#define TVR_ARM_TIMER_MASK 0xffffffff +#define TVR_ARM_TIMER_MAX 0xffffffff +#define TIMER_LOAD_VAL 0xffffffff + +static inline ulong read_timer(void) +{ + return readl(CNTMR_VAL_REG(UBOOT_CNTR)) + / (CONFIG_SYS_TCLK / 1000); +} + +static ulong timestamp; +static ulong lastdec; + +void reset_timer_masked(void) +{ + /* reset time */ + lastdec = read_timer(); + timestamp = 0; +} + +ulong get_timer_masked(void) +{ + ulong now = read_timer(); + + if (lastdec >= now) { + /* normal mode */ + timestamp += lastdec - now; + } else { + /* we have an overflow ... */ + timestamp += lastdec + + (TIMER_LOAD_VAL / (CONFIG_SYS_TCLK / 1000)) - now; + } + lastdec = now; + + return timestamp; +} + +void reset_timer(void) +{ + reset_timer_masked(); +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +void set_timer(ulong t) +{ + timestamp = t; +} + +static inline ulong uboot_cntr_val(void) +{ + return readl(CNTMR_VAL_REG(UBOOT_CNTR)); +} + +void __udelay(unsigned long usec) +{ + uint current; + ulong delayticks; + + current = uboot_cntr_val(); + delayticks = (usec * (CONFIG_SYS_TCLK / 1000000)); + + if (current < delayticks) { + delayticks -= current; + while (uboot_cntr_val() < current) + ; + while ((TIMER_LOAD_VAL - delayticks) < uboot_cntr_val()) + ; + } else { + while (uboot_cntr_val() > (current - delayticks)) + ; + } +} + +/* + * init the counter + */ +int timer_init(void) +{ + unsigned int cntmrctrl; + + /* load value into timer */ + writel(TIMER_LOAD_VAL, CNTMR_RELOAD_REG(UBOOT_CNTR)); + writel(TIMER_LOAD_VAL, CNTMR_VAL_REG(UBOOT_CNTR)); + + /* enable timer in auto reload mode */ + cntmrctrl = readl(CNTMR_CTRL_REG); + cntmrctrl |= CTCR_ARM_TIMER_EN(UBOOT_CNTR); + cntmrctrl |= CTCR_ARM_TIMER_AUTO_EN(UBOOT_CNTR); + writel(cntmrctrl, CNTMR_CTRL_REG); + + /* init the timestamp and lastdec value */ + reset_timer_masked(); + + return 0; +} diff --git a/arch/arm/cpu/arm_cortexa8/omap3/Makefile b/arch/arm/cpu/arm_cortexa8/omap3/Makefile index 136b163ad7..7d63c6beca 100644 --- a/arch/arm/cpu/arm_cortexa8/omap3/Makefile +++ b/arch/arm/cpu/arm_cortexa8/omap3/Makefile @@ -37,8 +37,11 @@ COBJS += syslib.o COBJS += sys_info.o COBJS += timer.o +COBJS-$(CONFIG_EMIF4) += emif4.o +COBJS-$(CONFIG_SDRC) += sdrc.o + SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +OBJS := $(addprefix $(obj),$(COBJS) $(COBJS-y) $(SOBJS)) all: $(obj).depend $(LIB) diff --git a/arch/arm/cpu/arm_cortexa8/omap3/board.c b/arch/arm/cpu/arm_cortexa8/omap3/board.c index 7b78fa448b..d2500ca3b2 100644 --- a/arch/arm/cpu/arm_cortexa8/omap3/board.c +++ b/arch/arm/cpu/arm_cortexa8/omap3/board.c @@ -40,8 +40,6 @@ extern omap3_sysinfo sysinfo; -extern u32 is_mem_sdr(void); - /****************************************************************************** * Routine: delay * Description: spinning delay to use before udelay works @@ -233,7 +231,7 @@ void s_init(void) per_clocks_enable(); if (!in_sdram) - sdrc_init(); + mem_init(); } /****************************************************************************** @@ -274,36 +272,6 @@ void watchdog_init(void) } /****************************************************************************** - * Routine: dram_init - * Description: sets uboots idea of sdram size - *****************************************************************************/ -int dram_init(void) -{ - DECLARE_GLOBAL_DATA_PTR; - unsigned int size0 = 0, size1 = 0; - - /* - * If a second bank of DDR is attached to CS1 this is - * where it can be started. Early init code will init - * memory on CS0. - */ - if ((sysinfo.mtype == DDR_COMBO) || (sysinfo.mtype == DDR_STACKED)) { - do_sdrc_init(CS1, NOT_EARLY); - make_cs1_contiguous(); - } - - size0 = get_sdr_cs_size(CS0); - size1 = get_sdr_cs_size(CS1); - - gd->bd->bi_dram[0].start = PHYS_SDRAM_1; - gd->bd->bi_dram[0].size = size0; - gd->bd->bi_dram[1].start = PHYS_SDRAM_1 + get_sdr_cs_offset(CS1); - gd->bd->bi_dram[1].size = size1; - - return 0; -} - -/****************************************************************************** * Dummy function to handle errors for EABI incompatibility *****************************************************************************/ void abort(void) diff --git a/arch/arm/cpu/arm_cortexa8/omap3/emif4.c b/arch/arm/cpu/arm_cortexa8/omap3/emif4.c new file mode 100644 index 0000000000..fae5b1161b --- /dev/null +++ b/arch/arm/cpu/arm_cortexa8/omap3/emif4.c @@ -0,0 +1,168 @@ +/* + * Author : + * Vaibhav Hiremath <hvaibhav@ti.com> + * + * Based on mem.c and sdrc.c + * + * Copyright (C) 2010 + * Texas Instruments Incorporated - http://www.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 + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/mem.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/emif4.h> + +extern omap3_sysinfo sysinfo; + +static emif4_t *emif4_base = (emif4_t *)OMAP34XX_SDRC_BASE; + +/* + * is_mem_sdr - + * - Return 1 if mem type in use is SDR + */ +u32 is_mem_sdr(void) +{ + return 0; +} + +/* + * get_sdr_cs_size - + * - Get size of chip select 0/1 + */ +u32 get_sdr_cs_size(u32 cs) +{ + u32 size; + + /* TODO: Calculate the size based on EMIF4 configuration */ + size = CONFIG_SYS_CS0_SIZE; + + return size; +} + +/* + * get_sdr_cs_offset - + * - Get offset of cs from cs0 start + */ +u32 get_sdr_cs_offset(u32 cs) +{ + u32 offset = 0; + + return offset; +} + +/* + * do_emif4_init - + * - Init the emif4 module for DDR access + * - Early init routines, called from flash or SRAM. + */ +void do_emif4_init(void) +{ + unsigned int regval; + /* Set the DDR PHY parameters in PHY ctrl registers */ + regval = (EMIF4_DDR1_READ_LAT | EMIF4_DDR1_PWRDN_DIS | + EMIF4_DDR1_EXT_STRB_DIS); + writel(regval, &emif4_base->ddr_phyctrl1); + writel(regval, &emif4_base->ddr_phyctrl1_shdw); + writel(0, &emif4_base->ddr_phyctrl2); + + /* Reset the DDR PHY and wait till completed */ + regval = readl(&emif4_base->sdram_iodft_tlgc); + regval |= (1<<10); + writel(regval, &emif4_base->sdram_iodft_tlgc); + /*Wait till that bit clears*/ + while ((readl(&emif4_base->sdram_iodft_tlgc) & (1<<10)) == 0x1); + /*Re-verify the DDR PHY status*/ + while ((readl(&emif4_base->sdram_sts) & (1<<2)) == 0x0); + + regval |= (1<<0); + writel(regval, &emif4_base->sdram_iodft_tlgc); + /* Set SDR timing registers */ + regval = (EMIF4_TIM1_T_WTR | EMIF4_TIM1_T_RRD | + EMIF4_TIM1_T_RC | EMIF4_TIM1_T_RAS | + EMIF4_TIM1_T_WR | EMIF4_TIM1_T_RCD | + EMIF4_TIM1_T_RP); + writel(regval, &emif4_base->sdram_time1); + writel(regval, &emif4_base->sdram_time1_shdw); + + regval = (EMIF4_TIM2_T_CKE | EMIF4_TIM2_T_RTP | + EMIF4_TIM2_T_XSRD | EMIF4_TIM2_T_XSNR | + EMIF4_TIM2_T_ODT | EMIF4_TIM2_T_XP); + writel(regval, &emif4_base->sdram_time2); + writel(regval, &emif4_base->sdram_time2_shdw); + + regval = (EMIF4_TIM3_T_RAS_MAX | EMIF4_TIM3_T_RFC); + writel(regval, &emif4_base->sdram_time3); + writel(regval, &emif4_base->sdram_time3_shdw); + + /* Set the PWR control register */ + regval = (EMIF4_PWR_PM_TIM | EMIF4_PWR_LP_MODE | + EMIF4_PWR_DPD_DIS | EMIF4_PWR_IDLE_MODE); + writel(regval, &emif4_base->sdram_pwr_mgmt); + writel(regval, &emif4_base->sdram_pwr_mgmt_shdw); + + /* Set the DDR refresh rate control register */ + regval = (EMIF4_REFRESH_RATE | EMIF4_INITREF_DIS); + writel(regval, &emif4_base->sdram_refresh_ctrl); + writel(regval, &emif4_base->sdram_refresh_ctrl_shdw); + + /* set the SDRAM configuration register */ + regval = (EMIF4_CFG_PGSIZE | EMIF4_CFG_EBANK | + EMIF4_CFG_IBANK | EMIF4_CFG_ROWSIZE | + EMIF4_CFG_CL | EMIF4_CFG_NARROW_MD | + EMIF4_CFG_SDR_DRV | EMIF4_CFG_DDR_DIS_DLL | + EMIF4_CFG_DDR2_DDQS | EMIF4_CFG_DDR_TERM | + EMIF4_CFG_IBANK_POS | EMIF4_CFG_SDRAM_TYP); + writel(regval, &emif4_base->sdram_config); +} + +/* + * dram_init - + * - Sets uboots idea of sdram size + */ +int dram_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int size0 = 0, size1 = 0; + + size0 = get_sdr_cs_size(CS0); + /* + * If a second bank of DDR is attached to CS1 this is + * where it can be started. Early init code will init + * memory on CS0. + */ + if ((sysinfo.mtype == DDR_COMBO) || (sysinfo.mtype == DDR_STACKED)) + size1 = get_sdr_cs_size(CS1); + + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = size0; + gd->bd->bi_dram[1].start = PHYS_SDRAM_1 + get_sdr_cs_offset(CS1); + gd->bd->bi_dram[1].size = size1; + + return 0; +} + +/* + * mem_init() - + * - Initialize memory subsystem + */ +void mem_init(void) +{ + do_emif4_init(); +} diff --git a/arch/arm/cpu/arm_cortexa8/omap3/mem.c b/arch/arm/cpu/arm_cortexa8/omap3/mem.c index dfb7e4c2ad..bd914b0ee5 100644 --- a/arch/arm/cpu/arm_cortexa8/omap3/mem.c +++ b/arch/arm/cpu/arm_cortexa8/omap3/mem.c @@ -79,26 +79,6 @@ static const u32 gpmc_onenand[GPMC_MAX_REG] = { #endif -static struct sdrc *sdrc_base = (struct sdrc *)OMAP34XX_SDRC_BASE; - -/************************************************************************** - * make_cs1_contiguous() - for es2 and above remap cs1 behind cs0 to allow - * command line mem=xyz use all memory with out discontinuous support - * compiled in. Could do it at the ATAG, but there really is two banks... - * Called as part of 2nd phase DDR init. - **************************************************************************/ -void make_cs1_contiguous(void) -{ - u32 size, a_add_low, a_add_high; - - size = get_sdr_cs_size(CS0); - size >>= 25; /* divide by 32 MiB to find size to offset CS1 */ - a_add_high = (size & 3) << 8; /* set up low field */ - a_add_low = (size & 0x3C) >> 2; /* set up high field */ - writel((a_add_high | a_add_low), &sdrc_base->cs_cfg); - -} - /******************************************************** * mem_ok() - test used to see if timings are correct * for a part. Helps in guessing which part @@ -123,76 +103,6 @@ u32 mem_ok(u32 cs) return 1; } -/******************************************************** - * sdrc_init() - init the sdrc chip selects CS0 and CS1 - * - early init routines, called from flash or - * SRAM. - *******************************************************/ -void sdrc_init(void) -{ - /* only init up first bank here */ - do_sdrc_init(CS0, EARLY_INIT); -} - -/************************************************************************* - * do_sdrc_init(): initialize the SDRAM for use. - * -code sets up SDRAM basic SDRC timings for CS0 - * -optimal settings can be placed here, or redone after i2c - * inspection of board info - * - * - code called once in C-Stack only context for CS0 and a possible 2nd - * time depending on memory configuration from stack+global context - **************************************************************************/ - -void do_sdrc_init(u32 cs, u32 early) -{ - struct sdrc_actim *sdrc_actim_base; - - if(cs) - sdrc_actim_base = (struct sdrc_actim *)SDRC_ACTIM_CTRL1_BASE; - else - sdrc_actim_base = (struct sdrc_actim *)SDRC_ACTIM_CTRL0_BASE; - - if (early) { - /* reset sdrc controller */ - writel(SOFTRESET, &sdrc_base->sysconfig); - wait_on_value(RESETDONE, RESETDONE, &sdrc_base->status, - 12000000); - writel(0, &sdrc_base->sysconfig); - - /* setup sdrc to ball mux */ - writel(SDRC_SHARING, &sdrc_base->sharing); - - /* Disable Power Down of CKE cuz of 1 CKE on combo part */ - writel(WAKEUPPROC | PWDNEN | SRFRONRESET | PAGEPOLICY_HIGH, - &sdrc_base->power); - - writel(ENADLL | DLLPHASE_90, &sdrc_base->dlla_ctrl); - sdelay(0x20000); - } - - writel(RASWIDTH_13BITS | CASWIDTH_10BITS | ADDRMUXLEGACY | - RAMSIZE_128 | BANKALLOCATION | B32NOT16 | B32NOT16 | - DEEPPD | DDR_SDRAM, &sdrc_base->cs[cs].mcfg); - writel(ARCV | ARE_ARCV_1, &sdrc_base->cs[cs].rfr_ctrl); - writel(V_ACTIMA_165, &sdrc_actim_base->ctrla); - writel(V_ACTIMB_165, &sdrc_actim_base->ctrlb); - - 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); - - /* - * CAS latency 3, Write Burst = Read Burst, Serial Mode, - * Burst length = 4 - */ - writel(CASL3 | BURSTLENGTH4, &sdrc_base->cs[cs].mr); - - if (!mem_ok(cs)) - writel(0, &sdrc_base->cs[cs].mcfg); -} - void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base, u32 size) { diff --git a/arch/arm/cpu/arm_cortexa8/omap3/sdrc.c b/arch/arm/cpu/arm_cortexa8/omap3/sdrc.c new file mode 100644 index 0000000000..96fd990c71 --- /dev/null +++ b/arch/arm/cpu/arm_cortexa8/omap3/sdrc.c @@ -0,0 +1,202 @@ +/* + * Functions related to OMAP3 SDRC. + * + * This file has been created after exctracting and consolidating + * the SDRC related content from mem.c and board.c, also created + * generic init function (mem_init). + * + * Copyright (C) 2004-2010 + * Texas Instruments Incorporated - http://www.ti.com/ + * + * Author : + * Vaibhav Hiremath <hvaibhav@ti.com> + * + * Original implementation by (mem.c, board.c) : + * Sunil Kumar <sunilsaini05@gmail.com> + * Shashi Ranjan <shashiranjanmca05@gmail.com> + * Manikandan Pillai <mani.pillai@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 + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/mem.h> +#include <asm/arch/sys_proto.h> + +extern omap3_sysinfo sysinfo; + +static struct sdrc *sdrc_base = (struct sdrc *)OMAP34XX_SDRC_BASE; + +/* + * is_mem_sdr - + * - Return 1 if mem type in use is SDR + */ +u32 is_mem_sdr(void) +{ + if (readl(&sdrc_base->cs[CS0].mr) == SDRC_MR_0_SDR) + return 1; + return 0; +} + +/* + * make_cs1_contiguous - + * - For es2 and above remap cs1 behind cs0 to allow command line + * mem=xyz use all memory with out discontinuous support compiled in. + * Could do it at the ATAG, but there really is two banks... + * - Called as part of 2nd phase DDR init. + */ +void make_cs1_contiguous(void) +{ + u32 size, a_add_low, a_add_high; + + size = get_sdr_cs_size(CS0); + size >>= 25; /* divide by 32 MiB to find size to offset CS1 */ + a_add_high = (size & 3) << 8; /* set up low field */ + a_add_low = (size & 0x3C) >> 2; /* set up high field */ + writel((a_add_high | a_add_low), &sdrc_base->cs_cfg); + +} + + +/* + * get_sdr_cs_size - + * - Get size of chip select 0/1 + */ +u32 get_sdr_cs_size(u32 cs) +{ + u32 size; + + /* get ram size field */ + size = readl(&sdrc_base->cs[cs].mcfg) >> 8; + size &= 0x3FF; /* remove unwanted bits */ + size <<= 21; /* multiply by 2 MiB to find size in MB */ + return size; +} + +/* + * get_sdr_cs_offset - + * - Get offset of cs from cs0 start + */ +u32 get_sdr_cs_offset(u32 cs) +{ + u32 offset; + + if (!cs) + return 0; + + offset = readl(&sdrc_base->cs_cfg); + offset = (offset & 15) << 27 | (offset & 0x30) >> 17; + + return offset; +} + +/* + * do_sdrc_init - + * - Initialize the SDRAM for use. + * - Sets up SDRC timings for CS0 + * - code called once in C-Stack only context for CS0 and a possible 2nd + * time depending on memory configuration from stack+global context + */ +void do_sdrc_init(u32 cs, u32 early) +{ + struct sdrc_actim *sdrc_actim_base; + + if (cs) + sdrc_actim_base = (struct sdrc_actim *)SDRC_ACTIM_CTRL1_BASE; + else + sdrc_actim_base = (struct sdrc_actim *)SDRC_ACTIM_CTRL0_BASE; + + if (early) { + /* reset sdrc controller */ + writel(SOFTRESET, &sdrc_base->sysconfig); + wait_on_value(RESETDONE, RESETDONE, &sdrc_base->status, + 12000000); + writel(0, &sdrc_base->sysconfig); + + /* setup sdrc to ball mux */ + writel(SDRC_SHARING, &sdrc_base->sharing); + + /* Disable Power Down of CKE cuz of 1 CKE on combo part */ + writel(WAKEUPPROC | SRFRONRESET | PAGEPOLICY_HIGH, + &sdrc_base->power); + + writel(ENADLL | DLLPHASE_90, &sdrc_base->dlla_ctrl); + sdelay(0x20000); + } + + writel(RASWIDTH_13BITS | CASWIDTH_10BITS | ADDRMUXLEGACY | + RAMSIZE_128 | BANKALLOCATION | B32NOT16 | B32NOT16 | + DEEPPD | DDR_SDRAM, &sdrc_base->cs[cs].mcfg); + writel(ARCV | ARE_ARCV_1, &sdrc_base->cs[cs].rfr_ctrl); + writel(V_ACTIMA_165, &sdrc_actim_base->ctrla); + writel(V_ACTIMB_165, &sdrc_actim_base->ctrlb); + + 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); + + /* + * CAS latency 3, Write Burst = Read Burst, Serial Mode, + * Burst length = 4 + */ + writel(CASL3 | BURSTLENGTH4, &sdrc_base->cs[cs].mr); + + if (!mem_ok(cs)) + writel(0, &sdrc_base->cs[cs].mcfg); +} + +/* + * dram_init - + * - Sets uboots idea of sdram size + */ +int dram_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int size0 = 0, size1 = 0; + + size0 = get_sdr_cs_size(CS0); + /* + * If a second bank of DDR is attached to CS1 this is + * where it can be started. Early init code will init + * memory on CS0. + */ + if ((sysinfo.mtype == DDR_COMBO) || (sysinfo.mtype == DDR_STACKED)) { + do_sdrc_init(CS1, NOT_EARLY); + make_cs1_contiguous(); + + size1 = get_sdr_cs_size(CS1); + } + + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = size0; + gd->bd->bi_dram[1].start = PHYS_SDRAM_1 + get_sdr_cs_offset(CS1); + gd->bd->bi_dram[1].size = size1; + + return 0; +} + +/* + * mem_init - + * - Init the sdrc chip, + * - Selects CS0 and CS1, + */ +void mem_init(void) +{ + /* only init up first bank here */ + do_sdrc_init(CS0, EARLY_INIT); +} diff --git a/arch/arm/cpu/arm_cortexa8/omap3/sys_info.c b/arch/arm/cpu/arm_cortexa8/omap3/sys_info.c index 08fb32eaae..1df4401d49 100644 --- a/arch/arm/cpu/arm_cortexa8/omap3/sys_info.c +++ b/arch/arm/cpu/arm_cortexa8/omap3/sys_info.c @@ -32,7 +32,6 @@ #include <i2c.h> extern omap3_sysinfo sysinfo; -static struct sdrc *sdrc_base = (struct sdrc *)OMAP34XX_SDRC_BASE; static struct ctrl *ctrl_base = (struct ctrl *)OMAP34XX_CTRL_BASE; static char *rev_s[CPU_3XX_MAX_REV] = { "1.0", @@ -104,46 +103,6 @@ u32 get_cpu_rev(void) } } -/**************************************************** - * is_mem_sdr() - return 1 if mem type in use is SDR - ****************************************************/ -u32 is_mem_sdr(void) -{ - if (readl(&sdrc_base->cs[CS0].mr) == SDRC_MR_0_SDR) - return 1; - return 0; -} - -/*********************************************************************** - * get_cs0_size() - get size of chip select 0/1 - ************************************************************************/ -u32 get_sdr_cs_size(u32 cs) -{ - u32 size; - - /* get ram size field */ - size = readl(&sdrc_base->cs[cs].mcfg) >> 8; - size &= 0x3FF; /* remove unwanted bits */ - size <<= 21; /* multiply by 2 MiB to find size in MB */ - return size; -} - -/*********************************************************************** - * get_sdr_cs_offset() - get offset of cs from cs0 start - ************************************************************************/ -u32 get_sdr_cs_offset(u32 cs) -{ - u32 offset; - - if (!cs) - return 0; - - offset = readl(&sdrc_base->cs_cfg); - offset = (offset & 15) << 27 | (offset & 0x30) >> 17; - - return offset; -} - /*************************************************************************** * get_gpmc0_base() - Return current address hardware will be * fetching from. The below effectively gives what is correct, its a bit diff --git a/arch/arm/cpu/pxa/start.S b/arch/arm/cpu/pxa/start.S index 63ab0c591a..3989fa61bc 100644 --- a/arch/arm/cpu/pxa/start.S +++ b/arch/arm/cpu/pxa/start.S @@ -140,7 +140,10 @@ stack_setup: #ifdef CONFIG_USE_IRQ sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #endif /* CONFIG_USE_IRQ */ - sub sp, r0, #12 /* leave 3 words for abort-stack */ + sub r0, r0, #12 /* leave 3 words for abort-stack */ + bic sp, r0, #7 /* NOTE: stack MUST be aligned to */ + /* 8 bytes in case we want to use */ + /* 64bit datatypes (eg. VSPRINTF64) */ clear_bss: ldr r0, _bss_start /* find start of bss segment */ |