Commit f41e588c033f31cdf4b1f1c70fac2e0264c6c4db

Authored by Siva Durga Prasad Paladugu
Committed by Michal Simek
1 parent 83a0e8054e

net: phy: Add gmiitorgmii converter support

This patch adds support for gmiitorgmii converter.
This converter sits between the MAC and the external phy
MAC <==> GMII2RGMII <==> RGMII_PHY.
The ethernet driver probes this bridge and this bridge driver
probes real phy driver and invokes the real phy functionalities
as requested. This bridge just needs to be configured based on
real phy negotiated speed and duplex.

Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>

Showing 5 changed files with 200 additions and 0 deletions Side-by-side Diff

drivers/net/phy/Kconfig
... ... @@ -228,6 +228,13 @@
228 228 config PHY_XILINX
229 229 bool "Xilinx Ethernet PHYs support"
230 230  
  231 +config PHY_XILINX_GMII2RGMII
  232 + bool "Xilinx GMII to RGMII Ethernet PHYs support"
  233 + help
  234 + This adds support for Xilinx GMII to RGMII IP core. This IP acts
  235 + as bridge between MAC connected over GMII and external phy that
  236 + is connected over RGMII interface.
  237 +
231 238 config PHY_FIXED
232 239 bool "Fixed-Link PHY"
233 240 depends on DM_ETH
drivers/net/phy/Makefile
... ... @@ -27,6 +27,7 @@
27 27 obj-$(CONFIG_PHY_TERANETICS) += teranetics.o
28 28 obj-$(CONFIG_PHY_TI) += ti.o
29 29 obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
  30 +obj-$(CONFIG_PHY_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
30 31 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
31 32 obj-$(CONFIG_PHY_MSCC) += mscc.o
32 33 obj-$(CONFIG_PHY_FIXED) += fixed.o
drivers/net/phy/phy.c
... ... @@ -545,6 +545,9 @@
545 545 #ifdef CONFIG_PHY_FIXED
546 546 phy_fixed_init();
547 547 #endif
  548 +#ifdef CONFIG_PHY_XILINX_GMII2RGMII
  549 + phy_xilinx_gmii2rgmii_init();
  550 +#endif
548 551 genphy_init();
549 552  
550 553 return 0;
... ... @@ -918,6 +921,41 @@
918 921 debug("%s connected to %s\n", dev->name, phydev->drv->name);
919 922 }
920 923  
  924 +#ifdef CONFIG_PHY_XILINX_GMII2RGMII
  925 +#ifdef CONFIG_DM_ETH
  926 +static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus,
  927 + struct udevice *dev,
  928 + phy_interface_t interface)
  929 +#else
  930 +static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus,
  931 + struct eth_device *dev,
  932 + phy_interface_t interface)
  933 +#endif
  934 +{
  935 + struct phy_device *phydev = NULL;
  936 + int sn = dev_of_offset(dev);
  937 + int off;
  938 +
  939 + while (sn > 0) {
  940 + off = fdt_node_offset_by_compatible(gd->fdt_blob, sn,
  941 + "xlnx,gmii-to-rgmii-1.0");
  942 + if (off > 0) {
  943 + phydev = phy_device_create(bus, off,
  944 + PHY_GMII2RGMII_ID, false,
  945 + interface);
  946 + break;
  947 + }
  948 + if (off == -FDT_ERR_NOTFOUND)
  949 + sn = fdt_first_subnode(gd->fdt_blob, sn);
  950 + else
  951 + printf("%s: Error finding compat string:%d\n",
  952 + __func__, off);
  953 + }
  954 +
  955 + return phydev;
  956 +}
  957 +#endif
  958 +
921 959 #ifdef CONFIG_PHY_FIXED
922 960 #ifdef CONFIG_DM_ETH
923 961 static struct phy_device *phy_connect_fixed(struct mii_dev *bus,
... ... @@ -963,6 +1001,10 @@
963 1001  
964 1002 #ifdef CONFIG_PHY_FIXED
965 1003 phydev = phy_connect_fixed(bus, dev, interface);
  1004 +#endif
  1005 +#ifdef CONFIG_PHY_XILINX_GMII2RGMII
  1006 + if (!phydev)
  1007 + phydev = phy_connect_gmii2rgmii(bus, dev, interface);
966 1008 #endif
967 1009  
968 1010 if (!phydev)
drivers/net/phy/xilinx_gmii2rgmii.c
  1 +// SPDX-License-Identifier: GPL-2.0
  2 +/*
  3 + * Xilinx GMII2RGMII phy driver
  4 + *
  5 + * Copyright (C) 2018 Xilinx, Inc.
  6 + */
  7 +
  8 +#include <dm.h>
  9 +#include <phy.h>
  10 +#include <config.h>
  11 +#include <common.h>
  12 +
  13 +DECLARE_GLOBAL_DATA_PTR;
  14 +
  15 +#define ZYNQ_GMII2RGMII_REG 0x10
  16 +#define ZYNQ_GMII2RGMII_SPEED_MASK (BMCR_SPEED1000 | BMCR_SPEED100)
  17 +
  18 +static int xilinxgmiitorgmii_config(struct phy_device *phydev)
  19 +{
  20 + struct phy_device *ext_phydev = phydev->priv;
  21 +
  22 + debug("%s\n", __func__);
  23 + if (ext_phydev->drv->config)
  24 + ext_phydev->drv->config(ext_phydev);
  25 +
  26 + return 0;
  27 +}
  28 +
  29 +static int xilinxgmiitorgmii_extread(struct phy_device *phydev, int addr,
  30 + int devaddr, int regnum)
  31 +{
  32 + struct phy_device *ext_phydev = phydev->priv;
  33 +
  34 + debug("%s\n", __func__);
  35 + if (ext_phydev->drv->readext)
  36 + ext_phydev->drv->readext(ext_phydev, addr, devaddr, regnum);
  37 +
  38 + return 0;
  39 +}
  40 +
  41 +static int xilinxgmiitorgmii_extwrite(struct phy_device *phydev, int addr,
  42 + int devaddr, int regnum, u16 val)
  43 +
  44 +{
  45 + struct phy_device *ext_phydev = phydev->priv;
  46 +
  47 + debug("%s\n", __func__);
  48 + if (ext_phydev->drv->writeext)
  49 + ext_phydev->drv->writeext(ext_phydev, addr, devaddr, regnum,
  50 + val);
  51 +
  52 + return 0;
  53 +}
  54 +
  55 +static int xilinxgmiitorgmii_startup(struct phy_device *phydev)
  56 +{
  57 + u16 val = 0;
  58 + struct phy_device *ext_phydev = phydev->priv;
  59 +
  60 + debug("%s\n", __func__);
  61 + ext_phydev->dev = phydev->dev;
  62 + if (ext_phydev->drv->startup)
  63 + ext_phydev->drv->startup(ext_phydev);
  64 +
  65 + val = phy_read(phydev, phydev->addr, ZYNQ_GMII2RGMII_REG);
  66 + val &= ~ZYNQ_GMII2RGMII_SPEED_MASK;
  67 +
  68 + if (ext_phydev->speed == SPEED_1000)
  69 + val |= BMCR_SPEED1000;
  70 + else if (ext_phydev->speed == SPEED_100)
  71 + val |= BMCR_SPEED100;
  72 +
  73 + phy_write(phydev, phydev->addr, ZYNQ_GMII2RGMII_REG, val |
  74 + BMCR_FULLDPLX);
  75 +
  76 + phydev->duplex = ext_phydev->duplex;
  77 + phydev->speed = ext_phydev->speed;
  78 + phydev->link = ext_phydev->link;
  79 +
  80 + return 0;
  81 +}
  82 +
  83 +static int xilinxgmiitorgmii_probe(struct phy_device *phydev)
  84 +{
  85 + int ofnode = phydev->addr;
  86 + u32 phy_of_handle;
  87 + int ext_phyaddr = -1;
  88 + struct phy_device *ext_phydev;
  89 +
  90 + debug("%s\n", __func__);
  91 +
  92 + if (phydev->interface != PHY_INTERFACE_MODE_GMII) {
  93 + printf("Incorrect interface type\n");
  94 + return -EINVAL;
  95 + }
  96 +
  97 + /*
  98 + * Read the phy address again as the one we read in ethernet driver
  99 + * was overwritten for the purpose of storing the ofnode
  100 + */
  101 + phydev->addr = fdtdec_get_int(gd->fdt_blob, ofnode, "reg", -1);
  102 + phy_of_handle = fdtdec_lookup_phandle(gd->fdt_blob, ofnode,
  103 + "phy-handle");
  104 + if (phy_of_handle > 0)
  105 + ext_phyaddr = fdtdec_get_int(gd->fdt_blob,
  106 + phy_of_handle,
  107 + "reg", -1);
  108 + ext_phydev = phy_find_by_mask(phydev->bus,
  109 + 1 << ext_phyaddr,
  110 + PHY_INTERFACE_MODE_RGMII);
  111 + if (!ext_phydev) {
  112 + printf("%s, No external phy device found\n", __func__);
  113 + return -EINVAL;
  114 + }
  115 +
  116 + ext_phydev->node = offset_to_ofnode(phy_of_handle);
  117 + phydev->priv = ext_phydev;
  118 +
  119 + debug("%s, gmii2rgmmi:0x%x, extphy:0x%x\n", __func__, phydev->addr,
  120 + ext_phyaddr);
  121 +
  122 + phydev->flags |= PHY_FLAG_BROKEN_RESET;
  123 +
  124 + return 0;
  125 +}
  126 +
  127 +static struct phy_driver gmii2rgmii_driver = {
  128 + .name = "XILINX GMII2RGMII",
  129 + .uid = PHY_GMII2RGMII_ID,
  130 + .mask = 0xffffffff,
  131 + .features = PHY_GBIT_FEATURES,
  132 + .probe = xilinxgmiitorgmii_probe,
  133 + .config = xilinxgmiitorgmii_config,
  134 + .startup = xilinxgmiitorgmii_startup,
  135 + .writeext = xilinxgmiitorgmii_extwrite,
  136 + .readext = xilinxgmiitorgmii_extread,
  137 +};
  138 +
  139 +int phy_xilinx_gmii2rgmii_init(void)
  140 +{
  141 + phy_register(&gmii2rgmii_driver);
  142 +
  143 + return 0;
  144 +}
... ... @@ -17,6 +17,11 @@
17 17 #include <phy_interface.h>
18 18  
19 19 #define PHY_FIXED_ID 0xa5a55a5a
  20 +/*
  21 + * There is no actual id for this.
  22 + * This is just a dummy id for gmii2rgmmi converter.
  23 + */
  24 +#define PHY_GMII2RGMII_ID 0x5a5a5a5a
20 25  
21 26 #define PHY_MAX_ADDR 32
22 27  
... ... @@ -391,6 +396,7 @@
391 396 int phy_xilinx_init(void);
392 397 int phy_mscc_init(void);
393 398 int phy_fixed_init(void);
  399 +int phy_xilinx_gmii2rgmii_init(void);
394 400  
395 401 int board_phy_config(struct phy_device *phydev);
396 402 int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id);