summaryrefslogtreecommitdiff
path: root/board/keymile
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-12-17 16:53:07 +0100
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-12-17 16:53:07 +0100
commitcb5473205206c7f14cbb1e747f28ec75b48826e2 (patch)
tree8f4808d60917100b18a10b05230f7638a0a9bbcc /board/keymile
parentbaf449fc5ff96f071bb0e3789fd3265f6d4fd9a0 (diff)
parent92c78a3bbcb2ce508b4bf1c4a1e0940406a024bb (diff)
downloadu-boot-imx-cb5473205206c7f14cbb1e747f28ec75b48826e2.zip
u-boot-imx-cb5473205206c7f14cbb1e747f28ec75b48826e2.tar.gz
u-boot-imx-cb5473205206c7f14cbb1e747f28ec75b48826e2.tar.bz2
Merge branch 'fixes' into cleanups
Conflicts: board/atmel/atngw100/atngw100.c board/atmel/atstk1000/atstk1000.c cpu/at32ap/at32ap700x/gpio.c include/asm-avr32/arch-at32ap700x/clk.h include/configs/atngw100.h include/configs/atstk1002.h include/configs/atstk1003.h include/configs/atstk1004.h include/configs/atstk1006.h include/configs/favr-32-ezkit.h include/configs/hammerhead.h include/configs/mimc200.h
Diffstat (limited to 'board/keymile')
-rw-r--r--board/keymile/common/common.c523
-rw-r--r--board/keymile/common/keymile_hdlc_enet.c620
-rw-r--r--board/keymile/common/keymile_hdlc_enet.h129
-rw-r--r--board/keymile/mgcoge/Makefile54
-rw-r--r--board/keymile/mgcoge/config.mk24
-rw-r--r--board/keymile/mgcoge/mgcoge.c349
-rw-r--r--board/keymile/mgcoge/mgcoge_hdlc_enet.c276
-rw-r--r--board/keymile/mgsuvd/Makefile48
-rw-r--r--board/keymile/mgsuvd/config.mk28
-rw-r--r--board/keymile/mgsuvd/mgsuvd.c204
-rw-r--r--board/keymile/mgsuvd/mgsuvd_hdlc_enet.c278
-rw-r--r--board/keymile/mgsuvd/u-boot.lds144
12 files changed, 2677 insertions, 0 deletions
diff --git a/board/keymile/common/common.c b/board/keymile/common/common.c
new file mode 100644
index 0000000..a4cf24c
--- /dev/null
+++ b/board/keymile/common/common.c
@@ -0,0 +1,523 @@
+/*
+ * (C) Copyright 2008
+ * Heiko Schocher, DENX Software Engineering, hs@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 <common.h>
+#include <mpc8260.h>
+#include <ioports.h>
+#include <malloc.h>
+#include <hush.h>
+
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#endif
+
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
+#include <i2c.h>
+#endif
+#include <asm/io.h>
+
+extern int i2c_soft_read_pin (void);
+
+int ivm_calc_crc (unsigned char *buf, int len)
+{
+ const unsigned short crc_tab[16] = {
+ 0x0000, 0xCC01, 0xD801, 0x1400,
+ 0xF001, 0x3C00, 0x2800, 0xE401,
+ 0xA001, 0x6C00, 0x7800, 0xB401,
+ 0x5000, 0x9C01, 0x8801, 0x4400};
+
+ unsigned short crc = 0; /* final result */
+ unsigned short r1 = 0; /* temp */
+ unsigned char byte = 0; /* input buffer */
+ int i;
+
+ /* calculate CRC from array data */
+ for (i = 0; i < len; i++) {
+ byte = buf[i];
+
+ /* lower 4 bits */
+ r1 = crc_tab[crc & 0xF];
+ crc = ((crc) >> 4) & 0x0FFF;
+ crc = crc ^ r1 ^ crc_tab[byte & 0xF];
+
+ /* upper 4 bits */
+ r1 = crc_tab[crc & 0xF];
+ crc = (crc >> 4) & 0x0FFF;
+ crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF];
+ }
+ return crc;
+}
+
+static int ivm_set_value (char *name, char *value)
+{
+ char tempbuf[256];
+
+ if (value != NULL) {
+ sprintf (tempbuf, "%s=%s", name, value);
+ return set_local_var (tempbuf, 0);
+ } else {
+ unset_local_var (name);
+ }
+ return 0;
+}
+
+static int ivm_get_value (unsigned char *buf, int len, char *name, int off,
+ int check)
+{
+ unsigned short val;
+ unsigned char valbuf[30];
+
+ if ((buf[off + 0] != buf[off + 2]) &&
+ (buf[off + 2] != buf[off + 4])) {
+ printf ("%s Error corrupted %s\n", __FUNCTION__, name);
+ val = -1;
+ } else {
+ val = buf[off + 0] + (buf[off + 1] << 8);
+ if ((val == 0) && (check == 1))
+ val = -1;
+ }
+ sprintf ((char *)valbuf, "%x", val);
+ ivm_set_value (name, (char *)valbuf);
+ return val;
+}
+
+#define INVENTORYBLOCKSIZE 0x100
+#define INVENTORYDATAADDRESS 0x21
+#define INVENTORYDATASIZE (INVENTORYBLOCKSIZE - INVENTORYDATAADDRESS - 3)
+
+#define IVM_POS_SHORT_TEXT 0
+#define IVM_POS_MANU_ID 1
+#define IVM_POS_MANU_SERIAL 2
+#define IVM_POS_PART_NUMBER 3
+#define IVM_POS_BUILD_STATE 4
+#define IVM_POS_SUPPLIER_PART_NUMBER 5
+#define IVM_POS_DELIVERY_DATE 6
+#define IVM_POS_SUPPLIER_BUILD_STATE 7
+#define IVM_POS_CUSTOMER_ID 8
+#define IVM_POS_CUSTOMER_PROD_ID 9
+#define IVM_POS_HISTORY 10
+#define IVM_POS_SYMBOL_ONLY 11
+
+static char convert_char (char c)
+{
+ return (c < ' ' || c > '~') ? '.' : c;
+}
+
+static int ivm_findinventorystring (int type,
+ unsigned char* const string,
+ unsigned long maxlen,
+ unsigned char *buf)
+{
+ int xcode = 0;
+ unsigned long cr = 0;
+ unsigned long addr = INVENTORYDATAADDRESS;
+ unsigned long size = 0;
+ unsigned long nr = type;
+ int stop = 0; /* stop on semicolon */
+
+ memset(string, '\0', maxlen);
+ switch (type) {
+ case IVM_POS_SYMBOL_ONLY:
+ nr = 0;
+ stop= 1;
+ break;
+ default:
+ nr = type;
+ stop = 0;
+ }
+
+ /* Look for the requested number of CR. */
+ while ((cr != nr) && (addr < INVENTORYDATASIZE)) {
+ if ((buf[addr] == '\r')) {
+ cr++;
+ }
+ addr++;
+ }
+
+ /* the expected number of CR was found until the end of the IVM
+ * content --> fill string */
+ if (addr < INVENTORYDATASIZE) {
+ /* Copy the IVM string in the corresponding string */
+ for (; (buf[addr] != '\r') &&
+ ((buf[addr] != ';') || (!stop)) &&
+ (size < (maxlen - 1) &&
+ (addr < INVENTORYDATASIZE)); addr++)
+ {
+ size += sprintf((char *)string + size, "%c",
+ convert_char (buf[addr]));
+ }
+
+ /* copy phase is done: check if everything is ok. If not,
+ * the inventory data is most probably corrupted: tell
+ * the world there is a problem! */
+ if (addr == INVENTORYDATASIZE) {
+ xcode = -1;
+ printf ("Error end of string not found\n");
+ } else if ((size >= (maxlen - 1)) &&
+ (buf[addr] != '\r')) {
+ xcode = -1;
+ printf ("string too long till next CR\n");
+ }
+ } else {
+ /* some CR are missing...
+ * the inventory data is most probably corrupted */
+ xcode = -1;
+ printf ("not enough cr found\n");
+ }
+ return xcode;
+}
+
+#define GET_STRING(name, which, len) \
+ if (ivm_findinventorystring (which, valbuf, len, buf) == 0) { \
+ ivm_set_value (name, (char *)valbuf); \
+ }
+
+static int ivm_check_crc (unsigned char *buf, int block)
+{
+ unsigned long crc;
+ unsigned long crceeprom;
+
+ crc = ivm_calc_crc (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2);
+ crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \
+ buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256);
+ if (crc != crceeprom) {
+ printf ("Error CRC Block: %d EEprom: calculated: %lx EEprom: %lx\n",
+ block, crc, crceeprom);
+ return -1;
+ }
+ return 0;
+}
+
+static int ivm_analyze_block2 (unsigned char *buf, int len)
+{
+ unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
+ unsigned long count;
+
+ /* IVM_MacAddress */
+ sprintf ((char *)valbuf, "%02X:%02X:%02X:%02X:%02X:%02X",
+ buf[1],
+ buf[2],
+ buf[3],
+ buf[4],
+ buf[5],
+ buf[6]);
+ ivm_set_value ("IVM_MacAddress", (char *)valbuf);
+ if (getenv ("ethaddr") == NULL)
+ setenv ((char *)"ethaddr", (char *)valbuf);
+ /* IVM_MacCount */
+ count = (buf[10] << 24) +
+ (buf[11] << 16) +
+ (buf[12] << 8) +
+ buf[13];
+ if (count == 0xffffffff)
+ count = 1;
+ sprintf ((char *)valbuf, "%lx", count);
+ ivm_set_value ("IVM_MacCount", (char *)valbuf);
+ return 0;
+}
+
+int ivm_analyze_eeprom (unsigned char *buf, int len)
+{
+ unsigned short val;
+ unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
+ unsigned char *tmp;
+
+ if (ivm_check_crc (buf, 0) != 0)
+ return -1;
+
+ ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_BoardId", 0, 1);
+ val = ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_HWKey", 6, 1);
+ if (val != 0xffff) {
+ sprintf ((char *)valbuf, "%x", ((val /100) % 10));
+ ivm_set_value ("IVM_HWVariant", (char *)valbuf);
+ sprintf ((char *)valbuf, "%x", (val % 100));
+ ivm_set_value ("IVM_HWVersion", (char *)valbuf);
+ }
+ ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_Functions", 12, 0);
+
+ GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8)
+ GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64)
+ tmp = (unsigned char *) getenv("IVM_DeviceName");
+ if (tmp) {
+ int len = strlen ((char *)tmp);
+ int i = 0;
+
+ while (i < len) {
+ if (tmp[i] == ';') {
+ ivm_set_value ("IVM_ShortText", (char *)&tmp[i + 1]);
+ break;
+ }
+ i++;
+ }
+ if (i >= len)
+ ivm_set_value ("IVM_ShortText", NULL);
+ } else {
+ ivm_set_value ("IVM_ShortText", NULL);
+ }
+ GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32)
+ GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20)
+ GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32)
+ GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32)
+ GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32)
+ GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32)
+ GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32)
+ GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32)
+ GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32)
+
+ if (ivm_check_crc (&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0)
+ return -2;
+ ivm_analyze_block2 (&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], CONFIG_SYS_IVM_EEPROM_PAGE_LEN);
+
+ return 0;
+}
+
+int ivm_read_eeprom (void)
+{
+ I2C_MUX_DEVICE *dev = NULL;
+ uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN];
+ uchar *buf;
+ unsigned dev_addr = CONFIG_SYS_IVM_EEPROM_ADR;
+
+ /* First init the Bus, select the Bus */
+#if defined(CONFIG_SYS_I2C_IVM_BUS)
+ dev = i2c_mux_ident_muxstring ((uchar *)CONFIG_SYS_I2C_IVM_BUS);
+#else
+ buf = (unsigned char *) getenv ("EEprom_ivm");
+ if (buf != NULL)
+ dev = i2c_mux_ident_muxstring (buf);
+#endif
+ if (dev == NULL) {
+ printf ("Error couldnt add Bus for IVM\n");
+ return -1;
+ }
+ i2c_set_bus_num (dev->busid);
+
+ buf = (unsigned char *) getenv ("EEprom_ivm_addr");
+ if (buf != NULL)
+ dev_addr = simple_strtoul ((char *)buf, NULL, 16);
+
+ if (eeprom_read (dev_addr, 0, i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN) != 0) {
+ printf ("Error reading EEprom\n");
+ return -2;
+ }
+
+ return ivm_analyze_eeprom (i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN);
+}
+
+#if defined(CONFIG_SYS_I2C_INIT_BOARD)
+#define DELAY_ABORT_SEQ 62
+#define DELAY_HALF_PERIOD (500 / (CONFIG_SYS_I2C_SPEED / 1000))
+
+#if defined(CONFIG_MGCOGE)
+#define SDA_MASK 0x00010000
+#define SCL_MASK 0x00020000
+static void set_pin (int state, unsigned long mask)
+{
+ volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3);
+
+ if (state)
+ iop->pdat |= (mask);
+ else
+ iop->pdat &= ~(mask);
+
+ iop->pdir |= (mask);
+}
+
+static int get_pin (unsigned long mask)
+{
+ volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3);
+
+ iop->pdir &= ~(mask);
+ return (0 != (iop->pdat & (mask)));
+}
+
+static void set_sda (int state)
+{
+ set_pin (state, SDA_MASK);
+}
+
+static void set_scl (int state)
+{
+ set_pin (state, SCL_MASK);
+}
+
+static int get_sda (void)
+{
+ return get_pin (SDA_MASK);
+}
+
+static int get_scl (void)
+{
+ return get_pin (SCL_MASK);
+}
+
+#if defined(CONFIG_HARD_I2C)
+static void setports (int gpio)
+{
+ volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3);
+
+ if (gpio) {
+ iop->ppar &= ~(SDA_MASK | SCL_MASK);
+ iop->podr &= ~(SDA_MASK | SCL_MASK);
+ } else {
+ iop->ppar |= (SDA_MASK | SCL_MASK);
+ iop->pdir &= ~(SDA_MASK | SCL_MASK);
+ iop->podr |= (SDA_MASK | SCL_MASK);
+ }
+}
+#endif
+#endif
+
+#if defined(CONFIG_MGSUVD)
+static void set_sda (int state)
+{
+ I2C_SDA(state);
+}
+
+static void set_scl (int state)
+{
+ I2C_SCL(state);
+}
+
+static int get_sda (void)
+{
+ return I2C_READ;
+}
+
+static int get_scl (void)
+{
+ int val;
+
+ *(unsigned short *)(I2C_BASE_DIR) &= ~SCL_CONF;
+ udelay (1);
+ val = *(unsigned char *)(I2C_BASE_PORT);
+
+ return ((val & SCL_BIT) == SCL_BIT);
+}
+
+#endif
+
+static void writeStartSeq (void)
+{
+ set_sda (1);
+ udelay (DELAY_HALF_PERIOD);
+ set_scl (1);
+ udelay (DELAY_HALF_PERIOD);
+ set_sda (0);
+ udelay (DELAY_HALF_PERIOD);
+ set_scl (0);
+ udelay (DELAY_HALF_PERIOD);
+}
+
+/* I2C is a synchronous protocol and resets of the processor in the middle
+ of an access can block the I2C Bus until a powerdown of the full unit is
+ done. This function toggles the SCL until the SCL and SCA line are
+ released, but max. 16 times, after this a I2C start-sequence is sent.
+ This I2C Deblocking mechanism was developed by Keymile in association
+ with Anatech and Atmel in 1998.
+ */
+static int i2c_make_abort (void)
+{
+ int scl_state = 0;
+ int sda_state = 0;
+ int i = 0;
+ int ret = 0;
+
+ if (!get_sda ()) {
+ ret = -1;
+ while (i < 16) {
+ i++;
+ set_scl (0);
+ udelay (DELAY_ABORT_SEQ);
+ set_scl (1);
+ udelay (DELAY_ABORT_SEQ);
+ scl_state = get_scl ();
+ sda_state = get_sda ();
+ if (scl_state && sda_state) {
+ ret = 0;
+ break;
+ }
+ }
+ }
+ if (ret == 0) {
+ for (i =0; i < 5; i++) {
+ writeStartSeq ();
+ }
+ }
+ get_sda ();
+ return ret;
+}
+
+/**
+ * i2c_init_board - reset i2c bus. When the board is powercycled during a
+ * bus transfer it might hang; for details see doc/I2C_Edge_Conditions.
+ */
+void i2c_init_board(void)
+{
+#if defined(CONFIG_HARD_I2C)
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ;
+ volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
+
+ /* disable I2C controller first, otherwhise it thinks we want to */
+ /* talk to the slave port... */
+ i2c->i2c_i2mod &= ~0x01;
+
+ /* Set the PortPins to GPIO */
+ setports (1);
+#endif
+
+ /* Now run the AbortSequence() */
+ i2c_make_abort ();
+
+#if defined(CONFIG_HARD_I2C)
+ /* Set the PortPins back to use for I2C */
+ setports (0);
+#endif
+}
+#endif
+
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
+int fdt_set_node_and_value (void *blob,
+ char *nodename,
+ char *regname,
+ void *var,
+ int size)
+{
+ int ret = 0;
+ int nodeoffset = 0;
+
+ nodeoffset = fdt_path_offset (blob, nodename);
+ if (nodeoffset >= 0) {
+ ret = fdt_setprop (blob, nodeoffset, regname, var,
+ size);
+ if (ret < 0)
+ printf("ft_blob_update(): cannot set %s/%s "
+ "property err:%s\n", nodename, regname,
+ fdt_strerror (ret));
+ } else {
+ printf("ft_blob_update(): cannot find %s node "
+ "err:%s\n", nodename, fdt_strerror (nodeoffset));
+ }
+ return ret;
+}
+#endif
diff --git a/board/keymile/common/keymile_hdlc_enet.c b/board/keymile/common/keymile_hdlc_enet.c
new file mode 100644
index 0000000..141371b
--- /dev/null
+++ b/board/keymile/common/keymile_hdlc_enet.c
@@ -0,0 +1,620 @@
+/*
+ * (C) Copyright 2008
+ * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
+ *
+ * Based in part on cpu/mpc8260/ether_scc.c.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+
+#ifdef CONFIG_KEYMILE_HDLC_ENET
+#ifdef TEST_IT
+#include <command.h>
+#endif
+
+#include "keymile_hdlc_enet.h"
+
+extern char keymile_slot; /* our slot number in the backplane */
+
+/* Allow up to about 50 ms for sending */
+#define TOUT_LOOP 50000
+
+/*
+ * Since, except during initialization, ethact is always HDLC ETHERNET
+ * while we're in the driver, just use serial_printf() everywhere for
+ * output. This avoids possible conflicts when netconsole is being
+ * used.
+ */
+#define dprintf(fmt, args...) serial_printf(fmt, ##args)
+
+/* Cannot use the storage from net.c because we allocate larger buffers */
+static volatile uchar MyPktBuf[HDLC_PKTBUFSRX * PKT_MAXBLR_SIZE + PKTALIGN];
+static volatile uchar *MyRxPackets[HDLC_PKTBUFSRX]; /* Receive packet */
+
+static unsigned int keymile_rxIdx; /* index of the current RX buffer */
+
+static IPaddr_t cachedNumbers[CACHEDNUMBERS]; /* 4 bytes per entry */
+void initCachedNumbers(int);
+
+/*
+ * SCC Ethernet Tx and Rx buffer descriptors allocated at the
+ * immr->udata_bd address on Dual-Port RAM
+ * Provide for Double Buffering
+ */
+typedef volatile struct CommonBufferDescriptor {
+ cbd_t txbd; /* Tx BD */
+ cbd_t rxbd[HDLC_PKTBUFSRX]; /* Rx BD */
+} RTXBD;
+
+/*
+ * This must be extern because it is allocated in DPRAM using CPM-sepcific
+ * code.
+ */
+static RTXBD *rtx;
+
+static int keymile_hdlc_enet_send(struct eth_device *, volatile void *, int);
+static int keymile_hdlc_enet_recv(struct eth_device *);
+void keymile_hdlc_enet_init_bds(RTXBD *);
+extern int keymile_hdlc_enet_init(struct eth_device *, bd_t *);
+extern void keymile_hdlc_enet_halt(struct eth_device *);
+
+/* flags in the buffer descriptor not defined anywhere else */
+#define BD_SC_CT BD_SC_CD
+#define BD_SC_CR 0x04
+#define BD_SC_DE 0x80
+#ifndef BD_SC_TC
+#define BD_SC_TC ((ushort)0x0400) /* Transmit CRC */
+#endif
+#define BD_SC_FIRST BD_SC_TC
+#define BD_SC_STATS (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_CR | BD_SC_CD \
+ | BD_SC_OV | BD_SC_DE)
+
+#if defined(TEST_RX) || defined(TEST_TX) || defined(TEST_IT)
+static void hexdump(unsigned char *buf, int len)
+{
+ int i;
+ const int bytesPerLine = 32;
+
+ if (len > 4 * bytesPerLine)
+ len = 4 * bytesPerLine;
+ dprintf("\t address: %08x\n", (unsigned int)buf);
+ for (i = 0; i < len; i++) {
+ if (i % bytesPerLine == 0)
+ dprintf("%04x: ", (unsigned short)i);
+ dprintf("%02x ", buf[i]);
+ if ((i + 1) % bytesPerLine == 0) {
+ dprintf("\n");
+ continue;
+ }
+ if ((i + 1) % 8 == 0)
+ printf(" ");
+ }
+ if (len % bytesPerLine)
+ dprintf("\n");
+}
+#endif
+
+int keymile_hdlc_enet_initialize(bd_t *bis)
+{
+ struct eth_device *dev;
+
+ dev = (struct eth_device *) malloc(sizeof *dev);
+ memset(dev, 0, sizeof *dev);
+#ifdef TEST_IT
+ seth = dev;
+#endif
+
+ sprintf(dev->name, "HDLC ETHERNET");
+ dev->init = keymile_hdlc_enet_init;
+ dev->halt = keymile_hdlc_enet_halt;
+ dev->send = keymile_hdlc_enet_send;
+ dev->recv = keymile_hdlc_enet_recv;
+
+ eth_register(dev);
+
+ return 1;
+}
+
+/*
+ * This is called from the board-specific driver after rtx is allocated.
+ */
+void keymile_hdlc_enet_init_bds(RTXBD *board_rtx)
+{
+ volatile cbd_t *bdp;
+ int i;
+
+ rtx = board_rtx;
+ keymile_rxIdx = 0;
+ /*
+ * Initialize the buffer descriptors.
+ */
+ bdp = &rtx->txbd;
+ bdp->cbd_sc = 0;
+ bdp->cbd_bufaddr = 0;
+ bdp->cbd_sc = BD_SC_WRAP;
+
+ /*
+ * Setup RX packet buffers, aligned correctly.
+ * Borrowed from net/net.c.
+ */
+ MyRxPackets[0] = &MyPktBuf[0] + (PKTALIGN - 1);
+ MyRxPackets[0] -= (ulong)MyRxPackets[0] % PKTALIGN;
+ for (i = 1; i < HDLC_PKTBUFSRX; i++)
+ MyRxPackets[i] = MyRxPackets[0] + i * PKT_MAXBLR_SIZE;
+
+ bdp = &rtx->rxbd[0];
+ for (i = 0; i < HDLC_PKTBUFSRX; i++) {
+ bdp->cbd_sc = BD_SC_EMPTY;
+ /* Leave space at the start for INET header. */
+ bdp->cbd_bufaddr = (unsigned int)(MyRxPackets[i] +
+ INET_HDR_ALIGN);
+ bdp++;
+ }
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+}
+
+/*
+ * This returns the current port number for NETCONSOLE. If nc_port
+ * in netconsole.c weren't declared static we wouldn't need this.
+ */
+static short get_netcons_port(void)
+{
+ char *p;
+ short nc_port;
+
+ nc_port = 6666; /* default */
+
+ p = getenv("ncip");
+ if (p != NULL) {
+ p = strchr(p, ':');
+ if (p != NULL)
+ nc_port = simple_strtoul(p + 1, NULL, 10);
+ }
+
+ return htons(nc_port);
+}
+
+/*
+ * Read the port numbers from the variables
+ */
+void initCachedNumbers(int verbose)
+{
+ char *str;
+ ushort port;
+
+ /* already in network order */
+ cachedNumbers[IP_ADDR] = getenv_IPaddr("ipaddr");
+ /* already in network order */
+ cachedNumbers[IP_SERVER] = getenv_IPaddr("serverip");
+ str = getenv("tftpsrcp");
+ if (str != NULL) {
+ /* avoid doing htons() again and again */
+ port = htons((ushort)simple_strtol(str, NULL, 10));
+ cachedNumbers[TFTP_SRC_PORT] = port;
+ } else
+ /* this can never be a valid port number */
+ cachedNumbers[TFTP_SRC_PORT] = (ulong)-1;
+ str = getenv("tftpdstp");
+ if (str != NULL) {
+ /* avoid doing htons() again and again */
+ port = htons((ushort)simple_strtol(str, NULL, 10));
+ cachedNumbers[TFTP_DST_PORT] = port;
+ } else
+ /* this is the default value */
+ cachedNumbers[TFTP_DST_PORT] = htons(WELL_KNOWN_PORT);
+ /* already in network order */
+ cachedNumbers[NETCONS_PORT] = get_netcons_port();
+ if (verbose) {
+ dprintf("\nIP Number Initialization:\n");
+ dprintf(" ip address %08lx\n", cachedNumbers[IP_ADDR]);
+ dprintf(" server ip address %08lx\n",
+ cachedNumbers[IP_SERVER]);
+ dprintf(" tftp client port %ld\n",
+ cachedNumbers[TFTP_SRC_PORT]);
+ dprintf(" tftp server port %ld\n",
+ cachedNumbers[TFTP_DST_PORT]);
+ dprintf(" netcons port %ld\n",
+ cachedNumbers[NETCONS_PORT]);
+ dprintf(" slot number (hex) %02x\n", keymile_slot);
+ }
+}
+
+static void keymile_hdlc_enet_doarp(volatile void *packet, int len)
+{
+ ARP_t *arp;
+ IPaddr_t src_ip; /* U-Boot's IP */
+ IPaddr_t dest_ip; /* the mgcoge's IP */
+ unsigned char *packet_copy = malloc(len);
+
+ /*
+ * Handling an ARP request means that a new transfer has started.
+ * Update our cached parameters now.
+ */
+ initCachedNumbers(0); /* may reinit port numbers */
+
+ /* special handling required for ARP */
+ arp = (ARP_t *)(packet + ETHER_HDR_SIZE);
+ /*
+ * XXXX
+ * This is pretty dirty! NetReceive only uses
+ * a few fields when handling an ARP reply, so
+ * we only modify those here. This could
+ * result in catastrophic failure at a later
+ * time if the handler is modified!
+ */
+ arp->ar_op = htons(ARPOP_REPLY);
+ /* save his/our IP */
+ src_ip = NetReadIP(&arp->ar_data[6]);
+ dest_ip = NetReadIP(&arp->ar_data[16]);
+ /* copy target IP to source IP */
+ NetCopyIP(&arp->ar_data[6], &dest_ip);
+ /* copy our IP to the right place */
+ NetCopyIP(&arp->ar_data[16], &src_ip);
+ /* always use 0x7f as the MAC for the coge */
+ arp->ar_data[0] = HDLC_UACUA;
+ /*
+ * copy the packet
+ * if NetReceive wants to write to stdout, it may overwrite packet
+ * especially if stdout is set to nc!
+ *
+ * However, if the malloc() above fails then we can still try the
+ * original packet, rather than causing the transfer to fail.
+ */
+ if (packet_copy != NULL) {
+ memcpy(packet_copy, (char *)packet, len);
+ NetReceive(packet_copy, len);
+ free(packet_copy);
+ } else
+ NetReceive(packet, len);
+}
+
+/*
+ * NOTE all callers ignore the returned value!
+ * At the moment this only handles ARP Requests, TFTP and NETCONSOLE.
+ */
+static int keymile_hdlc_enet_send(struct eth_device *dev, volatile void *packet,
+ int len)
+{
+ int j;
+ uint data_addr;
+ int data_len;
+ struct icn_hdr header;
+ struct icn_frame *frame;
+ Ethernet_t *et;
+ ARP_t *arp;
+ IP_t *ip;
+
+ if (len > (MAX_FRAME_LENGTH - sizeof(header)))
+ return -1;
+
+ frame = NULL;
+ et = NULL;
+ arp = NULL;
+ ip = NULL;
+
+ j = 0;
+ while ((rtx->txbd.cbd_sc & BD_SC_READY) && (j < TOUT_LOOP)) {
+ /* will also trigger Wd if needed, but maybe too often */
+ udelay(1);
+ j++;
+ }
+ if (j >= TOUT_LOOP) {
+ dprintf("TX not ready sc %x\n", rtx->txbd.cbd_sc);
+ return -1;
+ }
+
+ /*
+ * First check for an ARP Request since this requires special handling.
+ */
+ if (len >= (ARP_HDR_SIZE + ETHER_HDR_SIZE)) {
+ et = (Ethernet_t *)packet;
+ arp = (ARP_t *)(((char *)et) + ETHER_HDR_SIZE);
+ /* ARP and REQUEST? */
+ if (et->et_protlen == PROT_ARP &&
+ arp->ar_op == htons(ARPOP_REQUEST)) {
+ /* just short-circuit the request on the U-Boot side */
+ keymile_hdlc_enet_doarp(packet, len);
+ return 0;
+ }
+ }
+
+ /*
+ * GJ - I suppose the assumption here that len will always be
+ * > INET_HDR_SIZE is alright as long as the network stack
+ * isn't changed.
+ * Do not send INET header.
+ */
+ data_len = len + sizeof(header) - INET_HDR_SIZE;
+ frame = (struct icn_frame *) (((char *)packet) + INET_HDR_SIZE -
+ sizeof(header));
+
+#ifdef TEST_TX
+ printf("frame: %08x, ", frame);
+ hexdump((unsigned char *)packet, data_len + INET_HDR_SIZE);
+#endif
+
+ data_addr = (uint)frame;
+ if (len >= (IP_HDR_SIZE + ETHER_HDR_SIZE))
+ ip = (IP_t *)(packet + ETHER_HDR_SIZE);
+ /* Is it TFTP? TFTP always uses UDP and the cached dport */
+ if (ip != NULL && ip->ip_p == IPPROTO_UDP && ip->udp_dst ==
+ (ushort)cachedNumbers[TFTP_DST_PORT]) {
+ /* just in case the port wasn't set in the environment */
+ if (cachedNumbers[TFTP_SRC_PORT] == (ulong)-1)
+ cachedNumbers[TFTP_SRC_PORT] = ip->udp_src;
+ frame->hdr.application = MGS_TFTP;
+ }
+ /*
+ * Is it NETCONSOLE? NETCONSOLE always uses UDP.
+ */
+ else if (ip != NULL && ip->ip_p == IPPROTO_UDP
+ && ip->udp_dst == (ushort)cachedNumbers[NETCONS_PORT]) {
+ frame->hdr.application = MGS_NETCONS;
+ } else {
+ /* reject unknown packets */
+ /* may do some check on frame->hdr.application */
+ dprintf("Unknown packet type in %s, rejected\n",
+ __func__);
+ return -1;
+ }
+ /*
+ * Could extract the target's slot ID from its MAC here,
+ * but u-boot only wants to talk to the active server.
+ *
+ * avoid setting new source address when moving to another slot
+ */
+ frame->hdr.src_addr = keymile_slot;
+ frame->hdr.dest_addr = HDLC_UACUA;
+#ifdef TEST_TX
+ {
+ dprintf("TX: ");
+ hexdump((unsigned char *)data_addr, data_len);
+ }
+#endif
+
+ flush_cache(data_addr, data_len);
+ rtx->txbd.cbd_bufaddr = data_addr;
+ rtx->txbd.cbd_datlen = data_len;
+ rtx->txbd.cbd_sc |= (BD_SC_READY | BD_SC_TC | BD_SC_LAST | BD_SC_WRAP);
+
+ while ((rtx->txbd.cbd_sc & BD_SC_READY) && (j < TOUT_LOOP)) {
+ /* will also trigger Wd if needed, but maybe too often */
+ udelay(1);
+ j++;
+ }
+ if (j >= TOUT_LOOP)
+ dprintf("TX timeout\n");
+#ifdef ET_DEBUG
+ dprintf("cycles: %d status: %x\n", j, rtx->txbd.cbd_sc);
+#endif
+ j = (rtx->txbd.cbd_sc & BD_SC_STATS); /* return only status bits */
+ return j;
+}
+
+/*
+ * During a receive, the RxIdx points to the current incoming buffer.
+ * When we update through the ring, if the next incoming buffer has
+ * not been given to the system, we just set the empty indicator,
+ * effectively tossing the packet.
+ */
+static int keymile_hdlc_enet_recv(struct eth_device *dev)
+{
+ int length;
+ unsigned char app;
+ struct icn_frame *fp;
+ Ethernet_t *ep;
+ IP_t *ip;
+
+ for (;;) {
+ if (rtx->rxbd[keymile_rxIdx].cbd_sc & BD_SC_EMPTY) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ length = rtx->rxbd[keymile_rxIdx].cbd_datlen;
+#ifdef TEST_RX
+ dprintf("packet %d bytes long\n", length);
+#endif
+
+ /*
+ * BD_SC_BR -> LG bit
+ * BD_SC_FR -> NO bit
+ * BD_SC_PR -> AB bit
+ * BD_SC_NAK -> CR bit
+ * 0x80 -> DE bit
+ */
+ if (rtx->rxbd[keymile_rxIdx].cbd_sc & BD_SC_STATS) {
+#ifdef ET_DEBUG
+ dprintf("err: %x\n", rtx->rxbd[keymile_rxIdx].cbd_sc);
+#endif
+ } else if (length > MAX_FRAME_LENGTH) { /* can't happen */
+#ifdef ET_DEBUG
+ dprintf("err: packet too big\n");
+#endif
+ } else {
+ fp = (struct icn_frame *)(MyRxPackets[keymile_rxIdx] +
+ INET_HDR_ALIGN - INET_HDR_SIZE);
+#ifdef TEST_RX
+ dprintf("RX %d: ", keymile_rxIdx);
+ hexdump((unsigned char *)MyRxPackets[keymile_rxIdx],
+ INET_HDR_ALIGN + INET_HDR_SIZE + 4);
+#endif
+ /* copy icn header to the beginning */
+ memcpy(fp, ((char *)fp + INET_HDR_SIZE),
+ sizeof(struct icn_hdr));
+ app = fp->hdr.application;
+ if (app == MGS_NETCONS || app == MGS_TFTP) {
+ struct icn_hdr *ih = &fp->hdr;
+ unsigned char icn_src_addr = ih->src_addr;
+ unsigned char icn_dest_addr = ih->dest_addr;
+
+ /*
+ * expand header by INET_HDR_SIZE
+ */
+ length += INET_HDR_SIZE;
+ /* initalize header */
+ memset((char *)fp->data, 0x00, INET_HDR_SIZE);
+ ep = (Ethernet_t *)fp->data;
+ /* set MACs */
+ ep->et_dest[0] = icn_dest_addr;
+ ep->et_src[0] = icn_src_addr;
+ ep->et_protlen = htons(PROT_IP);
+ /* set ip stuff */
+ ip = (IP_t *)(fp->data + ETHER_HDR_SIZE);
+ /* set ip addresses */
+ ip->ip_src = cachedNumbers[IP_SERVER];
+ ip->ip_dst = cachedNumbers[IP_ADDR];
+ /* ip length */
+ ip->ip_len = htons(length - ETHER_HDR_SIZE -
+ REMOVE);
+ /* ip proto */
+ ip->ip_p = IPPROTO_UDP;
+ switch (app) {
+ case MGS_TFTP:
+ /* swap src/dst port numbers */
+ ip->udp_src = (ushort)
+ cachedNumbers[TFTP_DST_PORT];
+ ip->udp_dst = (ushort)
+ cachedNumbers[TFTP_SRC_PORT];
+ ip->udp_len = ip->ip_len -
+ IP_HDR_SIZE_NO_UDP;
+ ip->udp_xsum = 0;
+ break;
+ case MGS_NETCONS:
+ ip->udp_src = (ushort)
+ cachedNumbers[NETCONS_PORT];
+ /*
+ * in drivers/net/netconsole.c src port
+ * equals dest port
+ */
+ ip->udp_dst = ip->udp_src;
+ ip->udp_len = ip->ip_len -
+ IP_HDR_SIZE_NO_UDP;
+ ip->udp_xsum = 0;
+ break;
+ }
+ /* ip version */
+ ip->ip_hl_v = (0x40) | (0x0f &
+ (IP_HDR_SIZE_NO_UDP / 4));
+ ip->ip_tos = 0;
+ ip->ip_id = 0;
+ /* flags, fragment offset */
+ ip->ip_off = htons(0x4000);
+ ip->ip_ttl = 255; /* time to live */
+ /* have to fixup the checksum */
+ ip->ip_sum = ~NetCksum((uchar *)ip,
+ IP_HDR_SIZE_NO_UDP / 2);
+ /*
+ * Pass the packet up to the protocol layers
+ * but remove dest_addr, src_addr, application
+ * and the CRC.
+ */
+#ifdef TEST_RX
+ hexdump((unsigned char *)fp->data,
+ INET_HDR_SIZE + 4);
+#endif
+ NetReceive(fp->data, length - REMOVE);
+ } else {
+ /*
+ * the other application types are not yet
+ * supported by u-boot.
+ */
+ /* normally drop it */
+#ifdef TEST_NO
+ /* send it anyway */
+ fp = (struct icn_frame *)
+ (MyRxPackets[keymile_rxIdx] +
+ INET_HDR_ALIGN);
+ NetReceive(fp->data, length - REMOVE);
+#endif
+ }
+ }
+
+ /* Give the buffer back to the SCC. */
+ rtx->rxbd[keymile_rxIdx].cbd_datlen = 0;
+
+ /* wrap around buffer index when necessary */
+ if ((keymile_rxIdx + 1) >= HDLC_PKTBUFSRX) {
+ rtx->rxbd[HDLC_PKTBUFSRX - 1].cbd_sc =
+ (BD_SC_WRAP | BD_SC_EMPTY);
+ keymile_rxIdx = 0;
+ } else {
+ rtx->rxbd[keymile_rxIdx].cbd_sc = BD_SC_EMPTY;
+ keymile_rxIdx++;
+ }
+ }
+ return length;
+}
+
+#ifdef TEST_IT
+/* simple send test routine */
+int hdlc_enet_stest(struct cmd_tbl_s *a, int b, int c, char **d)
+{
+ unsigned char pkt[2];
+ int ret;
+
+ dprintf("enter stest\n");
+ /* may have to initialize things */
+ if (seth->state != ETH_STATE_ACTIVE) {
+ /* the bd_t* is not used */
+ if (seth->init(seth, NULL) >= 0)
+ seth->state = ETH_STATE_ACTIVE;
+ }
+ pkt[0] = 0xea;
+ pkt[1] = 0xae;
+ ret = keymile_hdlc_enet_send(seth, pkt, 2);
+ dprintf("return from send %x\n", ret);
+ dprintf("exit stest\n");
+ return ret;
+}
+U_BOOT_CMD(
+ stest, 1, 1, hdlc_enet_stest,
+ "stest - simple send test for hdlc_enet\n",
+ "no arguments\n"
+);
+/* simple receive test routine */
+int hdlc_enet_rtest(struct cmd_tbl_s *a, int b, int c, char **d)
+{
+ int ret;
+
+ dprintf("enter rtest\n");
+ /* may have to initialize things */
+ if (seth->state != ETH_STATE_ACTIVE) {
+ /* the bd_t* is not used */
+ if (seth->init(seth, NULL) >= 0)
+ seth->state = ETH_STATE_ACTIVE;
+ }
+ ret = keymile_hdlc_enet_recv(seth);
+ dprintf("return from recv %x\n", ret);
+ dprintf("exit rtest\n");
+ return ret;
+}
+U_BOOT_CMD(
+ rtest, 1, 1, hdlc_enet_rtest,
+ "rtest - simple receive test for hdlc_enet\n",
+ "no arguments\n"
+);
+#endif
+
+#endif /* CONFIG_KEYMILE_HDLC_ENET */
diff --git a/board/keymile/common/keymile_hdlc_enet.h b/board/keymile/common/keymile_hdlc_enet.h
new file mode 100644
index 0000000..965bd5a
--- /dev/null
+++ b/board/keymile/common/keymile_hdlc_enet.h
@@ -0,0 +1,129 @@
+/*
+ * (C) Copyright 2008
+ * Gary Jennejohn, DENX Software Engineering GmbH, garyj@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
+ */
+
+#ifndef _KEYMILE_HDLC_ENET_H_
+#define _KEYMILE_HDLC_ENET_H_
+
+/* Unfortuantely, we have do this to get the flag defines in the cbd_t */
+#ifdef CONFIG_MGSUVD
+#include <commproc.h>
+#endif
+#ifdef CONFIG_MGCOGE
+#include <mpc8260.h>
+#include <asm/cpm_8260.h>
+#endif
+
+/*
+ * Defines for the ICN protocol used for communication over HDLC
+ * on the backplane between MGSUVDs and MGCOGEs.
+ */
+
+/*
+ * MAC which is reserved for communication (0x00 - 0xff in the last byte,
+ * which is the slot number)
+ */
+
+/*
+ * A DLL frame looks like this:
+ * 8 bit | 8 bit | 8 bit | 8 bit | n * 8 bit| 16 bit| 8 bit
+ * opening| destination| source | application| data | FCS | closing
+ * flag | address | address| | | | flag
+ * (HW) (APP) (APP) (APP) (APP) (HW) (HW)
+ */
+
+/*
+ * The opening flag, the FCS and the closing flag are set by the hardware so
+ * they are not reflected in this struct.
+ */
+struct icn_hdr {
+ unsigned char dest_addr;
+ unsigned char src_addr;
+ unsigned char application;
+} __attribute__((packed));
+
+#define ICNHDR_LEN (sizeof(struct icn_hdr))
+#define CRC_LEN (sizeof(short))
+/* bytes to remove from packet before sending it upstream */
+#define REMOVE (ICNHDR_LEN + CRC_LEN)
+
+struct icn_frame {
+ struct icn_hdr hdr;
+ unsigned char data[0]; /* a place holder */
+} __attribute__((packed));
+
+/* Address field */
+#define HDLC_UUA 0x00 /* Unicast Unit Address */
+#define HDLC_UUA_MASK 0x3f /* the last 6 bits contain the slot number */
+#define SET_HDLC_UUA(x) ((HDLC_UUA | ((x) & HDLC_UUA_MASK)))
+#define HDLC_UACUA 0x7f /* Unicast Active Control Unit Address */
+#define HDLC_BCAST 0xff /* broadcast */
+
+/* Application field */
+#define MGS_UUSP 0x00
+#define MGS_UREP 0x01
+#define MGS_IUP 0x02
+#define MGS_UTA 0x03
+#define MGS_MDS 0x04
+#define MGS_ITIME 0x05
+/* added by DENX */
+#define MGS_NETCONS 0x06 /* netconsole */
+#define MGS_TFTP 0x07
+
+/* Useful defines for buffer sizes, etc. */
+#define HDLC_PKTBUFSRX 32
+#define MAX_FRAME_LENGTH 1500 /* ethernet frame size */
+ /* 14 + 28 */
+#define INET_HDR_SIZE (ETHER_HDR_SIZE + IP_HDR_SIZE)
+#define INET_HDR_ALIGN (((INET_HDR_SIZE + PKTALIGN - 1) / PKTALIGN) * PKTALIGN)
+/* INET_HDR_SIZE is stripped off */
+#define PKT_MAXBLR_SIZE (MAX_FRAME_LENGTH + INET_HDR_ALIGN)
+
+/*
+ * It is too slow to read always the port numbers and IP addresses from the
+ * string variables.
+ * cachedNumbers is meant to cache it.
+ * THIS IS ONLY A SPEED IMPROVEMENT!
+ */
+enum {
+ IP_ADDR = 0, /* getenv_IPaddr("serverip"); */
+ IP_SERVER, /* getenv_IPaddr("ipaddr"); */
+ TFTP_SRC_PORT, /* simple_strtol(getenv("tftpsrcp"), NULL, 10); */
+ TFTP_DST_PORT, /* simple_strtol(getenv("tftpdstp"), NULL, 10); */
+ NETCONS_PORT, /* simple_strtol(getenv("ncip"), NULL, 10); */
+ CACHEDNUMBERS
+};
+
+#define WELL_KNOWN_PORT 69 /* Well known TFTP port # */
+
+/* define this to create a test commend (htest) */
+#undef TEST_IT
+#ifdef TEST_IT
+/* have to save a copy of the eth_device for the test command's use */
+struct eth_device *seth;
+#endif
+/* define this for outputting of received packets */
+#undef TEST_RX
+/* define this for outputting of packets being sent */
+#undef TEST_TX
+
+#endif /* _KEYMILE_HDLC_ENET_H_ */
diff --git a/board/keymile/mgcoge/Makefile b/board/keymile/mgcoge/Makefile
new file mode 100644
index 0000000..2774a70
--- /dev/null
+++ b/board/keymile/mgcoge/Makefile
@@ -0,0 +1,54 @@
+#
+# (C) Copyright 2001-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+ifneq ($(OBJTREE),$(SRCTREE))
+$(shell mkdir -p $(obj)../common)
+endif
+
+LIB = $(obj)lib$(BOARD).a
+
+COBJS := $(BOARD).o ../common/common.o ../common/keymile_hdlc_enet.o \
+ mgcoge_hdlc_enet.o
+
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+SOBJS := $(addprefix $(obj),$(SOBJS))
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+clean:
+ rm -f $(SOBJS) $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak $(obj).depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/keymile/mgcoge/config.mk b/board/keymile/mgcoge/config.mk
new file mode 100644
index 0000000..143bc9f
--- /dev/null
+++ b/board/keymile/mgcoge/config.mk
@@ -0,0 +1,24 @@
+#
+# (C) Copyright 2007
+# Heiko Schocher, DENX Software Engineering, hs@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
+#
+
+TEXT_BASE = 0xFE000000
diff --git a/board/keymile/mgcoge/mgcoge.c b/board/keymile/mgcoge/mgcoge.c
new file mode 100644
index 0000000..3683417
--- /dev/null
+++ b/board/keymile/mgcoge/mgcoge.c
@@ -0,0 +1,349 @@
+/*
+ * (C) Copyright 2007 - 2008
+ * Heiko Schocher, DENX Software Engineering, hs@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 <common.h>
+#include <mpc8260.h>
+#include <ioports.h>
+#include <malloc.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#endif
+
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
+#include <i2c.h>
+#endif
+
+extern int ivm_read_eeprom (void);
+/*
+ * 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 */
+ { /* conf ppar psor pdir podr pdat */
+ /* PA31 */ { 0, 0, 0, 0, 0, 0 }, /* PA31 */
+ /* PA30 */ { 0, 0, 0, 0, 0, 0 }, /* PA30 */
+ /* PA29 */ { 0, 0, 0, 0, 0, 0 }, /* PA29 */
+ /* PA28 */ { 0, 0, 0, 0, 0, 0 }, /* PA28 */
+ /* PA27 */ { 0, 0, 0, 0, 0, 0 }, /* PA27 */
+ /* PA26 */ { 0, 0, 0, 0, 0, 0 }, /* PA26 */
+ /* PA25 */ { 0, 0, 0, 0, 0, 0 }, /* PA25 */
+ /* PA24 */ { 0, 0, 0, 0, 0, 0 }, /* PA24 */
+ /* PA23 */ { 0, 0, 0, 0, 0, 0 }, /* PA23 */
+ /* PA22 */ { 0, 0, 0, 0, 0, 0 }, /* PA22 */
+ /* PA21 */ { 0, 0, 0, 0, 0, 0 }, /* PA21 */
+ /* PA20 */ { 0, 0, 0, 0, 0, 0 }, /* PA20 */
+ /* PA19 */ { 0, 0, 0, 0, 0, 0 }, /* PA19 */
+ /* PA18 */ { 0, 0, 0, 0, 0, 0 }, /* PA18 */
+ /* PA17 */ { 0, 0, 0, 0, 0, 0 }, /* PA17 */
+ /* PA16 */ { 0, 0, 0, 0, 0, 0 }, /* PA16 */
+ /* PA15 */ { 0, 0, 0, 0, 0, 0 }, /* PA15 */
+ /* PA14 */ { 0, 0, 0, 0, 0, 0 }, /* PA14 */
+ /* PA13 */ { 0, 0, 0, 0, 0, 0 }, /* PA13 */
+ /* PA12 */ { 0, 0, 0, 0, 0, 0 }, /* PA12 */
+ /* PA11 */ { 0, 0, 0, 0, 0, 0 }, /* PA11 */
+ /* PA10 */ { 0, 0, 0, 0, 0, 0 }, /* PA10 */
+ /* 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 }, /* PA7 */
+ /* PA6 */ { 0, 0, 0, 0, 0, 0 }, /* PA6 */
+ /* PA5 */ { 0, 0, 0, 0, 0, 0 }, /* PA5 */
+ /* PA4 */ { 0, 0, 0, 0, 0, 0 }, /* PA4 */
+ /* PA3 */ { 0, 0, 0, 0, 0, 0 }, /* PA3 */
+ /* PA2 */ { 0, 0, 0, 0, 0, 0 }, /* PA2 */
+ /* PA1 */ { 0, 0, 0, 0, 0, 0 }, /* PA1 */
+ /* PA0 */ { 0, 0, 0, 0, 0, 0 } /* PA0 */
+ },
+
+ /* Port B */
+ { /* conf ppar psor pdir podr pdat */
+ /* PB31 */ { 0, 0, 0, 0, 0, 0 }, /* PB31 */
+ /* PB30 */ { 0, 0, 0, 0, 0, 0 }, /* PB30 */
+ /* PB29 */ { 0, 0, 0, 0, 0, 0 }, /* PB29 */
+ /* PB28 */ { 0, 0, 0, 0, 0, 0 }, /* PB28 */
+ /* PB27 */ { 0, 0, 0, 0, 0, 0 }, /* PB27 */
+ /* PB26 */ { 0, 0, 0, 0, 0, 0 }, /* PB26 */
+ /* PB25 */ { 0, 0, 0, 0, 0, 0 }, /* PB25 */
+ /* PB24 */ { 0, 0, 0, 0, 0, 0 }, /* PB24 */
+ /* PB23 */ { 0, 0, 0, 0, 0, 0 }, /* PB23 */
+ /* PB22 */ { 0, 0, 0, 0, 0, 0 }, /* PB22 */
+ /* PB21 */ { 0, 0, 0, 0, 0, 0 }, /* PB21 */
+ /* PB20 */ { 0, 0, 0, 0, 0, 0 }, /* PB20 */
+ /* PB19 */ { 0, 0, 0, 0, 0, 0 }, /* PB19 */
+ /* PB18 */ { 0, 0, 0, 0, 0, 0 }, /* PB18 */
+ /* PB17 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB16 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB15 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB14 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB13 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB12 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB11 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB10 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB9 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB8 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB7 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB6 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB5 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB4 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB3 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB2 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB1 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PB0 */ { 0, 0, 0, 0, 0, 0 } /* non-existent */
+ },
+
+ /* Port C */
+ { /* conf ppar psor pdir podr pdat */
+ /* PC31 */ { 0, 0, 0, 0, 0, 0 }, /* PC31 */
+ /* PC30 */ { 0, 0, 0, 0, 0, 0 }, /* PC30 */
+ /* PC29 */ { 0, 0, 0, 0, 0, 0 }, /* PC29 */
+ /* PC28 */ { 0, 0, 0, 0, 0, 0 }, /* PC28 */
+ /* PC27 */ { 0, 0, 0, 0, 0, 0 }, /* PC27 */
+ /* PC26 */ { 0, 0, 0, 0, 0, 0 }, /* PC26 */
+ /* PC25 */ { 1, 1, 0, 0, 0, 0 }, /* SCC4 RxClk */
+ /* PC24 */ { 1, 1, 0, 0, 0, 0 }, /* SCC4 TxClk */
+ /* PC23 */ { 0, 0, 0, 0, 0, 0 }, /* PC23 */
+ /* PC22 */ { 0, 0, 0, 0, 0, 0 }, /* PC22 */
+ /* PC21 */ { 0, 0, 0, 0, 0, 0 }, /* PC21 */
+ /* PC20 */ { 0, 0, 0, 0, 0, 0 }, /* PC20 */
+ /* PC19 */ { 0, 0, 0, 0, 0, 0 }, /* PC19 */
+ /* PC18 */ { 0, 0, 0, 0, 0, 0 }, /* PC18 */
+ /* PC17 */ { 0, 0, 0, 0, 0, 0 }, /* PC17 */
+ /* PC16 */ { 0, 0, 0, 0, 0, 0 }, /* PC16 */
+ /* PC15 */ { 0, 0, 0, 0, 0, 0 }, /* PC15 */
+ /* PC14 */ { 0, 0, 0, 0, 0, 0 }, /* PC14 */
+ /* PC13 */ { 0, 0, 0, 0, 0, 0 }, /* PC13 */
+ /* PC12 */ { 0, 0, 0, 0, 0, 0 }, /* PC12 */
+ /* PC11 */ { 0, 0, 0, 0, 0, 0 }, /* PC11 */
+ /* PC10 */ { 0, 0, 0, 0, 0, 0 }, /* PC10 */
+ /* PC9 */ { 1, 1, 0, 0, 0, 0 }, /* SCC4: CTS */
+ /* PC8 */ { 1, 1, 0, 0, 0, 0 }, /* SCC4: CD */
+ /* PC7 */ { 0, 0, 0, 0, 0, 0 }, /* PC7 */
+ /* PC6 */ { 0, 0, 0, 0, 0, 0 }, /* PC6 */
+ /* PC5 */ { 0, 0, 0, 0, 0, 0 }, /* PC5 */
+ /* PC4 */ { 0, 0, 0, 0, 0, 0 }, /* PC4 */
+ /* PC3 */ { 0, 0, 0, 0, 0, 0 }, /* PC3 */
+ /* PC2 */ { 0, 0, 0, 0, 0, 0 }, /* PC2 */
+ /* PC1 */ { 0, 0, 0, 0, 0, 0 }, /* PC1 */
+ /* PC0 */ { 0, 0, 0, 0, 0, 0 }, /* PC0 */
+ },
+
+ /* Port D */
+ { /* conf ppar psor pdir podr pdat */
+ /* PD31 */ { 0, 0, 0, 0, 0, 0 }, /* PD31 */
+ /* PD30 */ { 0, 0, 0, 0, 0, 0 }, /* PD30 */
+ /* PD29 */ { 0, 0, 0, 0, 0, 0 }, /* PD29 */
+ /* PD28 */ { 0, 0, 0, 0, 0, 0 }, /* PD28 */
+ /* PD27 */ { 0, 0, 0, 0, 0, 0 }, /* PD27 */
+ /* PD26 */ { 0, 0, 0, 0, 0, 0 }, /* PD26 */
+ /* PD25 */ { 0, 0, 0, 0, 0, 0 }, /* PD25 */
+ /* PD24 */ { 0, 0, 0, 0, 0, 0 }, /* PD24 */
+ /* PD23 */ { 0, 0, 0, 0, 0, 0 }, /* PD23 */
+ /* PD22 */ { 1, 1, 0, 0, 0, 0 }, /* SCC4: RXD */
+ /* PD21 */ { 1, 1, 0, 1, 0, 0 }, /* SCC4: TXD */
+ /* PD20 */ { 1, 1, 0, 1, 0, 0 }, /* SCC4: RTS */
+ /* PD19 */ { 0, 0, 0, 0, 0, 0 }, /* PD19 */
+ /* PD18 */ { 0, 0, 0, 0, 0, 0 }, /* PD18 */
+ /* PD17 */ { 0, 0, 0, 0, 0, 0 }, /* PD17 */
+ /* PD16 */ { 0, 0, 0, 0, 0, 0 }, /* PD16 */
+#if defined(CONFIG_HARD_I2C)
+ /* PD15 */ { 1, 1, 1, 0, 1, 0 }, /* I2C SDA */
+ /* PD14 */ { 1, 1, 1, 0, 1, 0 }, /* I2C SCL */
+#else
+ /* PD15 */ { 1, 0, 0, 0, 1, 1 }, /* PD15 */
+ /* PD14 */ { 1, 0, 0, 1, 1, 1 }, /* PD14 */
+#endif
+ /* PD13 */ { 0, 0, 0, 0, 0, 0 }, /* PD13 */
+ /* PD12 */ { 0, 0, 0, 0, 0, 0 }, /* PD12 */
+ /* PD11 */ { 0, 0, 0, 0, 0, 0 }, /* PD11 */
+ /* PD10 */ { 0, 0, 0, 0, 0, 0 }, /* PD10 */
+ /* PD9 */ { 0, 0, 0, 0, 0, 0 }, /* PD9 */
+ /* PD8 */ { 0, 0, 0, 0, 0, 0 }, /* PD8 */
+ /* PD7 */ { 0, 0, 0, 0, 0, 0 }, /* PD7 */
+ /* PD6 */ { 0, 0, 0, 0, 0, 0 }, /* PD6 */
+ /* PD5 */ { 0, 0, 0, 0, 0, 0 }, /* PD5 */
+ /* PD4 */ { 0, 0, 0, 0, 0, 0 }, /* PD4 */
+ /* PD3 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PD2 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PD1 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */
+ /* PD0 */ { 0, 0, 0, 0, 0, 0 } /* non-existent */
+ }
+};
+
+/* Try SDRAM initialization with P/LSDMR=sdmr and ORx=orx
+ *
+ * This routine performs standard 8260 initialization sequence
+ * and calculates the available memory size. It may be called
+ * several times to try different SDRAM configurations on both
+ * 60x and local buses.
+ */
+static long int try_init (volatile memctl8260_t * memctl, ulong sdmr,
+ ulong orx, volatile uchar * base)
+{
+ volatile uchar c = 0xff;
+ volatile uint *sdmr_ptr;
+ volatile uint *orx_ptr;
+ ulong maxsize, size;
+ int i;
+
+ /* We must be able to test a location outsize the maximum legal size
+ * to find out THAT we are outside; but this address still has to be
+ * mapped by the controller. That means, that the initial mapping has
+ * to be (at least) twice as large as the maximum expected size.
+ */
+ maxsize = (1 + (~orx | 0x7fff))/* / 2*/;
+
+ sdmr_ptr = &memctl->memc_psdmr;
+ orx_ptr = &memctl->memc_or1;
+
+ *orx_ptr = orx;
+
+ /*
+ * Quote from 8260 UM (10.4.2 SDRAM Power-On Initialization, 10-35):
+ *
+ * "At system reset, initialization software must set up the
+ * programmable parameters in the memory controller banks registers
+ * (ORx, BRx, P/LSDMR). After all memory parameters are configured,
+ * system software should execute the following initialization sequence
+ * for each SDRAM device.
+ *
+ * 1. Issue a PRECHARGE-ALL-BANKS command
+ * 2. Issue eight CBR REFRESH commands
+ * 3. Issue a MODE-SET command to initialize the mode register
+ *
+ * The initial commands are executed by setting P/LSDMR[OP] and
+ * accessing the SDRAM with a single-byte transaction."
+ *
+ * The appropriate BRx/ORx registers have already been set when we
+ * get here. The SDRAM can be accessed at the address CONFIG_SYS_SDRAM_BASE.
+ */
+
+ *sdmr_ptr = sdmr | PSDMR_OP_PREA;
+ *base = c;
+
+ *sdmr_ptr = sdmr | PSDMR_OP_CBRR;
+ for (i = 0; i < 8; i++)
+ *base = c;
+
+ *sdmr_ptr = sdmr | PSDMR_OP_MRW;
+ *(base + CONFIG_SYS_MRS_OFFS) = c; /* setting MR on address lines */
+
+ *sdmr_ptr = sdmr | PSDMR_OP_NORM | PSDMR_RFEN;
+ *base = c;
+
+ size = get_ram_size ((long *)base, maxsize);
+ *orx_ptr = orx | ~(size - 1);
+
+ return (size);
+}
+
+phys_size_t initdram (int board_type)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile memctl8260_t *memctl = &immap->im_memctl;
+
+ long psize;
+
+ memctl->memc_psrt = CONFIG_SYS_PSRT;
+ memctl->memc_mptpr = CONFIG_SYS_MPTPR;
+
+#ifndef CONFIG_SYS_RAMBOOT
+ /* 60x SDRAM setup:
+ */
+ psize = try_init (memctl, CONFIG_SYS_PSDMR, CONFIG_SYS_OR1,
+ (uchar *) CONFIG_SYS_SDRAM_BASE);
+#endif /* CONFIG_SYS_RAMBOOT */
+
+ icache_enable ();
+
+ return (psize);
+}
+
+int checkboard(void)
+{
+ puts ("Board: mgcoge\n");
+
+ return 0;
+}
+
+/*
+ * Early board initalization.
+ */
+int board_early_init_r (void)
+{
+ /* setup the UPIOx */
+ out_8((u8 *)(CONFIG_SYS_PIGGY_BASE + 0x02), 0xc0);
+ out_8((u8 *)(CONFIG_SYS_PIGGY_BASE + 0x03), 0x15);
+ return 0;
+}
+
+int hush_init_var (void)
+{
+ ivm_read_eeprom ();
+ return 0;
+}
+
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
+extern int fdt_set_node_and_value (void *blob,
+ char *nodename,
+ char *regname,
+ void *var,
+ int size);
+
+/*
+ * update "memory" property in the blob
+ */
+void ft_blob_update (void *blob, bd_t *bd)
+{
+ ulong memory_data[2] = {0};
+ ulong flash_data[8] = {0};
+
+ memory_data[0] = cpu_to_be32 (bd->bi_memstart);
+ memory_data[1] = cpu_to_be32 (bd->bi_memsize);
+ fdt_set_node_and_value (blob, "/memory", "reg", memory_data,
+ sizeof (memory_data));
+
+ /* update Flash addr, size */
+ flash_data[2] = cpu_to_be32 (CONFIG_SYS_FLASH_BASE);
+ flash_data[3] = cpu_to_be32 (CONFIG_SYS_FLASH_SIZE);
+ flash_data[4] = cpu_to_be32 (5);
+ flash_data[5] = cpu_to_be32 (0);
+ flash_data[6] = cpu_to_be32 (CONFIG_SYS_FLASH_BASE_1);
+ flash_data[7] = cpu_to_be32 (CONFIG_SYS_FLASH_SIZE_1);
+ fdt_set_node_and_value (blob, "/localbus", "ranges", flash_data,
+ sizeof (flash_data));
+ /* MAC addr */
+ fdt_set_node_and_value (blob, "/soc/cpm/ethernet", "mac-address",
+ bd->bi_enetaddr, sizeof (u8) * 6);
+}
+
+void ft_board_setup (void *blob, bd_t *bd)
+{
+ ft_cpu_setup (blob, bd);
+ ft_blob_update (blob, bd);
+}
+#endif /* defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) */
diff --git a/board/keymile/mgcoge/mgcoge_hdlc_enet.c b/board/keymile/mgcoge/mgcoge_hdlc_enet.c
new file mode 100644
index 0000000..34f04f5
--- /dev/null
+++ b/board/keymile/mgcoge/mgcoge_hdlc_enet.c
@@ -0,0 +1,276 @@
+/*
+ * (C) Copyright 2008
+ * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
+ *
+ * Based in part on cpu/mpc8260/ether_scc.c.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+
+#ifdef CONFIG_KEYMILE_HDLC_ENET
+
+#include "../common/keymile_hdlc_enet.h"
+
+char keymile_slot; /* our slot number in the backplane */
+
+/*
+ * Since, except during initialization, ethact is always HDLC ETHERNET
+ * while we're in the driver, just use serial_printf() everywhere for
+ * output. This avoids possible conflicts when netconsole is being
+ * used.
+ */
+#define dprintf(fmt, args...) serial_printf(fmt, ##args)
+
+static int already_inited;
+
+/*
+ * SCC Ethernet Tx and Rx buffer descriptors allocated at the
+ * immr->udata_bd address on Dual-Port RAM
+ * Provide for Double Buffering
+ */
+typedef volatile struct CommonBufferDescriptor {
+ cbd_t txbd; /* Tx BD */
+ cbd_t rxbd[HDLC_PKTBUFSRX]; /* Rx BD */
+} RTXBD;
+
+static RTXBD *rtx;
+
+int keymile_hdlc_enet_init(struct eth_device *, bd_t *);
+void keymile_hdlc_enet_halt(struct eth_device *);
+extern void keymile_hdlc_enet_init_bds(RTXBD *);
+extern void initCachedNumbers(int);
+
+/* Use SCC1 */
+#define CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE
+#define CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK
+#define CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\
+ CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK)
+#define CMXSCR_VALUE (CMXSCR_RS1CS_CLK11|CMXSCR_TS1CS_CLK11)
+#define MGC_PROFF_HDLC PROFF_SCC1
+#define MGC_SCC_HDLC 0 /* Index, not number! */
+
+int keymile_hdlc_enet_init(struct eth_device *dev, bd_t *bis)
+{
+ /* int i; */
+ uint dpr;
+ /* volatile cbd_t *bdp; */
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8260_t *cp = &(im->im_cpm);
+ volatile scc_t *sccp;
+ volatile scc_hdlc_t *hpr;
+ volatile iop8260_t *iop;
+
+ if (already_inited)
+ return 0;
+
+ hpr = (scc_hdlc_t *)(&im->im_dprambase[MGC_PROFF_HDLC]);
+ sccp = (scc_t *)(&im->im_scc[MGC_SCC_HDLC]);
+ iop = &im->im_ioport;
+
+ /*
+ * Disable receive and transmit just in case.
+ */
+ sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ /*
+ * Avoid exhausting DPRAM, which would cause a panic.
+ */
+ if (rtx == NULL) {
+ /* dpr is an offset into dpram */
+ dpr = m8260_cpm_dpalloc(sizeof(RTXBD), 8);
+ rtx = (RTXBD *)&im->im_dprambase[dpr];
+ }
+
+ /* We need the slot number for addressing. */
+ keymile_slot = *(char *)(CONFIG_SYS_SLOT_ID_BASE +
+ CONFIG_SYS_SLOT_ID_OFF) & CONFIG_SYS_SLOT_ID_MASK;
+ /*
+ * Be consistent with the Linux driver and set
+ * only enetaddr[0].
+ *
+ * Always add 1 to the slot number so that
+ * there are no problems with an ethaddr which
+ * is all 0s. This should be acceptable because
+ * a board should never have a slot number of 255,
+ * which is the broadcast address. The HDLC addressing
+ * uses only the slot number.
+ */
+ dev->enetaddr[0] = keymile_slot + 1;
+#ifdef TEST_IT
+ dprintf("slot %d\n", keymile_slot);
+#endif
+
+ /* use pd30, pd31 pins for TXD1, RXD1 respectively */
+ iop->iop_ppard |= (0x80000000 >> 30) | (0x80000000 >> 31);
+ iop->iop_pdird |= (0x80000000 >> 30);
+ iop->iop_psord |= (0x80000000 >> 30);
+
+ /* use pc21 as CLK11 */
+ iop->iop_pparc |= (0x80000000 >> 21);
+ iop->iop_pdirc &= ~(0x80000000 >> 21);
+ iop->iop_psorc &= ~(0x80000000 >> 21);
+
+ /* use pc15 as CTS1 */
+ iop->iop_pparc |= (0x80000000 >> 15);
+ iop->iop_pdirc &= ~(0x80000000 >> 15);
+ iop->iop_psorc &= ~(0x80000000 >> 15);
+
+ /*
+ * SI clock routing
+ * use CLK11
+ * this also connects SCC1 to NMSI
+ */
+ im->im_cpmux.cmx_scr = (im->im_cpmux.cmx_scr & ~CMXSCR_MASK) |
+ CMXSCR_VALUE;
+
+ /* keymile_rxIdx = 0; */
+
+ /*
+ * Initialize function code registers for big-endian.
+ */
+ hpr->sh_genscc.scc_rfcr = CPMFCR_EB;
+ hpr->sh_genscc.scc_tfcr = CPMFCR_EB;
+
+ /*
+ * Set maximum bytes per receive buffer.
+ */
+ hpr->sh_genscc.scc_mrblr = MAX_FRAME_LENGTH;
+
+ /* Setup CRC generator values for HDLC */
+ hpr->sh_cmask = 0x0000F0B8;
+ hpr->sh_cpres = 0x0000FFFF;
+
+ /* Initialize all error counters to 0 */
+ hpr->sh_disfc = 0;
+ hpr->sh_crcec = 0;
+ hpr->sh_abtsc = 0;
+ hpr->sh_nmarc = 0;
+ hpr->sh_retrc = 0;
+
+ /* Set maximum frame length size */
+ hpr->sh_mflr = MAX_FRAME_LENGTH;
+
+ /* set to 1 for per frame processing change later if needed */
+ hpr->sh_rfthr = 1;
+
+ hpr->sh_hmask = 0xff;
+
+ hpr->sh_haddr2 = SET_HDLC_UUA(keymile_slot);
+ hpr->sh_haddr3 = hpr->sh_haddr2;
+ hpr->sh_haddr4 = hpr->sh_haddr2;
+ /* broadcast */
+ hpr->sh_haddr1 = HDLC_BCAST;
+
+ hpr->sh_genscc.scc_rbase = (unsigned int) &rtx->rxbd[0];
+ hpr->sh_genscc.scc_tbase = (unsigned int) &rtx->txbd;
+
+#if 0
+ /*
+ * Initialize the buffer descriptors.
+ */
+ bdp = &rtx->txbd;
+ bdp->cbd_sc = 0;
+ bdp->cbd_bufaddr = 0;
+ bdp->cbd_sc = BD_SC_WRAP;
+
+ /*
+ * Setup RX packet buffers, aligned correctly.
+ * Borrowed from net/net.c.
+ */
+ MyRxPackets[0] = &MyPktBuf[0] + (PKTALIGN - 1);
+ MyRxPackets[0] -= (ulong)MyRxPackets[0] % PKTALIGN;
+ for (i = 1; i < HDLC_PKTBUFSRX; i++)
+ MyRxPackets[i] = MyRxPackets[0] + i * PKT_MAXBLR_SIZE;
+
+ bdp = &rtx->rxbd[0];
+ for (i = 0; i < HDLC_PKTBUFSRX; i++) {
+ bdp->cbd_sc = BD_SC_EMPTY;
+ /* Leave space at the start for INET header. */
+ bdp->cbd_bufaddr = (unsigned int)(MyRxPackets[i] +
+ INET_HDR_ALIGN);
+ bdp++;
+ }
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+#else
+ keymile_hdlc_enet_init_bds(rtx);
+#endif
+
+ /* Let's re-initialize the channel now. We have to do it later
+ * than the manual describes because we have just now finished
+ * the BD initialization.
+ */
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK,
+ 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+
+ sccp->scc_gsmrl = SCC_GSMRL_MODE_HDLC;
+ /* CTSS=1 */
+ sccp->scc_gsmrh = SCC_GSMRH_CTSS;
+ /* NOF=0, RTE=1, DRT=0, BUS=1 */
+ sccp->scc_psmr = ((0x8000 >> 6) | (0x8000 >> 10));
+
+/* loopback for local testing */
+#ifdef GJTEST
+ dprintf("LOOPBACK!\n");
+ sccp->scc_gsmrl |= SCC_GSMRL_DIAG_LOOP;
+#endif
+
+ /*
+ * Disable all interrupts and clear all pending
+ * events.
+ */
+ sccp->scc_sccm = 0;
+ sccp->scc_scce = 0xffff;
+
+ /*
+ * And last, enable the transmit and receive processing.
+ */
+ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ dprintf("%s: HDLC ENET Version 0.3 on SCC%d\n", dev->name,
+ MGC_SCC_HDLC + 1);
+
+ /*
+ * We may not get an ARP packet because ARP was already done on
+ * a different interface, so initialize the cached values now.
+ */
+ initCachedNumbers(1);
+
+ already_inited = 1;
+
+ return 0;
+}
+
+void keymile_hdlc_enet_halt(struct eth_device *dev)
+{
+#if 0 /* just return, but keep this for reference */
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ /* maybe should do a graceful stop here? */
+ immr->im_scc[MGC_SCC_HDLC].scc_gsmrl &=
+ ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+}
+
+#endif /* CONFIG_MGCOGE_HDLC_ENET */
diff --git a/board/keymile/mgsuvd/Makefile b/board/keymile/mgsuvd/Makefile
new file mode 100644
index 0000000..2c5732d
--- /dev/null
+++ b/board/keymile/mgsuvd/Makefile
@@ -0,0 +1,48 @@
+#
+# (C) Copyright 2007
+# Heiko Schocher, DENX Software Engineering, hs@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
+ifneq ($(OBJTREE),$(SRCTREE))
+$(shell mkdir -p $(obj)../common)
+endif
+
+LIB = $(obj)lib$(BOARD).a
+
+COBJS = $(BOARD).o ../common/common.o ../common/keymile_hdlc_enet.o \
+ mgsuvd_hdlc_enet.o
+
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+SOBJS := $(addprefix $(obj),$(SOBJS))
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/keymile/mgsuvd/config.mk b/board/keymile/mgsuvd/config.mk
new file mode 100644
index 0000000..8625cea
--- /dev/null
+++ b/board/keymile/mgsuvd/config.mk
@@ -0,0 +1,28 @@
+#
+# (C) Copyright 2007
+# Heiko Schocher, DENX Software Engineering, hs@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
+#
+
+#
+# mgsvud boards
+#
+
+TEXT_BASE = 0xf0000000
diff --git a/board/keymile/mgsuvd/mgsuvd.c b/board/keymile/mgsuvd/mgsuvd.c
new file mode 100644
index 0000000..3726acf
--- /dev/null
+++ b/board/keymile/mgsuvd/mgsuvd.c
@@ -0,0 +1,204 @@
+/*
+ * (C) Copyright 2007
+ * Heiko Schocher, DENX Software Engineering, hs@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 <common.h>
+#include <mpc8xx.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#endif
+
+extern int ivm_read_eeprom (void);
+
+DECLARE_GLOBAL_DATA_PTR;
+
+const uint sdram_table[] =
+{
+ 0x0f07fc04, 0x0ffffc04, 0x00bdfc04, 0x0ff77c00,
+ 0x1ffffc05, 0xfffffc04, 0xfffffc04, 0xfffffc04,
+ /* 0x08 Burst Read */
+ 0x0f07fc04, 0x0ffffc04, 0x00bdfc04, 0x00fffc00,
+ 0x00fffc00, 0x00fffc00, 0x0ff77c00, 0x1ffffc05,
+ /* 0x10 Load mode register */
+ 0x0ffffc34, 0x0ff57c04, 0x0ffffc04, 0x1ffffc05,
+ 0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04,
+ /* 0x18 Single Write */
+ 0x0f07fc04, 0x0ffffc00, 0x00bd7c04, 0x0ffffc04,
+ 0x0ff77c04, 0x1ffffc05, 0xfffffc04, 0xfffffc04,
+ /* 0x20 Burst Write */
+ 0x0f07fc04, 0x0ffffc00, 0x00bd7c00, 0x00fffc00,
+ 0x00fffc00, 0x00fffc04, 0x0ffffc04, 0x0ff77c04,
+ 0x1ffffc05, 0xfffffc04, 0xfffffc04, 0xfffffc04,
+ 0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04,
+ /* 0x30 Precharge all and Refresh */
+ 0x0ff77c04, 0x0ffffc04, 0x0ff5fc84, 0x0ffffc04,
+ 0x0ffffc04, 0x0ffffc84, 0x1ffffc05, 0xfffffc04,
+ 0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04,
+ /* 0x3C Exception */
+ 0x7ffffc04, 0xfffffc07, 0xfffffc04, 0xfffffc04,
+};
+
+int checkboard (void)
+{
+ puts ("Board: Keymile mgsuvd\n");
+ return (0);
+}
+
+phys_size_t initdram (int board_type)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ long int size;
+
+ upmconfig (UPMB, (uint *) sdram_table,
+ sizeof (sdram_table) / sizeof (uint));
+
+ /*
+ * Preliminary prescaler for refresh (depends on number of
+ * banks): This value is selected for four cycles every 62.4 us
+ * with two SDRAM banks or four cycles every 31.2 us with one
+ * bank. It will be adjusted after memory sizing.
+ */
+ memctl->memc_mptpr = CONFIG_SYS_MPTPR;
+
+ /*
+ * The following value is used as an address (i.e. opcode) for
+ * the LOAD MODE REGISTER COMMAND during SDRAM initialisation. If
+ * the port size is 32bit the SDRAM does NOT "see" the lower two
+ * address lines, i.e. mar=0x00000088 -> opcode=0x00000022 for
+ * MICRON SDRAMs:
+ * -> 0 00 010 0 010
+ * | | | | +- Burst Length = 4
+ * | | | +----- Burst Type = Sequential
+ * | | +------- CAS Latency = 2
+ * | +----------- Operating Mode = Standard
+ * +-------------- Write Burst Mode = Programmed Burst Length
+ */
+ memctl->memc_mar = CONFIG_SYS_MAR;
+
+ /*
+ * Map controller banks 1 to the SDRAM banks 1 at
+ * preliminary addresses - these have to be modified after the
+ * SDRAM size has been determined.
+ */
+ memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM;
+ memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM;
+
+ memctl->memc_mbmr = CONFIG_SYS_MBMR & (~(MBMR_PTBE)); /* no refresh yet */
+
+ udelay (200);
+
+ /* perform SDRAM initializsation sequence */
+
+ memctl->memc_mcr = 0x80802830; /* SDRAM bank 0 */
+ udelay (1);
+ memctl->memc_mcr = 0x80802110; /* SDRAM bank 0 - execute twice */
+ udelay (1);
+
+ memctl->memc_mbmr |= MBMR_PTBE; /* enable refresh */
+
+ udelay (1000);
+
+ /*
+ * Check Bank 0 Memory Size for re-configuration
+ *
+ */
+ size = get_ram_size(SDRAM_BASE1_PRELIM, SDRAM_MAX_SIZE);
+
+ udelay (1000);
+
+ debug ("SDRAM Bank 0: %ld MB\n", size >> 20);
+
+ return (size);
+}
+
+/*
+ * Early board initalization.
+ */
+int board_early_init_r(void)
+{
+ /* setup the UPIOx */
+ out_8((u8 *)(CONFIG_SYS_PIGGY_BASE + 0x02), 0xc0);
+ out_8((u8 *)(CONFIG_SYS_PIGGY_BASE + 0x03), 0x35);
+ return 0;
+}
+
+int hush_init_var (void)
+{
+ ivm_read_eeprom ();
+ return 0;
+}
+
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
+extern int fdt_set_node_and_value (void *blob,
+ char *nodename,
+ char *regname,
+ void *var,
+ int size);
+
+/*
+ * update "memory" property in the blob
+ */
+void ft_blob_update (void *blob, bd_t *bd)
+{
+ ulong brg_data[1] = {0};
+ ulong memory_data[2] = {0};
+ ulong flash_data[4] = {0};
+
+ memory_data[0] = cpu_to_be32 (bd->bi_memstart);
+ memory_data[1] = cpu_to_be32 (bd->bi_memsize);
+ fdt_set_node_and_value (blob, "/memory", "reg", memory_data,
+ sizeof (memory_data));
+
+ flash_data[2] = cpu_to_be32 (bd->bi_flashstart);
+ flash_data[3] = cpu_to_be32 (bd->bi_flashsize);
+ fdt_set_node_and_value (blob, "/localbus", "ranges", flash_data,
+ sizeof (flash_data));
+
+ /* BRG */
+ brg_data[0] = cpu_to_be32 (bd->bi_busfreq);
+ fdt_set_node_and_value (blob, "/soc/cpm", "brg-frequency", brg_data,
+ sizeof (brg_data));
+
+ /* MAC adr */
+ fdt_set_node_and_value (blob, "/soc/cpm/ethernet", "mac-address",
+ bd->bi_enetaddr, sizeof (u8) * 6);
+}
+
+void ft_board_setup(void *blob, bd_t *bd)
+{
+ ft_cpu_setup (blob, bd);
+ ft_blob_update (blob, bd);
+}
+#endif /* defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) */
+
+int i2c_soft_read_pin (void)
+{
+ int val;
+
+ *(unsigned short *)(I2C_BASE_DIR) &= ~SDA_CONF;
+ udelay(1);
+ val = *(unsigned char *)(I2C_BASE_PORT);
+
+ return ((val & SDA_BIT) == SDA_BIT);
+}
diff --git a/board/keymile/mgsuvd/mgsuvd_hdlc_enet.c b/board/keymile/mgsuvd/mgsuvd_hdlc_enet.c
new file mode 100644
index 0000000..9b93131
--- /dev/null
+++ b/board/keymile/mgsuvd/mgsuvd_hdlc_enet.c
@@ -0,0 +1,278 @@
+/*
+ * (C) Copyright 2008
+ * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
+ *
+ * Based in part on cpu/mpc8xx/scc.c.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h> /* commproc.h is included here */
+#include <malloc.h>
+#include <net.h>
+
+#ifdef CONFIG_KEYMILE_HDLC_ENET
+
+#include "../common/keymile_hdlc_enet.h"
+
+char keymile_slot; /* our slot number in the backplane */
+
+/*
+ * Since, except during initialization, ethact is always HDLC ETHERNET
+ * while we're in the driver, just use serial_printf() everywhere for
+ * output. This avoids possible conflicts when netconsole is being
+ * used.
+ */
+#define dprintf(fmt, args...) serial_printf(fmt, ##args)
+
+static int already_inited;
+
+/*
+ * SCC Ethernet Tx and Rx buffer descriptors allocated at the
+ * immr->udata_bd address on Dual-Port RAM
+ * Provide for Double Buffering
+ */
+typedef volatile struct CommonBufferDescriptor {
+ cbd_t txbd; /* Tx BD */
+ cbd_t rxbd[HDLC_PKTBUFSRX]; /* Rx BD */
+} RTXBD;
+
+static RTXBD *rtx;
+
+int keymile_hdlc_enet_init(struct eth_device *, bd_t *);
+void keymile_hdlc_enet_halt(struct eth_device *);
+extern void keymile_hdlc_enet_init_bds(RTXBD *);
+extern void initCachedNumbers(int);
+
+/* Use SCC4 */
+#define MGS_CPM_CR_HDLC CPM_CR_CH_SCC4
+#define MGS_PROFF_HDLC PROFF_SCC4
+#define MGS_SCC_HDLC 3 /* Index, not number! */
+
+int keymile_hdlc_enet_init(struct eth_device *dev, bd_t *bis)
+{
+ /* int i; */
+ /* volatile cbd_t *bdp; */
+ volatile cpm8xx_t *cp;
+ volatile scc_t *sccp;
+ volatile hdlc_pram_t *hpr;
+ volatile iop8xx_t *iop;
+
+ if (already_inited)
+ return 0;
+
+ cp = (cpm8xx_t *)&(((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm);
+ hpr = (hdlc_pram_t *)(&cp->cp_dparam[MGS_PROFF_HDLC]);
+ sccp = (volatile scc_t *)(&cp->cp_scc[MGS_SCC_HDLC]);
+ iop = (iop8xx_t *)&(((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport);
+
+ /*
+ * Disable receive and transmit just in case.
+ */
+ sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+#ifndef CONFIG_SYS_ALLOC_DPRAM
+#error "CONFIG_SYS_ALLOC_DPRAM must be defined"
+#else
+ /*
+ * Avoid exhausting DPRAM, which would cause a panic.
+ * Actually this isn't really necessary, but leave it here
+ * for safety's sake.
+ */
+ if (rtx == NULL) {
+ rtx = (RTXBD *) (cp->cp_dpmem +
+ dpram_alloc_align(sizeof(RTXBD), 8));
+ if (rtx == (RTXBD *)CPM_DP_NOSPACE)
+ return -1;
+ memset((void *)rtx, 0, sizeof(RTXBD));
+ }
+#endif /* !CONFIG_SYS_ALLOC_DPRAM */
+
+ /* We need the slot number for addressing. */
+ keymile_slot = *(char *)(CONFIG_SYS_SLOT_ID_BASE +
+ CONFIG_SYS_SLOT_ID_OFF) & CONFIG_SYS_SLOT_ID_MASK;
+ /*
+ * Be consistent with the Linux driver and set
+ * only enetaddr[0].
+ *
+ * Always add 1 to the slot number so that
+ * there are no problems with an ethaddr which
+ * is all 0s. This should be acceptable because
+ * a board should never have a slot number of 255,
+ * which is the broadcast address. The HDLC addressing
+ * uses only the slot number.
+ */
+ dev->enetaddr[0] = keymile_slot + 1;
+
+#ifdef TEST_IT
+ dprintf("slot %d\n", keymile_slot);
+#endif
+
+ /* use pa8, pa9 pins for TXD4, RXD4 respectively */
+ iop->iop_papar |= ((0x8000 >> 8) | (0x8000 >> 9));
+ iop->iop_padir &= ~((0x8000 >> 8) | (0x8000 >> 9));
+ iop->iop_paodr &= ~((0x8000 >> 8) | (0x8000 >> 9));
+
+ /* also use pa0 as CLK8 */
+ iop->iop_papar |= 0x8000;
+ iop->iop_padir &= ~0x8000;
+ iop->iop_paodr &= ~0x8000;
+
+ /* use pc5 as CTS4 */
+ iop->iop_pcpar &= ~(0x8000 >> 5);
+ iop->iop_pcdir &= ~(0x8000 >> 5);
+ iop->iop_pcso |= (0x8000 >> 5);
+
+ /*
+ * SI clock routing
+ * use CLK8
+ * this also connects SCC4 to NMSI
+ */
+ cp->cp_sicr = (cp->cp_sicr & ~0xff000000) | 0x3f000000;
+
+ /* keymile_rxIdx = 0; */
+
+ /*
+ * Initialize function code registers for big-endian.
+ */
+ hpr->rfcr = SCC_EB;
+ hpr->tfcr = SCC_EB;
+
+ /*
+ * Set maximum bytes per receive buffer.
+ */
+ hpr->mrblr = MAX_FRAME_LENGTH;
+
+ /* Setup CRC generator values for HDLC */
+ hpr->c_mask = 0x0000F0B8;
+ hpr->c_pres = 0x0000FFFF;
+
+ /* Initialize all error counters to 0 */
+ hpr->disfc = 0;
+ hpr->crcec = 0;
+ hpr->abtsc = 0;
+ hpr->nmarc = 0;
+ hpr->retrc = 0;
+
+ /* Set maximum frame length size */
+ hpr->mflr = MAX_FRAME_LENGTH;
+
+ /* set to 1 for per frame processing change later if needed */
+ hpr->rfthr = 1;
+
+ hpr->hmask = 0xff;
+
+ hpr->haddr2 = SET_HDLC_UUA(keymile_slot);
+ hpr->haddr3 = hpr->haddr2;
+ hpr->haddr4 = hpr->haddr2;
+ /* broadcast */
+ hpr->haddr1 = HDLC_BCAST;
+
+ hpr->rbase = (unsigned int) &rtx->rxbd[0];
+ hpr->tbase = (unsigned int) &rtx->txbd;
+
+#if 0
+ /*
+ * Initialize the buffer descriptors.
+ */
+ bdp = &rtx->txbd;
+ bdp->cbd_sc = 0;
+ bdp->cbd_bufaddr = 0;
+ bdp->cbd_sc = BD_SC_WRAP;
+
+ /*
+ * Setup RX packet buffers, aligned correctly.
+ * Borrowed from net/net.c.
+ */
+ MyRxPackets[0] = &MyPktBuf[0] + (PKTALIGN - 1);
+ MyRxPackets[0] -= (ulong)MyRxPackets[0] % PKTALIGN;
+ for (i = 1; i < HDLC_PKTBUFSRX; i++)
+ MyRxPackets[i] = MyRxPackets[0] + i * PKT_MAXBLR_SIZE;
+
+ bdp = &rtx->rxbd[0];
+ for (i = 0; i < HDLC_PKTBUFSRX; i++) {
+ bdp->cbd_sc = BD_SC_EMPTY;
+ /* Leave space at the start for INET header. */
+ bdp->cbd_bufaddr = (unsigned int)(MyRxPackets[i] +
+ INET_HDR_ALIGN);
+ bdp++;
+ }
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+#else
+ keymile_hdlc_enet_init_bds(rtx);
+#endif
+
+ /* Let's re-initialize the channel now. We have to do it later
+ * than the manual describes because we have just now finished
+ * the BD initialization.
+ */
+ cp->cp_cpcr = mk_cr_cmd(MGS_CPM_CR_HDLC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+
+ sccp->scc_gsmrl = SCC_GSMRL_MODE_HDLC;
+ /* CTSS=1 */
+ sccp->scc_gsmrh = SCC_GSMRH_CTSS;
+ /* NOF=0, RTE=1, DRT=0, BUS=1 */
+ sccp->scc_psmr = ((0x8000 >> 6) | (0x8000 >> 10));
+
+/* loopback for local testing */
+#ifdef GJTEST
+ dprintf("LOOPBACK!\n");
+ sccp->scc_gsmrl |= SCC_GSMRL_DIAG_LOOP;
+#endif
+
+ /*
+ * Disable all interrupts and clear all pending
+ * events.
+ */
+ sccp->scc_sccm = 0;
+ sccp->scc_scce = 0xffff;
+
+ /*
+ * And last, enable the transmit and receive processing.
+ */
+ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ dprintf("%s: HDLC ENET Version 0.3 on SCC%d\n", dev->name,
+ MGS_SCC_HDLC + 1);
+
+ /*
+ * We may not get an ARP packet because ARP was already done on
+ * a different interface, so initialize the cached values now.
+ */
+ initCachedNumbers(1);
+
+ already_inited = 1;
+
+ return 0;
+}
+
+void keymile_hdlc_enet_halt(struct eth_device *dev)
+{
+#if 0 /* just return, but keep this for reference */
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ /* maybe should do a graceful stop here? */
+ immr->im_cpm.cp_scc[MGS_SCC_HDLC].scc_gsmrl &=
+ ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+}
+
+#endif /* CONFIG_KEYMILE_HDLC_ENET */
diff --git a/board/keymile/mgsuvd/u-boot.lds b/board/keymile/mgsuvd/u-boot.lds
new file mode 100644
index 0000000..5af36c9
--- /dev/null
+++ b/board/keymile/mgsuvd/u-boot.lds
@@ -0,0 +1,144 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+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 :
+ {
+ /* WARNING - the following is hand-optimized to fit within */
+ /* the sector layout of our flash chips! XXX FIXME XXX */
+
+ cpu/mpc8xx/start.o (.text)
+ cpu/mpc8xx/traps.o (.text)
+ common/dlmalloc.o (.text)
+ lib_ppc/ppcstring.o (.text)
+ lib_generic/vsprintf.o (.text)
+ lib_generic/crc32.o (.text)
+ lib_generic/zlib.o (.text)
+ lib_ppc/cache.o (.text)
+ lib_ppc/time.o (.text)
+
+ . = DEFINED(env_offset) ? env_offset : .;
+ common/env_embedded.o (.ppcenv)
+
+ *(.text)
+ *(.fixup)
+ *(.got1)
+ }
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata1)
+ *(.rodata.str1.4)
+ *(.eh_frame)
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x00FF) & 0xFFFFFF00;
+ _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(256);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(256);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}