Skip to contentSkip to conversation

sunxi: emac: Add driver model support

PATCH New Hans de Goede 4 participants 8 messages Apr 25, 2015 – Apr 26, 2015

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v2 cover 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

#1 lore raw

PATCH v2 1/4 sunxi: emac: port to phylib

This is a preparation-patch for adding device-model support to the emac driver.

---
 drivers/net/sunxi_emac.c       | 111 +++++++++++++++++++++++++----------------
 include/configs/sunxi-common.h |   2 +
 2 files changed, 71 insertions(+), 42 deletions(-)
drivers/net/sunxi_emac.c +69 -42
index 7b31f8c..b9fd1b8 100644
@@ -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, &regs->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, &regs->mac_mcmd);
 
-	/* and write data */
-	*value = readl(&regs->mac_mrdd);
-
-	return 0;
+	/* And read data */
+	return readl(&regs->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, &regs->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, &regs->tx_mode);
@@ -262,12 +291,8 @@ static void emac_setup(struct eth_device *dev)
 	writel(EMAC_MAC_CTL0_SETUP, &regs->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, &regs->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], &regs->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(&regs->mac_supp, 1 << 8,
-			((phy_reg & (0x1 << 13)) >> 13) << 8);
+	if (priv->phydev->speed == SPEED_100)
+		setbits_le32(&regs->mac_supp, 1 << 8);
+	else
+		clrbits_le32(&regs->mac_supp, 1 << 8);
 
 	/* Set duplex depend on phy */
-	clrsetbits_le32(&regs->mac_ctl1, 1 << 0,
-			((phy_reg & (0x1 << 8)) >> 8) << 0);
+	if (priv->phydev->duplex == DUPLEX_FULL)
+		setbits_le32(&regs->mac_ctl1, 1 << 0);
+	else
+		clrbits_le32(&regs->mac_ctl1, 1 << 0);
 
 	/* Enable RX/TX */
 	setbits_le32(&regs->ctl, 0x7);
@@ -505,6 +533,7 @@ int sunxi_emac_initialize(void)
 	/* Set MII clock */
 	clrsetbits_le32(&regs->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);
 }
include/configs/sunxi-common.h +2 -0
index f97e626..40c7f63 100644
@@ -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
Signature · 1 line
2.3.5
#2 lore raw

PATCH v2 2/4 sunxi: emac: Prepare for driver-model support

In reply to Hans de Goede

Split all the core functionality out into functions taking a struct emac_eth_dev *priv argument as preparation for adding driver-model support.

---
 drivers/net/sunxi_emac.c | 115 +++++++++++++++++++++++++++++------------------
 1 file changed, 71 insertions(+), 44 deletions(-)
drivers/net/sunxi_emac.c +71 -44
index b9fd1b8..038f474 100644
@@ -309,9 +309,9 @@ static void emac_setup(struct emac_eth_dev *priv)
 	writel(EMAC_MAC_MFL, &regs->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], &regs->mac_a1);
-	writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 |
-	       dev->enetaddr[5], &regs->mac_a0);
+	writel(enetaddr[0] << 16 | enetaddr[1] << 8 | enetaddr[2],
+	       &regs->mac_a1);
+	writel(enetaddr[3] << 16 | enetaddr[4] << 8 | enetaddr[5],
+	       &regs->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(&regs->rx_fbc);
 		if (!rxcount)
-			return 0;
+			return -EAGAIN;
 	}
 
 	reg_val = readl(&regs->rx_io_data);
@@ -431,7 +425,7 @@ static int sunxi_emac_eth_recv(struct eth_device *dev)
 		/* Enable RX */
 		setbits_le32(&regs->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 *)&regs->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 *)&regs->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, &regs->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(&regs->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(&regs->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);
Signature · 1 line
2.3.5
#3 lore raw

PATCH v2 3/4 sunxi: emac: Rename DMA_CPU_TRRESHOLD to EMAC_RX_BUFSIZE

In reply to Hans de Goede

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.

---
 drivers/net/sunxi_emac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/sunxi_emac.c +2 -2
index 038f474..e43b1e7 100644
@@ -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;
 		}
Signature · 1 line
2.3.5
#4 lore raw

PATCH v2 3/4 sunxi: emac: Rename DMA_CPU_TRRESHOLD to EMAC_RX_BUFSIZE

Quoted 1 line · Hans de Goede

Besides being spelled wron, the DMA_CPU_TRRESHOLD define actually has

:-)

Quoted 7 lines

nothing to do with DMA as we only use mmio fifo access. Rename it to EMAC_RX_BUFSIZE to properly reflect what it does.

---
 drivers/net/sunxi_emac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Quoted 26 lines
drivers/net/sunxi_emac.c +2 -3
index 038f474..e43b1e7 100644
@@ -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

#5 lore raw

PATCH v2 4/4 sunxi: emac: Add driver model support

In reply to Hans de Goede

Modify the sunxi-emac eth driver to support driver model.

---
 arch/arm/cpu/armv7/sunxi/board.c |  4 +-
 drivers/net/sunxi_emac.c         | 81 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 1 deletion(-)
arch/arm/cpu/armv7/sunxi/board.c +3 -1
index 7e9cf11..cde13ef 100644
@@ -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");
drivers/net/sunxi_emac.c +81 -0

102 lines not on this page · raw message

Signature · 1 line
2.3.5
#6 lore raw

v2 cover sunxi: emac: Add driver model support

In reply to Hans de Goede
Quoted 9 lines · Hans de Goede

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 <[email protected]>

#7 lore raw

v2 cover sunxi: emac: Add driver model support

In reply to Hans de Goede
Quoted 7 lines · Hans de Goede

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:

Thanks,
Stefan