Add port for the lpc2292sodimm evaluation board from EmbeddedArtists
diff --git a/MAKEALL b/MAKEALL
index 40a5c77..4e4d04b 100755
--- a/MAKEALL
+++ b/MAKEALL
@@ -181,7 +181,7 @@
 LIST_ARM7="	\
 	armadillo	B2		ep7312		evb4510		\
 	impa7		integratorap	ap7		ap720t		\
-	modnet50							\
+	lpc2292sodimm	modnet50					\
 "
 
 #########################################################################
diff --git a/Makefile b/Makefile
index b1952ed..a44cba0 100644
--- a/Makefile
+++ b/Makefile
@@ -2029,6 +2029,9 @@
 evb4510_config :	unconfig
 	@$(MKCONFIG) $(@:_config=) arm arm720t evb4510
 
+lpc2292sodimm_config:	unconfig
+	@$(MKCONFIG) $(@:_config=) arm arm720t lpc2292sodimm
+
 #########################################################################
 ## XScale Systems
 #########################################################################
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 = .;
+}
diff --git a/cpu/arm720t/cpu.c b/cpu/arm720t/cpu.c
index a5b6de7..60c1aa9 100644
--- a/cpu/arm720t/cpu.c
+++ b/cpu/arm720t/cpu.c
@@ -73,7 +73,7 @@
 	/* go to high speed */
 	IO_SYSCON3 = (IO_SYSCON3 & ~CLKCTL) | CLKCTL_73;
 #endif
-#elif defined(CONFIG_NETARM) || defined(CONFIG_S3C4510B)
+#elif defined(CONFIG_NETARM) || defined(CONFIG_S3C4510B) || defined(CONFIG_LPC2292)
 	disable_interrupts ();
 	/* Nothing more needed */
 #elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR)
@@ -252,6 +252,7 @@
 	void icache_enable (void)
 	{
 	}
+#elif defined(CONFIG_LPC2292) /* just to satisfy the compiler */
 #else
 #error No icache/dcache enable/disable functions defined for this CPU type
 #endif
diff --git a/cpu/arm720t/interrupts.c b/cpu/arm720t/interrupts.c
index da62502..8f32124 100644
--- a/cpu/arm720t/interrupts.c
+++ b/cpu/arm720t/interrupts.c
@@ -36,6 +36,12 @@
 #define TIMER_LOAD_VAL 0xffff
 /* macro to read the 16 bit timer */
 #define READ_TIMER (IO_TC1D & 0xffff)
+
+#ifdef CONFIG_LPC2292
+#undef READ_TIMER
+#define READ_TIMER (0xFFFFFFFF - GET32(T0TC))
+#endif
+
 #else
 #define IRQEN	(*(volatile unsigned int *)(NETARM_GEN_MODULE_BASE + NETARM_GEN_INTR_ENABLE))
 #define TM2CTRL (*(volatile unsigned int *)(NETARM_GEN_MODULE_BASE + NETARM_GEN_TIMER2_CONTROL))
@@ -195,6 +201,13 @@
 	}
 #elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR)
 	/* No do_irq() for IntegratorAP/CM720T as yet */
+#elif defined(CONFIG_LPC2292)
+
+    void (*pfnct)(void);
+
+    pfnct = (void (*)(void))VICVectAddr;
+
+    (*pfnct)();
 #else
 #error do_irq() not defined for this CPU type
 #endif
@@ -293,6 +306,13 @@
 
 	/* Start timer */
 	SET_REG( REG_TMOD, TM0_RUN);
+#elif defined(CONFIG_LPC2292)
+	PUT32(T0IR, 0);		/* disable all timer0 interrupts */
+	PUT32(T0TCR, 0);	/* disable timer0 */
+	PUT32(T0PR, CFG_SYS_CLK_FREQ / CFG_HZ);
+ 	PUT32(T0MCR, 0);
+	PUT32(T0TC, 0);
+	PUT32(T0TCR, 1);	/* enable timer0 */
 
 #else
 #error No interrupt_init() defined for this CPU type
@@ -309,7 +329,7 @@
  */
 
 
-#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_NETARM) || defined(CONFIG_ARMADILLO)
+#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_NETARM) || defined(CONFIG_ARMADILLO) || defined(CONFIG_LPC2292)
 
 void reset_timer (void)
 {
@@ -337,7 +357,12 @@
 	tmo += get_timer (0);
 
 	while (get_timer_masked () < tmo)
+#ifdef CONFIG_LPC2292
+		/* GJ - not sure whether this is really needed or a misunderstanding */
+		__asm__ __volatile__(" nop");
+#else
 		/*NOP*/;
+#endif
 }
 
 void reset_timer_masked (void)
diff --git a/cpu/arm720t/serial.c b/cpu/arm720t/serial.c
index 054bab9..15c54af 100644
--- a/cpu/arm720t/serial.c
+++ b/cpu/arm720t/serial.c
@@ -123,4 +123,80 @@
 	}
 }
 
-#endif /* defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) */
+#elif defined(CONFIG_LPC2292)
+
+#include <asm/arch/hardware.h>
+
+void serial_setbrg (void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	unsigned short divisor = 0;
+
+	switch (gd->baudrate) {
+	case   1200:	divisor = 3072;	break;
+	case   9600:	divisor =  384;	break;
+	case  19200:	divisor =  192;	break;
+	case  38400:	divisor =   96;	break;
+	case  57600:	divisor =   64;	break;
+	case 115200:	divisor =   32;	break;
+	default:	hang ();	break;
+	}
+
+	/* init serial UART0 */
+	PUT8(U0LCR, 0);
+	PUT8(U0IER, 0);
+	PUT8(U0LCR, 0x80);	/* DLAB=1 */
+	PUT8(U0DLL, (unsigned char)(divisor & 0x00FF));
+	PUT8(U0DLM, (unsigned char)(divisor >> 8));
+	PUT8(U0LCR, 0x03);	/* 8N1, DLAB=0  */
+	PUT8(U0FCR, 1);		/* Enable RX and TX FIFOs */
+}
+
+int serial_init (void)
+{
+	unsigned long pinsel0;
+
+	serial_setbrg ();
+
+	pinsel0 = GET32(PINSEL0);
+	pinsel0 &= ~(0x00000003);
+	pinsel0 |= 5;
+	PUT32(PINSEL0, pinsel0);
+
+	return (0);
+}
+
+void serial_putc (const char c)
+{
+	if (c == '\n')
+	{
+		while((GET8(U0LSR) & (1<<5)) == 0); /* Wait for empty U0THR */
+		PUT8(U0THR, '\r');
+	}
+
+	while((GET8(U0LSR) & (1<<5)) == 0); /* Wait for empty U0THR */
+	PUT8(U0THR, c);
+}
+
+int serial_getc (void)
+{
+	while((GET8(U0LSR) & 1) == 0);
+	return GET8(U0RBR);
+}
+
+void
+serial_puts (const char *s)
+{
+	while (*s) {
+		serial_putc (*s++);
+	}
+}
+
+/* Test if there is a byte to read */
+int serial_tstc (void)
+{
+	return (GET8(U0LSR) & 1);
+}
+
+#endif
diff --git a/cpu/arm720t/start.S b/cpu/arm720t/start.S
index e66d109..96d5f54 100644
--- a/cpu/arm720t/start.S
+++ b/cpu/arm720t/start.S
@@ -43,7 +43,11 @@
 	ldr	pc, _software_interrupt
 	ldr	pc, _prefetch_abort
 	ldr	pc, _data_abort
+#ifdef CONFIG_LPC2292
+	.word	0xB4405F76 /* 2's complement of the checksum of the vectors */
+#else
 	ldr	pc, _not_used
+#endif
 	ldr	pc, _irq
 	ldr	pc, _fiq
 
@@ -123,6 +127,10 @@
 	bl	cpu_init_crit
 #endif
 
+#ifdef CONFIG_LPC2292
+	bl	lowlevel_init
+#endif
+
 #ifndef CONFIG_SKIP_RELOCATE_UBOOT
 relocate:				/* relocate U-Boot to RAM	    */
 	adr	r0, _start		/* r0 <- current position of code   */
@@ -131,6 +139,7 @@
 	beq	stack_setup
 
 #if TEXT_BASE
+#ifndef CONFIG_LPC2292 /* already done in lowlevel_init */
 	ldr	r2, =0x0		/* Relocate the exception vectors   */
 	cmp	r1, r2			/* and associated data to address   */
 	ldmneia r0!, {r3-r10}		/* 0x0. Do nothing if TEXT_BASE is  */
@@ -138,6 +147,7 @@
 	ldmneia r0, {r3-r9}
 	stmneia r2, {r3-r9}
 	adrne	r0, _start		/* restore r0			    */
+#endif	/* !CONFIG_LPC2292 */
 #endif
 
 	ldr	r2, _armboot_start
@@ -206,6 +216,14 @@
 #define CLKCTL_49      0x4  /* 49.152 MHz */
 #define CLKCTL_73      0x6  /* 73.728 MHz */
 
+#elif defined(CONFIG_LPC2292)
+PLLCFG_ADR:	.word	PLLCFG
+PLLFEED_ADR:	.word	PLLFEED
+PLLCON_ADR:	.word	PLLCON
+PLLSTAT_ADR:	.word	PLLSTAT
+VPBDIV_ADR:	.word	VPBDIV
+MEMMAP_ADR:	.word	MEMMAP
+
 #endif
 
 cpu_init_crit:
@@ -306,6 +324,50 @@
 
 #elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR)
 	/* No specific initialisation for IntegratorAP/CM720T as yet */
+#elif defined(CONFIG_LPC2292)
+	/* Set-up PLL */
+	mov	r3, #0xAA
+	mov	r4, #0x55
+	/* First disconnect and disable the PLL */	
+	ldr	r0, PLLCON_ADR
+	mov	r1, #0x00
+	str	r1, [r0]
+	ldr	r0, PLLFEED_ADR /* start feed sequence */
+	str	r3, [r0]
+	str	r4, [r0]	/* feed sequence done */	
+	/* Set new M and P values */
+	ldr	r0, PLLCFG_ADR
+	mov	r1, #0x23	/* M=4 and P=2 */
+	str	r1, [r0]
+	ldr	r0, PLLFEED_ADR /* start feed sequence */
+	str	r3, [r0]
+	str	r4, [r0]	/* feed sequence done */
+	/* Then enable the PLL */
+	ldr	r0, PLLCON_ADR
+	mov	r1, #0x01	/* PLL enable bit */
+	str	r1, [r0]
+	ldr	r0, PLLFEED_ADR /* start feed sequence */
+	str	r3, [r0]
+	str	r4, [r0]	/* feed sequence done */
+	/* Wait for the lock */	
+	ldr	r0, PLLSTAT_ADR
+	mov	r1, #0x400	/* lock bit */
+lock_loop:	
+	ldr	r2, [r0]
+	and	r2, r1, r2
+	cmp	r2, #0
+	beq	lock_loop
+	/* And finally connect the PLL */
+	ldr	r0, PLLCON_ADR
+	mov	r1, #0x03	/* PLL enable bit and connect bit */
+	str	r1, [r0]
+	ldr	r0, PLLFEED_ADR /* start feed sequence */
+	str	r3, [r0]
+	str	r4, [r0]	/* feed sequence done */		
+	/* Set-up VPBDIV register */
+	ldr	r0, VPBDIV_ADR
+	mov	r1, #0x01	/* VPB clock is same as process clock */
+	str	r1, [r0]
 #else
 #error No cpu_init_crit() defined for current CPU type
 #endif
@@ -321,6 +383,7 @@
 	str	r1, [r0]
 #endif
 
+#ifndef CONFIG_LPC2292
 	mov	ip, lr
 	/*
 	 * before relocating, we have to setup RAM timing
@@ -329,6 +392,7 @@
 	 */
 	bl	lowlevel_init
 	mov	lr, ip
+#endif
 
 	mov	pc, lr
 
@@ -537,6 +601,11 @@
  * on external peripherals such as watchdog timers, etc. */
 #elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR)
 	/* No specific reset actions for IntegratorAP/CM720T as yet */
+#elif defined(CONFIG_LPC2292)
+	.align	5
+.globl reset_cpu
+reset_cpu:
+	mov	pc, r0
 #else
 #error No reset_cpu() defined for current CPU type
 #endif
diff --git a/include/asm-arm/arch-arm720t/hardware.h b/include/asm-arm/arch-arm720t/hardware.h
index 3056ca7..1e9cd41 100644
--- a/include/asm-arm/arch-arm720t/hardware.h
+++ b/include/asm-arm/arch-arm720t/hardware.h
@@ -36,6 +36,8 @@
 /* include armadillo specific hardware file if there was one */
 #elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR)
 /* include IntegratorCP/CM720T specific hardware file if there was one */
+#elif defined(CONFIG_LPC2292)
+#include <asm-arm/arch-arm720t/lpc2292_registers.h>
 #else
 #error No hardware file defined for this configuration
 #endif
diff --git a/include/asm-arm/arch-arm720t/lpc2292_registers.h b/include/asm-arm/arch-arm720t/lpc2292_registers.h
new file mode 100644
index 0000000..5715f3e
--- /dev/null
+++ b/include/asm-arm/arch-arm720t/lpc2292_registers.h
@@ -0,0 +1,225 @@
+#ifndef __LPC2292_REGISTERS_H
+#define __LPC2292_REGISTERS_H
+
+#include <config.h>
+
+/* Macros for reading/writing registers */
+#define PUT8(reg, value) (*(volatile unsigned char*)(reg) = (value))
+#define PUT16(reg, value) (*(volatile unsigned short*)(reg) = (value))
+#define PUT32(reg, value) (*(volatile unsigned int*)(reg) = (value))
+#define GET8(reg) (*(volatile unsigned char*)(reg))
+#define GET16(reg) (*(volatile unsigned short*)(reg))
+#define GET32(reg) (*(volatile unsigned int*)(reg))
+
+/* External Memory Controller */
+
+#define BCFG0 0xFFE00000	/* 32-bits */
+#define BCFG1 0xFFE00004	/* 32-bits */
+#define BCFG2 0xFFE00008	/* 32-bits */
+#define BCFG3 0xFFE0000c	/* 32-bits */
+
+/* System Control Block */
+
+#define EXTINT   0xE01FC140
+#define EXTWAKE  0xE01FC144
+#define EXTMODE  0xE01FC148
+#define EXTPOLAR 0xE01FC14C
+#define MEMMAP   0xE01FC040
+#define PLLCON   0xE01FC080
+#define PLLCFG   0xE01FC084
+#define PLLSTAT  0xE01FC088
+#define PLLFEED  0xE01FC08C
+#define PCON     0xE01FC0C0
+#define PCONP    0xE01FC0C4
+#define VPBDIV   0xE01FC100
+
+/* Memory Acceleration Module */
+
+#define MAMCR  0xE01FC000
+#define MAMTIM 0xE01FC004
+
+/* Vectored Interrupt Controller */
+
+#define VICIRQStatus    0xFFFFF000
+#define VICFIQStatus    0xFFFFF004
+#define VICRawIntr      0xFFFFF008
+#define VICIntSelect    0xFFFFF00C
+#define VICIntEnable    0xFFFFF010
+#define VICIntEnClr     0xFFFFF014
+#define VICSoftInt      0xFFFFF018
+#define VICSoftIntClear 0xFFFFF01C
+#define VICProtection   0xFFFFF020
+#define VICVectAddr     0xFFFFF030
+#define VICDefVectAddr  0xFFFFF034
+#define VICVectAddr0    0xFFFFF100
+#define VICVectAddr1    0xFFFFF104
+#define VICVectAddr2    0xFFFFF108
+#define VICVectAddr3    0xFFFFF10C
+#define VICVectAddr4    0xFFFFF110
+#define VICVectAddr5    0xFFFFF114
+#define VICVectAddr6    0xFFFFF118
+#define VICVectAddr7    0xFFFFF11C
+#define VICVectAddr8    0xFFFFF120
+#define VICVectAddr9    0xFFFFF124
+#define VICVectAddr10   0xFFFFF128
+#define VICVectAddr11   0xFFFFF12C
+#define VICVectAddr12   0xFFFFF130
+#define VICVectAddr13   0xFFFFF134
+#define VICVectAddr14   0xFFFFF138
+#define VICVectAddr15   0xFFFFF13C
+#define VICVectCntl0    0xFFFFF200
+#define VICVectCntl1	0xFFFFF204
+#define VICVectCntl2	0xFFFFF208
+#define VICVectCntl3	0xFFFFF20C
+#define VICVectCntl4	0xFFFFF210
+#define VICVectCntl5	0xFFFFF214
+#define VICVectCntl6	0xFFFFF218
+#define VICVectCntl7	0xFFFFF21C
+#define VICVectCntl8	0xFFFFF220
+#define VICVectCntl9	0xFFFFF224
+#define VICVectCntl10	0xFFFFF228
+#define VICVectCntl11	0xFFFFF22C
+#define VICVectCntl12	0xFFFFF230
+#define VICVectCntl13	0xFFFFF234
+#define VICVectCntl14	0xFFFFF238
+#define VICVectCntl15	0xFFFFF23C
+
+/* Pin connect block */
+
+#define PINSEL0 0xE002C000	/* 32 bits */
+#define PINSEL1 0xE002C004	/* 32 bits */
+#define PINSEL2 0xE002C014	/* 32 bits */
+
+/* GPIO */
+
+#define IO0PIN 0xE0028000
+#define IO0SET 0xE0028004
+#define IO0DIR 0xE0028008
+#define IO0CLR 0xE002800C
+#define IO1PIN 0xE0028010
+#define IO1SET 0xE0028014
+#define IO1DIR 0xE0028018
+#define IO1CLR 0xE002801C
+#define IO2PIN 0xE0028020
+#define IO2SET 0xE0028024
+#define IO2DIR 0xE0028028
+#define IO2CLR 0xE002802C
+#define IO3PIN 0xE0028030
+#define IO3SET 0xE0028034
+#define IO3DIR 0xE0028038
+#define IO3CLR 0xE002803C
+
+/* Uarts */
+
+#define U0RBR 0xE000C000
+#define U0THR 0xE000C000
+#define U0IER 0xE000C004
+#define U0IIR 0xE000C008
+#define U0FCR 0xE000C008
+#define U0LCR 0xE000C00C
+#define U0LSR 0xE000C014
+#define U0SCR 0xE000C01C
+#define U0DLL 0xE000C000
+#define U0DLM 0xE000C004
+
+#define U1RBR 0xE0010000
+#define U1THR 0xE0010000
+#define U1IER 0xE0010004
+#define U1IIR 0xE0010008
+#define U1FCR 0xE0010008
+#define U1LCR 0xE001000C
+#define U1MCR 0xE0010010
+#define U1LSR 0xE0010014
+#define U1MSR 0xE0010018
+#define U1SCR 0xE001001C
+#define U1DLL 0xE0010000
+#define U1DLM 0xE0010004
+
+/* I2C */
+
+#define I2CONSET 0xE001C000
+#define I2STAT   0xE001C004
+#define I2DAT    0xE001C008
+#define I2ADR    0xE001C00C
+#define I2SCLH   0xE001C010
+#define I2SCLL   0xE001C014
+#define I2CONCLR 0xE001C018
+
+/* SPI */
+
+#define S0SPCR  0xE0020000
+#define S0SPSR  0xE0020004
+#define S0SPDR  0xE0020008
+#define S0SPCCR 0xE002000C
+#define S0SPINT 0xE002001C
+
+#define S1SPCR  0xE0030000
+#define S1SPSR  0xE0030004
+#define S1SPDR  0xE0030008
+#define S1SPCCR 0xE003000C
+#define S1SPINT 0xE003001C
+
+/* CAN controller */
+
+/* skip for now */
+
+/* Timers */
+
+#define T0IR  0xE0004000
+#define T0TCR 0xE0004004
+#define T0TC  0xE0004008
+#define T0PR  0xE000400C
+#define T0PC  0xE0004010
+#define T0MCR 0xE0004014
+#define T0MR0 0xE0004018
+#define T0MR1 0xE000401C
+#define T0MR2 0xE0004020
+#define T0MR3 0xE0004024
+#define T0CCR 0xE0004028
+#define T0CR0 0xE000402C
+#define T0CR1 0xE0004030
+#define T0CR2 0xE0004034
+#define T0CR3 0xE0004038
+#define T0EMR 0xE000403C
+
+#define T1IR  0xE0008000
+#define T1TCR 0xE0008004
+#define T1TC  0xE0008008
+#define T1PR  0xE000800C
+#define T1PC  0xE0008010
+#define T1MCR 0xE0008014
+#define T1MR0 0xE0008018
+#define T1MR1 0xE000801C
+#define T1MR2 0xE0008020
+#define T1MR3 0xE0008024
+#define T1CCR 0xE0008028
+#define T1CR0 0xE000802C
+#define T1CR1 0xE0008030
+#define T1CR2 0xE0008034
+#define T1CR3 0xE0008038
+#define T1EMR 0xE000803C
+
+/* PWM */
+
+/* skip for now */
+
+/* A/D converter */
+
+/* skip for now */
+
+/* Real Time Clock */
+
+/* skip for now */
+
+/* Watchdog */
+
+#define WDMOD  0xE0000000
+#define WDTC   0xE0000004
+#define WDFEED 0xE0000008
+#define WDTV   0xE000000C
+
+/* EmbeddedICE LOGIC */
+
+/* skip for now */
+
+#endif
diff --git a/include/asm-arm/arch-arm720t/mmc.h b/include/asm-arm/arch-arm720t/mmc.h
new file mode 100644
index 0000000..e664a5f
--- /dev/null
+++ b/include/asm-arm/arch-arm720t/mmc.h
@@ -0,0 +1,22 @@
+/*
+ * A dummy header file for use with the LPC2292 port to keep the
+ * compiler happy.
+ *
+ * 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_ARM_TDM_H_
+#define _MMC_ARM_TDM_H_
+#endif /* _MMC_ARM_TDM_H_ */
diff --git a/include/configs/lpc2292sodimm.h b/include/configs/lpc2292sodimm.h
new file mode 100644
index 0000000..7e51523
--- /dev/null
+++ b/include/configs/lpc2292sodimm.h
@@ -0,0 +1,158 @@
+/*
+ * (C) Copyright 2000
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Configuation settings for the EP7312 board.
+ *
+ * Modified to work on Armadillo HT1070 ARM720T board
+ * (C) Copyright 2005 Rowel Atienza rowel@diwalabs.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * If we are developing, we might want to start armboot from ram
+ * so we MUST NOT initialize critical regs like mem-timing ...
+ */
+#undef CONFIG_INIT_CRITICAL		/* undef for developing */
+
+#undef CONFIG_SKIP_LOWLEVEL_INIT
+#undef CONFIG_SKIP_RELOCATE_UBOOT
+
+/*
+ * High Level Configuration Options
+ * (easy to change)
+ */
+#define CONFIG_ARM7		1	/* This is a ARM7 CPU	*/
+#define CONFIG_ARM_THUMB	1	/* this is an ARM720TDMI */
+#define CONFIG_LPC2292
+#undef  CONFIG_ARM7_REVD	 	/* disable ARM720 REV.D Workarounds */
+
+#undef CONFIG_USE_IRQ			/* don't need them anymore */
+
+/*
+ * Size of malloc() pool
+ */
+#define CFG_MALLOC_LEN		(CFG_ENV_SIZE + 128*1024)
+#define CFG_GBL_DATA_SIZE	128	/* size in bytes reserved for initial data */
+
+/*
+ * Hardware drivers
+ */
+
+/*
+ * select serial console configuration
+ */
+#define CONFIG_SERIAL1		1	/* we use Serial line 1 */
+
+/* allow to overwrite serial and ethaddr */
+#define CONFIG_ENV_OVERWRITE
+
+#define CONFIG_BAUDRATE		115200
+
+#define CONFIG_BOOTP_MASK       (CONFIG_BOOTP_DEFAULT|CONFIG_BOOTP_BOOTFILESIZE)
+
+/*
+ * Supported commands
+ */
+#define CONFIG_COMMANDS	       (CONFIG_CMD_DFL	| \
+				CFG_CMD_DHCP	| \
+				CFG_CMD_FAT	| \
+				CFG_CMD_MMC	| \
+				CFG_CMD_NET	| \
+				CFG_CMD_PING)
+
+#define CONFIG_MAC_PARTITION
+#define CONFIG_DOS_PARTITION
+
+/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
+#include <cmd_confdefs.h>
+
+#define CONFIG_BOOTDELAY	5
+
+/*
+ * Miscellaneous configurable options
+ */
+#define	CFG_LONGHELP				/* undef to save memory		*/
+#define	CFG_PROMPT		"LPC2292SODIMM # " /* Monitor Command Prompt	*/
+#define	CFG_CBSIZE		256		/* Console I/O Buffer Size	*/
+#define	CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */
+#define	CFG_MAXARGS		16		/* max number of command args	*/
+#define CFG_BARGSIZE		CFG_CBSIZE	/* Boot Argument Buffer Size	*/
+
+#define CFG_MEMTEST_START	0x40000000	/* memtest works on	*/
+#define CFG_MEMTEST_END		0x40000000	/* 4 ... 8 MB in DRAM	*/
+
+#undef  CFG_CLKS_IN_HZ		/* everything, incl board info, in Hz */
+
+#define	CFG_LOAD_ADDR		0x00040000	/* default load address	for armadillo: kernel img is here*/
+
+#define CFG_SYS_CLK_FREQ        58982400        /* Hz */
+#define	CFG_HZ			2048		/* decrementer freq in Hz */
+
+						/* valid baudrates */
+#define CFG_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200 }
+
+/*-----------------------------------------------------------------------
+ * Stack sizes
+ *
+ * The stack sizes are set up in start.S using the settings below
+ */
+#define CONFIG_STACKSIZE	(128*1024)	/* regular stack */
+#ifdef CONFIG_USE_IRQ
+#define CONFIG_STACKSIZE_IRQ	(4*1024)	/* IRQ stack */
+#define CONFIG_STACKSIZE_FIQ	(4*1024)	/* FIQ stack */
+#endif
+
+/*-----------------------------------------------------------------------
+ * Physical Memory Map
+ */
+#define CONFIG_NR_DRAM_BANKS	1	   /* we have 1 bank of DRAM */
+#define PHYS_SDRAM_1		0x81000000 /* SDRAM Bank #1 */
+#define PHYS_SDRAM_1_SIZE	0x00800000 /* 8 MB SDRAM */
+
+#define PHYS_FLASH_1		0x80000000 /* Flash Bank #1 */
+#define PHYS_FLASH_SIZE		0x00200000 /* 2 MB */
+
+#define CFG_FLASH_BASE		PHYS_FLASH_1
+
+/*-----------------------------------------------------------------------
+ * FLASH and environment organization
+ */
+#define CFG_MAX_FLASH_BANKS	2	/* max number of memory banks		*/
+#define CFG_MAX_FLASH_SECT	1024	/* max number of sectors on one chip	*/
+
+/* timeout values are in ticks */
+#define CFG_FLASH_ERASE_TOUT	(2*CFG_HZ) /* Timeout for Flash Erase */
+#define CFG_FLASH_WRITE_TOUT	(2*CFG_HZ) /* Timeout for Flash Write */
+
+#define	CFG_ENV_IS_IN_FLASH	1
+#define CFG_ENV_ADDR		(0x0 + 0x3C000)	/* Addr of Environment Sector	*/
+#define CFG_ENV_SIZE		0x2000 /* Total Size of Environment Sector	*/
+
+#define CONFIG_CMDLINE_TAG
+#define CONFIG_SETUP_MEMORY_TAGS
+#define CONFIG_INITRD_TAG
+#define CONFIG_MMC 1
+
+#endif	/* __CONFIG_H */
diff --git a/include/flash.h b/include/flash.h
index 8b7e824..55b6d8f 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -304,6 +304,7 @@
 
 #define TOSH_ID_FVT160	0xC2		/* TC58FVT160 ID (16 M, top )		*/
 #define TOSH_ID_FVB160	0x43		/* TC58FVT160 ID (16 M, bottom )	*/
+#define PHILIPS_LPC2292 0x0401FF13  /* LPC2292 internal FLASH			*/
 
 /*-----------------------------------------------------------------------
  * Internal FLASH identification codes