Re: [linux-sunxi] [PATCH RFC 1/3] ethernet: add sun8i-emac driver
Hi, just some comments I have on the usage of the internal PHY. On 22/02/16 15:45, LABBE Corentin wrote: > This patch add support for sun8i-emac ethernet MAC hardware. > It could be found in Allwinner H3/A83T/A64 SoCs. > > Signed-off-by: LABBE Corentin> --- > drivers/net/ethernet/allwinner/Kconfig | 14 + > drivers/net/ethernet/allwinner/Makefile |1 + > drivers/net/ethernet/allwinner/sun8i-emac.c | 1493 > +++ > 3 files changed, 1508 insertions(+) > create mode 100644 drivers/net/ethernet/allwinner/sun8i-emac.c > > diff --git a/drivers/net/ethernet/allwinner/sun8i-emac.c > b/drivers/net/ethernet/allwinner/sun8i-emac.c > new file mode 100644 > index 000..a4e52cf > --- /dev/null > +++ b/drivers/net/ethernet/allwinner/sun8i-emac.c > @@ -0,0 +1,1493 @@ > +/* > + * sun8i-h3-emac driver > + * > + * Copyright (C) 2015-2016 Corentin LABBE > + * > + * This is the driver for Allwinner Ethernet MAC found in H3/A83T/A64 SoC > + * > + * This is a mono block driver that need to be splited: > + * - A classic ethernet MAC driver > + * - A PHY driver > + * - A clk driver > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +/* for A83T */ > +#include > + > +#define SUN8I_EMAC_BASIC_CTL0 0x00 > +#define SUN8I_EMAC_BASIC_CTL1 0x04 > + > +#define SUN8I_EMAC_MDIO_CMD 0x48 > +#define SUN8I_EMAC_MDIO_DATA 0x4C > + > +#define SUN8I_EMAC_RX_CTL0 0x24 > +#define SUN8I_EMAC_RX_CTL1 0x28 > + > +#define SUN8I_EMAC_TX_CTL0 0x10 > +#define SUN8I_EMAC_TX_CTL1 0x14 > + > +#define SUN8I_EMAC_TX_FLOW_CTL 0x1C > + > +#define SUN8I_EMAC_INT_STA 0x08 > +#define SUN8I_EMAC_INT_EN 0x0C > +#define SUN8I_EMAC_RGMII_STA 0xD0 > + > +#define SUN8I_EMAC_TX_DMA_STA 0xB0 > +#define SUN8I_EMAC_TX_CUR_DDESC 0xB4 > +#define SUN8I_EMAC_RX_DMA_STA 0xC0 > + > +#define MII_BUSY BIT(0) > +#define MII_WRITEBIT(1) > + > +#define SUN8I_EMAC_MACADDR_HI0x50 > +#define SUN8I_EMAC_MACADDR_LO0x54 > + > +#define SUN8I_EMAC_RX_DESC_LIST 0x34 > +#define SUN8I_EMAC_TX_DESC_LIST 0x20 > + > +#define SUN8I_COULD_BE_USED_BY_DMA BIT(31) > + > +struct dma_desc { > + u32 status; > + u32 st; > + u32 buf_addr; > + u32 next; > +} __attribute__((packed, aligned(4))); > + > +static int flow_ctrl; > +static int pause = 0x400; > + > +static int nbdesc = 4; > +struct sun8i_emac_priv { > + void __iomem *base; > + int irq; > + struct device *dev; > + struct net_device *ndev; > + struct mii_bus *mii; > + spinlock_t lock; > + spinlock_t tx_lock; > + int duplex; > + int speed; > + int link; > + u32 phy_interface; > + struct clk *busclk; > + struct clk *miiclk; > + u32 mdc; > + > + struct reset_control *rst_phy; > + struct reset_control *rst_mac; > + > + struct dma_desc *dd_rx cacheline_aligned; > + dma_addr_t dd_rx_phy cacheline_aligned; > + struct dma_desc *dd_tx; > + dma_addr_t dd_tx_phy; > + struct sk_buff **rx_sk; > + struct sk_buff **tx_sk; > + > + struct regulator *power; > +}; > + > +/* allocate a sk in a dma descriptor > +*/ > +static int sun8i_emac_rx_sk(struct net_device *ndev, int i) > +{ > + struct sun8i_emac_priv *priv = netdev_priv(ndev); > + struct dma_desc *ddesc; > + struct sk_buff *sk; > + > + ddesc = priv->dd_rx + i; > + > + ddesc->st = 0; > + > + sk = netdev_alloc_skb_ip_align(ndev, ndev->mtu); > + if (!sk) > + return -ENOMEM; > + > + if (priv->rx_sk[i]) { > + dev_warn(priv->dev, "WARN: Leaking a skbuff\n"); > + /* TODO should not happen */ > + } > + > + priv->rx_sk[i] = sk; > + > + ddesc->buf_addr = dma_map_single(priv->dev, sk->data, > + ndev->mtu, DMA_FROM_DEVICE); > + if (dma_mapping_error(priv->dev, ddesc->buf_addr)) { > + dev_err(priv->dev, "ERROR: Cannot dma_map RX\n"); > + dev_kfree_skb(sk); > + return -EINVAL; > + } > + ddesc->st |= ndev->mtu; > + ddesc->status = BIT(31); > + > + dev_info(priv->dev, "Init ddesc %02d at %pad buff=%p %x status=(%x > %x)\n", > + i, , >data, ddesc->buf_addr, ddesc->status, > ddesc->st); > + > + return 0; > +} > + > +/* Set MAC address for slot index > + * */ > +void sun8i_emac_set_macaddr(struct sun8i_emac_priv *priv, unsigned char > *addr, > + int index) > +{ > + u32 v; > + > + if (!is_valid_ether_addr(addr)) { > + random_ether_addr(priv->ndev->dev_addr); > + addr = priv->ndev->dev_addr; > + } > + dev_info(priv->dev, "%s %x %x %x %x %x %x\n", __func__, > + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]), > + > + v
[linux-sunxi] [PATCH RFC 1/3] ethernet: add sun8i-emac driver
This patch add support for sun8i-emac ethernet MAC hardware. It could be found in Allwinner H3/A83T/A64 SoCs. Signed-off-by: LABBE Corentin--- drivers/net/ethernet/allwinner/Kconfig | 14 + drivers/net/ethernet/allwinner/Makefile |1 + drivers/net/ethernet/allwinner/sun8i-emac.c | 1493 +++ 3 files changed, 1508 insertions(+) create mode 100644 drivers/net/ethernet/allwinner/sun8i-emac.c diff --git a/drivers/net/ethernet/allwinner/Kconfig b/drivers/net/ethernet/allwinner/Kconfig index 47da7e7..43cf91f 100644 --- a/drivers/net/ethernet/allwinner/Kconfig +++ b/drivers/net/ethernet/allwinner/Kconfig @@ -33,4 +33,18 @@ config SUN4I_EMAC To compile this driver as a module, choose M here. The module will be called sun4i-emac. +config SUN8I_EMAC +tristate "Allwinner H3 EMAC support" + depends on ARCH_SUNXI + depends on OF + select CRC32 + select MII + select PHYLIB + select MDIO_SUN4I +---help--- + Support for Allwinner H3 EMAC ethernet driver. + + To compile this driver as a module, choose M here. The module + will be called sun8i-emac. + endif # NET_VENDOR_ALLWINNER diff --git a/drivers/net/ethernet/allwinner/Makefile b/drivers/net/ethernet/allwinner/Makefile index 03129f7..8bd1693c 100644 --- a/drivers/net/ethernet/allwinner/Makefile +++ b/drivers/net/ethernet/allwinner/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_SUN4I_EMAC) += sun4i-emac.o +obj-$(CONFIG_SUN8I_EMAC) += sun8i-emac.o diff --git a/drivers/net/ethernet/allwinner/sun8i-emac.c b/drivers/net/ethernet/allwinner/sun8i-emac.c new file mode 100644 index 000..a4e52cf --- /dev/null +++ b/drivers/net/ethernet/allwinner/sun8i-emac.c @@ -0,0 +1,1493 @@ +/* + * sun8i-h3-emac driver + * + * Copyright (C) 2015-2016 Corentin LABBE + * + * This is the driver for Allwinner Ethernet MAC found in H3/A83T/A64 SoC + * + * This is a mono block driver that need to be splited: + * - A classic ethernet MAC driver + * - A PHY driver + * - A clk driver + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* for A83T */ +#include + +#define SUN8I_EMAC_BASIC_CTL0 0x00 +#define SUN8I_EMAC_BASIC_CTL1 0x04 + +#define SUN8I_EMAC_MDIO_CMD 0x48 +#define SUN8I_EMAC_MDIO_DATA 0x4C + +#define SUN8I_EMAC_RX_CTL0 0x24 +#define SUN8I_EMAC_RX_CTL1 0x28 + +#define SUN8I_EMAC_TX_CTL0 0x10 +#define SUN8I_EMAC_TX_CTL1 0x14 + +#define SUN8I_EMAC_TX_FLOW_CTL 0x1C + +#define SUN8I_EMAC_INT_STA 0x08 +#define SUN8I_EMAC_INT_EN 0x0C +#define SUN8I_EMAC_RGMII_STA 0xD0 + +#define SUN8I_EMAC_TX_DMA_STA 0xB0 +#define SUN8I_EMAC_TX_CUR_DDESC 0xB4 +#define SUN8I_EMAC_RX_DMA_STA 0xC0 + +#define MII_BUSY BIT(0) +#define MII_WRITE BIT(1) + +#define SUN8I_EMAC_MACADDR_HI 0x50 +#define SUN8I_EMAC_MACADDR_LO 0x54 + +#define SUN8I_EMAC_RX_DESC_LIST 0x34 +#define SUN8I_EMAC_TX_DESC_LIST 0x20 + +#define SUN8I_COULD_BE_USED_BY_DMA BIT(31) + +struct dma_desc { + u32 status; + u32 st; + u32 buf_addr; + u32 next; +} __attribute__((packed, aligned(4))); + +static int flow_ctrl; +static int pause = 0x400; + +static int nbdesc = 4; +struct sun8i_emac_priv { + void __iomem *base; + int irq; + struct device *dev; + struct net_device *ndev; + struct mii_bus *mii; + spinlock_t lock; + spinlock_t tx_lock; + int duplex; + int speed; + int link; + u32 phy_interface; + struct clk *busclk; + struct clk *miiclk; + u32 mdc; + + struct reset_control *rst_phy; + struct reset_control *rst_mac; + + struct dma_desc *dd_rx cacheline_aligned; + dma_addr_t dd_rx_phy cacheline_aligned; + struct dma_desc *dd_tx; + dma_addr_t dd_tx_phy; + struct sk_buff **rx_sk; + struct sk_buff **tx_sk; + + struct regulator *power; +}; + +/* allocate a sk in a dma descriptor +*/ +static int sun8i_emac_rx_sk(struct net_device *ndev, int i) +{ + struct sun8i_emac_priv *priv = netdev_priv(ndev); + struct dma_desc *ddesc; + struct sk_buff *sk; + + ddesc = priv->dd_rx + i; + + ddesc->st = 0; + + sk = netdev_alloc_skb_ip_align(ndev, ndev->mtu); + if (!sk) + return -ENOMEM; + + if (priv->rx_sk[i]) { + dev_warn(priv->dev, "WARN: Leaking a skbuff\n"); + /* TODO should not happen */ + } + + priv->rx_sk[i] = sk; + + ddesc->buf_addr = dma_map_single(priv->dev, sk->data, +ndev->mtu, DMA_FROM_DEVICE); + if (dma_mapping_error(priv->dev, ddesc->buf_addr)) { + dev_err(priv->dev, "ERROR: Cannot dma_map RX\n"); + dev_kfree_skb(sk); +