summaryrefslogtreecommitdiff
path: root/cpu/coldfire/fec.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/coldfire/fec.c')
-rw-r--r--cpu/coldfire/fec.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/cpu/coldfire/fec.c b/cpu/coldfire/fec.c
new file mode 100644
index 0000000..53a93c1
--- /dev/null
+++ b/cpu/coldfire/fec.c
@@ -0,0 +1,300 @@
+/*
+ * (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
+ */
+
+#include <common.h>
+#include <commproc.h>
+#include <net.h>
+#include <command.h>
+
+
+
+/**************************************************************
+ *
+ * FEC Ethernet Initialization Routine
+ *
+ *************************************************************/
+
+#define FEC_ECNTRL_ETHER_EN 0x00000002
+#define FEC_ECNTRL_RESET 0x00000001
+
+#define FEC_RCNTRL_BC_REJ 0x00000010
+#define FEC_RCNTRL_PROM 0x00000008
+#define FEC_RCNTRL_MII_MODE 0x00000004
+#define FEC_RCNTRL_DRT 0x00000002
+#define FEC_RCNTRL_LOOP 0x00000001
+
+#define FEC_TCNTRL_FDEN 0x00000004
+#define FEC_TCNTRL_HBC 0x00000002
+#define FEC_TCNTRL_GTS 0x00000001
+
+#define FEC_RESET_DELAY 50000
+
+
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH 1520
+
+#define TX_BUF_CNT 2
+
+#define TOUT_LOOP 100
+
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+#define PKT_MAXBLR_SIZE 1520
+
+
+
+#ifdef CONFIG_M5272
+#define FEC_ADDR 0x10000840
+#endif
+#ifdef CONFIG_M5282
+#define FEC_ADDR 0x40001000
+#endif
+
+#undef ET_DEBUG
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(FEC_ENET)
+
+
+
+static char txbuf[DBUF_LENGTH];
+
+static uint rxIdx; /* index of the current RX buffer */
+static uint txIdx; /* index of the current TX buffer */
+
+/*
+ * FEC 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 rxbd[PKTBUFSRX]; /* Rx BD */
+ cbd_t txbd[TX_BUF_CNT]; /* Tx BD */
+} RTXBD;
+
+static RTXBD *rtx = 0x380000;
+
+
+int eth_send(volatile void *packet, int length)
+{
+ int j, rc;
+ volatile fec_t *fecp = FEC_ADDR;
+
+ /* section 16.9.23.3
+ * Wait for ready
+ */
+ j = 0;
+ while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+ udelay(1);
+ j++;
+ }
+ if (j>=TOUT_LOOP) {
+ printf("TX not ready\n");
+ }
+
+ rtx->txbd[txIdx].cbd_bufaddr = (uint)packet;
+ rtx->txbd[txIdx].cbd_datlen = length;
+ rtx->txbd[txIdx].cbd_sc |= BD_ENET_TX_READY | BD_ENET_TX_LAST;
+
+ /* Activate transmit Buffer Descriptor polling */
+ fecp->fec_x_des_active = 0x01000000; /* Descriptor polling active */
+
+ j = 0;
+ while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+ udelay(1);
+ j++;
+ }
+ if (j>=TOUT_LOOP) {
+ printf("TX timeout\n");
+ }
+#ifdef ET_DEBUG
+ printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n",
+ __FILE__,__LINE__,__FUNCTION__,j,rtx->txbd[txIdx].cbd_sc,
+ (rtx->txbd[txIdx].cbd_sc & 0x003C)>>2);
+#endif
+ /* return only status bits */;
+ rc = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS);
+
+ txIdx = (txIdx + 1) % TX_BUF_CNT;
+
+ return rc;
+}
+
+int eth_rx(void)
+{
+ int length;
+ volatile fec_t *fecp = FEC_ADDR;
+
+ for (;;)
+ {
+ /* section 16.9.23.2 */
+ if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ length = rtx->rxbd[rxIdx].cbd_datlen;
+
+ if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) {
+#ifdef ET_DEBUG
+ printf("%s[%d] err: %x\n",
+ __FUNCTION__,__LINE__,rtx->rxbd[rxIdx].cbd_sc);
+#endif
+ } else {
+ /* Pass the packet up to the protocol layers. */
+ NetReceive(NetRxPackets[rxIdx], length - 4);
+ }
+
+ /* Give the buffer back to the FEC. */
+ rtx->rxbd[rxIdx].cbd_datlen = 0;
+
+ /* wrap around buffer index when necessary */
+ if ((rxIdx + 1) >= PKTBUFSRX) {
+ rtx->rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+ rxIdx = 0;
+ } else {
+ rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+ rxIdx++;
+ }
+
+ /* Try to fill Buffer Descriptors */
+ fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
+ }
+
+ return length;
+}
+
+
+int eth_init (bd_t * bd)
+{
+
+ int i;
+ volatile fec_t *fecp = FEC_ADDR;
+
+ /* Whack a reset.
+ * A delay is required between a reset of the FEC block and
+ * initialization of other FEC registers because the reset takes
+ * some time to complete. If you don't delay, subsequent writes
+ * to FEC registers might get killed by the reset routine which is
+ * still in progress.
+ */
+
+ fecp->fec_ecntrl = FEC_ECNTRL_RESET;
+ for (i = 0;
+ (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+ ++i) {
+ udelay (1);
+ }
+ if (i == FEC_RESET_DELAY) {
+ printf ("FEC_RESET_DELAY timeout\n");
+ return 0;
+ }
+
+ /* We use strictly polling mode only
+ */
+ fecp->fec_imask = 0;
+
+ /* Clear any pending interrupt */
+ fecp->fec_ievent = 0xffffffff;
+
+ /* Set station address */
+#define ea bd->bi_enetaddr
+ fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) |
+ (ea[2] << 8) | (ea[3] ) ;
+ fecp->fec_addr_high = (ea[4] << 24) | (ea[5] << 16 ) ;
+#undef ea
+
+ /* Clear multicast address hash table
+ */
+ fecp->fec_hash_table_high = 0;
+ fecp->fec_hash_table_low = 0;
+
+ /* Set maximum receive buffer size.
+ */
+ fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
+
+ /*
+ * Setup Buffers and Buffer Desriptors
+ */
+ rxIdx = 0;
+ txIdx = 0;
+
+ /*
+ * Setup Receiver Buffer Descriptors (13.14.24.18)
+ * Settings:
+ * Empty, Wrap
+ */
+ for (i = 0; i < PKTBUFSRX; i++) {
+ rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+ rtx->rxbd[i].cbd_datlen = 0; /* Reset */
+ rtx->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i];
+ }
+ rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /*
+ * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
+ * Settings:
+ * Last, Tx CRC
+ */
+ for (i = 0; i < TX_BUF_CNT; i++) {
+ rtx->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC;
+ rtx->txbd[i].cbd_datlen = 0; /* Reset */
+ rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]);
+ }
+ rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /* Set receive and transmit descriptor base
+ */
+ fecp->fec_r_des_start = (unsigned int) (&rtx->rxbd[0]);
+ fecp->fec_x_des_start = (unsigned int) (&rtx->txbd[0]);
+
+ /* Enable MII mode
+ */
+
+ /* Half duplex mode */
+ fecp->fec_r_cntrl = (PKT_MAXBUF_SIZE<<16) | FEC_RCNTRL_MII_MODE;
+ fecp->fec_r_cntrl = (PKT_MAXBUF_SIZE<<16) | FEC_RCNTRL_MII_MODE;
+ fecp->fec_x_cntrl = 0;
+
+ fecp->fec_mii_speed = 0;
+
+ /* Now enable the transmit and receive processing
+ */
+ fecp->fec_ecntrl = FEC_ECNTRL_ETHER_EN;
+
+ /* And last, try to fill Rx Buffer Descriptors */
+ fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
+
+ return 1;
+}
+
+
+
+void eth_halt(void)
+{
+ volatile fec_t *fecp = FEC_ADDR;
+ fecp->fec_ecntrl = 0;
+}
+
+#endif