From: Chaithrika U S <[EMAIL PROTECTED]>

Adds  MII/PHY layer support DM644x/DM646x

Signed-off-by: Chaithrika U S <[EMAIL PROTECTED]>
---
 drivers/net/Makefile       |    2 +-
 drivers/net/davinci_emac.c |  524 ++++++++++++++++++++------------------------
 2 files changed, 236 insertions(+), 290 deletions(-)

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 7d18969..a2adaaa 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the Linux network (ethercard) device drivers.
 #
 
-davinci_emac_driver-objs := davinci_emac.o davinci_emac_phy.o
+davinci_emac_driver-objs := davinci_emac.o
 obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac_driver.o
 
 obj-$(CONFIG_E1000) += e1000/
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 3e44232..9e35019 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -59,6 +59,7 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/semaphore.h>
+#include <linux/phy.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -69,8 +70,6 @@
 #include <mach/hardware.h>
 #include <mach/emac.h>
 
-#include "davinci_emac_phy.h"
-
 static int cfg_link_speed;
 module_param(cfg_link_speed, int, 0);
 MODULE_PARM_DESC(cfg_link_speed,
@@ -148,18 +147,6 @@ const char emac_version_string[] = "TI DaVinci EMAC Linux 
v6.0";
 #error "Error. DM644x has space for no more than total 256 (TX+RX) BD's"
 #endif
 
-/* Phy information */
-#define EMAC_LINK_OFF          (0) /* Link down */
-#define EMAC_LINK_ON           (1) /* Link up */
-#define EMAC_SPEED_AUTO        (0) /* Auto Negotiation */
-#define EMAC_SPEED_NO_PHY      (1) /* No Phy - Always ON - Ext Sw */
-#define EMAC_SPEED_10MBPS      (10) /* 10 Mbps */
-#define EMAC_SPEED_100MBPS     (100) /* 100 Mbps */
-#define EMAC_SPEED_1GBPS       (1000) /* 1 Gbpps */
-#define EMAC_DUPLEX_UNKNOWN    (1) /* Not known - negotiating? */
-#define EMAC_DUPLEX_HALF       (2) /* Half Duplex */
-#define EMAC_DUPLEX_FULL       (3) /* Full Duplex */
-
 /* config parameters that get tested for operation */
 #define EMAC_MIN_FREQUENCY_FOR_10MBPS  (5500000)
 #define EMAC_MIN_FREQUENCY_FOR_100MBPS (55000000)
@@ -215,6 +202,11 @@ const char emac_version_string[] = "TI DaVinci EMAC Linux 
v6.0";
 #define EMAC_MACCONTROL_GIGABITEN_SHIFT (7)
 #define EMAC_MACCONTROL_FULLDUPLEXEN   (0x1)
 
+/* GIGABIT MODE related bits */
+#define EMAC_DM646X_MACCONTORL_GMIIEN  (0x01 << 5)
+#define EMAC_DM646X_MACCONTORL_GIG     (0x01 << 7)
+#define EMAC_DM646X_MACCONTORL_GIGFORCE        (0x01 << 17)
+
 /* EMAC mac_status register */
 #define EMAC_MACSTATUS_TXERRCODE_MASK  (0xF00000)
 #define EMAC_MACSTATUS_TXERRCODE_SHIFT (20)
@@ -350,6 +342,26 @@ const char emac_version_string[] = "TI DaVinci EMAC Linux 
v6.0";
 #define EMAC_CTRL_EWCTL        (0x4)
 #define EMAC_CTRL_EWINTTCNT    (0x8)
 
+/* EMAC MDIO related */
+/* Mask & Control defines */
+#define MDIO_CONTROL_CLKDIV    (0xFF)
+#define MDIO_CONTROL_ENABLE    (1 << 30)
+#define MDIO_USERACCESS_GO     (1 << 31)
+#define MDIO_USERACCESS_WRITE  (1 << 30)
+#define MDIO_USERACCESS_READ   (0 << 30)
+#define MDIO_USERACCESS_WRITE  (1 << 30)
+#define MDIO_USERACCESS_REGADR (0x1F << 21)
+#define MDIO_USERACCESS_PHYADR (0x1F << 16)
+#define MDIO_USERACCESS_DATA   (0xFFFF)
+#define MDIO_USERPHYSEL_LINKSEL        (1 << 7)
+#define MDIO_VER_MODID         (0xFFFF << 16)
+#define MDIO_VER_REVMAJ                (0xFF   << 8)
+#define MDIO_VER_REVMIN                (0xFF)
+
+#define MDIO_USERACCESS(inst)  (0x80 + (inst * 8))
+#define MDIO_USERPHYSEL(inst)  (0x84 + (inst * 8))
+#define MDIO_CONTROL           (0x04)
+
 /* EMAC DM646X control module registers */
 #define EMAC_DM646X_CMRXINTEN  (0x14)
 #define EMAC_DM646X_CMTXINTEN  (0x18)
@@ -472,21 +484,6 @@ struct emac_rxch {
        u32 mis_queued_packets;
 };
 
-/** emac_mdio: EMAC MDIO data structure
- *
- * EMAC MDIO data structure
- */
-struct emac_mdio {
-       u32 mdio_base_address;
-       u32 mdio_reset_line;
-       u32 mdio_intr_line;
-       u32 phy_mask;
-       u32 MLink_mask;
-       u32 mdio_bus_frequency;
-       u32 mdio_clock_frequency;
-       u32 mdio_tick_msec;
-};
-
 /* emac_priv: EMAC private data structure
  *
  * EMAC adapter private data structure
@@ -502,8 +499,6 @@ struct emac_priv {
        u32 emac_base_regs;
        u32 emac_ctrl_regs;
        void __iomem *emac_ctrl_ram;
-       void __iomem *mdio_regs;
-       struct emac_mdio mdio;
        struct emac_txch *txch[EMAC_DEF_MAX_TX_CH];
        struct emac_rxch *rxch[EMAC_DEF_MAX_RX_CH];
        u32 link; /* 1=link on, 0=link off */
@@ -520,6 +515,10 @@ struct emac_priv {
        struct timer_list periodic_timer;
        u32 periodic_ticks;
        u32 timer_active;
+       /* mii_bus,phy members */
+       struct mii_bus *mii_bus;
+       struct phy_device *phydev;
+       spinlock_t lock;
 };
 
 /* clock frequency for EMAC */
@@ -582,7 +581,8 @@ static char *emac_rxhost_errcodes[16] = {
 #define emac_ctrl_write(reg, val) \
        davinci_writel(val, (priv->emac_ctrl_regs + (reg)))
 
-
+#define emac_mdio_read(reg)    davinci_readl((bus->priv + (reg)))
+#define emac_mdio_write(reg, val)      davinci_writel(val, (bus->priv + (reg)))
 /**
  * emac_dump_regs: Dump important EMAC registers to debug terminal
  * @priv: The DaVinci EMAC private adapter structure
@@ -689,77 +689,6 @@ static void emac_dump_regs(struct emac_priv *priv)
 /*************************************************************************
  *  EMAC MDIO/Phy Functionality
  *************************************************************************/
-
-/**
- * emac_netdev_set_ecmd: Set EMAC information to phy
- * @ndev: The DaVinci EMAC network adapter
- * @ecmd: ethtool command
- *
- * Executes ethtool set cmd & sets phy mode
- *
- */
-static int emac_netdev_set_ecmd(struct net_device *ndev,
-                               struct ethtool_cmd *ecmd)
-{
-       int speed_duplex = 0;
-       u32 phy_mode = 0;
-
-       if (ecmd->autoneg)
-               phy_mode |= NWAY_AUTO;
-
-       speed_duplex = ecmd->speed + ecmd->duplex;
-       switch (speed_duplex) {
-       case 10:        /* HD10 */
-               phy_mode |= NWAY_HD10;
-               break;
-       case 11: /* FD10 */
-               phy_mode |= NWAY_FD10;
-               break;
-       case 100: /* HD100 */
-               phy_mode |= NWAY_HD100;
-               break;
-       case 101:       /* FD100 */
-               phy_mode |= NWAY_FD100;
-               break;
-       case 1000:       /* HD100 */
-               phy_mode |= NWAY_HD1000;
-               break;
-       case 1001:      /* FD1000 */
-               phy_mode |= NWAY_FD1000;
-               break;
-       default:
-               return -1;
-       }
-       emac_mdio_set_phy_mode(phy_mode);
-       return 0;
-}
-
-
-/**
- * emac_netdev_get_ecmd: Get EMAC information from phy
- * @ndev: The DaVinci EMAC network adapter
- * @ecmd: ethtool command
- *
- * Executes ethtool get cmd & returns EMAC driver information from phy
- *
- */
-static int emac_netdev_get_ecmd(struct net_device *ndev,
-                               struct ethtool_cmd *ecmd)
-{
-       int dplx = emac_mdio_get_duplex();
-
-       /* Hard-coded, but should perhaps be retrieved from davinci_emac_phy */
-       /* TODO: ecmd->supported = emac_mdio_supported_rate(); */
-       /* TODO: ecmd->advertising = emac_mdio_autoneg_rate(); */
-       /* TODO: ecmd->autoneg = emac_mdio_get_autoneg(); */
-       ecmd->speed = emac_mdio_get_speed();
-       ecmd->transceiver = XCVR_EXTERNAL;
-       ecmd->port = PORT_MII;
-       ecmd->phy_address = emac_mdio_get_phy_num();
-       ecmd->duplex = (dplx == 3) ? DUPLEX_FULL : DUPLEX_HALF;
-       return 0;
-}
-
 /**
  * emac_get_drvinfo: Get EMAC driver information
  * @ndev: The DaVinci EMAC network adapter
@@ -786,7 +715,8 @@ static void emac_get_drvinfo(struct net_device *ndev,
 static int emac_get_settings(struct net_device *ndev,
                             struct ethtool_cmd *ecmd)
 {
-       return (emac_netdev_get_ecmd(ndev, ecmd));
+       struct emac_priv *priv = netdev_priv(ndev);
+       return phy_ethtool_gset(priv->phydev, ecmd);
 }
 
 /**
@@ -799,20 +729,10 @@ static int emac_get_settings(struct net_device *ndev,
  */
 static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
 {
-       return (emac_netdev_set_ecmd(ndev, ecmd));
+       struct emac_priv *priv = netdev_priv(ndev);
+       return phy_ethtool_sset(priv->phydev, ecmd);
 }
 
-/**
- * emac_get_link: Get EMAC adapter link status
- * @ndev: The DaVinci EMAC network adapter
- *
- * Returns link status link(1), no link (0)
- *
- */
-static u32 emac_get_link(struct net_device *ndev)
-{
-       return (emac_mdio_is_linked());
-}
 
 /**
  * ethtool_ops: DaVinci EMAC Ethtool structure
@@ -824,10 +744,9 @@ struct ethtool_ops ethtool_ops = {
        .get_drvinfo = emac_get_drvinfo,
        .get_settings = emac_get_settings,
        .set_settings = emac_set_settings,
-       .get_link = emac_get_link,
+       .get_link = ethtool_op_get_link,
 };
 
-
 /**
  * emac_update_phystatus: Update Phy status
  * @priv: The DaVinci EMAC private adapter structure
@@ -844,25 +763,28 @@ static void emac_update_phystatus(struct emac_priv *priv)
 
        mac_control = emac_read(EMAC_MACCONTROL);
 
-       /* Get link status from MDIO */
-       priv->link = emac_mdio_is_linked();
-       priv->speed = emac_mdio_get_speed();
-       new_duplex = emac_mdio_get_duplex();
-
-       if (EMAC_SPEED_NO_PHY == cfg_link_speed) {
-               priv->link = 1; /* Link always on when no phy */
-               priv->duplex = EMAC_DUPLEX_UNKNOWN;
-               mac_control |= (EMAC_MACCONTROL_FULLDUPLEXEN);
-       }
+       new_duplex = priv->phydev->duplex;
 
        /* We get called only if link has changed (speed/duplex/status) */
        if ((priv->link) && (new_duplex != priv->duplex)) {
                priv->duplex = new_duplex;
-               if (EMAC_DUPLEX_FULL == priv->duplex)
+               if (DUPLEX_FULL == priv->duplex)
                        mac_control |= (EMAC_MACCONTROL_FULLDUPLEXEN);
                else
                        mac_control &= ~(EMAC_MACCONTROL_FULLDUPLEXEN);
        }
+
+       if (priv->speed == SPEED_1000 && cpu_is_davinci_dm646x()) {
+               mac_control = emac_read(EMAC_MACCONTROL);
+               mac_control |= (EMAC_DM646X_MACCONTORL_GMIIEN |
+                               EMAC_DM646X_MACCONTORL_GIG |
+                               EMAC_DM646X_MACCONTORL_GIGFORCE);
+       } else {
+               /* Clear the GIG bit and GIGFORCE bit */
+               mac_control &= ~(EMAC_DM646X_MACCONTORL_GIGFORCE |
+                                       EMAC_DM646X_MACCONTORL_GIG);
+       }
+
        /* Update mac_control if changed */
        emac_write(EMAC_MACCONTROL, mac_control);
 
@@ -882,81 +804,6 @@ static void emac_update_phystatus(struct emac_priv *priv)
        }
 }
 
-/* Auto all covers all speeds and duplex modes */
-#define NWAY_AUTO_ALL (NWAY_AUTO | NWAY_HD10 | NWAY_FD10 | NWAY_HD100 | \
-                      NWAY_FD100 | NWAY_HD1000 | NWAY_FD1000)
-
-/**
- * emac_set_phymode: Set phy mode like speed, duplex, auto neg parameters
- * @priv: The DaVinci EMAC private adapter structure
- *
- * Sets phy mode (parameters like speed, duplex, auto negotiation) on the PHY
- *
- */
-static void emac_set_phymode(struct emac_priv *priv)
-{
-       u32 phy_mode;
-
-       /* Check module and config params and set MDIO mode accordingly */
-       if (EMAC_SPEED_NO_PHY == cfg_link_speed) {
-               priv->speed = EMAC_SPEED_NO_PHY;
-               priv->duplex = EMAC_DUPLEX_UNKNOWN;
-               phy_mode = NWAY_NOPHY;
-       } else if (EMAC_SPEED_AUTO == cfg_link_speed) {
-               priv->speed = EMAC_SPEED_AUTO;
-               priv->duplex = EMAC_DUPLEX_UNKNOWN;
-               phy_mode = NWAY_AUTO_ALL;
-       } else if (EMAC_SPEED_10MBPS == cfg_link_speed) {
-               /* Check if bus speed allows 10mbps */
-               if (priv->mdio.mdio_bus_frequency <=
-                   EMAC_MIN_FREQUENCY_FOR_10MBPS) {
-                       if (netif_msg_drv(priv)) {
-                       dev_warn(EMAC_DEV, "DaVinci EMAC: EMAC Bus freq %d"\
-                                " should be > than %d - for 10 mbps support",
-                                priv->mdio.mdio_bus_frequency,
-                                EMAC_MIN_FREQUENCY_FOR_10MBPS);
-                       }
-               }
-               priv->speed = EMAC_SPEED_10MBPS;
-               if (EMAC_DUPLEX_HALF == cfg_link_duplex) {
-                       phy_mode = NWAY_HD10;
-                       priv->duplex = EMAC_DUPLEX_HALF;
-               } else {
-                       phy_mode = NWAY_FD10;
-                       priv->duplex = EMAC_DUPLEX_FULL;
-               }
-       } else if (EMAC_SPEED_100MBPS == cfg_link_speed) {
-               if (priv->mdio.mdio_bus_frequency <=
-                   EMAC_MIN_FREQUENCY_FOR_100MBPS) {
-                       if (netif_msg_drv(priv)) {
-                               dev_warn(EMAC_DEV, "DaVinci EMAC: EMAC Bus "\
-                                        "freq %d should be greater than %d"\
-                                        " - for 100 mbps support",
-                                        priv->mdio.mdio_bus_frequency,
-                                        EMAC_MIN_FREQUENCY_FOR_100MBPS);
-                       }
-               }
-               priv->speed = EMAC_SPEED_100MBPS;
-               if (EMAC_DUPLEX_HALF == cfg_link_duplex) {
-                       phy_mode = NWAY_HD100;
-                       priv->duplex = EMAC_DUPLEX_HALF;
-               } else {
-                       phy_mode = NWAY_FD100;
-                       priv->duplex = EMAC_DUPLEX_FULL;
-               }
-       } else if (EMAC_SPEED_1GBPS == cfg_link_speed) {
-               phy_mode = NWAY_AUTO_ALL; /* Temporarily */
-               priv->speed = EMAC_SPEED_AUTO;
-               priv->duplex = EMAC_DUPLEX_UNKNOWN;
-       } else {
-               phy_mode = NWAY_AUTO_ALL; /* Fall back if wrong params set */
-               priv->speed = EMAC_SPEED_AUTO;
-               priv->duplex = EMAC_DUPLEX_UNKNOWN;
-       }
-       emac_mdio_set_phy_mode(phy_mode);
-       emac_update_phystatus(priv);
-}
-
 /**
  * hash_get: Calculate hash value from mac address
  * @addr: mac address to delete from hash table
@@ -1155,35 +1002,6 @@ static void emac_dev_mcast_set(struct net_device *ndev)
        emac_write(EMAC_RXMBPENABLE, mbp_enable);
 }
 
-/**
- * emac_timer_cb: EMAC Phy timer callback
- * @priv: The DaVinci EMAC private adapter structure
- *
- * EMAC uses a PHY poll timer - this callback function probes the PHY
- * periodically to see if the status has changed. PHY auto-negotiation logic
- * is also handled via this callback in the PHY code
- *
- */
-static void emac_timer_cb(struct emac_priv *priv)
-{
-       struct timer_list *p_timer = &priv->periodic_timer;
-       u32 change;
-
-       if (!netif_running(priv->ndev))
-               return;
-
-       if (1 == priv->timer_active) {
-               if (EMAC_SPEED_NO_PHY != cfg_link_speed) {
-                       change = emac_mdio_tick();
-                       if (unlikely(1 == change))
-                               emac_update_phystatus(priv);
-               }
-               p_timer->expires = jiffies + priv->periodic_ticks;
-               add_timer(p_timer);
-       }
-}
-
-
 /*************************************************************************
  *  EMAC Hardware manipulation
  *************************************************************************/
@@ -2243,8 +2061,6 @@ end_emac_rx_bdproc:
 static int emac_hw_enable(struct emac_priv *priv)
 {
        u32 ch, val, mbp_enable, mac_control;
-       u32 mii_mod_id, mii_rev_maj, mii_rev_min;
-       struct timer_list *p_timer = &priv->periodic_timer;
 
        /* Soft reset */
        emac_write(EMAC_SOFTRESET, 1);
@@ -2254,47 +2070,12 @@ static int emac_hw_enable(struct emac_priv *priv)
        /* Disable interrupt & Set pacing for more interrupts initially */
        emac_int_disable(priv);
 
-       /* Set speed and duplex mode */
-       priv->duplex = EMAC_DUPLEX_UNKNOWN;
-       if (EMAC_SPEED_NO_PHY == cfg_link_speed)
-               priv->speed = EMAC_SPEED_NO_PHY;
-       else if (EMAC_SPEED_AUTO == cfg_link_speed)
-               priv->speed = EMAC_SPEED_AUTO;
-
-       priv->mdio.mdio_base_address = (u32)priv->mdio_regs;
-       priv->mdio.mdio_reset_line = 0;
-       priv->mdio.mdio_intr_line = 0;
-       priv->mdio.phy_mask = EMAC_EVM_PHY_MASK;
-       priv->mdio.MLink_mask = EMAC_EVM_MLINK_MASK;
-       priv->mdio.mdio_bus_frequency = EMAC_EVM_BUS_FREQUENCY;
-       priv->mdio.mdio_clock_frequency = EMAC_EVM_MDIO_FREQUENCY;
-       priv->mdio.mdio_tick_msec = EMAC_DEF_MDIO_TICK_MS;
-
-       /* start MDIO autonegotiation and set phy mode */
-       emac_mdio_get_ver(priv->mdio.mdio_base_address,
-                         &mii_mod_id, &mii_rev_maj, &mii_rev_min);
-       emac_mdio_init(priv->mdio.mdio_base_address,
-                      0, /* instance id */
-                      priv->mdio.phy_mask,
-                      priv->mdio.MLink_mask,
-                      priv->mdio.mdio_bus_frequency,
-                      priv->mdio.mdio_clock_frequency,
-                      EMAC_MDIO_DEBUG); /* debug flag */
-
-       /* set phy mode */
-       emac_set_phymode(priv);
-
-       /* start the tick timer */
-       p_timer->expires = jiffies + priv->periodic_ticks;
-       add_timer(&priv->periodic_timer);
-       priv->timer_active = 1;
-
        /* Full duplex enable bit set when auto negotiation happens */
        mac_control =
                (((EMAC_DEF_TXPRIO_FIXED) ? (EMAC_MACCONTROL_TXPTYPE) : 0x0) |
                ((priv->speed == 1000) ? EMAC_MACCONTROL_GIGABITEN : 0x0) |
                ((EMAC_DEF_TXPACING_EN) ? (EMAC_MACCONTROL_TXPACEEN) : 0x0) |
-               ((priv->duplex == EMAC_DUPLEX_FULL) ? 0x1 : 0));
+               ((priv->duplex == DUPLEX_FULL) ? 0x1 : 0));
        emac_write(EMAC_MACCONTROL, mac_control);
 
        mbp_enable =
@@ -2329,7 +2110,7 @@ static int emac_hw_enable(struct emac_priv *priv)
        val |= EMAC_RX_CONTROL_RX_ENABLE_VAL;
        emac_write(EMAC_RXCONTROL, val);
        emac_write(EMAC_MACINTMASKSET, EMAC_MAC_HOST_ERR_INTMASK_VAL);
-;
+
        for (ch = 0; ch < EMAC_DEF_MAX_TX_CH; ch++) {
                emac_write(EMAC_TXHDP(ch), 0);
                emac_write(EMAC_TXINTMASKSET, (1 << ch));
@@ -2347,7 +2128,6 @@ static int emac_hw_enable(struct emac_priv *priv)
        val = emac_read(EMAC_MACCONTROL);
        val |= (EMAC_MACCONTROL_MIIEN);
        emac_write(EMAC_MACCONTROL, val);
-       emac_update_phystatus(priv);
 
        /* Enable NAPI and interrupts */
        napi_enable(&priv->napi);
@@ -2468,6 +2248,118 @@ void emac_poll_controller(struct net_device *ndev)
 }
 #endif
 
+/* PHY/MII bus related */
+
+/* Wait until mdio is ready for next command */
+#define MDIO_WAIT_FOR_USER_ACCESS\
+               while ((emac_mdio_read((MDIO_USERACCESS(0))) &\
+                       MDIO_USERACCESS_GO) != 0)
+
+static int emac_mii_read(struct mii_bus *bus, int phy_id, int phy_reg)
+{
+       unsigned int phy_data = 0;
+       unsigned int phy_control;
+
+       /* Wait until mdio is ready for next command */
+       MDIO_WAIT_FOR_USER_ACCESS;
+
+       phy_control = (MDIO_USERACCESS_GO |
+                      MDIO_USERACCESS_READ |
+                      ((phy_reg << 21) & MDIO_USERACCESS_REGADR) |
+                      ((phy_id << 16) & MDIO_USERACCESS_PHYADR) |
+                      (phy_data & MDIO_USERACCESS_DATA));
+       emac_mdio_write(MDIO_USERACCESS(0), phy_control);
+
+       /* Wait until mdio is ready for next command */
+       MDIO_WAIT_FOR_USER_ACCESS;
+
+       return emac_mdio_read(MDIO_USERACCESS(0)) & MDIO_USERACCESS_DATA;
+
+}
+
+static int emac_mii_write(struct mii_bus *bus, int phy_id,
+                         int phy_reg, u16 phy_data)
+{
+
+       unsigned int control;
+
+       /*  until mdio is ready for next command */
+       MDIO_WAIT_FOR_USER_ACCESS;
+
+       control = (MDIO_USERACCESS_GO |
+                  MDIO_USERACCESS_WRITE |
+                  ((phy_reg << 21) & MDIO_USERACCESS_REGADR) |
+                  ((phy_id << 16) & MDIO_USERACCESS_PHYADR) |
+                  (phy_data & MDIO_USERACCESS_DATA));
+       emac_mdio_write(MDIO_USERACCESS(0), control);
+
+       return 0;
+}
+
+static int emac_mii_reset(struct mii_bus *bus)
+{
+       unsigned int clk_div;
+       int mdio_bus_freq = emac_bus_frequency;
+       int mdio_clock_freq = EMAC_EVM_MDIO_FREQUENCY;
+
+       if (mdio_clock_freq & mdio_bus_freq)
+               clk_div = ((mdio_bus_freq / mdio_clock_freq) - 1);
+       else
+               clk_div = 0xFF;
+
+       clk_div &= MDIO_CONTROL_CLKDIV;
+
+       /* Set enable and clock divider in MDIOControl */
+       emac_mdio_write(MDIO_CONTROL, (clk_div | MDIO_CONTROL_ENABLE));
+
+       return 0;
+
+}
+
+static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, PHY_POLL };
+
+/* emac_driver: EMAC MII bus structure */
+
+static struct mii_bus *emac_mii;
+
+static void emac_adjust_link(struct net_device *ndev)
+{
+       struct emac_priv *priv = netdev_priv(ndev);
+       struct phy_device *phydev = priv->phydev;
+       unsigned long flags;
+       int new_state = 0;
+
+       spin_lock_irqsave(priv->lock, flags);
+
+       if (phydev->link) {
+               /* check the mode of operation - full/half duplex */
+               if (phydev->duplex != priv->duplex) {
+                       new_state = 1;
+                       priv->duplex = phydev->duplex;
+               }
+               if (phydev->speed != priv->speed) {
+                       new_state = 1;
+                       priv->speed = phydev->speed;
+               }
+               if (!priv->link) {
+                       new_state = 1;
+                       priv->link = 1;
+               }
+
+       } else if (priv->link) {
+               new_state = 1;
+               priv->link = 0;
+               priv->speed = 0;
+               priv->duplex = -1;
+       }
+       if (new_state) {
+               emac_update_phystatus(priv);
+               phy_print_status(priv->phydev);
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
 /*************************************************************************
  *  Linux Driver Model
  *************************************************************************/
@@ -2494,7 +2386,6 @@ static int emac_devioctl(struct net_device *ndev, struct 
ifreq *ifrq, int cmd)
        return(-EOPNOTSUPP);
 }
 
-typedef void (*timer_tick_func) (unsigned long);
 
 /**
  * emac_dev_open: EMAC device open
@@ -2509,6 +2400,7 @@ typedef void (*timer_tick_func) (unsigned long);
 static int emac_dev_open(struct net_device *ndev)
 {
        u32 rc, cnt, ch;
+       int phy_addr;
        struct resource *res;
        int q, m;
        int i = 0;
@@ -2525,14 +2417,6 @@ static int emac_dev_open(struct net_device *ndev)
        /* Configuration items */
        priv->rx_buf_size = EMAC_DEF_MAX_FRAME_SIZE + EMAC_DEF_EXTRA_RXBUF_SIZE;
 
-       /* initialize the timers for the net device */
-       init_timer(&priv->periodic_timer);
-       priv->periodic_ticks = (HZ * EMAC_DEF_MDIO_TICK_MS) / 1000;
-       priv->periodic_timer.expires = 0;
-       priv->timer_active = 0;
-       priv->periodic_timer.data = (unsigned long) priv;
-       priv->periodic_timer.function = (timer_tick_func) emac_timer_cb;
-
        /* Clear basic hardware */
        for (ch = 0; ch < EMAC_MAX_TXRX_CHANNELS; ch++) {
                emac_write(EMAC_TXHDP(ch), 0);
@@ -2571,12 +2455,46 @@ static int emac_dev_open(struct net_device *ndev)
 
        /* Start/Enable EMAC hardware */
        emac_hw_enable(priv);
+
+       /* find the first phy */
+       priv->phydev = NULL;
+       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+               if (priv->mii_bus->phy_map[phy_addr]) {
+                       priv->phydev = priv->mii_bus->phy_map[phy_addr];
+                       break;
+               }
+       }
+
+       if (!priv->phydev) {
+               printk(KERN_ERR "%s: no PHY found\n", ndev->name);
+               return -1;
+       }
+
+       priv->phydev = phy_connect(ndev, priv->phydev->dev.bus_id,
+                               &emac_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+
+       if (IS_ERR(priv->phydev)) {
+               printk(KERN_ERR "%s: Could not attach to PHY\n", ndev->name);
+               return PTR_ERR(priv->phydev);
+       }
+
+       priv->link = 0;
+       priv->speed = 0;
+       priv->duplex = -1;
+
+       printk(KERN_INFO "%s: attached PHY driver [%s] "
+               "(mii_bus:phy_addr=%s, id=%x)\n", ndev->name,
+               priv->phydev->drv->name, priv->phydev->dev.bus_id,
+               priv->phydev->phy_id);
+
        if (!netif_running(ndev)) /* debug only - to avoid compiler warning */
                emac_dump_regs(priv);
 
        if (netif_msg_drv(priv))
                dev_notice(EMAC_DEV, "DaVinci EMAC: Opened %s\n", ndev->name);
 
+       phy_start(priv->phydev);
+
        return (0);
 
 rollback:
@@ -2612,10 +2530,6 @@ static int emac_dev_stop(struct net_device *ndev)
        netif_stop_queue(ndev);
        napi_disable(&priv->napi);
 
-       /* stop and delete the mdio tick timer */
-       del_timer_sync(&priv->periodic_timer);
-       priv->timer_active = 0;
-
        netif_carrier_off(ndev);
        emac_int_disable(priv);
        emac_stop_txch(priv, EMAC_DEF_TX_CH);
@@ -2624,6 +2538,8 @@ static int emac_dev_stop(struct net_device *ndev)
        emac_cleanup_rxch(priv, EMAC_DEF_RX_CH);
        emac_write(EMAC_SOFTRESET, 1);
 
+       phy_disconnect(priv->phydev);
+
        /* Free IRQ */
        while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) {
                for (irq_num = res->start; irq_num <= res->end; irq_num++)
@@ -2710,7 +2626,6 @@ static int __devinit davinci_emac_probe(struct 
platform_device *pdev)
                return (-EBUSY);
        }
        emac_bus_frequency = clk_get_rate(emac_clk);
-
        /* TODO: Probe PHY here if possible */
 
        ndev = alloc_etherdev(sizeof(struct emac_priv));
@@ -2750,8 +2665,6 @@ static int __devinit davinci_emac_probe(struct 
platform_device *pdev)
 
        rc = ((u32)(priv->emac_base_regs) + EMAC_CONTROL_RAM_OFFSET);
        priv->emac_ctrl_ram = IO_ADDRESS(rc);
-       priv->mdio_regs = IO_ADDRESS(((u32)(priv->emac_base_regs) +
-                                    EMAC_MDIO_REGS_OFFSET));
 
        /* Note that DaVinci EMAC address region is contingous */
        if (!request_mem_region((u32)priv->emac_base_regs,
@@ -2767,6 +2680,7 @@ static int __devinit davinci_emac_probe(struct 
platform_device *pdev)
        ndev->open = emac_dev_open;   /*  i.e. start device  */
        ndev->stop = emac_dev_stop;
        ndev->do_ioctl = emac_devioctl;
+       SET_ETHTOOL_OPS(ndev, &ethtool_ops);
        ndev->get_stats = emac_dev_getnetstats;
        ndev->set_multicast_list = emac_dev_mcast_set;
        ndev->hard_start_xmit = emac_dev_xmit;
@@ -2789,6 +2703,32 @@ static int __devinit davinci_emac_probe(struct 
platform_device *pdev)
        }
 
        clk_enable(emac_clk);
+
+       /* MII/Phy intialisation, mdio bus registration */
+       emac_mii = mdiobus_alloc();
+       if (emac_mii == NULL) {
+               rc = -ENOMEM;
+               goto probe_quit;
+       }
+
+       priv->mii_bus = emac_mii;
+       emac_mii->name  = "emac-mii",
+       emac_mii->read  = emac_mii_read,
+       emac_mii->write = emac_mii_write,
+       emac_mii->reset = emac_mii_reset,
+       emac_mii->irq   = mii_irqs,
+       emac_mii->phy_mask = ~(EMAC_EVM_PHY_MASK);
+       /* Base address initialisation for MDIO */
+       emac_mii->priv = (void *)(((priv->emac_base_regs) +
+                                       EMAC_MDIO_REGS_OFFSET));
+       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", priv->pdev->id);
+       emac_mii->reset(emac_mii);
+
+       /* Register the MII bus */
+       rc = mdiobus_register(emac_mii);
+       if (rc)
+               goto mdiobus_quit;
+
        if (netif_msg_probe(priv)) {
                dev_notice(EMAC_DEV, "DaVinci EMAC Probe found device "\
                           "(regs: %p, irq: %d)\n",
@@ -2796,6 +2736,9 @@ static int __devinit davinci_emac_probe(struct 
platform_device *pdev)
        }
        return (0);
 
+mdiobus_quit:
+       mdiobus_free(emac_mii);
+
 probe_quit:
        clk_put(emac_clk);
        free_netdev(ndev);
@@ -2813,12 +2756,15 @@ static int __devexit davinci_emac_remove(struct 
platform_device *pdev)
 {
        struct resource *base_res;
        struct net_device *ndev = platform_get_drvdata(pdev);
+       struct emac_priv *priv = netdev_priv(ndev);
 
        dev_notice(&ndev->dev, "DaVinci EMAC: davinci_emac_remove()\n");
 
        clk_disable(emac_clk);
        platform_set_drvdata(pdev, NULL);
        base_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mdiobus_unregister(priv->mii_bus);
+       mdiobus_free(priv->mii_bus);
        release_mem_region(base_res->start, base_res->end - base_res->start);
        unregister_netdev(ndev);
        free_netdev(ndev);
-- 
1.5.4.1

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to