[U-Boot] [PATCH] Add support Asix's AX88783 ethernet chip v1.00

Joe Xue lgxue at hotmail.com
Fri Feb 4 20:56:42 CET 2011


for more information about this chip, please check:
http://www.asix.com.tw/products.php?op=pItemdetail&PItemID=98;65;86&PLine=6

Signed-off-by: Joe Xue <lgxue at hotmail.com>

Cc: Wolfgang Denk <wd at denx.de>
Cc: Stefano Babic <sbabic at denx.de>
---
 README                |    6 +
 drivers/net/Makefile  |    1 +
 drivers/net/ax88783.c |  295 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ax88783.h |  102 +++++++++++++++++
 include/netdev.h      |    1 +
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/ax88783.c
 create mode 100644 drivers/net/ax88783.h

diff --git a/README b/README
index 755d17c..b5e3c48 100644
--- a/README
+++ b/README
@@ -891,6 +891,12 @@ The following options need to be configured:
 			Define this if data bus is 16 bits. If your processor
 			automatically converts one 32 bit word to two 16 bit
 			words you may also try CONFIG_SMC911X_32_BIT.
+	 	CONFIG_DRIVER_AX88783
+	 	Support for ASIX's AX88783 chip
+
+	 		CONFIG_AX88783_BASE
+	 		Define this to hold the physical address
+	 		of the device (I/O space)
 
 - USB Support:
 		At the moment only the UHCI host controller is
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index fd9d0b4..7cd6e2c 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -30,6 +30,7 @@ COBJS-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o
 COBJS-$(CONFIG_ALTERA_TSE) += altera_tse.o
 COBJS-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o
+COBJS-$(CONFIG_DRIVER_AX88783) += ax88783.o
 COBJS-$(CONFIG_BCM570x) += bcm570x.o
 COBJS-$(CONFIG_BCM570x) += bcm570x_autoneg.o
 COBJS-$(CONFIG_BCM570x) += 5701rls.o
diff --git a/drivers/net/ax88783.c b/drivers/net/ax88783.c
new file mode 100644
index 0000000..f24288c
--- /dev/null
+++ b/drivers/net/ax88783.c
@@ -0,0 +1,295 @@
+/*
+ * (C) Copyright 2011 Joe Xue <lgxue at hotmail.com>
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+
+/*
+ * AX88783 has two ethernet ports, this driver uses port 0 in u-boot
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <linux/mii.h>
+#include <miiphy.h>
+#include <config.h>
+#include <asm/io.h>
+#include "ax88783.h"
+
+static int ax88783_phy_initial(struct eth_device *dev)
+{
+	int i;
+	int reg_num;
+	unsigned int tmp;
+	struct ax88783_reg * reg = (struct ax88783_reg *)dev->iobase;
+
+	/* reset chip */
+	tmp = readl(&reg->cr);
+	writel((tmp & ~CR_CHIP_RESET), &reg->cr);
+	udelay(1000);
+
+	writel((tmp | CR_CHIP_RESET), &reg->cr);
+
+	/* phy init */
+	tmp = readl(&reg->pcr);
+	tmp |= PCR_PHY0_RESET_CLEAR;
+
+	writel(tmp, &reg->pcr);
+	/* this delay is a bit long, but the physical initialization
+	 * only be called once when the board is starting, so it's
+	 * acceptable */
+	udelay(100000);
+
+	tmp = readl(&reg->pollcr);
+	tmp &= POLLCR_PORT0_PHYID_MASK;
+	tmp |= POLLCR_PORT0_PHYID(0x10);
+	writel(tmp, &reg->pollcr);
+
+	/* write MII mode */
+	tmp = readl(&reg->miicr) & 0xFF;
+	tmp &= (~MIICR_PORT0_MII_CLK_GEN);
+	tmp &= (~MIICR_PORT0_PHY_RMII);
+	writel(tmp, &reg->miicr);
+
+	/* set LED mode */
+	tmp = readl(&reg->ledcr);
+	tmp |= LEDCR_PORT_LED_ON(0) | LEDCR_LED0(PHY_LED_RX | PHY_LED_TX);
+	tmp |= LEDCR_PORT_LED_ON(1) | LEDCR_LED1(PHY_LED_LINK);
+	writel(tmp, &reg->ledcr);
+
+	/* set auto polling */
+	tmp = readl(&reg->pollcr);
+	tmp |= (POLLCR_PORT0_AUTO_POOLING);
+	writel(tmp, &reg->pollcr);
+
+	/* set link speed */
+	for (i = 0; i < 2; i++) {
+		reg_num = i*8+16;
+		tmp = MDCR_READ | MDCR_PHY_ID(0x10) | MDCR_PHY_REG(reg_num);
+		writel(tmp, &reg->mdcr);
+		tmp = readl(&reg->mdcr);
+		if (tmp & MDCR_VALID) {
+			puts("link speed init failed!\n");
+			return 1;
+		}
+
+		tmp = readl(&reg->mdcr) & MDCR_VALUE_MASK;
+		tmp = tmp | 0x1000 | MDCR_WRITE | \
+		      MDCR_PHY_ID(0x10) | MDCR_PHY_REG(reg_num);
+		writel(tmp, &reg->mdcr);
+		tmp = readl(&reg->mdcr);
+		if (tmp & MDCR_VALID) {
+			puts("link speed init failed!\n");
+			return 1;
+		}
+	}
+
+	/* media init */
+	tmp = MDCR_READ | MDCR_PHY_ID(0x10) | MDCR_PHY_REG(MII_ADVERTISE);
+	writel(tmp, &reg->mdcr);
+	tmp = readl(&reg->mdcr);
+	if (tmp & MDCR_VALID) {
+		puts("media init failed!\n");
+		return 1;
+	}
+
+	tmp = readl(&reg->mdcr) & MDCR_VALUE_MASK;
+	tmp &= (~ADVERTISE_ALL);
+	tmp |= ADVERTISE_ALL | 0x400;
+	tmp = tmp | MDCR_WRITE | MDCR_PHY_ID(0x10);
+
+	writel(tmp, &reg->mdcr);
+	tmp = readl(&reg->mdcr);
+	if (tmp & MDCR_VALID) {
+		puts("media init failed!\n");
+		return 1;
+	}
+
+	tmp = MDCR_WRITE | MDCR_PHY_ID(0x10) | \
+	      MDCR_PHY_REG(MII_BMCR)| \
+	      BMCR_ANRESTART | BMCR_ANENABLE;
+
+	writel(tmp, &reg->mdcr);
+	tmp = readl(&reg->mdcr);
+	if (tmp & MDCR_VALID) {
+		puts("media init failed!\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+static int ax88783_init(struct eth_device *dev, bd_t * bd)
+{
+	unsigned int tmp;
+	struct ax88783_reg *reg = (struct ax88783_reg *)dev->iobase;
+	unsigned char mactmp[4];
+	unsigned int * mac = (unsigned int *)mactmp;
+	int i;
+	unsigned int reg_num;
+	/* disable interrupt */
+	writel(IMSR_MASK_ALL, &reg->imsr);
+
+	/* set mac address*/
+	mactmp[0] = dev->enetaddr[5];
+	mactmp[1] = dev->enetaddr[4];
+	mactmp[2] = dev->enetaddr[3];
+	mactmp[3] = dev->enetaddr[2];
+	writel(*mac, &reg->p0mac0);
+
+	mactmp[0] = dev->enetaddr[1];
+	mactmp[1] = dev->enetaddr[0];
+	writel(*mac, &reg->p0mac1);
+
+	/* write mac to forward entry */
+	mactmp[0] = dev->enetaddr[3];
+	mactmp[1] = dev->enetaddr[2];
+	mactmp[2] = dev->enetaddr[1];
+	mactmp[3] = dev->enetaddr[0];
+	writel(*mac, &reg->ftdata);
+
+	tmp = dev->enetaddr[4] | (dev->enetaddr[5]<<8) | \
+	      FTCMD_FT_PORT(0x2) | FTCMD_FT_STATIC | \
+	      FTCMD_WRITE_FT;
+	writel(tmp, &reg->ftcmd);
+
+	/* packet order */
+	writel(BORDER_LITTLE, &reg->border);
+
+	/* local bus cpi */
+	tmp = readl(&reg->l2psr);
+	tmp |= L2PSR_CPIO_ON;
+	writel(tmp, &reg->l2psr);
+
+	tmp = readl(&reg->wcr);
+	tmp &= ~WCR_D1_SLEEP;
+	writel(tmp | WCR_D1_CLEAR_SLEEP, &reg->wcr);
+	return 0;
+
+}
+
+static void ax88783_halt(struct eth_device *dev)
+{
+	unsigned int tmp;
+	struct ax88783_reg *reg = (struct ax88783_reg *)dev->iobase;
+	tmp = readl(&reg->wcr);
+	writel((tmp | WCR_D1_SLEEP), &reg->wcr);
+}
+
+/* Get a data block via Ethernet */
+static int ax88783_recv(struct eth_device *dev)
+{
+	char *buf;
+	unsigned int i;
+	unsigned int tmp;
+	unsigned long length, reverse_length;
+	struct ax88783_reg * reg = (struct ax88783_reg *)dev->iobase;
+
+	tmp = readl(&reg->imsr);
+	while (tmp & IMSR_INT_CPO_EMPTY) {
+		tmp = readl(&reg->imsr);
+		writel(tmp, &reg->imsr);
+		writel(CSCR_CPO_START, &reg->cscr);
+
+		tmp = readl(&reg->dataport);
+		tmp = be32_to_cpu(tmp);
+		if (tmp == 0)
+			continue;
+
+		length = tmp & 0xffff;
+		reverse_length = (~(tmp>>16))&0xffff;
+		if (length != reverse_length) {
+			/* reset CPO */
+			tmp = readl(&reg->cr);
+			tmp &= ~CR_CPO_RESET;
+			writel(tmp, &reg->cr);
+			continue;
+		}
+
+		length = length & 0x7ff;
+		/* align the length */
+		length = ((length+3)/4)*4;
+
+		buf = NetRxPackets[0];
+		for (i = 0; i < length; i += 4) {
+			tmp = readl(&reg->dataport);
+			buf[i] = (unsigned char)(tmp & 0xff);
+			buf[i+1] = (unsigned char)((tmp >> 8) & 0xff);
+			buf[i+2] = (unsigned char)((tmp >> 16) & 0xff);
+			buf[i+3] = (unsigned char)((tmp >> 24) & 0xff);
+		}
+
+		/* pass to up level */
+		NetReceive(NetRxPackets[0], (unsigned short) length);
+		tmp = readl(&reg->imsr);
+	}
+
+	return (int) length;
+}
+
+/* Send a data block via Ethernet. */
+	static int
+ax88783_send(struct eth_device *dev, volatile void *packet, int length)
+{
+	unsigned int pkt_header, tmp, i;
+	unsigned char *buf = (unsigned char *)packet;
+	struct ax88783_reg * reg = (struct ax88783_reg *)dev->iobase;
+	tmp = length;
+	tmp = (~tmp << 16) | tmp;
+	pkt_header = cpu_to_be32(tmp);
+	writel(CSCR_CPI_START, &reg->cscr);
+	writel(pkt_header, &reg->dataport);
+
+	for (i = 0; i < length; i += 4) {
+		tmp = (unsigned int)*(buf + i) | \
+		      (((unsigned int)*(buf + i + 1)) << 8) | \
+		      (((unsigned int)*(buf + i + 2)) << 16) | \
+		      (((unsigned int)*(buf + i + 3)) << 24);
+		writel(tmp, &reg->dataport);
+	}
+
+	return 0;
+}
+
+int ax88783_initialize(bd_t *bis)
+{
+	struct eth_device *dev;
+	int res;
+	dev = (struct eth_device *)malloc(sizeof *dev);
+
+	if (NULL == dev)
+		return 0;
+
+	memset(dev, 0, sizeof *dev);
+
+	sprintf(dev->name, "AX88783");
+	dev->iobase = CONFIG_AX88783_BASE;
+	dev->init = ax88783_init;
+	dev->halt = ax88783_halt;
+	dev->send = ax88783_send;
+	dev->recv = ax88783_recv;
+
+	res = ax88783_phy_initial(dev);
+	if (res != 0) {
+		free(dev);
+		return 0;
+	}
+
+	eth_register(dev);
+
+	return 1;
+}
+
diff --git a/drivers/net/ax88783.h b/drivers/net/ax88783.h
new file mode 100644
index 0000000..0703ba2
--- /dev/null
+++ b/drivers/net/ax88783.h
@@ -0,0 +1,102 @@
+/*
+ * (C) Copyright 2011 Joe Xue <lgxue at hotmail.com>
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __AX88783_H__
+#define __AX88783_H__
+
+struct ax88783_reg {
+	unsigned int cr;
+	unsigned int pcr;
+	unsigned int pad0[2];
+	unsigned int l2psr;
+	unsigned int pad1[1];
+	unsigned int ftdata;
+	unsigned int ftcmd;
+	unsigned int pad2[7];
+	unsigned int mdcr;
+	unsigned int pad3[3];
+	unsigned int dataport;
+	unsigned int pad4[32];
+	unsigned int border;
+	unsigned int cscr;
+	unsigned int pad5[1];
+	unsigned int ledcr;
+	unsigned int pad6[6];
+	unsigned int imsr;
+	unsigned int pad7[2];
+	unsigned int wcr;
+	unsigned int pad8[14];
+	unsigned int pollcr;
+	unsigned int pad9[43];
+	unsigned int miicr;
+	unsigned int pad10[15];
+	unsigned int p0mac0;
+	unsigned int p0mac1;
+};
+
+#define CR_CPI_RESET                   (1 << 26)
+#define CR_CPO_RESET                   (1 << 27)
+#define CR_CHIP_RESET                  (1 << 31)
+
+#define PCR_PHY0_RESET_CLEAR           (1)
+
+#define L2PSR_CPIO_ON                  (1 << 9)
+
+#define FTCMD_WRITE_FT                 (1 << 31)
+#define FTCMD_FT_STATIC                (1 << 20)
+#define FTCMD_FT_PORT(x)               (x << 16)
+
+#define MDCR_WRITE                     (1 << 31)
+#define MDCR_READ                      (1 << 30)
+#define MDCR_VALID                     (1 << 29)
+#define MDCR_PHY_ID(x)                 (x << 24)
+#define MDCR_PHY_REG(x)                (x << 16)
+#define MDCR_VALUE_MASK                (0xFFFF)
+
+#define BORDER_BIG                     (0)
+#define BORDER_LITTLE                  (1)
+
+#define CSCR_CPI_START                 (1 << 15)
+#define CSCR_CPO_START                 (1 << 31)
+
+#define LEDCR_LED0(x)                  (x)
+#define LEDCR_LED1(x)                  (x << 8)
+#define LEDCR_LED2(x)                  (x << 16)
+#define LEDCR_PORT_LED_ON(Port)        (1 << (24 + Port))
+#define PHY_LED_SPEED                  (1 << 0)
+#define PHY_LED_DUPLEX                 (1 << 1)
+#define PHY_LED_LINK                   (1 << 2)
+#define PHY_LED_RX                     (1 << 3)
+#define PHY_LED_TX                     (1 << 4)
+#define PHY_LED_COLLISION              (1 << 5)
+
+#define IMSR_INT_CPO_EMPTY             (1 << 3)
+#define IMSR_MASK_ALL                  0xFFFF0000
+
+#define WCR_D1_SLEEP                      (1 << 16)
+#define WCR_D1_CLEAR_SLEEP                (1 << 18)
+
+#define POLLCR_PORT0_PHYID_MASK        (0xFFFFFFE0)
+#define POLLCR_PORT0_PHYID(x)          (x)
+#define POLLCR_PORT0_AUTO_POOLING      0x11000000
+
+#define MIICR_PORT0_MII_CLK_GEN        (1 << 0)
+#define MIICR_PORT0_PHY_RMII           (1 << 4)
+
+#endif
+
diff --git a/include/netdev.h b/include/netdev.h
index 6f0a971..c302142 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -44,6 +44,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);
 int ax88180_initialize(bd_t *bis);
+int ax88783_initialize(bd_t *bis);
 int au1x00_enet_initialize(bd_t*);
 int at91emac_register(bd_t *bis, unsigned long iobase);
 int bfin_EMAC_initialize(bd_t *bis);
-- 
1.7.0.4



More information about the U-Boot mailing list