[PATCH v1 01/10] net: ath79: add ar9344 support

Sascha Hauer s.hauer at pengutronix.de
Mon Sep 11 23:11:11 PDT 2017


On Sun, Aug 27, 2017 at 09:02:21AM +0200, Oleksij Rempel wrote:
> Signed-off-by: Oleksij Rempel <linux at rempel-privat.de>
> ---
>  drivers/net/ag71xx.c | 192 +++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 165 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/net/ag71xx.c b/drivers/net/ag71xx.c
> index d13bf9171..b8bd12bc3 100644
> --- a/drivers/net/ag71xx.c
> +++ b/drivers/net/ag71xx.c
> @@ -12,6 +12,7 @@
>   */
>  
>  #include <common.h>
> +#include <driver.h>
>  #include <net.h>
>  #include <dma.h>
>  #include <init.h>
> @@ -185,6 +186,11 @@
>  #define AG71XX_ETH_CFG_RGMII_GE0        (1<<0)
>  #define AG71XX_ETH_CFG_MII_GE0_SLAVE    (1<<4)
>  
> +enum ag71xx_type {
> +	AG71XX_TYPE_AR9331_GE0,
> +	AG71XX_TYPE_AR9344_GMAC0,
> +};
> +
>  /*
>   * h/w descriptor
>   */
> @@ -213,23 +219,31 @@ struct ag71xx {
>  	void __iomem *regs;
>  	void __iomem *regs_gmac;
>  	struct mii_bus miibus;
> +	const struct ag71xx_cfg *cfg;
>  
>  	void *rx_buffer;
>  
>  	unsigned char *rx_pkt[NO_OF_RX_FIFOS];
>  	ag7240_desc_t *fifo_tx;
>  	ag7240_desc_t *fifo_rx;
> +	dma_addr_t addr_tx;
> +	dma_addr_t addr_rx;
>  
>  	int next_tx;
>  	int next_rx;
>  };
>  
> +struct ag71xx_cfg {
> +	enum ag71xx_type type;
> +	void (*init_mii)(struct ag71xx *priv);
> +};
> +
>  static inline void ag71xx_check_reg_offset(struct ag71xx *priv, int reg)
>  {
>  	switch (reg) {
>  	case AG71XX_REG_MAC_CFG1 ... AG71XX_REG_MAC_MFL:
>  	case AG71XX_REG_MAC_IFCTL ... AG71XX_REG_TX_SM:
> -	case AG71XX_REG_MII_CFG:
> +	case AG71XX_REG_MII_CFG ... AG71XX_REG_MII_IND:
>  		break;
>  
>  	default:
> @@ -237,6 +251,16 @@ static inline void ag71xx_check_reg_offset(struct ag71xx *priv, int reg)
>  	}
>  }
>  
> +static inline u32 ar7240_reg_rd(u32 reg)
> +{
> +	return __raw_readl(KSEG1ADDR(reg));
> +}
> +
> +static inline void ar7240_reg_wr(u32 reg, u32 val)
> +{
> +	__raw_writel(val, KSEG1ADDR(reg));
> +}
> +
>  static inline u32 ag71xx_gmac_rr(struct ag71xx *dev, int reg)
>  {
>  	return __raw_readl(dev->regs_gmac + reg);
> @@ -263,13 +287,81 @@ static inline void ag71xx_wr(struct ag71xx *priv, int reg, u32 val)
>  	(void)__raw_readl(priv->regs + reg);
>  }
>  
> -static int ag71xx_ether_mii_read(struct mii_bus *miidev, int addr, int reg)
> +static int ag71xx_ether_mii_read(struct mii_bus *miidev, int phy_addr, int reg)
>  {
> -	return 0xffff;
> +	struct ag71xx *priv = miidev->priv;
> +	const struct ag71xx_cfg *cfg = priv->cfg;
> +	volatile int rddata;

The 'volatile' looks rather unnecessary.

> +	u16 addr = (phy_addr << MII_ADDR_SHIFT) | reg, val;
> +	u16 ii = 0xFFFF;

lowercase letters for hex numbers please.

This is a loop counter, no need to specify the width of the variable,
plain 'int' looks better here.

> +
> +	if (AG71XX_TYPE_AR9331_GE0 == cfg->type)
> +		return 0xffff;
> +	/*
> +	 * Check for previous transactions are complete. Added to avoid
> +	 * race condition while running at higher frequencies.
> +	 */
> +	do {
> +		udelay(5);
> +		rddata = ag71xx_rr(priv, AG71XX_REG_MII_IND) & MII_IND_BUSY;
> +	} while (rddata && --ii);
> +
> +	if (ii == 0)
> +		printk("ERROR:%s:%d transaction failed\n",__func__,__LINE__);

Please use dev_err when printing device specific messages.

Shouldn't you return an error here instead of continuing?

> +
> +
> +	ag71xx_wr(priv, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
> +	ag71xx_wr(priv, AG71XX_REG_MII_ADDR, addr);
> +	ag71xx_wr(priv, AG71XX_REG_MII_CMD, MII_CMD_READ);
> +
> +	do {
> +		udelay(5);
> +		rddata = ag71xx_rr(priv, AG71XX_REG_MII_IND) & MII_IND_BUSY;
> +	} while (rddata && --ii);
> +
> +	if (ii == 0)
> +		printk("Error!!! Leave ag7240_miiphy_read without polling correct status!\n");
> +
> +	val = ag71xx_rr(priv, AG71XX_REG_MII_STATUS);
> +	ag71xx_wr(priv, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
> +
> +	return val;
>  }
>  
> -static int ag71xx_ether_mii_write(struct mii_bus *miidev, int addr, int reg, u16 val)
> +static int ag71xx_ether_mii_write(struct mii_bus *miidev, int phy_addr,
> +				  int reg, u16 val)
>  {
> +	struct ag71xx *priv = miidev->priv;
> +	const struct ag71xx_cfg *cfg = priv->cfg;
> +	u16 addr = (phy_addr << MII_ADDR_SHIFT) | reg;
> +	u16 ii = 0xFFFF;
> +	volatile int rddata;

volatile?

> +
> +	if (AG71XX_TYPE_AR9331_GE0 == cfg->type)
> +		return 0;
> +
> +	/*
> +	 * Check for previous transactions are complete. Added to avoid
> +	 * race condition while running at higher frequencies.
> +	 */
> +	do {
> +		udelay(5);
> +		rddata = ag71xx_rr(priv, AG71XX_REG_MII_IND) & MII_IND_BUSY;
> +	} while (rddata && --ii);
> +
> +	if (ii == 0)
> +		printk("ERROR:%s:%d transaction failed\n", __func__, __LINE__);
> +
> +	ag71xx_wr(priv, AG71XX_REG_MII_ADDR, addr);
> +	ag71xx_wr(priv, AG71XX_REG_MII_CTRL, val);
> +
> +	do {
> +		rddata = ag71xx_rr(priv, AG71XX_REG_MII_IND) & MII_IND_BUSY;
> +	} while (rddata && --ii);
> +
> +	if (ii == 0)
> +		printk("Error!!! Leave ag7240_miiphy_write without polling correct status!\n");
> +
>  	return 0;
>  }
>  
> @@ -372,6 +464,13 @@ static int ag71xx_ether_send(struct eth_device *edev, void *packet, int length)
>  
>  static int ag71xx_ether_open(struct eth_device *edev)
>  {
> +	struct ag71xx *priv = edev->priv;
> +	const struct ag71xx_cfg *cfg = priv->cfg;
> +
> +	if (AG71XX_TYPE_AR9344_GMAC0 == cfg->type)
> +		return phy_device_connect(edev, &priv->miibus, 0,
> +			NULL, 0, PHY_INTERFACE_MODE_RGMII_TXID);
> +
>  	return 0;
>  }
>  
> @@ -408,25 +507,63 @@ static int ag71xx_ether_init(struct eth_device *edev)
>  	return 1;
>  }
>  
> -static int ag71xx_mii_setup(struct ag71xx *priv)
> +static void ag71xx_ar9331_ge0_mii_init(struct ag71xx *priv)
>  {
>  	u32 rd;
>  
> -	rd = ag71xx_gmac_rr(priv, 0);
> +	rd = ag71xx_rr(priv, AG71XX_REG_MAC_CFG2);
> +	rd |= (MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK | MAC_CFG2_IF_10_100);
> +	ag71xx_wr(priv, AG71XX_REG_MAC_CFG2, rd);
> +
> +	/* config FIFOs */
> +	ag71xx_wr(priv, AG71XX_REG_FIFO_CFG0, 0x1f00);
> +
> +	rd = ag71xx_gmac_rr(priv, AG71XX_REG_MAC_CFG1);
>  	rd |= AG71XX_ETH_CFG_MII_GE0_SLAVE;
>  	ag71xx_gmac_wr(priv, 0, rd);
> +}
>  
> -	return 0;
> +static void ag71xx_ar9344_gmac0_mii_init(struct ag71xx *priv)
> +{
> +	u32 rd;
> +
> +	rd = ag71xx_rr(priv, AG71XX_REG_MAC_CFG2);
> +	rd |= (MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK | MAC_CFG2_IF_1000);
> +	ag71xx_wr(priv, AG71XX_REG_MAC_CFG2, rd);
> +
> +	/* config FIFOs */
> +	ag71xx_wr(priv, AG71XX_REG_FIFO_CFG0, 0x1f00);
> +
> +	ag71xx_gmac_wr(priv, AG71XX_REG_MAC_CFG1, 1);
> +	udelay(1000);
> +	ag71xx_wr(priv, AG71XX_REG_MII_CFG, 4 | (1 << 31));
> +	ag71xx_wr(priv, AG71XX_REG_MII_CFG, 4);
>  }
>  
> +static struct ag71xx_cfg ag71xx_cfg_ar9331_ge0 = {
> +	.type = AG71XX_TYPE_AR9331_GE0,
> +	.init_mii = ag71xx_ar9331_ge0_mii_init,
> +};
> +
> +static struct ag71xx_cfg ag71xx_cfg_ar9344_gmac0 = {
> +	.type = AG71XX_TYPE_AR9344_GMAC0,
> +	.init_mii = ag71xx_ar9344_gmac0_mii_init,
> +};
> +
>  static int ag71xx_probe(struct device_d *dev)
>  {
>  	void __iomem *regs, *regs_gmac;
>  	struct mii_bus *miibus;
>  	struct eth_device *edev;
> +	struct ag71xx_cfg *cfg;
>  	struct ag71xx *priv;
>  	u32 mac_h, mac_l;
> -	u32 rd;
> +	u32 rd, mask;
> +	int ret;
> +
> +	ret = dev_get_drvdata(dev, (const void **)&cfg);
> +	if (ret)
> +		return ret;
>  
>  	regs_gmac = dev_request_mem_region_by_name(dev, "gmac");
>  	if (IS_ERR(regs_gmac))
> @@ -452,41 +589,42 @@ static int ag71xx_probe(struct device_d *dev)
>  	priv->dev = dev;
>  	priv->regs = regs;
>  	priv->regs_gmac = regs_gmac;
> +	priv->cfg = cfg;
>  
>  	miibus->read = ag71xx_ether_mii_read;
>  	miibus->write = ag71xx_ether_mii_write;
>  	miibus->priv = priv;
>  
>  	/* enable switch core */
> -	rd = __raw_readl((char *)KSEG1ADDR(AR71XX_PLL_BASE + AR933X_ETHSW_CLOCK_CONTROL_REG)) & ~(0x1f);
> +	rd = ar7240_reg_rd(AR71XX_PLL_BASE + AR933X_ETHSW_CLOCK_CONTROL_REG);
> +	rd &= ~(0x1f);
>  	rd |= 0x10;
> -	__raw_writel(rd, (char *)KSEG1ADDR(AR71XX_PLL_BASE + AR933X_ETHSW_CLOCK_CONTROL_REG));
> +	if ((ar7240_reg_rd(WASP_BOOTSTRAP_REG) & WASP_REF_CLK_25) == 0)
> +		rd |= 0x1;
> +	ar7240_reg_wr((AR71XX_PLL_BASE + AR933X_ETHSW_CLOCK_CONTROL_REG), rd);
>  
>  	if (ath79_reset_rr(AR933X_RESET_REG_RESET_MODULE) != 0)
>  		ath79_reset_wr(AR933X_RESET_REG_RESET_MODULE, 0);
>  
>  	/* reset GE0 MAC and MDIO */
> +	mask = AR933X_RESET_GE0_MAC | AR933X_RESET_GE0_MDIO
> +		| AR933X_RESET_SWITCH;
> +
>  	rd = ath79_reset_rr(AR933X_RESET_REG_RESET_MODULE);
> -	rd |= AR933X_RESET_GE0_MAC | AR933X_RESET_GE0_MDIO | AR933X_RESET_SWITCH;
> +	rd |= mask;
>  	ath79_reset_wr(AR933X_RESET_REG_RESET_MODULE, rd);
>  	mdelay(100);
>  
>  	rd = ath79_reset_rr(AR933X_RESET_REG_RESET_MODULE);
> -	rd &= ~(AR933X_RESET_GE0_MAC | AR933X_RESET_GE0_MDIO | AR933X_RESET_SWITCH);
> +	rd &= ~(mask);

This mask handling looks like a cleanup that should be in another patch.

>  	ath79_reset_wr(AR933X_RESET_REG_RESET_MODULE, rd);
>  	mdelay(100);
>  
>  	ag71xx_wr(priv, AG71XX_REG_MAC_CFG1, (MAC_CFG1_SR | MAC_CFG1_TX_RST | MAC_CFG1_RX_RST));
>  	ag71xx_wr(priv, AG71XX_REG_MAC_CFG1, (MAC_CFG1_RXE | MAC_CFG1_TXE));
>  
> -	rd = ag71xx_rr(priv, AG71XX_REG_MAC_CFG2);
> -	rd |= (MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK | MAC_CFG2_IF_10_100);
> -	ag71xx_wr(priv, AG71XX_REG_MAC_CFG2, rd);
> -
> -	/* config FIFOs */
> -	ag71xx_wr(priv, AG71XX_REG_FIFO_CFG0, 0x1f00);
> -
> -	ag71xx_mii_setup(priv);
> +	if (cfg->init_mii)
> +		cfg->init_mii(priv);
>  
>  	ag71xx_wr(priv, AG71XX_REG_FIFO_CFG1, 0x10ffff);
>  	ag71xx_wr(priv, AG71XX_REG_FIFO_CFG2, 0xAAA0555);
> @@ -497,8 +635,10 @@ static int ag71xx_probe(struct device_d *dev)
>  	ag71xx_wr(priv, AG71XX_REG_FIFO_CFG3, 0x1f00140);
>  
>  	priv->rx_buffer = xmemalign(PAGE_SIZE, NO_OF_RX_FIFOS * MAX_RBUFF_SZ);
> -	priv->fifo_tx = dma_alloc_coherent(NO_OF_TX_FIFOS * sizeof(ag7240_desc_t), DMA_ADDRESS_BROKEN);
> -	priv->fifo_rx = dma_alloc_coherent(NO_OF_RX_FIFOS * sizeof(ag7240_desc_t), DMA_ADDRESS_BROKEN);
> +	priv->fifo_tx = dma_alloc_coherent(NO_OF_TX_FIFOS * sizeof(ag7240_desc_t),
> +					   &priv->addr_tx);
> +	priv->fifo_rx = dma_alloc_coherent(NO_OF_RX_FIFOS * sizeof(ag7240_desc_t),
> +					   &priv->addr_rx);

I think this change deserves an extra patch.

>  	priv->next_tx = 0;
>  
>  	mac_l = 0x3344;
> @@ -516,11 +656,9 @@ static int ag71xx_probe(struct device_d *dev)
>  }
>  
>  static __maybe_unused struct of_device_id ag71xx_dt_ids[] = {
> -	{
> -		.compatible = "qca,ar7100-gmac",
> -	}, {
> -		/* sentinel */
> -	}
> +	{ .compatible = "qca,ar9331-ge0", .data = &ag71xx_cfg_ar9331_ge0, },
> +	{ .compatible = "qca,ar9344-gmac0", .data = &ag71xx_cfg_ar9344_gmac0, },

Why do you remove the original compatible string here?

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



More information about the barebox mailing list