aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwdenk <wdenk>2004-04-15 21:31:56 +0000
committerwdenk <wdenk>2004-04-15 21:31:56 +0000
commita6ab4bf978a3d5a52a47bbd259b7eb4c860ebd0c (patch)
tree7b9b794995dc1b3251a43fdc94a5190c955a5dd2
parent5a8c51cd5ef87195e05cdd9aaf2f1dcc753c9792 (diff)
Patches by Pantelis Antoniou, 30 Mar 2004:
Improve and fix various things in the MPC8xx FEC driver: 1. The new 87x and 88x series of processors have two FECs, and the new driver supports them both. 2. Another change in the 87x/88x series is support for the RMII (Reduced MII) interface. However numerous changes are needed to make it work since the PHYs are connected to the same lines. That means that you have to address them correctly over the MII interface.
-rw-r--r--CHANGELOG11
-rw-r--r--cpu/mpc8xx/fec.c688
-rw-r--r--include/asm-ppc/8xx_immap.h6
-rw-r--r--include/mpc8xx.h6
4 files changed, 481 insertions, 230 deletions
diff --git a/CHANGELOG b/CHANGELOG
index b1f1be386..8ababc72c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,17 @@ Changes for U-Boot 1.1.1:
(These displays are serial and not suitable for using a normal
framebuffer console on them)
- add infrastructure needed in order to POST any DSPs in a board
+ - improve and fix various things in the MPC8xx FEC driver:
+ 1. The new 87x and 88x series of processors have two FECs,
+ and the new driver supports them both.
+ 2. Another change in the 87x/88x series is support for
+ the RMII (Reduced MII) interface. However numerous
+ changes are needed to make it work since the PHYs
+ are connected to the same lines. That means that
+ you have to address them correctly over the MII
+ interface.
+ 3. We now correctly match the MII/RMII interface
+ configuration to what the PHY reports.
* Patch by Yuli Barcohen, 28 Mar 2004:
- Add support for MPC8272 family including MPC8247/8248/8271/8272
diff --git a/cpu/mpc8xx/fec.c b/cpu/mpc8xx/fec.c
index 811ac7971..b7603da45 100644
--- a/cpu/mpc8xx/fec.c
+++ b/cpu/mpc8xx/fec.c
@@ -29,13 +29,71 @@
#undef ET_DEBUG
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(FEC_ENET)
+#if (CONFIG_COMMANDS & CFG_CMD_NET) && \
+ (defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FEC1) || defined(CONFIG_ETHER_ON_FEC2))
-#ifdef CFG_DISCOVER_PHY
+/* compatibility test, if only FEC_ENET defined assume ETHER on FEC1 */
+#if defined(FEC_ENET) && !defined(CONFIG_ETHER_ON_FEC1) && !defined(CONFIG_ETHER_ON_FEC2)
+#define CONFIG_ETHER_ON_FEC1 1
+#endif
+
+/* define WANT_MII when MII support is required */
+#if defined(CFG_DISCOVER_PHY) || defined(CONFIG_FEC1_PHY) || defined(CONFIG_FEC2_PHY)
+#define WANT_MII
+#else
+#undef WANT_MII
+#endif
+
+#if defined(WANT_MII)
#include <miiphy.h>
-static void mii_discover_phy(void);
#endif
+#if defined(CONFIG_RMII) && !defined(WANT_MII)
+#error RMII support is unusable without a working PHY.
+#endif
+
+#ifdef CFG_DISCOVER_PHY
+static int mii_discover_phy(struct eth_device *dev);
+#endif
+
+static struct ether_fcc_info_s
+{
+ int ether_index;
+ int fecp_offset;
+ int bd_offset;
+ int phy_addr;
+ int actual_phy_addr;
+}
+ ether_fcc_info[] = {
+#if defined(CONFIG_ETHER_ON_FEC1)
+ {
+ 0,
+ offsetof(immap_t, im_cpm.cp_fec1),
+ CPM_FEC_BASE,
+#if defined(CONFIG_FEC1_PHY)
+ CONFIG_FEC1_PHY,
+#else
+ -1, /* discover */
+#endif
+ -1,
+
+ },
+#endif
+#if defined(CONFIG_ETHER_ON_FEC2)
+ {
+ 1,
+ offsetof(immap_t, im_cpm.cp_fec2),
+ CPM_FEC_BASE + 0x50,
+#if defined(CONFIG_FEC2_PHY)
+ CONFIG_FEC2_PHY,
+#else
+ -1,
+#endif
+ -1,
+ },
+#endif
+};
+
/* Ethernet Transmit and Receive Buffers */
#define DBUF_LENGTH 1520
@@ -47,8 +105,11 @@ static void mii_discover_phy(void);
#define PKT_MINBUF_SIZE 64
#define PKT_MAXBLR_SIZE 1520
-
-static char txbuf[DBUF_LENGTH];
+#ifdef __GNUC__
+static char txbuf[DBUF_LENGTH] __attribute__ ((aligned(8)));
+#else
+#error txbuf must be aligned.
+#endif
static uint rxIdx; /* index of the current RX buffer */
static uint txIdx; /* index of the current TX buffer */
@@ -74,28 +135,49 @@ static void fec_halt(struct eth_device* dev);
int fec_initialize(bd_t *bis)
{
struct eth_device* dev;
+ struct ether_fcc_info_s *efis;
+ int i;
- dev = (struct eth_device*) malloc(sizeof *dev);
- memset(dev, 0, sizeof *dev);
+ for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++) {
- sprintf(dev->name, "FEC ETHERNET");
- dev->iobase = 0;
- dev->priv = 0;
- dev->init = fec_init;
- dev->halt = fec_halt;
- dev->send = fec_send;
- dev->recv = fec_recv;
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL)
+ hang();
+
+ memset(dev, 0, sizeof(*dev));
+
+ /* for FEC1 make sure that the name of the interface is the same
+ as the old one for compatibility reasons */
+ if (i == 0) {
+ sprintf (dev->name, "FEC ETHERNET");
+ } else {
+ sprintf (dev->name, "FEC%d ETHERNET",
+ ether_fcc_info[i].ether_index + 1);
+ }
- eth_register(dev);
+ efis = &ether_fcc_info[i];
+ /*
+ * reset actual phy addr
+ */
+ efis->actual_phy_addr = -1;
+
+ dev->priv = efis;
+ dev->init = fec_init;
+ dev->halt = fec_halt;
+ dev->send = fec_send;
+ dev->recv = fec_recv;
+
+ eth_register(dev);
+ }
return 1;
}
static int fec_send(struct eth_device* dev, volatile void *packet, int length)
{
int j, rc;
- volatile immap_t *immr = (immap_t *) CFG_IMMR;
- volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset);
/* section 16.9.23.3
* Wait for ready
@@ -142,50 +224,66 @@ static int fec_send(struct eth_device* dev, volatile void *packet, int length)
return rc;
}
-static int fec_recv(struct eth_device* dev)
+static int fec_recv (struct eth_device *dev)
{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp =
+ (volatile fec_t *) (CFG_IMMR + efis->fecp_offset);
int length;
- volatile immap_t *immr = (immap_t *) CFG_IMMR;
- volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
- for (;;) {
- /* section 16.9.23.2 */
- if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
- length = -1;
- break; /* nothing received - leave for() loop */
- }
+ 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;
+ length = rtx->rxbd[rxIdx].cbd_datlen;
- if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) {
+ if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) {
#ifdef ET_DEBUG
- printf("%s[%d] err: %x\n",
- __FUNCTION__,__LINE__,rtx->rxbd[rxIdx].cbd_sc);
+ 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);
- }
+ } else {
+ volatile uchar *rx = NetRxPackets[rxIdx];
- /* Give the buffer back to the FEC. */
- rtx->rxbd[rxIdx].cbd_datlen = 0;
+ length -= 4;
- /* 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++;
- }
+#if (CONFIG_COMMANDS & CFG_CMD_CDP)
+ if ((rx[0] & 1) != 0
+ && memcmp ((uchar *) rx, NetBcastAddr, 6) != 0
+ && memcmp ((uchar *) rx, NetCDPAddr, 6) != 0)
+ rx = NULL;
+#endif
+ /*
+ * Pass the packet up to the protocol layers.
+ */
+ if (rx != NULL)
+ NetReceive (rx, length);
+ }
- __asm__ ("eieio");
+ /* 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++;
+ }
+
+ __asm__ ("eieio");
- /* Try to fill Buffer Descriptors */
- fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
- }
+ /* Try to fill Buffer Descriptors */
+ fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
+ }
- return length;
+ return length;
}
/**************************************************************
@@ -210,34 +308,250 @@ static int fec_recv(struct eth_device* dev)
#define FEC_RESET_DELAY 50
-static int fec_init(struct eth_device* dev, bd_t * bd)
+#if defined(CONFIG_RMII)
+
+static inline void fec_10Mbps(struct eth_device *dev)
{
+ struct ether_fcc_info_s *efis = dev->priv;
+ int fecidx = efis->ether_index;
+ uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
- int i;
+ if ((unsigned int)fecidx >= 2)
+ hang();
+
+ ((volatile immap_t *)CFG_IMMR)->im_cpm.cp_cptr |= mask;
+}
+
+static inline void fec_100Mbps(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ int fecidx = efis->ether_index;
+ uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
+
+ if ((unsigned int)fecidx >= 2)
+ hang();
+
+ ((volatile immap_t *)CFG_IMMR)->im_cpm.cp_cptr &= ~mask;
+}
+
+#endif
+
+static inline void fec_full_duplex(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset);
+
+ fecp->fec_r_cntrl &= ~FEC_RCNTRL_DRT;
+ fecp->fec_x_cntrl |= FEC_TCNTRL_FDEN; /* FD enable */
+}
+
+static inline void fec_half_duplex(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset);
+
+ fecp->fec_r_cntrl |= FEC_RCNTRL_DRT;
+ fecp->fec_x_cntrl &= ~FEC_TCNTRL_FDEN; /* FD disable */
+}
+
+static void fec_pin_init(int fecidx)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ bd_t *bd = gd->bd;
volatile immap_t *immr = (immap_t *) CFG_IMMR;
- volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
+ volatile fec_t *fecp;
-#if defined(CONFIG_FADS) /* FADS family uses FPGA (BCSR) to control PHYs */
-#if defined(CONFIG_DUET_ADS)
- *(vu_char *)BCSR5 &= ~(BCSR5_MII1_EN | BCSR5_MII1_RST);
-#else
- /* configure FADS for fast (FEC) ethernet, half-duplex */
- /* The LXT970 needs about 50ms to recover from reset, so
- * wait for it by discovering the PHY before leaving eth_init().
+ /*
+ * only two FECs please
*/
- {
- volatile uint *bcsr4 = (volatile uint *) BCSR4;
- *bcsr4 = (*bcsr4 & ~(BCSR4_FETH_EN | BCSR4_FETHCFG1))
- | (BCSR4_FETHCFG0 | BCSR4_FETHFDE | BCSR4_FETHRST);
-
- /* reset the LXT970 PHY */
- *bcsr4 &= ~BCSR4_FETHRST;
- udelay (10);
- *bcsr4 |= BCSR4_FETHRST;
- udelay (10);
+ if ((unsigned int)fecidx >= 2)
+ hang();
+
+ if (fecidx == 0)
+ fecp = &immr->im_cpm.cp_fec1;
+ else
+ fecp = &immr->im_cpm.cp_fec2;
+
+ /*
+ * Set MII speed to 2.5 MHz or slightly below.
+ * * According to the MPC860T (Rev. D) Fast ethernet controller user
+ * * manual (6.2.14),
+ * * the MII management interface clock must be less than or equal
+ * * to 2.5 MHz.
+ * * This MDC frequency is equal to system clock / (2 * MII_SPEED).
+ * * Then MII_SPEED = system_clock / 2 * 2,5 Mhz.
+ */
+ fecp->fec_mii_speed = ((bd->bi_intfreq + 4999999) / 5000000) << 1;
+
+#if defined(CONFIG_DUET) && defined(WANT_MII)
+ /* use MDC for MII */
+ immr->im_ioport.iop_pdpar |= 0x0080;
+ immr->im_ioport.iop_pddir &= ~0x0080;
+#endif
+
+ if (fecidx == 0) {
+#if defined(CONFIG_ETHER_ON_FEC1)
+
+#if defined(CONFIG_DUET) /* MPC87x/88x have got 2 FECs and different pinout */
+
+#if !defined(CONFIG_RMII)
+
+ immr->im_ioport.iop_papar |= 0xf830;
+ immr->im_ioport.iop_padir |= 0x0830;
+ immr->im_ioport.iop_padir &= ~0xf000;
+
+ immr->im_cpm.cp_pbpar |= 0x00001001;
+ immr->im_cpm.cp_pbdir &= ~0x00001001;
+
+ immr->im_ioport.iop_pcpar |= 0x000c;
+ immr->im_ioport.iop_pcdir &= ~0x000c;
+
+ immr->im_cpm.cp_pepar |= 0x00000003;
+ immr->im_cpm.cp_pedir |= 0x00000003;
+ immr->im_cpm.cp_peso &= ~0x00000003;
+
+ immr->im_cpm.cp_cptr &= ~0x00000100;
+
+#else
+
+#if !defined(CONFIG_FEC1_PHY_NORXERR)
+ immr->im_ioport.iop_papar |= 0x1000;
+ immr->im_ioport.iop_padir &= ~0x1000;
+#endif
+ immr->im_ioport.iop_papar |= 0xe810;
+ immr->im_ioport.iop_padir |= 0x0810;
+ immr->im_ioport.iop_padir &= ~0xe000;
+
+ immr->im_cpm.cp_pbpar |= 0x00000001;
+ immr->im_cpm.cp_pbdir &= ~0x00000001;
+
+ immr->im_cpm.cp_cptr |= 0x00000100;
+ immr->im_cpm.cp_cptr &= ~0x00000050;
+
+#endif /* !CONFIG_RMII */
+
+#elif !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210)
+ /*
+ * Configure all of port D for MII.
+ */
+ immr->im_ioport.iop_pdpar = 0x1fff;
+
+ /*
+ * Bits moved from Rev. D onward
+ */
+ if ((get_immr(0) & 0xffff) < 0x0501)
+ immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */
+ else
+ immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */
+#else
+ /*
+ * Configure port A for MII.
+ */
+
+#if defined(CONFIG_ICU862) && defined(CFG_DISCOVER_PHY)
+
+ /*
+ * On the ICU862 board the MII-MDC pin is routed to PD8 pin
+ * * of CPU, so for this board we need to configure Utopia and
+ * * enable PD8 to MII-MDC function
+ */
+ immr->im_ioport.iop_pdpar |= 0x4080;
+#endif
+
+ /*
+ * Has Utopia been configured?
+ */
+ if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) {
+ /*
+ * YES - Use MUXED mode for UTOPIA bus.
+ * This frees Port A for use by MII (see 862UM table 41-6).
+ */
+ immr->im_ioport.utmode &= ~0x80;
+ } else {
+ /*
+ * NO - set SPLIT mode for UTOPIA bus.
+ *
+ * This doesn't really effect UTOPIA (which isn't
+ * enabled anyway) but just tells the 862
+ * to use port A for MII (see 862UM table 41-6).
+ */
+ immr->im_ioport.utmode |= 0x80;
+ }
+#endif /* !defined(CONFIG_ICU862) */
+
+#endif /* CONFIG_ETHER_ON_FEC1 */
+ } else if (fecidx == 1) {
+
+#if defined(CONFIG_ETHER_ON_FEC2)
+
+#if defined(CONFIG_DUET) /* MPC87x/88x have got 2 FECs and different pinout */
+
+#if !defined(CONFIG_RMII)
+
+#warning this configuration is not tested; please report if it works
+ immr->im_cpm.cp_pepar |= 0x0003fffc;
+ immr->im_cpm.cp_pedir |= 0x0003fffc;
+ immr->im_cpm.cp_peso &= ~0x000087fc;
+ immr->im_cpm.cp_peso |= 0x00037800;
+
+ immr->im_cpm.cp_cptr &= ~0x00000080;
+#else
+
+#if !defined(CONFIG_FEC2_PHY_NORXERR)
+ immr->im_cpm.cp_pepar |= 0x00000010;
+ immr->im_cpm.cp_pedir |= 0x00000010;
+ immr->im_cpm.cp_peso &= ~0x00000010;
+#endif
+ immr->im_cpm.cp_pepar |= 0x00039620;
+ immr->im_cpm.cp_pedir |= 0x00039620;
+ immr->im_cpm.cp_peso |= 0x00031000;
+ immr->im_cpm.cp_peso &= ~0x00008620;
+
+ immr->im_cpm.cp_cptr |= 0x00000080;
+ immr->im_cpm.cp_cptr &= ~0x00000028;
+#endif /* CONFIG_RMII */
+
+#endif /* CONFIG_DUET */
+
+#endif /* CONFIG_ETHER_ON_FEC2 */
+
}
+}
+
+static int fec_init (struct eth_device *dev, bd_t * bd)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile immap_t *immr = (immap_t *) CFG_IMMR;
+ volatile fec_t *fecp =
+ (volatile fec_t *) (CFG_IMMR + efis->fecp_offset);
+ int i;
+
+ if (efis->ether_index == 0) {
+#if defined(CONFIG_FADS) /* FADS family uses FPGA (BCSR) to control PHYs */
+#if defined(CONFIG_DUET_ADS)
+ *(vu_char *) BCSR5 &= ~(BCSR5_MII1_EN | BCSR5_MII1_RST);
+#else
+ /* configure FADS for fast (FEC) ethernet, half-duplex */
+ /* The LXT970 needs about 50ms to recover from reset, so
+ * wait for it by discovering the PHY before leaving eth_init().
+ */
+ {
+ volatile uint *bcsr4 = (volatile uint *) BCSR4;
+
+ *bcsr4 = (*bcsr4 & ~(BCSR4_FETH_EN | BCSR4_FETHCFG1))
+ | (BCSR4_FETHCFG0 | BCSR4_FETHFDE |
+ BCSR4_FETHRST);
+
+ /* reset the LXT970 PHY */
+ *bcsr4 &= ~BCSR4_FETHRST;
+ udelay (10);
+ *bcsr4 |= BCSR4_FETHRST;
+ udelay (10);
+ }
#endif /* CONFIG_DUET_ADS */
#endif /* CONFIG_FADS */
+ }
+
/* Whack a reset.
* A delay is required between a reset of the FEC block and
* initialization of other FEC registers because the reset takes
@@ -269,15 +583,22 @@ static int fec_init(struct eth_device* dev, bd_t * bd)
/* Set station address
*/
#define ea eth_get_dev()->enetaddr
- fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) |
- (ea[2] << 8) | (ea[3] ) ;
- fecp->fec_addr_high = (ea[4] << 8) | (ea[5] ) ;
+ fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
+ fecp->fec_addr_high = (ea[4] << 8) | (ea[5]);
#undef ea
+#if (CONFIG_COMMANDS & CFG_CMD_CDP)
+ /*
+ * Turn on multicast address hash table
+ */
+ fecp->fec_hash_table_high = 0xffffffff;
+ fecp->fec_hash_table_low = 0xffffffff;
+#else
/* Clear multicast address hash table
*/
fecp->fec_hash_table_high = 0;
- fecp->fec_hash_table_low = 0;
+ fecp->fec_hash_table_low = 0;
+#endif
/* Set maximum receive buffer size.
*/
@@ -295,9 +616,10 @@ static int fec_init(struct eth_device* dev, bd_t * bd)
if (!rtx) {
#ifdef CFG_ALLOC_DPRAM
- rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + dpram_alloc_align(sizeof(RTXBD),8));
+ rtx = (RTXBD *) (immr->im_cpm.cp_dpmem +
+ dpram_alloc_align (sizeof (RTXBD), 8));
#else
- rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_FEC_BASE);
+ rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_FEC_BASE);
#endif
}
/*
@@ -306,8 +628,8 @@ static int fec_init(struct eth_device* dev, bd_t * bd)
* 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_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;
@@ -318,8 +640,8 @@ static int fec_init(struct eth_device* dev, bd_t * bd)
* 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_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;
@@ -331,10 +653,10 @@ static int fec_init(struct eth_device* dev, bd_t * bd)
/* Enable MII mode
*/
-#if 0 /* Full duplex mode */
+#if 0 /* Full duplex mode */
fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE;
fecp->fec_x_cntrl = FEC_TCNTRL_FDEN;
-#else /* Half duplex mode */
+#else /* Half duplex mode */
fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT;
fecp->fec_x_cntrl = 0;
#endif
@@ -343,86 +665,59 @@ static int fec_init(struct eth_device* dev, bd_t * bd)
*/
fecp->fec_fun_code = 0x78000000;
- /* Set MII speed to 2.5 MHz or slightly below.
- * According to the MPC860T (Rev. D) Fast ethernet controller user
- * manual (6.2.14),
- * the MII management interface clock must be less than or equal
- * to 2.5 MHz.
- * This MDC frequency is equal to system clock / (2 * MII_SPEED).
- * Then MII_SPEED = system_clock / 2 * 2,5 Mhz.
- */
- fecp->fec_mii_speed = ((bd->bi_intfreq + 4999999) / 5000000) << 1;
-
-#if defined(CONFIG_DUET) /* MPC87x/88x have got 2 FECs and different pinout */
- immr->im_ioport.iop_papar |= 0xf830;
- immr->im_ioport.iop_padir |= 0x0830;
- immr->im_ioport.iop_padir &= ~0xf000;
- immr->im_cpm.cp_pbpar |= 0x00001001;
- immr->im_cpm.cp_pbdir &= ~0x00001001;
- immr->im_ioport.iop_pcpar |= 0x000c;
- immr->im_ioport.iop_pcdir &= ~0x000c;
- immr->im_ioport.iop_pdpar |= 0x0080;
- immr->im_ioport.iop_pddir &= ~0x0080;
- immr->im_cpm.cp_pepar |= 0x00000003;
- immr->im_cpm.cp_pedir |= 0x00000003;
- immr->im_cpm.cp_peso &= ~0x00000003;
-#elif !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210)
- /* Configure all of port D for MII.
+ /*
+ * Setup the pin configuration of the FEC
*/
- immr->im_ioport.iop_pdpar = 0x1fff;
-
- /* Bits moved from Rev. D onward */
- if ((get_immr (0) & 0xffff) < 0x0501) {
- immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */
- } else {
- immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */
- }
-#else
- /* Configure port A for MII.
- */
+ fec_pin_init (efis->ether_index);
-#if defined(CONFIG_ICU862) && defined(CFG_DISCOVER_PHY)
+ rxIdx = 0;
+ txIdx = 0;
- /* On the ICU862 board the MII-MDC pin is routed to PD8 pin
- * of CPU, so for this board we need to configure Utopia and
- * enable PD8 to MII-MDC function */
- immr->im_ioport.iop_pdpar |= 0x4080;
-#endif
+ /*
+ * Now enable the transmit and receive processing
+ */
+ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
- /* Has Utopia been configured? */
- if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) {
+ if (efis->phy_addr == -1) {
+#ifdef CFG_DISCOVER_PHY
/*
- * YES - Use MUXED mode for UTOPIA bus.
- * This frees Port A for use by MII (see 862UM table 41-6).
+ * wait for the PHY to wake up after reset
*/
- immr->im_ioport.utmode &= ~0x80;
+ efis->actual_phy_addr = mii_discover_phy (dev);
+#else
+ efis->actual_phy_addr = -1;
+#endif
+ if (efis->actual_phy_addr == -1) {
+ printf ("Unable to discover phy!\n");
+ return 0;
+ }
} else {
- /*
- * NO - set SPLIT mode for UTOPIA bus.
- *
- * This doesn't really effect UTOPIA (which isn't
- * enabled anyway) but just tells the 862
- * to use port A for MII (see 862UM table 41-6).
- */
- immr->im_ioport.utmode |= 0x80;
+ efis->actual_phy_addr = efis->phy_addr;
}
-#endif /* !defined(CONFIG_ICU862) */
-
- rxIdx = 0;
- txIdx = 0;
-
- /* Now enable the transmit and receive processing
+#if defined(CONFIG_MII) && defined(CONFIG_RMII)
+ /*
+ * adapt the RMII speed to the speed of the phy
*/
- fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+ if (miiphy_speed (efis->actual_phy_addr) == _100BASET) {
+ fec_100Mbps (dev);
+ } else {
+ fec_10Mbps (dev);
+ }
+#endif
-#ifdef CFG_DISCOVER_PHY
- /* wait for the PHY to wake up after reset
+#if defined(CONFIG_MII)
+ /*
+ * adapt to the half/full speed settings
*/
- mii_discover_phy();
+ if (miiphy_duplex (efis->actual_phy_addr) == FULL) {
+ fec_full_duplex (dev);
+ } else {
+ fec_half_duplex (dev);
+ }
#endif
/* And last, try to fill Rx Buffer Descriptors */
- fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
+ fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
return 1;
}
@@ -431,23 +726,20 @@ static int fec_init(struct eth_device* dev, bd_t * bd)
static void fec_halt(struct eth_device* dev)
{
#if 0
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
- immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
#endif
}
#if 0
void restart(void)
{
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
- immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
#endif
-#if defined(CFG_DISCOVER_PHY) || (CONFIG_COMMANDS & CFG_CMD_MII)
-
-static int phyaddr = -1; /* didn't find a PHY yet */
-static uint phytype;
+#if defined(CFG_DISCOVER_PHY) || defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
/* Make MII read/write commands for the FEC.
*/
@@ -508,12 +800,13 @@ mii_send(uint mii_cmd)
#endif /* CFG_DISCOVER_PHY || (CONFIG_COMMANDS & CFG_CMD_MII) */
#if defined(CFG_DISCOVER_PHY)
-static void
-mii_discover_phy(void)
+static int mii_discover_phy(struct eth_device *dev)
{
#define MAX_PHY_PASSES 11
uint phyno;
int pass;
+ uint phytype;
+ int phyaddr;
phyaddr = -1; /* didn't find a PHY yet */
for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) {
@@ -571,10 +864,11 @@ mii_discover_phy(void)
if (phyaddr < 0) {
printf("No PHY device found.\n");
}
+ return phyaddr;
}
#endif /* CFG_DISCOVER_PHY */
-#if (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII)
+#if (defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)) && !defined(CONFIG_BITBANGMII)
static int mii_init_done = 0;
@@ -585,17 +879,16 @@ static int mii_init_done = 0;
*/
void mii_init (void)
{
- DECLARE_GLOBAL_DATA_PTR;
- bd_t *bd = gd->bd;
-
volatile immap_t *immr = (immap_t *) CFG_IMMR;
volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
- int i;
+ int i, j;
if (mii_init_done != 0) {
return;
}
+ for (j = 0; j < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); j++) {
+
/* Whack a reset.
* A delay is required between a reset of the FEC block and
* initialization of other FEC registers because the reset takes
@@ -623,76 +916,18 @@ void mii_init (void)
*/
fecp->fec_ievent = 0xffc0;
- /* Set MII speed to 2.5 MHz or slightly below.
- * According to the MPC860T (Rev. D) Fast ethernet controller user
- * manual (6.2.14),
- * the MII management interface clock must be less than or equal
- * to 2.5 MHz.
- * This MDC frequency is equal to system clock / (2 * MII_SPEED).
- * Then MII_SPEED = system_clock / 2 * 2,5 Mhz.
- */
- fecp->fec_mii_speed = ((bd->bi_intfreq + 4999999) / 5000000) << 1;
-
-#if defined(CONFIG_DUET) /* MPC87x/88x have got 2 FECs and different pinout */
- immr->im_ioport.iop_papar |= 0xf830;
- immr->im_ioport.iop_padir |= 0x0830;
- immr->im_ioport.iop_padir &= ~0xf000;
- immr->im_cpm.cp_pbpar |= 0x00001001;
- immr->im_cpm.cp_pbdir &= ~0x00001001;
- immr->im_ioport.iop_pcpar |= 0x000c;
- immr->im_ioport.iop_pcdir &= ~0x000c;
- immr->im_ioport.iop_pdpar |= 0x0080;
- immr->im_ioport.iop_pddir &= ~0x0080;
- immr->im_cpm.cp_pepar |= 0x00000003;
- immr->im_cpm.cp_pedir |= 0x00000003;
- immr->im_cpm.cp_peso &= ~0x00000003;
-#elif !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210)
- /* Configure all of port D for MII.
- */
- immr->im_ioport.iop_pdpar = 0x1fff;
-
- /* Bits moved from Rev. D onward */
- if ((get_immr (0) & 0xffff) < 0x0501) {
- immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */
- } else {
- immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */
- }
-#else
- /* Configure port A for MII.
+ /* Setup the pin configuration of the FEC(s)
*/
+ fec_pin_init(ether_fcc_info[i].ether_index);
-#if defined(CONFIG_ICU862)
-
- /* On the ICU862 board the MII-MDC pin is routed to PD8 pin
- * of CPU, so for this board we need to configure Utopia and
- * enable PD8 to MII-MDC function */
- immr->im_ioport.iop_pdpar |= 0x4080;
-#endif
-
- /* Has Utopia been configured? */
- if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) {
- /*
- * YES - Use MUXED mode for UTOPIA bus.
- * This frees Port A for use by MII (see 862UM table 41-6).
- */
- immr->im_ioport.utmode &= ~0x80;
- } else {
- /*
- * NO - set SPLIT mode for UTOPIA bus.
- *
- * This doesn't really effect UTOPIA (which isn't
- * enabled anyway) but just tells the 862
- * to use port A for MII (see 862UM table 41-6).
- */
- immr->im_ioport.utmode |= 0x80;
- }
-#endif /* !defined(CONFIG_ICU862) */
/* Now enable the transmit and receive processing
*/
fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+ }
mii_init_done = 1;
}
+
/*****************************************************************************
* Read and write a MII PHY register, routines used by MII Utilities
*
@@ -714,28 +949,23 @@ int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value)
rdreg = mii_send(mk_mii_read(addr, reg));
*value = rdreg;
-
#ifdef MII_DEBUG
printf ("0x%04x\n", *value);
#endif
-
return 0;
}
int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value)
{
short rdreg; /* register working value */
-
#ifdef MII_DEBUG
printf ("miiphy_write(0x%x) @ 0x%x = ", reg, addr);
#endif
-
rdreg = mii_send(mk_mii_write(addr, reg, value));
#ifdef MII_DEBUG
printf ("0x%04x\n", value);
#endif
-
return 0;
}
#endif /* (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII)*/
diff --git a/include/asm-ppc/8xx_immap.h b/include/asm-ppc/8xx_immap.h
index 469edb34f..2288115a6 100644
--- a/include/asm-ppc/8xx_immap.h
+++ b/include/asm-ppc/8xx_immap.h
@@ -473,7 +473,11 @@ typedef struct comm_proc {
union fec_lcd fl_un;
#define cp_fec fl_un.fl_un_fec
#define lcd_cmap fl_un.fl_un_cmap
- char res18[0x1000];
+ char res18[0xE00];
+
+ /* The DUET family has a second FEC here */
+ fec_t cp_fec2;
+#define cp_fec1 cp_fec /* consistency macro */
/* Dual Ported RAM follows.
* There are many different formats for this memory area
diff --git a/include/mpc8xx.h b/include/mpc8xx.h
index 3976125bf..29117589b 100644
--- a/include/mpc8xx.h
+++ b/include/mpc8xx.h
@@ -208,6 +208,12 @@
#define SCCR_DFBRG10 0x00001000 /* BRGCLK division by 16 */
#define SCCR_DFBRG11 0x00001800 /* BRGCLK division by 64 */
#define SCCR_DFNL000 0x00000000 /* Division by 2 (default = minimum) */
+#define SCCR_DFNL001 0x00000100 /* Division by 4 */
+#define SCCR_DFNL010 0x00000200 /* Division by 8 */
+#define SCCR_DFNL011 0x00000300 /* Division by 16 */
+#define SCCR_DFNL100 0x00000400 /* Division by 32 */
+#define SCCR_DFNL101 0x00000500 /* Division by 64 */
+#define SCCR_DFNL110 0x00000600 /* Division by 128 */
#define SCCR_DFNL111 0x00000700 /* Division by 256 (maximum) */
#define SCCR_DFNH000 0x00000000 /* Division by 1 (default = minimum) */
#define SCCR_DFNH110 0x000000D0 /* Division by 64 (maximum) */