On Thu, Oct 6, 2016 at 12:55 PM, Jagan Teki <jt...@openedev.com> wrote: > From: Jagan Teki <ja...@amarulasolutions.com> > > This patch add driver model support for fec_mxc driver. > > Cc: Simon Glass <s...@chromium.org> > Cc: Joe Hershberger <joe.hershber...@ni.com> > Cc: Peng Fan <peng....@nxp.com> > Cc: Stefano Babic <sba...@denx.de> > Cc: Michael Trimarchi <mich...@amarulasolutions.com> > Signed-off-by: Jagan Teki <ja...@amarulasolutions.com> > --- > drivers/net/fec_mxc.c | 314 > ++++++++++++++++++++++++++++++++++++++++++-------- > drivers/net/fec_mxc.h | 4 + > 2 files changed, 271 insertions(+), 47 deletions(-) > > diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c > index 0838d58..c0ec976 100644 > --- a/drivers/net/fec_mxc.c > +++ b/drivers/net/fec_mxc.c > @@ -9,6 +9,7 @@ > */ > > #include <common.h> > +#include <dm.h> > #include <malloc.h> > #include <memalign.h> > #include <net.h> > @@ -368,11 +369,8 @@ static int fec_get_hwaddr(int dev_id, unsigned char *mac) > return !is_valid_ethaddr(mac); > } > > -static int fec_set_hwaddr(struct eth_device *dev) > +static int _fec_set_hwaddr(struct fec_priv *fec, uchar *mac) > { > - uchar *mac = dev->enetaddr; > - struct fec_priv *fec = (struct fec_priv *)dev->priv; > - > writel(0, &fec->eth->iaddr1); > writel(0, &fec->eth->iaddr2); > writel(0, &fec->eth->gaddr1); > @@ -426,9 +424,8 @@ static void fec_reg_setup(struct fec_priv *fec) > * Start the FEC engine > * @param[in] dev Our device to handle > */ > -static int fec_open(struct eth_device *edev) > +static int fec_open(struct fec_priv *fec) > { > - struct fec_priv *fec = (struct fec_priv *)edev->priv; > int speed; > uint32_t addr, size; > int i; > @@ -534,14 +531,13 @@ static int fec_open(struct eth_device *edev) > return 0; > } > > -static int fec_init(struct eth_device *dev, bd_t* bd) > +static int _fec_init(struct fec_priv *fec, uchar *mac) > { > - struct fec_priv *fec = (struct fec_priv *)dev->priv; > uint32_t mib_ptr = (uint32_t)&fec->eth->rmon_t_drop; > int i; > > /* Initialize MAC address */ > - fec_set_hwaddr(dev); > + _fec_set_hwaddr(fec, mac); > > /* > * Setup transmit descriptors, there are two in total. > @@ -587,7 +583,7 @@ static int fec_init(struct eth_device *dev, bd_t* bd) > if (fec->xcv_type != SEVENWIRE) > miiphy_restart_aneg(dev); > #endif > - fec_open(dev); > + fec_open(fec); > return 0; > } > > @@ -595,9 +591,8 @@ static int fec_init(struct eth_device *dev, bd_t* bd) > * Halt the FEC engine > * @param[in] dev Our device to handle > */ > -static void fec_halt(struct eth_device *dev) > +static void _fec_halt(struct fec_priv *fec) > { > - struct fec_priv *fec = (struct fec_priv *)dev->priv; > int counter = 0xffff; > > /* > @@ -637,7 +632,7 @@ static void fec_halt(struct eth_device *dev) > * @param[in] length Data count in bytes > * @return 0 on success > */ > -static int fec_send(struct eth_device *dev, void *packet, int length) > +static int _fec_send(struct fec_priv *fec, void *packet, int length) > { > unsigned int status; > uint32_t size, end; > @@ -649,8 +644,6 @@ static int fec_send(struct eth_device *dev, void *packet, > int length) > * This routine transmits one frame. This routine only accepts > * 6-byte Ethernet addresses. > */ > - struct fec_priv *fec = (struct fec_priv *)dev->priv; > - > /* > * Check for valid length of data. > */ > @@ -777,14 +770,14 @@ out: > return ret; > } > > + > /** > * Pull one frame from the card > * @param[in] dev Our ethernet device to handle > * @return Length of packet read > */ > -static int fec_recv(struct eth_device *dev) > +static int _fec_recv(struct fec_priv *fec, uchar *mac) > { > - struct fec_priv *fec = (struct fec_priv *)dev->priv; > struct fec_bd *rbd = &fec->rbd_base[fec->rbd_index]; > unsigned long ievent; > int frame_length, len = 0; > @@ -800,8 +793,8 @@ static int fec_recv(struct eth_device *dev) > writel(ievent, &fec->eth->ievent); > debug("fec_recv: ievent 0x%lx\n", ievent); > if (ievent & FEC_IEVENT_BABR) { > - fec_halt(dev); > - fec_init(dev, fec->bd); > + _fec_halt(fec); > + _fec_init(fec, mac); > printf("some error: 0x%08lx\n", ievent); > return 0; > } > @@ -813,10 +806,10 @@ static int fec_recv(struct eth_device *dev) > if (ievent & FEC_IEVENT_GRA) { > /* Graceful stop complete */ > if (readl(&fec->eth->x_cntrl) & 0x00000001) { > - fec_halt(dev); > + _fec_halt(fec); > writel(~0x00000001 & readl(&fec->eth->x_cntrl), > &fec->eth->x_cntrl); > - fec_init(dev, fec->bd); > + _fec_init(fec, mac); > } > } > > @@ -970,6 +963,71 @@ static void fec_free_descs(struct fec_priv *fec) > free(fec->tbd_base); > } > > +struct mii_dev *fec_get_miibus(uint32_t base_addr, int dev_id) > +{ > + struct ethernet_regs *eth = (struct ethernet_regs *)base_addr; > + struct mii_dev *bus; > + int ret; > + > + bus = mdio_alloc(); > + if (!bus) { > + printf("mdio_alloc failed\n"); > + return NULL; > + } > + bus->read = fec_phy_read; > + bus->write = fec_phy_write; > + bus->priv = eth; > + fec_set_dev_name(bus->name, dev_id); > + > + ret = mdio_register(bus); > + if (ret) { > + printf("mdio_register failed\n"); > + free(bus); > + return NULL; > + } > + fec_mii_setspeed(eth); > + return bus; > +} > + > +#ifndef CONFIG_DM_ETH
Use positive logic where possible. #ifdef CONFIG_DM_ETH ... #else /* !CONFIG_DM_ETH */ ... #endif > +static int fec_recv(struct eth_device *dev) > +{ > + struct fec_priv *fec = (struct fec_priv *)dev->priv; > + uchar *mac = dev->enetaddr; > + > + return _fec_recv(fec, mac); > +} > + > +static int fec_send(struct eth_device *dev, void *packet, int length) > +{ > + struct fec_priv *fec = (struct fec_priv *)dev->priv; > + > + return _fec_send(fec, packet, length); > +} > + > +static void fec_halt(struct eth_device *dev) > +{ > + struct fec_priv *fec = (struct fec_priv *)dev->priv; > + > + _fec_halt(fec); > +} > + > +static int fec_set_hwaddr(struct eth_device *dev) > +{ > + struct fec_priv *fec = (struct fec_priv *)dev->priv; > + uchar *mac = dev->enetaddr; > + > + return _fec_set_hwaddr(fec, mac); > +} > + > +static int fec_init(struct eth_device *dev, bd_t *bd) > +{ > + struct fec_priv *fec = (struct fec_priv *)dev->priv; > + uchar *mac = dev->enetaddr; > + > + return _fec_init(fec, mac); > +} > + > #ifdef CONFIG_PHYLIB > int fec_probe(bd_t *bd, int dev_id, uint32_t base_addr, > struct mii_dev *bus, struct phy_device *phydev) > @@ -1061,32 +1119,6 @@ err1: > return ret; > } > > -struct mii_dev *fec_get_miibus(uint32_t base_addr, int dev_id) > -{ > - struct ethernet_regs *eth = (struct ethernet_regs *)base_addr; > - struct mii_dev *bus; > - int ret; > - > - bus = mdio_alloc(); > - if (!bus) { > - printf("mdio_alloc failed\n"); > - return NULL; > - } > - bus->read = fec_phy_read; > - bus->write = fec_phy_write; > - bus->priv = eth; > - fec_set_dev_name(bus->name, dev_id); > - > - ret = mdio_register(bus); > - if (ret) { > - printf("mdio_register failed\n"); > - free(bus); > - return NULL; > - } > - fec_mii_setspeed(eth); > - return bus; > -} > - > int fecmxc_initialize_multi(bd_t *bd, int dev_id, int phy_id, uint32_t addr) > { > uint32_t base_mii; > @@ -1146,3 +1178,191 @@ int fecmxc_register_mii_postcall(struct eth_device > *dev, int (*cb)(int)) > return 0; > } > #endif > + > +#else > + > +static int fec_set_hwaddr(struct udevice *dev) > +{ > + struct fec_priv *fec = dev_get_priv(dev); > + struct eth_pdata *pdata = dev_get_platdata(dev); > + uchar *mac = pdata->enetaddr; > + > + return _fec_set_hwaddr(fec, mac); > +} > + > +static void fec_halt(struct udevice *dev) > +{ > + struct fec_priv *fec = dev_get_priv(dev); > + > + _fec_halt(fec); > +} > + > +static int fec_recv(struct udevice *dev, int flags, uchar **packetp) > +{ > + struct fec_priv *fec = dev_get_priv(dev); > + struct eth_pdata *pdata = dev_get_platdata(dev); > + uchar *mac = pdata->enetaddr; > + > + return _fec_recv(fec, mac); > +} > + > +static int fec_send(struct udevice *dev, void *packet, int length) > +{ > + struct fec_priv *fec = dev_get_priv(dev); > + > + return _fec_send(fec, packet, length); > +} > + > +static int fec_init(struct udevice *dev) > +{ > + struct fec_priv *fec = dev_get_priv(dev); > + struct eth_pdata *pdata = dev_get_platdata(dev); > + uchar *mac = pdata->enetaddr; > + > + return _fec_init(fec, mac); > +} > + > +static const struct eth_ops fecmxc_ops = { > + .start = fec_init, > + .send = fec_send, > + .recv = fec_recv, > + .stop = fec_halt, > + .write_hwaddr = fec_set_hwaddr, > +}; > + > +static int fec_phy_init(struct fec_priv *priv, struct udevice *dev) > +{ > + struct phy_device *phydev; > + int mask = 0xffffffff; > + > +#ifdef CONFIG_PHYLIB > + mask = 1 << CONFIG_FEC_MXC_PHYADDR; > +#endif > + > + phydev = phy_find_by_mask(priv->bus, mask, priv->interface); > + if (!phydev) > + return -ENODEV; > + > + phy_connect_dev(phydev, dev); > + > + priv->phydev = phydev; > + phy_config(phydev); > + > + return 0; > +} > + > +static int fecmxc_probe(struct udevice *dev) > +{ > + struct eth_pdata *pdata = dev_get_platdata(dev); > + struct fec_priv *priv = dev_get_priv(dev); > + struct mii_dev *bus = NULL; > + int dev_id = -1; > + unsigned char ethaddr[6]; > + uint32_t start; > + int ret; > + > + ret = fec_alloc_descs(priv); > + if (ret) > + return ret; > + > + bus = fec_get_miibus((uint32_t)priv->eth, dev_id); > + if (!bus) > + goto err_mii; > + > + priv->bus = bus; > + priv->xcv_type = CONFIG_FEC_XCV_TYPE; > + priv->interface = pdata->phy_interface; > + ret = fec_phy_init(priv, dev); > + if (ret) > + goto err_phy; > + > + /* Reset chip. */ > + writel(readl(&priv->eth->ecntrl) | FEC_ECNTRL_RESET, > &priv->eth->ecntrl); > + start = get_timer(0); > + while (readl(&priv->eth->ecntrl) & FEC_ECNTRL_RESET) { > + if (get_timer(start) > (CONFIG_SYS_HZ * 5)) { > + printf("FEC MXC: Timeout reseting chip\n"); > + goto err_timeout; > + } > + udelay(10); > + } > + > + fec_reg_setup(priv); > + fec_set_dev_name((char *)dev->name, dev_id); > + priv->dev_id = (dev_id == -1) ? 0 : dev_id; > + > + ret = fec_get_hwaddr(dev_id, ethaddr); Is there a reason not to have this registered as ops->read_rom_hwaddr? > + if (!ret) { > + debug("got MAC%d address from fuse: %pM\n", dev_id, ethaddr); > + memcpy(pdata->enetaddr, ethaddr, 6); > + if (!getenv("ethaddr")) > + eth_setenv_enetaddr("ethaddr", ethaddr); > + } > + > + return 0; > + > +err_timeout: > + free(priv->phydev); > +err_phy: > + mdio_unregister(bus); > + free(bus); > +err_mii: > + fec_free_descs(priv); > + return ret; > +} > + > +static int fecmxc_remove(struct udevice *dev) > +{ > + struct fec_priv *priv = dev_get_priv(dev); > + > + free(priv->phydev); > + fec_free_descs(priv); > + mdio_unregister(priv->bus); > + mdio_free(priv->bus); > + > + return 0; > +} > + > +static int fecmxc_ofdata_to_platdata(struct udevice *dev) > +{ > + struct eth_pdata *pdata = dev_get_platdata(dev); > + struct fec_priv *priv = dev_get_priv(dev); > + const char *phy_mode; > + > + pdata->iobase = (phys_addr_t)dev_get_addr(dev); > + priv->eth = (struct ethernet_regs *)pdata->iobase; > + > + pdata->phy_interface = -1; > + phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", > NULL); > + if (phy_mode) > + pdata->phy_interface = phy_get_interface_by_name(phy_mode); > + if (pdata->phy_interface == -1) { > + debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); > + return -EINVAL; > + } > + > + /* TODO > + * Need to get the reset-gpio and related properties from DT > + * and implemet the enet reset code on .probe call > + */ > + > + return 0; > +} > + > +static const struct udevice_id fecmxc_ids[] = { > + { .compatible = "fsl,imx6q-fec" }, > + { } > +}; > + > +U_BOOT_DRIVER(fec_gem) = { > + .name = "fecmxc", > + .id = UCLASS_ETH, > + .of_match = fecmxc_ids, > + .ofdata_to_platdata = fecmxc_ofdata_to_platdata, > + .probe = fecmxc_probe, > + .remove = fecmxc_remove, > + .ops = &fecmxc_ops, > + .priv_auto_alloc_size = sizeof(struct fec_priv), > + .platdata_auto_alloc_size = sizeof(struct eth_pdata), > +}; > +#endif > diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h > index 0717cc6..9fc6153 100644 > --- a/drivers/net/fec_mxc.h > +++ b/drivers/net/fec_mxc.h > @@ -264,6 +264,10 @@ struct fec_priv { > int phy_id; > int (*mii_postcall)(int); > #endif > + > +#ifdef CONFIG_DM_ETH > + u32 interface; > +#endif > }; > > /** > -- > 2.7.4 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot