]> rtime.felk.cvut.cz Git - vajnamar/linux-xlnx.git/commitdiff
net: phy: Add gmiitorgmii converter support
authorKedareswara rao Appana <appanad@xilinx.com>
Thu, 8 Sep 2016 04:17:39 +0000 (09:47 +0530)
committerSoren Brinkmann <soren.brinkmann@xilinx.com>
Tue, 13 Sep 2016 18:22:13 +0000 (11:22 -0700)
This patch adds support for gmiitorgmii converter.

The GMII to RGMII IP core provides the Reduced Gigabit Media
Independent Interface (RGMII) between Ethernet physical media
Devices and the Gigabit Ethernet controller. This core can
Switch dynamically between the three different speed modes of
Operation by configuring the converter register through mdio write.

MDIO interface is used to set operating speed of Ethernet MAC.

This converter sits between the MAC and the external phy
MAC <==> GMII2RGMII <==> RGMII_PHY

Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com>
Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com>
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/xilinx_gmii2rgmii.c [new file with mode: 0644]

index 3e9e4f7f3aa871f214f0bcef9429fb465443ff04..d4d4373424209d85c41054bbeb8fdcd472b8a86d 100644 (file)
@@ -276,6 +276,13 @@ config MDIO_BCM_IPROC
          This module provides a driver for the MDIO busses found in the
          Broadcom iProc SoC's.
 
+config XILINX_GMII2RGMII
+       tristate "Xilinx GMII2RGMII converter driver"
+       ---help---
+         This driver support xilinx GMII to RGMII IP core it provides
+         the Reduced Gigabit Media Independent Interface(RGMII) between
+         Ethernet physical media devices and the Gigabit Ethernet controller.
+
 endif # PHYLIB
 
 config MICREL_KS8995MA
index 30f7be97db2d7bdaa98c8a9878fe071aca060feb..640084eb27b64b1e91dd4f75cf37796902f9f7c0 100644 (file)
@@ -45,3 +45,4 @@ obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
 obj-$(CONFIG_MICROCHIP_PHY)    += microchip.o
 obj-$(CONFIG_MDIO_BCM_IPROC)   += mdio-bcm-iproc.o
 obj-$(CONFIG_XILINX_PHY)       += xilinx_phy.o
+obj-$(CONFIG_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c
new file mode 100644 (file)
index 0000000..d15dd39
--- /dev/null
@@ -0,0 +1,112 @@
+/* Xilinx GMII2RGMII Converter driver
+ *
+ * Copyright (C) 2016 Xilinx, Inc.
+ * Copyright (C) 2016 Andrew Lunn <andrew@lunn.ch>
+ *
+ * Author: Andrew Lunn <andrew@lunn.ch>
+ * Author: Kedareswara rao Appana <appanad@xilinx.com>
+ *
+ * Description:
+ * This driver is developed for Xilinx GMII2RGMII Converter
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/mdio.h>
+#include <linux/phy.h>
+#include <linux/of_mdio.h>
+
+#define XILINX_GMII2RGMII_REG          0x10
+#define XILINX_GMII2RGMII_SPEED_MASK   (BMCR_SPEED1000 | BMCR_SPEED100)
+
+struct gmii2rgmii {
+       struct phy_device *phy_dev;
+       struct phy_driver *phy_drv;
+       struct phy_driver conv_phy_drv;
+       int addr;
+};
+
+static int xgmiitorgmii_read_status(struct phy_device *phydev)
+{
+       struct gmii2rgmii *priv = phydev->priv;
+       u16 val = 0;
+
+       priv->phy_drv->read_status(phydev);
+
+       val = mdiobus_read(phydev->mdio.bus, priv->addr, XILINX_GMII2RGMII_REG);
+       val &= XILINX_GMII2RGMII_SPEED_MASK;
+
+       if (phydev->speed == SPEED_1000)
+               val |= BMCR_SPEED1000;
+       else if (phydev->speed == SPEED_100)
+               val |= BMCR_SPEED100;
+       else
+               val |= BMCR_SPEED10;
+
+       mdiobus_write(phydev->mdio.bus, priv->addr, XILINX_GMII2RGMII_REG, val);
+
+       return 0;
+}
+
+static int xgmiitorgmii_probe(struct mdio_device *mdiodev)
+{
+       struct device *dev = &mdiodev->dev;
+       struct device_node *np = dev->of_node, *phy_node;
+       struct gmii2rgmii *priv;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       phy_node = of_parse_phandle(np, "phy-handle", 0);
+       if (!phy_node) {
+               dev_err(dev, "Couldn't parse phy-handle\n");
+               return -ENODEV;
+       }
+
+       priv->phy_dev = of_phy_find_device(phy_node);
+       of_node_put(phy_node);
+       if (!priv->phy_dev) {
+               dev_info(dev, "Couldn't find phydev\n");
+               return -EPROBE_DEFER;
+       }
+
+       priv->addr = mdiodev->addr;
+       priv->phy_drv = priv->phy_dev->drv;
+       memcpy(&priv->conv_phy_drv, priv->phy_dev->drv,
+              sizeof(struct phy_driver));
+       priv->conv_phy_drv.read_status = xgmiitorgmii_read_status;
+       priv->phy_dev->priv = priv;
+       priv->phy_dev->drv = &priv->conv_phy_drv;
+
+       return 0;
+}
+
+static const struct of_device_id xgmiitorgmii_of_match[] = {
+       { .compatible = "xlnx,gmii-to-rgmii-1.0" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xgmiitorgmii_of_match);
+
+static struct mdio_driver xgmiitorgmii_driver = {
+       .probe  = xgmiitorgmii_probe,
+       .mdiodrv.driver = {
+               .name = "xgmiitorgmii",
+               .of_match_table = xgmiitorgmii_of_match,
+       },
+};
+
+mdio_module_driver(xgmiitorgmii_driver);
+
+MODULE_DESCRIPTION("Xilinx GMII2RGMII converter driver");
+MODULE_LICENSE("GPL");