[U-Boot] [PATCH v3] Marvell Kirkwood family SOC support

Prafulla Wadaskar prafulla at marvell.com
Thu Apr 23 16:16:30 CEST 2009


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 at marvell.com>
Michael Blostein <michaelbl at marvell.com

Reviewed-by: Ronen Shitrit <rshitrit at marvell.com>
Signed-off-by: Prafulla Wadaskar <prafulla at 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 at 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 at 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 at 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 at 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 at 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 at 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, &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), &reg); /* 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), &reg); /* 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, &reg);
+#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 at 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 at 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 at 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 at 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 at 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 at 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


More information about the U-Boot mailing list