[U-Boot] [PATCH RFC 7/7] NET: AR934x: Ethernet drivers for SoC AR934x

Nikolaos Pasaloukos Nikolaos.Pasaloukos at imgtec.com
Fri Nov 29 10:48:08 CET 2013


Add Ethernet support for AR934x SoC. Since it uses Atheros generic phy
support, only one Ethernet port is being set up.

Signed-off-by: Nikolaos Pasaloukos <Nikolaos.Pasaloukos at imgtec.com>
Cc: Joe Hershberger <joe.hershberger at gmail.com>
---
 drivers/net/Makefile |   1 +
 drivers/net/ar934x.c | 572 +++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ar934x.h | 202 ++++++++++++++++++
 include/netdev.h     |   1 +
 4 files changed, 776 insertions(+)
 create mode 100644 drivers/net/ar934x.c
 create mode 100644 drivers/net/ar934x.h

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 7f9ce90..3e8887b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -7,6 +7,7 @@
 
 obj-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o
 obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
+obj-$(CONFIG_AR934X_ETH) += ar934x.o
 obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
 obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
diff --git a/drivers/net/ar934x.c b/drivers/net/ar934x.c
new file mode 100644
index 0000000..ce7fd56
--- /dev/null
+++ b/drivers/net/ar934x.c
@@ -0,0 +1,572 @@
+/*
+ *  Copyright (C) 2013 Imagination Technologies
+ *
+ *  Derived from works by OpenWRT
+ *
+ *  SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <pci.h>
+#include <phy.h>
+#include <miiphy.h>
+#include <asm/ar7240_addrspace.h>
+#include "ar934x.h"
+
+static struct ar934x_mac ar934x_macs[CONFIG_AR934x_NMACS];
+
+static u32 ioaddr;
+
+const struct {
+	const char *name;
+	u16 version;
+	u32 mask;	/* should clear the bits supported by this chip */
+} ath_chip_info[] = {
+	{"AR7240", 0x00c0, 0x00003300,},
+	{"AR7241", 0x0100, 0x00c03300,},
+	{"AR7242", 0x1100, 0x00c03300,},
+	{"AR9330", 0x0110, 0x00003300,},
+	{"AR9331", 0x1110, 0x00003300,},
+	{"AR9341", 0x0120, 0x00c03300,},
+	{"AR9342", 0x1120, 0x00c03300,},
+	{"AR9344", 0x2120, 0x00c03300,},
+};
+
+const struct pci_device_id supported[] = {
+	{PCI_VENDOR_ID_ATHEROS, 0xa02a},
+	{0, 0}
+};
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+uint16_t ar9344_mdio_read(char *devname, uint32_t phy_addr, uint8_t reg)
+{
+	uint16_t addr  = (phy_addr << AR934x_ADDR_SHIFT) | reg, val;
+	int rddata;
+	uint16_t ii = 0xFFFF;
+	ioaddr = ar_name2mac(devname);
+
+	/*
+	 * Check for previous transactions are complete. Added to avoid
+	 * race condition while running at higher frequencies.
+	 */
+	do {
+		udelay(5);
+		rddata = ATHRS_REG_R32(AR934x_MII_MGMT_IND) & 0x1;
+	} while (rddata && --ii);
+
+	if (ii == 0)
+		printf("ERROR:%s:%d transaction failed\n", __func__, __LINE__);
+
+	ATHRS_REG_W32(AR934x_MII_MGMT_CMD, 0x0);
+	ATHRS_REG_W32(AR934x_MII_MGMT_ADDRESS, addr);
+	ATHRS_REG_W32(AR934x_MII_MGMT_CMD, AR934x_MGMT_CMD_READ);
+
+	do {
+		udelay(5);
+		rddata = ATHRS_REG_R32(AR934x_MII_MGMT_IND) & 0x1;
+	} while (rddata && --ii);
+
+	if (ii == 0)
+		printf("Error!!! mdio_read polling has no correct status!\n");
+
+	val = ATHRS_REG_R32(AR934x_MII_MGMT_STATUS);
+	ATHRS_REG_W32(AR934x_MII_MGMT_CMD, 0x0);
+
+	return val;
+}
+
+void ar9344_mdio_write(char *devname, uint32_t phy_addr, uint8_t reg,
+		       uint16_t data)
+{
+	uint16_t addr  = (phy_addr << AR934x_ADDR_SHIFT) | reg;
+	int rddata;
+	uint16_t ii = 0xFFFF;
+	ioaddr = ar_name2mac(devname);
+
+	/*
+	 * Check for previous transactions are complete. Added to avoid
+	 * race condition while running at higher frequencies.
+	 */
+	do {
+		udelay(5);
+		rddata = ATHRS_REG_R32(AR934x_MII_MGMT_IND) & 0x1;
+	} while (rddata && --ii);
+
+	if (ii == 0)
+		printf("ERROR:%s:%d transaction failed\n", __func__, __LINE__);
+
+	ATHRS_REG_W32(AR934x_MII_MGMT_ADDRESS, addr);
+	ATHRS_REG_W32(AR934x_MII_MGMT_CTRL, data);
+
+	do {
+		rddata = ATHRS_REG_R32(AR934x_MII_MGMT_IND) & 0x1;
+	} while (rddata && --ii);
+
+	if (ii == 0)
+		printf("Error!!! mdio_write polling has no correct status!\n");
+}
+#endif		/* defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
+
+#if defined(CONFIG_PHYLIB)
+int ar9344_miiphy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
+		       int reg_addr)
+{
+	uint16_t ret;
+	uint32_t addr;
+
+	addr = (dev_addr == 0xffffffff) ? 0x00000001 : dev_addr;
+
+	ret = ar9344_mdio_read(bus->name, addr, reg_addr);
+
+	return ret;
+}
+
+int ar9344_miiphy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
+		       int reg_addr, uint16_t data)
+{
+	uint32_t addr;
+
+	addr = (dev_addr == 0xffffffff) ? 0x00000001 : dev_addr;
+
+	ar9344_mdio_write(bus->name, addr, reg_addr, data);
+
+	return 0;
+}
+#endif		/* defined(CONFIG_PHYLIB) */
+
+static void ar934x_get_ethaddr(struct eth_device *dev)
+{
+	if (!eth_getenv_enetaddr("ethaddr", dev->enetaddr)) {
+		/* Use random address if the above address is invalid */
+		if (!is_valid_ether_addr(dev->enetaddr)) {
+#ifdef CONFIG_RANDOM_MACADDR
+			eth_random_enetaddr(dev->enetaddr);
+			debug("Using random MAC address\n");
+#else
+			printf("WARNING: No valid MAC address!");
+#endif
+		}
+	}
+	printf("%s MAC is: %pM\n", dev->name, dev->enetaddr);
+}
+
+static int ar934x_send(struct eth_device *dev, void *packet, int length)
+{
+	int i;
+
+	struct ar934x_mac *mac = (struct ar934x_mac *)dev->priv;
+	struct ar934x_desc *f = mac->fifo_tx[mac->next_tx];
+	ioaddr = mac->mac_base;
+
+	f->pkt_size = length;
+	f->res1 = 0;
+	f->pkt_start_addr = virt_to_phys(packet);
+
+	ar7240_tx_give_to_dma(f);
+	flush_cache((u32) packet, length);
+	ATHRS_REG_W32(AR934x_DMA_TX_DESC, virt_to_phys(f));
+	ATHRS_REG_W32(AR934x_DMA_TX_CTRL, AR934x_TXE);
+
+	for (i = 0; i < MAX_WAIT; i++) {
+		udelay(10);
+		if (!ar7240_tx_owned_by_dma(f))
+			break;
+	}
+	if (i == MAX_WAIT)
+		printf("Tx Timed out\n");
+
+	f->pkt_start_addr = 0;
+	f->pkt_size = 0;
+
+	if (++mac->next_tx >= NO_OF_TX_FIFOS)
+		mac->next_tx = 0;
+
+	return 0;
+}
+
+static int ar934x_recv(struct eth_device *dev)
+{
+	int length;
+	struct ar934x_desc *f;
+	struct ar934x_mac *mac;
+
+	mac = (struct ar934x_mac *)dev->priv;
+	ioaddr = mac->mac_base;
+
+	for (;;) {
+		f = mac->fifo_rx[mac->next_rx];
+		if (ar7240_rx_owned_by_dma(f))
+			break;
+
+		length = f->pkt_size;
+
+		NetReceive(NetRxPackets[mac->next_rx], length-4);
+		flush_cache((u32)NetRxPackets[mac->next_rx], PKTSIZE_ALIGN);
+
+		ar7240_rx_give_to_dma(f);
+
+		if (++mac->next_rx >= NO_OF_RX_FIFOS)
+			mac->next_rx = 0;
+	}
+
+	if (!(ATHRS_REG_R32(AR934x_DMA_RX_CTRL))) {
+		ATHRS_REG_W32(AR934x_DMA_RX_DESC, virt_to_phys(f));
+		ATHRS_REG_W32(AR934x_DMA_RX_CTRL, 1);
+	}
+
+	return 0;
+}
+
+static int ar934x_alloc_fifo(int ndesc, struct ar934x_desc **fifo)
+{
+	int i;
+	u32 size;
+	uchar *p = NULL;
+
+	size = sizeof(struct ar934x_desc) * ndesc;
+	size += CONFIG_SYS_CACHELINE_SIZE - 1;
+
+	p = malloc(size);
+	if (p == NULL) {
+		printf("Cant allocate fifos\n");
+		return -1;
+	}
+
+	p = (uchar *)(((u32) p + CONFIG_SYS_CACHELINE_SIZE - 1) &
+		     ~(CONFIG_SYS_CACHELINE_SIZE - 1));
+	p = (uchar *)UNCACHED_SDRAM(p);
+
+	for (i = 0; i < ndesc; i++)
+		fifo[i] = (struct ar934x_desc *)p + i;
+
+	return 0;
+}
+
+static int ar934x_setup_fifos(struct ar934x_mac *mac)
+{
+	int i;
+
+	if (ar934x_alloc_fifo(NO_OF_TX_FIFOS, mac->fifo_tx))
+		return 1;
+
+	for (i = 0; i < NO_OF_TX_FIFOS; i++) {
+		mac->fifo_tx[i]->next_desc = (i == NO_OF_TX_FIFOS - 1) ?
+					     virt_to_phys(mac->fifo_tx[0]) :
+					     virt_to_phys(mac->fifo_tx[i + 1]);
+		ar7240_tx_own(mac->fifo_tx[i]);
+	}
+
+	if (ar934x_alloc_fifo(NO_OF_RX_FIFOS, mac->fifo_rx))
+		return 1;
+
+	for (i = 0; i < NO_OF_RX_FIFOS; i++) {
+		mac->fifo_rx[i]->next_desc = (i == NO_OF_RX_FIFOS - 1) ?
+					     virt_to_phys(mac->fifo_rx[0]) :
+					     virt_to_phys(mac->fifo_rx[i + 1]);
+	}
+
+	return 1;
+}
+
+static void ar934x_set_rx_mode(struct eth_device *dev)
+{
+	u32 mgmt_cfg_val;
+	struct ar934x_mac *mac = (struct ar934x_mac *)dev->priv;
+	ioaddr = mac->mac_base;
+
+	if ((ar_reg_rd(&ar7240_rst2->bootstrap) & WASP_REF_CLK_25) == 0)
+		ar_reg_wr(&ar7240_pll->switch_clk_spare, 0x271);
+	else
+		ar_reg_wr(&ar7240_pll->switch_clk_spare, 0x570);
+
+	if (is_ar934x(&ar7240_rst2) && dev->index == 0) {
+		debug("WASP  ----> S17 PHY *\n");
+		mgmt_cfg_val = 4;
+		if (dev->index == 0)
+			ar_reg_wr(AR7240_ETH_CFG, AR7240_ETH_CFG_RGMII_GE0);
+
+		udelay(1000);
+
+		ATHRS_REG_W32(AR934x_MAC_MII_MGMT_CFG,
+			      mgmt_cfg_val | (1 << 31));
+		ATHRS_REG_W32(AR934x_MAC_MII_MGMT_CFG, mgmt_cfg_val);
+	}
+}
+
+static void ar934x_hw_start(struct eth_device *dev)
+{
+	struct ar934x_mac *mac = (struct ar934x_mac *)dev->priv;
+	ioaddr = mac->mac_base;
+
+	if (dev->index) {
+		ATHRS_REG_W32(AR934x_MAC_CFG1, (AR934x_MAC_CFG1_RX_EN |
+						AR934x_MAC_CFG1_TX_EN));
+		ar_mac_reg_set(AR934x_MAC_CFG2, (AR934x_MAC_CFG2_PAD_CRC_EN |
+						 AR934x_MAC_CFG2_LEN_CHECK |
+						 AR934x_MAC_CFG2_IF_1000));
+	} else {
+		ATHRS_REG_W32(AR934x_MAC_CFG1, (AR934x_MAC_CFG1_RX_EN |
+						AR934x_MAC_CFG1_TX_EN));
+		ar_mac_reg_set(AR934x_MAC_CFG2, (AR934x_MAC_CFG2_PAD_CRC_EN |
+						 AR934x_MAC_CFG2_LEN_CHECK |
+						 AR934x_MAC_CFG2_IF_10_100));
+	}
+	ATHRS_REG_W32(AR934x_MAC_FIFO_CFG_0, 0x1f00);
+
+	ar934x_set_rx_mode(dev);
+
+	ATHRS_REG_W32(AR934x_MAC_FIFO_CFG_1, 0x10ffff);
+	ATHRS_REG_W32(AR934x_MAC_FIFO_CFG_2, 0xAAA0555);
+
+	ar_mac_reg_set(AR934x_MAC_FIFO_CFG_4, 0x3ffff);
+
+	/*
+	 * Setting Drop CRC Errors, Pause Frames,Length Error frames
+	 * and Multi/Broad cast frames.
+	 */
+	ATHRS_REG_W32(AR934x_MAC_FIFO_CFG_5, 0x7eccf);
+
+	ATHRS_REG_W32(AR934x_MAC_FIFO_CFG_3, 0x1f00140);
+
+	debug(" : cfg1 %#x cfg2 %#x\n", ATHRS_REG_R32(AR934x_MAC_CFG1),
+	      ATHRS_REG_R32(AR934x_MAC_CFG2));
+}
+
+static int ar9344_init_board(struct eth_device *dev)
+{
+	int i;
+	u32 reg_val;
+
+	struct ar934x_mac *mac = (struct ar934x_mac *)dev->priv;
+	ioaddr = mac->mac_base;
+
+	reg_val = ATHRS_REG_R32(AR934x_MAC_CFG1);
+	ATHRS_REG_W32(AR934x_MAC_CFG1, reg_val | AR934x_MAC_CFG1_SOFT_RST |
+		      AR934x_MAC_CFG1_RX_RST | AR934x_MAC_CFG1_TX_RST);
+
+	reg_val = ar_reg_rd(&ar7240_rst2->rev_id) & AR9344_REV_ID_MASK;
+	for (i = ARRAY_SIZE(ath_chip_info) - 1; i >= 0; i--) {
+		if (reg_val == ath_chip_info[i].version) {
+			debug("wasp reset mask: %08x\n", ath_chip_info[i].mask);
+			ar_reg_rd_set(&ar7240_rst1->reset,
+				      ath_chip_info[i].mask);
+			udelay(100 * 1000);
+			ar_reg_rd_clr(&ar7240_rst1->reset,
+				      ath_chip_info[i].mask);
+			return 0;
+		}
+	}
+
+	/* if unknown chip, assume array element #0, original AR7240 */
+	printf("PCI device %s: unknown chip version, assuming AR7240\n",
+	       dev->name);
+	printf("PCI device: TxConfig = 0x%08X\n",
+	       ar_reg_rd(&ar7240_rst2->rev_id));
+
+	return 0;
+}
+
+/*
+ * HALT - Turn off ethernet interface
+ */
+static void ar934x_halt(struct eth_device *dev)
+{
+	struct ar934x_mac *mac = (struct ar934x_mac *)dev->priv;
+	ioaddr = mac->mac_base;
+
+	/* Stop the chip's Tx and Rx DMA processes. */
+	ATHRS_REG_W32(AR934x_DMA_RX_CTRL, 0x00);
+
+	while (ATHRS_REG_R32(AR934x_DMA_RX_CTRL))
+		udelay(10);
+}
+
+static int ar934x_check_link(struct ar934x_mac *mac)
+{
+	struct phy_device *phydev;
+
+	ioaddr = mac->mac_base;
+	phydev = mac->phydev;
+	phy_startup(phydev);
+
+	if (!phydev->link) {
+		printf("%s link down\n", mac->dev->name);
+		return 0;
+	}
+
+	switch (phydev->speed) {
+	case _1000BASET:
+		ar7240_set_mac_if(1);
+		ar_mac_reg_set(AR934x_MAC_FIFO_CFG_5, (1 << 19));
+		if (is_ar7242(&ar7240_rst2) && (mac->dev->index == 0))
+			ar_reg_wr(&ar7240_pll->eth_xmii_config, 0x1c000000);
+		if (is_ar934x(&ar7240_rst2) && (mac->dev->index == 0))
+			ar_reg_wr(&ar7240_pll->eth_xmii_config, 0x06000000);
+		break;
+
+	case _100BASET:
+		ar7240_set_mac_if(0);
+		ar_mac_reg_set(AR934x_MAC_IFCTL, AR934x_MAC_IFCTL_SPEED);
+		ar_mac_reg_clr(AR934x_MAC_FIFO_CFG_5, (1 << 19));
+		if ((is_ar7242(&ar7240_rst2) || is_ar934x(&ar7240_rst2)) &&
+		    (mac->dev->index == 0))
+			ar_reg_wr(&ar7240_pll->eth_xmii_config, 0x0101);
+		break;
+
+	case _10BASET:
+		ar7240_set_mac_if(0);
+		ar_mac_reg_clr(AR934x_MAC_IFCTL, AR934x_MAC_IFCTL_SPEED);
+		ar_mac_reg_clr(AR934x_MAC_FIFO_CFG_5, (1 << 19));
+
+		if ((is_ar7242(&ar7240_rst2) || is_ar934x(&ar7240_rst2)) &&
+		    (mac->dev->index == 0))
+			ar_reg_wr(&ar7240_pll->eth_xmii_config, 0x1616);
+		break;
+
+	default:
+		printf("Invalid speed detected\n");
+		return 0;
+	}
+
+	if (phydev->link && (phydev->duplex == mac->duplex) &&
+	    (phydev->speed == mac->speed))
+		return 1;
+
+	mac->duplex = phydev->duplex;
+	mac->speed = phydev->speed;
+
+	debug("dup %d speed %d\n", phydev->duplex, phydev->speed);
+
+	ar7240_set_mac_duplex(phydev->duplex);
+
+	return 1;
+}
+
+/*
+ * For every command we re-setup the ring and start with clean h/w rx state
+ */
+static int ar934x_init_ring(struct eth_device *dev, bd_t *bis)
+{
+	int i;
+	struct ar934x_desc *fr;
+	struct ar934x_mac *mac = (struct ar934x_mac *)dev->priv;
+	ioaddr = mac->mac_base;
+
+
+	if (!ar934x_check_link(mac))
+		return 0;
+
+	mac->next_rx = 0;
+	for (i = 0; i < NO_OF_RX_FIFOS; i++) {
+		fr = mac->fifo_rx[i];
+		fr->pkt_start_addr = virt_to_phys(NetRxPackets[i]);
+		flush_cache((u32) NetRxPackets[i], PKTSIZE_ALIGN);
+		ar7240_rx_give_to_dma(fr);
+	}
+
+	ATHRS_REG_W32(AR934x_DMA_RX_DESC, virt_to_phys(mac->fifo_rx[0]));
+	ATHRS_REG_W32(AR934x_DMA_RX_CTRL, AR934x_RXE);	/* rx start */
+	udelay(1000 * 1000);
+
+	return 1;
+}
+
+/*
+ *INIT - Finish setting up the ethernet interface
+ */
+static int ar934x_init(struct eth_device *dev, bd_t *bis)
+{
+	struct ar934x_mac *mac = (struct ar934x_mac *)dev->priv;
+	struct mii_dev *bus;
+	struct phy_device *phydev;
+	u32 mac_h, mac_l, supported;
+	int ret;
+	ioaddr = mac->mac_base;
+
+	ret = ar9344_init_board(dev);
+	if (ret)
+		return ret;
+
+	ar934x_hw_start(dev);
+
+	ar934x_setup_fifos(mac);
+	udelay(100 * 1000);
+
+	mac_l = (dev->enetaddr[4] << 8) | (dev->enetaddr[5]);
+	mac_h = (dev->enetaddr[0] << 24) |
+		(dev->enetaddr[1] << 16) |
+		(dev->enetaddr[2] << 8) |
+		(dev->enetaddr[3] << 0);
+
+	ATHRS_REG_W32(AR934x_GE_MAC_ADDR1, mac_l);
+	ATHRS_REG_W32(AR934x_GE_MAC_ADDR2, mac_h);
+
+	bus = mdio_alloc();
+	if (!bus) {
+		printf("Can not allocate memory of bus\n");
+		return 0;
+	}
+
+	bus->read = ar9344_miiphy_read;
+	bus->write = ar9344_miiphy_write;
+	sprintf(bus->name, "%s", dev->name);
+
+	phydev = phy_connect(bus, 0, dev, PHY_INTERFACE_MODE_RGMII);
+	if (!phydev) {
+		printf("phy_connect failed\n");
+		return 0;
+	}
+	mac->phydev = phydev;
+	supported = (PHY_BASIC_FEATURES | SUPPORTED_1000baseT_Full |
+		     SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+	phydev->supported &= supported;
+	phy_config(phydev);
+
+	printf("%s up\n", dev->name);
+
+	return 1;
+}
+
+int ar934x_initialize(bd_t *bis)
+{
+	int card_num;
+	struct eth_device *dev;
+
+	for (card_num = 0; card_num < ARRAY_SIZE(supported) - 1; card_num++) {
+		printf("Atheros AR934x --> eth%d\n", card_num);
+
+		dev = (struct eth_device *)malloc(sizeof(*dev));
+		if (!dev) {
+			printf("Can not allocate memory of ar9344\n");
+			break;
+		}
+
+		memset(dev, 0, sizeof(*dev));
+		sprintf(dev->name, "eth%d", card_num);
+
+		ar934x_macs[card_num].mac_base = card_num ? AR7240_GE1_BASE :
+							     AR7240_GE0_BASE;
+		ar934x_macs[card_num].dev = dev;
+
+		dev->priv = (void *)&ar934x_macs[card_num];
+		dev->iobase = 0;
+		dev->init = ar934x_init_ring;
+		dev->halt = ar934x_halt;
+		dev->send = ar934x_send;
+		dev->recv = ar934x_recv;
+		dev->index = card_num;
+
+		ar934x_get_ethaddr(dev);
+
+		eth_register(dev);
+
+		ar934x_init(dev, bis);
+	}
+	return card_num;
+}
diff --git a/drivers/net/ar934x.h b/drivers/net/ar934x.h
new file mode 100644
index 0000000..66781a0
--- /dev/null
+++ b/drivers/net/ar934x.h
@@ -0,0 +1,202 @@
+/*
+ *  Copyright (C) 2013 Imagination Technologies
+ *
+ *  Derived from works by OpenWRT
+ *
+ *  SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef _AR934x_H
+#define _AR934x_H
+
+#include <linux/types.h>
+
+/*
+ *  h/w descriptor
+ */
+#define CONFIG_AR934x_NMACS	1
+
+#define NO_OF_TX_FIFOS  8
+#define NO_OF_RX_FIFOS  8
+
+struct ar934x_desc {
+	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;
+};
+
+struct ar934x_mac {
+	struct ar934x_desc *fifo_tx[NO_OF_TX_FIFOS];
+	struct ar934x_desc *fifo_rx[NO_OF_RX_FIFOS];
+	struct eth_device *dev;
+	struct phy_device *phydev;
+	u32 next_tx;
+	u32 next_rx;
+	u32 link;
+	u32 duplex;
+	u32 speed;
+	u32 mac_base;
+};
+
+#define MAX_WAIT        1000
+
+/*
+ *  Config/Mac Register definitions
+ */
+#define AR934x_MAC_CFG1             0x00
+#define AR934x_MAC_CFG2             0x04
+#define AR934x_MAC_IFCTL            0x38
+
+/*
+ *  fifo control registers
+ */
+#define AR934x_MAC_FIFO_CFG_0      0x48
+#define AR934x_MAC_FIFO_CFG_1      0x4c
+#define AR934x_MAC_FIFO_CFG_2      0x50
+#define AR934x_MAC_FIFO_CFG_3      0x54
+#define AR934x_MAC_FIFO_CFG_4      0x58
+
+#define AR934x_MAC_FIFO_CFG_5      0x5c
+#define AR934x_BYTE_PER_CLK_EN     (1 << 19)
+
+#define AR934x_MAC_FIFO_RAM_0      0x60
+#define AR934x_MAC_FIFO_RAM_1      0x64
+#define AR934x_MAC_FIFO_RAM_2      0x68
+#define AR934x_MAC_FIFO_RAM_3      0x6c
+#define AR934x_MAC_FIFO_RAM_4      0x70
+#define AR934x_MAC_FIFO_RAM_5      0x74
+#define AR934x_MAC_FIFO_RAM_6      0x78
+#define AR934x_MAC_FIFO_RAM_7      0x7c
+
+/*
+ *  fields
+ */
+#define AR934x_MAC_CFG1_SOFT_RST	(1 << 31)
+#define AR934x_MAC_CFG1_RX_RST		(1 << 19)
+#define AR934x_MAC_CFG1_TX_RST		(1 << 18)
+#define AR934x_MAC_CFG1_LOOPBACK	(1 << 8)
+#define AR934x_MAC_CFG1_RX_EN		(1 << 2)
+#define AR934x_MAC_CFG1_TX_EN		(1 << 0)
+
+#define AR934x_MAC_CFG2_FDX		(1 << 0)
+#define AR934x_MAC_CFG2_PAD_CRC_EN	(1 << 2)
+#define AR934x_MAC_CFG2_LEN_CHECK	(1 << 4)
+#define AR934x_MAC_CFG2_HUGE_FRAME_EN	(1 << 5)
+#define AR934x_MAC_CFG2_IF_1000		(1 << 9)
+#define AR934x_MAC_CFG2_IF_10_100	(1 << 8)
+
+#define AR934x_MAC_IFCTL_SPEED		(1 << 16)
+
+/* 0 - 25MHz	1 - 40 MHz */
+#define WASP_REF_CLK_25			(1 << 4)
+
+/*
+ *  DMA (tx/rx) register defines
+ */
+#define AR934x_DMA_TX_CTRL              0x180
+#define AR934x_DMA_TX_DESC              0x184
+#define AR934x_DMA_TX_STATUS            0x188
+#define AR934x_DMA_RX_CTRL              0x18c
+#define AR934x_DMA_RX_DESC              0x190
+#define AR934x_DMA_RX_STATUS            0x194
+#define AR934x_DMA_INTR_MASK            0x198
+#define AR934x_DMA_INTR                 0x19c
+
+/*
+ *  tx/rx ctrl and status bits
+ */
+#define AR934x_TXE                      (1 << 0)
+#define AR934x_TX_STATUS_PKTCNT_SHIFT   16
+#define AR934x_TX_STATUS_PKT_SENT       0x1
+#define AR934x_TX_STATUS_URN            0x2
+#define AR934x_TX_STATUS_BUS_ERROR      0x8
+
+#define AR934x_RXE                      (1 << 0)
+
+#define AR934x_RX_STATUS_PKTCNT_MASK    0xff0000
+#define AR934x_RX_STATUS_PKT_RCVD       (1 << 0)
+#define AR934x_RX_STATUS_OVF            (1 << 2)
+#define AR934x_RX_STATUS_BUS_ERROR      (1 << 3)
+
+/*
+ *  MII registers
+ */
+#define AR934x_MAC_MII_MGMT_CFG         0x20
+#define AR934x_MGMT_CFG_CLK_DIV_20      0x07
+
+#define AR934x_MII_MGMT_CMD             0x24
+#define AR934x_MGMT_CMD_READ            0x1
+
+#define AR934x_MII_MGMT_ADDRESS         0x28
+#define AR934x_ADDR_SHIFT               8
+
+#define AR934x_MII_MGMT_CTRL            0x2c
+#define AR934x_MII_MGMT_STATUS          0x30
+
+#define AR934x_MII_MGMT_IND             0x34
+#define AR934x_MGMT_IND_BUSY            (1 << 0)
+#define AR934x_MGMT_IND_INVALID         (1 << 2)
+
+#define AR934x_GE_MAC_ADDR1             0x40
+#define AR934x_GE_MAC_ADDR2             0x44
+
+/*
+ *  Ownership of descriptors between DMA and cpu
+ */
+#define ar7240_rx_owned_by_dma(_ds)     ((_ds)->is_empty == 1)
+#define ar7240_rx_give_to_dma(_ds)      ((_ds)->is_empty = 1)
+#define ar7240_tx_owned_by_dma(_ds)     ((_ds)->is_empty == 0)
+#define ar7240_tx_give_to_dma(_ds)      ((_ds)->is_empty = 0)
+#define ar7240_tx_own(_ds)              ((_ds)->is_empty = 1)
+
+/*
+ *  Primitives
+ */
+
+#define ar_name2mac(name)		strcmp(name, "eth0") ? \
+						KSEG1ADDR(AR7240_GE1_BASE) : \
+						KSEG1ADDR(AR7240_GE0_BASE)
+
+#define ar_reg_rd(_addr)		readl(KSEG1ADDR((_addr)))
+#define ar_reg_wr(_addr, _val)		writel((_val), KSEG1ADDR((_addr)))
+
+#define ATHRS_REG_W32(reg, val32)	ar_reg_wr(ioaddr + (reg), (val32))
+#define ATHRS_REG_R32(reg)		readl(KSEG1ADDR(ioaddr + (reg)))
+
+#define ar_reg_rd_set(_reg, _mask)					       \
+	ar_reg_wr((_reg), (ar_reg_rd((_reg)) | (_mask)))
+
+#define ar_reg_rd_clr(_reg, _mask)					       \
+	ar_reg_wr((_reg), (ar_reg_rd((_reg)) & ~(_mask)))
+
+#define ar_mac_reg_set(_x, _y)		ar_reg_rd_set(((_x) + ioaddr), (_y))
+#define ar_mac_reg_clr(_x, _y)		ar_reg_rd_clr(((_x) + ioaddr), (_y))
+
+/*
+ *  Link settings
+ */
+
+#define ar7240_set_mac_duplex(_fdx)	do {				       \
+	if ((_fdx))							       \
+		ar_mac_reg_set(AR934x_MAC_CFG2, AR934x_MAC_CFG2_FDX);	       \
+	else								       \
+		ar_mac_reg_clr(AR934x_MAC_CFG2, AR934x_MAC_CFG2_FDX);	       \
+} while (0)
+
+#define ar7240_set_mac_if(_is_xgmii)    do {				       \
+	ar_mac_reg_clr(AR934x_MAC_CFG2, AR934x_MAC_CFG2_IF_1000 |	       \
+					AR934x_MAC_CFG2_IF_10_100);\
+	if ((_is_xgmii)) {						       \
+		ar_mac_reg_set(AR934x_MAC_CFG2, AR934x_MAC_CFG2_IF_1000);      \
+		ar_mac_reg_set(AR934x_MAC_FIFO_CFG_5, AR934x_BYTE_PER_CLK_EN); \
+	} else {							       \
+		ar_mac_reg_set(AR934x_MAC_CFG2, AR934x_MAC_CFG2_IF_10_100);    \
+		ar_mac_reg_clr(AR934x_MAC_FIFO_CFG_5, AR934x_BYTE_PER_CLK_EN); \
+	}								       \
+} while (0)
+
+#endif
diff --git a/include/netdev.h b/include/netdev.h
index 47fa80d..b235c9f 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -28,6 +28,7 @@ int cpu_eth_init(bd_t *bis);
 int altera_tse_initialize(u8 dev_num, int mac_base,
 			  int sgdma_rx_base, int sgdma_tx_base,
 			  u32 sgdma_desc_base, u32 sgdma_desc_size);
+int ar934x_initialize(bd_t *bis);
 int at91emac_register(bd_t *bis, unsigned long iobase);
 int au1x00_enet_initialize(bd_t*);
 int ax88180_initialize(bd_t *bis);
-- 
1.8.3.2




More information about the U-Boot mailing list