Add the files for the SMN42 board
diff --git a/cpu/arm720t/lpc2292/Makefile b/cpu/arm720t/lpc2292/Makefile
new file mode 100644
index 0000000..240f1e3
--- /dev/null
+++ b/cpu/arm720t/lpc2292/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000-2007
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).a
+
+COBJS	= flash.o mmc.o mmc_hw.o spi.o
+SOBJS	= $(obj)iap_entry.o
+
+SRCS	:= $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS) $(SOBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS)
+
+# this MUST be compiled as thumb code!
+$(SOBJS):
+	$(CC) $(AFLAGS) -march=armv4t -c -o $(SOBJS) iap_entry.S
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/cpu/arm720t/lpc2292/flash.c b/cpu/arm720t/lpc2292/flash.c
new file mode 100644
index 0000000..e5c8697
--- /dev/null
+++ b/cpu/arm720t/lpc2292/flash.c
@@ -0,0 +1,249 @@
+/*
+ * (C) Copyright 2006 Embedded Artists AB <www.embeddedartists.com>
+ *
+ * Modified to remove all but the IAP-command related code by
+ * Gary Jennejohn <garyj@denx.de>
+ *
+ * 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
+
+static unsigned long command[5];
+static unsigned long result[2];
+
+extern void iap_entry(unsigned long * command, unsigned long * result);
+
+/*-----------------------------------------------------------------------
+ *
+ */
+static 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 lpc2292_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;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int lpc2292_flash_erase (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 lpc2292_write_buff (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;
+
+	debug("\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));
+
+	/* 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);
+	lpc2292_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++) {
+		debug("copy middle block: %lX -> %lX 512 bytes, "
+		"%lX -> %lX 512 bytes\n",
+		(ulong)src,
+		(ulong)COPY_BUFFER_LOCATION,
+		(ulong)COPY_BUFFER_LOCATION,
+		(ulong)addr);
+
+		memcpy((void*)COPY_BUFFER_LOCATION, src, 512);
+		lpc2292_copy_buffer_to_flash(info, addr);
+		src += 512;
+		addr += 512;
+	}
+
+
+	if (last_copy_size > 0) {
+		debug("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);
+
+		/* copy last block */
+		memcpy((void*)COPY_BUFFER_LOCATION,
+			(void*)(last_block * 512), 512);
+		memcpy((void*)COPY_BUFFER_LOCATION,
+			src, last_copy_size);
+		lpc2292_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;
+}
diff --git a/cpu/arm720t/lpc2292/iap_entry.S b/cpu/arm720t/lpc2292/iap_entry.S
new file mode 100644
index 0000000..c31d519
--- /dev/null
+++ b/cpu/arm720t/lpc2292/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/cpu/arm720t/lpc2292/mmc.c b/cpu/arm720t/lpc2292/mmc.c
new file mode 100644
index 0000000..fd7f149b
--- /dev/null
+++ b/cpu/arm720t/lpc2292/mmc.c
@@ -0,0 +1,157 @@
+/*
+ * 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 <asm/arch/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,
+			     void *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();
+	/* this meeds to be done twice */
+	mmc_hw_init();
+	udelay(1000);
+	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/cpu/arm720t/lpc2292/mmc_hw.c b/cpu/arm720t/lpc2292/mmc_hw.c
new file mode 100644
index 0000000..b4dc4a6
--- /dev/null
+++ b/cpu/arm720t/lpc2292/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 <asm/arch/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/cpu/arm720t/lpc2292/mmc_hw.h b/cpu/arm720t/lpc2292/mmc_hw.h
new file mode 100644
index 0000000..3687dbf
--- /dev/null
+++ b/cpu/arm720t/lpc2292/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/cpu/arm720t/lpc2292/spi.c b/cpu/arm720t/lpc2292/spi.c
new file mode 100644
index 0000000..d296bda
--- /dev/null
+++ b/cpu/arm720t/lpc2292/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 <asm/arch/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;
+}