phy: Add phy driver support for xilinx PCS/PMA core
authorSiva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Fri, 5 Feb 2016 07:52:10 +0000 (13:22 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Mon, 4 Apr 2016 18:10:44 +0000 (20:10 +0200)
Add phy driver support for xilinx PCS/PMA core

Signed-off-by: Siva Durga Prasad Paladugu <sivadur@xilinx.com>
Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/net/phy/Makefile
drivers/net/phy/phy.c
drivers/net/phy/xilinx_phy.c [new file with mode: 0644]
include/phy.h

index 9e4d4927e676a3fa9a48c156838e048260c511dc..1e299b97b96187517fa81d97d3768fd2255c96c9 100644 (file)
@@ -25,4 +25,5 @@ obj-$(CONFIG_PHY_REALTEK) += realtek.o
 obj-$(CONFIG_PHY_SMSC) += smsc.o
 obj-$(CONFIG_PHY_TERANETICS) += teranetics.o
 obj-$(CONFIG_PHY_TI) += ti.o
+obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
index 17866a244b3a9d8dbcb38c1f703bfc626f5f2b74..23c82bb36e93ed0e70f50af532e659ab6612a68f 100644 (file)
@@ -503,6 +503,9 @@ int phy_init(void)
 #ifdef CONFIG_PHY_VITESSE
        phy_vitesse_init();
 #endif
+#ifdef CONFIG_PHY_XILINX
+       phy_xilinx_init();
+#endif
 
        return 0;
 }
diff --git a/drivers/net/phy/xilinx_phy.c b/drivers/net/phy/xilinx_phy.c
new file mode 100644 (file)
index 0000000..f3eaf2e
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Xilinx PCS/PMA Core phy driver
+ *
+ * Copyright (C) 2015 - 2016 Xilinx, Inc.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <phy.h>
+#include <dm.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MII_PHY_STATUS_SPD_MASK                0x0C00
+#define MII_PHY_STATUS_FULLDUPLEX      0x1000
+#define MII_PHY_STATUS_1000            0x0800
+#define MII_PHY_STATUS_100             0x0400
+#define XPCSPMA_PHY_CTRL_ISOLATE_DISABLE 0xFBFF
+
+/* Mask used for ID comparisons */
+#define XILINX_PHY_ID_MASK             0xfffffff0
+
+/* Known PHY IDs */
+#define XILINX_PHY_ID                  0x01740c00
+
+/* struct phy_device dev_flags definitions */
+#define XAE_PHY_TYPE_MII               0
+#define XAE_PHY_TYPE_GMII              1
+#define XAE_PHY_TYPE_RGMII_1_3         2
+#define XAE_PHY_TYPE_RGMII_2_0         3
+#define XAE_PHY_TYPE_SGMII             4
+#define XAE_PHY_TYPE_1000BASE_X                5
+
+static int xilinxphy_startup(struct phy_device *phydev)
+{
+       int err;
+       int status = 0;
+
+       debug("%s\n", __func__);
+       /* Update the link, but return if there
+        * was an error
+        */
+       err = genphy_update_link(phydev);
+       if (err)
+               return err;
+
+       if (AUTONEG_ENABLE == phydev->autoneg) {
+               status = phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
+               status = status & MII_PHY_STATUS_SPD_MASK;
+
+               if (status & MII_PHY_STATUS_FULLDUPLEX)
+                       phydev->duplex = DUPLEX_FULL;
+               else
+                       phydev->duplex = DUPLEX_HALF;
+
+               switch (status) {
+               case MII_PHY_STATUS_1000:
+                       phydev->speed = SPEED_1000;
+                       break;
+
+               case MII_PHY_STATUS_100:
+                       phydev->speed = SPEED_100;
+                       break;
+
+               default:
+                       phydev->speed = SPEED_10;
+                       break;
+               }
+       } else {
+               int bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+
+               if (bmcr < 0)
+                       return bmcr;
+
+               if (bmcr & BMCR_FULLDPLX)
+                       phydev->duplex = DUPLEX_FULL;
+               else
+                       phydev->duplex = DUPLEX_HALF;
+
+               if (bmcr & BMCR_SPEED1000)
+                       phydev->speed = SPEED_1000;
+               else if (bmcr & BMCR_SPEED100)
+                       phydev->speed = SPEED_100;
+               else
+                       phydev->speed = SPEED_10;
+       }
+
+       /*
+        * For 1000BASE-X Phy Mode the speed/duplex will always be
+        * 1000Mbps/fullduplex
+        */
+       if (phydev->flags == XAE_PHY_TYPE_1000BASE_X) {
+               phydev->duplex = DUPLEX_FULL;
+               phydev->speed = SPEED_1000;
+       }
+
+       return 0;
+}
+
+static int xilinxphy_of_init(struct phy_device *phydev)
+{
+       struct udevice *dev = (struct udevice *)&phydev->dev;
+       u32 phytype;
+
+       debug("%s\n", __func__);
+       phytype = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "phy-type", -1);
+       if (phytype == XAE_PHY_TYPE_1000BASE_X)
+               phydev->flags |= XAE_PHY_TYPE_1000BASE_X;
+
+       return 0;
+}
+
+static int xilinxphy_config(struct phy_device *phydev)
+{
+       int temp;
+
+       debug("%s\n", __func__);
+       xilinxphy_of_init(phydev);
+       temp = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+       temp &= XPCSPMA_PHY_CTRL_ISOLATE_DISABLE;
+       phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, temp);
+
+       return 0;
+}
+
+static struct phy_driver xilinxphy_driver = {
+       .uid = XILINX_PHY_ID,
+       .mask = XILINX_PHY_ID_MASK,
+       .name = "Xilinx PCS/PMA PHY",
+       .features = PHY_GBIT_FEATURES,
+       .config = &xilinxphy_config,
+       .startup = &xilinxphy_startup,
+       .shutdown = &genphy_shutdown,
+};
+
+int phy_xilinx_init(void)
+{
+       debug("%s\n", __func__);
+       phy_register(&xilinxphy_driver);
+
+       return 0;
+}
index 09bbe483a4b120e1642d968692aeaad46ca63a9a..21459a8c80937b4808c0b5ddc7bc7274b93eaf2c 100644 (file)
@@ -264,6 +264,7 @@ int phy_smsc_init(void);
 int phy_teranetics_init(void);
 int phy_ti_init(void);
 int phy_vitesse_init(void);
+int phy_xilinx_init(void);
 
 int board_phy_config(struct phy_device *phydev);
 int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id);