|
@@ -47,6 +47,7 @@
|
|
|
#include <linux/spinlock.h>
|
|
|
#include <linux/ethtool.h>
|
|
|
#include <linux/mii.h>
|
|
|
+#include <linux/phy.h>
|
|
|
#include <linux/netdevice.h>
|
|
|
#include <linux/etherdevice.h>
|
|
|
#include <linux/skbuff.h>
|
|
@@ -94,6 +95,9 @@ static struct net_dma_desc_tx *current_tx_ptr;
|
|
|
static struct net_dma_desc_tx *tx_desc;
|
|
|
static struct net_dma_desc_rx *rx_desc;
|
|
|
|
|
|
+static void bf537mac_disable(void);
|
|
|
+static void bf537mac_enable(void);
|
|
|
+
|
|
|
static void desc_list_free(void)
|
|
|
{
|
|
|
struct net_dma_desc_rx *r;
|
|
@@ -282,8 +286,11 @@ static int setup_pin_mux(int action)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * MII operations
|
|
|
+ */
|
|
|
/* Wait until the previous MDC/MDIO transaction has completed */
|
|
|
-static void poll_mdc_done(void)
|
|
|
+static void mdio_poll(void)
|
|
|
{
|
|
|
int timeout_cnt = MAX_TIMEOUT_CNT;
|
|
|
|
|
@@ -299,154 +306,201 @@ static void poll_mdc_done(void)
|
|
|
}
|
|
|
|
|
|
/* Read an off-chip register in a PHY through the MDC/MDIO port */
|
|
|
-static u16 read_phy_reg(u16 PHYAddr, u16 RegAddr)
|
|
|
+static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
|
|
|
{
|
|
|
- poll_mdc_done();
|
|
|
+ mdio_poll();
|
|
|
+
|
|
|
/* read mode */
|
|
|
- bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) |
|
|
|
- SET_REGAD(RegAddr) |
|
|
|
+ bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
|
|
|
+ SET_REGAD((u16) regnum) |
|
|
|
STABUSY);
|
|
|
- poll_mdc_done();
|
|
|
|
|
|
- return (u16) bfin_read_EMAC_STADAT();
|
|
|
+ mdio_poll();
|
|
|
+
|
|
|
+ return (int) bfin_read_EMAC_STADAT();
|
|
|
}
|
|
|
|
|
|
/* Write an off-chip register in a PHY through the MDC/MDIO port */
|
|
|
-static void raw_write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data)
|
|
|
+static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
|
|
|
+ u16 value)
|
|
|
{
|
|
|
- bfin_write_EMAC_STADAT(Data);
|
|
|
+ mdio_poll();
|
|
|
+
|
|
|
+ bfin_write_EMAC_STADAT((u32) value);
|
|
|
|
|
|
/* write mode */
|
|
|
- bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) |
|
|
|
- SET_REGAD(RegAddr) |
|
|
|
+ bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
|
|
|
+ SET_REGAD((u16) regnum) |
|
|
|
STAOP |
|
|
|
STABUSY);
|
|
|
|
|
|
- poll_mdc_done();
|
|
|
+ mdio_poll();
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static void write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data)
|
|
|
+static int mdiobus_reset(struct mii_bus *bus)
|
|
|
{
|
|
|
- poll_mdc_done();
|
|
|
- raw_write_phy_reg(PHYAddr, RegAddr, Data);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-/* set up the phy */
|
|
|
-static void bf537mac_setphy(struct net_device *dev)
|
|
|
+static void bf537_adjust_link(struct net_device *dev)
|
|
|
{
|
|
|
- u16 phydat;
|
|
|
struct bf537mac_local *lp = netdev_priv(dev);
|
|
|
+ struct phy_device *phydev = lp->phydev;
|
|
|
+ unsigned long flags;
|
|
|
+ int new_state = 0;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&lp->lock, flags);
|
|
|
+ if (phydev->link) {
|
|
|
+ /* Now we make sure that we can be in full duplex mode.
|
|
|
+ * If not, we operate in half-duplex mode. */
|
|
|
+ if (phydev->duplex != lp->old_duplex) {
|
|
|
+ u32 opmode = bfin_read_EMAC_OPMODE();
|
|
|
+ new_state = 1;
|
|
|
+
|
|
|
+ if (phydev->duplex)
|
|
|
+ opmode |= FDMODE;
|
|
|
+ else
|
|
|
+ opmode &= ~(FDMODE);
|
|
|
+
|
|
|
+ bfin_write_EMAC_OPMODE(opmode);
|
|
|
+ lp->old_duplex = phydev->duplex;
|
|
|
+ }
|
|
|
|
|
|
- /* Program PHY registers */
|
|
|
- pr_debug("start setting up phy\n");
|
|
|
-
|
|
|
- /* issue a reset */
|
|
|
- raw_write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, 0x8000);
|
|
|
-
|
|
|
- /* wait half a second */
|
|
|
- msleep(500);
|
|
|
-
|
|
|
- phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL);
|
|
|
-
|
|
|
- /* advertise flow control supported */
|
|
|
- phydat = read_phy_reg(lp->PhyAddr, PHYREG_ANAR);
|
|
|
- phydat |= (1 << 10);
|
|
|
- write_phy_reg(lp->PhyAddr, PHYREG_ANAR, phydat);
|
|
|
+ if (phydev->speed != lp->old_speed) {
|
|
|
+#if defined(CONFIG_BFIN_MAC_RMII)
|
|
|
+ u32 opmode = bfin_read_EMAC_OPMODE();
|
|
|
+ bf537mac_disable();
|
|
|
+ switch (phydev->speed) {
|
|
|
+ case 10:
|
|
|
+ opmode |= RMII_10;
|
|
|
+ break;
|
|
|
+ case 100:
|
|
|
+ opmode &= ~(RMII_10);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING
|
|
|
+ "%s: Ack! Speed (%d) is not 10/100!\n",
|
|
|
+ DRV_NAME, phydev->speed);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bfin_write_EMAC_OPMODE(opmode);
|
|
|
+ bf537mac_enable();
|
|
|
+#endif
|
|
|
|
|
|
- phydat = 0;
|
|
|
- if (lp->Negotiate)
|
|
|
- phydat |= 0x1000; /* enable auto negotiation */
|
|
|
- else {
|
|
|
- if (lp->FullDuplex)
|
|
|
- phydat |= (1 << 8); /* full duplex */
|
|
|
- else
|
|
|
- phydat &= (~(1 << 8)); /* half duplex */
|
|
|
+ new_state = 1;
|
|
|
+ lp->old_speed = phydev->speed;
|
|
|
+ }
|
|
|
|
|
|
- if (!lp->Port10)
|
|
|
- phydat |= (1 << 13); /* 100 Mbps */
|
|
|
- else
|
|
|
- phydat &= (~(1 << 13)); /* 10 Mbps */
|
|
|
+ if (!lp->old_link) {
|
|
|
+ new_state = 1;
|
|
|
+ lp->old_link = 1;
|
|
|
+ netif_schedule(dev);
|
|
|
+ }
|
|
|
+ } else if (lp->old_link) {
|
|
|
+ new_state = 1;
|
|
|
+ lp->old_link = 0;
|
|
|
+ lp->old_speed = 0;
|
|
|
+ lp->old_duplex = -1;
|
|
|
}
|
|
|
|
|
|
- if (lp->Loopback)
|
|
|
- phydat |= (1 << 14); /* enable TX->RX loopback */
|
|
|
-
|
|
|
- write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, phydat);
|
|
|
- msleep(500);
|
|
|
-
|
|
|
- phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL);
|
|
|
- /* check for SMSC PHY */
|
|
|
- if ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID1) == 0x7) &&
|
|
|
- ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID2) & 0xfff0) == 0xC0A0)) {
|
|
|
- /*
|
|
|
- * we have SMSC PHY so reqest interrupt
|
|
|
- * on link down condition
|
|
|
- */
|
|
|
-
|
|
|
- /* enable interrupts */
|
|
|
- write_phy_reg(lp->PhyAddr, 30, 0x0ff);
|
|
|
+ if (new_state) {
|
|
|
+ u32 opmode = bfin_read_EMAC_OPMODE();
|
|
|
+ phy_print_status(phydev);
|
|
|
+ pr_debug("EMAC_OPMODE = 0x%08x\n", opmode);
|
|
|
}
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&lp->lock, flags);
|
|
|
}
|
|
|
|
|
|
-/**************************************************************************/
|
|
|
-void setup_system_regs(struct net_device *dev)
|
|
|
+static int mii_probe(struct net_device *dev)
|
|
|
{
|
|
|
- int phyaddr;
|
|
|
- unsigned short sysctl, phydat;
|
|
|
- u32 opmode;
|
|
|
struct bf537mac_local *lp = netdev_priv(dev);
|
|
|
- int count = 0;
|
|
|
-
|
|
|
- phyaddr = lp->PhyAddr;
|
|
|
+ struct phy_device *phydev = NULL;
|
|
|
+ unsigned short sysctl;
|
|
|
+ int i;
|
|
|
|
|
|
- /* Enable PHY output */
|
|
|
+ /* Enable PHY output early */
|
|
|
if (!(bfin_read_VR_CTL() & PHYCLKOE))
|
|
|
bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
|
|
|
|
|
|
/* MDC = 2.5 MHz */
|
|
|
- sysctl = SET_MDCDIV(24);
|
|
|
- /* Odd word alignment for Receive Frame DMA word */
|
|
|
- /* Configure checksum support and rcve frame word alignment */
|
|
|
-#if defined(BFIN_MAC_CSUM_OFFLOAD)
|
|
|
- sysctl |= RXDWA | RXCKS;
|
|
|
-#else
|
|
|
- sysctl |= RXDWA;
|
|
|
-#endif
|
|
|
+ sysctl = bfin_read_EMAC_SYSCTL();
|
|
|
+ sysctl |= SET_MDCDIV(24);
|
|
|
bfin_write_EMAC_SYSCTL(sysctl);
|
|
|
- /* auto negotiation on */
|
|
|
- /* full duplex */
|
|
|
- /* 100 Mbps */
|
|
|
- phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET;
|
|
|
- write_phy_reg(phyaddr, PHYREG_MODECTL, phydat);
|
|
|
|
|
|
- /* test if full duplex supported */
|
|
|
- do {
|
|
|
- msleep(100);
|
|
|
- phydat = read_phy_reg(phyaddr, PHYREG_MODESTAT);
|
|
|
- if (count > 30) {
|
|
|
- printk(KERN_NOTICE DRV_NAME ": Link is down\n");
|
|
|
- printk(KERN_NOTICE DRV_NAME
|
|
|
- "please check your network connection\n");
|
|
|
- break;
|
|
|
- }
|
|
|
- count++;
|
|
|
- } while (!(phydat & 0x0004));
|
|
|
+ /* search for connect PHY device */
|
|
|
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
|
|
|
+ struct phy_device *const tmp_phydev = lp->mii_bus.phy_map[i];
|
|
|
|
|
|
- phydat = read_phy_reg(phyaddr, PHYREG_ANLPAR);
|
|
|
+ if (!tmp_phydev)
|
|
|
+ continue; /* no PHY here... */
|
|
|
|
|
|
- if ((phydat & 0x0100) || (phydat & 0x0040)) {
|
|
|
- opmode = FDMODE;
|
|
|
- } else {
|
|
|
- opmode = 0;
|
|
|
- printk(KERN_INFO DRV_NAME
|
|
|
- ": Network is set to half duplex\n");
|
|
|
+ phydev = tmp_phydev;
|
|
|
+ break; /* found it */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* now we are supposed to have a proper phydev, to attach to... */
|
|
|
+ if (!phydev) {
|
|
|
+ printk(KERN_INFO "%s: Don't found any phy device at all\n",
|
|
|
+ dev->name);
|
|
|
+ return -ENODEV;
|
|
|
}
|
|
|
|
|
|
#if defined(CONFIG_BFIN_MAC_RMII)
|
|
|
- opmode |= RMII; /* For Now only 100MBit are supported */
|
|
|
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
|
|
|
+ PHY_INTERFACE_MODE_RMII);
|
|
|
+#else
|
|
|
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
|
|
|
+ PHY_INTERFACE_MODE_MII);
|
|
|
#endif
|
|
|
|
|
|
- bfin_write_EMAC_OPMODE(opmode);
|
|
|
+ if (IS_ERR(phydev)) {
|
|
|
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
|
|
|
+ return PTR_ERR(phydev);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* mask with MAC supported features */
|
|
|
+ phydev->supported &= (SUPPORTED_10baseT_Half
|
|
|
+ | SUPPORTED_10baseT_Full
|
|
|
+ | SUPPORTED_100baseT_Half
|
|
|
+ | SUPPORTED_100baseT_Full
|
|
|
+ | SUPPORTED_Autoneg
|
|
|
+ | SUPPORTED_Pause | SUPPORTED_Asym_Pause
|
|
|
+ | SUPPORTED_MII
|
|
|
+ | SUPPORTED_TP);
|
|
|
+
|
|
|
+ phydev->advertising = phydev->supported;
|
|
|
+
|
|
|
+ lp->old_link = 0;
|
|
|
+ lp->old_speed = 0;
|
|
|
+ lp->old_duplex = -1;
|
|
|
+ lp->phydev = phydev;
|
|
|
+
|
|
|
+ printk(KERN_INFO "%s: attached PHY driver [%s] "
|
|
|
+ "(mii_bus:phy_addr=%s, irq=%d)\n",
|
|
|
+ DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**************************************************************************/
|
|
|
+void setup_system_regs(struct net_device *dev)
|
|
|
+{
|
|
|
+ unsigned short sysctl;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Odd word alignment for Receive Frame DMA word
|
|
|
+ * Configure checksum support and rcve frame word alignment
|
|
|
+ */
|
|
|
+ sysctl = bfin_read_EMAC_SYSCTL();
|
|
|
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
|
|
|
+ sysctl |= RXDWA | RXCKS;
|
|
|
+#else
|
|
|
+ sysctl |= RXDWA;
|
|
|
+#endif
|
|
|
+ bfin_write_EMAC_SYSCTL(sysctl);
|
|
|
|
|
|
bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
|
|
|
|
|
@@ -686,18 +740,18 @@ static void bf537mac_disable(void)
|
|
|
/*
|
|
|
* Enable Interrupts, Receive, and Transmit
|
|
|
*/
|
|
|
-static int bf537mac_enable(struct net_device *dev)
|
|
|
+static void bf537mac_enable(void)
|
|
|
{
|
|
|
u32 opmode;
|
|
|
|
|
|
- pr_debug("%s: %s\n", dev->name, __FUNCTION__);
|
|
|
+ pr_debug("%s: %s\n", DRV_NAME, __FUNCTION__);
|
|
|
|
|
|
/* Set RX DMA */
|
|
|
bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));
|
|
|
bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);
|
|
|
|
|
|
/* Wait MII done */
|
|
|
- poll_mdc_done();
|
|
|
+ mdio_poll();
|
|
|
|
|
|
/* We enable only RX here */
|
|
|
/* ASTP : Enable Automatic Pad Stripping
|
|
@@ -721,8 +775,6 @@ static int bf537mac_enable(struct net_device *dev)
|
|
|
#endif
|
|
|
/* Turn on the EMAC rx */
|
|
|
bfin_write_EMAC_OPMODE(opmode);
|
|
|
-
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
/* Our watchdog timed out. Called by the networking layer */
|
|
@@ -735,7 +787,7 @@ static void bf537mac_timeout(struct net_device *dev)
|
|
|
/* reset tx queue */
|
|
|
tx_list_tail = tx_list_head->next;
|
|
|
|
|
|
- bf537mac_enable(dev);
|
|
|
+ bf537mac_enable();
|
|
|
|
|
|
/* We can accept TX packets again */
|
|
|
dev->trans_start = jiffies;
|
|
@@ -789,6 +841,7 @@ static void bf537mac_shutdown(struct net_device *dev)
|
|
|
*/
|
|
|
static int bf537mac_open(struct net_device *dev)
|
|
|
{
|
|
|
+ struct bf537mac_local *lp = netdev_priv(dev);
|
|
|
int retval;
|
|
|
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
|
|
|
|
|
@@ -808,10 +861,10 @@ static int bf537mac_open(struct net_device *dev)
|
|
|
if (retval)
|
|
|
return retval;
|
|
|
|
|
|
- bf537mac_setphy(dev);
|
|
|
+ phy_start(lp->phydev);
|
|
|
setup_system_regs(dev);
|
|
|
bf537mac_disable();
|
|
|
- bf537mac_enable(dev);
|
|
|
+ bf537mac_enable();
|
|
|
|
|
|
pr_debug("hardware init finished\n");
|
|
|
netif_start_queue(dev);
|
|
@@ -828,11 +881,14 @@ static int bf537mac_open(struct net_device *dev)
|
|
|
*/
|
|
|
static int bf537mac_close(struct net_device *dev)
|
|
|
{
|
|
|
+ struct bf537mac_local *lp = netdev_priv(dev);
|
|
|
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
|
|
|
|
|
|
netif_stop_queue(dev);
|
|
|
netif_carrier_off(dev);
|
|
|
|
|
|
+ phy_stop(lp->phydev);
|
|
|
+
|
|
|
/* clear everything */
|
|
|
bf537mac_shutdown(dev);
|
|
|
|
|
@@ -846,6 +902,7 @@ static int __init bf537mac_probe(struct net_device *dev)
|
|
|
{
|
|
|
struct bf537mac_local *lp = netdev_priv(dev);
|
|
|
int retval;
|
|
|
+ int i;
|
|
|
|
|
|
/* Grab the MAC address in the MAC */
|
|
|
*(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
|
|
@@ -862,7 +919,6 @@ static int __init bf537mac_probe(struct net_device *dev)
|
|
|
|
|
|
/* set the GPIO pins to Ethernet mode */
|
|
|
retval = setup_pin_mux(1);
|
|
|
-
|
|
|
if (retval)
|
|
|
return retval;
|
|
|
|
|
@@ -880,6 +936,23 @@ static int __init bf537mac_probe(struct net_device *dev)
|
|
|
|
|
|
setup_mac_addr(dev->dev_addr);
|
|
|
|
|
|
+ /* MDIO bus initial */
|
|
|
+ lp->mii_bus.priv = dev;
|
|
|
+ lp->mii_bus.read = mdiobus_read;
|
|
|
+ lp->mii_bus.write = mdiobus_write;
|
|
|
+ lp->mii_bus.reset = mdiobus_reset;
|
|
|
+ lp->mii_bus.name = "bfin_mac_mdio";
|
|
|
+ lp->mii_bus.id = 0;
|
|
|
+ lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
|
|
|
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
|
|
|
+ lp->mii_bus.irq[i] = PHY_POLL;
|
|
|
+
|
|
|
+ mdiobus_register(&lp->mii_bus);
|
|
|
+
|
|
|
+ retval = mii_probe(dev);
|
|
|
+ if (retval)
|
|
|
+ return retval;
|
|
|
+
|
|
|
/* Fill in the fields of the device structure with ethernet values. */
|
|
|
ether_setup(dev);
|
|
|
|
|
@@ -893,13 +966,6 @@ static int __init bf537mac_probe(struct net_device *dev)
|
|
|
dev->poll_controller = bf537mac_poll;
|
|
|
#endif
|
|
|
|
|
|
- /* fill in some of the fields */
|
|
|
- lp->version = 1;
|
|
|
- lp->PhyAddr = 0x01;
|
|
|
- lp->CLKIN = 25;
|
|
|
- lp->FullDuplex = 0;
|
|
|
- lp->Negotiate = 1;
|
|
|
- lp->FlowControl = 0;
|
|
|
spin_lock_init(&lp->lock);
|
|
|
|
|
|
/* now, enable interrupts */
|
|
@@ -912,9 +978,6 @@ static int __init bf537mac_probe(struct net_device *dev)
|
|
|
return -EBUSY;
|
|
|
}
|
|
|
|
|
|
- /* Enable PHY output early */
|
|
|
- if (!(bfin_read_VR_CTL() & PHYCLKOE))
|
|
|
- bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
|
|
|
|
|
|
retval = register_netdev(dev);
|
|
|
if (retval == 0) {
|