From patchwork Fri Feb 4 19:56:42 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joe Xue X-Patchwork-Id: 81942 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 6D8EBB712D for ; Sat, 5 Feb 2011 06:57:29 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id BE8BE28364; Fri, 4 Feb 2011 20:57:27 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FxT2FkczV-VU; Fri, 4 Feb 2011 20:57:27 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id C87672837F; Fri, 4 Feb 2011 20:57:25 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 97D5E2837F for ; Fri, 4 Feb 2011 20:57:22 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id QLCC6NVbf5hC for ; Fri, 4 Feb 2011 20:57:20 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-02.primus.ca (smtp-noauth7.primus.ca [216.254.180.38]) by theia.denx.de (Postfix) with ESMTP id 288DC28364 for ; Fri, 4 Feb 2011 20:57:15 +0100 (CET) Received: from kodiak.precidia.com ([206.191.32.166]) by mail-02.primus.ca with esmtp (Exim 4.72) (envelope-from ) id 1PlRmI-0003yC-2J; Fri, 04 Feb 2011 14:57:11 -0500 Received: from savana.precidia.com ([206.191.32.165]:33309 helo=kokopo) by kodiak.precidia.com with esmtp (Exim 4.62) (envelope-from ) id 1PlRmH-0000II-Hn; Fri, 04 Feb 2011 14:57:09 -0500 Received: by kokopo (Postfix, from userid 70015) id 51C5D3C18AC; Fri, 4 Feb 2011 14:57:09 -0500 (EST) From: Joe Xue To: u-boot@lists.denx.de Date: Fri, 4 Feb 2011 14:56:42 -0500 Message-Id: <1296849402-8662-1-git-send-email-lgxue@hotmail.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: References: Cc: Joe Xue Subject: [U-Boot] [PATCH] Add support Asix's AX88783 ethernet chip v1.00 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 Cc: Wolfgang Denk Cc: Stefano Babic --- 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#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(®->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); + /* 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(®->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!\n"); + 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!\n"); + 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!\n"); + 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!\n"); + 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!\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, ®->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(®->wcr); + tmp &= ~WCR_D1_SLEEP; + writel(tmp | WCR_D1_CLEAR_SLEEP, ®->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(®->wcr); + writel((tmp | WCR_D1_SLEEP), ®->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(®->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 = 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 + * + * 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);