summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/rtl8139.c23
-rw-r--r--drivers/net/tsec.c117
-rw-r--r--drivers/net/tsec.h8
3 files changed, 117 insertions, 31 deletions
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
index 4c24805..097f684 100644
--- a/drivers/net/rtl8139.c
+++ b/drivers/net/rtl8139.c
@@ -80,10 +80,7 @@
#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
defined(CONFIG_RTL8139)
-#define TICKS_PER_SEC CFG_HZ
-#define TICKS_PER_MS (TICKS_PER_SEC/1000)
-
-#define RTL_TIMEOUT (1*TICKS_PER_SEC)
+#define RTL_TIMEOUT 100000
#define ETH_FRAME_LEN 1514
#define ETH_ALEN 6
@@ -392,6 +389,7 @@ static void rtl_reset(struct eth_device *dev)
#ifdef DEBUG_RX
printf("rx ring address is %X\n",(unsigned long)rx_ring);
#endif
+ flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf);
/* If we add multicast support, the MAR0 register would have to be
@@ -414,9 +412,10 @@ static void rtl_reset(struct eth_device *dev)
static int rtl_transmit(struct eth_device *dev, volatile void *packet, int length)
{
- unsigned int status, to;
+ unsigned int status;
unsigned long txstatus;
unsigned int len = length;
+ int i = 0;
ioaddr = dev->iobase;
@@ -432,12 +431,11 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt
tx_buffer[len++] = '\0';
}
+ flush_cache((unsigned long)tx_buffer, length);
outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4);
outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len,
ioaddr + TxStatus0 + cur_tx*4);
- to = currticks() + RTL_TIMEOUT;
-
do {
status = inw(ioaddr + IntrStatus);
/* Only acknlowledge interrupt sources we can properly handle
@@ -445,7 +443,8 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt
* rtl_poll() function. */
outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus);
if ((status & (TxOK | TxErr | PCIErr)) != 0) break;
- } while (currticks() < to);
+ udelay(10);
+ } while (i++ < RTL_TIMEOUT);
txstatus = inl(ioaddr + TxStatus0 + cur_tx*4);
@@ -458,8 +457,8 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt
return length;
} else {
#ifdef DEBUG_TX
- printf("tx timeout/error (%d ticks), status %hX txstatus %X\n",
- currticks()-to, status, txstatus);
+ printf("tx timeout/error (%d usecs), status %hX txstatus %X\n",
+ 10*i, status, txstatus);
#endif
rtl_reset(dev);
@@ -489,7 +488,8 @@ static int rtl_poll(struct eth_device *dev)
#endif
ring_offs = cur_rx % RX_BUF_LEN;
- rx_status = *(unsigned int*)KSEG1ADDR((rx_ring + ring_offs));
+ /* ring_offs is guaranteed being 4-byte aligned */
+ rx_status = le32_to_cpu(*(unsigned int *)(rx_ring + ring_offs));
rx_size = rx_status >> 16;
rx_status &= 0xffff;
@@ -519,6 +519,7 @@ static int rtl_poll(struct eth_device *dev)
printf("rx packet %d bytes", rx_size-4);
#endif
}
+ flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
outw(cur_rx - 16, ioaddr + RxBufPtr);
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 25392f6..e91d9ea 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -241,10 +241,9 @@ int tsec_init(struct eth_device *dev, bd_t * bd)
* It will wait for the write to be done (or for a timeout to
* expire) before exiting
*/
-void write_phy_reg(struct tsec_private *priv, uint regnum, uint value)
+void write_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum, uint value)
{
volatile tsec_t *regbase = priv->phyregs;
- uint phyid = priv->phyaddr;
int timeout = 1000000;
regbase->miimadd = (phyid << 8) | regnum;
@@ -255,17 +254,19 @@ void write_phy_reg(struct tsec_private *priv, uint regnum, uint value)
while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
}
+/* #define to provide old write_phy_reg functionality without duplicating code */
+#define write_phy_reg(priv, regnum, value) write_any_phy_reg(priv,priv->phyaddr,regnum,value)
+
/* Reads register regnum on the device's PHY through the
* registers specified in priv. It lowers and raises the read
* command, and waits for the data to become valid (miimind
* notvalid bit cleared), and the bus to cease activity (miimind
* busy bit cleared), and then returns the value
*/
-uint read_phy_reg(struct tsec_private *priv, uint regnum)
+uint read_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum)
{
uint value;
volatile tsec_t *regbase = priv->phyregs;
- uint phyid = priv->phyaddr;
/* Put the address of the phy, and the register
* number into MIIMADD */
@@ -288,6 +289,9 @@ uint read_phy_reg(struct tsec_private *priv, uint regnum)
return value;
}
+/* #define to provide old read_phy_reg functionality without duplicating code */
+#define read_phy_reg(priv,regnum) read_any_phy_reg(priv,priv->phyaddr,regnum)
+
/* Discover which PHY is attached to the device, and configure it
* properly. If the PHY is not recognized, then return 0
* (failure). Otherwise, return 1
@@ -571,6 +575,63 @@ uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv)
return 0;
}
+/* Parse the RTL8211B's status register for speed and duplex
+ * information
+ */
+uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv)
+{
+ uint speed;
+
+ mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
+ if ((mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) &&
+ !(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
+ int i = 0;
+
+ puts("Waiting for PHY realtime link");
+ while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
+ /* Timeout reached ? */
+ if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+ puts(" TIMEOUT !\n");
+ priv->link = 0;
+ break;
+ }
+
+ if ((i++ % 1000) == 0) {
+ putc('.');
+ }
+ udelay(1000); /* 1 ms */
+ mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
+ }
+ puts(" done\n");
+ udelay(500000); /* another 500 ms (results in faster booting) */
+ } else {
+ if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK)
+ priv->link = 1;
+ else
+ priv->link = 0;
+ }
+
+ if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX)
+ priv->duplexity = 1;
+ else
+ priv->duplexity = 0;
+
+ speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED);
+
+ switch (speed) {
+ case MIIM_RTL8211B_PHYSTAT_GBIT:
+ priv->speed = 1000;
+ break;
+ case MIIM_RTL8211B_PHYSTAT_100:
+ priv->speed = 100;
+ break;
+ default:
+ priv->speed = 10;
+ }
+
+ return 0;
+}
+
/* Parse the cis8201's status register for speed and duplex
* information
*/
@@ -1361,6 +1422,33 @@ struct phy_info phy_info_dp83865 = {
},
};
+struct phy_info phy_info_rtl8211b = {
+ 0x001cc91,
+ "RealTek RTL8211B",
+ 4,
+ (struct phy_cmd[]){ /* config */
+ /* Reset and configure the PHY */
+ {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+ {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+ {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+ {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+ {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+ {miim_end,}
+ },
+ (struct phy_cmd[]){ /* startup */
+ /* Status is read once to clear old link state */
+ {MIIM_STATUS, miim_read, NULL},
+ /* Auto-negotiate */
+ {MIIM_STATUS, miim_read, &mii_parse_sr},
+ /* Read the status */
+ {MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr},
+ {miim_end,}
+ },
+ (struct phy_cmd[]){ /* shutdown */
+ {miim_end,}
+ },
+};
+
struct phy_info *phy_info[] = {
&phy_info_cis8204,
&phy_info_cis8201,
@@ -1374,6 +1462,7 @@ struct phy_info *phy_info[] = {
&phy_info_lxt971,
&phy_info_VSC8244,
&phy_info_dp83865,
+ &phy_info_rtl8211b,
&phy_info_generic,
NULL
};
@@ -1497,18 +1586,6 @@ static void relocate_cmds(void)
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
&& !defined(BITBANGMII)
-struct tsec_private *get_priv_for_phy(unsigned char phyaddr)
-{
- int i;
-
- for (i = 0; i < MAXCONTROLLERS; i++) {
- if (privlist[i]->phyaddr == phyaddr)
- return privlist[i];
- }
-
- return NULL;
-}
-
/*
* Read a MII PHY register.
*
@@ -1519,14 +1596,14 @@ static int tsec_miiphy_read(char *devname, unsigned char addr,
unsigned char reg, unsigned short *value)
{
unsigned short ret;
- struct tsec_private *priv = get_priv_for_phy(addr);
+ struct tsec_private *priv = privlist[0];
if (NULL == priv) {
printf("Can't read PHY at address %d\n", addr);
return -1;
}
- ret = (unsigned short)read_phy_reg(priv, reg);
+ ret = (unsigned short)read_any_phy_reg(priv, addr, reg);
*value = ret;
return 0;
@@ -1541,14 +1618,14 @@ static int tsec_miiphy_read(char *devname, unsigned char addr,
static int tsec_miiphy_write(char *devname, unsigned char addr,
unsigned char reg, unsigned short value)
{
- struct tsec_private *priv = get_priv_for_phy(addr);
+ struct tsec_private *priv = privlist[0];
if (NULL == priv) {
printf("Can't write PHY at address %d\n", addr);
return -1;
}
- write_phy_reg(priv, reg, value);
+ write_any_phy_reg(priv, addr, reg, value);
return 0;
}
diff --git a/drivers/net/tsec.h b/drivers/net/tsec.h
index 2f0092a..d4dc15a 100644
--- a/drivers/net/tsec.h
+++ b/drivers/net/tsec.h
@@ -184,6 +184,14 @@
#define MIIM_88E1145_PHY_PAGE 29
#define MIIM_88E1145_PHY_CAL_OV 30
+/* RTL8211B PHY Status Register */
+#define MIIM_RTL8211B_PHY_STATUS 0x11
+#define MIIM_RTL8211B_PHYSTAT_SPEED 0xc000
+#define MIIM_RTL8211B_PHYSTAT_GBIT 0x8000
+#define MIIM_RTL8211B_PHYSTAT_100 0x4000
+#define MIIM_RTL8211B_PHYSTAT_DUPLEX 0x2000
+#define MIIM_RTL8211B_PHYSTAT_SPDDONE 0x0800
+#define MIIM_RTL8211B_PHYSTAT_LINK 0x0400
/* DM9161 Control register values */
#define MIIM_DM9161_CR_STOP 0x0400