st 11. 9. 2019 v 14:08 odesÃlatel Michal Simek <[email protected]> napsal: > > From: Siva Durga Prasad Paladugu <[email protected]> > > 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 <[email protected]> > Signed-off-by: Michal Simek <[email protected]> > --- > > 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 _______________________________________________ U-Boot mailing list [email protected] https://lists.denx.de/listinfo/u-boot

