[U-Boot] [PATCH v3] net: phy: Add gmiitorgmii converter support

Michal Simek monstr at monstr.eu
Tue Oct 8 07:48:22 UTC 2019


st 11. 9. 2019 v 14:08 odesílatel Michal Simek <michal.simek at xilinx.com> napsal:
>
> From: Siva Durga Prasad Paladugu <siva.durga.paladugu at xilinx.com>
>
> 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 at xilinx.com>
> Signed-off-by: Michal Simek <michal.simek at xilinx.com>
> ---
>
> Changes in v3:
> - Check that input interface type is gmii
> - Hardcode rgmii interface type
> - Add check for external phy detection
> - Fill node pointer for external phy
> - Define readext and writeext routines
>
> Changes in v2:
> - Include "net: phy: Fix logic around gmiitorgmii wiring" patch
> - Update patch on the top of
>  "net: phy: Add clause 45 identifier to phy_device
>  (sha1: b3eabd82f21b4d9206622fc5aee16751d2f4be8f) which adds one more
>  parameter to phy_device_create (bool is_c45)
>
> It is quite a long time when I sent v2 on this. There were some changes we
> found in connection to this driver and it's wiring.
>
> DT binding is present here.
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/net/xilinx_gmii2rgmii.txt
>
> v2
> https://lists.denx.de/pipermail/u-boot/2019-January/356777.html
> v1
> https://lists.denx.de/pipermail/u-boot/2018-November/349309.html
>
> ---
>  drivers/net/phy/Kconfig             |   7 ++
>  drivers/net/phy/Makefile            |   1 +
>  drivers/net/phy/phy.c               |  42 ++++++++
>  drivers/net/phy/xilinx_gmii2rgmii.c | 144 ++++++++++++++++++++++++++++
>  include/phy.h                       |   6 ++
>  5 files changed, 200 insertions(+)
>  create mode 100644 drivers/net/phy/xilinx_gmii2rgmii.c
>
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index 2a3da068c90a..30bd8e765304 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -228,6 +228,13 @@ config PHY_VITESSE
>  config PHY_XILINX
>         bool "Xilinx Ethernet PHYs support"
>
> +config PHY_XILINX_GMII2RGMII
> +       bool "Xilinx GMII to RGMII Ethernet PHYs support"
> +       help
> +         This adds support for Xilinx GMII to RGMII IP core. This IP acts
> +         as bridge between MAC connected over GMII and external phy that
> +         is connected over RGMII interface.
> +
>  config PHY_FIXED
>         bool "Fixed-Link PHY"
>         depends on DM_ETH
> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> index 555da83630f4..76b6197009bc 100644
> --- a/drivers/net/phy/Makefile
> +++ b/drivers/net/phy/Makefile
> @@ -27,6 +27,7 @@ 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_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
>  obj-$(CONFIG_PHY_VITESSE) += vitesse.o
>  obj-$(CONFIG_PHY_MSCC) += mscc.o
>  obj-$(CONFIG_PHY_FIXED) += fixed.o
> diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
> index 8c4043445e86..f2d17aa91a07 100644
> --- a/drivers/net/phy/phy.c
> +++ b/drivers/net/phy/phy.c
> @@ -544,6 +544,9 @@ int phy_init(void)
>  #endif
>  #ifdef CONFIG_PHY_FIXED
>         phy_fixed_init();
> +#endif
> +#ifdef CONFIG_PHY_XILINX_GMII2RGMII
> +       phy_xilinx_gmii2rgmii_init();
>  #endif
>         genphy_init();
>
> @@ -918,6 +921,41 @@ void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev)
>         debug("%s connected to %s\n", dev->name, phydev->drv->name);
>  }
>
> +#ifdef CONFIG_PHY_XILINX_GMII2RGMII
> +#ifdef CONFIG_DM_ETH
> +static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus,
> +                                                struct udevice *dev,
> +                                                phy_interface_t interface)
> +#else
> +static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus,
> +                                                struct eth_device *dev,
> +                                                phy_interface_t interface)
> +#endif
> +{
> +       struct phy_device *phydev = NULL;
> +       int sn = dev_of_offset(dev);
> +       int off;
> +
> +       while (sn > 0) {
> +               off = fdt_node_offset_by_compatible(gd->fdt_blob, sn,
> +                                                   "xlnx,gmii-to-rgmii-1.0");
> +               if (off > 0) {
> +                       phydev = phy_device_create(bus, off,
> +                                                  PHY_GMII2RGMII_ID, false,
> +                                                  interface);
> +                       break;
> +               }
> +               if (off == -FDT_ERR_NOTFOUND)
> +                       sn = fdt_first_subnode(gd->fdt_blob, sn);
> +               else
> +                       printf("%s: Error finding compat string:%d\n",
> +                              __func__, off);
> +       }
> +
> +       return phydev;
> +}
> +#endif
> +
>  #ifdef CONFIG_PHY_FIXED
>  #ifdef CONFIG_DM_ETH
>  static struct phy_device *phy_connect_fixed(struct mii_dev *bus,
> @@ -964,6 +1002,10 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr,
>  #ifdef CONFIG_PHY_FIXED
>         phydev = phy_connect_fixed(bus, dev, interface);
>  #endif
> +#ifdef CONFIG_PHY_XILINX_GMII2RGMII
> +       if (!phydev)
> +               phydev = phy_connect_gmii2rgmii(bus, dev, interface);
> +#endif
>
>         if (!phydev)
>                 phydev = phy_find_by_mask(bus, mask, interface);
> diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c
> new file mode 100644
> index 000000000000..8c20da268206
> --- /dev/null
> +++ b/drivers/net/phy/xilinx_gmii2rgmii.c
> @@ -0,0 +1,144 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Xilinx GMII2RGMII phy driver
> + *
> + * Copyright (C) 2018 Xilinx, Inc.
> + */
> +
> +#include <dm.h>
> +#include <phy.h>
> +#include <config.h>
> +#include <common.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#define ZYNQ_GMII2RGMII_REG            0x10
> +#define ZYNQ_GMII2RGMII_SPEED_MASK     (BMCR_SPEED1000 | BMCR_SPEED100)
> +
> +static int xilinxgmiitorgmii_config(struct phy_device *phydev)
> +{
> +       struct phy_device *ext_phydev = phydev->priv;
> +
> +       debug("%s\n", __func__);
> +       if (ext_phydev->drv->config)
> +               ext_phydev->drv->config(ext_phydev);
> +
> +       return 0;
> +}
> +
> +static int xilinxgmiitorgmii_extread(struct phy_device *phydev, int addr,
> +                                    int devaddr, int regnum)
> +{
> +       struct phy_device *ext_phydev = phydev->priv;
> +
> +       debug("%s\n", __func__);
> +       if (ext_phydev->drv->readext)
> +               ext_phydev->drv->readext(ext_phydev, addr, devaddr, regnum);
> +
> +       return 0;
> +}
> +
> +static int xilinxgmiitorgmii_extwrite(struct phy_device *phydev, int addr,
> +                                     int devaddr, int regnum, u16 val)
> +
> +{
> +       struct phy_device *ext_phydev = phydev->priv;
> +
> +       debug("%s\n", __func__);
> +       if (ext_phydev->drv->writeext)
> +               ext_phydev->drv->writeext(ext_phydev, addr, devaddr, regnum,
> +                                         val);
> +
> +       return 0;
> +}
> +
> +static int xilinxgmiitorgmii_startup(struct phy_device *phydev)
> +{
> +       u16 val = 0;
> +       struct phy_device *ext_phydev = phydev->priv;
> +
> +       debug("%s\n", __func__);
> +       ext_phydev->dev = phydev->dev;
> +       if (ext_phydev->drv->startup)
> +               ext_phydev->drv->startup(ext_phydev);
> +
> +       val = phy_read(phydev, phydev->addr, ZYNQ_GMII2RGMII_REG);
> +       val &= ~ZYNQ_GMII2RGMII_SPEED_MASK;
> +
> +       if (ext_phydev->speed == SPEED_1000)
> +               val |= BMCR_SPEED1000;
> +       else if (ext_phydev->speed == SPEED_100)
> +               val |= BMCR_SPEED100;
> +
> +       phy_write(phydev, phydev->addr, ZYNQ_GMII2RGMII_REG, val |
> +                 BMCR_FULLDPLX);
> +
> +       phydev->duplex = ext_phydev->duplex;
> +       phydev->speed = ext_phydev->speed;
> +       phydev->link = ext_phydev->link;
> +
> +       return 0;
> +}
> +
> +static int xilinxgmiitorgmii_probe(struct phy_device *phydev)
> +{
> +       int ofnode = phydev->addr;
> +       u32 phy_of_handle;
> +       int ext_phyaddr = -1;
> +       struct phy_device *ext_phydev;
> +
> +       debug("%s\n", __func__);
> +
> +       if (phydev->interface != PHY_INTERFACE_MODE_GMII) {
> +               printf("Incorrect interface type\n");
> +               return -EINVAL;
> +       }
> +
> +       /*
> +        * Read the phy address again as the one we read in ethernet driver
> +        * was overwritten for the purpose of storing the ofnode
> +        */
> +       phydev->addr = fdtdec_get_int(gd->fdt_blob, ofnode, "reg", -1);
> +       phy_of_handle = fdtdec_lookup_phandle(gd->fdt_blob, ofnode,
> +                                             "phy-handle");
> +       if (phy_of_handle > 0)
> +               ext_phyaddr = fdtdec_get_int(gd->fdt_blob,
> +                                            phy_of_handle,
> +                                            "reg", -1);
> +       ext_phydev = phy_find_by_mask(phydev->bus,
> +                                     1 << ext_phyaddr,
> +                                     PHY_INTERFACE_MODE_RGMII);
> +       if (!ext_phydev) {
> +               printf("%s, No external phy device found\n", __func__);
> +               return -EINVAL;
> +       }
> +
> +       ext_phydev->node = offset_to_ofnode(phy_of_handle);
> +       phydev->priv = ext_phydev;
> +
> +       debug("%s, gmii2rgmmi:0x%x, extphy:0x%x\n", __func__, phydev->addr,
> +             ext_phyaddr);
> +
> +       phydev->flags |= PHY_FLAG_BROKEN_RESET;
> +
> +       return 0;
> +}
> +
> +static struct phy_driver gmii2rgmii_driver = {
> +       .name = "XILINX GMII2RGMII",
> +       .uid = PHY_GMII2RGMII_ID,
> +       .mask = 0xffffffff,
> +       .features = PHY_GBIT_FEATURES,
> +       .probe = xilinxgmiitorgmii_probe,
> +       .config = xilinxgmiitorgmii_config,
> +       .startup = xilinxgmiitorgmii_startup,
> +       .writeext = xilinxgmiitorgmii_extwrite,
> +       .readext = xilinxgmiitorgmii_extread,
> +};
> +
> +int phy_xilinx_gmii2rgmii_init(void)
> +{
> +       phy_register(&gmii2rgmii_driver);
> +
> +       return 0;
> +}
> diff --git a/include/phy.h b/include/phy.h
> index f4530faeb997..e50f56b6eb16 100644
> --- a/include/phy.h
> +++ b/include/phy.h
> @@ -17,6 +17,11 @@
>  #include <phy_interface.h>
>
>  #define PHY_FIXED_ID           0xa5a55a5a
> +/*
> + * There is no actual id for this.
> + * This is just a dummy id for gmii2rgmmi converter.
> + */
> +#define PHY_GMII2RGMII_ID      0x5a5a5a5a
>
>  #define PHY_MAX_ADDR 32
>
> @@ -391,6 +396,7 @@ int phy_vitesse_init(void);
>  int phy_xilinx_init(void);
>  int phy_mscc_init(void);
>  int phy_fixed_init(void);
> +int phy_xilinx_gmii2rgmii_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);
> --
> 2.17.1
>

It is assigned to me in patchwork that's why I am applying it.
M


-- 
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs


More information about the U-Boot mailing list