[U-Boot] [U-BOOT] [PATCH] net: Add EMAC driver for H3/A83T/A64
Corentin LABBE
clabbe.montjoie at gmail.com
Sun May 15 16:39:08 CEST 2016
Hello
I have some minor comments below
Le 15/05/2016 11:41, Amit Singh Tomar a écrit :
> This patch add EMAC driver support for H3/A83T/A64 SoCs.
>
> It has been tested on Oragnepipc(H3) board that has internal PHY.
A little typo
>
> Signed-off-by: Amit Singh Tomar <amittomer25 at gmail.com>
> ---
> arch/arm/dts/sun8i-h3-orangepi-pc.dts | 10 +
> arch/arm/dts/sun8i-h3.dtsi | 7 +
> drivers/net/Kconfig | 8 +
> drivers/net/Makefile | 1 +
> drivers/net/sun8i_emac.c | 678 +++++++++++++++++++++++++++++++++
> 5 files changed, 704 insertions(+)
> create mode 100644 drivers/net/sun8i_emac.c
>
> diff --git a/arch/arm/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/dts/sun8i-h3-orangepi-pc.dts
> index 30ccca0..3a40fb8 100644
> --- a/arch/arm/dts/sun8i-h3-orangepi-pc.dts
> +++ b/arch/arm/dts/sun8i-h3-orangepi-pc.dts
> @@ -173,3 +173,13 @@
> /* USB VBUS is always on */
> status = "okay";
> };
> +
> +&emac {
> + phy = <&phy1>;
> + phy-mode = "mii";
> + status = "okay";
> +
> + phy1: ethernet-phy at 1 {
> + reg = <1>;
> + };
> +};
> diff --git a/arch/arm/dts/sun8i-h3.dtsi b/arch/arm/dts/sun8i-h3.dtsi
> index c2f63c5..1e403e3 100644
> --- a/arch/arm/dts/sun8i-h3.dtsi
> +++ b/arch/arm/dts/sun8i-h3.dtsi
> @@ -616,6 +616,13 @@
> status = "disabled";
> };
>
> + emac: ethernet at 01c30000 {
> + compatible = "allwinner,sun8i-h3-emac";
> + reg = <0x01c30000 0x10000>;
10000 is too high
> + #address-cells = <1>;
> + #size-cells = <0>;
> + };
> +
> gic: interrupt-controller at 01c81000 {
> compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
> reg = <0x01c81000 0x1000>,
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 91b7690..3c21810 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -46,6 +46,14 @@ menuconfig NETDEVICES
>
> if NETDEVICES
>
> +config SUN8I_EMAC
> + bool "Allwinner Sun8i Ethernet MAC support"
> + depends on DM_ETH
> + select PHYLIB
> + help
> + This driver supports the Allwinner based SUN8I Ethernet MAC.It can
Space after dot. Try also to keep a minimum of alphabetical order of config.
> + be found in Allwinners H3/A64/A83T based SoCs.
> +
> config ALTERA_TSE
> bool "Altera Triple-Speed Ethernet MAC support"
> depends on DM_ETH
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index fbedd04..f78fdc5 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -74,3 +74,4 @@ obj-$(CONFIG_FSL_MC_ENET) += ldpaa_eth/
> obj-$(CONFIG_FSL_MEMAC) += fm/memac_phy.o
> obj-$(CONFIG_VSC9953) += vsc9953.o
> obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o
> +obj-$(CONFIG_SUN8I_EMAC) = sun8i_emac.o
You could put it just after the other sunxi driver
> diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
> new file mode 100644
> index 0000000..0858235
> --- /dev/null
> +++ b/drivers/net/sun8i_emac.c
> @@ -0,0 +1,678 @@
> +/*
> + * (C) Copyright 2016
> + * Author: Amit Singh Tomar, amittomer25 at gmail.com
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + *
> + * Ethernet driver for H3/A64 based SoC
You forgot A83T
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <linux/err.h>
> +#include <malloc.h>
> +#include <miiphy.h>
> +#include <net.h>
> +#include <asm/io.h>
> +#include <asm/arch/clock.h>
> +#include <asm/arch/gpio.h>
Sort also headers
> +
> +#define SUN8I_AHB2_EPHY 0x02c8
> +
> +#define AHB2_CFG_REG 0x005c
> +
> +#define BUS_SOFT_RST_REG0 0x02c0
> +#define BUS_SOFT_RST_REG2 0x02c8
> +
> +#define EPHY_RST (0x1 << 2)
> +#define EMAC_RST (0x1 << 17)
> +
> +#define SUN8I_CCU_BASE 0x01c20000
> +#define SUN8I_SCTL_BASE 0x01c00000
> +
> +#define SCTL_EMAC_TX_CLK_SRC_MII ((1 << 1) | (1 << 0))
> +#define SCTL_EMAC_EPIT_MII (1 << 2)
> +#define SCTL_EMAC_CLK_SEL (1 << 18) /* 25 Mhz */
Use BIT()
> +
> +#define MDIO_CMD_MII_BUSY BIT(0)
> +#define MDIO_CMD_MII_WRITE BIT(1)
> +
> +#define MDIO_CMD_MII_PHY_REG_ADDR_MASK 0x000001f0
> +#define MDIO_CMD_MII_PHY_REG_ADDR_SHIFT 4
> +#define MDIO_CMD_MII_PHY_ADDR_MASK 0x0001f000
> +#define MDIO_CMD_MII_PHY_ADDR_SHIFT 12
> +
> +#define CONFIG_TX_DESCR_NUM 128
> +#define CONFIG_RX_DESCR_NUM 128
> +#define CONFIG_ETH_BUFSIZE 1522
I do not know the memory pressure on uboot but the number of descriptors could be less since uboot seems to not have any scattergather for network (so 64 or perhaps 32 could be enought)
> +
> +#define TX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_TX_DESCR_NUM)
> +#define RX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_RX_DESCR_NUM)
> +
> +#define REG_DEFAULT_VALUE 0x58000
> +#define REG_DEFAULT_MASK GENMASK(31, 15)
> +
> +#define REG_PHY_ADDR_SHIFT 20
> +#define REG_PHY_ADDR_MASK GENMASK(4, 0)
> +#define REG_LED_POL BIT(17) /* 1: active low, 0: active high */
> +#define REG_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */
> +#define REG_PHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */
> +
> +#define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ)
> +
> +#define AHB_GATE_OFFSET_GMAC 17
> +#define AHB_GATE_OFFSET_EPHY 0
> +
> +#define SUN8I_GPD8_GMAC 4
> +
> +/* H3/A64 EMAC Register Base */
> +#define SUN8I_EMAC_BASE 0x01c30000
> +
> +/* H3/A64 EMAC Register's offset */
> +#define CTL0 0x00
> +#define CTL1 0x04
> +#define INT_STA 0x08
> +#define INT_EN 0x0c
> +#define TX_CTL0 0x10
> +#define TX_CTL1 0x14
> +#define TX_FLOW_CTL 0x1c
> +#define TX_DMA_DESC 0x20
It seems you have mixed space and tab
> +#define RX_CTL0 0x24
> +#define RX_CTL1 0x28
> +#define RX_DMA_DESC 0x34
> +#define MII_CMD 0x48
> +#define MII_DATA 0x4c
> +#define ADDR0_HIGH 0x50
> +#define ADDR0_LOW 0x54
> +#define TX_DMA_STA 0xb0
> +#define TX_CUR_DESC 0xb4
> +#define TX_CUR_BUF 0xb8
> +#define RX_DMA_STA 0xc0
> +#define RX_CUR_DESC 0xc4
Perhaps prefixing all register with SUN8I_EMAC or just EMAC/GMAC could be better.
> +
> +/* CCM Register base */
> +#define SUN8I_CCM_BASE 0x01c20000
> +
> +/* CCM Register offset */
> +#define CLK_GATING_REG0 0x60
> +#define CLK_GATING_REG1 0x64
> +#define CLK_GATING_REG2 0x68
> +#define CLK_GATING_REG3 0x6c
> +#define CLK_GATING_REG4 0x70
> +
> +/* System Control Register base */
> +#define SUN8I_SCTL_BASE 0x01c00000
> +
> +/* System Control Register's offset */
> +#define VER_REG 0x24
> +#define EMAC_CLK_REG 0x30
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct emac_dma_desc {
> + u32 status;
> + u32 st;
> + void *buf_addr;
> + struct emac_dma_desc *next;
> +} __aligned(ARCH_DMA_MINALIGN);
> +
> +struct emac_eth_dev {
> + struct emac_dma_desc rx_chain[CONFIG_TX_DESCR_NUM];
> + struct emac_dma_desc tx_chain[CONFIG_RX_DESCR_NUM];
> + char rxbuffer[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
> + char txbuffer[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
> +
> + u32 interface;
> + u32 phyaddr;
> + u32 link;
> + u32 speed;
> + u32 duplex;
> + u32 phy_configured;
> + u32 tx_currdescnum;
> + u32 rx_currdescnum;
> + u32 addr;
> + u32 tx_slot;
> + void *mac_reg;
> + void *sysctl_reg;
> + void *ccu_reg;
> + struct phy_device *phydev;
> + struct mii_dev *bus;
> +};
> +
> +static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
> +{
> + struct emac_eth_dev *priv = bus->priv;
> + ulong start;
> + u32 miiaddr = 0;
> + int timeout = CONFIG_MDIO_TIMEOUT;
> +
> + miiaddr &= ~MDIO_CMD_MII_WRITE;
> + miiaddr &= ~MDIO_CMD_MII_PHY_REG_ADDR_MASK;
> + miiaddr |= (reg << MDIO_CMD_MII_PHY_REG_ADDR_SHIFT) &
> + MDIO_CMD_MII_PHY_REG_ADDR_MASK;
> +
> + miiaddr &= ~MDIO_CMD_MII_PHY_ADDR_MASK;
> +
> + miiaddr |= (addr << MDIO_CMD_MII_PHY_ADDR_SHIFT) &
> + MDIO_CMD_MII_PHY_ADDR_MASK;
> +
> + miiaddr |= MDIO_CMD_MII_BUSY;
> +
> + writel(miiaddr, priv->mac_reg + MII_CMD);
> +
> + start = get_timer(0);
> + while (get_timer(start) < timeout) {
> + if (!(readl(priv->mac_reg + MII_CMD) & MDIO_CMD_MII_BUSY))
> + return readl(priv->mac_reg + MII_DATA);
> + udelay(10);
> + };
> +
> + return -1;
> +}
> +
> +static int sun8i_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
> + u16 val)
> +{
> + struct emac_eth_dev *priv = bus->priv;
> + ulong start;
> + u32 miiaddr = 0;
> + int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
> +
> + miiaddr &= ~MDIO_CMD_MII_PHY_REG_ADDR_MASK;
> + miiaddr |= (reg << MDIO_CMD_MII_PHY_REG_ADDR_SHIFT) &
> + MDIO_CMD_MII_PHY_REG_ADDR_MASK;
> +
> + miiaddr &= ~MDIO_CMD_MII_PHY_ADDR_MASK;
> + miiaddr |= (addr << MDIO_CMD_MII_PHY_ADDR_SHIFT) &
> + MDIO_CMD_MII_PHY_ADDR_MASK;
> +
> + miiaddr |= MDIO_CMD_MII_WRITE;
> + miiaddr |= MDIO_CMD_MII_BUSY;
> +
> + writel(miiaddr, priv->mac_reg + MII_CMD);
> + writel(val, priv->mac_reg + MII_DATA);
> +
> + start = get_timer(0);
> + while (get_timer(start) < timeout) {
> + if (!(readl(priv->mac_reg + MII_CMD) & MDIO_CMD_MII_BUSY)) {
> + ret = 0;
> + break;
> + }
> + udelay(10);
> + };
> +
> + return ret;
> +}
> +
> +static int _sun8i_write_hwaddr(struct emac_eth_dev *priv, u8 *mac_id)
> +{
> + u32 macid_lo, macid_hi;
> +
> + macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
> + (mac_id[3] << 24);
> + macid_hi = mac_id[4] + (mac_id[5] << 8);
> +
> + writel(macid_hi, priv->mac_reg + ADDR0_HIGH);
> + writel(macid_lo, priv->mac_reg + ADDR0_LOW);
> +
> + return 0;
> +}
> +
> +static int sun8i_phy_init(struct emac_eth_dev *priv, void *dev)
> +{
> + struct phy_device *phydev;
> + u32 val;
> +
> + /* H3 based SoC has an Internal PHY that needs
> + to be configured and powered up before use
> + */
> +
> + val = readl(priv->sysctl_reg + EMAC_CLK_REG);
> + val = (val & ~REG_DEFAULT_MASK) | REG_DEFAULT_VALUE;
> +
> + val |= priv->phyaddr << REG_PHY_ADDR_SHIFT;
> + val &= ~REG_SHUTDOWN;
> + val |= REG_PHY_SELECT;
> +
> + setbits_le32((priv->sysctl_reg + EMAC_CLK_REG), (1 << 13));
> + writel(val, (priv->sysctl_reg + EMAC_CLK_REG));
> +
> + phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
> + if (!phydev)
> + return -ENODEV;
> +
> + phy_connect_dev(phydev, dev);
> +
> + priv->phydev = phydev;
> + phy_config(phydev);
> +
> + return 0;
> +}
> +
> +static void sun8i_adjust_link(struct emac_eth_dev *priv,
> + struct phy_device *phydev)
> +{
> + u32 v;
> + v = readl(priv->mac_reg + CTL0);
> +
> + if (phydev->duplex)
> + v |= BIT(0);
> + else
> + v &= ~BIT(0);
> +
> + v &= ~0x0C;
> +
> + switch (phydev->speed) {
> + case 1000:
> + break;
> + case 100:
> + v |= BIT(2);
> + v |= BIT(3);
> + break;
> + case 10:
> + v |= BIT(3);
> + break;
> + }
> + writel(v, priv->mac_reg + CTL0);
> +}
> +
> +static void rx_descs_init(struct emac_eth_dev *priv)
> +{
> + struct emac_dma_desc *desc_table_p = &priv->rx_chain[0];
> + char *rxbuffs = &priv->rxbuffer[0];
> + struct emac_dma_desc *desc_p;
> + u32 idx;
> +
> + /* flush Rx buffers */
> + flush_dcache_range((unsigned int)rxbuffs, (unsigned int)rxbuffs +
> + RX_TOTAL_BUFSIZE);
> +
> + for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
> + desc_p = &desc_table_p[idx];
> + desc_p->buf_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
> + desc_p->next = &desc_table_p[idx + 1];
> + desc_p->st |= CONFIG_ETH_BUFSIZE;
> + desc_p->status = BIT(31);
> + }
> +
> + /* Correcting the last pointer of the chain */
> + desc_p->next = &desc_table_p[0];
> +
> + flush_dcache_range((unsigned int)priv->rx_chain,
> + (unsigned int)priv->rx_chain +
> + sizeof(priv->rx_chain));
> +
> + writel((ulong)&desc_table_p[0], (priv->mac_reg + RX_DMA_DESC));
> + priv->rx_currdescnum = 0;
> +}
> +
> +static void tx_descs_init(struct emac_eth_dev *priv)
> +{
> + struct emac_dma_desc *desc_table_p = &priv->tx_chain[0];
> + char *txbuffs = &priv->txbuffer[0];
> + struct emac_dma_desc *desc_p;
> + u32 idx;
> +
> + for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
> + desc_p = &desc_table_p[idx];
> + desc_p->buf_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE];
> + desc_p->next = &desc_table_p[idx + 1];
> + desc_p->status = (1 << 31);
You forgot a BIT()
> + desc_p->st = 0;
> + }
> +
> + /* Correcting the last pointer of the chain */
> + desc_p->next = &desc_table_p[0];
> +
> + /* Flush all Tx buffer descriptors */
> + flush_dcache_range((unsigned int)priv->tx_chain,
> + (unsigned int)priv->tx_chain +
> + sizeof(priv->tx_chain));
> +
> + writel((ulong)&desc_table_p[0], priv->mac_reg + TX_DMA_DESC);
> + priv->tx_currdescnum = 0;
> +}
> +
> +static int _sun8i_emac_eth_init(struct emac_eth_dev *priv, u8 *enetaddr)
> +{
> + u32 reg, v;
> + int timeout = 100;
> +
> + reg = readl((priv->mac_reg + CTL1));
> +
> + if (!(reg & 0x1)) {
> + /* Soft reset MAC */
> + setbits_le32((priv->mac_reg + CTL1), 0x1 << 0);
The <<0 is useless
> + do {
> + reg = readl(priv->mac_reg + CTL1);
> + } while ((reg & 0x01) != 0 && (--timeout));
> + if (!timeout) {
> + printf("%s: Timeout\n", __func__);
> + return -1;
> +
> + }
> +
> + }
> +
> + /* Rewrite mac address after reset */
> + _sun8i_write_hwaddr(priv, enetaddr);
> +
> + v = readl(priv->mac_reg + TX_CTL1);
> + /* TX_MD Transmission starts after a full frame located in TX DMA FIFO*/
> + v |= BIT(1);
> + writel(v, priv->mac_reg + TX_CTL1);
> +
> + v = readl(priv->mac_reg + RX_CTL1);
> + /* RX_MD RX DMA reads data from RX DMA FIFO to host memory after a
> + * complete frame has been written to RX DMA FIFO
> + */
> + v |= BIT(1);
> + writel(v, priv->mac_reg + RX_CTL1);
> +
> + /* DMA */
> + writel(8 << 24 , priv->mac_reg + CTL1);
> +
> + /* Initialize rx/tx descriptors */
> + rx_descs_init(priv);
> + tx_descs_init(priv);
> +
> + /*Start up the PHY */
> + if (phy_startup(priv->phydev)) {
> + printf("Could not initialize PHY %s\n",
> + priv->phydev->dev->name);
> + return -1;
> + }
> +
> + sun8i_adjust_link(priv, priv->phydev);
> +
> + /* Start RX DMA */
> + v = readl(priv->mac_reg + RX_CTL1);
> + v |= BIT(30);
> + writel(v, priv->mac_reg + RX_CTL1);
> + /* Start TX DMA */
> + v = readl(priv->mac_reg + TX_CTL1);
> + v |= BIT(30);
> + writel(v, priv->mac_reg + TX_CTL1);
> +
> + /* Enable RX/TX */
> + setbits_le32(priv->mac_reg + RX_CTL0, 0x1 << 31);
> + setbits_le32(priv->mac_reg + TX_CTL0, 0x1 << 31);
BIT() again
> +
> + return 0;
> +}
> +
> +static void sun8i_emac_board_setup(struct emac_eth_dev *priv)
> +{
> + priv->ccu_reg = (void *)SUN8I_CCU_BASE;
> + priv->sysctl_reg = (void *)SUN8I_SCTL_BASE;
> + int pin;
> +
> + /* Set clock gating for emac */
> + setbits_le32((priv->ccu_reg + CLK_GATING_REG0),
> + 0x1 << AHB_GATE_OFFSET_GMAC);
> +
> + /* Set clock gating for ephy */
> + setbits_le32((priv->ccu_reg + CLK_GATING_REG4),
> + 0x1 << AHB_GATE_OFFSET_EPHY);
> +
> + /* Set Tx clock source as MII with rate 25 MZ */
> + clrbits_le32((priv->sysctl_reg + EMAC_CLK_REG),
> + SCTL_EMAC_TX_CLK_SRC_MII |
> + SCTL_EMAC_EPIT_MII | SCTL_EMAC_CLK_SEL);
> +
> + /* Set EMAC clock */
> + setbits_le32((priv->ccu_reg + AHB2_CFG_REG), (0x1 << 1) | (0x1 << 0));
> +
> + /* Deassert EPHY */
> + setbits_le32((priv->ccu_reg + BUS_SOFT_RST_REG2), EPHY_RST);
> +
> + /* De-assert EMAC */
> + setbits_le32((priv->ccu_reg + BUS_SOFT_RST_REG0), EMAC_RST);
> +
> + /* Pin mux setting for emac */
> + for (pin = SUNXI_GPD(8); pin <= SUNXI_GPD(22); pin++)
> + sunxi_gpio_set_cfgpin(pin, SUN8I_GPD8_GMAC);
> +}
> +
> +static int _sun8i_eth_recv(struct emac_eth_dev *priv, uchar **packetp)
> +{
> + u32 status, desc_num = priv->rx_currdescnum;
> + struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num];
> + int length = -EAGAIN;
> + uint32_t desc_start = (uint32_t)desc_p;
> + uint32_t desc_end = desc_start +
> + roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
> +
> + uint32_t data_start = (uint32_t)desc_p->buf_addr;
> + uint32_t data_end;
> +
> + /* Invalidate entire buffer descriptor */
> + invalidate_dcache_range(desc_start, desc_end);
> +
> + status = desc_p->status;
> +
> + /* Check for DMA own bit */
> + if (!(status & BIT(31))) {
> + length = (desc_p->status >> 16) & 0x3FFF;
> + data_end = data_start + length;
> + /* Invalidate received data */
> + invalidate_dcache_range(rounddown(data_start,
> + ARCH_DMA_MINALIGN),
> + roundup(data_end,
> + ARCH_DMA_MINALIGN));
> + *packetp = desc_p->buf_addr;
> + }
> + return length;
> +}
You do not check for any reception error.
> +
> +static int _sun8i_emac_eth_send(struct emac_eth_dev *priv, void *packet,
> + int len)
> +{
> + u32 v, desc_num = priv->tx_currdescnum;
> + struct emac_dma_desc *desc_p = &priv->tx_chain[desc_num];
> + uint32_t desc_start = (uint32_t)desc_p;
> + uint32_t desc_end = desc_start +
> + roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
> +
> + uint32_t data_start = (uint32_t)desc_p->buf_addr;
> + uint32_t data_end = data_start +
> + roundup(len, ARCH_DMA_MINALIGN);
> +
> + /* Invalidate entire buffer descriptor */
> + invalidate_dcache_range(desc_start, desc_end);
> +
> + desc_p->st = len;
> + /* Mandatory undocumented bit */
> + desc_p->st |= BIT(24);
> +
> + memcpy(desc_p->buf_addr, packet, len);
Since I do not see any MTU settings, perhaps you need to check len against CONFIG_ETH_BUFSIZE (sunxi_emac.c do this for reception with rx_len > EMAC_RX_BUFSIZE)
> +
> + /* Flush data to be sent */
> + flush_dcache_range(data_start, data_end);
> +
> + /* frame end */
> + desc_p->st |= BIT(30);
> + desc_p->st |= BIT(31);
> +
> + /*frame begin */
> + desc_p->st |= BIT(29);
> + desc_p->status = BIT(31);
> +
> + /*Descriptors st and status field has changed, so FLUSH it */
> + flush_dcache_range(desc_start, desc_end);
> +
> + /* Move to next Descriptor and wrap around */
> + if (++desc_num >= CONFIG_TX_DESCR_NUM)
> + desc_num = 0;
> + priv->tx_currdescnum = desc_num;
> +
> + /* Start the DMA */
> + v = readl(priv->mac_reg + TX_CTL1);
> + v |= BIT(31);/* mandatory */
> + v |= BIT(30);/* mandatory */
> + writel(v, priv->mac_reg + TX_CTL1);
> +
> + return 0;
> +}
> +
> +static int sun8i_emac_eth_send(struct udevice *dev, void *packet, int length)
> +{
> + struct emac_eth_dev *priv = dev_get_priv(dev);
> + return _sun8i_emac_eth_send(priv, packet, length);
> +}
> +
> +static void sun8i_emac_eth_stop(struct udevice *dev)
> +{
> + struct emac_eth_dev *priv = dev_get_priv(dev);
> +
> + /* Stop Rx/Tx transmitter */
> + clrbits_le32(priv->mac_reg + RX_CTL0, BIT(31));
> + clrbits_le32(priv->mac_reg + TX_CTL0, BIT(31));
> +
> + /* Stop TX DMA */
> + clrbits_le32(priv->mac_reg + TX_CTL1, BIT(30));
> +
> + /* Disable Interrupt, This is required to leave
> + from U-boot and enter OS in proper Interrupt state */
> + writel(0, priv->mac_reg + INT_EN);
> +
> + phy_shutdown(priv->phydev);
> +}
You disable interrupt but I do not see any enabling of it.
> +
> +
> +static int sun8i_emac_eth_start(struct udevice *dev)
> +{
> + struct eth_pdata *pdata = dev_get_platdata(dev);
> + return _sun8i_emac_eth_init(dev->priv, pdata->enetaddr);
> +}
> +
> +static int sun8i_mdio_init(const char *name, struct emac_eth_dev *priv)
> +{
> + struct mii_dev *bus = mdio_alloc();
> +
> + if (!bus) {
> + printf("Failed to allocate MDIO bus\n");
> + return -ENOMEM;
> + }
> +
> + bus->read = sun8i_mdio_read;
> + bus->write = sun8i_mdio_write;
> + snprintf(bus->name, sizeof(bus->name), name);
> + bus->priv = (void *)priv;
> +
> + return mdio_register(bus);
> +}
> +
> +static int sun8i_emac_eth_probe(struct udevice *dev)
> +{
> + struct eth_pdata *pdata = dev_get_platdata(dev);
> + struct emac_eth_dev *priv = dev_get_priv(dev);
> +
> + priv->mac_reg = (void *)pdata->iobase;
> + sun8i_emac_board_setup(priv);
> +
> + sun8i_mdio_init(dev->name, priv);
> + priv->bus = miiphy_get_dev_by_name(dev->name);
> +
> + return sun8i_phy_init(priv, dev);
> +}
> +
> +static int sun8i_eth_write_hwaddr(struct udevice *dev)
> +{
> + struct eth_pdata *pdata = dev_get_platdata(dev);
> + struct emac_eth_dev *priv = dev_get_priv(dev);
> + return _sun8i_write_hwaddr(priv, pdata->enetaddr);
> +}
> +
> +static int sun8i_emac_eth_recv(struct udevice *dev, int flags, uchar **packetp)
> +{
> + struct emac_eth_dev *priv = dev_get_priv(dev);
> +
> + return _sun8i_eth_recv(priv, packetp);
> +}
> +
> +static int _sun8i_free_pkt(struct emac_eth_dev *priv)
> +{
> + u32 desc_num = priv->rx_currdescnum;
> + struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num];
> + uint32_t desc_start = (uint32_t)desc_p;
> + uint32_t desc_end = desc_start +
> + roundup(sizeof(u32), ARCH_DMA_MINALIGN);
> +
> + /* Make the current descriptor valid again */
> + desc_p->status |= BIT(31);
> +
> + /* Flush Status field of descriptor */
> + flush_dcache_range(desc_start, desc_end);
> +
> + /* Move to next desc and wrap-around condition. */
> + if (++desc_num >= CONFIG_RX_DESCR_NUM)
> + desc_num = 0;
> + priv->rx_currdescnum = desc_num;
> +
> + return 0;
> +}
> +
> +static int sun8i_eth_free_pkt(struct udevice *dev, uchar *packet,
> + int length)
> +{
> + struct emac_eth_dev *priv = dev_get_priv(dev);
> +
> + return _sun8i_free_pkt(priv);
> +}
> +
> +static const struct eth_ops sun8i_emac_eth_ops = {
> + .start = sun8i_emac_eth_start,
> + .write_hwaddr = sun8i_eth_write_hwaddr,
> + .send = sun8i_emac_eth_send,
> + .recv = sun8i_emac_eth_recv,
> + .free_pkt = sun8i_eth_free_pkt,
> + .stop = sun8i_emac_eth_stop,
> +};
> +
> +static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
> +{
> + struct eth_pdata *pdata = dev_get_platdata(dev);
> + struct emac_eth_dev *priv = dev_get_priv(dev);
> + const char *phy_mode;
> + int offset = 0;
> + pdata->iobase = dev_get_addr(dev);
> +
> + pdata->phy_interface = -1;
> + priv->phyaddr = -1;
> +
> + offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
> + "phy");
> + if (offset > 0)
> + priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -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) {
> + printf("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
> + return -EINVAL;
> + }
> +
> + priv->interface = pdata->phy_interface;
> +
> + return 0;
> +}
> +
> +static const struct udevice_id sun8i_emac_eth_ids[] = {
> + { .compatible = "allwinner,sun8i-h3-emac" },
> + { }
> +};
> +
> +U_BOOT_DRIVER(eth_sun8i_emac) = {
> + .name = "eth_sun8i_emac",
> + .id = UCLASS_ETH,
> + .of_match = sun8i_emac_eth_ids,
> + .ofdata_to_platdata = sun8i_emac_eth_ofdata_to_platdata,
> + .probe = sun8i_emac_eth_probe,
> + .ops = &sun8i_emac_eth_ops,
> + .priv_auto_alloc_size = sizeof(struct emac_eth_dev),
> + .platdata_auto_alloc_size = sizeof(struct eth_pdata),
> + .flags = DM_FLAG_ALLOC_PRIV_DMA,
> +};
>
Regards
More information about the U-Boot
mailing list