summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Jennejohn <garyj@denx.de>2008-11-09 12:36:15 +0100
committerWolfgang Denk <wd@denx.de>2008-12-07 01:33:52 +0100
commit135f5534538bb8ea4f38a7030da12187d22ef7e0 (patch)
tree8cc5fc64e76a3e386b4c3a5cbc299c717b306903
parent1cb82a9207a550557399eabc7fe47f21bbd9ddf8 (diff)
keymile add the common parts of the HDLC driver
This implements the ICN protocol used across the backplane and is needed by all the keymile boards. Signed-off-by: Gary Jennejohn <garyj@denx.de>
-rw-r--r--board/keymile/common/keymile_hdlc_enet.c620
-rw-r--r--board/keymile/common/keymile_hdlc_enet.h129
2 files changed, 749 insertions, 0 deletions
diff --git a/board/keymile/common/keymile_hdlc_enet.c b/board/keymile/common/keymile_hdlc_enet.c
new file mode 100644
index 000000000..141371b8f
--- /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 000000000..965bd5a4b
--- /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_ */