Patch by Juergen Selent, 17 May 2005:
Add support for Funkwerk VoVPN gateway module.
diff --git a/board/funkwerk/vovpn-gw/Makefile b/board/funkwerk/vovpn-gw/Makefile
new file mode 100644
index 0000000..f77cc60
--- /dev/null
+++ b/board/funkwerk/vovpn-gw/Makefile
@@ -0,0 +1,46 @@
+#
+# (C) Copyright 2001
+# 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	= lib$(BOARD).a
+
+OBJS	:= $(BOARD).o flash.o m88e6060.o
+
+$(LIB):	$(OBJS) $(SOBJS)
+	$(AR) crv $@ $(OBJS)
+
+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/funkwerk/vovpn-gw/config.mk b/board/funkwerk/vovpn-gw/config.mk
new file mode 100644
index 0000000..e59b483
--- /dev/null
+++ b/board/funkwerk/vovpn-gw/config.mk
@@ -0,0 +1,21 @@
+# (C) Copyright 2004
+# Elmeg Communications Systems GmbH, Juergen Selent (j.selent@elmeg.de)
+#
+# Support for the Elmeg VoVPN Gateway Module
+#
+# 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
+
+TEXT_BASE = 0xfff00000
diff --git a/board/funkwerk/vovpn-gw/flash.c b/board/funkwerk/vovpn-gw/flash.c
new file mode 100644
index 0000000..1e53d45
--- /dev/null
+++ b/board/funkwerk/vovpn-gw/flash.c
@@ -0,0 +1,506 @@
+/*
+ * (C) Copyright 2004
+ * Elmeg Communications Systems GmbH, Juergen Selent (j.selent@elmeg.de)
+ *
+ * Support for the Elmeg VoVPN Gateway Module
+ * ------------------------------------------
+ * This is a signle bank flashdriver for INTEL 28F320J3, 28F640J3
+ * and 28F128J3A flashs working in 8 Bit mode. 
+ *
+ * Most of this code is taken from existing u-boot source code.
+ *
+ * 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>
+
+flash_info_t				flash_info[CFG_MAX_FLASH_BANKS];
+
+#define FLASH_CMD_READ_ID		0x90
+#define FLASH_CMD_READ_STATUS		0x70
+#define FLASH_CMD_RESET			0xff
+#define FLASH_CMD_BLOCK_ERASE		0x20
+#define FLASH_CMD_ERASE_CONFIRM		0xd0
+#define FLASH_CMD_CLEAR_STATUS		0x50
+#define FLASH_CMD_SUSPEND_ERASE		0xb0
+#define FLASH_CMD_WRITE			0x40
+#define FLASH_CMD_WRITE_BUFF		0xe8
+#define FLASH_CMD_PROG_RESUME		0xd0
+#define FLASH_CMD_PROTECT		0x60
+#define FLASH_CMD_PROTECT_SET		0x01
+#define FLASH_CMD_PROTECT_CLEAR		0xd0
+#define FLASH_STATUS_DONE		0x80
+
+#define FLASH_WRITE_BUFFER_SIZE		32
+
+#ifdef CFG_FLASH_16BIT
+#define FLASH_WORD_SIZE			unsigned short
+#define FLASH_ID_MASK			0xffff
+#define FLASH_CMD_ADDR_SHIFT		0
+#else
+#define FLASH_WORD_SIZE			unsigned char
+#define FLASH_ID_MASK			0xff
+/* A0 is not used in either 8x or 16x for READ ID */
+#define FLASH_CMD_ADDR_SHIFT		1
+#endif
+
+
+static unsigned long
+flash_get(volatile FLASH_WORD_SIZE *addr, flash_info_t *info)
+{
+	volatile FLASH_WORD_SIZE *p;
+	FLASH_WORD_SIZE value;
+	int i;
+
+	addr[0] = FLASH_CMD_READ_ID;
+
+	/* manufactor */
+	value = addr[0 << FLASH_CMD_ADDR_SHIFT];
+	switch (value) {
+	case (INTEL_MANUFACT & FLASH_ID_MASK):
+		info->flash_id = FLASH_MAN_INTEL;
+		break;
+	default:
+		info->flash_id = FLASH_UNKNOWN;
+		info->sector_count = 0;
+		info->size = 0;
+		*addr = FLASH_CMD_RESET;
+		return (0);
+
+	}
+
+	/* device */
+	value = addr[1 << FLASH_CMD_ADDR_SHIFT];
+	switch (value) {
+	case (INTEL_ID_28F320J3A & FLASH_ID_MASK):
+		info->flash_id += FLASH_28F320J3A;
+		info->sector_count = 32;
+		info->size = 0x00400000;
+		break;
+	case (INTEL_ID_28F640J3A & FLASH_ID_MASK):
+		info->flash_id += FLASH_28F640J3A;
+		info->sector_count = 64;
+		info->size = 0x00800000;
+		break;
+	case (INTEL_ID_28F128J3A & FLASH_ID_MASK):
+		info->flash_id += FLASH_28F128J3A;
+		info->sector_count = 128;
+		info->size = 0x01000000;
+		break;
+	default:
+		info->flash_id = FLASH_UNKNOWN;
+		info->sector_count = 0;
+		info->size = 0;
+		*addr = FLASH_CMD_RESET;
+		return (0);
+	}
+
+	/* setup sectors */
+	for (i = 0; i < info->sector_count; i++) {
+		info->start[i] = (unsigned long)addr + (i * info->size/info->sector_count);
+	}
+
+	/* check protected sectors */
+	for (i = 0; i < info->sector_count; i++) {
+		p = (volatile FLASH_WORD_SIZE *)(info->start[i]);
+		info->protect[i] = p[2 << FLASH_CMD_ADDR_SHIFT] & 1;
+	}
+
+	/* reset bank */
+	*addr = FLASH_CMD_RESET;
+	return (info->size);
+}
+
+unsigned long
+flash_init(void)
+{
+	unsigned long	size;
+	int		i;
+
+	for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+		flash_info[i].flash_id = FLASH_UNKNOWN;
+	}
+	size = flash_get((volatile FLASH_WORD_SIZE *)CFG_FLASH_BASE, &flash_info[0]);
+	if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+		printf ("## Unknown FLASH Size=0x%08lx\n", size);
+		return (0);
+	}
+
+	/* always protect 1 sector containing the HRCW */
+	flash_protect(FLAG_PROTECT_SET,
+		      flash_info[0].start[0],
+		      flash_info[0].start[1] - 1,
+		      &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+	flash_protect(FLAG_PROTECT_SET,
+		      CFG_MONITOR_FLASH,
+		      CFG_MONITOR_FLASH+CFG_MONITOR_LEN-1,
+		      &flash_info[0]);
+#endif
+#ifdef	CFG_ENV_IS_IN_FLASH
+	flash_protect(FLAG_PROTECT_SET,
+		      CFG_ENV_ADDR,
+		      CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+		      &flash_info[0]);
+#endif
+	return (size);
+}
+
+void
+flash_print_info(flash_info_t *info)
+{
+	int i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		printf ("missing or unknown FLASH type\n");
+		return;
+	}
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case FLASH_MAN_INTEL:	printf ("INTEL ");		break;
+	default:		printf ("Unknown Vendor ");	break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case FLASH_28F320J3A:	printf ("28F320JA3 (32 Mbit)\n");
+				break;
+	case FLASH_28F640J3A:	printf ("28F640JA3 (64 Mbit)\n");
+				break;
+	case FLASH_28F128J3A:	printf ("28F128JA3 (128 Mbit)\n");
+				break;
+	default:		printf ("Unknown Chip Type");
+				break;
+	}
+
+	printf ("  Size: %ld MB in %d Sectors\n",
+		info->size >> 20, info->sector_count);
+
+	printf ("  Sector Start Addresses:");
+	for (i=0; i<info->sector_count; ++i) {
+		if ((i % 5) == 0)
+			printf ("\n   ");
+		printf (" %08lX%s",
+			info->start[i],
+			info->protect[i] ? " (RO)" : "     "
+		);
+	}
+	printf ("\n");
+}
+
+int
+flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+	unsigned long start, now, last;
+	int flag, prot, sect;
+	volatile FLASH_WORD_SIZE *addr;
+	FLASH_WORD_SIZE status;
+
+	if ((s_first < 0) || (s_first > s_last)) {
+		if (info->flash_id == FLASH_UNKNOWN) {
+			printf ("- missing\n");
+		} else {
+			printf ("- no sectors to erase\n");
+		}
+		return (1);
+	}
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		printf ("Cannot erase unknown flash - aborted\n");
+		return (1);
+	}
+
+	prot = 0;
+	for (sect=s_first; sect<=s_last; ++sect) {
+		if (info->protect[sect]) {
+			prot++;
+		}
+	}
+
+	if (prot) {
+		printf ("- Warning: %d protected sectors will not be erased!\n", prot);
+	} else {
+		printf ("\n");
+	}
+
+	start = get_timer (0);
+	last  = start;
+
+	for (sect = s_first; sect<=s_last; sect++) {
+		if (info->protect[sect]) {
+			continue;
+		}
+
+		addr = (volatile FLASH_WORD_SIZE *)(info->start[sect]);
+		/* Disable interrupts which might cause a timeout here */
+		flag = disable_interrupts();
+
+#ifdef DEBUG
+		printf("Erase sector %d at start addr 0x%08X", sect, (unsigned int)info->start[sect]);
+#endif
+
+		*addr = FLASH_CMD_CLEAR_STATUS;
+		*addr = FLASH_CMD_BLOCK_ERASE;
+		*addr = FLASH_CMD_ERASE_CONFIRM;
+
+		/* re-enable interrupts if necessary */
+		if (flag) {
+			enable_interrupts();
+		}
+
+		/* wait at least 80us - let's wait 1 ms */
+		udelay (1000);
+
+		while (((status = *addr) & FLASH_STATUS_DONE) != FLASH_STATUS_DONE) {
+			if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+				printf("Flash erase timeout at address %lx\n", info->start[sect]);
+				*addr = FLASH_CMD_SUSPEND_ERASE;
+				*addr = FLASH_CMD_RESET;
+				return (1);
+			}
+
+			/* show that we're waiting */
+			if ((now - last) > 1000) {	/* every second */
+				putc ('.');
+				last = now;
+			}
+		}
+		*addr = FLASH_CMD_RESET;
+	}
+	printf (" done\n");
+	return (0);
+}
+
+static int
+write_buff2( volatile FLASH_WORD_SIZE *dst,
+             volatile FLASH_WORD_SIZE *src,
+             unsigned long cnt )
+{
+	unsigned long start;
+	FLASH_WORD_SIZE status;
+	int flag, i;
+
+	start = get_timer (0);
+	while (1) {
+		/* Disable interrupts which might cause a timeout here */
+		flag = disable_interrupts();
+		dst[0] = FLASH_CMD_WRITE_BUFF;
+		if ((status = *dst) & FLASH_STATUS_DONE) {
+			break;
+		}
+
+		/* re-enable interrupts if necessary */
+		if (flag) {
+			enable_interrupts();
+		}
+
+		if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+			return (-1);
+		}
+	}
+	dst[0] = (FLASH_WORD_SIZE)(cnt - 1);
+	for (i=0; i<cnt; i++) {
+		dst[i] = src[i];
+	}
+	dst[0] = FLASH_CMD_PROG_RESUME;
+
+	if (flag) {
+		enable_interrupts();
+	}
+
+	return( 0 );
+}
+
+static int
+poll_status( volatile FLASH_WORD_SIZE *addr )
+{
+	unsigned long start;
+
+	start = get_timer (0);
+	/* wait for error or finish */
+	while (1) {
+		if (*addr == FLASH_STATUS_DONE) {
+			if (*addr == FLASH_STATUS_DONE) {
+				break;
+			}
+		}
+		if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+			*addr = FLASH_CMD_RESET;
+			return (-1);
+		}
+	}
+	*addr = FLASH_CMD_RESET;
+	return (0);
+}
+
+/*
+ * write_buff return values:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+int
+write_buff(flash_info_t *info, uchar *src, ulong udst, ulong cnt)
+{
+	volatile FLASH_WORD_SIZE *addr, *dst;
+	unsigned long bcnt;
+	int flag, i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		return (4);
+	}
+
+	addr = (volatile FLASH_WORD_SIZE *)(info->start[0]);
+	dst = (volatile FLASH_WORD_SIZE *) udst;
+
+#ifdef CFG_FLASH_16BIT
+#error NYI
+#else
+	while (cnt > 0) {
+		/* Check if buffer write is possible */
+		if (cnt > 1 && (((unsigned long)dst & (FLASH_WRITE_BUFFER_SIZE - 1)) == 0)) {
+			bcnt = cnt > FLASH_WRITE_BUFFER_SIZE ? FLASH_WRITE_BUFFER_SIZE : cnt;
+			/* Check if Flash is (sufficiently) erased */
+			for (i=0; i<bcnt; i++) {
+				if ((dst[i] & src[i]) != src[i]) {
+					return (2);
+				}
+			}
+			if (write_buff2( dst,src,bcnt ) != 0) {
+				addr[0] = FLASH_CMD_READ_STATUS;
+			}
+			if (poll_status( dst ) != 0) {
+				return (1);
+			}
+			cnt -= bcnt;
+			dst += bcnt;
+			src += bcnt;
+			continue;
+		}
+
+		/* Check if Flash is (sufficiently) erased */
+		if ((*dst & *src) != *src) {
+			return (2);
+		}
+
+		/* Disable interrupts which might cause a timeout here */
+		flag = disable_interrupts();
+		addr[0] = FLASH_CMD_ERASE_CONFIRM;
+		addr[0] = FLASH_CMD_WRITE;
+		*dst++ = *src++;
+		/* re-enable interrupts if necessary */
+		if (flag) {
+			enable_interrupts();
+		}
+
+		if (poll_status( dst ) != 0) {
+			return (1);
+		}
+		cnt --;
+	}
+#endif
+	return (0);
+}
+
+int
+flash_real_protect(flash_info_t *info, long sector, int prot)
+{
+	volatile FLASH_WORD_SIZE *addr;
+	unsigned long start;
+
+	addr = (volatile FLASH_WORD_SIZE *)(info->start[sector]);
+	*addr = FLASH_CMD_CLEAR_STATUS;
+	*addr = FLASH_CMD_PROTECT;
+
+	if(prot) {
+		*addr = FLASH_CMD_PROTECT_SET;
+	} else {
+		*addr = FLASH_CMD_PROTECT_CLEAR;
+	}
+
+	/* wait for error or finish */
+	start = get_timer (0);
+	while(!(addr[0] & FLASH_STATUS_DONE)){
+		if (get_timer(start) > CFG_FLASH_ERASE_TOUT) {
+			printf("Flash protect timeout at address %lx\n",  info->start[sector]);
+			addr[0] = FLASH_CMD_RESET;
+			return (1);
+		}
+	}
+
+	/* Set software protect flag */
+	info->protect[sector] = prot;
+	*addr = FLASH_CMD_RESET;
+	return (0);
+}
+
+/*-----------------------------------------------------------------------
+ * Support for flash file system (JFFS2)
+ *
+ * We use custom partition info function because we have to fit the
+ * file system image between first sector (containing hard reset
+ * configuration word) and the sector containing U-Boot image. Standard
+ * partition info function does not allow for last sector specification
+ * and assumes that the file system occupies flash bank up to and
+ * including bank's last sector.
+ */
+#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CFG_JFFS_CUSTOM_PART)
+#error TODO
+
+#ifndef CFG_JFFS2_FIRST_SECTOR
+#define CFG_JFFS2_FIRST_SECTOR 0
+#endif
+#ifndef CFG_JFFS2_FIRST_BANK
+#define CFG_JFFS2_FIRST_BANK 0
+#endif
+#ifndef CFG_JFFS2_NUM_BANKS
+#define CFG_JFFS2_NUM_BANKS 1
+#endif
+#define CFG_JFFS2_LAST_BANK (CFG_JFFS2_FIRST_BANK + CFG_JFFS2_NUM_BANKS - 1)
+
+#include <jffs2/jffs2.h>
+
+static struct part_info partition;
+
+struct part_info *jffs2_part_info(int part_num)
+{
+	int i;
+
+	if (part_num == 0) {
+		if (partition.usr_priv == 0) {
+			partition.offset =
+				(unsigned char *) flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR];
+			for (i = CFG_JFFS2_FIRST_BANK; i <= CFG_JFFS2_LAST_BANK; i++)
+				partition.size += flash_info[i].size;
+			partition.size -=
+				flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR] -
+				flash_info[CFG_JFFS2_FIRST_BANK].start[0];
+#ifdef CFG_JFFS2_LAST_SECTOR
+			i = flash_info[CFG_JFFS2_LAST_BANK].sector_count - 1;
+			partition.size -=
+				flash_info[CFG_JFFS2_LAST_BANK].start[i] -
+				flash_info[CFG_JFFS2_LAST_BANK].start[CFG_JFFS2_LAST_SECTOR];
+#endif
+
+			partition.usr_priv = (void *)1;
+		}
+		return &partition;
+	}
+	return 0;
+}
+
+#endif /* JFFS2 */
diff --git a/board/funkwerk/vovpn-gw/m88e6060.c b/board/funkwerk/vovpn-gw/m88e6060.c
new file mode 100644
index 0000000..e4ff3c3
--- /dev/null
+++ b/board/funkwerk/vovpn-gw/m88e6060.c
@@ -0,0 +1,262 @@
+/*
+ * (C) Copyright 2004
+ * Elmeg Communications Systems GmbH, Juergen Selent (j.selent@elmeg.de)
+ *
+ * Support for the Elmeg VoVPN Gateway Module
+ * ------------------------------------------
+ * Initialize Marvell M88E6060 Switch
+ *
+ * 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 <ioports.h>
+#include <mpc8260.h>
+#include <asm/m8260_pci.h>
+#include <net.h>
+#include <miiphy.h>
+
+#include "m88e6060.h"
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+static int		prtTab[M88X_PRT_CNT] = { 8, 9, 10, 11, 12, 13 };
+static int		phyTab[M88X_PHY_CNT] = { 0, 1, 2, 3, 4 };
+
+static m88x_regCfg_t	prtCfg0[] = {
+	{  4, 0x3e7c, 0x8000 },
+	{  4, 0x3e7c, 0x8003 },
+	{  6, 0x0fc0, 0x001e },
+	{ -1, 0xffff, 0x0000 }
+};
+
+static m88x_regCfg_t	prtCfg1[] = {
+	{  4, 0x3e7c, 0x8000 },
+	{  4, 0x3e7c, 0x8003 },
+	{  6, 0x0fc0, 0x001d },
+	{ -1, 0xffff, 0x0000 }
+};
+
+static m88x_regCfg_t	prtCfg2[] = {
+	{  4, 0x3e7c, 0x8000 },
+	{  4, 0x3e7c, 0x8003 },
+	{  6, 0x0fc0, 0x001b },
+	{ -1, 0xffff, 0x0000 }
+};
+
+static m88x_regCfg_t	prtCfg3[] = {
+	{  4, 0x3e7c, 0x8000 },
+	{  4, 0x3e7c, 0x8003 },
+	{  6, 0x0fc0, 0x0017 },
+	{ -1, 0xffff, 0x0000 }
+};
+
+static m88x_regCfg_t	prtCfg4[] = {
+	{  4, 0x3e7c, 0x8000 },
+	{  4, 0x3e7c, 0x8003 },
+	{  6, 0x0fc0, 0x000f },
+	{ -1, 0xffff, 0x0000 }
+};
+
+static m88x_regCfg_t	*prtCfg[M88X_PRT_CNT] = {
+	prtCfg0,prtCfg1,prtCfg2,prtCfg3,prtCfg4,NULL
+};
+
+static m88x_regCfg_t	phyCfgX[] = {
+	{  4, 0xfa1f, 0x01e0 },
+	{  0, 0x213f, 0x1200 },
+	{ 24, 0x81ff, 0x1200 },
+	{ -1, 0xffff, 0x0000 }
+};
+
+static m88x_regCfg_t	*phyCfg[M88X_PHY_CNT] = {
+	phyCfgX,phyCfgX,phyCfgX,phyCfgX,NULL
+};
+
+#if 0
+static void
+m88e6060_dump( int devAddr )
+{
+	int		i, j;
+	unsigned short	val[6];
+
+	printf( "M88E6060 Register Dump\n" );
+	printf( "====================================\n" );
+	printf( "PortNo    0    1    2    3    4    5\n" );
+	for (i=0; i<6; i++)
+		miiphy_read( devAddr+prtTab[i],M88X_PRT_STAT,&val[i] );
+	printf( "STAT   %04hx %04hx %04hx %04hx %04hx %04hx\n",
+		val[0],val[1],val[2],val[3],val[4],val[5] );
+
+	for (i=0; i<6; i++)
+		miiphy_read( devAddr+prtTab[i],M88X_PRT_ID,&val[i] );
+	printf( "ID     %04hx %04hx %04hx %04hx %04hx %04hx\n",
+		val[0],val[1],val[2],val[3],val[4],val[5] );
+
+	for (i=0; i<6; i++)
+		miiphy_read( devAddr+prtTab[i],M88X_PRT_CNTL,&val[i] );
+	printf( "CNTL   %04hx %04hx %04hx %04hx %04hx %04hx\n",
+		val[0],val[1],val[2],val[3],val[4],val[5] );
+
+	for (i=0; i<6; i++)
+		miiphy_read( devAddr+prtTab[i],M88X_PRT_VLAN,&val[i] );
+	printf( "VLAN   %04hx %04hx %04hx %04hx %04hx %04hx\n",
+		val[0],val[1],val[2],val[3],val[4],val[5] );
+
+	for (i=0; i<6; i++)
+		miiphy_read( devAddr+prtTab[i],M88X_PRT_PAV,&val[i] );
+	printf( "PAV    %04hx %04hx %04hx %04hx %04hx %04hx\n",
+		val[0],val[1],val[2],val[3],val[4],val[5] );
+
+	for (i=0; i<6; i++)
+		miiphy_read( devAddr+prtTab[i],M88X_PRT_RX,&val[i] );
+	printf( "RX     %04hx %04hx %04hx %04hx %04hx %04hx\n",
+		val[0],val[1],val[2],val[3],val[4],val[5] );
+
+	for (i=0; i<6; i++)
+		miiphy_read( devAddr+prtTab[i],M88X_PRT_TX,&val[i] );
+	printf( "TX     %04hx %04hx %04hx %04hx %04hx %04hx\n",
+		val[0],val[1],val[2],val[3],val[4],val[5] );
+
+	printf( "------------------------------------\n" );
+	printf( "PhyNo     0    1    2    3    4\n" );
+	for (i=0; i<9; i++) {
+		for (j=0; j<5; j++) {
+			miiphy_read( devAddr+phyTab[j],i,&val[j] );
+		}
+		printf( "0x%02x   %04hx %04hx %04hx %04hx %04hx\n",
+			i,val[0],val[1],val[2],val[3],val[4] );
+	}
+	for (i=0x10; i<0x1d; i++) {
+		for (j=0; j<5; j++) {
+			miiphy_read( devAddr+phyTab[j],i,&val[j] );
+		}
+		printf( "0x%02x   %04hx %04hx %04hx %04hx %04hx\n",
+			i,val[0],val[1],val[2],val[3],val[4] );
+	}
+}
+#endif
+
+int
+m88e6060_initialize( int devAddr )
+{
+	static char	*_f = "m88e6060_initialize:";
+	m88x_regCfg_t	*p;
+	int		err;
+	int		i;
+	unsigned short	val;
+
+	/*** reset all phys into powerdown ************************************/
+	for (i=0, err=0; i<M88X_PHY_CNT; i++) {
+		err += miiphy_read( devAddr+phyTab[i],M88X_PHY_CNTL,&val );
+		/* keep SpeedLSB, Duplex */
+		val &= 0x2100;
+		/* set SWReset, AnegEn, PwrDwn, RestartAneg */
+		val |= 0x9a00;
+		err += miiphy_write( devAddr+phyTab[i],M88X_PHY_CNTL,val );
+	}
+	if (err) {
+		printf( "%s [ERR] reset phys\n",_f );
+		return( -1 );
+	}
+
+	/*** disable all ports ************************************************/
+	for (i=0, err=0; i<M88X_PRT_CNT; i++) {
+		err += miiphy_read( devAddr+prtTab[i],M88X_PRT_CNTL,&val );
+		val &= 0xfffc;
+		err += miiphy_write( devAddr+prtTab[i],M88X_PRT_CNTL,val );
+	}
+	if (err) {
+		printf( "%s [ERR] disable ports\n",_f );
+		return( -1 );
+	}
+
+	/*** initialize switch ************************************************/
+	/* set switch mac addr */
+#define ea eth_get_dev()->enetaddr
+	val = (ea[4] <<  8) | ea[5];
+	err = miiphy_write( devAddr+15,M88X_GLB_MAC45,val );
+	val = (ea[2] <<  8) | ea[3];
+	err += miiphy_write( devAddr+15,M88X_GLB_MAC23,val );
+	val = (ea[0] <<  8) | ea[1];
+#undef ea
+	val &= 0xfeff;		/* clear DiffAddr */
+	err += miiphy_write( devAddr+15,M88X_GLB_MAC01,val );
+	if (err) {
+		printf( "%s [ERR] switch mac address register\n",_f );
+		return( -1 );
+	}
+
+	/* !DiscardExcessive, MaxFrameSize, CtrMode */
+	err = miiphy_read( devAddr+15,M88X_GLB_CNTL,&val );
+	val &= 0xd870;
+	val |= 0x0500;
+	err += miiphy_write( devAddr+15,M88X_GLB_CNTL,val );
+	if (err) {
+		printf( "%s [ERR] switch global control register\n",_f );
+		return( -1 );
+	}
+
+	/* LernDis off, ATUSize 1024, AgeTime 5min */
+	err = miiphy_read( devAddr+15,M88X_ATU_CNTL,&val );
+	val &= 0x000f;
+	val |= 0x2130;
+	err += miiphy_write( devAddr+15,M88X_ATU_CNTL,val );
+	if (err) {
+		printf( "%s [ERR] atu control register\n",_f );
+		return( -1 );
+	}
+
+	/*** initialize ports *************************************************/
+	for (i=0; i<M88X_PRT_CNT; i++) {
+		if ((p = prtCfg[i]) == NULL) {
+			continue;
+		}
+		while (p->reg != -1) {
+			err = 0;
+			err += miiphy_read( devAddr+prtTab[i],p->reg,&val );
+			val &= p->msk;
+			val |= p->val;
+			err += miiphy_write( devAddr+prtTab[i],p->reg,val );
+			if (err) {
+				printf( "%s [ERR] config port %d register %d\n",_f,i,p->reg );
+				/* XXX what todo */
+			}
+			p++;
+		}
+	}
+
+	/*** initialize phys **************************************************/
+	for (i=0; i<M88X_PHY_CNT; i++) {
+		if ((p = phyCfg[i]) == NULL) {
+			continue;
+		}
+		while (p->reg != -1) {
+			err = 0;
+			err += miiphy_read( devAddr+phyTab[i],p->reg,&val );
+			val &= p->msk;
+			val |= p->val;
+			err += miiphy_write( devAddr+phyTab[i],p->reg,val );
+			if (err) {
+				printf( "%s [ERR] config phy %d register %d\n",_f,i,p->reg );
+				/* XXX what todo */
+			}
+			p++;
+		}
+	}
+	udelay(100000);
+	return( 0 );
+}
+#endif
diff --git a/board/funkwerk/vovpn-gw/m88e6060.h b/board/funkwerk/vovpn-gw/m88e6060.h
new file mode 100644
index 0000000..563a5e0
--- /dev/null
+++ b/board/funkwerk/vovpn-gw/m88e6060.h
@@ -0,0 +1,94 @@
+/*
+ * (C) Copyright 2004
+ * Elmeg Communications Systems GmbH, Juergen Selent (j.selent@elmeg.de)
+ *
+ * Support for the Elmeg VoVPN Gateway Module
+ * ------------------------------------------
+ * Initialize Marvell M88E6060 Switch
+ *
+ * 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 _INC_m88e6060_h_
+#define _INC_m88e6060_h_
+
+/* ************************************************************************** */
+/* *** DEFINES ************************************************************** */
+
+/* switch hw */
+#define M88X_PRT_CNT			6
+#define M88X_PHY_CNT			5
+
+/* phy register offsets */
+#define M88X_PHY_CNTL			0x00
+#define M88X_PHY_STAT			0x00
+#define M88X_PHY_ID0			0x02
+#define M88X_PHY_ID1			0x03
+#define M88X_PHY_ANEG_ADV		0x04
+#define M88X_PHY_LPA			0x05
+#define M88X_PHY_ANEG_EXP		0x06
+#define M88X_PHY_NPT			0x07
+#define M88X_PHY_LPNP			0x08
+
+/* port register offsets */
+#define M88X_PRT_STAT			0x00
+#define M88X_PRT_ID			0x03
+#define M88X_PRT_CNTL			0x04
+#define M88X_PRT_VLAN			0x06
+#define M88X_PRT_PAV			0x0b
+#define M88X_PRT_RX			0x10
+#define M88X_PRT_TX			0x11
+
+/* global/atu register offsets */
+#define M88X_GLB_STAT			0x00
+#define M88X_GLB_MAC01			0x01
+#define M88X_GLB_MAC23			0x02
+#define M88X_GLB_MAC45			0x03
+#define M88X_GLB_CNTL			0x04
+#define M88X_ATU_CNTL			0x0a
+#define M88X_ATU_OP			0x0b
+
+/* id0 register - 0x02 */
+#define M88X_PHY_ID0_VALUE		0x0141
+
+/* id1 register - 0x03 */
+#define M88X_PHY_ID1_VALUE		0x0c80		/* without revision ! */
+
+
+/* misc */
+#define M88E6060_ID		((M88X_PHY_ID0_VALUE<<16) | M88X_PHY_ID1_VALUE)
+
+
+
+/* ************************************************************************** */
+/* *** TYPEDEFS ************************************************************* */
+
+typedef struct {
+	int		reg;
+	unsigned short	msk;
+	unsigned short	val;
+} m88x_regCfg_t;
+
+
+
+/* ************************************************************************** */
+/* *** PROTOTYPES *********************************************************** */
+
+extern int		m88e6060_initialize( int );
+
+
+
+#endif	/* _INC_m88e6060_h_ */
diff --git a/board/funkwerk/vovpn-gw/u-boot.lds b/board/funkwerk/vovpn-gw/u-boot.lds
new file mode 100644
index 0000000..098c046
--- /dev/null
+++ b/board/funkwerk/vovpn-gw/u-boot.lds
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2001-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Modified by Yuli Barcohen <yuli@arabellasw.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
+ */
+
+OUTPUT_ARCH(powerpc)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text) 	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data) 	}
+  .rel.rodata    : { *(.rel.rodata) 	}
+  .rela.rodata   : { *(.rela.rodata) 	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+  .init          : { *(.init)	}
+  .plt : { *(.plt) }
+  .text      :
+  {
+    cpu/mpc8260/start.o	(.text)
+    *(.text)
+    *(.fixup)
+    *(.got1)
+    . = ALIGN(16);
+    *(.rodata)
+    *(.rodata1)
+    *(.rodata.str1.4)
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  _erotext = .;
+  PROVIDE (erotext = .);
+  .reloc   :
+  {
+    *(.got)
+    _GOT2_TABLE_ = .;
+    *(.got2)
+    _FIXUP_TABLE_ = .;
+    *(.fixup)
+  }
+  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  __u_boot_cmd_start = .;
+  .u_boot_cmd : { *(.u_boot_cmd) }
+  __u_boot_cmd_end = .;
+
+
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
+ENTRY(_start)
diff --git a/board/funkwerk/vovpn-gw/vovpn-gw.c b/board/funkwerk/vovpn-gw/vovpn-gw.c
new file mode 100644
index 0000000..03b3cdf
--- /dev/null
+++ b/board/funkwerk/vovpn-gw/vovpn-gw.c
@@ -0,0 +1,375 @@
+/*
+ * (C) Copyright 2004
+ * Elmeg Communications Systems GmbH, Juergen Selent (j.selent@elmeg.de)
+ *
+ * Support for the Elmeg VoVPN Gateway Module
+ *
+ * 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 <ioports.h>
+#include <mpc8260.h>
+#include <asm/m8260_pci.h>
+#include <miiphy.h>
+
+#include "m88e6060.h"
+
+/*
+ * I/O Port configuration table
+ *
+ * if conf is 1, then that port pin will be configured at boot time
+ * according to the five values podr/pdir/ppar/psor/pdat for that entry
+ */
+
+const iop_conf_t iop_conf_tab[4][32] = {
+    /* Port A configuration */
+    {	/*	     conf ppar psor pdir podr pdat */
+	/* PA31 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1252           */
+	/* PA30 */ { 1,   0,   0,   0,   0,   0 }, /* GPI    BP_RES           */
+	/* PA29 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1253           */
+	/* PA28 */ { 1,   1,   1,   1,   0,   0 }, /* FCC1   RMII TX_EN       */
+	/* PA27 */ { 1,   1,   1,   0,   0,   0 }, /* FCC1   RMII CRS_DV      */
+	/* PA26 */ { 1,   1,   1,   0,   0,   0 }, /* FCC1   RMII RX_ERR      */
+	/* PA25 */ { 1,   0,   0,   0,   0,   0 }, /* GPI    HWID             */
+	/* PA24 */ { 1,   0,   0,   0,   0,   0 }, /* GPI    HWID             */
+	/* PA23 */ { 1,   0,   0,   0,   0,   0 }, /* GPI    HWID             */
+	/* PA22 */ { 1,   0,   0,   0,   0,   0 }, /* GPI    HWID             */
+	/* PA21 */ { 1,   0,   0,   0,   0,   0 }, /* GPI    HWID             */
+	/* PA20 */ { 1,   0,   0,   1,   0,   1 }, /* GPO    LED STATUS       */
+	/* PA19 */ { 1,   1,   0,   1,   0,   0 }, /* FCC1   RMII TxD[1]      */
+	/* PA18 */ { 1,   1,   0,   1,   0,   0 }, /* FCC1   RMII TxD[0]      */
+	/* PA17 */ { 1,   1,   0,   0,   0,   0 }, /* FCC1   RMII RxD[0]      */
+	/* PA16 */ { 1,   1,   0,   0,   0,   0 }, /* FCC1   RMII RxD[1]      */
+	/* PA15 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1255           */
+	/* PA14 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP????           */
+	/* PA13 */ { 1,   0,   0,   1,   0,   1 }, /* GPO    EN_BCTL1 XXX jse */
+	/* PA12 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    SWITCH RESET     */
+	/* PA11 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    DSP SL1 RESET    */
+	/* PA10 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    DSP SL2 RESET    */
+	/* PA9  */ { 1,   1,   0,   1,   0,   0 }, /* SMC2   TXD              */
+	/* PA8  */ { 1,   1,   0,   0,   0,   0 }, /* SMC2   RXD              */
+	/* PA7  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exit       */
+	/* PA6  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exit       */
+	/* PA5  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exit       */
+	/* PA4  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exit       */
+	/* PA3  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exit       */
+	/* PA2  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exit       */
+	/* PA1  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exit       */
+	/* PA0  */ { 0,   0,   0,   0,   0,   0 }  /* pin does not exit       */
+    },
+
+    /* Port B configuration */
+    {   /*	     conf ppar psor pdir podr pdat */
+	/* PB31 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1257           */
+	/* PB30 */ { 1,   1,   0,   0,   0,   0 }, /* FCC2   RMII CRS_DV      */
+	/* PB29 */ { 1,   1,   1,   1,   0,   0 }, /* FCC2   RMII TX_EN       */
+	/* PB28 */ { 1,   1,   0,   0,   0,   0 }, /* FCC2   RMII RX_ERR      */
+	/* PB27 */ { 1,   1,   1,   0,   1,   0 }, /* TDM_B2 L1TXD XXX val=0  */
+	/* PB26 */ { 1,   1,   1,   0,   1,   0 }, /* TDM_B2 L1RXD XXX val,dr */
+	/* PB25 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1259           */
+	/* PB24 */ { 1,   1,   1,   0,   0,   0 }, /* TDM_B2 L1RSYNC          */
+	/* PB23 */ { 1,   1,   0,   1,   0,   0 }, /* FCC2   RMII TxD[1]      */
+	/* PB22 */ { 1,   1,   0,   1,   0,   0 }, /* FCC2   RMII TxD[0]      */
+	/* PB21 */ { 1,   1,   0,   0,   0,   0 }, /* FCC2   RMII RxD[0]      */
+	/* PB20 */ { 1,   1,   0,   0,   0,   0 }, /* FCC2   RMII RxD[1]      */
+	/* PB19 */ { 1,   0,   0,   1,   0,   1 }, /* GPO    PHY MDC          */
+	/* PB18 */ { 1,   0,   0,   0,   0,   0 }, /* GPIO   PHY MDIO         */
+	/* PB17 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB16 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB15 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB14 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB13 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB12 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB11 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB10 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB9  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB8  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB7  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB6  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB5  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB4  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB3  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB2  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB1  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PB0  */ { 0,   0,   0,   0,   0,   0 }  /* pin does not exist      */
+    },
+
+    /* Port C */
+    {   /*	     conf ppar psor pdir podr pdat */
+	/* PC31 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PC30 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PC29 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1183           */
+	/* PC28 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1184           */
+	/* PC27 */ { 1,   1,   0,   0,   0,   0 }, /* CLK5   TDM_A1 RX        */
+	/* PC26 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1185           */
+	/* PC25 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1178           */
+	/* PC24 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1186           */
+	/* PC23 */ { 1,   1,   0,   0,   0,   0 }, /* CLK9   TDM_B2 RX        */
+	/* PC22 */ { 1,   1,   0,   0,   0,   0 }, /* CLK10  FCC1 RMII REFCLK */
+	/* PC21 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1187           */
+	/* PC20 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1182           */
+	/* PC19 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1188           */
+	/* PC18 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    HW RESET         */
+	/* PC17 */ { 1,   1,   0,   1,   0,   0 }, /* BRG8   SWITCH CLKIN     */
+	/* PC16 */ { 1,   1,   0,   0,   0,   0 }, /* CLK16  FCC2 RMII REFCLK */
+	/* PC15 */ { 1,   0,   0,   0,   0,   0 }, /* GPI    SL1_MTYPE_3      */
+	/* PC14 */ { 1,   0,   0,   0,   0,   0 }, /* GPI    SL1_MTYPE_2      */
+	/* PC13 */ { 1,   0,   0,   0,   0,   0 }, /* GPI    SL1_MTYPE_1      */
+	/* PC12 */ { 1,   0,   0,   0,   0,   0 }, /* GPI    SL1_MTYPE_0      */
+	/* PC11 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1176           */
+	/* PC10 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1177           */
+	/* PC9  */ { 1,   0,   0,   0,   0,   0 }, /* GPI    SL2_MTYPE_3      */
+	/* PC8  */ { 1,   0,   0,   0,   0,   0 }, /* GPI    SL2_MTYPE_2      */
+	/* PC7  */ { 1,   0,   0,   0,   0,   0 }, /* GPI    SL2_MTYPE_1      */
+	/* PC6  */ { 1,   0,   0,   0,   0,   0 }, /* GPI    SL2_MTYPE_0      */
+	/* PC5  */ { 1,   1,   0,   1,   0,   0 }, /* SMC1   TXD              */
+	/* PC4  */ { 1,   1,   0,   0,   0,   0 }, /* SMC1   RXD              */
+	/* PC3  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PC2  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PC1  */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1192           */
+	/* PC0  */ { 1,   0,   0,   0,   0,   0 }, /* GPI    RACK             */
+    },
+
+    /* Port D */
+    {   /*	     conf ppar psor pdir podr pdat */
+	/* PD31 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1193           */
+	/* PD30 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1194           */
+	/* PD29 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1195           */
+	/* PD28 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD27 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD26 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD25 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1179           */
+	/* PD24 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1180           */
+	/* PD23 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1181           */
+	/* PD22 */ { 1,   1,   1,   0,   1,   0 }, /* TDM_A2 L1TXD            */
+	/* PD21 */ { 1,   1,   1,   0,   1,   0 }, /* TDM_A2 L1RXD            */
+	/* PD20 */ { 1,   1,   1,   0,   0,   0 }, /* TDM_A2 L1RSYNC          */
+	/* PD19 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1196           */
+	/* PD18 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1197           */
+	/* PD17 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1198           */
+	/* PD16 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1199           */
+	/* PD15 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1250           */
+	/* PD14 */ { 1,   0,   0,   1,   0,   0 }, /* GPO    TP1251           */
+	/* PD13 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD12 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD11 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD10 */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD9  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD8  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD7  */ { 0,   0,   0,   1,   0,   0 }, /* GPO    FL_BYTE          */
+	/* PD6  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD5  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD4  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD3  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD2  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD1  */ { 0,   0,   0,   0,   0,   0 }, /* pin does not exist      */
+	/* PD0  */ { 0,   0,   0,   0,   0,   0 }  /* pin does not exist      */
+    }
+};
+
+void reset_phy (void)
+{
+	volatile ioport_t *iop;
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+	int i;
+	unsigned short val;
+#endif
+
+	iop = ioport_addr((immap_t *)CFG_IMMR, 0);
+
+	/* Reset the PHY */
+	iop->pdat &= 0xfff7ffff;	/* PA12 = |SWITCH_RESET */
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+	udelay(20000);
+	iop->pdat |= 0x00080000;
+	for (i=0; i<100; i++) {
+		udelay(20000);
+		if (miiphy_read( CFG_PHY_ADDR,2,&val ) == 0) {
+			break;
+		}
+	}
+	/* initialize switch */
+	m88e6060_initialize( CFG_PHY_ADDR );
+#endif
+}
+
+static unsigned long UPMATable[] = {
+	0x8fffec00,  0x0ffcfc00,  0x0ffcfc00,  0x0ffcfc00, //Words 0 to 3
+	0x0ffcfc04,  0x3ffdfc00,  0xfffffc01,  0xfffffc01, //Words 4 to 7
+	0xfffffc00,  0xfffffc04,  0xfffffc01,  0xfffffc00, //Words 8 to 11
+	0xfffffc00,  0xfffffc00,  0xfffffc00,  0xfffffc00, //Words 12 to 15
+	0xfffffc00,  0xfffffc00,  0xfffffc00,  0xfffffc00, //Words 16 to 19
+	0xfffffc00,  0xfffffc00,  0xfffffc00,  0xfffffc01, //Words 20 to 23
+	0x8fffec00,  0x00fffc00,  0x00fffc00,  0x00fffc00, //Words 24 to 27
+	0x0ffffc04,  0xfffffc01,  0xfffffc01,  0xfffffc01, //Words 28 to 31
+	0xfffffc00,  0xfffffc01,  0xfffffc01,  0xfffffc00, //Words 32 to 35
+	0xfffffc00,  0xfffffc00,  0xfffffc00,  0xfffffc00, //Words 36 to 39
+	0xfffffc00,  0xfffffc00,  0xfffffc00,  0xfffffc00, //Words 40 to 43
+	0xfffffc00,  0xfffffc00,  0xfffffc00,  0xfffffc01, //Words 44 to 47
+	0xfffffc00,  0xfffffc04,  0xfffffc01,  0xfffffc00, //Words 48 to 51
+	0xfffffc00,  0xfffffc00,  0xfffffc00,  0xfffffc00, //Words 52 to 55
+	0xfffffc00,  0xfffffc00,  0xfffffc00,  0xfffffc01, //Words 56 to 59
+	0xffffec00,  0xffffec04,  0xffffec00,  0xfffffc01  //Words 60 to 63
+};
+
+int board_early_init_f (void)
+{
+	volatile immap_t *immap;
+	volatile memctl8260_t *memctl;
+	volatile unsigned char *dummy;
+	int i;
+
+	immap = (immap_t *) CFG_IMMR;
+	memctl = &immap->im_memctl;
+
+#if 0
+	/* CS2-5 - DSP via UPMA */
+	dummy = (volatile unsigned char *) (memctl->memc_br2 & BRx_BA_MSK);
+	memctl->memc_mar = 0;
+	memctl->memc_mamr = MxMR_OP_WARR;
+	for (i = 0; i < 64; i++) {
+		memctl->memc_mdr = UPMATable[i];
+		*dummy = 0;
+	}
+	memctl->memc_mamr = 0x00044440;
+#else
+	/* CS7 - DPRAM via UPMA */
+	dummy = (volatile unsigned char *) (memctl->memc_br7 & BRx_BA_MSK);
+	memctl->memc_mar = 0;
+	memctl->memc_mamr = MxMR_OP_WARR;
+	for (i = 0; i < 64; i++) {
+		memctl->memc_mdr = UPMATable[i];
+		*dummy = 0;
+	}
+	memctl->memc_mamr = 0x00044440;
+#endif
+	return 0;
+}
+
+int misc_init_r (void)
+{
+	volatile ioport_t *iop;
+	unsigned char temp;
+#if 0
+	/* DUMP UPMA RAM */
+	volatile immap_t *immap;
+	volatile memctl8260_t *memctl;
+	volatile unsigned char *dummy;
+	unsigned char c;
+	int i;
+
+	immap = (immap_t *) CFG_IMMR;
+	memctl = &immap->im_memctl;
+
+
+	dummy = (volatile unsigned char *) (memctl->memc_br7 & BRx_BA_MSK);
+	memctl->memc_mar = 0;
+	memctl->memc_mamr = MxMR_OP_RARR;
+	for (i = 0; i < 64; i++) {
+		c = *dummy;
+		printf( "UPMA[%02d]: 0x%08lx,0x%08lx: 0x%08lx\n",i,
+		        memctl->memc_mamr,
+		        memctl->memc_mar,
+		        memctl->memc_mdr );
+	}
+	memctl->memc_mamr = 0x00044440;
+#endif
+	/* enable buffers (DSP, DPRAM) */
+	iop = ioport_addr((immap_t *)CFG_IMMR, 0);
+	iop->pdat &= 0xfffbffff;	/* PA13 = |EN_M_BCTL1 */
+
+	/* destroy DPRAM magic */
+	*(volatile unsigned char *)0xf0500000 = 0x00;
+
+	/* clear any pending DPRAM irq */
+	temp = *(volatile unsigned char *)0xf05003ff;
+
+	/* write module-id into DPRAM */
+	*(volatile unsigned char *)0xf0500201 = 0x50;
+
+	return 0;
+}
+
+#if defined(CONFIG_HAVE_OWN_RESET)
+int
+do_reset (void *cmdtp, int flag, int argc, char *argv[])
+{
+	volatile ioport_t *iop;
+
+	iop = ioport_addr((immap_t *)CFG_IMMR, 2);
+	iop->pdat |= 0x00002000;	/* PC18 = HW_RESET */
+	return 1;
+}
+#endif	/* CONFIG_HAVE_OWN_RESET */
+
+#define ns2clk(ns) (ns / (1000000000 / CONFIG_8260_CLKIN) + 1)
+
+long int initdram (int board_type)
+{
+#ifndef CFG_RAMBOOT
+	volatile immap_t *immap;
+	volatile memctl8260_t *memctl;
+	volatile uchar *ramaddr;
+	int i;
+	uchar c;
+
+	immap = (immap_t *) CFG_IMMR;
+	memctl = &immap->im_memctl;
+	ramaddr = (uchar *) CFG_SDRAM_BASE;
+	c = 0xff;
+
+	immap->im_siu_conf.sc_ppc_acr  = 0x02;
+	immap->im_siu_conf.sc_ppc_alrh = 0x01267893;
+	immap->im_siu_conf.sc_ppc_alrl = 0x89abcdef;
+	immap->im_siu_conf.sc_tescr1   = 0x00000000;
+	immap->im_siu_conf.sc_tescr2   = 0x00000000;
+
+	memctl->memc_mptpr = CFG_MPTPR;
+	memctl->memc_psrt = CFG_PSRT;
+	memctl->memc_or1 = CFG_OR1_PRELIM;
+	memctl->memc_br1 = CFG_SDRAM_BASE | CFG_BR1_PRELIM;
+
+	/* Precharge all banks */
+	memctl->memc_psdmr = CFG_PSDMR | 0x28000000;
+	*ramaddr = c;
+
+	/* CBR refresh */
+	memctl->memc_psdmr = CFG_PSDMR | 0x08000000;
+	for (i = 0; i < 8; i++)
+		*ramaddr = c;
+
+	/* Mode Register write */
+	memctl->memc_psdmr = CFG_PSDMR | 0x18000000;
+	*ramaddr = c;
+
+	/* Refresh enable */
+	memctl->memc_psdmr = CFG_PSDMR | 0x40000000;
+	*ramaddr = c;
+#endif /* CFG_RAMBOOT */
+
+	return (CFG_SDRAM_SIZE);
+}
+
+int checkboard (void)
+{
+#ifdef CONFIG_CLKIN_66MHz
+	puts ("Board: Elmeg VoVPN Gateway Module (66MHz)\n");
+#else
+	puts ("Board: Elmeg VoVPN Gateway Module (100MHz)\n");
+#endif
+	return 0;
+}