[U-Boot] [PATCH 1/2] LPC2468 support

Remco Poelstra
2009-04-28T09:14:20Z

This patch includes support for the LPC2468 processor from NXP.

Signed-off-by: Remco Poelstra <remco.poelstra+u-boot@duran-audio.com>
---
It now also includes support for the ethernet interface.
It does not include any changes to flash related code, until it's known
where to put it. Stefan was right that the unreferenced function are needed
by the board code.
Neither does it contain any significant changes to the interrupt code,
waiting for the patch to clean it up.
I would be gratefull if the patch can be applied before then, I can then help
clean up the code, instead of staying behind.
Concerning thumb code: As explained earlier, it is needed to call the internal
IAP functions. These are seldom used, so there is no performance penalty.

From 10ae52e03e99a2567f4b74434ba346b45c24ac02 Mon Sep 17 00:00:00 2001
From: Remco Poelstra <remco.poelstra+u-boot@duran-audio.com>
Date: Fri, 24 Apr 2009 12:18:21 +0200
Subject: [PATCH] Support for LPC2468 processor from NXP

---
Makefile | 3 +
cpu/arm720t/cpu.c | 4 +-
cpu/arm720t/interrupts.c | 38 ++-
cpu/arm720t/lpc24xx/Makefile | 50 +++
cpu/arm720t/lpc24xx/flash.c | 236 +++++++++++++++
cpu/arm720t/lpc24xx/iap_entry.S | 7 +
cpu/arm720t/start.S | 12 +-
drivers/net/Makefile | 1 +
drivers/net/lpc2468_eth.c | 494 +++++++++++++++++++++++++++++++
drivers/net/lpc2468_eth.h | 159 ++++++++++
drivers/serial/Makefile | 1 +
drivers/serial/serial_lpc2468.c | 119 ++++++++
include/asm-arm/arch-lpc24xx/hardware.h | 32 ++
include/asm-arm/arch-lpc24xx/immap.h | 406 +++++++++++++++++++++++++
include/asm-arm/config.h | 4 +
include/flash.h | 1 +
16 files changed, 1558 insertions(+), 9 deletions(-)
create mode 100644 cpu/arm720t/lpc24xx/Makefile
create mode 100644 cpu/arm720t/lpc24xx/flash.c
create mode 100644 cpu/arm720t/lpc24xx/iap_entry.S
create mode 100644 drivers/net/lpc2468_eth.c
create mode 100644 drivers/net/lpc2468_eth.h
create mode 100644 drivers/serial/serial_lpc2468.c
create mode 100644 include/asm-arm/arch-lpc24xx/hardware.h
create mode 100644 include/asm-arm/arch-lpc24xx/immap.h

diff --git a/Makefile b/Makefile
index e91c051..fb23ee6 100644
--- a/Makefile
+++ b/Makefile
@@ -2940,6 +2940,9 @@ B2_config : unconfig
## ARM720T Systems
#########################################################################

+LPC2468_config: unconfig
+ @$(MKCONFIG) $(@:_config=) arm arm720t LPC2468 NULL lpc24xx
+
armadillo_config: unconfig
@$(MKCONFIG) $(@:_config=) arm arm720t armadillo

diff --git a/cpu/arm720t/cpu.c b/cpu/arm720t/cpu.c
index 6c40903..29e13d0 100644
--- a/cpu/arm720t/cpu.c
+++ b/cpu/arm720t/cpu.c
@@ -75,7 +75,9 @@ int cleanup_before_linux (void)
/* go to high speed */
IO_SYSCON3 = (IO_SYSCON3 & ~CLKCTL) | CLKCTL_73;
#endif
-#elif defined(CONFIG_NETARM) || defined(CONFIG_S3C4510B) || defined(CONFIG_LPC2292)
+#elif defined(CONFIG_NETARM) || defined(CONFIG_S3C4510B) ||\
+ defined(CONFIG_LPC2000)
+
disable_interrupts ();
/* Nothing more needed */
#elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR)
diff --git a/cpu/arm720t/interrupts.c b/cpu/arm720t/interrupts.c
index 39ed345..8671b63 100644
--- a/cpu/arm720t/interrupts.c
+++ b/cpu/arm720t/interrupts.c
@@ -29,17 +29,26 @@
#include <common.h>
#include <clps7111.h>
#include <asm/proc-armv/ptrace.h>
+#include <asm/io.h>
+#if defined(CONFIG_LPC2468)
+#include <asm/arch/immap.h>
+#else
#include <asm/hardware.h>
+#endif

#ifndef CONFIG_NETARM
+
+#if defined(CONFIG_LPC2292)
+#define TIMER_LOAD_VAL 0xffff
+#define READ_TIMER (0xFFFFFFFF - GET32(T0TC))
+#elif defined(CONFIG_LPC2468)
+#define TIMER_LOAD_VAL 0
+#define READ_TIMER (0xFFFFFFFF - 0xE0004008)
+#else
/* we always count down the max. */
#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
@@ -80,6 +89,14 @@ void do_irq (struct pt_regs *pt_regs)
pfnct = (void (*)(void))VICVectAddr;

(*pfnct)();
+#elif defined(CONFIG_LPC2468)
+ void (*pfnct) (void);
+ vic_2468_t *vic = &(((immap_t *)CONFIG_SYS_IMMAP)->ahb.vic);
+
+ pfnct = (void (*)(void))(&(vic->vicaddr));
+
+ (*pfnct) ();
+
#else
#error do_irq() not defined for this CPU type
#endif
@@ -112,6 +129,9 @@ static ulong lastdec;

int interrupt_init (void)
{
+#if defined(CONFIG_LPC2468)
+ timer_2468_t *timer0=&(((immap_t *)CONFIG_SYS_IMMAP)->apb.timer0);
+#endif

#if defined(CONFIG_NETARM)
/* disable all interrupts */
@@ -185,6 +205,13 @@ int interrupt_init (void)
PUT32(T0MCR, 0);
PUT32(T0TC, 0);
PUT32(T0TCR, 1); /* enable timer0 */
+#elif defined(CONFIG_LPC2468)
+ writel (0, &(timer0->ir)); /*disable all timer0 interupts */
+ writel (0, &(timer0->tcr)); /*disable timer0 */
+ writel (CFG_SYS_CLK_FREQ / CONFIG_SYS_HZ - 1, &(timer0->pr));
+ writel (0, &(timer0->mcr));
+ writel (0, &(timer0->tc));
+ writel (1, &(timer0->tcr));

#else
#error No interrupt_init() defined for this CPU type
@@ -201,7 +228,8 @@ int interrupt_init (void)
*/

-#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_NETARM) || defined(CONFIG_ARMADILLO) || defined(CONFIG_LPC2292)
+#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_NETARM) ||\
+ defined(CONFIG_ARMADILLO) || defined(CONFIG_LPC2000)

void reset_timer (void)
{
diff --git a/cpu/arm720t/lpc24xx/Makefile b/cpu/arm720t/lpc24xx/Makefile
new file mode 100644
index 0000000..f091502
--- /dev/null
+++ b/cpu/arm720t/lpc24xx/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd at 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
+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/lpc24xx/flash.c b/cpu/arm720t/lpc24xx/flash.c
new file mode 100644
index 0000000..963bf6e
--- /dev/null
+++ b/cpu/arm720t/lpc24xx/flash.c
@@ -0,0 +1,236 @@
+/*
+ * (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/io.h>
+#include <asm/arch/immap.h>
+
+/* IAP commands use 32 bytes at the top of CPU internal sram, we
+ * use 512 bytes below that
+ */
+
+#define COPY_BUFFER_LOCATION 0x4000fde0
+
+#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);
+
+/*-----------------------------------------------------------------------
+ *
+ */
+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 lpc24xx_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 lpc24xx_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 lpc24xx_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;
+ sys_con_2468_t *sys_con=&(((immap_t *)CONFIG_SYS_IMMAP)->apb.sys_con);
+ 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);
+ lpc24xx_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);
+ lpc24xx_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);
+ lpc24xx_copy_buffer_to_flash (info, addr);
+ }
+
+ /* verify write */
+ memmap_value = readl(&(sys_con->memmap));
+
+ disable_interrupts ();
+
+ writel(01, &(sys_con->memmap)); /* 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++;
+ }
+
+ writel(memmap_value, &(sys_con->memmap));
+ enable_interrupts ();
+
+ return ret;
+}
diff --git a/cpu/arm720t/lpc24xx/iap_entry.S b/cpu/arm720t/lpc24xx/iap_entry.S
new file mode 100644
index 0000000..c31d519
--- /dev/null
+++ b/cpu/arm720t/lpc24xx/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/start.S b/cpu/arm720t/start.S
index 022b873..1b2e4bf 100644
--- a/cpu/arm720t/start.S
+++ b/cpu/arm720t/start.S
@@ -127,7 +127,7 @@ reset:
bl cpu_init_crit
#endif

-#ifdef CONFIG_LPC2292
+#if defined(CONFIG_LPC2000)
bl lowlevel_init
#endif

@@ -368,6 +368,12 @@ lock_loop:
ldr r0, VPBDIV_ADR
mov r1, #0x01 /* VPB clock is same as process clock */
str r1, [r0]
+#elif defined(CONFIG_LPC2468)
+ ldr r0, =0x40008000 /* 0x40000000 is internal SRAM,
+ * 0x4000FFFF is end of SRAM
+ */
+ mov sp,r0
+ sub sl,sp,#0x2000
#else
#error No cpu_init_crit() defined for current CPU type
#endif
@@ -383,7 +389,7 @@ lock_loop:
str r1, [r0]
#endif

-#ifndef CONFIG_LPC2292
+#if !defined(CONFIG_LPC2000)
mov ip, lr
/*
* before relocating, we have to setup RAM timing
@@ -601,7 +607,7 @@ reset_cpu:
* 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)
+#elif defined(CONFIG_LPC2000)
.align 5
.globl reset_cpu
reset_cpu:
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a360a50..83a1401 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -42,6 +42,7 @@ COBJS-$(CONFIG_GRETH) += greth.o
COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
COBJS-$(CONFIG_DRIVER_LAN91C96) += lan91c96.o
+COBJS-$(CONFIG_LPC2468_ETH) += lpc2468_eth.o
COBJS-$(CONFIG_MACB) += macb.o
COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
COBJS-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
diff --git a/drivers/net/lpc2468_eth.c b/drivers/net/lpc2468_eth.c
new file mode 100644
index 0000000..b16e404
--- /dev/null
+++ b/drivers/net/lpc2468_eth.c
@@ -0,0 +1,494 @@
+/*
+ * (C) Copyright 2009 Duran Audio B.V. <www.duran-audio.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
+ *
+ * 18-03-2009 Updated for U-boot 2009.3
+ * by Remco Poelstra <remco.poelstra+u-boot@duran-audio.com>
+ * Based on sample code from NXP
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <asm/io.h>
+#include <asm/arch/immap.h>
+#include "lpc2468_eth.h"
+
+/******************************************************************************
+ * Local variables
+ *****************************************************************************/
+
+static unsigned char macAddr[6];
+static volatile int phyAddr = 0x1000;
+static int eth_initialized = 0;
+mac_2468_t *mac=&(((immap_t *)CONFIG_SYS_IMMAP)->ahb.mac);
+
+/******************************************************************************
+ * Local functions
+ *****************************************************************************/
+
+static void writePhy (u32 phyReg, u32 phyData)
+{
+
+ /* write command */
+ writel (0x0, &(mac->mcmd));
+
+ /* [12:8] == PHY addr, [4:0]=0x00(BMCR) register addr */
+ writel ((phyAddr | phyReg), &(mac->madr));
+ writel (phyData, &(mac->mwtd));
+ while (readl (&(mac->mind)) != 0) ;
+}
+
+static u32 readPhy (u32 phyReg)
+{
+
+ /* read command */
+ writel (0x1, &(mac->mcmd));
+
+ /* [12:8] == PHY addr, [4:0]=0x00(BMCR) register addr */
+ writel ((phyAddr | phyReg), &(mac->madr));
+
+ while (readl (&(mac->mind)) != 0);
+
+ writel (0x0, &(mac->mcmd));
+
+ return readl (&(mac->mrdd));
+}
+
+static int emac_start_xmit (volatile void *buf, int length)
+{
+
+ u32 txProduceIndex = 0;
+ u32 txConsumeIndex = 0;
+ u8 *pData = 0;
+ u32 len = length;
+ u32 sendLen = 0;
+ u32 *tx_desc_addr = NULL;
+
+ txProduceIndex = readl (&(mac->txproduceindex));
+ txConsumeIndex = readl (&(mac->txconsumeindex));
+
+ if (txConsumeIndex != txProduceIndex) {
+ /* TODO why return here? This just means that the transmit array isn't empty */
+ printf ("emac: emac_tx transmit array isn't empty\n");
+ return -1;
+ }
+
+ if (txProduceIndex == EMAC_TX_DESCRIPTOR_COUNT) {
+ /* should never happen */
+ printf ("emac: emac_tx produce index == count\n");
+ }
+
+ if (len > 0) {
+ pData = (u8 *) EMAC_TX_BUFFER_ADDR;
+ memcpy (pData, (void *)buf, length);
+
+ do {
+ tx_desc_addr =
+ (u32 *) (TX_DESCRIPTOR_ADDR + txProduceIndex * 8);
+
+ sendLen = len;
+ if (sendLen > EMAC_BLOCK_SIZE) {
+ sendLen = EMAC_BLOCK_SIZE;
+ } else {
+ /* last fragment */
+ sendLen |= EMAC_TX_DESC_LAST;
+ }
+
+ writel ((unsigned long) pData, tx_desc_addr);
+ tx_desc_addr++;
+ writel ((u32) (EMAC_TX_DESC_INT | (sendLen - 1)),
+ tx_desc_addr);
+
+ txProduceIndex++;
+ if (txProduceIndex == EMAC_TX_DESCRIPTOR_COUNT) {
+ txProduceIndex = 0;
+ }
+
+ writel (txProduceIndex, &(mac->txproduceindex));
+
+ len -= (sendLen & ~EMAC_TX_DESC_LAST);
+ pData += (sendLen & ~EMAC_TX_DESC_LAST);
+ } while (len > 0);
+ }
+
+ return 0;
+}
+
+static void emac_rx (void)
+{
+ u32 rxProduceIndex = 0;
+ u32 rxConsumeIndex = 0;
+ u32 *rxStatusAddr = 0;
+ u32 recvSize = 0;
+ u32 *recvAddr = 0;
+
+ /* the input parameter, EMCBuf, needs to be word aligned */
+
+ rxProduceIndex = readl (&(mac->rxproduceindex));
+ rxConsumeIndex = readl (&(mac->rxconsumeindex));
+
+ /* consume the received packets */
+ while (rxConsumeIndex != rxProduceIndex) {
+
+ rxStatusAddr = (u32 *) (RX_STATUS_ADDR + rxConsumeIndex * 8);
+
+ recvSize = readl (rxStatusAddr);
+
+ if ((recvSize & RX_DESC_STATUS_LAST) == 0) {
+ /* TODO: could this occur when EMAC_BLOCK_SIZE == 0x0600? */
+ printf ("emac_rx: NOT LAST fragment\n");
+ }
+
+ recvSize = (recvSize & DESC_SIZE_MASK) + 1;
+
+ recvAddr = (u32 *) (RX_DESCRIPTOR_ADDR + rxConsumeIndex * 8);
+
+ /* TODO: allocate buffer? */
+ NetReceive ((uchar *) (readl (recvAddr) /*inBuf */ ),
+ recvSize);
+
+ rxConsumeIndex++;
+ if (rxConsumeIndex == EMAC_RX_DESCRIPTOR_COUNT) {
+ rxConsumeIndex = 0;
+ }
+
+ writel (rxConsumeIndex, &(mac->rxconsumeindex));
+
+ }
+
+}
+
+static void emac_interrupt (void)
+{
+ volatile u32 regValue = 0;
+
+ regValue = readl (&(mac->intstatus));
+
+ do {
+ if (regValue == 0) {
+ break;
+ }
+
+ if (regValue & EMAC_INT_RXOVERRUN) {
+ writel (EMAC_INT_RXOVERRUN, &(mac->intclear));
+ printf ("rxOverrun\n");
+ break;
+ }
+
+ if (regValue & EMAC_INT_RXERROR) {
+ writel (EMAC_INT_RXERROR, &(mac->intclear));
+ }
+
+ if (regValue & EMAC_INT_RXFINISHED) {
+ writel (EMAC_INT_RXFINISHED, &(mac->intclear));
+ }
+
+ if (regValue & EMAC_INT_RXDONE) {
+ writel (EMAC_INT_RXDONE, &(mac->intclear));
+ emac_rx ();
+ }
+
+ if (regValue & EMAC_INT_TXUNDERRUN) {
+ printf ("TX underrun\n");
+ writel (EMAC_INT_TXUNDERRUN, &(mac->intclear));
+ break;
+ }
+
+ if (regValue & EMAC_INT_TXERROR) {
+ printf ("TX err\n");
+ writel (EMAC_INT_TXERROR, &(mac->intclear));
+ break;
+ }
+
+ if (regValue & EMAC_INT_TXFINISHED) {
+ writel (EMAC_INT_TXFINISHED, &(mac->intclear));
+ }
+
+ if (regValue & EMAC_INT_TXDONE) {
+ writel (EMAC_INT_TXDONE, &(mac->intclear));
+ }
+
+ } while (0);
+}
+
+static int emac_open (void)
+{
+ /* enable Rx & Tx */
+ BFS32 (&(mac->command), CMD_RX_ENABLE);
+ BFS32 (&(mac->command), CMD_TX_ENABLE);
+ BFS32 (&(mac->command), CMD_PASS_RX_FILTER);
+ BFS32 (&(mac->mac1), 0x01);
+
+ return 0;
+}
+
+static void emac_close (void)
+{
+ /* disable Rx6 Tx */
+ BFC32 (&(mac->command), CMD_RX_ENABLE);
+ BFC32 (&(mac->command), CMD_TX_ENABLE);
+ BFC32 (&(mac->mac1), 0x01);
+}
+
+static int phyInit (void)
+{
+ int i = 0;
+ u32 regValue = 0;
+ u32 timeout = 0;
+
+ writel (0x801C, &(mac->mcfg)); /* host clock divided by 28,
+ no suppress preamble,
+ no scan increment */
+
+ for (i = 0; i < 0x40; i++)
+ asm volatile (" nop");
+
+ /* MII Mgmt. Divided by 28. */
+ writel (0x001C, &(mac->mcfg));
+ writel (0x0, &(mac->mcmd));
+
+ for (i = 0; i < 0x100; i++)
+ asm volatile (" nop");
+
+ /*Reset the PHY */
+ writePhy (PHY_BMCR, BMCR_RESET);
+ udelay (100);
+
+ timeout = MII_BMSR_TIMEOUT * 4;
+ while (timeout != 0) {
+ regValue = readPhy (PHY_BMCR);
+ if ((regValue & BMCR_RESET) == 0x0000) {
+ /* reset bit has been cleared */
+ break;
+ }
+ timeout--;
+ }
+
+ if (timeout == 0) {
+ printf (" Error: phyInit failed to reset PHY\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void emacTxDescriptorInit (void)
+{
+ int i = 0;
+ u32 *txDescAddr = NULL;
+ u32 *txStatusAddr = NULL;
+
+ /* base address of tx descriptor array */
+ writel (TX_DESCRIPTOR_ADDR, &(mac->txdescriptor));
+
+ /* base address of tx status */
+ writel (TX_STATUS_ADDR, &(mac->txstatus));
+
+ /* number of tx descriptors */
+ writel (EMAC_TX_DESCRIPTOR_COUNT - 1, &(mac->txdescriptornumber));
+
+ for (i = 0; i < EMAC_TX_DESCRIPTOR_COUNT; i++) {
+ txDescAddr = (u32 *) (TX_DESCRIPTOR_ADDR + i * 8);
+ writel ((EMAC_TX_BUFFER_ADDR + i * EMAC_BLOCK_SIZE),
+ (unsigned long)txDescAddr);
+
+ /* control field in descriptor */
+ txDescAddr++;
+ writel ((EMAC_TX_DESC_INT | (EMAC_BLOCK_SIZE - 1)),
+ (unsigned long)txDescAddr);
+ }
+
+ for (i = 0; i < EMAC_TX_DESCRIPTOR_COUNT; i++) {
+
+ txStatusAddr = (u32 *) (TX_STATUS_ADDR + i * 4);
+
+ /* set status info to 0 */
+ writel (0x0, (unsigned long)txStatusAddr);
+ }
+
+ writel (0x0, &(mac->txproduceindex));
+}
+
+static void emacRxDescriptorInit (void)
+{
+ int i;
+ u32 *rxDescAddr = NULL;
+ u32 *rxStatusAddr = NULL;
+
+ /* base address of rx descriptor array */
+ writel (RX_DESCRIPTOR_ADDR, &(mac->rxdescriptor));
+
+ /* base address of rx status */
+ writel (RX_STATUS_ADDR, &(mac->rxstatus));
+
+ /* number of rx descriptors */
+ writel (EMAC_RX_DESCRIPTOR_COUNT - 1, &(mac->rxdescriptornumber));
+
+ for (i = 0; i < EMAC_RX_DESCRIPTOR_COUNT; i++) {
+ rxDescAddr = (u32 *) (RX_DESCRIPTOR_ADDR + i * 8);
+
+ writel ((EMAC_RX_BUFFER_ADDR + i * EMAC_BLOCK_SIZE),
+ (unsigned long)rxDescAddr);
+
+ rxDescAddr++;
+
+ writel ((EMAC_RX_DESC_INT |
+ ((EMAC_BLOCK_SIZE - 1) & DESC_SIZE_MASK)),
+ (unsigned long)rxDescAddr);
+ }
+
+ for (i = 0; i < EMAC_RX_DESCRIPTOR_COUNT; i++) {
+ /* RX status, two words, status info. and status hash CRC. */
+ rxStatusAddr = (u32 *) (RX_STATUS_ADDR + i * 8);
+ writel (0x0, (unsigned long)rxStatusAddr);
+ rxStatusAddr++;
+ writel (0x0, (unsigned long)rxStatusAddr);
+ }
+
+ writel (0x0, &(mac->rxconsumeindex));
+}
+
+static int emacInit (void)
+{
+ int i = 0;
+ pin_connect_2468_t *pin_connect=&(((immap_t *)CONFIG_SYS_IMMAP)->apb.pin_connect);
+
+ /* turn on the ethernet MAC clock in PCONP, bit 30 */
+ BFS32 (&(((immap_t *)CONFIG_SYS_IMMAP)->apb.sys_con.pconp), PCONP_EMAC_CLOCK);
+ /*-----------------------------------------------------------------------
+ * write to PINSEL2/3 to select the PHY functions on P1[17:0]
+ *-----------------------------------------------------------------------*/
+
+ /* documentation needs to be updated */
+ writel (0x55555555, &(pin_connect->pinsel2)); /* selects P1[0,1,4,8,9,10,14,15] */
+ writel (0x00000005, &(pin_connect->pinsel3)); /* selects P1[17:16] */
+
+ /*reset MAC modules, tx, mcs_tx, rx, mcs_rx, simulation and soft reset*/
+ writel (0xCF00, &(mac->mac1));
+
+ /* reset datapaths and host registers */
+ writel (0x0038, &(mac->command));
+
+ /* short delay after reset */
+ for (i = 0; i < 0x40; i++)
+ asm volatile (" nop");
+
+ /*Remove reset conditions*/
+ writel (0x0, &(mac->mac1));
+
+ /*disable Tx*/
+ BFC32 (&(mac->command), CMD_TX_ENABLE);
+
+ /*disable Rx*/
+ BFC32 (&(mac->command), CMD_RX_ENABLE);
+
+ /*initialize MAC2 to default value
+ TODO don't thinkt this is necessary?? m_nic_write(EMAC_MAC2, 0x0);*/
+ writel (0x030, &(mac->mac2));
+
+ /*non back-to-back Inter-Packet-Gap register
+ The manual recommends the value 0x12 */
+ writel (0x12, &(mac->ipgr));
+
+ /*collision window/retry register. Using recommended value from manual*/
+ writel (0x370F, &(mac->clrt));
+
+ /* intialize PHY. */
+ if (phyInit () < 0)
+ return -1;
+
+ /* write the mac address */
+ writel ((macAddr[5] << 8 | macAddr[4]), &(mac->sa0));
+ writel ((macAddr[3] << 8 | macAddr[2]), &(mac->sa1));
+ writel ((macAddr[1] << 8 | macAddr[0]), &(mac->sa2));
+
+ printf ("emac: MAC address = %2x:%2x:%2x:%2x:%2x:%2x\n",
+ macAddr[0],
+ macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
+
+ emacTxDescriptorInit ();
+ emacRxDescriptorInit ();
+
+ /* pass all receive frames */
+ BFS32 (&(mac->mac1), 0x002);
+
+ /* set up the Rx filter
+ [0]-AllUnicast, [1]-AllBroadCast, [2]-AllMulticast, [3]-UnicastHash
+ [4]-MulticastHash, [5]-Perfect, [12]-MagicPacketEnWoL,
+ [13]-RxFilterEnWoL
+ PUT32(MAC_RXFILTERCTRL, 0x0022); */
+ writel (0x003F, &(mac->rxfilterctrl)); /*Pass everything */
+
+ /* clear all interrupts */
+ writel (0xFFFF, &(mac->intclear));
+
+ /* enable interrupts (not SoftInt and WoL) */
+ writel (0x00FF, &(mac->intenable));
+
+ return 0;
+}
+
+/* ##############################
+ * u-boot interface
+ * ##############################
+ */
+
+/*
+ * Returns 0 when failes otherwise 1
+ */
+int eth_init (bd_t * bis)
+{
+ int ret;
+ if (!eth_initialized) {
+ if (!eth_getenv_enetaddr ("ethaddr", macAddr)) {
+ printf ("Failed to get MAC address from environment\n");
+ return 1;
+ }
+
+ ret = emacInit ();
+ if (ret != 0) {
+ return ret;
+ }
+
+ eth_initialized = 1;
+ }
+
+ emac_open ();
+ return 0;
+}
+
+int eth_send (volatile void *packet, int length)
+{
+ emac_start_xmit (packet, length);
+ return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * Check for received packets. Call NetReceive for each packet. The return
+ * value is ignored by the caller.
+ */
+int eth_rx (void)
+{
+ emac_interrupt ();
+ return 0;
+}
+
+void eth_halt (void)
+{
+ emac_close ();
+}
diff --git a/drivers/net/lpc2468_eth.h b/drivers/net/lpc2468_eth.h
new file mode 100644
index 0000000..b1c4671
--- /dev/null
+++ b/drivers/net/lpc2468_eth.h
@@ -0,0 +1,159 @@
+#ifndef LPC2468_ETH_H
+#define LPC2468_ETH_H
+
+/******************************************************************************
+ * Typedefs and defines
+ *****************************************************************************/
+#define MAX_PHY_INIT_RETRY 10
+
+/* EMAC MODULE ID */
+#define OLD_EMAC_MODULE_ID ((0x3902 << 16) | 0x2000)
+
+/* MAC registers and parameters */
+#define PCONP_EMAC_CLOCK 0x40000000
+
+#define SPEED_100 1
+#define SPEED_10 0
+#define FULL_DUPLEX 1
+#define HALF_DUPLEX 0
+
+#define EMAC_RAM_ADDR 0x7FE00000
+#define EMAC_RAM_SIZE 0x00004000
+
+#define EMAC_TX_DESCRIPTOR_COUNT 5
+#define EMAC_RX_DESCRIPTOR_COUNT 4
+
+/*
+ * (Rx|Tx)Descriptor ::
+ * [4] packet - base address of the buffer containing the data
+ * [4] control - control information
+ */
+#define TX_DESCRIPTOR_SIZE (EMAC_TX_DESCRIPTOR_COUNT * 8)
+#define RX_DESCRIPTOR_SIZE (EMAC_RX_DESCRIPTOR_COUNT * 8)
+
+/*
+ * TxStatus ::
+ * [4] status
+ */
+#define TX_STATUS_SIZE (EMAC_TX_DESCRIPTOR_COUNT * 4)
+
+/*
+ * RxStatus ::
+ * [4] status - receive status flags
+ * [4] statusHashCRC - concat of dest addr hash CRC and src addr CRC
+ */
+#define RX_STATUS_SIZE (EMAC_RX_DESCRIPTOR_COUNT * 8)
+
+#define TOTAL_DESCRIPTOR_SIZE (TX_DESCRIPTOR_SIZE + RX_DESCRIPTOR_SIZE + TX_STATUS_SIZE + RX_STATUS_SIZE)
+
+/* descriptors are placed at the end of the emac address space */
+#define EMAC_DESCRIPTOR_ADDR (EMAC_RAM_ADDR + EMAC_RAM_SIZE - TOTAL_DESCRIPTOR_SIZE)
+
+#define TX_DESCRIPTOR_ADDR EMAC_DESCRIPTOR_ADDR
+#define TX_STATUS_ADDR (EMAC_DESCRIPTOR_ADDR + TX_DESCRIPTOR_SIZE)
+#define RX_DESCRIPTOR_ADDR (TX_STATUS_ADDR + TX_STATUS_SIZE)
+#define RX_STATUS_ADDR (RX_DESCRIPTOR_ADDR + RX_DESCRIPTOR_SIZE)
+
+#define EMAC_DMA_ADDR EMAC_RAM_ADDR
+#define EMAC_DMA_SIZE EMAC_RAM_ADDR + EMAC_RAM_END - TOTAL_DESCRIPTOR_SIZE
+
+#define EMAC_BLOCK_SIZE 0x600
+#define EMAC_TX_BLOCK_NUM 5
+#define EMAC_RX_BLOCK_NUM 5
+#define TOTAL_EMAC_BLOCK_NUM 10
+
+#define EMAC_BUFFER_SIZE (EMAC_BLOCK_SIZE * (EMAC_TX_BLOCK_NUM + EMAC_RX_BLOCK_NUM ))
+#define EMAC_TX_BUFFER_ADDR EMAC_RAM_ADDR
+#define EMAC_RX_BUFFER_ADDR (EMAC_RAM_ADDR + EMAC_BLOCK_SIZE * EMAC_TX_BLOCK_NUM)
+
+/* EMAC Descriptor TX and RX Control fields */
+#define EMAC_TX_DESC_INT 0x80000000
+#define EMAC_TX_DESC_LAST 0x40000000
+#define EMAC_TX_DESC_CRC 0x20000000
+#define EMAC_TX_DESC_PAD 0x10000000
+#define EMAC_TX_DESC_HUGE 0x08000000
+#define EMAC_TX_DESC_OVERRIDE 0x04000000
+
+#define EMAC_RX_DESC_INT 0x80000000
+
+/* EMAC Descriptor status related definition */
+#define TX_DESC_STATUS_ERR 0x80000000
+#define TX_DESC_STATUS_NODESC 0x40000000
+#define TX_DESC_STATUS_UNDERRUN 0x20000000
+#define TX_DESC_STATUS_LCOL 0x10000000
+#define TX_DESC_STATUS_ECOL 0x08000000
+#define TX_DESC_STATUS_EDEFER 0x04000000
+#define TX_DESC_STATUS_DEFER 0x02000000
+#define TX_DESC_STATUS_COLCNT 0x01E00000 /* four bits, it's a mask, not exact count */
+
+#define RX_DESC_STATUS_ERR 0x80000000
+#define RX_DESC_STATUS_LAST 0x40000000
+#define RX_DESC_STATUS_NODESC 0x20000000
+#define RX_DESC_STATUS_OVERRUN 0x10000000
+#define RX_DESC_STATUS_ALGNERR 0x08000000
+#define RX_DESC_STATUS_RNGERR 0x04000000
+#define RX_DESC_STATUS_LENERR 0x02000000
+#define RX_DESC_STATUS_SYMERR 0x01000000
+#define RX_DESC_STATUS_CRCERR 0x00800000
+#define RX_DESC_STATUS_BCAST 0x00400000
+#define RX_DESC_STATUS_MCAST 0x00200000
+#define RX_DESC_STATUS_FAILFLT 0x00100000
+#define RX_DESC_STATUS_VLAN 0x00080000
+#define RX_DESC_STATUS_CTLFRAM 0x00040000
+
+#define DESC_SIZE_MASK 0x000007FF /* 11 bits for both TX and RX */
+
+/* EMAC interrupt controller related definition */
+#define EMAC_INT_RXOVERRUN 0x01 << 0
+#define EMAC_INT_RXERROR 0x01 << 1
+#define EMAC_INT_RXFINISHED 0x01 << 2
+#define EMAC_INT_RXDONE 0x01 << 3
+#define EMAC_INT_TXUNDERRUN 0x01 << 4
+#define EMAC_INT_TXERROR 0x01 << 5
+#define EMAC_INT_TXFINISHED 0x01 << 6
+#define EMAC_INT_TXDONE 0x01 << 7
+#define EMAC_INT_SOFTINT 0x01 << 12
+#define EMAC_INT_WOL 0x01 << 13
+
+#define PHY_BMCR 0x0000
+#define PHY_BMSR 0x0001
+#define PHY_PHYIDR1 0x0002
+#define PHY_PHYIDR2 0x0003
+#define PHY_ANAR 0x0004
+#define PHY_ANLPAR 0x0005
+#define PHY_ANLPARNP 0x0005
+#define PHY_ANER 0x0006
+#define PHY_ANNPTR 0x0007
+
+/* BMCR setting */
+#define BMCR_RESET 0x8000
+#define BMCR_LOOPBACK 0x4000
+#define BMCR_SPEED_100 0x2000
+#define BMCR_AN 0x1000
+#define BMCR_POWERDOWN 0x0800
+#define BMCR_ISOLATE 0x0400
+#define BMCR_RE_AN 0x0200
+#define BMCR_DUPLEX 0x0100
+
+/* BMSR setting */
+#define BMSR_100BE_T4 0x8000
+#define BMSR_100TX_FULL 0x4000
+#define BMSR_100TX_HALF 0x2000
+#define BMSR_10BE_FULL 0x1000
+#define BMSR_10BE_HALF 0x0800
+#define BMSR_AUTO_DONE 0x0020
+#define BMSR_REMOTE_FAULT 0x0010
+#define BMSR_NO_AUTO 0x0008
+#define BMSR_LINK_ESTABLISHED 0x0004
+
+#define MII_BMSR_TIMEOUT 0x1000000
+
+#define CMD_RX_ENABLE 0x01
+#define CMD_TX_ENABLE 0x02
+#define CMD_PASS_RX_FILTER 0x80
+
+/* Helper macros */
+#define BFS32(reg,value) writel( (readl(reg)|=(value)) ,reg)
+#define BFC32(reg,value) writel( (readl(reg)&=(~value)) ,reg)
+
+#endif
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index bb99a34..929fb5a 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -39,6 +39,7 @@ COBJS-$(CONFIG_IMX_SERIAL) += serial_imx.o
COBJS-$(CONFIG_IXP_SERIAL) += serial_ixp.o
COBJS-$(CONFIG_KS8695_SERIAL) += serial_ks8695.o
COBJS-$(CONFIG_LPC2292_SERIAL) += serial_lpc2292.o
+COBJS-$(CONFIG_LPC2468_SERIAL) += serial_lpc2468.o
COBJS-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o
COBJS-$(CONFIG_MX31_UART) += serial_mx31.o
COBJS-$(CONFIG_NETARM_SERIAL) += serial_netarm.o
diff --git a/drivers/serial/serial_lpc2468.c b/drivers/serial/serial_lpc2468.c
new file mode 100644
index 0000000..4b8f241
--- /dev/null
+++ b/drivers/serial/serial_lpc2468.c
@@ -0,0 +1,119 @@
+/*
+ * (C) Copyright 2002-2004
+ * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw at its.tudelft.nl)
+ *
+ * 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/immap.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void serial_setbrg (void)
+{
+ unsigned short divisor;
+ uart_2468_t *uart0=&(((immap_t *)CONFIG_SYS_IMMAP)->apb.uart0);
+
+ switch (gd->baudrate) {
+ case 1200:
+ case 9600:
+ case 19200:
+ case 38400:
+ case 57600:
+ case 115200:
+ divisor = CFG_SYS_CLK_FREQ / (gd->baudrate * 16);
+ break;
+ default:
+ hang ();
+ break;
+ }
+
+ /* init serial UART0 */
+ writeb (0, &(uart0->iir_fcr)); /* Disable RX and TX FIFOs */
+ writeb (0, &(uart0->lcr));
+ writeb (0, &(uart0->ier_dlm));
+ writeb (0x80, &(uart0->lcr)); /* DLAB=1 */
+ writeb ((unsigned char)(divisor & 0x00FF), &(uart0->rbr_thr_dll));
+ writeb ((unsigned char)(divisor >> 8),&(uart0->ier_dlm));
+ writeb (0x03, &(uart0->lcr)); /* 8N1, DLAB=0 */
+ writeb (0x7, &(uart0->iir_fcr)); /* Enable RX and TX FIFOs */
+}
+
+int serial_init (void)
+{
+ unsigned long pinsel0;
+ pin_connect_2468_t *pin_connect=
+ &(((immap_t *)CONFIG_SYS_IMMAP)->apb.pin_connect);
+
+ /*enable uart #0 pins in GPIO (P0.2 = TxD0, P0.3 = RxD0) */
+ pinsel0 = readl (&(pin_connect->pinsel0));
+ pinsel0 &= ~(0x000000f0);
+ pinsel0 |= 0x00000050;
+ writel (pinsel0, &(pin_connect->pinsel0));
+
+ serial_setbrg ();
+
+ return (0);
+}
+
+void serial_putc (const char c)
+{
+ uart_2468_t *uart0=&(((immap_t *)CONFIG_SYS_IMMAP)->apb.uart0);
+
+ if (c == '\n') {
+ /* Wait for empty U0THR */
+ while ((readb (&(uart0->lsr)) & (1 << 5)) == 0) ;
+ writeb ('\r', &(uart0->rbr_thr_dll));
+ }
+ /* Wait for empty U0THR */
+ while ((readb (&(uart0->lsr)) & (1 << 5)) == 0) ;
+ writeb (c, &(uart0->rbr_thr_dll));
+}
+
+int serial_getc (void)
+{
+ uart_2468_t *uart0=&(((immap_t *)CONFIG_SYS_IMMAP)->apb.uart0);
+
+ while ((readb (&(uart0->lsr)) & 1) == 0) ;
+ return readb (&(uart0->rbr_thr_dll));
+}
+
+void serial_puts (const char *s)
+{
+ while (*s) {
+ serial_putc (*s++);
+ }
+}
+
+/* Test if there is a byte to read */
+int serial_tstc (void)
+{
+ uart_2468_t *uart0=&(((immap_t *)CONFIG_SYS_IMMAP)->apb.uart0);
+
+ return (readb (&(uart0->lsr)) & 1);
+}
diff --git a/include/asm-arm/arch-lpc24xx/hardware.h b/include/asm-arm/arch-lpc24xx/hardware.h
new file mode 100644
index 0000000..b42746e
--- /dev/null
+++ b/include/asm-arm/arch-lpc24xx/hardware.h
@@ -0,0 +1,32 @@
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+/*
+ * Copyright (c) 2004 Cucy Systems (http://www.cucy.com)
+ * Curt Brune <curt@cucy.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
+ */
+
+#if defined(CONFIG_LPC2468)
+#else
+#error No hardware file defined for this configuration
+#endif
+
+#endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/include/asm-arm/arch-lpc24xx/immap.h b/include/asm-arm/arch-lpc24xx/immap.h
new file mode 100644
index 0000000..ab25dd5
--- /dev/null
+++ b/include/asm-arm/arch-lpc24xx/immap.h
@@ -0,0 +1,406 @@
+/*
+ * (C) Copyright 2009 Duran Audio B.V.
+ *
+ * LPC2468 Internal Memory Map
+ *
+ * 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 __LPC24XX_IMMAP_H
+#define __LPC24XX_IMMAP_H
+
+#include <asm/types.h>
+#include <config.h>
+
+typedef struct watchdog_2468 {
+ u8 fixme[0x4000];
+} watchdog2468_t;
+
+typedef struct timer_2468 {
+ u32 ir; /* Interrupt register */
+ u32 tcr; /* Timer control register */
+ u32 tc; /* Timer counter */
+ u32 pr; /* Prescale register */
+ u32 pc; /* Prescale counter */
+ u32 mcr; /* Match control register */
+ u32 mr0; /* Match register 0 */
+ u32 mr1; /* Match register 1 */
+ u32 mr2; /* Match register 2 */
+ u32 mr3; /* Match register 3 */
+ u32 ccr; /* Capture control register */
+ u32 cr0; /* Capture register 0 */
+ u32 cr1; /* Capture register 1 */
+ u32 cr2; /* Capture register 2 */
+ u32 cr3; /* Capture register 3 */
+ u32 emr; /* External match register */
+ u32 ctcr; /* Count control register */
+ u8 notused[0x3fbc];
+} timer_2468_t;
+
+/*These two UART structs can probably be combined*/
+typedef struct uart_2468 {
+ u32 rbr_thr_dll; /*Receive buffer/transmit holding/divisor latch lsb register */
+ u32 ier_dlm; /*Interrupt enable/divisor latch msb register */
+ u32 iir_fcr; /*Interrupt ID/FIFO control register */
+ u32 lcr; /* Line control register */
+ u32 notused1;
+ u32 lsr; /*Line status register */
+ u32 notused2;
+ u32 scr; /*Scratch pad register */
+ u32 acr; /*Auto-baud control register */
+ u32 icr; /*IrDA control register */
+ u32 fdr; /*Fractional division register */
+ u32 notused3;
+ u32 ter; /* Transmit enable register */
+ u8 notused[0x3fcc];
+} uart_2468_t;
+
+typedef struct uart1_2468 {
+ u8 fixme[0x4000];
+} uart1_2468_t;
+
+typedef struct pwm0_2468 {
+ u8 fixme[0x4000];
+} pwm0_2468_t;
+
+typedef struct pwm1_2468 {
+ u8 fixme[0x4000];
+} pwm1_2468_t;
+
+typedef struct i2c0_2468 {
+ u8 fixme[0x4000];
+} i2c0_2468_t;
+
+typedef struct spi_2468 {
+ u8 fixme[0x4000];
+} spi_2468_t;
+
+typedef struct rtc_2468 {
+ u8 fixme[0x4000];
+} rtc_2468_t;
+
+typedef struct gpio_2468 {
+ u8 fixme[0x4000];
+} gpio_2468_t;
+
+typedef struct pin_connect_2468 {
+ u32 pinsel0; /*Pin function select register*/
+ u32 pinsel1;
+ u32 pinsel2;
+ u32 pinsel3;
+ u32 pinsel4;
+ u32 pinsel5;
+ u32 pinsel6;
+ u32 pinsel7;
+ u32 pinsel8;
+ u32 pinsel9;
+ u32 pinsel10;
+ u32 pinsel11;
+ u32 pinmode0; /*Pin mode select register*/
+ u32 pinmode1;
+ u32 pinmode2;
+ u32 pinmode3;
+ u32 pinmode4;
+ u32 pinmode5;
+ u32 pinmode6;
+ u32 pinmode7;
+ u32 pinmode8;
+ u32 pinmode9;
+ u8 fixme[0x3fa8];
+} pin_connect_2468_t;
+
+typedef struct ssp1_2468 {
+ u8 fixme[0x4000];
+} ssp1_2468_t;
+
+typedef struct adc_2468 {
+ u8 fixme[0x4000];
+} adc_2468_t;
+
+typedef struct can_accept_ram_2468 {
+ u8 fixme[0x4000];
+} can_accept_ram_2468_t;
+
+typedef struct can_accept_filter_2468 {
+ u8 fixme[0x4000];
+} can_accept_filter_2468_t;
+
+typedef struct can_common_2468 {
+ u8 fixme[0x4000];
+} can_common_2468_t;
+
+typedef struct can1_2468 {
+ u8 fixme[0x4000];
+} can1_2468_t;
+
+typedef struct can2_2468 {
+ u8 fixme[0x4000];
+} can2_2468_t;
+
+typedef struct i2c1_2468 {
+ u8 fixme[0x4000];
+} i2c1_2468_t;
+
+typedef struct ssp0_2468 {
+ u8 fixme[0x4000];
+} ssp0_2468_t;
+
+typedef struct dac_2468 {
+ u8 fixme[0x4000];
+} dac_2468_t;
+
+typedef struct i2c2_2468 {
+ u8 fixme[0x4000];
+} i2c2_2468_t;
+
+typedef struct batt_ram_2468 {
+ u8 fixme[0x4000];
+} batt_ram_2468_t;
+
+typedef struct i2s_2468 {
+ u8 fixme[0x4000];
+} i2s_2468_t;
+
+typedef struct mmc_2468 {
+ u8 fixme[0x4000];
+} mmc_2468_t;
+
+typedef struct sys_con_2468 {
+ u8 notused1[0x40];
+ u32 memmap; /*Memory mapping control register c040*/
+ u8 notused2[0x80];
+ u32 pconp; /*Power control for peripherals register c0c4*/
+ u8 notused3[0x7c];
+ u32 extint; /*External interrupt flag register c140*/
+ u32 extmode; /*External interrupt mode resgister c148*/
+ u32 extpolar; /*External interrupt polarity register c14c*/
+ u8 notused4[0x30];
+ u32 rsid; /*Reset source identification register c180*/
+ u32 cspr; /*Code security protection register c184*/
+ u8 notused5[0x18];
+ u32 scs; /*System control and status register c1a0*/
+ u8 notused6[0x3e5c];
+} sys_con_2468_t;
+
+
+typedef struct mac_2468 {
+ u32 mac1; /* MAC configuration register 1 */
+ u32 mac2; /* MAC configuration register 2 */
+ u32 ipgt; /* Back-to-back Inter-Packet-Gap register */
+ u32 ipgr; /* Non Back-to-back Inter-Packet-Gap register */
+ u32 clrt; /* Collision window/Retry register */
+ u32 maxf; /* Maximum frame register */
+ u32 supp; /* PHY support register */
+ u32 test; /* Test register */
+ u32 mcfg; /* MII mgmt Configuration register */
+ u32 mcmd; /* MII mgmt Command register */
+ u32 madr; /* MII mgmt Address register */
+ u32 mwtd; /* MII mgmt Write data register */
+ u32 mrdd; /* MII mgmt Read data register */
+ u32 mind; /* MII mgmt Indicators register */
+ u8 reserved1[0x8];
+ u32 sa0; /* Station Address 0 register */
+ u32 sa1; /* Station Address 1 register */
+ u32 sa2; /* Station Address 2 register */
+ u8 reserved2[0xb4];
+ u32 command; /* Command register */
+ u32 status; /* Status register */
+ u32 rxdescriptor; /* Receive descriptor base address register */
+ u32 rxstatus; /* Receive status base address register */
+ u32 rxdescriptornumber; /* Receive number of descriptors register */
+ u32 rxproduceindex; /* Receive produce index register */
+ u32 rxconsumeindex; /* Receive consume index register */
+ u32 txdescriptor; /* Transmit descriptor base address register */
+ u32 txstatus; /* Transmit status base address register */
+ u32 txdescriptornumber; /* Transmit number of descriptors register */
+ u32 txproduceindex; /* Transmit produce index register */
+ u32 txconsumeindex; /* Transmite consume index register */
+ u8 reserved3[0x28];
+ u32 tsv0; /* Transmit status vector 0 register */
+ u32 tsv1; /* Transmit status vector 1 register */
+ u32 rsv; /* Receive status vector register */
+ u8 reserved4[0xc];
+ u32 flowcontrolcounter; /*Flow control counter register */
+ u32 flowcontrolstatus; /* Flow control status register */
+ u8 reserved5[0x88];
+ u32 rxfilterctrl; /* Receive filter control register */
+ u32 rxfilterwolstatus; /* Receive filter WoL status register */
+ u32 rxfilterwolclear; /* Receive filter WoL clear register */
+ u8 reserved6[0x4];
+ u32 hashfilterL; /* Hash filter LSBs register */
+ u32 hashfilterH; /* Hash filter MSBs register */
+ u8 reserved7[0xdc8];
+ u32 intstatus; /* Interrupt status register */
+ u32 intenable; /* Interrupt enable register */
+ u32 intclear; /* Interrupt clear register */
+ u32 intset; /* Interrupt set register */
+ u8 reserved8[0x4];
+ u32 powerdown; /* Powerdown register */
+ u8 notused[0x3008];
+} mac_2468_t;
+
+typedef struct gpdma__2468 {
+ u8 fixme[0x4000];
+} gpdma_2468_t;
+
+typedef struct ext_mem_2468 {
+ u8 fixme[0x4000];
+} ext_mem_2468_t;
+
+typedef struct usb_2468 {
+ u8 fixme[0x4000];
+} usb_2468_t;
+
+typedef struct lcd_2468 {
+ u8 fixme[0x4000];
+} lcd_2468_t;
+
+typedef struct vic_2468 {
+ u32 vicirqstat; /*IRQ status register */
+ u32 vicfiqstat; /*FIQ status register */
+ u32 vicrawintr; /*Raw interrupt status register */
+ u32 vicintselect; /*Interrupt select register */
+ u32 vicintenable; /*Interrupt enable register */
+ u32 vicinenclr; /*Interrupt enable clear register */
+ u32 vicsoftint; /*Software interrupt register */
+ u32 vicsoftintclr; /*Software interrupt clear register */
+ u32 vicprotect; /*Protection enable register */
+ u32 vicswpriomask; /*Software Priority Mask Register */
+ u8 notused1[0xd8];
+ u32 vicvectaddr0; /*Vector address register */
+ u32 vicvectaddr1;
+ u32 vicvectaddr2;
+ u32 vicvectaddr3;
+ u32 vicvectaddr4;
+ u32 vicvectaddr5;
+ u32 vicvectaddr6;
+ u32 vicvectaddr7;
+ u32 vicvectaddr8;
+ u32 vicvectaddr9;
+ u32 vicvectaddr10;
+ u32 vicvectaddr11;
+ u32 vicvectaddr12;
+ u32 vicvectaddr13;
+ u32 vicvectaddr14;
+ u32 vicvectaddr15;
+ u32 vicvectaddr16;
+ u32 vicvectaddr17;
+ u32 vicvectaddr18;
+ u32 vicvectaddr19;
+ u32 vicvectaddr20;
+ u32 vicvectaddr21;
+ u32 vicvectaddr22;
+ u32 vicvectaddr23;
+ u32 vicvectaddr24;
+ u32 vicvectaddr25;
+ u32 vicvectaddr26;
+ u32 vicvectaddr27;
+ u32 vicvectaddr28;
+ u32 vicvectaddr29;
+ u32 vicvectaddr30;
+ u32 vicvectaddr31;
+ u8 notused2[0x7f];
+ u32 vicvectprio0; /*Vector priority register */
+ u32 vicvectprio1;
+ u32 vicvectprio2;
+ u32 vicvectprio3;
+ u32 vicvectprio4;
+ u32 vicvectprio5;
+ u32 vicvectprio6;
+ u32 vicvectprio7;
+ u32 vicvectprio8;
+ u32 vicvectprio9;
+ u32 vicvectprio10;
+ u32 vicvectprio11;
+ u32 vicvectprio12;
+ u32 vicvectprio13;
+ u32 vicvectprio14;
+ u32 vicvectprio15;
+ u32 vicvectprio16;
+ u32 vicvectprio17;
+ u32 vicvectprio18;
+ u32 vicvectprio19;
+ u32 vicvectprio20;
+ u32 vicvectprio21;
+ u32 vicvectprio22;
+ u32 vicvectprio23;
+ u32 vicvectprio24;
+ u32 vicvectprio25;
+ u32 vicvectprio26;
+ u32 vicvectprio27;
+ u32 vicvectprio28;
+ u32 vicvectprio29;
+ u32 vicvectprio30;
+ u32 vicvectprio31;
+ u8 notused3[0xc7f];
+ u32 vicaddr; /*Vector address register for active interrupt*/
+} vic_2468_t;
+
+typedef struct apb_2468 { /*Peripheral bus memory layout*/
+ watchdog2468_t watchdog;
+ timer_2468_t timer0;
+ timer_2468_t timer1;
+ uart_2468_t uart0;
+ uart1_2468_t uart1;
+ pwm0_2468_t pwm0;
+ pwm1_2468_t pwm1;
+ i2c0_2468_t i2c0;
+ spi_2468_t spi;
+ rtc_2468_t rtc;
+ gpio_2468_t gpio;
+ pin_connect_2468_t pin_connect;
+ ssp1_2468_t ssp1;
+ adc_2468_t adc;
+ can_accept_ram_2468_t can_accept_ram;
+ can_accept_filter_2468_t can_accept_filter;
+ can_common_2468_t can_comon;
+ can1_2468_t can1;
+ can2_2468_t can2;
+ u8 not_used1[0x10000];
+ i2c1_2468_t i2c1;
+ u8 notused2[0x8000];
+ ssp0_2468_t ssp0;
+ dac_2468_t dac;
+ timer_2468_t timer2;
+ timer_2468_t timer3;
+ uart_2468_t uart2;
+ uart_2468_t uart3;
+ i2c2_2468_t i2c2;
+ batt_ram_2468_t batt_ram;
+ i2s_2468_t i2s;
+ mmc_2468_t mmc;
+ u8 not_used3[0x16c000];
+ sys_con_2468_t sys_con;
+} apb_2468_t;
+
+typedef struct ahb_2468 { /*High-speed bus memory layout*/
+ mac_2468_t mac;
+ gpdma_2468_t gpdma;
+ ext_mem_2468_t ext_mem;
+ usb_2468_t usb;
+ lcd_2468_t lcd;
+ u8 notused1[0x1eb000];
+ vic_2468_t vic;
+} ahb_2468_t;
+
+typedef struct immap { /*LPC24xx memory layout*/
+ apb_2468_t apb; /*Peripheral bus*/
+ u8 res1[0x1fc00000];
+ ahb_2468_t ahb; /*High-speed bus*/
+} immap_t;
+
+#endif
diff --git a/include/asm-arm/config.h b/include/asm-arm/config.h
index 049c44e..2d46a34 100644
--- a/include/asm-arm/config.h
+++ b/include/asm-arm/config.h
@@ -21,4 +21,8 @@
#ifndef _ASM_CONFIG_H_
#define _ASM_CONFIG_H_

+#if defined(CONFIG_LPC2292) || defined(CONFIG_LPC2468)
+#define CONFIG_LPC2000
+#endif
+
#endif
diff --git a/include/flash.h b/include/flash.h
index b016162..ac4a705 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -337,6 +337,7 @@ extern flash_info_t *flash_get_info(ulong base);
#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 */
+#define PHILIPS_LPC2468 0x0603FF35 /* LPC2468 internal FLASH */

/*-----------------------------------------------------------------------
* Internal FLASH identification codes
--
1.6.2.4