]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/net/phy/marvell.c
net: Add support for Marvell 88E1510 PHY
[karo-tx-uboot.git] / drivers / net / phy / marvell.c
index 4b271989acbbaf5dbc8c4333e705f29ab0f9d642..eab15585c31a9d160b9fb05f4e783474821db438 100644 (file)
@@ -1,24 +1,10 @@
 /*
  * Marvell PHY drivers
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0+
  *
  * Copyright 2010-2011 Freescale Semiconductor, Inc.
  * author Andy Fleming
- *
  */
 #include <config.h>
 #include <common.h>
 
 #define MIIM_88E1149_PHY_PAGE  29
 
+/* 88E1310 PHY defines */
+#define MIIM_88E1310_PHY_LED_CTRL      16
+#define MIIM_88E1310_PHY_IRQ_EN                18
+#define MIIM_88E1310_PHY_RGMII_CTRL    21
+#define MIIM_88E1310_PHY_PAGE          22
+
 /* Marvell 88E1011S */
 static int m88e1011s_config(struct phy_device *phydev)
 {
@@ -284,6 +276,85 @@ static int m88e1111s_config(struct phy_device *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)
 {
@@ -394,6 +465,37 @@ static int m88e1149_config(struct phy_device *phydev)
        return 0;
 }
 
+/* Marvell 88E1310 */
+static int m88e1310_config(struct phy_device *phydev)
+{
+       u16 reg;
+
+       /* LED link and activity */
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
+       reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL);
+       reg = (reg & ~0xf) | 0x1;
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg);
+
+       /* Set LED2/INT to INT mode, low active */
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
+       reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN);
+       reg = (reg & 0x77ff) | 0x0880;
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg);
+
+       /* Set RGMII delay */
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002);
+       reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL);
+       reg |= 0x0030;
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg);
+
+       /* 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;
+}
 
 static struct phy_driver M88E1011S_driver = {
        .name = "Marvell 88E1011S",
@@ -465,8 +567,39 @@ 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 = &m88e1518_config,
+       .startup = &m88e1011s_startup,
+       .shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver M88E1310_driver = {
+       .name = "Marvell 88E1310",
+       .uid = 0x01410e90,
+       .mask = 0xffffff0,
+       .features = PHY_GBIT_FEATURES,
+       .config = &m88e1310_config,
+       .startup = &m88e1011s_startup,
+       .shutdown = &genphy_shutdown,
+};
+
 int phy_marvell_init(void)
 {
+       phy_register(&M88E1310_driver);
        phy_register(&M88E1149S_driver);
        phy_register(&M88E1145_driver);
        phy_register(&M88E1121R_driver);
@@ -474,6 +607,8 @@ 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;
 }