summaryrefslogtreecommitdiff
path: root/board
diff options
context:
space:
mode:
authorGary Jennejohn <garyj@pollux.denx.de>2007-01-24 12:16:56 +0100
committerGary Jennejohn <garyj@pollux.denx.de>2007-01-24 12:16:56 +0100
commit6bd2447ee47ee23c18d2b3c7ccd5a20f7626f5b3 (patch)
treeb002914fc995346cb06a8f79dbb100c5e9164cd6 /board
parentb78bb469f536b357ee21c54f40201dbe4b201ac3 (diff)
downloadu-boot-imx-6bd2447ee47ee23c18d2b3c7ccd5a20f7626f5b3.zip
u-boot-imx-6bd2447ee47ee23c18d2b3c7ccd5a20f7626f5b3.tar.gz
u-boot-imx-6bd2447ee47ee23c18d2b3c7ccd5a20f7626f5b3.tar.bz2
Add port for the lpc2292sodimm evaluation board from EmbeddedArtists
Diffstat (limited to 'board')
-rw-r--r--board/lpc2292sodimm/Makefile58
-rw-r--r--board/lpc2292sodimm/config.mk31
-rw-r--r--board/lpc2292sodimm/eth.c884
-rw-r--r--board/lpc2292sodimm/flash.c477
-rw-r--r--board/lpc2292sodimm/iap_entry.S7
-rw-r--r--board/lpc2292sodimm/lowlevel_init.S87
-rw-r--r--board/lpc2292sodimm/lpc2292sodimm.c62
-rw-r--r--board/lpc2292sodimm/mmc.c154
-rw-r--r--board/lpc2292sodimm/mmc_hw.c233
-rw-r--r--board/lpc2292sodimm/mmc_hw.h29
-rw-r--r--board/lpc2292sodimm/spi.c40
-rw-r--r--board/lpc2292sodimm/spi.h84
-rw-r--r--board/lpc2292sodimm/u-boot.lds55
13 files changed, 2201 insertions, 0 deletions
diff --git a/board/lpc2292sodimm/Makefile b/board/lpc2292sodimm/Makefile
new file mode 100644
index 0000000..5a30198
--- /dev/null
+++ b/board/lpc2292sodimm/Makefile
@@ -0,0 +1,58 @@
+#
+# (C) Copyright 2002
+# Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+# Marius Groeger <mgroeger@sysgo.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = lib$(BOARD).a
+
+OBJS := lpc2292sodimm.o flash.o mmc.o spi.o mmc_hw.o eth.o
+SOBJS := lowlevel_init.o iap_entry.o
+
+$(LIB): $(OBJS) $(SOBJS)
+ $(AR) crv $@ $(OBJS) $(SOBJS)
+
+# this MUST be compiled as thumb code!
+iap_entry.o:
+ arm-linux-gcc -D__ASSEMBLY__ -g -Os -fno-strict-aliasing \
+ -fno-common -ffixed-r8 -msoft-float -D__KERNEL__ \
+ -DTEXT_BASE=0x81500000 -I/home/garyj/proj/LPC/u-boot/include \
+ -fno-builtin -ffreestanding -nostdinc -isystem \
+ /opt/eldk/arm/usr/bin/../lib/gcc/arm-linux/4.0.0/include -pipe \
+ -DCONFIG_ARM -D__ARM__ -march=armv4t -mtune=arm7tdmi -mabi=apcs-gnu \
+ -c -o iap_entry.o iap_entry.S
+
+clean:
+ rm -f $(SOBJS) $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak .depend
+
+#########################################################################
+
+.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
+ $(CC) -M $(CPPFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@
+
+-include .depend
+
+#########################################################################
diff --git a/board/lpc2292sodimm/config.mk b/board/lpc2292sodimm/config.mk
new file mode 100644
index 0000000..4146dac
--- /dev/null
+++ b/board/lpc2292sodimm/config.mk
@@ -0,0 +1,31 @@
+#
+# (C) Copyright 2000
+# Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+# Marius Groeger <mgroeger@sysgo.de>
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+#address where u-boot will be relocated
+#TEXT_BASE = 0x0
+TEXT_BASE = 0x81500000
+
diff --git a/board/lpc2292sodimm/eth.c b/board/lpc2292sodimm/eth.c
new file mode 100644
index 0000000..14bec19
--- /dev/null
+++ b/board/lpc2292sodimm/eth.c
@@ -0,0 +1,884 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <asm/arch/hardware.h>
+#include "spi.h"
+
+/*
+ * Control Registers in Bank 0
+ */
+
+#define CTL_REG_ERDPTL 0x00
+#define CTL_REG_ERDPTH 0x01
+#define CTL_REG_EWRPTL 0x02
+#define CTL_REG_EWRPTH 0x03
+#define CTL_REG_ETXSTL 0x04
+#define CTL_REG_ETXSTH 0x05
+#define CTL_REG_ETXNDL 0x06
+#define CTL_REG_ETXNDH 0x07
+#define CTL_REG_ERXSTL 0x08
+#define CTL_REG_ERXSTH 0x09
+#define CTL_REG_ERXNDL 0x0A
+#define CTL_REG_ERXNDA 0x0B
+#define CTL_REG_ERXRDPTL 0x0C
+#define CTL_REG_ERXRDPTH 0x0D
+#define CTL_REG_ERXWRPTL 0x0E
+#define CTL_REG_ERXWRPTH 0x0F
+#define CTL_REG_EDMASTL 0x10
+#define CTL_REG_EDMASTH 0x11
+#define CTL_REG_EDMANDL 0x12
+#define CTL_REG_EDMANDH 0x13
+#define CTL_REG_EDMADSTL 0x14
+#define CTL_REG_EDMADSTH 0x15
+#define CTL_REG_EDMACSL 0x16
+#define CTL_REG_EDMACSH 0x17
+/* these are common in all banks */
+#define CTL_REG_EIE 0x1B
+#define CTL_REG_EIR 0x1C
+#define CTL_REG_ESTAT 0x1D
+#define CTL_REG_ECON2 0x1E
+#define CTL_REG_ECON1 0x1F
+
+/*
+ * Control Registers in Bank 1
+ */
+
+#define CTL_REG_EHT0 0x00
+#define CTL_REG_EHT1 0x01
+#define CTL_REG_EHT2 0x02
+#define CTL_REG_EHT3 0x03
+#define CTL_REG_EHT4 0x04
+#define CTL_REG_EHT5 0x05
+#define CTL_REG_EHT6 0x06
+#define CTL_REG_EHT7 0x07
+#define CTL_REG_EPMM0 0x08
+#define CTL_REG_EPMM1 0x09
+#define CTL_REG_EPMM2 0x0A
+#define CTL_REG_EPMM3 0x0B
+#define CTL_REG_EPMM4 0x0C
+#define CTL_REG_EPMM5 0x0D
+#define CTL_REG_EPMM6 0x0E
+#define CTL_REG_EPMM7 0x0F
+#define CTL_REG_EPMCSL 0x10
+#define CTL_REG_EPMCSH 0x11
+#define CTL_REG_EPMOL 0x14
+#define CTL_REG_EPMOH 0x15
+#define CTL_REG_EWOLIE 0x16
+#define CTL_REG_EWOLIR 0x17
+#define CTL_REG_ERXFCON 0x18
+#define CTL_REG_EPKTCNT 0x19
+
+/*
+ * Control Registers in Bank 2
+ */
+
+#define CTL_REG_MACON1 0x00
+#define CTL_REG_MACON2 0x01
+#define CTL_REG_MACON3 0x02
+#define CTL_REG_MACON4 0x03
+#define CTL_REG_MABBIPG 0x04
+#define CTL_REG_MAIPGL 0x06
+#define CTL_REG_MAIPGH 0x07
+#define CTL_REG_MACLCON1 0x08
+#define CTL_REG_MACLCON2 0x09
+#define CTL_REG_MAMXFLL 0x0A
+#define CTL_REG_MAMXFLH 0x0B
+#define CTL_REG_MAPHSUP 0x0D
+#define CTL_REG_MICON 0x11
+#define CTL_REG_MICMD 0x12
+#define CTL_REG_MIREGADR 0x14
+#define CTL_REG_MIWRL 0x16
+#define CTL_REG_MIWRH 0x17
+#define CTL_REG_MIRDL 0x18
+#define CTL_REG_MIRDH 0x19
+
+/*
+ * Control Registers in Bank 3
+ */
+
+#define CTL_REG_MAADR1 0x00
+#define CTL_REG_MAADR0 0x01
+#define CTL_REG_MAADR3 0x02
+#define CTL_REG_MAADR2 0x03
+#define CTL_REG_MAADR5 0x04
+#define CTL_REG_MAADR4 0x05
+#define CTL_REG_EBSTSD 0x06
+#define CTL_REG_EBSTCON 0x07
+#define CTL_REG_EBSTCSL 0x08
+#define CTL_REG_EBSTCSH 0x09
+#define CTL_REG_MISTAT 0x0A
+#define CTL_REG_EREVID 0x12
+#define CTL_REG_ECOCON 0x15
+#define CTL_REG_EFLOCON 0x17
+#define CTL_REG_EPAUSL 0x18
+#define CTL_REG_EPAUSH 0x19
+
+
+/*
+ * PHY Register
+ */
+
+#define PHY_REG_PHID1 0x02
+#define PHY_REG_PHID2 0x03
+
+
+/*
+ * Receive Filter Register (ERXFCON) bits
+ */
+
+#define ENC_RFR_UCEN 0x80
+#define ENC_RFR_ANDOR 0x40
+#define ENC_RFR_CRCEN 0x20
+#define ENC_RFR_PMEN 0x10
+#define ENC_RFR_MPEN 0x08
+#define ENC_RFR_HTEN 0x04
+#define ENC_RFR_MCEN 0x02
+#define ENC_RFR_BCEN 0x01
+
+/*
+ * ECON1 Register Bits
+ */
+
+#define ENC_ECON1_TXRST 0x80
+#define ENC_ECON1_RXRST 0x40
+#define ENC_ECON1_DMAST 0x20
+#define ENC_ECON1_CSUMEN 0x10
+#define ENC_ECON1_TXRTS 0x08
+#define ENC_ECON1_RXEN 0x04
+#define ENC_ECON1_BSEL1 0x02
+#define ENC_ECON1_BSEL0 0x01
+
+/*
+ * ECON2 Register Bits
+ */
+#define ENC_ECON2_AUTOINC 0x80
+#define ENC_ECON2_PKTDEC 0x40
+#define ENC_ECON2_PWRSV 0x20
+#define ENC_ECON2_VRPS 0x08
+
+/*
+ * EIR Register Bits
+ */
+#define ENC_EIR_PKTIF 0x40
+#define ENC_EIR_DMAIF 0x20
+#define ENC_EIR_LINKIF 0x10
+#define ENC_EIR_TXIF 0x08
+#define ENC_EIR_WOLIF 0x04
+#define ENC_EIR_TXERIF 0x02
+#define ENC_EIR_RXERIF 0x01
+
+/*
+ * ESTAT Register Bits
+ */
+
+#define ENC_ESTAT_INT 0x80
+#define ENC_ESTAT_LATECOL 0x10
+#define ENC_ESTAT_RXBUSY 0x04
+#define ENC_ESTAT_TXABRT 0x02
+#define ENC_ESTAT_CLKRDY 0x01
+
+/*
+ * EIE Register Bits
+ */
+
+#define ENC_EIE_INTIE 0x80
+#define ENC_EIE_PKTIE 0x40
+#define ENC_EIE_DMAIE 0x20
+#define ENC_EIE_LINKIE 0x10
+#define ENC_EIE_TXIE 0x08
+#define ENC_EIE_WOLIE 0x04
+#define ENC_EIE_TXERIE 0x02
+#define ENC_EIE_RXERIE 0x01
+
+/*
+ * MACON1 Register Bits
+ */
+#define ENC_MACON1_LOOPBK 0x10
+#define ENC_MACON1_TXPAUS 0x08
+#define ENC_MACON1_RXPAUS 0x04
+#define ENC_MACON1_PASSALL 0x02
+#define ENC_MACON1_MARXEN 0x01
+
+
+/*
+ * MACON2 Register Bits
+ */
+#define ENC_MACON2_MARST 0x80
+#define ENC_MACON2_RNDRST 0x40
+#define ENC_MACON2_MARXRST 0x08
+#define ENC_MACON2_RFUNRST 0x04
+#define ENC_MACON2_MATXRST 0x02
+#define ENC_MACON2_TFUNRST 0x01
+
+/*
+ * MACON3 Register Bits
+ */
+#define ENC_MACON3_PADCFG2 0x80
+#define ENC_MACON3_PADCFG1 0x40
+#define ENC_MACON3_PADCFG0 0x20
+#define ENC_MACON3_TXCRCEN 0x10
+#define ENC_MACON3_PHDRLEN 0x08
+#define ENC_MACON3_HFRMEN 0x04
+#define ENC_MACON3_FRMLNEN 0x02
+#define ENC_MACON3_FULDPX 0x01
+
+/*
+ * MICMD Register Bits
+ */
+#define ENC_MICMD_MIISCAN 0x02
+#define ENC_MICMD_MIIRD 0x01
+
+/*
+ * MISTAT Register Bits
+ */
+#define ENC_MISTAT_NVALID 0x04
+#define ENC_MISTAT_SCAN 0x02
+#define ENC_MISTAT_BUSY 0x01
+
+/*
+ * PHID1 and PHID2 values
+ */
+#define ENC_PHID1_VALUE 0x0083
+#define ENC_PHID2_VALUE 0x1400
+#define ENC_PHID2_MASK 0xFC00
+
+
+#define ENC_SPI_SLAVE_CS 0x00010000 /* pin P1.16 */
+#define ENC_RESET 0x00020000 /* pin P1.17 */
+
+#define FAILSAFE_VALUE 5000
+
+/*
+ * Controller memory layout:
+ *
+ * 0x0000 - 0x17ff 6k bytes receive buffer
+ * 0x1800 - 0x1fff 2k bytes transmit buffer
+ */
+/* Use the lower memory for receiver buffer. See errata pt. 5 */
+#define ENC_RX_BUF_START 0x0000
+#define ENC_TX_BUF_START 0x1800
+
+/* maximum frame length */
+#define ENC_MAX_FRM_LEN 1518
+
+#define enc_enable() PUT32(IO1CLR, ENC_SPI_SLAVE_CS)
+#define enc_disable() PUT32(IO1SET, ENC_SPI_SLAVE_CS)
+#define enc_cfg_spi() spi_set_cfg(0, 0, 0); spi_set_clock(8);
+
+
+static unsigned char encReadReg(unsigned char regNo);
+static void encWriteReg(unsigned char regNo, unsigned char data);
+static void encWriteRegRetry(unsigned char regNo, unsigned char data, int c);
+static void encReadBuff(unsigned short length, unsigned char *pBuff);
+static void encWriteBuff(unsigned short length, unsigned char *pBuff);
+static void encBitSet(unsigned char regNo, unsigned char data);
+static void encBitClr(unsigned char regNo, unsigned char data);
+static void encReset(void);
+static void encInit(unsigned char *pEthAddr);
+static unsigned short phyRead(unsigned char addr);
+static void encPoll(void);
+static void encRx(void);
+
+#define m_nic_read(reg) encReadReg(reg)
+#define m_nic_write(reg, data) encWriteReg(reg, data)
+#define m_nic_write_retry(reg, data, count) encWriteRegRetry(reg, data, count)
+#define m_nic_read_data(len, buf) encReadBuff((len), (buf))
+#define m_nic_write_data(len, buf) encWriteBuff((len), (buf))
+
+/* bit field set */
+#define m_nic_bfs(reg, data) encBitSet(reg, data)
+
+/* bit field clear */
+#define m_nic_bfc(reg, data) encBitClr(reg, data)
+
+static unsigned char bank = 0; /* current bank in enc28j60 */
+static unsigned char next_pointer_lsb;
+static unsigned char next_pointer_msb;
+
+static unsigned char buffer[ENC_MAX_FRM_LEN];
+static int rxResetCounter = 0;
+#define RX_RESET_COUNTER 1000;
+
+/*-----------------------------------------------------------------------------
+ * Returns 0 when failes otherwize 1
+ */
+int eth_init(bd_t *bis)
+{
+ /* configure GPIO */
+ (*((volatile unsigned long *) IO1DIR)) |= ENC_SPI_SLAVE_CS;
+ (*((volatile unsigned long *) IO1DIR)) |= ENC_RESET;
+
+ /* CS and RESET active low */
+ PUT32(IO1SET, ENC_SPI_SLAVE_CS);
+ PUT32(IO1SET, ENC_RESET);
+
+ spi_init();
+
+ /* initialize controller */
+ encReset();
+ encInit(bis->bi_enetaddr);
+
+ m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_RXEN); /* enable receive */
+
+ return 0;
+}
+
+int eth_send(volatile void *packet, int length)
+{
+ /* check frame length, etc. */
+ /* TODO: */
+
+ /* switch to bank 0 */
+ m_nic_bfc(CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+ /* set EWRPT */
+ m_nic_write(CTL_REG_EWRPTL, (ENC_TX_BUF_START & 0xff));
+ m_nic_write(CTL_REG_EWRPTH, (ENC_TX_BUF_START >> 8));
+
+ /* set ETXST */
+ m_nic_write(CTL_REG_ETXSTL, ENC_TX_BUF_START & 0xFF);
+ m_nic_write(CTL_REG_ETXSTH, ENC_TX_BUF_START >> 8);
+
+ /* write packet */
+ m_nic_write_data(length, (unsigned char*)packet);
+
+ /* set ETXND */
+ m_nic_write(CTL_REG_ETXNDL, (length + ENC_TX_BUF_START) & 0xFF);
+ m_nic_write(CTL_REG_ETXNDH, (length + ENC_TX_BUF_START) >> 8);
+
+ /* set ECON1.TXRTS */
+ m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_TXRTS);
+
+ return 0;
+}
+
+
+/*****************************************************************************
+ * This function resets the receiver only. This function may be called from
+ * interrupt-context.
+ */
+static void encReceiverReset(void)
+{
+ unsigned char econ1;
+
+ econ1 = m_nic_read(CTL_REG_ECON1);
+ if((econ1 & ENC_ECON1_RXRST) == 0) {
+ m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_RXRST);
+ rxResetCounter = RX_RESET_COUNTER;
+ }
+}
+
+/*****************************************************************************
+ * receiver reset timer
+ */
+static void encReceiverResetCallback(void)
+{
+ m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_RXRST);
+ m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_RXEN); /* enable receive */
+}
+
+/*-----------------------------------------------------------------------------
+ * Check for received packets. Call NetReceive for each packet. The return
+ * value is ignored by the caller.
+ */
+int eth_rx(void)
+{
+ if(rxResetCounter > 0 && --rxResetCounter == 0)
+ {
+ encReceiverResetCallback();
+ }
+
+ encPoll();
+
+ return 0;
+}
+
+void eth_halt(void)
+{
+ m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_RXEN); /* disable receive */
+}
+
+/*****************************************************************************/
+
+static void encPoll(void)
+{
+ unsigned char eir_reg;
+ volatile unsigned char estat_reg;
+ unsigned char pkt_cnt;
+
+ /* clear global interrupt enable bit in enc28j60 */
+ m_nic_bfc(CTL_REG_EIE, ENC_EIE_INTIE);
+ estat_reg = m_nic_read(CTL_REG_ESTAT);
+
+ eir_reg = m_nic_read(CTL_REG_EIR);
+
+ if (eir_reg & ENC_EIR_TXIF){
+ /* clear TXIF bit in EIR */
+ m_nic_bfc(CTL_REG_EIR, ENC_EIR_TXIF);
+ }
+
+ /* We have to use pktcnt and not pktif bit, see errata pt. 6 */
+
+ /* move to bank 1 */
+ m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+ m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+
+ /* read pktcnt */
+ pkt_cnt = m_nic_read(CTL_REG_EPKTCNT);
+
+ if (pkt_cnt > 0) {
+ if ((eir_reg & ENC_EIR_PKTIF) == 0) {
+ /*printf("encPoll: pkt cnt > 0, but pktif not set\n"); */
+ }
+ encRx();
+ /* clear PKTIF bit in EIR, this should not need to be done but it
+ seems like we get problems if we do not */
+ m_nic_bfc(CTL_REG_EIR, ENC_EIR_PKTIF);
+ }
+
+ if (eir_reg & ENC_EIR_RXERIF) {
+ printf("encPoll: rx error\n");
+ m_nic_bfc(CTL_REG_EIR, ENC_EIR_RXERIF);
+ }
+ if (eir_reg & ENC_EIR_TXERIF) {
+ printf("encPoll: tx error\n");
+ m_nic_bfc(CTL_REG_EIR, ENC_EIR_TXERIF);
+ }
+
+ /* set global interrupt enable bit in enc28j60 */
+ m_nic_bfs(CTL_REG_EIE, ENC_EIE_INTIE);
+}
+
+static void encRx(void)
+{
+ unsigned short pkt_len;
+ unsigned short copy_len;
+ unsigned short status;
+ unsigned char eir_reg;
+ unsigned char pkt_cnt = 0;
+
+ /* switch to bank 0 */
+ m_nic_bfc(CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+ m_nic_write(CTL_REG_ERDPTL, next_pointer_lsb);
+ m_nic_write(CTL_REG_ERDPTH, next_pointer_msb);
+
+ do {
+ m_nic_read_data(6, buffer);
+ next_pointer_lsb = buffer[0];
+ next_pointer_msb = buffer[1];
+ pkt_len = buffer[2];
+ pkt_len |= (unsigned short)buffer[3] << 8;
+ status = buffer[4];
+ status |= (unsigned short)buffer[5] << 8;
+
+ if (pkt_len <= ENC_MAX_FRM_LEN) {
+ copy_len = pkt_len;
+ } else {
+ copy_len = 0;
+ /* p_priv->stats.rx_dropped++; */
+ /* we will drop this packet */
+ }
+
+ if ((status & (1L << 7)) == 0) { /* check Received Ok bit */
+ copy_len = 0;
+ /* p_priv->stats.rx_errors++; */
+ }
+
+ if (copy_len > 0) {
+ m_nic_read_data(copy_len, buffer);
+ }
+
+ /* advance read pointer to next pointer */
+ m_nic_write(CTL_REG_ERDPTL, next_pointer_lsb);
+ m_nic_write(CTL_REG_ERDPTH, next_pointer_msb);
+
+ /* decrease packet counter */
+ m_nic_bfs(CTL_REG_ECON2, ENC_ECON2_PKTDEC);
+
+ /* move to bank 1 */
+ m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+ m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+
+ /* read pktcnt */
+ pkt_cnt = m_nic_read(CTL_REG_EPKTCNT);
+
+ /* switch to bank 0 */
+ m_nic_bfc(CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+ if (copy_len == 0) {
+ eir_reg = m_nic_read(CTL_REG_EIR);
+ encReceiverReset();
+ printf("eth_rx: copy_len=0\n");
+ continue;
+ }
+
+ NetReceive((unsigned char *)buffer, pkt_len);
+
+ eir_reg = m_nic_read(CTL_REG_EIR);
+ } while (pkt_cnt); /* Use EPKTCNT not EIR.PKTIF flag, see errata pt. 6 */
+ m_nic_write(CTL_REG_ERXRDPTL, next_pointer_lsb);
+ m_nic_write(CTL_REG_ERXRDPTH, next_pointer_msb);
+}
+
+static void encWriteReg(unsigned char regNo, unsigned char data)
+{
+ spi_lock();
+ enc_cfg_spi();
+ enc_enable();
+
+ spi_write(0x40 | regNo); /* write in regNo */
+ spi_write(data);
+
+ enc_disable();
+ enc_enable();
+
+ spi_write(0x1f); /* write reg 0x1f */
+
+ enc_disable();
+ spi_unlock();
+}
+
+static void encWriteRegRetry(unsigned char regNo, unsigned char data, int c)
+{
+ unsigned char readback;
+ int i;
+
+ spi_lock();
+
+ for (i = 0; i < c; i++) {
+ enc_cfg_spi();
+ enc_enable();
+
+ spi_write(0x40 | regNo); /* write in regNo */
+ spi_write(data);
+
+ enc_disable();
+ enc_enable();
+
+ spi_write(0x1f); /* write reg 0x1f */
+
+ enc_disable();
+
+ spi_unlock(); /* we must unlock spi first */
+
+ readback = encReadReg(regNo);
+
+ spi_lock();
+
+ if (readback == data)
+ break;
+ }
+ spi_unlock();
+
+ if (i == c) {
+ printf("enc28j60: write reg %d failed\n", regNo);
+ }
+}
+
+static unsigned char encReadReg(unsigned char regNo)
+{
+ unsigned char rxByte;
+
+ spi_lock();
+ enc_cfg_spi();
+ enc_enable();
+
+ spi_write(0x1f); /* read reg 0x1f */
+
+ bank = spi_read() & 0x3;
+
+ enc_disable();
+ enc_enable();
+
+ spi_write(regNo);
+ rxByte = spi_read();
+
+ /* check if MAC or MII register */
+ if (((bank == 2) && (regNo <= 0x1a)) ||
+ ((bank == 3) && (regNo <= 0x05 || regNo == 0x0a))) {
+ /* ignore first byte and read another byte */
+ rxByte = spi_read();
+ }
+
+ enc_disable();
+ spi_unlock();
+
+ return rxByte;
+}
+
+static void encReadBuff(unsigned short length, unsigned char *pBuff)
+{
+ spi_lock();
+ enc_cfg_spi();
+ enc_enable();
+
+ spi_write(0x20 | 0x1a); /* read buffer memory */
+
+ while(length--) {
+ if(pBuff != NULL)
+ *pBuff++ = spi_read();
+ else
+ spi_write(0);
+ }
+
+ enc_disable();
+ spi_unlock();
+}
+
+static void encWriteBuff(unsigned short length,
+ unsigned char *pBuff)
+{
+ spi_lock();
+ enc_cfg_spi();
+ enc_enable();
+
+ spi_write(0x60 | 0x1a); /* write buffer memory */
+
+ spi_write(0x00); /* control byte */
+
+ while(length--)
+ spi_write(*pBuff++);
+
+ enc_disable();
+ spi_unlock();
+}
+
+static void encBitSet(unsigned char regNo, unsigned char data)
+{
+ spi_lock();
+ enc_cfg_spi();
+ enc_enable();
+
+ spi_write(0x80 | regNo); /* bit field set */
+ spi_write(data);
+
+ enc_disable();
+ spi_unlock();
+}
+
+static void encBitClr(unsigned char regNo, unsigned char data)
+{
+ spi_lock();
+ enc_cfg_spi();
+ enc_enable();
+
+ spi_write(0xA0 | regNo); /* bit field clear */
+ spi_write(data);
+
+ enc_disable();
+ spi_unlock();
+}
+
+static void encReset(void)
+{
+ spi_lock();
+ enc_cfg_spi();
+ enc_enable();
+
+ spi_write(0xff); /* soft reset */
+
+ enc_disable();
+ spi_unlock();
+
+ /* sleep 1 ms. See errata pt. 2 */
+ udelay(1000);
+
+#if 0
+ (*((volatile unsigned long*)IO1CLR)) &= ENC_RESET;
+ mdelay(5);
+ (*((volatile unsigned long*)IO1SET)) &= ENC_RESET;
+#endif
+}
+
+static void encInit(unsigned char *pEthAddr)
+{
+ unsigned short phid1 = 0;
+ unsigned short phid2 = 0;
+
+ /* switch to bank 0 */
+ m_nic_bfc(CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+ /*
+ * Setup the buffer space. The reset values are valid for the
+ * other pointers.
+ */
+#if 0
+ /* We shall not write to ERXST, see errata pt. 5. Instead we
+ have to make sure that ENC_RX_BUS_START is 0. */
+ m_nic_write_retry(CTL_REG_ERXSTL, (ENC_RX_BUF_START & 0xFF), 1);
+ m_nic_write_retry(CTL_REG_ERXSTH, (ENC_RX_BUF_START >> 8), 1);
+#endif
+ m_nic_write_retry(CTL_REG_ERDPTL, (ENC_RX_BUF_START & 0xFF), 1);
+ m_nic_write_retry(CTL_REG_ERDPTH, (ENC_RX_BUF_START >> 8), 1);
+
+ next_pointer_lsb = (ENC_RX_BUF_START & 0xFF);
+ next_pointer_msb = (ENC_RX_BUF_START >> 8);
+
+ /*
+ * For tracking purposes, the ERXRDPT registers should be programmed with
+ * the same value. This is the read pointer.
+ */
+ m_nic_write(CTL_REG_ERXRDPTL, (ENC_RX_BUF_START & 0xFF));
+ m_nic_write_retry(CTL_REG_ERXRDPTH, (ENC_RX_BUF_START >> 8), 1);
+
+ /* Setup receive filters. */
+
+ /* move to bank 1 */
+ m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+ m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+
+ /* OR-filtering, Unicast, CRC-check and broadcast */
+ m_nic_write_retry(CTL_REG_ERXFCON,
+ (ENC_RFR_UCEN|ENC_RFR_CRCEN|ENC_RFR_BCEN), 1);
+
+ /* Wait for Oscillator Start-up Timer (OST). */
+ while((m_nic_read(CTL_REG_ESTAT) & ENC_ESTAT_CLKRDY) == 0) {
+ static int cnt = 0;
+ if(cnt++ >= 1000){
+ cnt = 0;
+ }
+ }
+
+ /* verify identification */
+ phid1 = phyRead(PHY_REG_PHID1);
+ phid2 = phyRead(PHY_REG_PHID2);
+
+ if(phid1 != ENC_PHID1_VALUE
+ || (phid2 & ENC_PHID2_MASK) != ENC_PHID2_VALUE) {
+ printf("ERROR: failed to identify controller\n");
+ printf("phid1 = %x, phid2 = %x\n",
+ phid1, (phid2&ENC_PHID2_MASK));
+ printf("should be phid1 = %x, phid2 = %x\n",
+ ENC_PHID1_VALUE, ENC_PHID2_VALUE);
+ }
+
+ /*
+ * --- MAC Initialization ---
+ */
+
+ /* Pull MAC out of Reset */
+
+ /* switch to bank 2 */
+ m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+ m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+ /* clear MAC reset bits */
+ m_nic_write_retry(CTL_REG_MACON2, 0, 1);
+
+ /* enable MAC to receive frames */
+ m_nic_write_retry(CTL_REG_MACON1, ENC_MACON1_MARXEN, 10);
+
+ /* configure pad, tx-crc and duplex */
+ /* TODO maybe enable FRMLNEN */
+ m_nic_write_retry(CTL_REG_MACON3, (ENC_MACON3_PADCFG0|ENC_MACON3_TXCRCEN),
+ 10);
+
+ /* set maximum frame length */
+ m_nic_write_retry(CTL_REG_MAMXFLL, (ENC_MAX_FRM_LEN & 0xff), 10);
+ m_nic_write_retry(CTL_REG_MAMXFLH, (ENC_MAX_FRM_LEN >> 8), 10);
+
+ /*
+ * Set MAC back-to-back inter-packet gap. Recommended 0x12 for half duplex
+ * and 0x15 for full duplex.
+ */
+ m_nic_write_retry(CTL_REG_MABBIPG, 0x12, 10);
+
+ /* Set (low byte) Non-Back-to_Back Inter-Packet Gap. Recommended 0x12 */
+ m_nic_write_retry(CTL_REG_MAIPGL, 0x12, 10);
+
+ /*
+ * Set (high byte) Non-Back-to_Back Inter-Packet Gap. Recommended
+ * 0x0c for half-duplex. Nothing for full-duplex
+ */
+ m_nic_write_retry(CTL_REG_MAIPGH, 0x0C, 10);
+
+ /* set MAC address */
+
+ /* switch to bank 3 */
+ m_nic_bfs(CTL_REG_ECON1, (ENC_ECON1_BSEL0|ENC_ECON1_BSEL1));
+
+ m_nic_write_retry(CTL_REG_MAADR0, pEthAddr[5], 1);
+ m_nic_write_retry(CTL_REG_MAADR1, pEthAddr[4], 1);
+ m_nic_write_retry(CTL_REG_MAADR2, pEthAddr[3], 1);
+ m_nic_write_retry(CTL_REG_MAADR3, pEthAddr[2], 1);
+ m_nic_write_retry(CTL_REG_MAADR4, pEthAddr[1], 1);
+ m_nic_write_retry(CTL_REG_MAADR5, pEthAddr[0], 1);
+
+ /*
+ * Receive settings
+ */
+
+ /* auto-increment RX-pointer when reading a received packet */
+ m_nic_bfs(CTL_REG_ECON2, ENC_ECON2_AUTOINC);
+
+ /* enable interrupts */
+ m_nic_bfs(CTL_REG_EIE, ENC_EIE_PKTIE);
+ m_nic_bfs(CTL_REG_EIE, ENC_EIE_TXIE);
+ m_nic_bfs(CTL_REG_EIE, ENC_EIE_RXERIE);
+ m_nic_bfs(CTL_REG_EIE, ENC_EIE_TXERIE);
+ m_nic_bfs(CTL_REG_EIE, ENC_EIE_INTIE);
+}
+
+/*****************************************************************************
+ *
+ * Description:
+ * Read PHY registers.
+ *
+ * NOTE! This function will change to Bank 2.
+ *
+ * Params:
+ * [in] addr address of the register to read
+ *
+ * Returns:
+ * The value in the register
+ */
+static unsigned short phyRead(unsigned char addr)
+{
+ unsigned short ret = 0;
+
+ /* move to bank 2 */
+ m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+ m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+ /* write address to MIREGADR */
+ m_nic_write(CTL_REG_MIREGADR, addr);
+
+ /* set MICMD.MIIRD */
+ m_nic_write(CTL_REG_MICMD, ENC_MICMD_MIIRD);
+
+ /* poll MISTAT.BUSY bit until operation is complete */
+ while((m_nic_read(CTL_REG_MISTAT) & ENC_MISTAT_BUSY) != 0) {
+ static int cnt = 0;
+
+ if(cnt++ >= 1000) {
+ /* GJ - this seems extremely dangerous! */
+ /* printf("#"); */
+ cnt = 0;
+ }
+ }
+
+ /* clear MICMD.MIIRD */
+ m_nic_write(CTL_REG_MICMD, 0);
+
+ ret = (m_nic_read(CTL_REG_MIRDH) << 8);
+ ret |= (m_nic_read(CTL_REG_MIRDL) & 0xFF);
+
+ return ret;
+}
diff --git a/board/lpc2292sodimm/flash.c b/board/lpc2292sodimm/flash.c
new file mode 100644
index 0000000..dcef7dd
--- /dev/null
+++ b/board/lpc2292sodimm/flash.c
@@ -0,0 +1,477 @@
+/*
+ * (C) Copyright 2006 Embedded Artists AB <www.embeddedartists.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/arch/hardware.h>
+
+/* IAP commands use 32 bytes at the top of CPU internal sram, we
+ use 512 bytes below that */
+#define COPY_BUFFER_LOCATION 0x40003de0
+
+#define IAP_LOCATION 0x7ffffff1
+#define IAP_CMD_PREPARE 50
+#define IAP_CMD_COPY 51
+#define IAP_CMD_ERASE 52
+#define IAP_CMD_CHECK 53
+#define IAP_CMD_ID 54
+#define IAP_CMD_VERSION 55
+#define IAP_CMD_COMPARE 56
+
+#define IAP_RET_CMD_SUCCESS 0
+
+#define SST_BASEADDR 0x80000000
+#define SST_ADDR1 ((volatile ushort*)(SST_BASEADDR + (0x5555 << 1)))
+#define SST_ADDR2 ((volatile ushort*)(SST_BASEADDR + (0x2AAA << 1)))
+
+
+static unsigned long command[5];
+static unsigned long result[2];
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+extern void iap_entry(unsigned long * command, unsigned long * result);
+
+/*-----------------------------------------------------------------------
+ *
+ */
+int get_flash_sector(flash_info_t * info, ulong flash_addr)
+{
+ int i;
+
+ for(i=1; i < (info->sector_count); i++) {
+ if (flash_addr < (info->start[i]))
+ break;
+ }
+
+ return (i-1);
+}
+
+/*-----------------------------------------------------------------------
+ * This function assumes that flash_addr is aligned on 512 bytes boundary
+ * in flash. This function also assumes that prepare have been called
+ * for the sector in question.
+ */
+int copy_buffer_to_flash(flash_info_t * info, ulong flash_addr)
+{
+ int first_sector;
+ int last_sector;
+
+ first_sector = get_flash_sector(info, flash_addr);
+ last_sector = get_flash_sector(info, flash_addr + 512 - 1);
+
+ /* prepare sectors for write */
+ command[0] = IAP_CMD_PREPARE;
+ command[1] = first_sector;
+ command[2] = last_sector;
+ iap_entry(command, result);
+ if (result[0] != IAP_RET_CMD_SUCCESS) {
+ printf("IAP prepare failed\n");
+ return ERR_PROG_ERROR;
+ }
+
+ command[0] = IAP_CMD_COPY;
+ command[1] = flash_addr;
+ command[2] = COPY_BUFFER_LOCATION;
+ command[3] = 512;
+ command[4] = CFG_SYS_CLK_FREQ >> 10;
+ iap_entry(command, result);
+ if (result[0] != IAP_RET_CMD_SUCCESS) {
+ printf("IAP copy failed\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ *
+ */
+void write_word_sst(ulong addr, ushort data)
+{
+ ushort tmp;
+
+ *SST_ADDR1 = 0x00AA;
+ *SST_ADDR2 = 0x0055;
+ *SST_ADDR1 = 0x00A0;
+ *((volatile ushort*)addr) = data;
+ /* do data polling */
+ do {
+ tmp = *((volatile ushort*)addr);
+ } while (tmp != data);
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+ulong flash_init (void)
+{
+ int j, k;
+ ulong size = 0;
+ ulong flashbase = 0;
+
+ flash_info[0].flash_id = (PHILIPS_LPC2292 & FLASH_VENDMASK);
+ flash_info[0].size = 0x003E000; /* 256 - 8 KB */
+ flash_info[0].sector_count = 17;
+ memset (flash_info[0].protect, 0, 17);
+ flashbase = 0x00000000;
+ for (j = 0, k = 0; j < 8; j++, k++) {
+ flash_info[0].start[k] = flashbase;
+ flashbase += 0x00002000;
+ }
+ for (j = 0; j < 2; j++, k++) {
+ flash_info[0].start[k] = flashbase;
+ flashbase += 0x00010000;
+ }
+ for (j = 0; j < 7; j++, k++) {
+ flash_info[0].start[k] = flashbase;
+ flashbase += 0x00002000;
+ }
+ size += flash_info[0].size;
+
+ flash_info[1].flash_id = (SST_MANUFACT & FLASH_VENDMASK);
+ flash_info[1].size = 0x00200000; /* 2 MB */
+ flash_info[1].sector_count = 512;
+ memset (flash_info[1].protect, 0, 512);
+ flashbase = SST_BASEADDR;
+ for (j=0; j<512; j++) {
+ flash_info[1].start[j] = flashbase;
+ flashbase += 0x1000; /* 4 KB sectors */
+ }
+ size += flash_info[1].size;
+
+ /* Protect monitor and environment sectors */
+ flash_protect (FLAG_PROTECT_SET,
+ 0x0,
+ 0x0 + monitor_flash_len - 1,
+ &flash_info[0]);
+
+ flash_protect (FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+ &flash_info[0]);
+
+ return size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
+{
+ int i;
+ int erased = 0;
+ unsigned long j;
+ unsigned long count;
+ unsigned char *p;
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case (SST_MANUFACT & FLASH_VENDMASK):
+ printf("SST: ");
+ break;
+ case (PHILIPS_LPC2292 & FLASH_VENDMASK):
+ printf("Philips: ");
+ break;
+ default:
+ printf ("Unknown Vendor ");
+ break;
+ }
+
+ printf (" Size: %ld KB in %d Sectors\n",
+ info->size >> 10, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i = 0; i < info->sector_count; i++) {
+ if ((i % 5) == 0) {
+ printf ("\n ");
+ }
+ if (i < (info->sector_count - 1)) {
+ count = info->start[i+1] - info->start[i];
+ }
+ else {
+ count = info->start[0] + info->size - info->start[i];
+ }
+ p = (unsigned char*)(info->start[i]);
+ erased = 1;
+ for (j = 0; j < count; j++) {
+ if (*p != 0xFF) {
+ erased = 0;
+ break;
+ }
+ p++;
+ }
+ printf (" %08lX%s%s", info->start[i], info->protect[i] ? " RO" : " ",
+ erased ? " E" : " ");
+ }
+ printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase_philips (flash_info_t * info, int s_first, int s_last)
+{
+ int flag;
+ int prot;
+ int sect;
+
+ prot = 0;
+ for (sect = s_first; sect <= s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+ if (prot)
+ return ERR_PROTECTED;
+
+
+ flag = disable_interrupts();
+
+ printf ("Erasing %d sectors starting at sector %2d.\n"
+ "This make take some time ... ",
+ s_last - s_first + 1, s_first);
+
+ command[0] = IAP_CMD_PREPARE;
+ command[1] = s_first;
+ command[2] = s_last;
+ iap_entry(command, result);
+ if (result[0] != IAP_RET_CMD_SUCCESS) {
+ printf("IAP prepare failed\n");
+ return ERR_PROTECTED;
+ }
+
+ command[0] = IAP_CMD_ERASE;
+ command[1] = s_first;
+ command[2] = s_last;
+ command[3] = CFG_SYS_CLK_FREQ >> 10;
+ iap_entry(command, result);
+ if (result[0] != IAP_RET_CMD_SUCCESS) {
+ printf("IAP erase failed\n");
+ return ERR_PROTECTED;
+ }
+
+ if (flag)
+ enable_interrupts();
+
+ return ERR_OK;
+}
+
+int flash_erase_sst (flash_info_t * info, int s_first, int s_last)
+{
+ int i;
+
+ for (i = s_first; i <= s_last; i++) {
+ *SST_ADDR1 = 0x00AA;
+ *SST_ADDR2 = 0x0055;
+ *SST_ADDR1 = 0x0080;
+ *SST_ADDR1 = 0x00AA;
+ *SST_ADDR2 = 0x0055;
+ *((volatile ushort*)(info->start[i])) = 0x0030;
+ /* wait for erase to finish */
+ udelay(25000);
+ }
+
+ return ERR_OK;
+}
+
+int flash_erase (flash_info_t * info, int s_first, int s_last)
+{
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case (SST_MANUFACT & FLASH_VENDMASK):
+ return flash_erase_sst(info, s_first, s_last);
+ case (PHILIPS_LPC2292 & FLASH_VENDMASK):
+ return flash_erase_philips(info, s_first, s_last);
+ default:
+ return ERR_PROTECTED;
+ }
+ return ERR_PROTECTED;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ *
+ * cnt is in bytes
+ */
+
+int write_buff_sst (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+{
+ ushort tmp;
+ ulong i;
+ uchar* src_org;
+ uchar* dst_org;
+ ulong cnt_org = cnt;
+ int ret = ERR_OK;
+
+ src_org = src;
+ dst_org = (uchar*)addr;
+
+ if (addr & 1) { /* if odd address */
+ tmp = *((uchar*)(addr - 1)); /* little endian */
+ tmp |= (*src << 8);
+ write_word_sst(addr - 1, tmp);
+ addr += 1;
+ cnt -= 1;
+ src++;
+ }
+ while (cnt > 1) {
+ tmp = ((*(src+1)) << 8) + (*src); /* little endian */
+ write_word_sst(addr, tmp);
+ addr += 2;
+ src += 2;
+ cnt -= 2;
+ }
+ if (cnt > 0) {
+ tmp = (*((uchar*)(addr + 1))) << 8;
+ tmp |= *src;
+ write_word_sst(addr, tmp);
+ }
+
+ for (i = 0; i < cnt_org; i++) {
+ if (*dst_org != *src_org) {
+ printf("Write failed. Byte %lX differs\n", i);
+ ret = ERR_PROG_ERROR;
+ break;
+ }
+ dst_org++;
+ src_org++;
+ }
+
+
+ return ret;
+}
+
+int write_buff_philips (flash_info_t * info,
+ uchar * src,
+ ulong addr,
+ ulong cnt)
+{
+ int first_copy_size;
+ int last_copy_size;
+ int first_block;
+ int last_block;
+ int nbr_mid_blocks;
+ uchar memmap_value;
+ ulong i;
+ uchar* src_org;
+ uchar* dst_org;
+ int ret = ERR_OK;
+
+ src_org = src;
+ dst_org = (uchar*)addr;
+
+ first_block = addr / 512;
+ last_block = (addr + cnt) / 512;
+ nbr_mid_blocks = last_block - first_block - 1;
+
+ first_copy_size = 512 - (addr % 512);
+ last_copy_size = (addr + cnt) % 512;
+
+#if 0
+ printf("\ncopy first block: (1) %lX -> %lX 0x200 bytes, "
+ "(2) %lX -> %lX 0x%X bytes, (3) %lX -> %lX 0x200 bytes\n",
+ (ulong)(first_block * 512),
+ (ulong)COPY_BUFFER_LOCATION,
+ (ulong)src,
+ (ulong)(COPY_BUFFER_LOCATION + 512 - first_copy_size),
+ first_copy_size,
+ (ulong)COPY_BUFFER_LOCATION,
+ (ulong)(first_block * 512));
+#endif
+
+ /* copy first block */
+ memcpy((void*)COPY_BUFFER_LOCATION,
+ (void*)(first_block * 512), 512);
+ memcpy((void*)(COPY_BUFFER_LOCATION + 512 - first_copy_size),
+ src, first_copy_size);
+ copy_buffer_to_flash(info, first_block * 512);
+ src += first_copy_size;
+ addr += first_copy_size;
+
+ /* copy middle blocks */
+ for (i = 0; i < nbr_mid_blocks; i++) {
+#if 0
+ printf("copy middle block: %lX -> %lX 512 bytes, "
+ "%lX -> %lX 512 bytes\n",
+ (ulong)src,
+ (ulong)COPY_BUFFER_LOCATION,
+ (ulong)COPY_BUFFER_LOCATION,
+ (ulong)addr);
+#endif
+ memcpy((void*)COPY_BUFFER_LOCATION, src, 512);
+ copy_buffer_to_flash(info, addr);
+ src += 512;
+ addr += 512;
+ }
+
+
+ if (last_copy_size > 0) {
+#if 0
+ printf("copy last block: (1) %lX -> %lX 0x200 bytes, "
+ "(2) %lX -> %lX 0x%X bytes, (3) %lX -> %lX x200 bytes\n",
+ (ulong)(last_block * 512),
+ (ulong)COPY_BUFFER_LOCATION,
+ (ulong)src,
+ (ulong)(COPY_BUFFER_LOCATION),
+ last_copy_size,
+ (ulong)COPY_BUFFER_LOCATION,
+ (ulong)addr);
+#endif
+ /* copy last block */
+ memcpy((void*)COPY_BUFFER_LOCATION,
+ (void*)(last_block * 512), 512);
+ memcpy((void*)COPY_BUFFER_LOCATION,
+ src, last_copy_size);
+ copy_buffer_to_flash(info, addr);
+ }
+
+ /* verify write */
+ memmap_value = GET8(MEMMAP);
+
+ disable_interrupts();
+
+ PUT8(MEMMAP, 01); /* we must make sure that initial 64
+ bytes are taken from flash when we
+ do the compare */
+
+ for (i = 0; i < cnt; i++) {
+ if (*dst_org != *src_org){
+ printf("Write failed. Byte %lX differs\n", i);
+ ret = ERR_PROG_ERROR;
+ break;
+ }
+ dst_org++;
+ src_org++;
+ }
+
+ PUT8(MEMMAP, memmap_value);
+ enable_interrupts();
+
+ return ret;
+}
+
+int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+{
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case (SST_MANUFACT & FLASH_VENDMASK):
+ return write_buff_sst(info, src, addr, cnt);
+ case (PHILIPS_LPC2292 & FLASH_VENDMASK):
+ return write_buff_philips(info, src, addr, cnt);
+ default:
+ return ERR_PROG_ERROR;
+ }
+ return ERR_PROG_ERROR;
+}
diff --git a/board/lpc2292sodimm/iap_entry.S b/board/lpc2292sodimm/iap_entry.S
new file mode 100644
index 0000000..28ed805
--- /dev/null
+++ b/board/lpc2292sodimm/iap_entry.S
@@ -0,0 +1,7 @@
+IAP_ADDRESS: .word 0x7FFFFFF1
+
+.globl iap_entry
+iap_entry:
+ ldr r2, IAP_ADDRESS
+ bx r2
+ mov pc, lr
diff --git a/board/lpc2292sodimm/lowlevel_init.S b/board/lpc2292sodimm/lowlevel_init.S
new file mode 100644
index 0000000..a91e678
--- /dev/null
+++ b/board/lpc2292sodimm/lowlevel_init.S
@@ -0,0 +1,87 @@
+/*
+ * (C) Copyright 2006 Embedded Artists AB <www.embeddedartists.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <version.h>
+#include <asm/arch/hardware.h>
+
+/* some parameters for the board */
+/* setting up the memory */
+#define SRAM_START 0x40000000
+#define SRAM_SIZE 0x00004000
+#define BCFG0_VALUE 0x1000ffef
+#define BCFG1_VALUE 0x10001C61
+
+_TEXT_BASE:
+ .word TEXT_BASE
+MEMMAP_ADR:
+ .word MEMMAP
+BCFG0_ADR:
+ .word BCFG0
+_BCFG0_VALUE:
+ .word BCFG0_VALUE
+BCFG1_ADR:
+ .word BCFG1
+_BCFG1_VALUE:
+ .word BCFG1_VALUE
+PINSEL2_ADR:
+ .word PINSEL2
+PINSEL2_MASK:
+ .word 0x00000000
+PINSEL2_VALUE:
+ .word 0x0F800914
+
+.extern _start
+
+.globl lowlevel_init
+lowlevel_init:
+ /* set up memory control register for bank 0 */
+ ldr r0, _BCFG0_VALUE
+ ldr r1, BCFG0_ADR
+ str r0, [r1]
+
+ /* set up memory control register for bank 1 */
+ ldr r0, _BCFG1_VALUE
+ ldr r1, BCFG1_ADR
+ str r0, [r1]
+
+ /* set up PINSEL2 for bus-pins */
+ ldr r0, PINSEL2_ADR
+ ldr r1, [r0]
+ ldr r2, PINSEL2_MASK
+ ldr r3, PINSEL2_VALUE
+ and r1, r1, r2
+ orr r1, r1, r3
+ str r1, [r0]
+
+ /* move vectors to beginning of SRAM */
+ mov r2, #SRAM_START
+ mov r0, #0 /*_start*/
+ ldmneia r0!, {r3-r10}
+ stmneia r2!, {r3-r10}
+ ldmneia r0, {r3-r9}
+ stmneia r2, {r3-r9}
+
+ /* Set-up MEMMAP register, so vectors are taken from SRAM */
+ ldr r0, MEMMAP_ADR
+ mov r1, #0x02 /* vectors re-mapped to static RAM */
+ str r1, [r0]
+
+ /* everything is fine now */
+ mov pc, lr
diff --git a/board/lpc2292sodimm/lpc2292sodimm.c b/board/lpc2292sodimm/lpc2292sodimm.c
new file mode 100644
index 0000000..de04c66
--- /dev/null
+++ b/board/lpc2292sodimm/lpc2292sodimm.c
@@ -0,0 +1,62 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2005 Rowel Atienza <rowel@diwalabs.com>
+ * Armadillo board HT1070
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <clps7111.h>
+
+/* ------------------------------------------------------------------------- */
+
+
+/*
+ * Miscelaneous platform dependent initialisations
+ */
+
+int board_init (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ /* Activate LED flasher */
+ IO_LEDFLSH = 0x40;
+
+ /* arch number MACH_TYPE_ARMADILLO - not official*/
+ gd->bd->bi_arch_number = 83;
+
+ /* location of boot parameters */
+ gd->bd->bi_boot_params = 0xc0000100;
+
+ return 0;
+}
+
+int dram_init (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
+ gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
+
+ return (0);
+}
diff --git a/board/lpc2292sodimm/mmc.c b/board/lpc2292sodimm/mmc.c
new file mode 100644
index 0000000..e361db1
--- /dev/null
+++ b/board/lpc2292sodimm/mmc.c
@@ -0,0 +1,154 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <mmc.h>
+#include <asm/errno.h>
+#include <asm/arch/hardware.h>
+#include <part.h>
+#include <fat.h>
+#include "mmc_hw.h"
+#include "spi.h"
+
+#ifdef CONFIG_MMC
+
+#undef MMC_DEBUG
+
+static block_dev_desc_t mmc_dev;
+
+/* these are filled out by a call to mmc_hw_get_parameters */
+static int hw_size; /* in kbytes */
+static int hw_nr_sects;
+static int hw_sect_size; /* in bytes */
+
+block_dev_desc_t * mmc_get_dev(int dev)
+{
+ return (block_dev_desc_t *)(&mmc_dev);
+}
+
+unsigned long mmc_block_read(int dev,
+ unsigned long start,
+ lbaint_t blkcnt,
+ unsigned long *buffer)
+{
+ unsigned long rc = 0;
+ unsigned char *p = (unsigned char *)buffer;
+ unsigned long i;
+ unsigned long addr = start;
+
+#ifdef MMC_DEBUG
+ printf("mmc_block_read: start=%lu, blkcnt=%lu\n", start,
+ (unsigned long)blkcnt);
+#endif
+
+ for(i = 0; i < (unsigned long)blkcnt; i++) {
+#ifdef MMC_DEBUG
+ printf("mmc_read_sector: addr=%lu, buffer=%p\n", addr, p);
+#endif
+ (void)mmc_read_sector(addr, p);
+ rc++;
+ addr++;
+ p += hw_sect_size;
+ }
+
+ return rc;
+}
+
+/*-----------------------------------------------------------------------------
+ * Read hardware paramterers (sector size, size, number of sectors)
+ */
+static int mmc_hw_get_parameters(void)
+{
+ unsigned char csddata[16];
+ unsigned int sizemult;
+ unsigned int size;
+
+ mmc_read_csd(csddata);
+ hw_sect_size = 1<<(csddata[5] & 0x0f);
+ size = ((csddata[6]&0x03)<<10)+(csddata[7]<<2)+(csddata[8]&0xc0);
+ sizemult = ((csddata[10] & 0x80)>>7)+((csddata[9] & 0x03)<<1);
+ hw_nr_sects = (size+1)*(1<<(sizemult+2));
+ hw_size = hw_nr_sects*hw_sect_size/1024;
+
+#ifdef MMC_DEBUG
+ printf("mmc_hw_get_parameters: hw_sect_size=%d, hw_nr_sects=%d, "
+ "hw_size=%d\n", hw_sect_size, hw_nr_sects, hw_size);
+#endif
+
+ return 0;
+}
+
+int mmc_init(int verbose)
+{
+ int ret = -ENODEV;
+
+ if (verbose)
+ printf("mmc_init\n");
+
+ spi_init();
+ mmc_hw_init();
+
+ mmc_hw_get_parameters();
+
+ mmc_dev.if_type = IF_TYPE_MMC;
+ mmc_dev.part_type = PART_TYPE_DOS;
+ mmc_dev.dev = 0;
+ mmc_dev.lun = 0;
+ mmc_dev.type = 0;
+ mmc_dev.blksz = hw_sect_size;
+ mmc_dev.lba = hw_nr_sects;
+ sprintf((char*)mmc_dev.vendor, "Unknown vendor");
+ sprintf((char*)mmc_dev.product, "Unknown product");
+ sprintf((char*)mmc_dev.revision, "N/A");
+ mmc_dev.removable = 0; /* should be true??? */
+ mmc_dev.block_read = mmc_block_read;
+
+ fat_register_device(&mmc_dev, 1);
+
+ ret = 0;
+
+ return ret;
+}
+
+int mmc_write(uchar * src, ulong dst, int size)
+{
+#ifdef MMC_DEBUG
+ printf("mmc_write: src=%p, dst=%lu, size=%u\n", src, dst, size);
+#endif
+ /* Since mmc2info always returns 0 this function will never be called */
+ return 0;
+}
+
+int mmc_read(ulong src, uchar * dst, int size)
+{
+#ifdef MMC_DEBUG
+ printf("mmc_read: src=%lu, dst=%p, size=%u\n", src, dst, size);
+#endif
+ /* Since mmc2info always returns 0 this function will never be called */
+ return 0;
+}
+
+int mmc2info(ulong addr)
+{
+ /* This function is used by cmd_cp to determine if source or destination
+ address resides on MMC-card or not. We do not support copy to and from
+ MMC-card so we always return 0. */
+ return 0;
+}
+
+#endif /* CONFIG_MMC */
diff --git a/board/lpc2292sodimm/mmc_hw.c b/board/lpc2292sodimm/mmc_hw.c
new file mode 100644
index 0000000..0b5ddf9
--- /dev/null
+++ b/board/lpc2292sodimm/mmc_hw.c
@@ -0,0 +1,233 @@
+/*
+ This code was original written by Ulrich Radig and modified by
+ Embedded Artists AB (www.embeddedartists.com).
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <config.h>
+#include <common.h>
+#include <asm/arch/hardware.h>
+#include "spi.h"
+
+#define MMC_Enable() PUT32(IO1CLR, 1l << 22)
+#define MMC_Disable() PUT32(IO1SET, 1l << 22)
+#define mmc_spi_cfg() spi_set_clock(8); spi_set_cfg(0, 1, 0);
+
+static unsigned char Write_Command_MMC (unsigned char *CMD);
+static void MMC_Read_Block(unsigned char *CMD, unsigned char *Buffer,
+ unsigned short int Bytes);
+
+/* initialize the hardware */
+int mmc_hw_init(void)
+{
+ unsigned long a;
+ unsigned short int Timeout = 0;
+ unsigned char b;
+ unsigned char CMD[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95};
+
+ /* set-up GPIO and SPI */
+ (*((volatile unsigned long *)PINSEL2)) &= ~(1l << 3); /* clear bit 3 */
+ (*((volatile unsigned long *)IO1DIR)) |= (1l << 22); /* set bit 22 (output) */
+
+ MMC_Disable();
+
+ spi_lock();
+ spi_set_clock(248);
+ spi_set_cfg(0, 1, 0);
+ MMC_Enable();
+
+ /* waste some time */
+ for(a=0; a < 20000; a++)
+ asm("nop");
+
+ /* Put the MMC/SD-card into SPI-mode */
+ for (b = 0; b < 10; b++) /* Sends min 74+ clocks to the MMC/SD-card */
+ spi_write(0xff);
+
+ /* Sends command CMD0 to MMC/SD-card */
+ while (Write_Command_MMC(CMD) != 1) {
+ if (Timeout++ > 200) {
+ MMC_Disable();
+ spi_unlock();
+ return(1); /* Abort with command 1 (return 1) */
+ }
+ }
+ /* Sends Command CMD1 an MMC/SD-card */
+ Timeout = 0;
+ CMD[0] = 0x41;/* Command 1 */
+ CMD[5] = 0xFF;
+
+ while (Write_Command_MMC(CMD) != 0) {
+ if (Timeout++ > 200) {
+ MMC_Disable();
+ spi_unlock();
+ return (2); /* Abort with command 2 (return 2) */
+ }
+ }
+
+ MMC_Disable();
+ spi_unlock();
+
+ return 0;
+}
+
+/* ############################################################################
+ Sends a command to the MMC/SD-card
+ ######################################################################### */
+static unsigned char Write_Command_MMC (unsigned char *CMD)
+{
+ unsigned char a, tmp = 0xff;
+ unsigned short int Timeout = 0;
+
+ MMC_Disable();
+ spi_write(0xFF);
+ MMC_Enable();
+
+ for (a = 0; a < 0x06; a++)
+ spi_write(*CMD++);
+
+ while (tmp == 0xff) {
+ tmp = spi_read();
+ if (Timeout++ > 5000)
+ break;
+ }
+
+ return (tmp);
+}
+
+/* ############################################################################
+ Routine to read the CID register from the MMC/SD-card (16 bytes)
+ ######################################################################### */
+void MMC_Read_Block(unsigned char *CMD, unsigned char *Buffer, unsigned short
+ int Bytes)
+{
+ unsigned short int a;
+
+ spi_lock();
+ mmc_spi_cfg();
+ MMC_Enable();
+
+ if (Write_Command_MMC(CMD) != 0) {
+ MMC_Disable();
+ spi_unlock();
+ return;
+ }
+
+ while (spi_read() != 0xfe) {};
+ for (a = 0; a < Bytes; a++)
+ *Buffer++ = spi_read();
+
+ /* Read the CRC-byte */
+ spi_read(); /* CRC - byte is discarded */
+ spi_read(); /* CRC - byte is discarded */
+ /* set MMC_Chip_Select to high (MMC/SD-card Inaktiv) */
+ MMC_Disable();
+ spi_unlock();
+
+ return;
+}
+
+/* ############################################################################
+ Routine to read a block (512 bytes) from the MMC/SD-card
+ ######################################################################### */
+unsigned char mmc_read_sector (unsigned long addr,unsigned char *Buffer)
+{
+ /* Command 16 to read aBlocks from the MMC/SD - caed */
+ unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF};
+
+ /* The addres on the MMC/SD-card is in bytes,
+ addr is transformed from blocks to bytes and the result is
+ placed into the command */
+
+ addr = addr << 9; /* addr = addr * 512 */
+
+ CMD[1] = ((addr & 0xFF000000) >> 24);
+ CMD[2] = ((addr & 0x00FF0000) >> 16);
+ CMD[3] = ((addr & 0x0000FF00) >> 8 );
+
+ MMC_Read_Block(CMD, Buffer, 512);
+
+ return (0);
+}
+
+/* ############################################################################
+ Routine to write a block (512 byte) to the MMC/SD-card
+ ######################################################################### */
+unsigned char mmc_write_sector (unsigned long addr,unsigned char *Buffer)
+{
+ unsigned char tmp, a;
+ unsigned short int b;
+ /* Command 24 to write a block to the MMC/SD - card */
+ unsigned char CMD[] = {0x58, 0x00, 0x00, 0x00, 0x00, 0xFF};
+
+ /* The addres on the MMC/SD-card is in bytes,
+ addr is transformed from blocks to bytes and the result is
+ placed into the command */
+
+ addr = addr << 9; /* addr = addr * 512 */
+
+ CMD[1] = ((addr & 0xFF000000) >> 24);
+ CMD[2] = ((addr & 0x00FF0000) >> 16);
+ CMD[3] = ((addr & 0x0000FF00) >> 8 );
+
+ spi_lock();
+ mmc_spi_cfg();
+ MMC_Enable();
+
+ /* Send command CMD24 to the MMC/SD-card (Write 1 Block/512 Bytes) */
+ tmp = Write_Command_MMC(CMD);
+ if (tmp != 0) {
+ MMC_Disable();
+ spi_unlock();
+ return(tmp);
+ }
+
+ /* Do a short delay and send a clock-pulse to the MMC/SD-card */
+ for (a = 0; a < 100; a++)
+ spi_read();
+
+ /* Send a start byte to the MMC/SD-card */
+ spi_write(0xFE);
+
+ /* Write the block (512 bytes) to the MMC/SD-card */
+ for (b = 0; b < 512; b++)
+ spi_write(*Buffer++);
+
+ /* write the CRC-Byte */
+ spi_write(0xFF); /* write a dummy CRC */
+ spi_write(0xFF); /* CRC code is not used */
+
+ /* Wait for MMC/SD-card busy */
+ while (spi_read() != 0xff) {};
+
+ /* set MMC_Chip_Select to high (MMC/SD-card inactive) */
+ MMC_Disable();
+ spi_unlock();
+ return (0);
+}
+
+/* #########################################################################
+ Routine to read the CSD register from the MMC/SD-card (16 bytes)
+ ######################################################################### */
+unsigned char mmc_read_csd (unsigned char *Buffer)
+{
+ /* Command to read the CSD register */
+ unsigned char CMD[] = {0x49, 0x00, 0x00, 0x00, 0x00, 0xFF};
+
+ MMC_Read_Block(CMD, Buffer, 16);
+
+ return (0);
+}
diff --git a/board/lpc2292sodimm/mmc_hw.h b/board/lpc2292sodimm/mmc_hw.h
new file mode 100644
index 0000000..3687dbf
--- /dev/null
+++ b/board/lpc2292sodimm/mmc_hw.h
@@ -0,0 +1,29 @@
+/*
+ This module implements a linux character device driver for the 24c256 chip.
+ Copyright (C) 2006 Embedded Artists AB (www.embeddedartists.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MMC_HW_
+#define _MMC_HW_
+
+unsigned char mmc_read_csd(unsigned char *Buffer);
+unsigned char mmc_read_sector (unsigned long addr,
+ unsigned char *Buffer);
+unsigned char mmc_write_sector (unsigned long addr,unsigned char *Buffer);
+int mmc_hw_init(void);
+
+#endif /* _MMC_HW_ */
diff --git a/board/lpc2292sodimm/spi.c b/board/lpc2292sodimm/spi.c
new file mode 100644
index 0000000..4ba1468
--- /dev/null
+++ b/board/lpc2292sodimm/spi.c
@@ -0,0 +1,40 @@
+/*
+ This module implements an interface to the SPI on the lpc22xx.
+ Copyright (C) 2006 Embedded Artists AB (www.embeddedartists.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <config.h>
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/arch/hardware.h>
+#include "spi.h"
+
+unsigned long spi_flags;
+unsigned char spi_idle = 0x00;
+
+int spi_init(void)
+{
+ unsigned long pinsel0_value;
+
+ /* activate spi pins */
+ pinsel0_value = GET32(PINSEL0);
+ pinsel0_value &= ~(0xFFl << 8);
+ pinsel0_value |= (0x55l << 8);
+ PUT32(PINSEL0, pinsel0_value);
+
+ return 0;
+}
diff --git a/board/lpc2292sodimm/spi.h b/board/lpc2292sodimm/spi.h
new file mode 100644
index 0000000..64f088c
--- /dev/null
+++ b/board/lpc2292sodimm/spi.h
@@ -0,0 +1,84 @@
+/*
+ This file defines the interface to the lpc22xx SPI module.
+ Copyright (C) 2006 Embedded Artists AB (www.embeddedartists.com)
+
+ This file may be included in software not adhering to the GPL.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef SPI_H
+#define SPI_H
+
+#include <config.h>
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/arch/hardware.h>
+
+#define SPIF 0x80
+
+#define spi_lock() disable_interrupts();
+#define spi_unlock() enable_interrupts();
+
+extern unsigned long spi_flags;
+extern unsigned char spi_idle;
+
+int spi_init(void);
+
+static inline unsigned char spi_read(void)
+{
+ unsigned char b;
+
+ PUT8(S0SPDR, spi_idle);
+ while (!(GET8(S0SPSR) & SPIF));
+ b = GET8(S0SPDR);
+
+ return b;
+}
+
+static inline void spi_write(unsigned char b)
+{
+ PUT8(S0SPDR, b);
+ while (!(GET8(S0SPSR) & SPIF));
+ GET8(S0SPDR); /* this will clear the SPIF bit */
+}
+
+static inline void spi_set_clock(unsigned char clk_value)
+{
+ PUT8(S0SPCCR, clk_value);
+}
+
+static inline void spi_set_cfg(unsigned char phase,
+ unsigned char polarity,
+ unsigned char lsbf)
+{
+ unsigned char v = 0x20; /* master bit set */
+
+ if (phase)
+ v |= 0x08; /* set phase bit */
+ if (polarity) {
+ v |= 0x10; /* set polarity bit */
+ spi_idle = 0xFF;
+ } else {
+ spi_idle = 0x00;
+ }
+ if (lsbf)
+ v |= 0x40; /* set lsbf bit */
+
+ PUT8(S0SPCR, v);
+}
+
+#endif
+
diff --git a/board/lpc2292sodimm/u-boot.lds b/board/lpc2292sodimm/u-boot.lds
new file mode 100644
index 0000000..64d946c
--- /dev/null
+++ b/board/lpc2292sodimm/u-boot.lds
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x00000000;
+
+ . = ALIGN(4);
+ .text :
+ {
+ cpu/arm720t/start.o (.text)
+ *(.text)
+ }
+
+ . = ALIGN(4);
+ .rodata : { *(.rodata) }
+
+ . = ALIGN(4);
+ .data : { *(.data) }
+
+ . = ALIGN(4);
+ .got : { *(.got) }
+
+ __u_boot_cmd_start = .;
+ .u_boot_cmd : { *(.u_boot_cmd) }
+ __u_boot_cmd_end = .;
+
+ . = ALIGN(4);
+ __bss_start = .;
+ .bss : { *(.bss) }
+ _end = .;
+}