[PATCH v2 05/13] net: ath79: add ag71xx Ethernet driver
Peter Mamonov
pmamonov at gmail.com
Mon Aug 7 13:45:05 PDT 2017
On Mon, Aug 07, 2017 at 04:39:19PM +0200, Oleksij Rempel wrote:
> From: Yegor Yefremov <yegorslists at googlemail.com>
>
> Signed-off-by: Yegor Yefremov <yegorslists at googlemail.com>
> Signed-off-by: Antony Pavlov <antonynpavlov at gmail.com>
> ---
> Documentation/boards/mips/tplink-mr3020.rst | 7 +
> arch/mips/mach-ath79/include/mach/ar71xx_regs.h | 12 +
> drivers/net/Kconfig | 7 +
> drivers/net/Makefile | 1 +
> drivers/net/ag71xx.c | 530 ++++++++++++++++++++++++
> 5 files changed, 557 insertions(+)
> create mode 100644 drivers/net/ag71xx.c
>
> diff --git a/Documentation/boards/mips/tplink-mr3020.rst b/Documentation/boards/mips/tplink-mr3020.rst
> index 99101c337..4119c1e7e 100644
> --- a/Documentation/boards/mips/tplink-mr3020.rst
> +++ b/Documentation/boards/mips/tplink-mr3020.rst
> @@ -60,6 +60,13 @@ Next, setup network on MR3020 and run ``6F01A8C0.img``, e.g.:
> hornet> tftpboot 0x81000000 6F01A8C0.img
> hornet> bootm 0x81000000
>
> +WIP: Short form:
> + hornet> set ipaddr 192.168.0.2; set serverip 192.168.0.1
> + hornet> tftpboot 0x81000000 6F01A8C0.img; bootm 0x81000000
> +
> +u-boot_mod:
> + uboot> setenv ipaddr 192.168.1.12; setenv serverip 192.168.1.2
> + uboot> tftpboot 0x81000000 6F01A8C0.img; bootm 0x81000000
>
> Links
> -----
> diff --git a/arch/mips/mach-ath79/include/mach/ar71xx_regs.h b/arch/mips/mach-ath79/include/mach/ar71xx_regs.h
> index f56c3f724..31d33b3c4 100644
> --- a/arch/mips/mach-ath79/include/mach/ar71xx_regs.h
> +++ b/arch/mips/mach-ath79/include/mach/ar71xx_regs.h
> @@ -102,6 +102,8 @@
> #define AR933X_PLL_CLOCK_CTRL_REG 0x08
> #define AR933X_PLL_DITHER_FRAC_REG 0x10
> #define AR933X_PLL_DITHER_REG 0x14
> +#define AR933X_ETHSW_CLOCK_CONTROL_REG 0x24
> +#define AR933X_ETH_XMII_CONTROL_REG 0x2c
>
> #define AR933X_PLL_CPU_CONFIG_NINT_SHIFT 10
> #define AR933X_PLL_CPU_CONFIG_NINT_MASK 0x3f
> @@ -125,6 +127,16 @@
> #define AR933X_RESET_REG_RESET_MODULE 0x1c
> #define AR933X_RESET_REG_BOOTSTRAP 0xac
>
> +#define AR933X_RESET_GE1_MDIO BIT(23)
> +#define AR933X_RESET_GE0_MDIO BIT(22)
> +#define AR933X_RESET_GE1_MAC BIT(13)
> +#define AR933X_RESET_WMAC BIT(11)
> +#define AR933X_RESET_GE0_MAC BIT(9)
> +#define AR933X_RESET_SWITCH BIT(8)
> +#define AR933X_RESET_USB_HOST BIT(5)
> +#define AR933X_RESET_USB_PHY BIT(4)
> +#define AR933X_RESET_USBSUS_OVERRIDE BIT(3)
> +
> #define AR71XX_RESET_FULL_CHIP BIT(24)
>
> #define AR933X_BOOTSTRAP_REF_CLK_40 BIT(0)
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index c3980e78f..9d69b6aeb 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -204,6 +204,13 @@ config DRIVER_NET_EFI_SNP
> bool "EFI SNP ethernet driver"
> depends on EFI_BOOTUP
>
> +config DRIVER_NET_AG71XX
> + bool "Atheros AG71xx ethernet driver"
> + depends on MACH_MIPS_ATH79
> + select PHYLIB
> + help
> + This option enables support for Atheros AG71XX ethernet chip.
> +
> config DRIVER_NET_TSE
> depends on NIOS2
> bool "Altera TSE ethernet driver"
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 42ea208e3..86c8ac32f 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -30,3 +30,4 @@ obj-$(CONFIG_DRIVER_NET_SMC91111) += smc91111.o
> obj-$(CONFIG_DRIVER_NET_TAP) += tap.o
> obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o
> obj-$(CONFIG_DRIVER_NET_EFI_SNP) += efi-snp.o
> +obj-$(CONFIG_DRIVER_NET_AG71XX) += ag71xx.o
> diff --git a/drivers/net/ag71xx.c b/drivers/net/ag71xx.c
> new file mode 100644
> index 000000000..b2e066be3
> --- /dev/null
> +++ b/drivers/net/ag71xx.c
> @@ -0,0 +1,530 @@
> +/*
> + * Atheros AR71xx built-in ethernet mac driver
> + *
> + * Copyright (C) 2008-2010 Gabor Juhos <juhosg at openwrt.org>
> + * Copyright (C) 2008 Imre Kaloz <kaloz at openwrt.org>
> + *
> + * Based on Atheros' AG7100 driver
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> + * by the Free Software Foundation.
> + */
> +
> +#include <common.h>
> +#include <net.h>
> +#include <dma.h>
> +#include <init.h>
> +#include <io.h>
> +#include <linux/err.h>
> +#include <linux/phy.h>
> +#include <of_net.h>
> +#include <of_address.h>
> +
> +#include <mach/ath79.h>
> +
> +/* Register offsets */
> +#define AG71XX_REG_MAC_CFG1 0x0000
> +#define AG71XX_REG_MAC_CFG2 0x0004
> +#define AG71XX_REG_MAC_IPG 0x0008
> +#define AG71XX_REG_MAC_HDX 0x000c
> +#define AG71XX_REG_MAC_MFL 0x0010
> +#define AG71XX_REG_MII_CFG 0x0020
> +#define AG71XX_REG_MII_CMD 0x0024
> +#define AG71XX_REG_MII_ADDR 0x0028
> +#define AG71XX_REG_MII_CTRL 0x002c
> +#define AG71XX_REG_MII_STATUS 0x0030
> +#define AG71XX_REG_MII_IND 0x0034
> +#define AG71XX_REG_MAC_IFCTL 0x0038
> +#define AG71XX_REG_MAC_ADDR1 0x0040
> +#define AG71XX_REG_MAC_ADDR2 0x0044
> +#define AG71XX_REG_FIFO_CFG0 0x0048
> +#define AG71XX_REG_FIFO_CFG1 0x004c
> +#define AG71XX_REG_FIFO_CFG2 0x0050
> +#define AG71XX_REG_FIFO_CFG3 0x0054
> +#define AG71XX_REG_FIFO_CFG4 0x0058
> +#define AG71XX_REG_FIFO_CFG5 0x005c
> +#define AG71XX_REG_FIFO_RAM0 0x0060
> +#define AG71XX_REG_FIFO_RAM1 0x0064
> +#define AG71XX_REG_FIFO_RAM2 0x0068
> +#define AG71XX_REG_FIFO_RAM3 0x006c
> +#define AG71XX_REG_FIFO_RAM4 0x0070
> +#define AG71XX_REG_FIFO_RAM5 0x0074
> +#define AG71XX_REG_FIFO_RAM6 0x0078
> +#define AG71XX_REG_FIFO_RAM7 0x007c
> +
> +#define AG71XX_REG_TX_CTRL 0x0180
> +#define AG71XX_REG_TX_DESC 0x0184
> +#define AG71XX_REG_TX_STATUS 0x0188
> +#define AG71XX_REG_RX_CTRL 0x018c
> +#define AG71XX_REG_RX_DESC 0x0190
> +#define AG71XX_REG_RX_STATUS 0x0194
> +#define AG71XX_REG_INT_ENABLE 0x0198
> +#define AG71XX_REG_INT_STATUS 0x019c
> +
> +#define AG71XX_REG_FIFO_DEPTH 0x01a8
> +#define AG71XX_REG_RX_SM 0x01b0
> +#define AG71XX_REG_TX_SM 0x01b4
> +
> +#define MAC_CFG1_TXE BIT(0) /* Tx Enable */
> +#define MAC_CFG1_STX BIT(1) /* Synchronize Tx Enable */
> +#define MAC_CFG1_RXE BIT(2) /* Rx Enable */
> +#define MAC_CFG1_SRX BIT(3) /* Synchronize Rx Enable */
> +#define MAC_CFG1_TFC BIT(4) /* Tx Flow Control Enable */
> +#define MAC_CFG1_RFC BIT(5) /* Rx Flow Control Enable */
> +#define MAC_CFG1_LB BIT(8) /* Loopback mode */
> +#define MAC_CFG1_TX_RST BIT(18) /* Tx Reset */
> +#define MAC_CFG1_RX_RST BIT(19) /* Rx Reset */
> +#define MAC_CFG1_SR BIT(31) /* Soft Reset */
> +
> +#define MAC_CFG2_FDX BIT(0)
> +#define MAC_CFG2_CRC_EN BIT(1)
> +#define MAC_CFG2_PAD_CRC_EN BIT(2)
> +#define MAC_CFG2_LEN_CHECK BIT(4)
> +#define MAC_CFG2_HUGE_FRAME_EN BIT(5)
> +#define MAC_CFG2_IF_1000 BIT(9)
> +#define MAC_CFG2_IF_10_100 BIT(8)
> +
> +#define FIFO_CFG0_WTM BIT(0) /* Watermark Module */
> +#define FIFO_CFG0_RXS BIT(1) /* Rx System Module */
> +#define FIFO_CFG0_RXF BIT(2) /* Rx Fabric Module */
> +#define FIFO_CFG0_TXS BIT(3) /* Tx System Module */
> +#define FIFO_CFG0_TXF BIT(4) /* Tx Fabric Module */
> +#define FIFO_CFG0_ALL (FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \
> + | FIFO_CFG0_TXS | FIFO_CFG0_TXF)
> +
> +#define FIFO_CFG0_ENABLE_SHIFT 8
> +
> +#define FIFO_CFG4_DE BIT(0) /* Drop Event */
> +#define FIFO_CFG4_DV BIT(1) /* RX_DV Event */
> +#define FIFO_CFG4_FC BIT(2) /* False Carrier */
> +#define FIFO_CFG4_CE BIT(3) /* Code Error */
> +#define FIFO_CFG4_CR BIT(4) /* CRC error */
> +#define FIFO_CFG4_LM BIT(5) /* Length Mismatch */
> +#define FIFO_CFG4_LO BIT(6) /* Length out of range */
> +#define FIFO_CFG4_OK BIT(7) /* Packet is OK */
> +#define FIFO_CFG4_MC BIT(8) /* Multicast Packet */
> +#define FIFO_CFG4_BC BIT(9) /* Broadcast Packet */
> +#define FIFO_CFG4_DR BIT(10) /* Dribble */
> +#define FIFO_CFG4_LE BIT(11) /* Long Event */
> +#define FIFO_CFG4_CF BIT(12) /* Control Frame */
> +#define FIFO_CFG4_PF BIT(13) /* Pause Frame */
> +#define FIFO_CFG4_UO BIT(14) /* Unsupported Opcode */
> +#define FIFO_CFG4_VT BIT(15) /* VLAN tag detected */
> +#define FIFO_CFG4_FT BIT(16) /* Frame Truncated */
> +#define FIFO_CFG4_UC BIT(17) /* Unicast Packet */
> +
> +#define FIFO_CFG5_DE BIT(0) /* Drop Event */
> +#define FIFO_CFG5_DV BIT(1) /* RX_DV Event */
> +#define FIFO_CFG5_FC BIT(2) /* False Carrier */
> +#define FIFO_CFG5_CE BIT(3) /* Code Error */
> +#define FIFO_CFG5_LM BIT(4) /* Length Mismatch */
> +#define FIFO_CFG5_LO BIT(5) /* Length Out of Range */
> +#define FIFO_CFG5_OK BIT(6) /* Packet is OK */
> +#define FIFO_CFG5_MC BIT(7) /* Multicast Packet */
> +#define FIFO_CFG5_BC BIT(8) /* Broadcast Packet */
> +#define FIFO_CFG5_DR BIT(9) /* Dribble */
> +#define FIFO_CFG5_CF BIT(10) /* Control Frame */
> +#define FIFO_CFG5_PF BIT(11) /* Pause Frame */
> +#define FIFO_CFG5_UO BIT(12) /* Unsupported Opcode */
> +#define FIFO_CFG5_VT BIT(13) /* VLAN tag detected */
> +#define FIFO_CFG5_LE BIT(14) /* Long Event */
> +#define FIFO_CFG5_FT BIT(15) /* Frame Truncated */
> +#define FIFO_CFG5_16 BIT(16) /* unknown */
> +#define FIFO_CFG5_17 BIT(17) /* unknown */
> +#define FIFO_CFG5_SF BIT(18) /* Short Frame */
> +#define FIFO_CFG5_BM BIT(19) /* Byte Mode */
> +
> +#define AG71XX_INT_TX_PS BIT(0)
> +#define AG71XX_INT_TX_UR BIT(1)
> +#define AG71XX_INT_TX_BE BIT(3)
> +#define AG71XX_INT_RX_PR BIT(4)
> +#define AG71XX_INT_RX_OF BIT(6)
> +#define AG71XX_INT_RX_BE BIT(7)
> +
> +#define MAC_IFCTL_SPEED BIT(16)
> +
> +#define MII_CFG_CLK_DIV_4 0
> +#define MII_CFG_CLK_DIV_6 2
> +#define MII_CFG_CLK_DIV_8 3
> +#define MII_CFG_CLK_DIV_10 4
> +#define MII_CFG_CLK_DIV_14 5
> +#define MII_CFG_CLK_DIV_20 6
> +#define MII_CFG_CLK_DIV_28 7
> +#define MII_CFG_CLK_DIV_34 8
> +#define MII_CFG_CLK_DIV_42 9
> +#define MII_CFG_CLK_DIV_50 10
> +#define MII_CFG_CLK_DIV_58 11
> +#define MII_CFG_CLK_DIV_66 12
> +#define MII_CFG_CLK_DIV_74 13
> +#define MII_CFG_CLK_DIV_82 14
> +#define MII_CFG_CLK_DIV_98 15
> +#define MII_CFG_RESET BIT(31)
> +
> +#define MII_CMD_WRITE 0x0
> +#define MII_CMD_READ 0x1
> +#define MII_ADDR_SHIFT 8
> +#define MII_IND_BUSY BIT(0)
> +#define MII_IND_INVALID BIT(2)
> +
> +#define TX_CTRL_TXE BIT(0) /* Tx Enable */
> +
> +#define TX_STATUS_PS BIT(0) /* Packet Sent */
> +#define TX_STATUS_UR BIT(1) /* Tx Underrun */
> +#define TX_STATUS_BE BIT(3) /* Bus Error */
> +
> +#define RX_CTRL_RXE BIT(0) /* Rx Enable */
> +
> +#define RX_STATUS_PR BIT(0) /* Packet Received */
> +#define RX_STATUS_OF BIT(2) /* Rx Overflow */
> +#define RX_STATUS_BE BIT(3) /* Bus Error */
> +
> +/*
> + * GMAC register macros
> + */
> +#define AG71XX_ETH_CFG_RGMII_GE0 (1<<0)
> +#define AG71XX_ETH_CFG_MII_GE0_SLAVE (1<<4)
> +
> +/*
> + * h/w descriptor
> + */
> +typedef struct {
> + uint32_t pkt_start_addr;
> +
> + uint32_t is_empty : 1;
> + uint32_t res1 : 10;
> + uint32_t ftpp_override : 5;
> + uint32_t res2 : 4;
> + uint32_t pkt_size : 12;
> +
> + uint32_t next_desc ;
> +} ag7240_desc_t;
> +
> +#define NO_OF_TX_FIFOS 8
> +#define NO_OF_RX_FIFOS 8
> +#define TX_RING_SZ (NO_OF_TX_FIFOS * sizeof(ag7240_desc_t))
> +#define MAX_RBUFF_SZ 0x600 /* 1518 rounded up */
> +
> +#define MAX_WAIT 1000
> +
> +struct ag71xx {
> + struct device_d *dev;
> + struct eth_device netdev;
> + void __iomem *regs;
> + void __iomem *regs_gmac;
> + struct mii_bus miibus;
> +
> + void *rx_buffer;
> +
> + unsigned char *rx_pkt[NO_OF_RX_FIFOS];
> + ag7240_desc_t *fifo_tx;
> + ag7240_desc_t *fifo_rx;
> +
> + int next_tx;
> + int next_rx;
> +};
> +
> +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:
> + break;
> +
> + default:
> + BUG();
> + }
> +}
> +
> +static inline u32 ag71xx_gmac_rr(struct ag71xx *dev, int reg)
> +{
> + return __raw_readl(dev->regs_gmac + reg);
> +}
> +
> +static inline void ag71xx_gmac_wr(struct ag71xx *dev, int reg, u32 val)
> +{
> + __raw_writel(val, dev->regs_gmac + reg);
> +}
> +
> +static inline u32 ag71xx_rr(struct ag71xx *priv, int reg)
> +{
> + ag71xx_check_reg_offset(priv, reg);
> +
> + return __raw_readl(priv->regs + reg);
> +}
> +
> +static inline void ag71xx_wr(struct ag71xx *priv, int reg, u32 val)
> +{
> + ag71xx_check_reg_offset(priv, reg);
> +
> + __raw_writel(val, priv->regs + reg);
> + /* flush write */
> + (void)__raw_readl(priv->regs + reg);
> +}
> +
> +static int ag71xx_ether_mii_read(struct mii_bus *miidev, int addr, int reg)
> +{
> + return 0xffff;
> +}
> +
> +static int ag71xx_ether_mii_write(struct mii_bus *miidev, int addr, int reg, u16 val)
> +{
> + return 0;
> +}
> +
> +static int ag71xx_ether_set_ethaddr(struct eth_device *edev, const unsigned char *adr)
> +{
> + return 0;
> +}
> +
> +static int ag71xx_ether_get_ethaddr(struct eth_device *edev, unsigned char *adr)
> +{
> + /* We have no eeprom */
> + return -1;
> +}
> +
> +static void ag71xx_ether_halt(struct eth_device *edev)
> +{
> + struct ag71xx *priv = edev->priv;
> +
> + ag71xx_wr(priv, AG71XX_REG_RX_CTRL, 0);
> + while (ag71xx_rr(priv, AG71XX_REG_RX_CTRL))
> + ;
> +}
> +
> +static int ag71xx_ether_rx(struct eth_device *edev)
> +{
> + struct ag71xx *priv = edev->priv;
> + ag7240_desc_t *f;
> + unsigned int work_done;
> +
> + for (work_done = 0; work_done < NO_OF_RX_FIFOS; work_done++) {
> + unsigned int pktlen;
> + unsigned char *rx_pkt;
> +
> + f = &priv->fifo_rx[priv->next_rx];
> +
> + if (f->is_empty)
> + break;
> +
> + pktlen = f->pkt_size;
> + rx_pkt = priv->rx_pkt[priv->next_rx];
> +
> + /* invalidate */
> + dma_sync_single_for_cpu((unsigned long)rx_pkt, pktlen,
> + DMA_FROM_DEVICE);
> +
> + net_receive(edev, rx_pkt, pktlen - 4);
> +
> + f->is_empty = 1;
> +
> + priv->next_rx = (priv->next_rx + 1) % NO_OF_RX_FIFOS;
> + }
> +
> + if (!(ag71xx_rr(priv, AG71XX_REG_RX_CTRL) & RX_CTRL_RXE)) {
> + f = &priv->fifo_rx[priv->next_rx];
> + ag71xx_wr(priv, AG71XX_REG_RX_DESC, virt_to_phys(f));
> + ag71xx_wr(priv, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
> + }
> +
> + return work_done;
> +}
> +
> +static int ag71xx_ether_send(struct eth_device *edev, void *packet, int length)
> +{
> + struct ag71xx *priv = edev->priv;
> + struct device_d *dev = priv->dev;
> + ag7240_desc_t *f = &priv->fifo_tx[priv->next_tx];
> + int i;
> +
> + /* flush */
> + dma_sync_single_for_device((unsigned long)packet, length, DMA_TO_DEVICE);
> +
> + f->pkt_start_addr = virt_to_phys(packet);
A couple of remarks regarding this code:
Despite the fact that this code should work fine, it violates the Linux DMA
API, which the Barebox tends to conform to. The problem is that the Barebox is
missing dma_map_*() functions, which should be used instead of virt_to_phys()
here.
Another DMA-related Barebox issue is the type of the first argument to
dma_sync_*() functions, which should be dma_addr_t (just like the return value
of dma_map_*() functions), instead of unsigned long. This is of no importance
for 32 bit architectures, however it will break for 64 bit targets.
> + f->res1 = 0;
> + f->pkt_size = length;
> + f->is_empty = 0;
> + ag71xx_wr(priv, AG71XX_REG_TX_DESC, virt_to_phys(f));
> + ag71xx_wr(priv, AG71XX_REG_TX_CTRL, TX_CTRL_TXE);
> +
> + /* flush again?! */
> + dma_sync_single_for_cpu((unsigned long)packet, length, DMA_TO_DEVICE);
> +
> + for (i = 0; i < MAX_WAIT; i++) {
> + udelay(100);
> + if (f->is_empty) {
> + break;
> + }
> + }
> +
> + if (i == MAX_WAIT) {
> + dev_err(dev, "Tx Timed out\n");
> + }
> +
> + f->pkt_start_addr = 0;
> + f->pkt_size = 0;
> +
> + priv->next_tx = (priv->next_tx + 1) % NO_OF_TX_FIFOS;
> +
> + return 0;
> +}
> +
> +static int ag71xx_ether_open(struct eth_device *edev)
> +{
> + return 0;
> +}
> +
> +static int ag71xx_ether_init(struct eth_device *edev)
> +{
> + struct ag71xx *priv = edev->priv;
> + int i;
> + void *rxbuf = priv->rx_buffer;
> +
> + priv->next_rx = 0;
> +
> + for (i = 0; i < NO_OF_RX_FIFOS; i++) {
> + ag7240_desc_t *fr = &priv->fifo_rx[i];
> +
> + priv->rx_pkt[i] = rxbuf;
> + fr->pkt_start_addr = virt_to_phys(rxbuf);
> + fr->pkt_size = MAX_RBUFF_SZ;
> + fr->is_empty = 1;
> + fr->next_desc = virt_to_phys(&priv->fifo_rx[(i + 1) % NO_OF_RX_FIFOS]);
> +
> + /* invalidate */
> + dma_sync_single_for_device((unsigned long)rxbuf, MAX_RBUFF_SZ,
> + DMA_FROM_DEVICE);
> +
> + rxbuf += MAX_RBUFF_SZ;
> + }
> +
> + /* Clean Tx BD's */
> + memset(priv->fifo_tx, 0, TX_RING_SZ);
> +
> + ag71xx_wr(priv, AG71XX_REG_RX_DESC, virt_to_phys(priv->fifo_rx));
> + ag71xx_wr(priv, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
> +
> + return 1;
> +}
> +
> +static int ag71xx_mii_setup(struct ag71xx *priv)
> +{
> + u32 rd;
> +
> + rd = ag71xx_gmac_rr(priv, 0);
> + rd |= AG71XX_ETH_CFG_MII_GE0_SLAVE;
> + ag71xx_gmac_wr(priv, 0, rd);
> +
> + return 0;
> +}
> +
> +static int ag71xx_probe(struct device_d *dev)
> +{
> + void __iomem *regs, *regs_gmac;
> + struct mii_bus *miibus;
> + struct eth_device *edev;
> + struct ag71xx *priv;
> + u32 mac_h, mac_l;
> + u32 rd;
> +
> + regs_gmac = dev_request_mem_region_by_name(dev, "gmac");
> + if (IS_ERR(regs_gmac))
> + return PTR_ERR(regs_gmac);
> +
> + regs = dev_request_mem_region_by_name(dev, "ge0");
> + if (IS_ERR(regs))
> + return PTR_ERR(regs);
> +
> + priv = xzalloc(sizeof(struct ag71xx));
> + edev = &priv->netdev;
> + miibus = &priv->miibus;
> + edev->priv = priv;
> +
> + edev->init = ag71xx_ether_init;
> + edev->open = ag71xx_ether_open;
> + edev->send = ag71xx_ether_send;
> + edev->recv = ag71xx_ether_rx;
> + edev->halt = ag71xx_ether_halt;
> + edev->get_ethaddr = ag71xx_ether_get_ethaddr;
> + edev->set_ethaddr = ag71xx_ether_set_ethaddr;
> +
> + priv->dev = dev;
> + priv->regs = regs;
> + priv->regs_gmac = regs_gmac;
> +
> + 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 |= 0x10;
> + __raw_writel(rd, (char *)KSEG1ADDR(AR71XX_PLL_BASE + AR933X_ETHSW_CLOCK_CONTROL_REG));
> +
> + if (ath79_reset_rr(AR933X_RESET_REG_RESET_MODULE) != 0)
> + ath79_reset_wr(AR933X_RESET_REG_RESET_MODULE, 0);
> +
> + /* reset GE0 MAC and MDIO */
> + rd = ath79_reset_rr(AR933X_RESET_REG_RESET_MODULE);
> + rd |= AR933X_RESET_GE0_MAC | AR933X_RESET_GE0_MDIO | AR933X_RESET_SWITCH;
> + 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);
> + 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);
> +
> + ag71xx_wr(priv, AG71XX_REG_FIFO_CFG1, 0x10ffff);
> + ag71xx_wr(priv, AG71XX_REG_FIFO_CFG2, 0xAAA0555);
> +
> + ag71xx_wr(priv, AG71XX_REG_FIFO_CFG4, 0x3ffff);
> + ag71xx_wr(priv, AG71XX_REG_FIFO_CFG5, 0x66b82);
> + 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->next_tx = 0;
> +
> + mac_l = 0x3344;
> + mac_h = 0x0004d980;
> +
> + ag71xx_wr(priv, AG71XX_REG_MAC_ADDR1, mac_l);
> + ag71xx_wr(priv, AG71XX_REG_MAC_ADDR2, mac_h);
> +
> + mdiobus_register(miibus);
> + eth_register(edev);
> +
> + dev_info(dev, "network device registered\n");
> +
> + return 0;
> +}
> +
> +static __maybe_unused struct of_device_id ag71xx_dt_ids[] = {
> + {
> + .compatible = "qca,ar7100-gmac",
> + }, {
> + /* sentinel */
> + }
> +};
> +
> +static struct driver_d ag71xx_driver = {
> + .name = "ag71xx-gmac",
> + .probe = ag71xx_probe,
> + .of_compatible = DRV_OF_COMPAT(ag71xx_dt_ids),
> +};
> +device_platform_driver(ag71xx_driver);
> --
> 2.11.0
>
>
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
More information about the barebox
mailing list