[U-Boot] [PATCH] Add support for ASIX's AX88783 ethernet chip
Joe Xue
lgxue at hotmail.com
Mon Jan 31 18:42:38 CET 2011
for more information about this chip, please check:
http://www.asix.com.tw/products.php?op=pItemdetail&PItemID=98;65;86&PLine=65
Signed-off-by: Joe Xue <lgxue at hotmail.com>
---
README | 7 +++++++
drivers/net/Makefile | 1 +
include/netdev.h | 1 +
3 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/README b/README
index 755d17c..c9657d8 100644
--- a/README
+++ b/README
@@ -892,6 +892,13 @@ The following options need to be configured:
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
supported (PIP405, MIP405, MPC5200); define
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..4eae949
--- /dev/null
+++ b/drivers/net/ax88783.c
@@ -0,0 +1,297 @@
+/*
+ *
+ * (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 ax88183_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(®->cr);
+ writel((tmp & ~CR_CHIP_RESET), ®->cr);
+ udelay(1000);
+
+ writel((tmp | CR_CHIP_RESET), ®->cr);
+
+ /* phy init */
+ tmp = readl(®->pcr);
+ tmp |= PCR_PHY0_RESET_CLEAR;
+
+ writel(tmp, ®->pcr);
+ udelay(100000);
+
+ tmp = readl(®->pollcr);
+ tmp &= POLLCR_PORT0_PHYID_MASK;
+ tmp |= POLLCR_PORT0_PHYID(0x10);
+ writel(tmp, ®->pollcr);
+
+ /* write MII mode */
+ tmp = readl(®->miicr) & 0xFF;
+ tmp &= (~MIICR_PORT0_MII_CLK_GEN);
+ tmp &= (~MIICR_PORT0_PHY_RMII);
+ writel(tmp, ®->miicr);
+
+ /* set LED mode */
+ tmp = readl(®->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, ®->ledcr);
+
+ /* set auto polling */
+ tmp = readl(®->pollcr);
+ tmp |= (POLLCR_PORT0_AUTO_POOLING);
+ writel(tmp, ®->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, ®->mdcr);
+ tmp = readl(®->mdcr);
+ if (tmp & MDCR_VALID) {
+ puts("link speed init failed!");
+ return 1;
+ }
+
+ tmp = readl(®->mdcr) & MDCR_VALUE_MASK;
+ tmp = tmp | 0x1000 | MDCR_WRITE | \
+ MDCR_PHY_ID(0x10) | MDCR_PHY_REG(reg_num);
+ writel(tmp, ®->mdcr);
+ tmp = readl(®->mdcr);
+ if (tmp & MDCR_VALID) {
+ puts("link speed init failed!");
+ return 1;
+ }
+ }
+
+ /* media init */
+ tmp = MDCR_READ | MDCR_PHY_ID(0x10) | MDCR_PHY_REG(MII_ADVERTISE);
+ writel(tmp, ®->mdcr);
+ tmp = readl(®->mdcr);
+ if (tmp & MDCR_VALID) {
+ puts("media init failed!");
+ return 1;
+ }
+
+ tmp = readl(®->mdcr) & MDCR_VALUE_MASK;
+ tmp &= (~ADVERTISE_ALL);
+ tmp |= ADVERTISE_ALL | 0x400;
+ tmp = tmp | MDCR_WRITE | MDCR_PHY_ID(0x10);
+
+ writel(tmp, ®->mdcr);
+ tmp = readl(®->mdcr);
+ if (tmp & MDCR_VALID) {
+ puts("media init failed!");
+ return 1;
+ }
+
+ tmp = MDCR_WRITE | MDCR_PHY_ID(0x10) | \
+ MDCR_PHY_REG(MII_BMCR)| \
+ BMCR_ANRESTART | BMCR_ANENABLE;
+
+ writel(tmp, ®->mdcr);
+ tmp = readl(®->mdcr);
+ if (tmp & MDCR_VALID) {
+ puts("media init failed!");
+ 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;
+
+ /* disable interrupt */
+ writel(IMSR_MASK_ALL, ®->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, ®->p0mac0);
+
+ mactmp[0] = dev->enetaddr[1];
+ mactmp[1] = dev->enetaddr[0];
+ writel(*mac, ®->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, ®->ftdata);
+
+ tmp = dev->enetaddr[4] | (dev->enetaddr[5]<<8) | \
+ FTCMD_FT_PORT(0x2) | FTCMD_FT_STATIC | \
+ FTCMD_WRITE_FT;
+ writel(tmp, ®->ftcmd);
+
+ /* packet order */
+ writel(BORDER_LITTLE, ®->border);
+
+ /* local bus cpi */
+ tmp = readl(®->l2psr);
+ tmp |= L2PSR_CPIO_ON;
+ writel(tmp, ®->l2psr);
+
+ tmp = readl(®->pcr);
+ writel(tmp & ~PCR_LOOP_BACK, ®->pcr);
+ return 0;
+
+}
+
+static void ax88783_halt(struct eth_device *dev)
+{
+ unsigned int tmp;
+ struct ax88783_reg *reg = (struct ax88783_reg *)dev->iobase;
+ tmp = readl(®->pcr);
+ writel((tmp | PCR_LOOP_BACK), ®->pcr);
+}
+
+/* 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(®->imsr);
+ while (tmp & IMSR_INT_CPO_EMPTY) {
+ tmp = readl(®->imsr);
+ writel(tmp, ®->imsr);
+ writel(CSCR_CPO_START, ®->cscr);
+
+ tmp = readl(®->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(®->cr);
+ tmp &= ~CR_CPO_RESET;
+ writel(tmp, ®->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(®->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(®->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, ®->cscr);
+ writel(pkt_header, ®->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, ®->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 = eth_getenv_enetaddr("ethaddr", dev->enetaddr);
+ if (!res) {
+ puts("Please set your MAC address!");
+ free(dev);
+ return 0;
+ }
+
+ res = ax88183_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..09ac9ed
--- /dev/null
+++ b/drivers/net/ax88783.h
@@ -0,0 +1,100 @@
+/*
+ *
+ * (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[17];
+ unsigned int pollcr;
+ unsigned int pad8[43];
+ unsigned int miicr;
+ unsigned int pad9[15];
+ unsigned int p0mac0;
+ unsigned int p0mac1;
+ unsigned int pad10[1];
+};
+
+#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 PCR_LOOP_BACK (8)
+
+#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 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 1a542e8..fddc64d 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