Merge branch 'rmobile' of git://git.denx.de/u-boot-sh
[platform/kernel/u-boot.git] / drivers / net / phy / marvell.c
index d2ecadc..4eeb0f6 100644 (file)
@@ -8,6 +8,7 @@
  */
 #include <config.h>
 #include <common.h>
+#include <errno.h>
 #include <phy.h>
 
 #define PHY_AUTONEGOTIATE_TIMEOUT 5000
@@ -103,7 +104,7 @@ static int m88e1011s_config(struct phy_device *phydev)
 /* Parse the 88E1011's status register for speed and duplex
  * information
  */
-static uint m88e1xxx_parse_status(struct phy_device *phydev)
+static int m88e1xxx_parse_status(struct phy_device *phydev)
 {
        unsigned int speed;
        unsigned int mii_reg;
@@ -120,7 +121,7 @@ static uint m88e1xxx_parse_status(struct phy_device *phydev)
                        if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
                                puts(" TIMEOUT !\n");
                                phydev->link = 0;
-                               break;
+                               return -ETIMEDOUT;
                        }
 
                        if ((i++ % 1000) == 0)
@@ -162,17 +163,19 @@ static uint m88e1xxx_parse_status(struct phy_device *phydev)
 
 static int m88e1011s_startup(struct phy_device *phydev)
 {
-       genphy_update_link(phydev);
-       m88e1xxx_parse_status(phydev);
+       int ret;
 
-       return 0;
+       ret = genphy_update_link(phydev);
+       if (ret)
+               return ret;
+
+       return m88e1xxx_parse_status(phydev);
 }
 
 /* Marvell 88E1111S */
 static int m88e1111s_config(struct phy_device *phydev)
 {
        int reg;
-       int timeout;
 
        if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
                        (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
@@ -236,16 +239,7 @@ static int m88e1111s_config(struct phy_device *phydev)
                        MIIM_88E1111_PHY_EXT_SR, reg);
 
                /* soft reset */
-               timeout = 1000;
-               phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
-               udelay(1000);
-               reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
-               while ((reg & BMCR_RESET) && --timeout) {
-                       udelay(1000);
-                       reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
-               }
-               if (!timeout)
-                       printf("%s: phy soft reset timeout\n", __func__);
+               phy_reset(phydev);
 
                reg = phy_read(phydev, MDIO_DEVAD_NONE,
                        MIIM_88E1111_PHY_EXT_SR);
@@ -258,24 +252,93 @@ static int m88e1111s_config(struct phy_device *phydev)
        }
 
        /* soft reset */
-       timeout = 1000;
-       phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
-       udelay(1000);
-       reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
-       while ((reg & BMCR_RESET) && --timeout) {
-               udelay(1000);
-               reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
-       }
-       if (!timeout)
-               printf("%s: phy soft reset timeout\n", __func__);
+       phy_reset(phydev);
 
        genphy_config_aneg(phydev);
-
-       phy_reset(phydev);
+       genphy_restart_aneg(phydev);
 
        return 0;
 }
 
+/**
+ * m88e1518_phy_writebits - write bits to a register
+ */
+void m88e1518_phy_writebits(struct phy_device *phydev,
+                  u8 reg_num, u16 offset, u16 len, u16 data)
+{
+       u16 reg, mask;
+
+       if ((len + offset) >= 16)
+               mask = 0 - (1 << offset);
+       else
+               mask = (1 << (len + offset)) - (1 << offset);
+
+       reg = phy_read(phydev, MDIO_DEVAD_NONE, reg_num);
+
+       reg &= ~mask;
+       reg |= data << offset;
+
+       phy_write(phydev, MDIO_DEVAD_NONE, reg_num, reg);
+}
+
+static int m88e1518_config(struct phy_device *phydev)
+{
+       /*
+        * As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512
+        * /88E1514 Rev A0, Errata Section 3.1
+        */
+
+       /* EEE initialization */
+       phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00ff);
+       phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B);
+       phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144);
+       phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28);
+       phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146);
+       phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xB233);
+       phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D);
+       phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C);
+       phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159);
+       phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000);
+
+       /* SGMII-to-Copper mode initialization */
+       if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+               /* Select page 18 */
+               phy_write(phydev, MDIO_DEVAD_NONE, 22, 18);
+
+               /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
+               m88e1518_phy_writebits(phydev, 20, 0, 3, 1);
+
+               /* PHY reset is necessary after changing MODE[2:0] */
+               m88e1518_phy_writebits(phydev, 20, 15, 1, 1);
+
+               /* Reset page selection */
+               phy_write(phydev, MDIO_DEVAD_NONE, 22, 0);
+
+               udelay(100);
+       }
+
+       return m88e1111s_config(phydev);
+}
+
+/* Marvell 88E1510 */
+static int m88e1510_config(struct phy_device *phydev)
+{
+       /* Select page 3 */
+       phy_write(phydev, MDIO_DEVAD_NONE, 22, 3);
+
+       /* Enable INTn output on LED[2] */
+       m88e1518_phy_writebits(phydev, 18, 7, 1, 1);
+
+       /* Configure LEDs */
+       m88e1518_phy_writebits(phydev, 16, 0, 4, 3); /* LED[0]:0011 (ACT) */
+       m88e1518_phy_writebits(phydev, 16, 4, 4, 6); /* LED[1]:0110 (LINK) */
+
+       /* Reset page selection */
+       phy_write(phydev, MDIO_DEVAD_NONE, 22, 0);
+
+       return m88e1518_config(phydev);
+}
+
 /* Marvell 88E1118 */
 static int m88e1118_config(struct phy_device *phydev)
 {
@@ -290,22 +353,21 @@ static int m88e1118_config(struct phy_device *phydev)
        /* Change Page Number */
        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
 
-       genphy_config_aneg(phydev);
-
-       phy_reset(phydev);
-
-       return 0;
+       return genphy_config_aneg(phydev);
 }
 
 static int m88e1118_startup(struct phy_device *phydev)
 {
+       int ret;
+
        /* Change Page Number */
        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
 
-       genphy_update_link(phydev);
-       m88e1xxx_parse_status(phydev);
+       ret = genphy_update_link(phydev);
+       if (ret)
+               return ret;
 
-       return 0;
+       return m88e1xxx_parse_status(phydev);
 }
 
 /* Marvell 88E1121R */
@@ -362,12 +424,15 @@ static int m88e1145_config(struct phy_device *phydev)
 
 static int m88e1145_startup(struct phy_device *phydev)
 {
-       genphy_update_link(phydev);
+       int ret;
+
+       ret = genphy_update_link(phydev);
+       if (ret)
+               return ret;
+
        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL,
                        MIIM_88E1145_PHY_LED_DIRECT);
-       m88e1xxx_parse_status(phydev);
-
-       return 0;
+       return m88e1xxx_parse_status(phydev);
 }
 
 /* Marvell 88E1149S */
@@ -412,10 +477,7 @@ static int m88e1310_config(struct phy_device *phydev)
        /* Ensure to return to page 0 */
        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000);
 
-       genphy_config_aneg(phydev);
-       phy_reset(phydev);
-
-       return 0;
+       return genphy_config_aneg(phydev);
 }
 
 static struct phy_driver M88E1011S_driver = {
@@ -488,12 +550,22 @@ static struct phy_driver M88E1149S_driver = {
        .shutdown = &genphy_shutdown,
 };
 
+static struct phy_driver M88E1510_driver = {
+       .name = "Marvell 88E1510",
+       .uid = 0x1410dd0,
+       .mask = 0xffffff0,
+       .features = PHY_GBIT_FEATURES,
+       .config = &m88e1510_config,
+       .startup = &m88e1011s_startup,
+       .shutdown = &genphy_shutdown,
+};
+
 static struct phy_driver M88E1518_driver = {
        .name = "Marvell 88E1518",
        .uid = 0x1410dd1,
        .mask = 0xffffff0,
        .features = PHY_GBIT_FEATURES,
-       .config = &m88e1111s_config,
+       .config = &m88e1518_config,
        .startup = &m88e1011s_startup,
        .shutdown = &genphy_shutdown,
 };
@@ -518,6 +590,7 @@ int phy_marvell_init(void)
        phy_register(&M88E1118R_driver);
        phy_register(&M88E1111S_driver);
        phy_register(&M88E1011S_driver);
+       phy_register(&M88E1510_driver);
        phy_register(&M88E1518_driver);
 
        return 0;