
Kirkwood family controllers are highly integrated SOCs based on Feroceon-88FR131/Sheeva-88SV131 cpu core.
SOC versions supported:- 1) 88F6281-A0 define CONFIG_KW88F6281_A0 2) 88F6192-A0 define CONFIG_KW88F6192_A0
Other supported features:- 1) get_random_hex() function 2) SPI port controller driver 3) PCI Express port initialization
Contributors: Yotam Admon yotam@marvell.com Michael Blostein <michaelbl@marvell.com
Reviewed-by: Ronen Shitrit rshitrit@marvell.com Signed-off-by: Prafulla Wadaskar prafulla@marvell.com --- Change log: v2: crated arch-kirkwood and moved some header files there renamed and moved spi.c to drivers/spi/ renamed and moved serial.c to drivers/serial/ doimage utility removed soc_init.S renamed as lowlevel_init.S debug prints removed
v3: lowlevel_init.S converted to lowlevel_init.c removed BITxx macros, removed entire assembly code Added CONFIG_ARCH_LOWLEVE_INIT support for arm926ejs core updated as per review comments for v2
board/Marvell/include/core.h | 4 + cpu/arm926ejs/kirkwood/Makefile | 49 +++++ cpu/arm926ejs/kirkwood/config.mk | 25 +++ cpu/arm926ejs/kirkwood/dram.c | 57 ++++++ cpu/arm926ejs/kirkwood/kwcore.c | 304 +++++++++++++++++++++++++++++ cpu/arm926ejs/kirkwood/kwcore.h | 112 +++++++++++ cpu/arm926ejs/kirkwood/lowlevel_init.c | 93 +++++++++ cpu/arm926ejs/kirkwood/timer.c | 165 ++++++++++++++++ cpu/arm926ejs/start.S | 7 +- drivers/serial/Makefile | 1 + drivers/serial/kirkwood_serial.c | 187 ++++++++++++++++++ drivers/spi/Makefile | 1 + drivers/spi/kirkwood_spi.c | 199 +++++++++++++++++++ include/asm-arm/arch-kirkwood/kirkwood.h | 140 +++++++++++++ include/asm-arm/arch-kirkwood/kw88f6192.h | 37 ++++ include/asm-arm/arch-kirkwood/kw88f6281.h | 37 ++++ include/asm-arm/config.h | 4 + 17 files changed, 1421 insertions(+), 1 deletions(-) create mode 100644 cpu/arm926ejs/kirkwood/Makefile create mode 100644 cpu/arm926ejs/kirkwood/config.mk create mode 100644 cpu/arm926ejs/kirkwood/dram.c create mode 100644 cpu/arm926ejs/kirkwood/kwcore.c create mode 100644 cpu/arm926ejs/kirkwood/kwcore.h create mode 100644 cpu/arm926ejs/kirkwood/lowlevel_init.c create mode 100644 cpu/arm926ejs/kirkwood/timer.c create mode 100644 drivers/serial/kirkwood_serial.c create mode 100644 drivers/spi/kirkwood_spi.c create mode 100644 include/asm-arm/arch-kirkwood/kirkwood.h create mode 100644 include/asm-arm/arch-kirkwood/kw88f6192.h create mode 100644 include/asm-arm/arch-kirkwood/kw88f6281.h
diff --git a/board/Marvell/include/core.h b/board/Marvell/include/core.h index c413439..ecc4682 100644 --- a/board/Marvell/include/core.h +++ b/board/Marvell/include/core.h @@ -12,9 +12,11 @@ space). The macros take care of Big/Little endian conversions. #ifndef __INCcoreh #define __INCcoreh
+#ifndef CONFIG_KIRKWOOD #include "mv_gen_reg.h"
extern unsigned int INTERNAL_REG_BASE_ADDR; +#endif /* CONFIG_KIRKWOOD */
/****************************************/ /* GENERAL Definitions */ @@ -91,10 +93,12 @@ extern unsigned int INTERNAL_REG_BASE_ADDR; #define _1G 0x40000000 #define _2G 0x80000000
+#ifndef __ASSEMBLY__ #ifndef BOOL_WAS_DEFINED #define BOOL_WAS_DEFINED typedef enum _bool{false,true} bool; #endif +#endif
/* Little to Big endian conversion macros */
diff --git a/cpu/arm926ejs/kirkwood/Makefile b/cpu/arm926ejs/kirkwood/Makefile new file mode 100644 index 0000000..9f9aed2 --- /dev/null +++ b/cpu/arm926ejs/kirkwood/Makefile @@ -0,0 +1,49 @@ +# +# (C) Copyright 2009 +# Marvell Semiconductor <www.marvell.com> +# 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 = dram.o +COBJS-y += kwcore.o +COBJS-$(CONFIG_ARCH_LOWLEVEL_INIT) += lowlevel_init.o +COBJS-y += timer.o + +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/cpu/arm926ejs/kirkwood/config.mk b/cpu/arm926ejs/kirkwood/config.mk new file mode 100644 index 0000000..000eeb4 --- /dev/null +++ b/cpu/arm926ejs/kirkwood/config.mk @@ -0,0 +1,25 @@ +# +# (C) Copyright 2009 +# Marvell Semiconductor <www.marvell.com> +# 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 +# + +PLATFORM_CPPFLAGS += -march=armv5te diff --git a/cpu/arm926ejs/kirkwood/dram.c b/cpu/arm926ejs/kirkwood/dram.c new file mode 100644 index 0000000..03f3277 --- /dev/null +++ b/cpu/arm926ejs/kirkwood/dram.c @@ -0,0 +1,57 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * 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> + +#define KW_REG_CPUCS_WIN_BAR(x) (0x1500+ (x * 0x08)) +#define KW_REG_CPUCS_WIN_SZ(x) (0x1504+ (x * 0x08)) +/* + * kw_sdram_bar - reads SDRAM Base Address Register + */ +u32 kw_sdram_bar(enum memory_bank bank) +{ + u32 result = 0; + u32 enable = 0x01 & readl(KW_REG_CPUCS_WIN_SZ(bank)); + + if ((!enable) || (bank > BANK3)) + return 0; + + result = readl(KW_REG_CPUCS_WIN_BAR(bank)); + return result; +} + +/* + * kw_sdram_bs - reads SDRAM Bank size + */ +u32 kw_sdram_bs(enum memory_bank bank) +{ + u32 result = 0; + u32 enable = 0x01 & readl(KW_REG_CPUCS_WIN_SZ(bank)); + + if ((!enable) || (bank > BANK3)) + return 0; + result = 0xff000000 & readl(KW_REG_CPUCS_WIN_SZ(bank)); + result += 0x01000000; + return result; +} diff --git a/cpu/arm926ejs/kirkwood/kwcore.c b/cpu/arm926ejs/kirkwood/kwcore.c new file mode 100644 index 0000000..df57f4c --- /dev/null +++ b/cpu/arm926ejs/kirkwood/kwcore.c @@ -0,0 +1,304 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * 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 <u-boot/md5.h> + +void reset_cpu(unsigned long ignored) +{ + writel_set_bits(KW_REG_CPU_RSTOUTN_MASK, 1<<2); + writel_set_bits(KW_REG_CPU_SYS_SOFT_RST, 1<<0); + while (1) ; +} + +/* + * Generates Ramdom hex number reading some time varient system registers + * and using md5 algorithm + */ +unsigned char get_random_hex(void) +{ + int i; + u32 inbuf[16]; + u8 outbuf[16]; + + /* + * in case of 88F6281/88F6192 A0, + * 1<<7 need to reset to generate random values in 0x1470 + * Soc reg offsets 0x1470 and 0x1478 are reserved regs and + * Does not have names at this moment (no errata available) + */ + writel_reset_bits(0x1478, 1<<7); + for (i = 0; i < 16; i++) { + inbuf[i] = readl(0x1470); + } + md5((u8 *) inbuf, 64, outbuf); + return outbuf[outbuf[7] % 0x0f]; +} + +/* + * 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 1?EUR(tm)s followed by + * sequence of 0?EUR(tm)s. The number of 1?EUR(tm)s 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. + */ +static unsigned int kw_winctrl_calcsize(unsigned int sizeval) +{ + int i; + unsigned int j = 0; + + for (i = 0; i < (sizeval / 0x10000); i++) { + j |= 1 << i; + } + return (0x0000ffff & j); +} + +/* prepares data to be loaded in win_Ctrl register */ +#define KWCPU_WIN_CTRL_DATA(size, target, attr, en) (en | target<<4 \ + | attr<<8 | kw_winctrl_calcsize(size)<<16) + +/* + * kw_window_ctrl_reg_init - Mbus-L to Mbus Bridge Registers init. + * + * Ref: Sec 25.1 and 25.3 of Datasheet + * The CPU interfaces with the device units over the Mbus-L to Mbus bridge. + * This bridge forwards CPU transactions to the device units over the Mbus, + * and forwards read responses back from the units to the CPU. + * + * NOTE: If the remap function for this register is not used, + * the <Remap> field in the Window0 Remap Low Register must be set to same + * value as the <Base> field in this register + */ +int kw_window_ctrl_reg_init(void) +{ + writel(KW_REG_WIN_CTRL(0), + KWCPU_WIN_CTRL_DATA(0xc0000, KWCPU_TARGET_PCIE, + KWCPU_ATTR_PCIE_MEM, KWCPU_WIN_ENABLE)); + + writel(KW_REG_WIN_BASE(0), 0x90000000); + writel(KW_REG_WIN_REMAP_LOW(0), 0x90000000); + writel(KW_REG_WIN_REMAP_HIGH(0), 0x00000000); + + writel(KW_REG_WIN_CTRL(1), + KWCPU_WIN_CTRL_DATA(0x70000, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_NANDFLASH, KWCPU_WIN_ENABLE)); + writel(KW_REG_WIN_BASE(1), 0xF9000000); + writel(KW_REG_WIN_REMAP_LOW(1), 0xF9000000); + writel(KW_REG_WIN_REMAP_HIGH(1), 0x00000000); + + writel(KW_REG_WIN_CTRL(2), + KWCPU_WIN_CTRL_DATA(0x80000, KWCPU_TARGET_PCIE, + KWCPU_ATTR_PCIE_IO, KWCPU_WIN_ENABLE)); + writel(KW_REG_WIN_BASE(2), 0xF0000000); + writel(KW_REG_WIN_REMAP_LOW(2), 0xC0000000); + writel(KW_REG_WIN_REMAP_HIGH(2), 0x00000000); + + writel(KW_REG_WIN_CTRL(3), + KWCPU_WIN_CTRL_DATA(0x80000, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_SPIFLASH, KWCPU_WIN_ENABLE)); + writel(KW_REG_WIN_BASE(3), 0xF8000000); + writel(KW_REG_WIN_REMAP_LOW(3), 0x00000000); + writel(KW_REG_WIN_REMAP_HIGH(3), 0x00000000); + + writel(KW_REG_WIN_CTRL(4), + KWCPU_WIN_CTRL_DATA(0x80000, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_BOOTROM, KWCPU_WIN_ENABLE)); + writel(KW_REG_WIN_BASE(4), 0xFF000000); + writel(KW_REG_WIN_REMAP_LOW(4), 0x00000000); + writel(KW_REG_WIN_REMAP_HIGH(4), 0x00000000); + + writel(KW_REG_WIN_CTRL(5), + KWCPU_WIN_CTRL_DATA(0xb0000, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_SPIFLASH, KWCPU_WIN_DISABLE)); + writel(KW_REG_WIN_BASE(5), 0xE8000000); + writel(KW_REG_WIN_REMAP_LOW(5), 0x00000000); + writel(KW_REG_WIN_REMAP_HIGH(5), 0x00000000); + + writel(KW_REG_WIN_CTRL(6), + KWCPU_WIN_CTRL_DATA(0xb0000, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_BOOTROM, KWCPU_WIN_DISABLE)); + writel(KW_REG_WIN_BASE(6), 0xF0000000); + writel(KW_REG_WIN_REMAP_LOW(6), 0x00000000); + writel(KW_REG_WIN_REMAP_HIGH(6), 0x00000000); + + writel(KW_REG_WIN_CTRL(7), + KWCPU_WIN_CTRL_DATA(0x0, KWCPU_TARGET_SASRAM, KWCPU_ATTR_SASRAM, + KWCPU_WIN_ENABLE)); + writel(KW_REG_WIN_BASE(7), 0xFB000000); + writel(KW_REG_WIN_REMAP_LOW(7), 0x00000000); + writel(KW_REG_WIN_REMAP_HIGH(7), 0x00000000); + + return KW_OK; +} + +/* + * kw_gpio_init - Init gpios for default values + */ +void kw_gpio_init(u32 gpp0_oe_val, u32 gpp1_oe_val, u32 gpp0_oe, u32 gpp1_oe) +{ + /* Init GPIOS to default values as per board requirement */ + writel(KW_REG_GPP0_DATA_OUT, gpp0_oe_val); + writel(KW_REG_GPP1_DATA_OUT, gpp1_oe_val); + writel(KW_REG_GPP0_DATA_OUT_EN, gpp0_oe); + writel(KW_REG_GPP1_DATA_OUT_EN, gpp1_oe); +} + +/* + * kw_mpp_control_init - initialize mpp for board specific functionality + */ +int kw_mpp_control_init(u32 mpp0_7, u32 mpp8_15, u32 mpp16_23, u32 mpp24_31, + u32 mpp32_39, u32 mpp40_47, u32 mpp48_55) +{ + /* program mpp registers */ + writel(KW_REG_MPP_CONTROL0, mpp0_7); + writel(KW_REG_MPP_CONTROL1, mpp8_15); + writel(KW_REG_MPP_CONTROL2, mpp16_23); + writel(KW_REG_MPP_CONTROL3, mpp24_31); + writel(KW_REG_MPP_CONTROL4, mpp32_39); + writel(KW_REG_MPP_CONTROL5, mpp40_47); + writel(KW_REG_MPP_CONTROL6, mpp48_55); + return KW_OK; +} + +char *kwsoc_name(void) +{ + switch (readl(KW_REG_DEVICE_ID) & 0x03) { + case 1: + return ("88F6192_A0"); + break; + case 2: + return ("88F6281_A0"); + break; + default: + return ("Unknown"); + } +} + +/* + * kw_misc_init_r - SOC specific misc init (mainly cache initialization) + */ +int kw_misc_init_r(void) +{ + char *env; + volatile unsigned int temp; + + printf("SoC: %s\n", kwsoc_name()); + + /*CPU streaming & write allocate */ + env = getenv("enaWrAllo"); + temp = readfr_extra_feature_reg(); + if (env && ((strcmp(env, "yes") == 0) || (strcmp(env, "Yes") == 0))) + temp |= 1<<28; /*Enable wr alloc */ + else + temp &= ~1<<28; /*disable wr alloc */ + writefr_extra_feature_reg(temp); + + env = getenv("enaCpuStream"); + temp = readfr_extra_feature_reg(); + if (!env || (strcmp(env, "no") == 0) || (strcmp(env, "No") == 0)) + temp &= ~1<<29; /* streaming disabled */ + else + temp |= 1<<29; /*streaming enabled */ + writefr_extra_feature_reg(temp); + + /* Verify write allocate and streaming */ + printf("\n"); + temp = readfr_extra_feature_reg(); + if (temp & 1<<29) + printf("Streaming enabled\n"); + else + printf("Streaming disabled\n"); + if (temp & 1<<28) + printf("Write allocate enabled\n"); + else + printf("Write allocate disabled\n"); + + /* DCache Pref */ + env = getenv("enaDCPref"); + if (env && ((strcmp(env, "yes") == 0) || (strcmp(env, "Yes") == 0))) { + temp = readl(KW_REG_CPU_CONFIG); + temp |= 1<<17; /* Set CCR_DCACH_PREF_BUF_ENABLE */ + writel(KW_REG_CPU_CONFIG, temp); + } + + if (env && ((strcmp(env, "no") == 0) || (strcmp(env, "No") == 0))) { + temp = readl(KW_REG_CPU_CONFIG); + temp &= ~1<<17; /* Reset CCR_DCACH_PREF_BUF_ENABLE */ + writel(KW_REG_CPU_CONFIG, temp); + } + + /* ICache Pref */ + env = getenv("enaICPref"); + if (env && ((strcmp(env, "yes") == 0) || (strcmp(env, "Yes") == 0))) { + temp = readl(KW_REG_CPU_CONFIG); + temp |= 1<<16; /* Set CCR_ICACH_PREF_BUF_ENABLE */ + writel(KW_REG_CPU_CONFIG, temp); + } + + if (env && ((strcmp(env, "no") == 0) || (strcmp(env, "No") == 0))) { + temp = readl(KW_REG_CPU_CONFIG); + temp &= ~1<<16; /* Reset CCR_ICACH_PREF_BUF_ENABLE */ + writel(KW_REG_CPU_CONFIG, temp); + } + /* Set L2C WT mode - Set bit 4 */ + temp = readl(KW_REG_CPU_L2_CONFIG); + env = getenv("setL2CacheWT"); + if (!env || ((strcmp(env, "yes") == 0) || (strcmp(env, "Yes") == 0))) { + temp |= 1<<4; + } else + temp &= ~1<<4; + writel(KW_REG_CPU_L2_CONFIG, temp); + + /* L2Cache settings */ + asm("mrc p15, 1, %0, c15, c1, 0":"=r"(temp)); + + /* Disable L2C pre fetch - Set bit 24 */ + env = getenv("disL2Prefetch"); + if (env && ((strcmp(env, "no") == 0) || (strcmp(env, "No") == 0))) + temp &= ~1<<24; + else + temp |= 1<<24; + + /* enable L2C - Set bit 22 */ + env = getenv("disL2Cache"); + if (!env || ((strcmp(env, "no") == 0) || (strcmp(env, "No") == 0))) + temp |= 1<<22; + else + temp &= ~1<<22; + + asm("mcr p15, 1, %0, c15, c1, 0": :"r"(temp)); + + /* Enable i cache */ + asm("mrc p15, 0, %0, c1, c0, 0":"=r"(temp)); + temp |= 1<<12; + asm("mcr p15, 0, %0, c1, c0, 0": :"r"(temp)); + /* Change reset vector to address 0x0 */ + asm("mrc p15, 0, %0, c1, c0, 0":"=r"(temp)); + temp &= ~1<<13; + asm("mcr p15, 0, %0, c1, c0, 0": :"r"(temp)); + + return (0); +} + diff --git a/cpu/arm926ejs/kirkwood/kwcore.h b/cpu/arm926ejs/kirkwood/kwcore.h new file mode 100644 index 0000000..feec86b --- /dev/null +++ b/cpu/arm926ejs/kirkwood/kwcore.h @@ -0,0 +1,112 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * 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 + */ + +#ifndef _KWCORE_H +#define _KWCORE_H + +#include <asm/system.h> + +#ifndef __ASSEMBLY__ +enum memory_bank { + BANK0, + BANK1, + BANK2, + BANK3 +}; + +enum kwcpu_winen { + KWCPU_WIN_DISABLE, + KWCPU_WIN_ENABLE +}; + +enum kwcpu_target { + KWCPU_TARGET_RESERVED, + KWCPU_TARGET_MEMORY, + KWCPU_TARGET_1RESERVED, + KWCPU_TARGET_SASRAM, + KWCPU_TARGET_PCIE +}; + +enum kwcpu_attrib { + KWCPU_ATTR_SASRAM = 0x01, + KWCPU_ATTR_NANDFLASH = 0x2f, + KWCPU_ATTR_SPIFLASH = 0x1e, + KWCPU_ATTR_BOOTROM = 0x1d, + KWCPU_ATTR_PCIE_IO = 0xe0, + KWCPU_ATTR_PCIE_MEM = 0xe8 +}; + +/* + * read feroceon/sheeva core extra feature register + * using co-proc instruction + */ +static inline unsigned int readfr_extra_feature_reg(void) +{ + unsigned int val; + asm volatile ("mrc p15, 1, %0, c15, c1, 0 @ readfr exfr" + : "=r" (val) : : "cc"); + return val; +} + +/* + * write feroceon/sheeva core extra feature register + * using co-proc instruction + */ +static inline void writefr_extra_feature_reg(unsigned int val) +{ + asm volatile("mcr p15, 1, %0, c15, c1, 0 @ writefr exfr" + : : "r" (val) : "cc"); + isb(); +} + +/* + * Invalidate L2 Cache using co-proc instruction + */ +static inline void invalidate_l2_cache(void) +{ + unsigned int val=0; + + asm volatile("mcr p15, 1, %0, c15, c11, 0 @ invl l2 cache" + : : "r" (val) : "cc"); + isb(); +} + +/* + * functions + */ +void reset_cpu(unsigned long ignored); +unsigned char get_random_hex(void); +unsigned int kw_sdram_bar(enum memory_bank bank); +unsigned int kw_sdram_bs(enum memory_bank bank); +int kw_window_ctrl_reg_init(void); +void kw_gpio_init(unsigned int gpp0_oe_val, unsigned int gpp1_oe_val, + unsigned int gpp0_oe, unsigned int gpp1_oe); +int kw_mpp_control_init(unsigned int mpp0_7, unsigned int mpp8_15, + unsigned int mpp16_23, unsigned int mpp24_31, + unsigned int mpp32_39, unsigned int mpp40_47, + unsigned int mpp48_55); +int kw_misc_init_r(void); +#endif /* __ASSEMBLY__ */ + +#endif /* _KWCORE_H */ diff --git a/cpu/arm926ejs/kirkwood/lowlevel_init.c b/cpu/arm926ejs/kirkwood/lowlevel_init.c new file mode 100644 index 0000000..21bfc81 --- /dev/null +++ b/cpu/arm926ejs/kirkwood/lowlevel_init.c @@ -0,0 +1,93 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * 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> + +void kw_cpu_if_pre_init(void) +{ + u32 reg; + +#ifdef CONFIG_KIRKWOOD_RGMII_PAD_1V8 + /* + * Configures the I/O voltage of the pads connected to Egigabit + * Ethernet interface to 1.8V + * By defult it is set to 3.3V + */ + reg = readl(KW_REG_MPP_OUT_DRV_REG); + reg |= 1 << 7; + writel(KW_REG_MPP_OUT_DRV_REG, ®); +#endif +#ifdef CONFIG_KIRKWOOD_EGIGA_INIT + /* + * Set egiga port0/1 in normal functional mode + * This is required becasue on kirkwood by default ports are in reset mode + * OS egiga driver may not have provision to set them in normal mode + * and if u-boot is build without network support, network may fail at OS level + */ + reg = readl((KW_EGIGA0_BASE + 0x44c)); /* PORT_SERIAL_CONTROL1_REG */ + reg &= ~(1 << 4); /* Clear PortReset Bit */ + writel((KW_EGIGA0_BASE + 0x44c), ®); /* PORT_SERIAL_CONTROL1_REG */ + reg = readl((KW_EGIGA1_BASE + 0x44c)); /* PORT_SERIAL_CONTROL1_REG */ + reg &= ~(1 << 4); /* Clear PortReset Bit */ + writel((KW_EGIGA1_BASE + 0x44c), ®); /* PORT_SERIAL_CONTROL1_REG */ +#endif +#ifdef CONFIG_KIRKWOOD_PCIE_INIT + /* + * Enable PCI Express Port0 + */ + reg = readl(KW_REG_CPU_CTRL_STAT); + reg |= 1 << 0; /* Set PEX0En Bit */ + writel(KW_REG_CPU_CTRL_STAT, ®); +#endif +} + +void kw_enable_invalidate_l2_cache(void) +{ + u32 reg; + + /* Enable L2 cache in write through mode */ + reg = readl(KW_REG_CPU_L2_CONFIG); + reg |= 0x18; + writel(KW_REG_CPU_L2_CONFIG, reg); + /* Read operation to make sure the L2 bit is set */ + reg = readl(KW_REG_CPU_L2_CONFIG); + + invalidate_l2_cache(); +} + +void arch_lowlevel_init(void) +{ + /* Linux expects` the internal registers to be at 0xf1000000 */ + writel(KW_REGS_PHY_BASE, KW_OFFSET_REG); + + /* Enable L2 cache in write through mode */ + kw_enable_invalidate_l2_cache(); + + /* + * kw_cpu_if_pre_init contains + * Initialize BUS-L to DDR configuration parameters + * so must be done prior to DDR operation + */ + kw_cpu_if_pre_init(); +} diff --git a/cpu/arm926ejs/kirkwood/timer.c b/cpu/arm926ejs/kirkwood/timer.c new file mode 100644 index 0000000..c6e1a26 --- /dev/null +++ b/cpu/arm926ejs/kirkwood/timer.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * 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> + +#define UBOOT_CNTR 0 /* counter to use for uboot timer */ + +/* + * ARM Timers Registers Map + */ +#define CNTMR_CTRL_REG KW_REG_TMR_CTRL +#define CNTMR_RELOAD_REG(tmrnum) (KW_REG_TMR_RELOAD + tmrnum*8) +#define CNTMR_VAL_REG(tmrnum) (KW_REG_TMR_VAL + tmrnum*8) + +/* + * ARM Timers Control Register + * CPU_TIMERS_CTRL_REG (CTCR) + */ +#define TIMER0_NUM 0 +#define TIMER1_NUM 1 +#define WATCHDOG_NUM 2 + +#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 + +/* This enumerator describe counters\watchdog numbers */ +typedef enum _kwCntmrID { + TIMER0 = 0, + TIMER1, + WATCHDOG +} KW_CNTMR_ID; + +#define READ_TIMER (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; +} + +void udelay(unsigned long usec) +{ + uint current; + ulong delayticks; + + current = readl(CNTMR_VAL_REG(UBOOT_CNTR)); + delayticks = (usec * (CONFIG_SYS_TCLK / 1000000)); + + if (current < delayticks) { + delayticks -= current; + while (readl(CNTMR_VAL_REG(UBOOT_CNTR)) < current) ; + while ((TIMER_LOAD_VAL - delayticks) < + readl(CNTMR_VAL_REG(UBOOT_CNTR))) ; + } else { + while (readl(CNTMR_VAL_REG(UBOOT_CNTR)) > + (current - delayticks)) ; + } +} + +/* + * init the counter + */ +int timer_init(void) +{ + unsigned int cntmrCtrl; + + /* load value onto counter\timer */ + writel(CNTMR_RELOAD_REG(UBOOT_CNTR), TIMER_LOAD_VAL); + writel(CNTMR_VAL_REG(UBOOT_CNTR), TIMER_LOAD_VAL); + + /* set the counter to load in the first time */ + writel(CNTMR_VAL_REG(UBOOT_CNTR), TIMER_LOAD_VAL); + + /* set control for timer \ cunter and enable */ + /* read control register */ + cntmrCtrl = readl(CNTMR_CTRL_REG); + cntmrCtrl |= CTCR_ARM_TIMER_EN(UBOOT_CNTR); /* enable cnt\timer */ + cntmrCtrl |= CTCR_ARM_TIMER_AUTO_EN(UBOOT_CNTR); /* Auto mode */ + + writel(CNTMR_CTRL_REG, cntmrCtrl); + + /* init the timestamp and lastdec value */ + reset_timer_masked(); + + return 0; +} diff --git a/cpu/arm926ejs/start.S b/cpu/arm926ejs/start.S index ed4932a..520dcef 100644 --- a/cpu/arm926ejs/start.S +++ b/cpu/arm926ejs/start.S @@ -201,7 +201,7 @@ _start_armboot: * ************************************************************************* */ -#ifndef CONFIG_SKIP_LOWLEVEL_INIT +#if !defined (CONFIG_SKIP_LOWLEVEL_INIT) || defined (CONFIG_ARCH_LOWLEVEL_INIT) cpu_init_crit: /* * flush v4 I/D caches @@ -224,7 +224,12 @@ cpu_init_crit: * Go setup Memory and board specific bits prior to relocation. */ mov ip, lr /* perserve link reg across call */ +#ifdef CONFIG_ARCH_LOWLEVEL_INIT + bl arch_lowlevel_init /* go setup arch specific init */ +#endif /* CONFIG_ARCH_LOWLEVEL_INIT */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl lowlevel_init /* go setup pll,mux,memory */ +#endif /* CONFIG_SKIP_LOWLEVEL_INIT */ mov lr, ip /* restore link */ mov pc, lr /* back to my caller */ #endif /* CONFIG_SKIP_LOWLEVEL_INIT */ diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index bb99a34..dd59ff8 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -28,6 +28,7 @@ LIB := $(obj)libserial.a COBJS-$(CONFIG_ARM_DCC) += arm_dcc.o COBJS-$(CONFIG_AT91RM9200_USART) += at91rm9200_usart.o COBJS-$(CONFIG_ATMEL_USART) += atmel_usart.o +COBJS-$(CONFIG_KIRKWOOD) += kirkwood_serial.o COBJS-$(CONFIG_MCFUART) += mcfuart.o COBJS-$(CONFIG_NS9750_UART) += ns9750_serial.o COBJS-$(CONFIG_SYS_NS16550) += ns16550.o diff --git a/drivers/serial/kirkwood_serial.c b/drivers/serial/kirkwood_serial.c new file mode 100644 index 0000000..6422ab2 --- /dev/null +++ b/drivers/serial/kirkwood_serial.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * 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> + +/* registers feilds */ +#define FCR_FIFO_EN 1<<0 /* fifo enable */ +#define FCR_RXSR 1<<1 /* receiver soft reset */ +#define FCR_TXSR 1<<2 /* transmitter soft reset */ +#define MCR_RTS 1<<1 /* ready to send */ + +#define LCR_WLS_OFFS 0 +#define LCR_WLS_MASK 0x3 << LCR_WLS_OFFS /* character length mask */ +#define LCR_WLS_5 0x0 << LCR_WLS_OFFS /* 5 bit character length */ +#define LCR_WLS_6 0x1 << LCR_WLS_OFFS /* 6 bit character length */ +#define LCR_WLS_7 0x2 << LCR_WLS_OFFS /* 7 bit character length */ +#define LCR_WLS_8 0x3 << LCR_WLS_OFFS /* 8 bit character length */ +#define LCR_STP_OFFS 2 +#define LCR_1_STB 0x0 << LCR_STP_OFFS /* Number of stop Bits */ +#define LCR_2_STB 0x1 << LCR_STP_OFFS /* Number of stop Bits */ +#define LCR_PEN 0x8 /* Parity enable */ +#define LCR_PS_OFFS 4 +#define LCR_EPS 0x1 << LCR_PS_OFFS /* Even Parity Select */ +#define LCR_OPS 0x0 << LCR_PS_OFFS /* Odd Parity Select */ +#define LCR_SBRK_OFFS 0x6 +#define LCR_SBRK 0x1 << LCR_SBRK_OFFS /* Set Break */ +#define LCR_DIVL_OFFS 7 +#define LCR_DIVL_EN 0x1 << LCR_DIVL_OFFS /* Divisior latch enable */ + +#define LSR_DR 1<<0 /* Data ready */ +#define LSR_OE 1<<1 /* Overrun */ +#define LSR_PE 1<<2 /* Parity error */ +#define LSR_FE 1<<3 /* Framing error */ +#define LSR_BI 1<<4 /* Break */ +#define LSR_THRE 1<<5 /* Xmit holding register empty */ +#define LSR_TEMT 1<<6 /* Xmitter empty */ +#define LSR_ERR 1<<7 /* Error */ + +/* useful defaults for LCR*/ +#define LCR_8N1 LCR_WLS_8 | LCR_1_STB + +/* This structure describes the registers offsets for one UART port/channel */ +typedef struct kwUartPort { + u8 rbr; /* 0 = 0-3 */ + u8 pad1[3]; + u8 ier; /* 1 = 4-7 */ + u8 pad2[3]; + u8 fcr; /* 2 = 8-b */ + u8 pad3[3]; + u8 lcr; /* 3 = c-f */ + u8 pad4[3]; + u8 mcr; /* 4 = 10-13 */ + u8 pad5[3]; + u8 lsr; /* 5 = 14-17 */ + u8 pad6[3]; + u8 msr; /* 6 =18-1b */ + u8 pad7[3]; + u8 scr; /* 7 =1c-1f */ + u8 pad8[3]; +} kw_uart_port; + +/* aliases - for registers which has the same offsets */ +#define thr rbr +#define iir fcr +#define dll rbr +#define dlm ier + +/* static variables */ +#if defined (CONFIG_CONS_INDEX) /* comes from board config */ +#if (CONFIG_CONS_INDEX == 0 ) +static volatile kw_uart_port *p_uart_port = (void *)KW_REGISTER(KW_UART0_BASE); +#elif (CONFIG_CONS_INDEX == 1 ) +static volatile kw_uart_port *p_uart_port = (void *)KW_REGISTER(KW_UART1_BASE); +#endif +#else +#error CONFIG_CONS_INDEX not defined correctly +#endif + +#define CONFIG_KW_UART_PORTS { (void *)KW_UART0_BASE, \ + (void *)KW_UART1_BASE } + +/* + * Serial init banner is kept simplest one + * if required can be created good one + */ +int serial_init(void) +{ + serial_setbrg(); + printf + ("\n*************************************************************"); + return (0); +} + +void kwUartPutc(u8 c) +{ + while ((p_uart_port->lsr & LSR_THRE) == 0) ; + p_uart_port->thr = c; + return; +} + +void serial_putc(const char c) +{ + if (c == '\n') + kwUartPutc('\r'); + + kwUartPutc(c); +} + +int serial_getc(void) +{ + while ((p_uart_port->lsr & LSR_DR) == 0) ; + return (p_uart_port->rbr); +} + +int serial_tstc(void) +{ + return ((p_uart_port->lsr & LSR_DR) != 0); +} + +void serial_setbrg(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + int clock_divisor = (CONFIG_SYS_TCLK / 16) / gd->baudrate; + + p_uart_port->ier = 0x00; + p_uart_port->lcr = LCR_DIVL_EN; /* Access baud rate */ + p_uart_port->dll = clock_divisor & 0xff; /* 9600 baud */ + p_uart_port->dlm = (clock_divisor >> 8) & 0xff; + p_uart_port->lcr = LCR_8N1; /* 8 data, 1 stop, no parity */ + /* Clear & enable FIFOs */ + p_uart_port->fcr = FCR_FIFO_EN | FCR_RXSR | FCR_TXSR; + return; +} + +void serial_puts(const char *s) +{ + while (*s) { + serial_putc(*s++); + } +} + +#ifdef CONFIG_CMD_KGDB +void kgdb_serial_init(void) +{ +} + +void putDebugChar(int c) +{ + serial_putc(c); +} + +void putDebugStr(const char *str) +{ + serial_puts(str); +} + +int getDebugChar(void) +{ + return serial_getc(); +} + +void kgdb_interruptible(int yes) +{ + return; +} +#endif /* CONFIG_CMD_KGDB */ diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 1350f3e..7ffa47d 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -28,6 +28,7 @@ LIB := $(obj)libspi.a COBJS-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o +COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c new file mode 100644 index 0000000..a884ac1 --- /dev/null +++ b/drivers/spi/kirkwood_spi.c @@ -0,0 +1,199 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Prafulla Wadaskar prafulla@marvell.com + * + * Derived from drivers/spi/mpc8xxx_spi.c + * + * 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 <malloc.h> +#include <spi.h> + +/* SPI Registers on kirkwood SOC */ +#define KW_REG_SPI_CTRL (0x10600) +#define KW_REG_SPI_CONFIG (0x10604) +#define KW_REG_SPI_DATA_OUT (0x10608) +#define KW_REG_SPI_DATA_IN (0x1060c) +#define KW_REG_SPI_IRQ_CAUSE (0x10610) +#define KW_REG_SPI_IRQ_MASK (0x10614) + +#define KW_SPI_TIMEOUT 10000 + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct spi_slave *slave; + u32 data; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + slave = malloc(sizeof(struct spi_slave)); + if (!slave) + return NULL; + + slave->bus = bus; + slave->cs = cs; + + writel(KW_REG_SPI_CTRL, 0x00000002); + /* program spi clock prescaller using max_hz */ + data = ((CONFIG_SYS_TCLK / 2) / max_hz) & 0x0000000f; + debug("data = 0x%08x \n", data); + writel(KW_REG_SPI_CONFIG, 0x00000210 | data); + writel(KW_REG_SPI_IRQ_CAUSE, 0x00000001); + writel(KW_REG_SPI_IRQ_MASK, 0x00000000); + + /* program mpp registers to select SPI_CSn */ + if (cs) + writel(KW_REG_MPP_CONTROL0, + ((readl(KW_REG_MPP_CONTROL0) & 0x0fffffff) | + 0x20000000)); + else + writel(KW_REG_MPP_CONTROL0, + ((readl(KW_REG_MPP_CONTROL0) & 0xfffffff0) | + 0x00000002)); + + return slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ +} + +#ifndef CONFIG_SPI_CS_IS_VALID +/* + * you can define this function board specific + * define above CONFIG in board specific config file and + * provide the function in board specific src file + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return (bus == 0 && (cs == 0 || cs == 1)); +} +#endif + +void spi_cs_activate(struct spi_slave *slave) +{ + writel_set_bits(KW_REG_SPI_CTRL, 1<<0); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + writel_reset_bits(KW_REG_SPI_CTRL, 1<<0); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + unsigned int tmpdout, tmpdin; + int tm, isRead = 0; + + debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", + slave->bus, slave->cs, dout, din, bitlen); + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + /* + * handle data in 8-bit chunks + * TBD: 2byte xfer mode to be enabled + */ + while (bitlen > 4) { + debug("loopstart bitlen %d\n", bitlen); + tmpdout = 0; + if (1) { //bitlen <= 8) { + /*1 byte xfer mode */ + writel_reset_bits(KW_REG_SPI_CONFIG, 1<<5); + /* Shift data so it's msb-justified */ + if (dout) { + tmpdout = *(u32 *) dout & 0x0ff; + } + } else { + /*2 byte xfer mode */ + writel_set_bits(KW_REG_SPI_CONFIG, 1<<5); + /* Shift data so it's msb-justified */ + if (dout) { + tmpdout = *(u32 *) dout & 0x0ffff; + } + } + + writel(KW_REG_SPI_IRQ_CAUSE, 0x0); /* clear bit */ + writel(KW_REG_SPI_DATA_OUT, tmpdout); /* Write the data out */ + debug("*** spi_xfer: ... %08x written, bitlen %d\n", + tmpdout, bitlen); + + /* + * Wait for SPI transmit to get out + * or time out (1 second = 1000 ms) + * The NE event must be read and cleared first + */ + for (tm = 0, isRead = 0; tm < KW_SPI_TIMEOUT; ++tm) { + if (readl(KW_REG_SPI_IRQ_CAUSE)) { + isRead = 1; + tmpdin = readl(KW_REG_SPI_DATA_IN); + debug + ("*** spi_xfer: din %08X ... %08x read\n", + din, tmpdin); + + if (1) { //bitlen <= 8) { + if (din) { + *((u8 *) din) = (u8) tmpdin; + din += 1; + } + if (dout) + dout += 1; + bitlen -= 8; + } else { + if (din) { + *((u16 *) din) = (u16) tmpdin; + din += 1; + } + if (dout) + dout += 1; + bitlen -= 16; + } + } + if (isRead) + break; + } + if (tm >= KW_SPI_TIMEOUT) + printf + ("*** spi_xfer: Time out during SPI transfer\n"); + + debug("loopend bitlen %d\n", bitlen); + } + + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + return 0; +} diff --git a/include/asm-arm/arch-kirkwood/kirkwood.h b/include/asm-arm/arch-kirkwood/kirkwood.h new file mode 100644 index 0000000..f07aa64 --- /dev/null +++ b/include/asm-arm/arch-kirkwood/kirkwood.h @@ -0,0 +1,140 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Prafulla Wadaskar prafulla@marvell.com + * + * Header file for the Marvell's Feroceon CPU core. + * + * 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 + */ + +#ifndef _ASM_ARCH_KIRKWOOD_H +#define _ASM_ARCH_KIRKWOOD_H + +#if defined (__ARMEL__) +#define LE +#else +#define BE +#endif /* __ARMEL__ */ + +#ifndef __ASSEMBLY__ +#include <asm-arm/types.h> +#endif /* __ASSEMBLY__ */ +#include <../board/Marvell/include/core.h> + +#if defined (CONFIG_FEROCEON_88FR131) || defined (CONFIG_SHEEVA_88SV131) +#if defined (CONFIG_KIRKWOOD) +#include <../cpu/arm926ejs/kirkwood/kwcore.h> + +/* SOC specific definations */ +#define INTREG_BASE 0xd0000000 +#define KW_REGISTER(x) (KW_REGS_PHY_BASE | x) +#define KW_OFFSET_REG (INTREG_BASE | 0x20080) + +#define KW_UART0_BASE (0x12000) /* UArt 0 */ +#define KW_UART1_BASE (0x13000) /* UArt 1 */ + +/* Controler environment registers offsets */ +#define KW_REG_MPP_CONTROL0 (0x10000) +#define KW_REG_MPP_CONTROL1 (0x10004) +#define KW_REG_MPP_CONTROL2 (0x10008) +#define KW_REG_MPP_CONTROL3 (0x1000C) +#define KW_REG_MPP_CONTROL4 (0x10010) +#define KW_REG_MPP_CONTROL5 (0x10014) +#define KW_REG_MPP_CONTROL6 (0x10018) +#define KW_REG_MPP_SMPL_AT_RST (0x10030) +#define KW_REG_DEVICE_ID (0x10034) +#define KW_REG_MPP_OUT_DRV_REG (0x100E0) + +#define KW_REG_GPP0_DATA_OUT (0x10100) +#define KW_REG_GPP0_DATA_OUT_EN (0x10104) +#define KW_REG_GPP0_BLINK_EN (0x10108) +#define KW_REG_GPP0_DATA_IN_POL (0x1010C) +#define KW_REG_GPP0_DATA_IN (0x10110) +#define KW_REG_GPP0_INT_CAUSE (0x10114) +#define KW_REG_GPP0_INT_MASK (0x10118) +#define KW_REG_GPP0_INT_LVL (0x1011c) + +#define KW_REG_GPP1_DATA_OUT (0x10140) +#define KW_REG_GPP1_DATA_OUT_EN (0x10144) +#define KW_REG_GPP1_BLINK_EN (0x10148) +#define KW_REG_GPP1_DATA_IN_POL (0x1014C) +#define KW_REG_GPP1_DATA_IN (0x10150) +#define KW_REG_GPP1_INT_CAUSE (0x10154) +#define KW_REG_GPP1_INT_MASK (0x10158) +#define KW_REG_GPP1_INT_LVL (0x1015c) + +#define KW_REG_NAND_READ_PARAM (0x10418) +#define KW_REG_NAND_WRITE_PARAM (0x1041c) +#define KW_REG_NAND_CTRL (0x10470) + +#define KW_REG_WIN_CTRL(x) (0x20000+(x*0x10)) +#define KW_REG_WIN_BASE(x) (0x20004+(x*0x10)) +#define KW_REG_WIN_REMAP_LOW(x) (0x20008+(x*0x10)) +#define KW_REG_WIN_REMAP_HIGH(x) (0x2000c+(x*0x10)) + +#define KW_REG_CPU_CONFIG (0x20100) +#define KW_REG_CPU_CTRL_STAT (0x20104) +#define KW_REG_CPU_RSTOUTN_MASK (0x20108) +#define KW_REG_CPU_SYS_SOFT_RST (0x2010C) +#define KW_REG_CPU_AHB_MBUS_CAUSE_INT (0x20110) +#define KW_REG_CPU_AHB_MBUS_MASK_INT (0x20114) +#define KW_REG_CPU_FTDLL_CONFIG (0x20120) +#define KW_REG_CPU_L2_CONFIG (0x20128) +#define KW_REG_L2_RAM_TIMING0 (0x20134) +#define KW_REG_L2_RAM_TIMING1 (0x20138) + +#define KW_REG_TMR_CTRL (0x20300) +#define KW_REG_TMR_RELOAD (0x20310) +#define KW_REG_TMR_VAL (0x20314) + +#define KW_REG_PCIE_BASE (0x40000) + +/* + * Macros + * CPU architecture dependent I/O read/write + */ +#define writel(addr, data) \ + (*((volatile unsigned int*)(KW_REGISTER(addr))) \ + = (unsigned int)WORD_SWAP((data))) + +#define readl(addr) \ + (WORD_SWAP(*((volatile unsigned int*)(KW_REGISTER(addr))))) + +#define writel_set_bits(adr, bits) (writel(adr, readl(adr)\ + | ((unsigned int)WORD_SWAP(bits)))) + +#define writel_reset_bits(adr, bits) (writel(adr, readl(adr)\ + & ~((unsigned int)WORD_SWAP(bits)))) + +/* + * Error codes + */ +#define KW_ERROR (-1) +#define KW_OK (0) + +#if defined (CONFIG_KW88F6281) +#include "kw88f6281.h" +#endif /* CONFIG_KW88F6281 */ +#if defined (CONFIG_KW88F6192) +#include "kw88f6192.h" +#endif /* CONFIG_KW88F6192 */ +#endif /* CONFIG_KIRKWOOD */ +#endif /* CONFIG_FEROCEON_88FR131 */ +#endif /* _ASM_ARCH_KIRKWOOD_H */ diff --git a/include/asm-arm/arch-kirkwood/kw88f6192.h b/include/asm-arm/arch-kirkwood/kw88f6192.h new file mode 100644 index 0000000..000fc16 --- /dev/null +++ b/include/asm-arm/arch-kirkwood/kw88f6192.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Prafulla Wadaskar prafulla@marvell.com + * + * Header file for Feroceon CPU core 88FR131 Based KW88F6192 SOC. + * + * 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 + */ + +#ifndef _CONFIG_KW88F6192_H +#define _CONFIG_KW88F6192_H + +/* SOC specific definations */ +#define KW88F6192_REGS_PHYS_BASE 0xf1000000 +#define KW_REGS_PHY_BASE KW88F6192_REGS_PHYS_BASE + +/* TCLK Core Clock defination */ +#define CONFIG_SYS_TCLK 166000000 /* 166MHz */ + +#endif /* _CONFIG_KW88F6192_H */ diff --git a/include/asm-arm/arch-kirkwood/kw88f6281.h b/include/asm-arm/arch-kirkwood/kw88f6281.h new file mode 100644 index 0000000..270d931 --- /dev/null +++ b/include/asm-arm/arch-kirkwood/kw88f6281.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Prafulla Wadaskar prafulla@marvell.com + * + * Header file for Feroceon CPU core 88FR131 Based KW88F6281 SOC. + * + * 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 + */ + +#ifndef _ASM_ARCH_KW88F6281_H +#define _ASM_ARCH_KW88F6281_H + +/* SOC specific definations */ +#define KW88F6281_REGS_PHYS_BASE 0xf1000000 +#define KW_REGS_PHY_BASE KW88F6281_REGS_PHYS_BASE + +/* TCLK Core Clock defination*/ +#define CONFIG_SYS_TCLK 200000000 /* 200MHz */ + +#endif /* _ASM_ARCH_KW88F6281_H */ diff --git a/include/asm-arm/config.h b/include/asm-arm/config.h index 049c44e..5d52f15 100644 --- a/include/asm-arm/config.h +++ b/include/asm-arm/config.h @@ -21,4 +21,8 @@ #ifndef _ASM_CONFIG_H_ #define _ASM_CONFIG_H_
+#if defined (CONFIG_KIRKWOOD) +#include <asm-arm/arch-kirkwood/kirkwood.h> +#endif /* CONFIG_KIRKWOOD */ + #endif -- 1.5.3.4