summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c806
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.c32
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/mdio_bus.c5
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/phy_device.c2
4 files changed, 374 insertions, 471 deletions
diff --git a/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c b/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c
index e73a76b148..89c997844f 100644
--- a/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c
+++ b/cleopatre/linux-2.6.25.10-spc300/drivers/net/arm/synop3504.c
@@ -27,7 +27,7 @@
*/
#define DRV_NAME "Synop3504"
-#define DRV_VERSION "2.4"
+#define DRV_VERSION "3.1"
#define DRV_RELDATE "nov 17, 2009"
//#define TRACE_FRAME 1
@@ -49,6 +49,7 @@
#include <asm/cacheflush.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/phy.h>
#include <linux/dma-mapping.h>
#include <linux/kthread.h>
@@ -108,10 +109,6 @@ struct dma_rx
/** Private structure for our net device */
struct net_priv
{
- uint32_t phy_id;
- uint32_t phy_oui;
- uint32_t phy_model;
- uint32_t phy_rev;
uint32_t gmac_addr;
uint32_t dma_addr;
uint32_t support_gmii;
@@ -122,10 +119,14 @@ struct net_priv
struct net_device_stats stats;
struct dma_tx tx;
struct dma_rx rx;
- struct timer_list timer;
struct napi_struct napi;
struct net_device *dev;
struct platform_device *pdev;
+ struct mii_bus *mii_bus;
+ struct phy_device *phydev;
+ unsigned int link;
+ unsigned int speed;
+ unsigned int duplex;
};
/** How many Tx buffers to clean */
@@ -251,7 +252,7 @@ const struct ethtool_ops synop3504_ethtool_ops = {
.set_msglevel = synop3504_set_msglevel,*/
};
-/**
+/**
* Read a MII register.
* \param dev device structure.
* \param phy phy addr (not used for us).
@@ -453,315 +454,6 @@ static void synop3504_rxdesc_reset(struct net_device *dev)
}// synop3504_rxdesc_reset
-
-/**
- * What to do when a link up appears.
- *
- * \param dev device structure.
- */
-static void synop3504_on_link_up(struct net_device *dev)
-{
- struct net_priv *priv = (struct net_priv *)dev->priv;
- Synopsys *synop = &priv->synop;
- volatile uint32_t status, estatus, negotiated;
- int speed=0;
- int fdx=0;
-
- //Check PHY model
- if((priv->phy_oui == OUI_ICPLUS) &&
- (priv->phy_model == ICPLUS_MODEL_IP175) &&
- (priv->phy_addr == 5))
- {
- //IP175 switch on MAC5 no autoneg capability, force link
- printk("100Mbs full duplex link forced\n");
- fdx = 1;
- speed = 100;
- }
- else
- {
- //Find ETH speed and duplex for DMA config
- status = mdio_read(dev, priv->phy_addr, MII_BMSR);
- estatus = mdio_read(dev, priv->phy_addr, MII_ESTATUS);
-
- if((status & BMSR_ESTATEN) &&
- ((estatus & ESTATUS_1000_TFULL) || (estatus & ESTATUS_1000_THALF)))
- { //PHY can manage GIGA bits
- negotiated = mdio_read(dev, priv->phy_addr, MII_STAT1000);
-
- if(negotiated & LPA_1000FULL)
- {
- printk("1000Mbs full duplex link detected\n");
- fdx = 1;
- speed = 1000;
- }
- else if(negotiated & LPA_1000HALF)
- {
- printk("1000Mbs half duplex link detected\n");
- fdx = 0;
- speed = 1000;
- }
- }
-
- if(speed == 0)
- { //No GIGA Bits detected
- negotiated = mdio_read(dev, priv->phy_addr, MII_LPA);
-
- if(negotiated & LPA_100FULL)
- {
- printk("100Mbs full duplex link detected\n");
- fdx = 1;
- speed = 100;
- }
- else if(negotiated & LPA_100HALF)
- {
- printk("100Mbs half duplex link detected\n");
- fdx = 0;
- speed = 100;
- }
- else if(negotiated & LPA_10FULL)
- {
- printk("10Mbs full duplex link detected\n");
- fdx = 1;
- speed = 10;
- }
- else
- {
- printk("10Mbs half duplex link detected\n");
- fdx = 0;
- speed = 10;
- }
- }
- }
-
- SynopsysSetMiiClkCap(synop, speed);
- SynopsysSetSpeedDuplex(synop, speed, fdx);
- priv->mii_if.full_duplex = fdx;
-
- //Start TX and RX DMA
- SynopsysStartTx(synop);
- SynopsysStartRx(synop);
-
- //Enable Interrupts
- SynopsysEnableInt(synop);
-}// synop3504_on_link_up
-
-/**
- * What to do when a link down appears.
- *
- * \param dev device structure.
- */
-static void synop3504_on_link_down(struct net_device *dev)
-{
- struct net_priv *priv = (struct net_priv *)dev->priv;
- Synopsys *synop = &priv->synop;
-
- //Disable Interrupts
- SynopsysDisableInt(synop);
-
- //Stop RX and TX
- SynopsysStopRx(synop);
- SynopsysStopTx(synop);
-
- //Reset descriptors
- synop3504_txdesc_reset(dev);
- synop3504_rxdesc_reset(dev);
-
- //Force PHY communication mode to GMII if allowed
- SynopsysSetMiiClkCap(synop, 1000);
-
-}// synop3504_on_link_down
-
-/**
- * Enable Auto-Negotiation for PHY.
- * \param dev device structure.
- */
-static void synop3504_enable_autonegotiation(struct net_device *dev)
-{
- volatile uint32_t data;
- volatile uint32_t estatus;
- struct net_priv *priv = NULL;
-
- //Check pointer
- if(dev == NULL)
- return;
- priv = (struct net_priv *)dev->priv;
- if(priv == NULL)
- return;
-
-#ifdef CONFIG_MACH_ARIZONA
- //Force hardware to be 10M FULL just for first tests
- //Disable Auto-Negotiation
- data = mdio_read(dev, priv->phy_addr, MII_BMCR);
- data &= ~BMCR_ANENABLE;
- mdio_write(dev, priv->phy_addr, MII_BMCR, data);
-
- //Force 10M Full Duplex
- data = mdio_read(dev, priv->phy_addr, MII_BMCR);
- data &= ~BMCR_SPEED100;
- data |= BMCR_FULLDPLX;
- mdio_write(dev, priv->phy_addr, MII_BMCR, data);
-#else
- //Ensure that PHY is Auto-Negotiation capable
- if (mdio_read(dev, priv->phy_addr, MII_BMSR) & BMSR_ANEGCAPABLE)
- {
- //Disable Auto-Negotiation
- data = mdio_read(dev, priv->phy_addr, MII_BMCR);
- data &= ~BMCR_ANENABLE;
- mdio_write(dev, priv->phy_addr, MII_BMCR, data);
-
- //Set Auto-Negotiation advertisement register - all techs
- data = mdio_read(dev, priv->phy_addr, MII_ADVERTISE);
- data |= ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL;
- mdio_write(dev, priv->phy_addr, MII_ADVERTISE, data);
-
- //Check Giga bits capabilities
- if((mdio_read(dev, priv->phy_addr, MII_BMSR)) & BMSR_ESTATEN)
- {
- estatus = mdio_read(dev, priv->phy_addr, MII_ESTATUS);
- data = mdio_read(dev, priv->phy_addr, MII_CTRL1000);
-
- if(estatus & ESTATUS_1000_TFULL)
- data |= ADVERTISE_1000FULL;
- if(estatus & ESTATUS_1000_THALF)
- data |= ADVERTISE_1000HALF;
-
- mdio_write(dev, priv->phy_addr, MII_STAT1000, data);
- }
-
- //Kick Auto-Negotiation
- data = mdio_read(dev, priv->phy_addr, MII_BMCR);
- data |= BMCR_ANENABLE;
- mdio_write(dev, priv->phy_addr, MII_BMCR, data);
- }
-#endif
-}// synop3504_enable_autonegotiation
-
-/**
- * Delay for thread.
- * \param msec value of the delay in ms.
- */
-static inline void mdly (unsigned int msec)
-{
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout((msec + MSEC_PER_JIFFY - 1) / MSEC_PER_JIFFY);
-}//mdly
-
-/**
- * Start Auto-Negotiation procedure.
- * \param dev device structure.
- * \param wait wait Auto-Negotiation ending or not.
- * \return error code.
- */
-static int synop3504_autonegotiate(struct net_device *dev, int wait)
-{
- struct net_priv *priv = NULL;
-
- //Check pointer
- if(dev == NULL)
- return -1;
- priv = (struct net_priv *)dev->priv;
- if(priv == NULL)
- return -1;
-
-#ifdef CONFIG_MACH_ARIZONA
- //Only start link up because the link is forced to 10M FULL
- synop3504_on_link_up(dev);
- netif_carrier_on(dev);
- netif_start_queue(dev);
-#else
- //Start the Auto-Negotiation
- if(mdio_read(dev, priv->phy_addr, MII_BMSR) & BMSR_ANEGCAPABLE)
- {
- TRACE("starting AutoNegotiation for %s\n", dev->name);
- //Kick Auto Negotiation
- mii_nway_restart(&priv->mii_if);
-
- //Wait Auto-Negotiation ending
- if(wait)
- {
- int timeout = AUTONEG_TIMEOUT * 1000 / AUTONEG_STEP;
- volatile uint32_t data;
- do
- {
- mdly(AUTONEG_STEP);
- data = mdio_read(dev, priv->phy_addr, MII_BMSR);
- } while(!(data & BMSR_ANEGCOMPLETE) && timeout--);
-
- if(timeout <= 0)
- {
- printk(KERN_WARNING DRV_NAME ": AutoNegotiation timed out after %d s for %s\n", AUTONEG_TIMEOUT, dev->name);
- return -1;
- }
- else
- {
- TRACE("AutoNegotiation complete after %d ms for %s\n", AUTONEG_TIMEOUT * 1000 - timeout * AUTONEG_STEP, dev->name);
- }
- synop3504_on_link_up(dev);
- netif_carrier_on(dev);
- netif_start_queue(dev);
- }
- }
-#endif
-
- return 0;
-}// synop3504_autonegotiate
-
-/**
- * Poll the link status to check connexion/unconnexion.
- * \param data device structure.
- */
-static void synop3504_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct net_priv *priv = NULL;
-
- //Check pointer
- if(dev == NULL)
- {
- printk(KERN_ERR DRV_NAME": Error with timer parameter\n");
- return;
- }
- priv = (struct net_priv *)dev->priv;
- if(priv == NULL)
- {
- printk(KERN_ERR DRV_NAME": Error with timer parameter\n");
- return;
- }
-
- if(!(mdio_read(dev, priv->phy_addr, MII_BMSR) & BMSR_LSTATUS))
- {
- if(netif_carrier_ok(dev))
- {
- //OK LINK DOWN.
- printk(DRV_NAME ": %s: " "Link DOWN\n", dev->name);
- netif_stop_queue(dev);
- netif_carrier_off(dev);
- synop3504_on_link_down(dev);
- }
- else
- {
-// TRACE("%s: Link still down\n", dev->name);
- }
- }
- else
- {
- if(!netif_carrier_ok(dev))
- {
- //OK LINK UP.
- printk(DRV_NAME ": %s: Link UP\n", dev->name);
- synop3504_on_link_up(dev);
- netif_carrier_on(dev);
- netif_wake_queue(dev);
- }
- else
- {
-// TRACE("%s: Link still up\n", dev->name);
- }
- }
- mod_timer(&priv->timer, jiffies + TIMEOUT);
-}//synop3504_timer
-
-
/**
* Read packet status from the device.
* \param dev device structure.
@@ -942,7 +634,8 @@ static int synop3504_ethtool_ioctl(struct net_device *dev, void *useraddr)
//Restart Auto-Negotiation
case ETHTOOL_NWAY_RST:
{
- return synop3504_autonegotiate(dev, 1);
+ /*TODO return synop3504_autonegotiate(dev, 1);*/
+ return 0;
}
//Get link status
case ETHTOOL_GLINK:
@@ -1005,100 +698,6 @@ static int synop3504_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}// synop3504_ioctl
/**
- * Read the PHY MII registers by /proc.
- *
- * \param file file structure.
- * \param buffer string pointer given by user.
- * \param start string pointer begin.
- * \param offset offset value.
- * \param count count parameter.
- * \param eof end of file.
- * \param data network device structure.
- * \return new pointer position.
- */
-static int synop3504_readproc_mii(char *buf, char **start, off_t offset, int count, int *eof, void *data)
-{
- int phy_begin, phy_end, phy_addr;
- struct net_device *dev = (struct net_device *)data;
- struct net_priv *priv = dev->priv;
- int reg;
- uint16_t val;
- char *p;
-
- p = buf;
-
- if((priv->phy_oui == OUI_ICPLUS) && (priv->phy_model == ICPLUS_MODEL_IP175))
- {
- phy_begin = 0;
- phy_end = 5;
- }
- else
- {
- phy_begin = priv->phy_addr;
- phy_end = priv->phy_addr;
- }
-
- for(phy_addr=phy_begin ; phy_addr<=phy_end ; phy_addr++)
- {
- for(reg=0 ; reg<=31 ; reg++)
- {
- val = mdio_read(dev, phy_addr, reg);
- p += sprintf(p, "PHY%d REG%-2d 0x%04x\n", phy_addr, reg, val);
- }
- }
-
- if((priv->phy_oui == OUI_ICPLUS) && (priv->phy_model == ICPLUS_MODEL_IP175))
- {
- for(phy_addr=20 ; phy_addr<=26 ; phy_addr++)
- {
- p += sprintf(p,"\n");
- for(reg=0 ; reg<=31 ; reg++)
- {
- val = mdio_read(dev, phy_addr, reg);
- p += sprintf(p, "PHY%d REG%-2d 0x%04x\n", phy_addr, reg, val);
- }
- }
- for(phy_addr=29 ; phy_addr<=31 ; phy_addr++)
- {
- p += sprintf(p,"\n");
- for(reg=0 ; reg<=31 ; reg++)
- {
- val = mdio_read(dev, phy_addr, reg);
- p += sprintf(p, "PHY%d REG%-2d 0x%04x\n", phy_addr, reg, val);
- }
- }
- }
-
- *eof = 1;
- return p-buf+1;
-}
-
-/**
- * Write into PHY MII registers by /proc.
- *
- * \param file file structure.
- * \param buffer string pointer given by user.
- * \param count count parameter.
- * \param data network device structure.
- * \return counter value.
- */
-static int synop3504_writeproc_mii(struct file *file, const char *buffer, unsigned long count, void *data)
-{
- struct net_device *dev = (struct net_device *)data;
- unsigned int reg;
- int value;
- int phy;
-
- if(sscanf(buffer,"PHY%d REG%u %i",&phy, &reg, &value) == 3)
- {
- mdio_write(dev, phy, reg, value);
- printk("Sent PHY%d REG%d 0x%04x\n", phy, reg, value);
- }
-
- return count;
-}
-
-/**
* transmit frame procedure.
* \param skb frame structure.
* \param dev device structure.
@@ -1497,57 +1096,311 @@ static irqreturn_t synop3504_interrupt(int irq, void * dev_id)
return IRQ_HANDLED;
}// synop3504_interrupt
+
+/**
+ * Read a MII register.
+ * \param bus mii_bus structure.
+ * \param phy_id phy addr (not used for us).
+ * \param regnum register to write.
+ * \return value read.
+ */
+static int mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+ return mdio_read(((struct net_priv *)(bus->priv))->dev, phy_id, regnum);
+}
+
+/**
+ * Write a MII register.
+ * \param bus mii_bus structure.
+ * \param phy_id phy addr (not used for us).
+ * \param regnum register to write.
+ * \param val value to write.
+ */
+static int mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
+{
+ mdio_write(((struct net_priv *)(bus->priv))->dev, phy_id, regnum, val);
+ return 0;
+}
+
+/**
+ * Read the PHY MII registers by /proc.
+ *
+ * \param file file structure.
+ * \param buffer string pointer given by user.
+ * \param start string pointer begin.
+ * \param offset offset value.
+ * \param count count parameter.
+ * \param eof end of file.
+ * \param data network device structure.
+ * \return new pointer position.
+ */
+static int synop3504_readproc_mii(char *buf, char **start, off_t offset, int count, int *eof, void *data)
+{
+ struct phy_device *phydev = (struct phy_device *)data;
+ int reg;
+ uint16_t val;
+ char *p;
+
+ p = buf;
+
+ for(reg=0 ; reg<=31 ; reg++)
+ {
+ val = mdiobus_read(phydev->bus, phydev->addr, reg);
+ p += sprintf(p, "PHY%d REG%-2d 0x%04x\n", phydev->addr, reg, val);
+ }
+
+ *eof = 1;
+ return p-buf+1;
+}
+
+/**
+ * Write into PHY MII registers by /proc.
+ *
+ * \param file file structure.
+ * \param buffer string pointer given by user.
+ * \param count count parameter.
+ * \param data network device structure.
+ * \return counter value.
+ */
+static int synop3504_writeproc_mii(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ struct phy_device *phydev = (struct phy_device *)data;
+ unsigned int reg;
+ int value;
+
+ if(sscanf(buffer,"REG%u %i", &reg, &value) == 2)
+ {
+ mdiobus_write(phydev->bus, phydev->addr, reg, value);
+ printk("Sent PHY%d REG%d 0x%04x\n", phydev->addr, reg, value);
+ }
+
+ return count;
+}
+
+/**
+ * Link up config.
+ * \param dev device structure.
+ */
+static void synop3504_on_link_up(struct net_device *dev)
+{
+ struct net_priv *priv = (struct net_priv *)dev->priv;
+ Synopsys *synop = &priv->synop;
+
+ //Start TX and RX DMA
+ SynopsysStartTx(synop);
+ SynopsysStartRx(synop);
+
+ //Enable Interrupts
+ SynopsysEnableInt(synop);
+
+ //restart transmit
+ netif_carrier_on(dev);
+ netif_wake_queue(dev);
+
+}// synop3504_on_link_up
+
+/**
+ * Link down config.
+ * \param dev device structure.
+ */
+static void synop3504_on_link_down(struct net_device *dev)
+{
+ struct net_priv *priv = (struct net_priv *)dev->priv;
+ Synopsys *synop = &priv->synop;
+
+ //stop transmitted packets
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+ //Disable Interrupts
+ SynopsysDisableInt(synop);
+
+ //Stop RX and TX
+ SynopsysStopRx(synop);
+ SynopsysStopTx(synop);
+
+ //Reset descriptors
+ synop3504_txdesc_reset(dev);
+ synop3504_rxdesc_reset(dev);
+
+}// synop3504_on_link_down
+
+
/**
- * Find PHY reference.
+ * Link change callback.
* \param dev device structure.
*/
-static void synop3504_find_phy_ref(struct net_device *dev)
+static void synop3504_handle_link_change(struct net_device *dev)
{
struct net_priv *priv = NULL;
+ Synopsys *synop = NULL;
+ struct phy_device *phydev = NULL;
+ int status_change = 0;
//Check pointers
if(dev == NULL)
return;
- priv = (struct net_priv *)dev->priv;
+ priv = netdev_priv(dev);
if(priv == NULL)
return;
+ synop = &priv->synop;
+ if(synop == NULL)
+ return;
+ phydev = priv->phydev;
+ if (phydev == NULL)
+ return;
- //Find PHY identifier
- priv->phy_id = PHYSID_GET_ID(mdio_read(dev, priv->phy_addr, MII_PHYSID1), mdio_read(dev, priv->phy_addr, MII_PHYSID2));
-
- //PHY identifier not found, but it can be a switch IP175 so let's check at
- //phy_addr 0
- if(0 == priv->phy_id)
+ if (phydev->link)
{
- priv->phy_id = PHYSID_GET_ID(mdio_read(dev, 0, MII_PHYSID1), mdio_read(dev, 0, MII_PHYSID2));
-
- if((OUI_ICPLUS != PHYSID_GET_OUI(priv->phy_id)) || (ICPLUS_MODEL_IP175 != PHYSID_GET_MODEL(priv->phy_id)))
+ if ((priv->speed != phydev->speed) || (priv->duplex != phydev->duplex))
{
- priv->phy_id = 0;
- printk(DRV_NAME ": PHY ID not found for %s\n", dev->name);
- return;
+ SynopsysSetMiiClkCap(synop, phydev->speed);
+ SynopsysSetSpeedDuplex(synop, phydev->speed, phydev->duplex);
+ priv->mii_if.full_duplex = phydev->duplex;
+ priv->speed = phydev->speed;
+ priv->duplex = phydev->duplex;
+ status_change = 1;
}
}
- priv->phy_oui = PHYSID_GET_OUI(priv->phy_id);
- priv->phy_model = PHYSID_GET_MODEL(priv->phy_id);
- priv->phy_rev = PHYSID_GET_REV(priv->phy_id);
-
- if((OUI_ICPLUS == priv->phy_oui) && (ICPLUS_MODEL_IP175 == priv->phy_model))
+ //link change
+ if (phydev->link != priv->link)
{
- if(0x175D == mdio_read (dev, 20, 0))
+ if (phydev->link)
{
- printk(DRV_NAME ": PHY for %s is IC+ IP175D rev %u\n", dev->name, priv->phy_rev);
+ //link up
+ synop3504_on_link_up(dev);
}
else
{
- printk(DRV_NAME ": PHY for %s is IC+ IP175C rev %u\n", dev->name, priv->phy_rev);
+ //link down
+ synop3504_on_link_down(dev);
+ //Force PHY communication mode to GMII if allowed
+ SynopsysSetMiiClkCap(synop, 1000);
+ priv->speed = 0;
+ priv->duplex = -1;
}
+
+ priv->link = phydev->link;
+ status_change = 1;
+ }
+
+ if (status_change)
+ {
+ if (phydev->link)
+ printk(KERN_ERR DRV_NAME": %s: link up (%d/%s)\n", dev->name, phydev->speed, DUPLEX_FULL == phydev->duplex ? "Full":"Half");
+ else
+ printk(KERN_ERR DRV_NAME": %s: link down\n", dev->name);
+ }
+}
+
+/**
+ * Connect the PHY
+ * \param dev device structure.
+ * \return error code.
+ */
+static int synop3504_mii_probe(struct net_device *dev)
+{
+ struct net_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+ struct synop3504_platform_data *pdata;
+
+ // Get phy addr from NVRAM data
+ pdata = priv->pdev->dev.platform_data;
+ phydev = priv->mii_bus->phy_map[pdata->phy_addr];
+
+ if (!phydev)
+ {
+ printk (KERN_ERR "%s: no PHY found\n", dev->name);
+ return -1;
+ }
+
+ // attach the mac to the phy
+ if (pdata && pdata->support_gmii)
+ {
+ phydev = phy_connect(dev, phydev->dev.bus_id, &synop3504_handle_link_change, 0, PHY_INTERFACE_MODE_GMII);
}
- else if(priv->phy_oui == OUI_ICPLUS && priv->phy_model == ICPLUS_MODEL_IP1001)
- printk(DRV_NAME ": PHY for %s is IC+ IP1001 rev %u\n", dev->name, priv->phy_rev);
else
- printk(DRV_NAME ": PHY ID for %s id is 0x%8.8x\n", dev->name, priv->phy_id);
+ {
+ if (pdata && pdata->support_rmii)
+ phydev = phy_connect(dev, phydev->dev.bus_id, &synop3504_handle_link_change, 0, PHY_INTERFACE_MODE_RMII);
+ else
+ phydev = phy_connect(dev, phydev->dev.bus_id, &synop3504_handle_link_change, 0, PHY_INTERFACE_MODE_MII);
+ }
+
+ 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 &= PHY_GBIT_FEATURES;
+ phydev->advertising = phydev->supported;
+
+ priv->link = 0;
+ priv->speed = 0;
+ priv->duplex = -1;
+ priv->phydev = phydev;
+
+ return 0;
+}
+
+/**
+ * Initialize the MDIO Bus.
+ * \param dev device structure.
+ * \return error code.
+ */
+static int synop3504_mii_init(struct net_device *dev)
+{
+ struct net_priv *priv = netdev_priv(dev);
+ int err = -ENXIO, i;
+
+ if (NULL == priv)
+ return -EINVAL;
+
+ priv->mii_bus = kzalloc(sizeof(*(priv->mii_bus)), GFP_KERNEL);
+ if (NULL == priv->mii_bus)
+ {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ priv->mii_bus->name = "SYNOP3504 MII Bus";
+ priv->mii_bus->read = &mdiobus_read;
+ priv->mii_bus->write = &mdiobus_write;
+ priv->mii_bus->id = priv->pdev->id;
+ priv->mii_bus->priv = priv;
+ priv->mii_bus->dev = &priv->dev->dev;
+ priv->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+
+ if (NULL == priv->mii_bus->irq)
+ {
+ err = -ENOMEM;
+ goto err_out_free_mdio_bus;
+ }
+
+ for(i = 0; i < PHY_MAX_ADDR; ++i)
+ priv->mii_bus->irq[i] = PHY_POLL;
+
+ platform_set_drvdata(priv->dev, &priv->mii_bus);
+
+ if (mdiobus_register(priv->mii_bus))
+ goto err_out_free_mdio_irq;
+
+ if (synop3504_mii_probe(priv->dev) != 0)
+ goto err_out_unregister_bus;
+
+ return 0;
+
+err_out_unregister_bus:
+ mdiobus_unregister(priv->mii_bus);
+err_out_free_mdio_irq:
+ kfree(priv->mii_bus->irq);
+err_out_free_mdio_bus:
+ kfree(priv->mii_bus);
+err_out:
+ return err;
}
/**
@@ -1569,6 +1422,8 @@ static int synop3504_open(struct net_device *dev)
synop = &priv->synop;
if(synop == NULL)
return -1;
+ if (!priv->phydev)
+ return -EAGAIN;
TRACE("%s: open\n", dev->name);
@@ -1579,9 +1434,6 @@ static int synop3504_open(struct net_device *dev)
mdio_write(dev, priv->phy_addr, MII_BMCR, BMCR_RESET);
while(mdio_read(dev, priv->phy_addr, MII_BMCR) & BMCR_RESET);
- //Check PHY ID
- synop3504_find_phy_ref(dev);
-
//Initialise DMA descriptors
synop3504_txdesc_init(dev);
synop3504_rxdesc_init(dev);
@@ -1592,18 +1444,11 @@ static int synop3504_open(struct net_device *dev)
//Set MAC address to synopsys hardware
SynopsysSetupEthernetAddress(synop, dev->dev_addr);
- //Activate Auto-Negotiation
- synop3504_enable_autonegotiation(dev);
-
//Prepare Linux as link down
- netif_stop_queue(dev);
- netif_carrier_off(dev);
-
- //Prepare hardware as link down
synop3504_on_link_down(dev);
- //Start Auto-Negotiation
- synop3504_autonegotiate(dev, 0);
+ //Force PHY communication mode to GMII if allowed
+ SynopsysSetMiiClkCap(synop, 1000);
//Request irq
if(request_irq(dev->irq, synop3504_interrupt, 0, dev->name, dev) != 0)
@@ -1615,9 +1460,10 @@ static int synop3504_open(struct net_device *dev)
//Start NAPI
napi_enable(&priv->napi);
- //Auto-Negotiation polling will be started in timer thread immediately
- priv->timer.expires = jiffies;
- add_timer(&priv->timer);
+ /* schedule a link state check */
+ phy_start(priv->phydev);
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
return 0;
}// synop3504_open
@@ -1651,8 +1497,9 @@ static int synop3504_stop(struct net_device *dev)
//Stop NAPI
napi_disable(&priv->napi);
- //Stop timer thread
- del_timer_sync(&priv->timer);
+ //Stop PHY
+ if (priv->phydev)
+ phy_stop(priv->phydev);
//Disable Interrupts
SynopsysDisableInt(synop);
@@ -1736,11 +1583,6 @@ static int synop3504_init(struct net_device *dev)
priv->mii_if.phy_id_mask = 0x1F;
priv->mii_if.reg_num_mask = 0x1F;
- //Initialise timer thread
- init_timer(&priv->timer);
- priv->timer.data = (unsigned long) dev;
- priv->timer.function = synop3504_timer;
-
return 0;
}// synop3504_init
@@ -1758,8 +1600,10 @@ static int __init synop3504_module_probe(struct platform_device *pdev)
struct net_device *dev = NULL;
struct net_priv *priv;
struct synop3504_platform_data *pdata;
- struct proc_dir_entry *eth_dir;
+ struct proc_dir_entry *phy_dir;
struct proc_dir_entry *entry;
+ int i;
+ char buf[10];
printk("%s", version);
@@ -1844,16 +1688,32 @@ static int __init synop3504_module_probe(struct platform_device *pdev)
goto err_out_free_dev;
}
+ if (synop3504_mii_init(dev) != 0)
+ {
+ goto err_out_unregister_netdev;
+ }
+
//Create a proc entry for MII
- eth_dir = proc_mkdir("eth", init_net.proc_net);
- entry = create_proc_entry("mii", 0, eth_dir);
- entry->read_proc = synop3504_readproc_mii;
- entry->write_proc = synop3504_writeproc_mii;
- entry->data = (int*)dev;
+ phy_dir = proc_mkdir("phy", init_net.proc_net);
+
+ for(i = 0; i < PHY_MAX_ADDR; i++)
+ {
+ if (priv->mii_bus->phy_map[i])
+ {
+ sprintf(buf, "phy%d", i);
+ entry = create_proc_entry(buf, 0, phy_dir);
+ entry->read_proc = synop3504_readproc_mii;
+ entry->write_proc = synop3504_writeproc_mii;
+ entry->data = (int*)(priv->mii_bus->phy_map[i]);
+ }
+ }
platform_set_drvdata(pdev, dev);
+
return 0;
+err_out_unregister_netdev:
+ unregister_netdev(dev);
err_out_free_dev:
kfree(dev->priv);
free_netdev(dev);
@@ -1873,6 +1733,8 @@ static void __exit synop3504_module_remove(struct platform_device *pdev)
{
struct net_device *dev;
struct net_priv *priv;
+ int i;
+ char buf[15];
dev = platform_get_drvdata(pdev);
@@ -1880,6 +1742,12 @@ static void __exit synop3504_module_remove(struct platform_device *pdev)
{
//Freeing private field of the net device structure
priv = netdev_priv(dev);
+ if (priv->phydev)
+ phy_disconnect(priv->phydev);
+ mdiobus_unregister(priv->mii_bus);
+ kfree(priv->mii_bus->irq);
+ kfree(priv->mii_bus);
+
if(priv)
kfree(priv);
@@ -1890,8 +1758,12 @@ static void __exit synop3504_module_remove(struct platform_device *pdev)
free_netdev(dev);
//Remove proc
- remove_proc_entry("eth/mii", init_net.proc_net);
- remove_proc_entry("eth", init_net.proc_net);
+ for(i = 0; i < PHY_MAX_ADDR; i++)
+ {
+ sprintf(buf, "phy/phy%d", i);
+ remove_proc_entry(buf, init_net.proc_net);
+ }
+ remove_proc_entry("phy", init_net.proc_net);
//Erase driver data informations
platform_set_drvdata(pdev, NULL);
diff --git a/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.c b/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.c
index af3f1f2a9f..be4c3387f5 100644
--- a/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.c
+++ b/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/icplus.c
@@ -40,6 +40,8 @@ static int ip175c_config_init(struct phy_device *phydev)
int err, i;
static int full_reset_performed = 0;
+ printk("ICPlus IP175C : Driver Initialization - PHY addr = %d\n", phydev->addr);
+
if (full_reset_performed == 0) {
/* master reset */
@@ -92,17 +94,41 @@ static int ip175c_config_init(struct phy_device *phydev)
static int ip175c_read_status(struct phy_device *phydev)
{
+ int i, status;
+
if (phydev->addr == 4) /* WAN port */
genphy_read_status(phydev);
- else
- /* Don't need to read status for switch ports */
- phydev->irq = PHY_IGNORE_INTERRUPT;
+
+ if (phydev->addr == 5) /* MAC 5 */
+ {
+ /* Read all links status */
+ phydev->link = 0;
+ for (i = 0; i < 5; i++) {
+ /* Do a fake read */
+ status = phydev->bus->read(phydev->bus, i, MII_BMSR);
+ if (status < 0)
+ return status;
+ /* Read link and autonegotiation status */
+ status = phydev->bus->read(phydev->bus, i, MII_BMSR);
+ if (status < 0)
+ return status;
+ if ((status & BMSR_LSTATUS) != 0)
+ phydev->link = 1;
+ }
+ }
return 0;
}
static int ip175c_config_aneg(struct phy_device *phydev)
{
+ if (phydev->addr == 5) /* MAC 5 */
+ {
+ phydev->autoneg = AUTONEG_DISABLE;
+ phydev->speed = SPEED_100;
+ phydev->duplex = DUPLEX_FULL;
+ genphy_config_aneg(phydev);
+ }
if (phydev->addr == 4) /* WAN port */
genphy_config_aneg(phydev);
diff --git a/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/mdio_bus.c b/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/mdio_bus.c
index 963630c65c..f74f79e9a6 100644
--- a/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/mdio_bus.c
+++ b/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/mdio_bus.c
@@ -81,6 +81,11 @@ int mdiobus_register(struct mii_bus *bus)
* 5) mii_bus
* And, we need to register it */
if (phydev) {
+
+ //PHY identifier not found, in case of a switch (exp IP175) so let's check atp hy_addr 0
+ if((phydev->phy_id == 0)&&bus->phy_map[0])
+ phydev->phy_id = (bus->phy_map[0])->phy_id;
+
phydev->irq = bus->irq[i];
phydev->dev.parent = bus->dev;
diff --git a/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/phy_device.c b/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/phy_device.c
index f4c4fd8542..6aca3f9450 100644
--- a/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/phy_device.c
+++ b/cleopatre/linux-2.6.25.10-spc300/drivers/net/phy/phy_device.c
@@ -117,7 +117,7 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
phy_id |= (phy_reg & 0xffff);
/* If the phy_id is all Fs, there is no device there */
- if (0xffffffff == phy_id)
+ if (((phy_id & 0x1fff0000) == 0x1fff0000)||((phy_id & 0x0000ffff) == 0x0000ffff))
return NULL;
dev = phy_device_create(bus, addr, phy_id);