[U-Boot] [PATCH v2 0/4] sunxi: emac: Add driver model support

Hi All,
Here is v2 of my patch series to add driver model support to the sunxi emac driver.
Changes since v1: -Add a patch to rename DMA_CPU_TRRESHOLD to EMAC_RX_BUFSIZE.
Please review.
Regards,
Hans

This is a preparation-patch for adding device-model support to the emac driver.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- drivers/net/sunxi_emac.c | 111 +++++++++++++++++++++++++---------------- include/configs/sunxi-common.h | 2 + 2 files changed, 71 insertions(+), 42 deletions(-)
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index 7b31f8c..b9fd1b8 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -156,9 +156,9 @@ struct sunxi_sramc_regs { #define DMA_CPU_TRRESHOLD 2000
struct emac_eth_dev { - u32 speed; - u32 duplex; - u32 phy_configured; + struct emac_regs *regs; + struct mii_dev *bus; + struct phy_device *phydev; int link_printed; };
@@ -195,11 +195,10 @@ static void emac_outblk_32bit(void *reg, void *data, int count) }
/* Read a word from phyxcer */ -static int emac_phy_read(const char *devname, unsigned char addr, - unsigned char reg, unsigned short *value) +static int emac_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) { - struct eth_device *dev = eth_get_dev_by_name(devname); - struct emac_regs *regs = (struct emac_regs *)dev->iobase; + struct emac_eth_dev *priv = bus->priv; + struct emac_regs *regs = priv->regs;
/* issue the phy address and reg */ writel(addr << 8 | reg, ®s->mac_madr); @@ -213,18 +212,16 @@ static int emac_phy_read(const char *devname, unsigned char addr, /* push down the phy io line */ writel(0x0, ®s->mac_mcmd);
- /* and write data */ - *value = readl(®s->mac_mrdd); - - return 0; + /* And read data */ + return readl(®s->mac_mrdd); }
/* Write a word to phyxcer */ -static int emac_phy_write(const char *devname, unsigned char addr, - unsigned char reg, unsigned short value) +static int emac_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 value) { - struct eth_device *dev = eth_get_dev_by_name(devname); - struct emac_regs *regs = (struct emac_regs *)dev->iobase; + struct emac_eth_dev *priv = bus->priv; + struct emac_regs *regs = priv->regs;
/* issue the phy address and reg */ writel(addr << 8 | reg, ®s->mac_madr); @@ -244,12 +241,44 @@ static int emac_phy_write(const char *devname, unsigned char addr, return 0; }
-static void emac_setup(struct eth_device *dev) +static int sunxi_emac_init_phy(struct emac_eth_dev *priv, void *dev) { - struct emac_regs *regs = (struct emac_regs *)dev->iobase; + int ret, mask = 0xffffffff; + +#ifdef CONFIG_PHY_ADDR + mask = 1 << CONFIG_PHY_ADDR; +#endif + + priv->bus = mdio_alloc(); + if (!priv->bus) { + printf("Failed to allocate MDIO bus\n"); + return -ENOMEM; + } + + priv->bus->read = emac_mdio_read; + priv->bus->write = emac_mdio_write; + priv->bus->priv = priv; + strcpy(priv->bus->name, "emac"); + + ret = mdio_register(priv->bus); + if (ret) + return ret; + + priv->phydev = phy_find_by_mask(priv->bus, mask, + PHY_INTERFACE_MODE_MII); + if (!priv->phydev) + return -ENODEV; + + phy_connect_dev(priv->phydev, dev); + phy_config(priv->phydev); + + return 0; +} + +static void emac_setup(struct emac_eth_dev *priv) +{ + struct emac_regs *regs = priv->regs; u32 reg_val; - u16 phy_val; - u32 duplex_flag;
/* Set up TX */ writel(EMAC_TX_SETUP, ®s->tx_mode); @@ -262,12 +291,8 @@ static void emac_setup(struct eth_device *dev) writel(EMAC_MAC_CTL0_SETUP, ®s->mac_ctl0);
/* Set MAC CTL1 */ - emac_phy_read(dev->name, 1, 0, &phy_val); - debug("PHY SETUP, reg 0 value: %x\n", phy_val); - duplex_flag = !!(phy_val & (1 << 8)); - reg_val = 0; - if (duplex_flag) + if (priv->phydev->duplex == DUPLEX_FULL) reg_val = (0x1 << 0); writel(EMAC_MAC_CTL1_SETUP | reg_val, ®s->mac_ctl1);
@@ -302,7 +327,7 @@ static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd) { struct emac_regs *regs = (struct emac_regs *)dev->iobase; struct emac_eth_dev *priv = dev->priv; - u16 phy_reg; + int ret;
/* Init EMAC */
@@ -320,7 +345,7 @@ static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd) udelay(1);
/* Set up EMAC */ - emac_setup(dev); + emac_setup(priv);
writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 | dev->enetaddr[2], ®s->mac_a1); @@ -332,29 +357,32 @@ static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd) emac_reset(dev);
/* PHY POWER UP */ - emac_phy_read(dev->name, 1, 0, &phy_reg); - emac_phy_write(dev->name, 1, 0, phy_reg & (~(0x1 << 11))); - mdelay(1); - - emac_phy_read(dev->name, 1, 0, &phy_reg); - - priv->speed = miiphy_speed(dev->name, 0); - priv->duplex = miiphy_duplex(dev->name, 0); + ret = phy_startup(priv->phydev); + if (ret) { + printf("Could not initialize PHY %s\n", + priv->phydev->dev->name); + return ret; + }
/* Print link status only once */ if (!priv->link_printed) { printf("ENET Speed is %d Mbps - %s duplex connection\n", - priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL"); + priv->phydev->speed, + priv->phydev->duplex ? "FULL" : "HALF"); priv->link_printed = 1; }
/* Set EMAC SPEED depend on PHY */ - clrsetbits_le32(®s->mac_supp, 1 << 8, - ((phy_reg & (0x1 << 13)) >> 13) << 8); + if (priv->phydev->speed == SPEED_100) + setbits_le32(®s->mac_supp, 1 << 8); + else + clrbits_le32(®s->mac_supp, 1 << 8);
/* Set duplex depend on phy */ - clrsetbits_le32(®s->mac_ctl1, 1 << 0, - ((phy_reg & (0x1 << 8)) >> 8) << 0); + if (priv->phydev->duplex == DUPLEX_FULL) + setbits_le32(®s->mac_ctl1, 1 << 0); + else + clrbits_le32(®s->mac_ctl1, 1 << 0);
/* Enable RX/TX */ setbits_le32(®s->ctl, 0x7); @@ -505,6 +533,7 @@ int sunxi_emac_initialize(void) /* Set MII clock */ clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2);
+ priv->regs = regs; dev->iobase = (int)regs; dev->priv = priv; dev->init = sunxi_emac_eth_init; @@ -515,7 +544,5 @@ int sunxi_emac_initialize(void)
eth_register(dev);
- miiphy_register(dev->name, emac_phy_read, emac_phy_write); - - return 0; + return sunxi_emac_init_phy(priv, dev); } diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index f97e626..40c7f63 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -350,7 +350,9 @@ extern int soft_i2c_gpio_scl;
/* Ethernet support */ #ifdef CONFIG_SUNXI_EMAC +#define CONFIG_PHY_ADDR 1 #define CONFIG_MII /* MII PHY management */ +#define CONFIG_PHYLIB #endif
#ifdef CONFIG_SUNXI_GMAC

Split all the core functionality out into functions taking a struct emac_eth_dev *priv argument as preparation for adding driver-model support.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- drivers/net/sunxi_emac.c | 115 +++++++++++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 44 deletions(-)
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index b9fd1b8..038f474 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -309,9 +309,9 @@ static void emac_setup(struct emac_eth_dev *priv) writel(EMAC_MAC_MFL, ®s->mac_maxf); }
-static void emac_reset(struct eth_device *dev) +static void emac_reset(struct emac_eth_dev *priv) { - struct emac_regs *regs = (struct emac_regs *)dev->iobase; + struct emac_regs *regs = priv->regs;
debug("resetting device\n");
@@ -323,10 +323,9 @@ static void emac_reset(struct eth_device *dev) udelay(200); }
-static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd) +static int _sunxi_emac_eth_init(struct emac_eth_dev *priv, u8 *enetaddr) { - struct emac_regs *regs = (struct emac_regs *)dev->iobase; - struct emac_eth_dev *priv = dev->priv; + struct emac_regs *regs = priv->regs; int ret;
/* Init EMAC */ @@ -347,14 +346,14 @@ static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd) /* Set up EMAC */ emac_setup(priv);
- writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 | - dev->enetaddr[2], ®s->mac_a1); - writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 | - dev->enetaddr[5], ®s->mac_a0); + writel(enetaddr[0] << 16 | enetaddr[1] << 8 | enetaddr[2], + ®s->mac_a1); + writel(enetaddr[3] << 16 | enetaddr[4] << 8 | enetaddr[5], + ®s->mac_a0);
mdelay(1);
- emac_reset(dev); + emac_reset(priv);
/* PHY POWER UP */ ret = phy_startup(priv->phydev); @@ -390,14 +389,9 @@ static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd) return 0; }
-static void sunxi_emac_eth_halt(struct eth_device *dev) +static int _sunxi_emac_eth_recv(struct emac_eth_dev *priv, void *packet) { - /* Nothing to do here */ -} - -static int sunxi_emac_eth_recv(struct eth_device *dev) -{ - struct emac_regs *regs = (struct emac_regs *)dev->iobase; + struct emac_regs *regs = priv->regs; struct emac_rxhdr rxhdr; u32 rxcount; u32 reg_val; @@ -415,7 +409,7 @@ static int sunxi_emac_eth_recv(struct eth_device *dev) /* Had one stuck? */ rxcount = readl(®s->rx_fbc); if (!rxcount) - return 0; + return -EAGAIN; }
reg_val = readl(®s->rx_io_data); @@ -431,7 +425,7 @@ static int sunxi_emac_eth_recv(struct eth_device *dev) /* Enable RX */ setbits_le32(®s->ctl, 0x1 << 2);
- return 0; + return -EAGAIN; }
/* A packet ready now @@ -463,22 +457,19 @@ static int sunxi_emac_eth_recv(struct eth_device *dev) if (good_packet) { if (rx_len > DMA_CPU_TRRESHOLD) { printf("Received packet is too big (len=%d)\n", rx_len); - } else { - emac_inblk_32bit((void *)®s->rx_io_data, - net_rx_packets[0], rx_len); - - /* Pass to upper layer */ - net_process_received_packet(net_rx_packets[0], rx_len); - return rx_len; + return -EMSGSIZE; } + emac_inblk_32bit((void *)®s->rx_io_data, packet, rx_len); + return rx_len; }
- return 0; + return -EIO; /* Bad packet */ }
-static int sunxi_emac_eth_send(struct eth_device *dev, void *packet, int len) +static int _sunxi_emac_eth_send(struct emac_eth_dev *priv, void *packet, + int len) { - struct emac_regs *regs = (struct emac_regs *)dev->iobase; + struct emac_regs *regs = priv->regs;
/* Select channel 0 */ writel(0, ®s->tx_ins); @@ -495,17 +486,64 @@ static int sunxi_emac_eth_send(struct eth_device *dev, void *packet, int len) return 0; }
-int sunxi_emac_initialize(void) +static void sunxi_emac_board_setup(struct emac_eth_dev *priv) { struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; struct sunxi_sramc_regs *sram = (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE; + struct emac_regs *regs = priv->regs; + int pin; + + /* Map SRAM to EMAC */ + setbits_le32(&sram->ctrl1, 0x5 << 2); + + /* Configure pin mux settings for MII Ethernet */ + for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++) + sunxi_gpio_set_cfgpin(pin, SUNXI_GPA_EMAC); + + /* Set up clock gating */ + setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_EMAC); + + /* Set MII clock */ + clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2); +} + +static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bis) +{ + return _sunxi_emac_eth_init(dev->priv, dev->enetaddr); +} + +static void sunxi_emac_eth_halt(struct eth_device *dev) +{ + /* Nothing to do here */ +} + +static int sunxi_emac_eth_recv(struct eth_device *dev) +{ + int rx_len; + + rx_len = _sunxi_emac_eth_recv(dev->priv, net_rx_packets[0]); + if (rx_len <= 0) + return 0; + + /* Pass to upper layer */ + net_process_received_packet(net_rx_packets[0], rx_len); + + return rx_len; +} + +static int sunxi_emac_eth_send(struct eth_device *dev, void *packet, int length) +{ + return _sunxi_emac_eth_send(dev->priv, packet, length); +} + +int sunxi_emac_initialize(void) +{ struct emac_regs *regs = (struct emac_regs *)SUNXI_EMAC_BASE; struct eth_device *dev; struct emac_eth_dev *priv; - int pin;
dev = malloc(sizeof(*dev)); if (dev == NULL) @@ -520,19 +558,6 @@ int sunxi_emac_initialize(void) memset(dev, 0, sizeof(*dev)); memset(priv, 0, sizeof(struct emac_eth_dev));
- /* Map SRAM to EMAC */ - setbits_le32(&sram->ctrl1, 0x5 << 2); - - /* Configure pin mux settings for MII Ethernet */ - for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++) - sunxi_gpio_set_cfgpin(pin, SUNXI_GPA_EMAC); - - /* Set up clock gating */ - setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_EMAC); - - /* Set MII clock */ - clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2); - priv->regs = regs; dev->iobase = (int)regs; dev->priv = priv; @@ -542,6 +567,8 @@ int sunxi_emac_initialize(void) dev->recv = sunxi_emac_eth_recv; strcpy(dev->name, "emac");
+ sunxi_emac_board_setup(priv); + eth_register(dev);
return sunxi_emac_init_phy(priv, dev);

Besides being spelled wron, the DMA_CPU_TRRESHOLD define actually has nothing to do with DMA as we only use mmio fifo access. Rename it to EMAC_RX_BUFSIZE to properly reflect what it does.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- drivers/net/sunxi_emac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index 038f474..e43b1e7 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -153,7 +153,7 @@ struct sunxi_sramc_regs { #define EMAC_CRCERR (0x1 << 4) #define EMAC_LENERR (0x3 << 5)
-#define DMA_CPU_TRRESHOLD 2000 +#define EMAC_RX_BUFSIZE 2000
struct emac_eth_dev { struct emac_regs *regs; @@ -455,7 +455,7 @@ static int _sunxi_emac_eth_recv(struct emac_eth_dev *priv, void *packet)
/* Move data from EMAC */ if (good_packet) { - if (rx_len > DMA_CPU_TRRESHOLD) { + if (rx_len > EMAC_RX_BUFSIZE) { printf("Received packet is too big (len=%d)\n", rx_len); return -EMSGSIZE; }

On 25 April 2015 at 05:51, Hans de Goede hdegoede@redhat.com wrote:
Besides being spelled wron, the DMA_CPU_TRRESHOLD define actually has
:-)
nothing to do with DMA as we only use mmio fifo access. Rename it to EMAC_RX_BUFSIZE to properly reflect what it does.
Signed-off-by: Hans de Goede hdegoede@redhat.com
drivers/net/sunxi_emac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index 038f474..e43b1e7 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -153,7 +153,7 @@ struct sunxi_sramc_regs { #define EMAC_CRCERR (0x1 << 4) #define EMAC_LENERR (0x3 << 5)
-#define DMA_CPU_TRRESHOLD 2000 +#define EMAC_RX_BUFSIZE 2000
struct emac_eth_dev { struct emac_regs *regs; @@ -455,7 +455,7 @@ static int _sunxi_emac_eth_recv(struct emac_eth_dev *priv, void *packet)
/* Move data from EMAC */ if (good_packet) {
if (rx_len > DMA_CPU_TRRESHOLD) {
if (rx_len > EMAC_RX_BUFSIZE) { printf("Received packet is too big (len=%d)\n", rx_len); return -EMSGSIZE; }
-- 2.3.5

Modify the sunxi-emac eth driver to support driver model.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/board.c | 4 +- drivers/net/sunxi_emac.c | 81 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-)
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 7e9cf11..cde13ef 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -12,7 +12,9 @@
#include <common.h> #include <i2c.h> +#ifndef CONFIG_DM_ETH #include <netdev.h> +#endif #include <miiphy.h> #include <serial.h> #ifdef CONFIG_SPL_BUILD @@ -224,7 +226,7 @@ int cpu_eth_init(bd_t *bis) mdelay(200); #endif
-#ifdef CONFIG_SUNXI_EMAC +#if defined CONFIG_SUNXI_EMAC && !defined CONFIG_DM_ETH rc = sunxi_emac_initialize(bis); if (rc < 0) { printf("sunxi: failed to initialize emac\n"); diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index e43b1e7..306a022 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -7,6 +7,7 @@ */
#include <common.h> +#include <dm.h> #include <linux/err.h> #include <malloc.h> #include <miiphy.h> @@ -160,6 +161,9 @@ struct emac_eth_dev { struct mii_dev *bus; struct phy_device *phydev; int link_printed; +#ifdef CONFIG_DM_ETH + uchar rx_buf[EMAC_RX_BUFSIZE]; +#endif };
struct emac_rxhdr { @@ -509,6 +513,7 @@ static void sunxi_emac_board_setup(struct emac_eth_dev *priv) clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2); }
+#ifndef CONFIG_DM_ETH static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bis) { return _sunxi_emac_eth_init(dev->priv, dev->enetaddr); @@ -573,3 +578,79 @@ int sunxi_emac_initialize(void)
return sunxi_emac_init_phy(priv, dev); } +#endif + +#ifdef CONFIG_DM_ETH +static int sunxi_emac_eth_start(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + return _sunxi_emac_eth_init(dev->priv, pdata->enetaddr); +} + +static int sunxi_emac_eth_send(struct udevice *dev, void *packet, int length) +{ + struct emac_eth_dev *priv = dev_get_priv(dev); + + return _sunxi_emac_eth_send(priv, packet, length); +} + +static int sunxi_emac_eth_recv(struct udevice *dev, uchar **packetp) +{ + struct emac_eth_dev *priv = dev_get_priv(dev); + int rx_len; + + rx_len = _sunxi_emac_eth_recv(priv, priv->rx_buf); + *packetp = priv->rx_buf; + + return rx_len; +} + +static void sunxi_emac_eth_stop(struct udevice *dev) +{ + /* Nothing to do here */ +} + +static int sunxi_emac_eth_probe(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct emac_eth_dev *priv = dev_get_priv(dev); + + priv->regs = (struct emac_regs *)pdata->iobase; + sunxi_emac_board_setup(priv); + + return sunxi_emac_init_phy(priv, dev); +} + +static const struct eth_ops sunxi_emac_eth_ops = { + .start = sunxi_emac_eth_start, + .send = sunxi_emac_eth_send, + .recv = sunxi_emac_eth_recv, + .stop = sunxi_emac_eth_stop, +}; + +static int sunxi_emac_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = dev_get_addr(dev); + + return 0; +} + +static const struct udevice_id sunxi_emac_eth_ids[] = { + { .compatible = "allwinner,sun4i-a10-emac" }, + { } +}; + +U_BOOT_DRIVER(eth_sunxi_emac) = { + .name = "eth_sunxi_emac", + .id = UCLASS_ETH, + .of_match = sunxi_emac_eth_ids, + .ofdata_to_platdata = sunxi_emac_eth_ofdata_to_platdata, + .probe = sunxi_emac_eth_probe, + .ops = &sunxi_emac_eth_ops, + .priv_auto_alloc_size = sizeof(struct emac_eth_dev), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; +#endif

On Sat, 2015-04-25 at 13:51 +0200, Hans de Goede wrote:
Hi All,
Here is v2 of my patch series to add driver model support to the sunxi emac driver.
Changes since v1: -Add a patch to rename DMA_CPU_TRRESHOLD to EMAC_RX_BUFSIZE.
Please review.
All LGTM: Acked-by: Ian Campbell ijc@hellion.org.uk

On 25.04.2015 13:51, Hans de Goede wrote:
Here is v2 of my patch series to add driver model support to the sunxi emac driver.
Changes since v1: -Add a patch to rename DMA_CPU_TRRESHOLD to EMAC_RX_BUFSIZE.
Please review.
Looks good, so:
Reviewed-by: Stefan Roese sr@denx.de
Thanks, Stefan
participants (4)
-
Hans de Goede
-
Ian Campbell
-
Simon Glass
-
Stefan Roese