Message ID | 1470137470-6051-8-git-send-email-jcmvbkbc@gmail.com |
---|---|
State | Superseded |
Delegated to: | Joe Hershberger |
Headers | show |
Hi Max, On Tue, Aug 2, 2016 at 6:31 AM, Max Filippov <jcmvbkbc@gmail.com> wrote: > Implement MDIO bus read/write functions, initialize the bus and scan for > the PHY when phylib is enabled. Limit PHY speeds to 10/100 Mbps. > > Cc: Michal Simek <monstr@monstr.eu> > Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> > --- > drivers/net/ethoc.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 146 insertions(+), 6 deletions(-) > > diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c > index fa623d5..fe04396 100644 > --- a/drivers/net/ethoc.c > +++ b/drivers/net/ethoc.c > @@ -181,6 +181,11 @@ struct ethoc { > void __iomem *iobase; > void __iomem *packet; > phys_addr_t packet_phys; > + > +#ifdef CONFIG_PHYLIB > + struct mii_dev *bus; > + struct phy_device *phydev; > +#endif > }; > > /** > @@ -319,13 +324,31 @@ static int ethoc_reset(struct ethoc *priv) > > static int ethoc_init_common(struct ethoc *priv) > { > + int ret = 0; > + > priv->num_tx = 1; > priv->num_rx = PKTBUFSRX; > ethoc_write(priv, TX_BD_NUM, priv->num_tx); > ethoc_init_ring(priv); > ethoc_reset(priv); > > - return 0; > +#ifdef CONFIG_PHYLIB > + ret = phy_startup(priv->phydev); > + if (ret) { > + printf("Could not initialize PHY %s\n", > + priv->phydev->dev->name); > + return ret; > + } > +#endif > + return ret; > +} > + > +static void ethoc_stop_common(struct ethoc *priv) > +{ > + ethoc_disable_rx_and_tx(priv); > +#ifdef CONFIG_PHYLIB > + phy_shutdown(priv->phydev); > +#endif > } > > static int ethoc_update_rx_stats(struct ethoc_bd *bd) > @@ -509,13 +532,119 @@ static int ethoc_free_pkt_common(struct ethoc *priv) > return 0; > } > > +#ifdef CONFIG_PHYLIB > + > +static int ethoc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) > +{ > + struct ethoc *priv = bus->priv; > + ulong tmo = get_timer(0); > + > + ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(addr, reg)); > + ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ); > + > + while (get_timer(tmo) < CONFIG_SYS_HZ) { > + u32 status = ethoc_read(priv, MIISTATUS); > + > + if (!(status & MIISTATUS_BUSY)) { It would be good to use wait_for_bit(). You could add a small helper to this file that adds the iobase to the addr and then calls wait_for_bit(). > + u32 data = ethoc_read(priv, MIIRX_DATA); > + > + /* reset MII command register */ > + ethoc_write(priv, MIICOMMAND, 0); > + return data; > + } > + } > + return -ETIMEDOUT; > +} > + > +static int ethoc_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, > + u16 val) > +{ > + struct ethoc *priv = bus->priv; > + ulong tmo = get_timer(0); > + > + ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(addr, reg)); > + ethoc_write(priv, MIITX_DATA, val); > + ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE); > + > + while (get_timer(tmo) < CONFIG_SYS_HZ) { > + u32 stat = ethoc_read(priv, MIISTATUS); > + > + if (!(stat & MIISTATUS_BUSY)) { > + /* reset MII command register */ > + ethoc_write(priv, MIICOMMAND, 0); > + return 0; > + } > + } > + return -ETIMEDOUT; > +} > + > +static int ethoc_mdio_init(const char *name, struct ethoc *priv) > +{ > + struct mii_dev *bus = mdio_alloc(); > + int ret; > + > + if (!bus) { > + printf("Failed to allocate MDIO bus\n"); > + return -ENOMEM; > + } > + > + bus->read = ethoc_mdio_read; > + bus->write = ethoc_mdio_write; > + snprintf(bus->name, sizeof(bus->name), "%s", name); > + bus->priv = priv; > + > + ret = mdio_register(bus); > + if (ret < 0) > + return ret; > + > + priv->bus = miiphy_get_dev_by_name(name); > + return 0; > +} > + > +static int ethoc_phy_init(struct ethoc *priv, void *dev) > +{ > + struct phy_device *phydev; > + int mask = 0xffffffff; > + > +#ifdef CONFIG_PHY_ADDR > + mask = 1 << CONFIG_PHY_ADDR; > +#endif > + > + phydev = phy_find_by_mask(priv->bus, mask, PHY_INTERFACE_MODE_MII); > + if (!phydev) > + return -ENODEV; > + > + phy_connect_dev(phydev, dev); > + > + phydev->supported &= PHY_BASIC_FEATURES; > + phydev->advertising = phydev->supported; > + > + priv->phydev = phydev; > + phy_config(phydev); > + > + return 0; > +} > + > +#else > + > +static inline int ethoc_mdio_init(const char *name, struct ethoc *priv) > +{ > + return 0; > +} > + > +static inline int ethoc_phy_init(struct ethoc *priv, void *dev) > +{ > + return 0; > +} > + > +#endif > + > #ifndef CONFIG_DM_ETH > > static int ethoc_init(struct eth_device *dev, bd_t *bd) > { > struct ethoc *priv = (struct ethoc *)dev->priv; > > - priv->iobase = ioremap(dev->iobase, ETHOC_IOSIZE); Why? Is this an accident? At the very least it seems unrelated and should be a separate patch. > return ethoc_init_common(priv); > } > > @@ -534,7 +663,7 @@ static int ethoc_send(struct eth_device *dev, void *packet, int length) > > static void ethoc_halt(struct eth_device *dev) > { > - ethoc_disable_rx_and_tx(dev->priv); > + ethoc_stop_common(dev->priv); > } > > static int ethoc_recv(struct eth_device *dev) > @@ -584,6 +713,10 @@ int ethoc_initialize(u8 dev_num, int base_addr) > priv->iobase = ioremap(dev->iobase, ETHOC_IOSIZE); > > eth_register(dev); > + > + ethoc_mdio_init(dev->name, priv); > + ethoc_phy_init(priv, dev); > + > return 1; > } > > @@ -625,9 +758,7 @@ static int ethoc_start(struct udevice *dev) > > static void ethoc_stop(struct udevice *dev) > { > - struct ethoc *priv = dev_get_priv(dev); > - > - ethoc_disable_rx_and_tx(priv); > + ethoc_stop_common(dev_get_priv(dev)); > } > > static int ethoc_ofdata_to_platdata(struct udevice *dev) > @@ -653,6 +784,10 @@ static int ethoc_probe(struct udevice *dev) > priv->packet = ioremap(pdata->packet_base, > (1 + PKTBUFSRX) * PKTSIZE_ALIGN); > } > + > + ethoc_mdio_init(dev->name, priv); > + ethoc_phy_init(priv, dev); > + > return 0; > } > > @@ -660,6 +795,11 @@ static int ethoc_remove(struct udevice *dev) > { > struct ethoc *priv = dev_get_priv(dev); > > +#ifdef CONFIG_PHYLIB > + free(priv->phydev); > + mdio_unregister(priv->bus); > + mdio_free(priv->bus); > +#endif > iounmap(priv->iobase); > return 0; > } > -- > 2.1.4 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot
On Thu, Aug 4, 2016 at 11:48 PM, Joe Hershberger <joe.hershberger@gmail.com> wrote: > On Tue, Aug 2, 2016 at 6:31 AM, Max Filippov <jcmvbkbc@gmail.com> wrote: >> Implement MDIO bus read/write functions, initialize the bus and scan for >> the PHY when phylib is enabled. Limit PHY speeds to 10/100 Mbps. >> >> Cc: Michal Simek <monstr@monstr.eu> >> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> [...] >> +static int ethoc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) >> +{ >> + struct ethoc *priv = bus->priv; >> + ulong tmo = get_timer(0); >> + >> + ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(addr, reg)); >> + ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ); >> + >> + while (get_timer(tmo) < CONFIG_SYS_HZ) { >> + u32 status = ethoc_read(priv, MIISTATUS); >> + >> + if (!(status & MIISTATUS_BUSY)) { > > It would be good to use wait_for_bit(). You could add a small helper > to this file that adds the iobase to the addr and then calls > wait_for_bit(). Ok. [...] >> static int ethoc_init(struct eth_device *dev, bd_t *bd) >> { >> struct ethoc *priv = (struct ethoc *)dev->priv; >> >> - priv->iobase = ioremap(dev->iobase, ETHOC_IOSIZE); > > Why? Is this an accident? At the very least it seems unrelated and > should be a separate patch. Oops, right. I've been moving this bit around several times and apparently haven't cleaned up all of its traces.
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index fa623d5..fe04396 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -181,6 +181,11 @@ struct ethoc { void __iomem *iobase; void __iomem *packet; phys_addr_t packet_phys; + +#ifdef CONFIG_PHYLIB + struct mii_dev *bus; + struct phy_device *phydev; +#endif }; /** @@ -319,13 +324,31 @@ static int ethoc_reset(struct ethoc *priv) static int ethoc_init_common(struct ethoc *priv) { + int ret = 0; + priv->num_tx = 1; priv->num_rx = PKTBUFSRX; ethoc_write(priv, TX_BD_NUM, priv->num_tx); ethoc_init_ring(priv); ethoc_reset(priv); - return 0; +#ifdef CONFIG_PHYLIB + ret = phy_startup(priv->phydev); + if (ret) { + printf("Could not initialize PHY %s\n", + priv->phydev->dev->name); + return ret; + } +#endif + return ret; +} + +static void ethoc_stop_common(struct ethoc *priv) +{ + ethoc_disable_rx_and_tx(priv); +#ifdef CONFIG_PHYLIB + phy_shutdown(priv->phydev); +#endif } static int ethoc_update_rx_stats(struct ethoc_bd *bd) @@ -509,13 +532,119 @@ static int ethoc_free_pkt_common(struct ethoc *priv) return 0; } +#ifdef CONFIG_PHYLIB + +static int ethoc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct ethoc *priv = bus->priv; + ulong tmo = get_timer(0); + + ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(addr, reg)); + ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ); + + while (get_timer(tmo) < CONFIG_SYS_HZ) { + u32 status = ethoc_read(priv, MIISTATUS); + + if (!(status & MIISTATUS_BUSY)) { + u32 data = ethoc_read(priv, MIIRX_DATA); + + /* reset MII command register */ + ethoc_write(priv, MIICOMMAND, 0); + return data; + } + } + return -ETIMEDOUT; +} + +static int ethoc_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 val) +{ + struct ethoc *priv = bus->priv; + ulong tmo = get_timer(0); + + ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(addr, reg)); + ethoc_write(priv, MIITX_DATA, val); + ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE); + + while (get_timer(tmo) < CONFIG_SYS_HZ) { + u32 stat = ethoc_read(priv, MIISTATUS); + + if (!(stat & MIISTATUS_BUSY)) { + /* reset MII command register */ + ethoc_write(priv, MIICOMMAND, 0); + return 0; + } + } + return -ETIMEDOUT; +} + +static int ethoc_mdio_init(const char *name, struct ethoc *priv) +{ + struct mii_dev *bus = mdio_alloc(); + int ret; + + if (!bus) { + printf("Failed to allocate MDIO bus\n"); + return -ENOMEM; + } + + bus->read = ethoc_mdio_read; + bus->write = ethoc_mdio_write; + snprintf(bus->name, sizeof(bus->name), "%s", name); + bus->priv = priv; + + ret = mdio_register(bus); + if (ret < 0) + return ret; + + priv->bus = miiphy_get_dev_by_name(name); + return 0; +} + +static int ethoc_phy_init(struct ethoc *priv, void *dev) +{ + struct phy_device *phydev; + int mask = 0xffffffff; + +#ifdef CONFIG_PHY_ADDR + mask = 1 << CONFIG_PHY_ADDR; +#endif + + phydev = phy_find_by_mask(priv->bus, mask, PHY_INTERFACE_MODE_MII); + if (!phydev) + return -ENODEV; + + phy_connect_dev(phydev, dev); + + phydev->supported &= PHY_BASIC_FEATURES; + phydev->advertising = phydev->supported; + + priv->phydev = phydev; + phy_config(phydev); + + return 0; +} + +#else + +static inline int ethoc_mdio_init(const char *name, struct ethoc *priv) +{ + return 0; +} + +static inline int ethoc_phy_init(struct ethoc *priv, void *dev) +{ + return 0; +} + +#endif + #ifndef CONFIG_DM_ETH static int ethoc_init(struct eth_device *dev, bd_t *bd) { struct ethoc *priv = (struct ethoc *)dev->priv; - priv->iobase = ioremap(dev->iobase, ETHOC_IOSIZE); return ethoc_init_common(priv); } @@ -534,7 +663,7 @@ static int ethoc_send(struct eth_device *dev, void *packet, int length) static void ethoc_halt(struct eth_device *dev) { - ethoc_disable_rx_and_tx(dev->priv); + ethoc_stop_common(dev->priv); } static int ethoc_recv(struct eth_device *dev) @@ -584,6 +713,10 @@ int ethoc_initialize(u8 dev_num, int base_addr) priv->iobase = ioremap(dev->iobase, ETHOC_IOSIZE); eth_register(dev); + + ethoc_mdio_init(dev->name, priv); + ethoc_phy_init(priv, dev); + return 1; } @@ -625,9 +758,7 @@ static int ethoc_start(struct udevice *dev) static void ethoc_stop(struct udevice *dev) { - struct ethoc *priv = dev_get_priv(dev); - - ethoc_disable_rx_and_tx(priv); + ethoc_stop_common(dev_get_priv(dev)); } static int ethoc_ofdata_to_platdata(struct udevice *dev) @@ -653,6 +784,10 @@ static int ethoc_probe(struct udevice *dev) priv->packet = ioremap(pdata->packet_base, (1 + PKTBUFSRX) * PKTSIZE_ALIGN); } + + ethoc_mdio_init(dev->name, priv); + ethoc_phy_init(priv, dev); + return 0; } @@ -660,6 +795,11 @@ static int ethoc_remove(struct udevice *dev) { struct ethoc *priv = dev_get_priv(dev); +#ifdef CONFIG_PHYLIB + free(priv->phydev); + mdio_unregister(priv->bus); + mdio_free(priv->bus); +#endif iounmap(priv->iobase); return 0; }
Implement MDIO bus read/write functions, initialize the bus and scan for the PHY when phylib is enabled. Limit PHY speeds to 10/100 Mbps. Cc: Michal Simek <monstr@monstr.eu> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> --- drivers/net/ethoc.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 146 insertions(+), 6 deletions(-)