--- /dev/null
+/*
+ * ASIX AX88796C Ethernet
+ * (C) Copyright 2011
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ *
+ */
+
+#include <common.h>
+#include <miiphy.h>
+#include <malloc.h>
+#include <net.h>
+#include <spi.h>
+#include <asm/errno.h>
+#include "ax88796c_spi.h"
+
+#ifdef CONFIG_DRIVER_AX88796C_SPI
+
+static unsigned char tx_packet[2048];
+static unsigned char rx_packet[2048];
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_claim_bus
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static int ax88796c_claim_bus(struct eth_device *dev)
+{
+ struct ax88796c_private *ax_local =
+ (struct ax88796c_private *)dev->priv;
+
+ int rc = spi_claim_bus(ax_local->slave);
+
+ if (rc)
+ printf("Failed to claim SPI bus!\n");
+
+ return rc;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_release_bus
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static void ax88796c_release_bus(struct eth_device *dev)
+{
+ struct ax88796c_private *ax_local =
+ (struct ax88796c_private *)dev->priv;
+
+ spi_release_bus(ax_local->slave);
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: read_reg
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static unsigned short read_reg(struct eth_device *dev, unsigned char reg_addr)
+{
+ struct ax88796c_private *ax_local =
+ (struct ax88796c_private *)dev->priv;
+ unsigned char opbuf[4];
+ unsigned char rxbuf[2];
+
+ opbuf[0] = OP_READ_GREG; /* OP: read register */
+ opbuf[1] = reg_addr; /* Reg Addr */
+ opbuf[2] = 0xFF; /* Dummy */
+ opbuf[3] = 0xFF; /* Dummy */
+ spi_xfer(ax_local->slave, 4 * 8, opbuf, NULL, SPI_XFER_BEGIN);
+
+ rxbuf[0] = rxbuf[1] = 0;
+ spi_xfer(ax_local->slave, 2 * 8, NULL, rxbuf, SPI_XFER_END);
+
+ return le16_to_cpu(*((unsigned short *)rxbuf));
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: write_reg
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static void write_reg(struct eth_device *dev, unsigned char reg_addr,
+ unsigned short reg_value)
+{
+ struct ax88796c_private *ax_local =
+ (struct ax88796c_private *)dev->priv;
+ unsigned char opbuf[2];
+ unsigned char txbuf[2];
+
+ opbuf[0] = OP_WRITE_GREG; /* OP: write register */
+ opbuf[1] = reg_addr; /* Reg Addr */
+ spi_xfer(ax_local->slave, 2 * 8, opbuf, NULL, SPI_XFER_BEGIN);
+
+ txbuf[0] = (unsigned char)reg_value;
+ txbuf[1] = (unsigned char)(reg_value >> 8);
+ spi_xfer(ax_local->slave, 2 * 8, txbuf, NULL, SPI_XFER_END);
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_read_fifo_pio
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static void ax88796c_read_fifo_pio(struct eth_device *dev, unsigned char *rxbuf,
+ int count)
+{
+ struct ax88796c_private *ax_local =
+ (struct ax88796c_private *)dev->priv;
+ unsigned char opbuf[5];
+
+ opbuf[0] = OP_READ_RXQ; /* OP: read RXQ */
+ opbuf[1] = 0xFF; /* Dummy */
+ opbuf[2] = 0xFF; /* Dummy */
+ opbuf[3] = 0xFF; /* Dummy */
+ opbuf[4] = 0xFF; /* Dummy */
+ spi_xfer(ax_local->slave, 5 * 8, opbuf, NULL, SPI_XFER_BEGIN);
+
+ spi_xfer(ax_local->slave, count * 8, NULL, rxbuf, SPI_XFER_END);
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_write_fifo_pio
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static void ax88796c_write_fifo_pio(struct eth_device *dev, unsigned char *txbuf,
+ int count)
+{
+ struct ax88796c_private *ax_local =
+ (struct ax88796c_private *)dev->priv;
+ unsigned char opbuf[4];
+
+ opbuf[0] = OP_WRITE_TXQ; /* OP: write RXQ */
+ opbuf[1] = 0xFF; /* Dummy */
+ opbuf[2] = 0xFF; /* Dummy */
+ opbuf[3] = 0xFF; /* Dummy */
+ spi_xfer(ax_local->slave, 4 * 8, opbuf, NULL, SPI_XFER_BEGIN);
+
+ spi_xfer(ax_local->slave, count * 8, txbuf, NULL, SPI_XFER_END);
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_set_enetaddr
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static void ax88796c_set_enetaddr(struct eth_device *dev)
+{
+ write_reg(dev, P3_MACASR0, (dev->enetaddr[4] << 8) | dev->enetaddr[5]);
+ write_reg(dev, P3_MACASR1, (dev->enetaddr[2] << 8) | dev->enetaddr[3]);
+ write_reg(dev, P3_MACASR2, (dev->enetaddr[0] << 8) | dev->enetaddr[1]);
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_get_enetaddr
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static void ax88796c_get_enetaddr(struct eth_device *dev)
+{
+ unsigned short mac_addr;
+
+ mac_addr = read_reg(dev, P3_MACASR0);
+ dev->enetaddr[5] = mac_addr & 0x00FF;
+ dev->enetaddr[4] = mac_addr >> 8;
+ mac_addr = read_reg(dev, P3_MACASR1);
+ dev->enetaddr[3] = mac_addr & 0x00FF;
+ dev->enetaddr[2] = mac_addr >> 8;
+ mac_addr = read_reg(dev, P3_MACASR2);
+ dev->enetaddr[1] = mac_addr & 0x00FF;
+ dev->enetaddr[0] = mac_addr >> 8;
+
+ if ((dev->enetaddr[0] & 0x01) ||
+ ((dev->enetaddr[0] == 0) && (dev->enetaddr[1] == 0) &&
+ (dev->enetaddr[2] == 0) && (dev->enetaddr[3] == 0) &&
+ (dev->enetaddr[4] == 0) && (dev->enetaddr[5] == 0))) {
+ dev->enetaddr[0] = 0x08;
+ dev->enetaddr[1] = 0x00;
+ dev->enetaddr[2] = 0x3e;
+ dev->enetaddr[3] = 0x26;
+ dev->enetaddr[4] = 0x0a;
+ dev->enetaddr[5] = 0x5b;
+ }
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_mdio_read
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static int ax88796c_mdio_read(struct eth_device *dev, int phy_id, int loc)
+{
+ unsigned long time_out;
+ unsigned short val;
+
+ write_reg(dev, P2_MDIOCR, MDIOCR_RADDR(loc) |
+ MDIOCR_FADDR(phy_id) | MDIOCR_READ);
+
+ time_out = get_timer(0) + (CFG_HZ / 100);
+ while ((read_reg(dev, P2_MDIOCR) & MDIOCR_VALID) == 0){
+ if (get_timer(0) > time_out) {
+ return -EIO;
+ }
+ }
+
+ val = read_reg(dev, P2_MDIODR);
+
+ return val;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_mdio_write
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static int ax88796c_mdio_write(struct eth_device *dev, int phy_id, int loc,
+ int value)
+{
+ unsigned long time_out;
+
+ write_reg(dev, P2_MDIODR, value);
+ write_reg(dev, P2_MDIOCR, MDIOCR_RADDR(loc) |
+ MDIOCR_FADDR(phy_id) | MDIOCR_WRITE);
+
+ time_out = get_timer(0) + (CFG_HZ / 100);
+ while ((read_reg(dev, P2_MDIOCR) & MDIOCR_VALID) == 0){
+ if (get_timer(0) > time_out) {
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_AX88796C_DBG
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_dump_regs
+ * Purpose: Dump all MAC registers
+ * -----------------------------------------------------------------------------
+ */
+static void ax88796c_dump_regs(struct eth_device *dev)
+{
+ unsigned char i, j;
+
+ printf("\n");
+ printf(" Page0 Page1 Page2 Page3 "
+ "Page4 Page5 Page6 Page7\n");
+ for (i = 0; i < 0x20; i += 2) {
+
+ printf("0x%02x ", i);
+ for (j = 0; j < 8; j++) {
+ printf("0x%04x ",
+ read_reg(dev, j * 0x20 + i));
+ }
+ printf("\n");
+ }
+ printf("\n");
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_dump_phy_regs
+ * Purpose: Dump PHY register from MR0 to MR5
+ * -----------------------------------------------------------------------------
+ */
+static void ax88796c_dump_phy_regs(struct eth_device *dev)
+{
+ int i;
+
+ printf("Dump PHY registers:\n");
+ for (i = 0; i < 6; i++) {
+ printf(" MR%d = 0x%04x\n", i,
+ ax88796c_mdio_read(dev, PHY_ID, i));
+ }
+ printf("\n");
+}
+#endif
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_reset
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static int ax88796c_reset(struct eth_device *dev)
+{
+ unsigned long time_out;
+
+ write_reg(dev, P0_PSR, PSR_RESET);
+ write_reg(dev, P0_PSR, PSR_RESET_CLR);
+
+ time_out = get_timer(0) + (CFG_HZ / 100);
+ while (!(read_reg(dev, P0_PSR) & PSR_DEV_READY)){
+ if (get_timer(0) > time_out) {
+ return -ENXIO;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_bind
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static void ax88796c_bind(struct eth_device *dev)
+{
+ ax88796c_get_enetaddr(dev);
+
+ /* Setup LED mode */
+ write_reg(dev, P2_LCR0, LCR_LED0_EN | LCR_LED0_DUPLEX |
+ LCR_LED1_EN | LCR_LED1_100MODE);
+ write_reg(dev, P2_LCR1, (read_reg(dev, P2_LCR1) & LCR_LED2_MASK) |
+ LCR_LED2_EN | LCR_LED2_LINK);
+
+ ax88796c_mdio_write(dev, PHY_ID, PHY_ANAR, MII_ADVERTISE);
+ ax88796c_mdio_write(dev, PHY_ID, PHY_BMCR,
+ PHY_BMCR_100MB | PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_halt
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static void ax88796c_halt(struct eth_device *dev)
+{
+ if (!ax88796c_claim_bus(dev)){
+ ax88796c_reset(dev);
+ ax88796c_release_bus(dev);
+ }
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_init
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static int ax88796c_init(struct eth_device *dev, bd_t * bis)
+{
+ struct ax88796c_private *ax_local =
+ (struct ax88796c_private *)dev->priv;
+
+ ax_local->seq_num = 0;
+
+ if (ax88796c_claim_bus(dev))
+ return -EBUSY;
+
+ /* Enable RX Packet process */
+ write_reg(dev, P1_RPPER, 0x01);
+
+ /* Disable RX Stuffing Padding */
+ write_reg(dev, P1_RXBSPCR, 0);
+
+ /* Byte Swap, Enable TX RX bridge */
+ write_reg(dev, P0_FER, read_reg(dev, P0_FER) |
+ FER_IPALM | FER_BSWAP | FER_RXEN | FER_TXEN);
+
+ /* Set MAC address */
+ ax88796c_set_enetaddr(dev);
+
+ /* Set Unicast + Broadcast */
+ write_reg(dev, P2_RXCR, RXCR_AB);
+
+ /* Set LED mode */
+ write_reg(dev, P2_LCR0, LCR_LED0_EN | LCR_LED0_DUPLEX |
+ LCR_LED1_EN | LCR_LED1_100MODE);
+ write_reg(dev, P2_LCR1, (read_reg(dev, P2_LCR1) & LCR_LED2_MASK) |
+ LCR_LED2_EN | LCR_LED2_LINK);
+
+ /* Init PHY auto-polling */
+ write_reg(dev, P2_POOLCR, (PHY_ID << 8) | POOLCR_POLL_EN |
+ POOLCR_POLL_BMCR);
+
+#ifdef CONFIG_AX88796C_DBG
+ printf("Dump all MAC registers after initialization:\n");
+ ax88796c_dump_regs(dev);
+ ax88796c_dump_phy_regs(dev);
+#endif
+
+ ax88796c_release_bus(dev);
+
+ return 0;
+}
+
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_nic_to_pc
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static unsigned char ax88796c_nic_to_pc(struct eth_device *dev)
+{
+ unsigned short rcphr, rxlen, burst_len, pkt_cnt;
+ unsigned long time_out;
+
+ /* check rx packet and total word count */
+ write_reg(dev, P0_RTWCR, read_reg(dev, P0_RTWCR) | RTWCR_RX_LATCH);
+
+ pkt_cnt = read_reg (dev, P0_RXBCR2) & RXBCR2_PKT_MASK;
+ if (!pkt_cnt)
+ return 0;
+
+ rcphr = read_reg(dev, P0_RCPHR);
+
+ /* Check the correctness of packet */
+ if (rcphr & RX_HDR_ERROR) {
+ write_reg(dev, P0_RXBCR1, RXBCR1_RXB_DISCARD);
+ return -EIO;
+ }
+
+ rxlen = (rcphr & RX_HDR_LEN);
+
+ if ((rxlen < 60) || (rxlen > 1518)) {
+ write_reg(dev, P0_RXBCR1, RXBCR1_RXB_DISCARD);
+ return -EIO;
+ }
+
+ /*
+ * Burst Word Count (header length + packet length has
+ * to be double word alignment)
+ */
+ burst_len = ((rxlen + sizeof(struct rx_header) + 3) & 0xFFFC) >> 1;
+ write_reg(dev, P0_RXBCR1, (burst_len | RXBCR1_RXB_START));
+
+ time_out = get_timer(0) + (CFG_HZ / 100);
+ while ((read_reg(dev, P0_RXBCR2) & RXBCR2_RXB_READY) == 0) {
+ if (get_timer(0) > time_out) {
+ write_reg(dev, P0_RXBCR1, RXBCR1_RXB_DISCARD);
+ goto error_out;
+ }
+ }
+
+ /* Receive RX Header, data and padding */
+ ax88796c_read_fifo_pio(dev, (unsigned char*)&rx_packet[0], burst_len * 2);
+
+ time_out = get_timer(0) + (CFG_HZ / 100);
+ while ((read_reg(dev, P0_RXBCR2) & RXBCR2_RXB_IDLE) == 0) {
+ if (get_timer(0) > time_out) {
+ goto error_out;
+ }
+ }
+
+ /* Pass the packet up to the protocol layers, skip the header */
+ ax88796c_release_bus(dev);
+
+ NetReceive(rx_packet + RX_HDR_SIZE, rxlen);
+
+ if (ax88796c_claim_bus(dev))
+ return -EBUSY;
+
+ return 0;
+
+error_out:
+ write_reg(dev, P0_RXBCR2, RXBCR2_RXB_REINIT);
+
+ return -EIO;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_recv
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static int ax88796c_recv(struct eth_device *dev)
+{
+ unsigned short interrupts;
+
+ if (ax88796c_claim_bus(dev))
+ return -EBUSY;
+
+ interrupts = read_reg(dev, P0_ISR);
+
+ /* Acknowledge all interrupts */
+ write_reg(dev, P0_ISR, interrupts);
+
+ if (interrupts & ISR_RXPCT)
+ ax88796c_nic_to_pc(dev);
+
+ ax88796c_release_bus(dev);
+
+ return 0;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_handle_tx_hdr
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static void ax88796c_handle_tx_hdr(struct tx_header * txhdr,
+ unsigned short len, unsigned short seq_num)
+{
+ unsigned short len_bar = (~len & TX_HDR_SOP_PKTLENBAR);
+
+ /* SOP Header */
+ txhdr->sop.flags_pktlen = cpu_to_be16(len);
+ txhdr->sop.seqnum_pktlenbar =
+ cpu_to_be16(TX_HDR_SEQNUM (seq_num) | len_bar);
+
+ /* Segment Header */
+ txhdr->seg.flags_seqnum_seglen =
+ cpu_to_be16(TX_HDR_SEG_FS | TX_HDR_SEG_LS | len);
+ txhdr->seg.eo_so_seglenbar = cpu_to_be16(len_bar);
+
+ /* EOP Header */
+ txhdr->eop.seqnum_pktlen = cpu_to_be16(TX_HDR_SEQNUM (seq_num) | len);
+ txhdr->eop.seqnumbar_pktlenbar =
+ cpu_to_be16(TX_HDR_SEQNUM(~seq_num) | len_bar);
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_send
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+static int ax88796c_send(struct eth_device *dev, volatile void *packet,
+ int length)
+{
+ unsigned long time_out;
+ unsigned char align_count;
+ unsigned char align_byte = 0xFF;
+ int i;
+
+ struct tx_header hdr;
+
+ struct ax88796c_private *ax_local =
+ (struct ax88796c_private *)dev->priv;
+
+ ax88796c_handle_tx_hdr(&hdr, length, ax_local->seq_num);
+
+ memcpy(tx_packet, &hdr, TX_HDR_SIZE);
+ memcpy(&tx_packet[TX_HDR_SIZE], (unsigned char *)packet, length);
+
+ /* Double-word alignment */
+ align_count = ((length + 3 ) & 0x7FC) - length;
+ if (align_count != 0){
+ for (i = 0; i < align_count; i++){
+ memcpy(&tx_packet[TX_HDR_SIZE + length + i], &align_byte, 1);
+ }
+ }
+
+ memcpy(&tx_packet[TX_HDR_SIZE + length + align_count], &hdr.eop, EOP_SIZE);
+
+ if (ax88796c_claim_bus(dev))
+ return -EBUSY;
+
+ write_reg(dev, P0_TSNR, TSNR_TXB_START | TSNR_PKT_CNT(1));
+
+ /* Send packet */
+ ax88796c_write_fifo_pio(dev, (unsigned char*)&tx_packet,
+ TX_HDR_SIZE + length + EOP_SIZE + align_count);
+
+ time_out = get_timer(0) + (CFG_HZ / 100);
+ while ((read_reg(dev, P0_TSNR) & TSNR_TXB_IDLE) == 0){
+ if (get_timer(0) > time_out) {
+ goto error_out;
+ }
+ }
+
+ if (read_reg(dev, P0_ISR) & ISR_TXERR)
+ goto error_out;
+
+ ax_local->seq_num++;
+ ax_local->seq_num &= 0x1F;
+
+ ax88796c_release_bus(dev);
+
+ return 0;
+
+error_out:
+ write_reg(dev, P0_TSNR, TSNR_TXB_REINIT);
+
+ ax_local->seq_num = 0;
+
+ ax88796c_release_bus(dev);
+
+ return -EBUSY;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function Name: ax88796c_spi_initialize
+ * Purpose:
+ * -----------------------------------------------------------------------------
+ */
+int ax88796c_spi_initialize(int SPI_BUS, int CS, int MAX_HZ, int MODE)
+{
+ struct eth_device *dev;
+ struct ax88796c_private *ax_local;
+
+ dev = (struct eth_device *)malloc(sizeof *dev);
+ if (NULL == dev)
+ return -EFAULT;
+
+ ax_local = (struct ax88796c_private *)malloc(sizeof *ax_local);
+ if (NULL == ax_local){
+ free(dev);
+ return -EFAULT;
+ }
+
+ memset(dev, 0, sizeof *dev);
+ memset(ax_local, 0, sizeof *ax_local);
+
+ sprintf(dev->name, "AX88796C_SPI");
+ dev->priv = ax_local;
+ dev->init = ax88796c_init;
+ dev->halt = ax88796c_halt;
+ dev->send = ax88796c_send;
+ dev->recv = ax88796c_recv;
+
+ ax_local->slave = spi_setup_slave(SPI_BUS, CS, MAX_HZ, MODE);
+ if (!ax_local->slave){
+ printf("invalid SPI device!\n");
+ free(dev);
+ free(ax_local);
+ return -ENXIO;
+ }
+
+ if (ax88796c_claim_bus(dev))
+ return -EBUSY;
+
+#ifdef CONFIG_AX88796C_DBG
+ printf("Dump all MAC registers before initialization:\n");
+ ax88796c_dump_regs(dev);
+ ax88796c_dump_phy_regs(dev);
+#endif
+
+ if (!ax88796c_reset(dev)){
+ ax88796c_bind(dev);
+ eth_register(dev);
+ }else {
+ ax88796c_release_bus(dev);
+ return -EIO;
+ }
+
+ ax88796c_release_bus(dev);
+
+ return 0;
+}
+
+#endif /* CONFIG_DRIVER_AX88796C_SPI */
--- /dev/null
+/*
+ * ASIX AX88796C Ethernet
+ * (C) Copyright 2011
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ *
+ */
+
+#include <asm/types.h>
+#include <config.h>
+
+#ifdef CONFIG_DRIVER_AX88796C_SPI
+
+struct ax88796c_private {
+ unsigned short seq_num;
+ struct spi_slave *slave;
+};
+
+/* Sturctures declaration */
+
+/* Tx headers structure */
+struct tx_sop_header {
+ u16 flags_pktlen;
+ u16 seqnum_pktlenbar;
+} __attribute__((packed));
+
+struct tx_segment_header {
+ u16 flags_seqnum_seglen;
+ u16 eo_so_seglenbar;
+} __attribute__((packed));
+
+struct tx_eop_header {
+ u16 seqnum_pktlen;
+ u16 seqnumbar_pktlenbar;
+} __attribute__((packed));
+
+struct tx_header {
+ struct tx_sop_header sop;
+ struct tx_segment_header seg;
+ struct tx_eop_header eop;
+} __attribute__((packed));
+
+struct rx_hdr1 {
+ u16 flags_len;
+ u16 seq_lenbar;
+}__attribute__((packed));
+
+struct rx_header {
+ struct rx_hdr1 hdr1;
+ u16 hdr2;
+} __attribute__((packed));
+
+#define PHY_ID 0x10
+#define MII_ADVERTISE 0x25E1
+
+/*TX Header*/
+#define TX_HDR_SEG_FS 0x8000
+#define TX_HDR_SEG_LS 0x4000
+#define TX_HDR_SOP_PKTLENBAR 0x07FF
+#define TX_HDR_SEQNUM(x) (((x) & 0x1F) << 11)
+#define TX_HDR_SIZE 8
+#define EOP_SIZE 4
+/*RX Header*/
+#define RX_HDR_ERROR 0x7000
+#define RX_HDR_LEN 0x07FF
+#define RX_HDR_SIZE 6
+
+/* SPI Operation */
+#define OP_READ_GREG 0x03
+#define OP_WRITE_GREG 0xD8
+#define OP_READ_RXQ 0x0B
+#define OP_WRITE_TXQ 0x02
+#define OP_READ_STATUS 0x05
+
+/* A88796C register definition */
+ /* Definition of PAGE0 */
+#define P0_PSR (0x00)
+ #define PSR_DEV_READY (1 << 7)
+ #define PSR_RESET (0 << 15)
+ #define PSR_RESET_CLR (1 << 15)
+#define P0_BOR (0x02)
+#define P0_FER (0x04)
+ #define FER_IPALM (1 << 0)
+ #define FER_DCRC (1 << 1)
+ #define FER_RH3M (1 << 2)
+ #define FER_HEADERSWAP (1 << 7)
+ #define FER_WSWAP (1 << 8)
+ #define FER_BSWAP (1 << 9)
+ #define FER_INTHI (1 << 10)
+ #define FER_INTLO (0 << 10)
+ #define FER_IRQ_PULL (1 << 11)
+ #define FER_RXEN (1 << 14)
+ #define FER_TXEN (1 << 15)
+#define P0_ISR (0x06)
+ #define ISR_RXPCT (1 << 0)
+ #define ISR_MDQ (1 << 4)
+ #define ISR_TXT (1 << 5)
+ #define ISR_TXPAGES (1 << 6)
+ #define ISR_TXERR (1 << 8)
+ #define ISR_LINK (1 << 9)
+#define P0_IMR (0x08)
+ #define IMR_RXPKT (1 << 0)
+ #define IMR_MDQ (1 << 4)
+ #define IMR_TXT (1 << 5)
+ #define IMR_TXPAGES (1 << 6)
+ #define IMR_TXERR (1 << 8)
+ #define IMR_LINK (1 << 9)
+ #define IMR_MASKALL (0xFFFF)
+ #define IMR_DEFAULT (IMR_TXERR)
+#define P0_WFCR (0x0A)
+ #define WFCR_PMEIND (1 << 0) /* PME indication */
+ #define WFCR_PMETYPE (1 << 1) /* PME I/O type */
+ #define WFCR_PMEPOL (1 << 2) /* PME polarity */
+ #define WFCR_PMERST (1 << 3) /* Reset PME */
+ #define WFCR_SLEEP (1 << 4) /* Enable sleep mode */
+ #define WFCR_WAKEUP (1 << 5) /* Enable wakeup mode */
+ #define WFCR_WAITEVENT (1 << 6) /* Reserved */
+ #define WFCR_CLRWAKE (1 << 7) /* Clear wakeup */
+ #define WFCR_LINKCH (1 << 8) /* Enable link change */
+ #define WFCR_MAGICP (1 << 9) /* Enable magic packet */
+ #define WFCR_WAKEF (1 << 10) /* Enable wakeup frame */
+ #define WFCR_PMEEN (1 << 11) /* Enable PME pin */
+ #define WFCR_LINKCHS (1 << 12) /* Link change status */
+ #define WFCR_MAGICPS (1 << 13) /* Magic packet status */
+ #define WFCR_WAKEFS (1 << 14) /* Wakeup frame status */
+ #define WFCR_PMES (1 << 15) /* PME pin status */
+#define P0_PSCR (0x0C)
+ #define PSCR_PS_MASK (0xFFF0)
+ #define PSCR_PS_D0 (0)
+ #define PSCR_PS_D1 (1 << 0)
+ #define PSCR_PS_D2 (1 << 1)
+ #define PSCR_FPS (1 << 3) /* Enable fiber mode PS */
+ #define PSCR_SWPS (1 << 4) /* Enable software PS control */
+ #define PSCR_WOLPS (1 << 5) /* Enable WOL PS */
+ #define PSCR_SWWOL (1 << 6) /* Enable software select WOL PS */
+ #define PSCR_PHYOSC (1 << 7) /* Internal PHY OSC control */
+ #define PSCR_FOFEF (1 << 8) /* Force PHY generate FEF */
+ #define PSCR_FOF (1 << 9) /* Force PHY in fiber mode */
+ #define PSCR_PHYPD (1 << 10) /* PHY power down. Active high */
+ #define PSCR_PHYRST (1 << 11) /* PHY reset signal. Active low */
+ #define PSCR_PHYCSIL (1 << 12) /* PHY cable energy detect */
+ #define PSCR_PHYCOFF (1 << 13) /* PHY cable off */
+ #define PSCR_PHYLINK (1 << 14) /* PHY link status */
+ #define PSCR_EEPOK (1 << 15) /* EEPROM load complete */
+#define P0_MACCR (0x0E)
+ #define MACCR_RXFC_ENABLE (1 << 3)
+ #define MACCR_RXFC_MASK 0xFFF7
+ #define MACCR_TXFC_ENABLE (1 << 4)
+ #define MACCR_TXFC_MASK 0xFFEF
+ #define MACCR_PF (1 << 7)
+ #define MACCR_PMM_BITS 8
+ #define MACCR_PMM_MASK (0x1F00)
+ #define MACCR_PMM_RESET (1 << 8)
+ #define MACCR_PMM_WAIT (2 << 8)
+ #define MACCR_PMM_READY (3 << 8)
+ #define MACCR_PMM_D1 (4 << 8)
+ #define MACCR_PMM_D2 (5 << 8)
+ #define MACCR_PMM_WAKE (7 << 8)
+ #define MACCR_PMM_D1_WAKE (8 << 8)
+ #define MACCR_PMM_D2_WAKE (9 << 8)
+ #define MACCR_PMM_SLEEP (10 << 8)
+ #define MACCR_PMM_PHY_RESET (11 << 8)
+ #define MACCR_PMM_SOFT_D1 (16 << 8)
+ #define MACCR_PMM_SOFT_D2 (17 << 8)
+#define P0_TFBFCR (0x10)
+ #define TFBFCR_SCHE_FREE_PAGE 0xE07F
+ #define TFBFCR_FREE_PAGE_BITS 0x07
+ #define TFBFCR_FREE_PAGE_LATCH (1 << 6)
+ #define TFBFCR_SET_FREE_PAGE(x) ((x & 0x3F) << TFBFCR_FREE_PAGE_BITS)
+ #define TFBFCR_TX_PAGE_SET (1 << 13)
+ #define TFBFCR_MANU_ENTX (1 << 15)
+ #define TX_FREEBUF_MASK 0x003F
+ #define TX_DPTSTART 0x4000
+#define P0_TSNR (0x12)
+ #define TSNR_TXB_ERR (1 << 5)
+ #define TSNR_TXB_IDLE (1 << 6)
+ #define TSNR_PKT_CNT(x) (((x) & 0x3F) << 8)
+ #define TSNR_TXB_REINIT (1 << 14)
+ #define TSNR_TXB_START (1 << 15)
+#define P0_RTDPR (0x14)
+#define P0_RXBCR1 (0x16)
+ #define RXBCR1_RXB_DISCARD (1 << 14)
+ #define RXBCR1_RXB_START (1 << 15)
+#define P0_RXBCR2 (0x18)
+ #define RXBCR2_PKT_MASK (0xFF)
+ #define RXBCR2_RXPC_MASK (0x7F)
+ #define RXBCR2_RXB_READY (1 << 13)
+ #define RXBCR2_RXB_IDLE (1 << 14)
+ #define RXBCR2_RXB_REINIT (1 << 15)
+#define P0_RTWCR (0x1A)
+ #define RTWCR_RXWC_MASK (0x3FFF)
+ #define RTWCR_RX_LATCH (1 << 15)
+#define P0_RCPHR (0x1C)
+
+ /* Definition of PAGE1 */
+#define P1_RPPER (0x22)
+ #define RPPER_RXEN (1 << 0)
+#define P1_MRCR (0x28)
+#define P1_MDR (0x2A)
+#define P1_RMPR (0x2C)
+#define P1_TMPR (0x2E)
+#define P1_RXBSPCR (0x30)
+ #define RXBSPCR_STUF_WORD_CNT(x) (((x) & 0x7000) >> 12)
+ #define RXBSPCR_STUF_ENABLE (1 << 15)
+#define P1_MCR (0x32)
+ #define MCR_SBP (1 << 8)
+ #define MCR_SM (1 << 9)
+ #define MCR_CRCENLAN (1 << 11)
+ #define MCR_STP (1 << 12)
+
+ /* Definition of PAGE2 */
+#define P2_CIR (0x42)
+#define P2_POOLCR (0x44)
+ #define POOLCR_POLL_EN (1 << 0)
+ #define POOLCR_POLL_FLOWCTRL (1 << 1)
+ #define POOLCR_POLL_BMCR (1 << 2)
+ #define POOLCR_PHYID(x) ((x) << 8)
+#define P2_PHYSR (0x46)
+#define P2_MDIODR (0x48)
+#define P2_MDIOCR (0x4A)
+ #define MDIOCR_RADDR(x) ((x) & 0x1F)
+ #define MDIOCR_FADDR(x) (((x) & 0x1F) << 8)
+ #define MDIOCR_VALID (1 << 13)
+ #define MDIOCR_READ (1 << 14)
+ #define MDIOCR_WRITE (1 << 15)
+#define P2_LCR0 (0x4C)
+ #define LCR_LED0_EN (1 << 0)
+ #define LCR_LED0_100MODE (1 << 1)
+ #define LCR_LED0_DUPLEX (1 << 2)
+ #define LCR_LED0_LINK (1 << 3)
+ #define LCR_LED0_ACT (1 << 4)
+ #define LCR_LED0_COL (1 << 5)
+ #define LCR_LED0_10MODE (1 << 6)
+ #define LCR_LED0_DUPCOL (1 << 7)
+ #define LCR_LED1_EN (1 << 8)
+ #define LCR_LED1_100MODE (1 << 9)
+ #define LCR_LED1_DUPLEX (1 << 10)
+ #define LCR_LED1_LINK (1 << 11)
+ #define LCR_LED1_ACT (1 << 12)
+ #define LCR_LED1_COL (1 << 13)
+ #define LCR_LED1_10MODE (1 << 14)
+ #define LCR_LED1_DUPCOL (1 << 15)
+#define P2_LCR1 (0x4E)
+ #define LCR_LED2_MASK (0xFF00)
+ #define LCR_LED2_EN (1 << 0)
+ #define LCR_LED2_100MODE (1 << 1)
+ #define LCR_LED2_DUPLEX (1 << 2)
+ #define LCR_LED2_LINK (1 << 3)
+ #define LCR_LED2_ACT (1 << 4)
+ #define LCR_LED2_COL (1 << 5)
+ #define LCR_LED2_10MODE (1 << 6)
+ #define LCR_LED2_DUPCOL (1 << 7)
+#define P2_IPGCR (0x50)
+#define P2_FLHWCR (0x54)
+#define P2_RXCR (0x56)
+ #define RXCR_PRO (1 << 0)
+ #define RXCR_AMALL (1 << 1)
+ #define RXCR_SEP (1 << 2)
+ #define RXCR_AB (1 << 3)
+ #define RXCR_AM (1 << 4)
+ #define RXCR_AP (1 << 5)
+ #define RXCR_ARP (1 << 6)
+#define P2_JLCR (0x58)
+#define P2_MPLR (0x5C)
+
+ /* Definition of PAGE3 */
+#define P3_MACASR0 (0x62)
+ #define P3_MACASR(x) (P3_MACASR0 + 2*x)
+ #define MACASR_LOWBYTE_MASK 0x00FF
+ #define MACASR_HIGH_BITS 0x08
+#define P3_MACASR1 (0x64)
+#define P3_MACASR2 (0x66)
+#define P3_MFAR01 (0x68)
+#define P3_MFAR_BASE (0x68)
+ #define P3_MFAR(x) (P3_MFAR_BASE + 2*x)
+
+#define P3_MFAR23 (0x6A)
+#define P3_MFAR45 (0x6C)
+#define P3_MFAR67 (0x6E)
+#define P3_VID0FR (0x70)
+#define P3_VID1FR (0x72)
+#define P3_EECSR (0x74)
+#define P3_EEDR (0x76)
+#define P3_EECR (0x78)
+ #define EECR_ADDR_MASK (0x00FF)
+ #define EECR_READ_ACT (1 << 8)
+ #define EECR_WRITE_ACT (1 << 9)
+ #define EECR_WRITE_DISABLE (1 << 10)
+ #define EECR_WRITE_ENABLE (1 << 11)
+ #define EECR_EE_READY (1 << 13)
+ #define EECR_RELOAD (1 << 14)
+ #define EECR_RESET (1 << 15)
+#define P3_TPCR (0x7A)
+ #define TPCR_PATT_MASK (0xFF)
+ #define TPCR_RAND_PKT_EN (1 << 14)
+ #define TPCR_FIXED_PKT_EN (1 << 15)
+#define P3_TPLR (0x7C)
+
+ /* Definition of PAGE4 */
+#define P4_SPICR (0x8A)
+ #define SPICR_RCEN (1 << 0)
+ #define SPICR_QCEN (1 << 1)
+ #define SPICR_RBRE (1 << 3)
+ #define SPICR_PMM (1 << 4)
+ #define SPICR_LOOPBACK (1 << 8)
+ #define SPICR_CORE_RES_CLR (1 << 10)
+ #define SPICR_SPI_RES_CLR (1 << 11)
+#define P4_SPIISMR (0x8C)
+
+#define P4_COERCR0 (0x92)
+ #define COERCR0_RXIPCE (1 << 0)
+ #define COERCR0_RXIPVE (1 << 1)
+ #define COERCR0_RXV6PE (1 << 2)
+ #define COERCR0_RXTCPE (1 << 3)
+ #define COERCR0_RXUDPE (1 << 4)
+ #define COERCR0_RXICMP (1 << 5)
+ #define COERCR0_RXIGMP (1 << 6)
+ #define COERCR0_RXICV6 (1 << 7)
+
+ #define COERCR0_RXTCPV6 (1 << 8)
+ #define COERCR0_RXUDPV6 (1 << 9)
+ #define COERCR0_RXICMV6 (1 << 10)
+ #define COERCR0_RXIGMV6 (1 << 11)
+ #define COERCR0_RXICV6V6 (1 << 12)
+
+ #define COERCR0_DEFAULT (COERCR0_RXIPCE | COERCR0_RXV6PE | \
+ COERCR0_RXTCPE | COERCR0_RXUDPE | \
+ COERCR0_RXTCPV6 | COERCR0_RXUDPV6)
+#define P4_COERCR1 (0x94)
+ #define COERCR1_IPCEDP (1 << 0)
+ #define COERCR1_IPVEDP (1 << 1)
+ #define COERCR1_V6VEDP (1 << 2)
+ #define COERCR1_TCPEDP (1 << 3)
+ #define COERCR1_UDPEDP (1 << 4)
+ #define COERCR1_ICMPDP (1 << 5)
+ #define COERCR1_IGMPDP (1 << 6)
+ #define COERCR1_ICV6DP (1 << 7)
+ #define COERCR1_RX64TE (1 << 8)
+ #define COERCR1_RXPPPE (1 << 9)
+ #define COERCR1_TCP6DP (1 << 10)
+ #define COERCR1_UDP6DP (1 << 11)
+ #define COERCR1_IC6DP (1 << 12)
+ #define COERCR1_IG6DP (1 << 13)
+ #define COERCR1_ICV66DP (1 << 14)
+ #define COERCR1_RPCE (1 << 15)
+
+ #define COERCR1_DEFAULT (COERCR1_RXPPPE)
+#define P4_COETCR0 (0x96)
+ #define COETCR0_TXIP (1 << 0)
+ #define COETCR0_TXTCP (1 << 1)
+ #define COETCR0_TXUDP (1 << 2)
+ #define COETCR0_TXICMP (1 << 3)
+ #define COETCR0_TXIGMP (1 << 4)
+ #define COETCR0_TXICV6 (1 << 5)
+ #define COETCR0_TXTCPV6 (1 << 8)
+ #define COETCR0_TXUDPV6 (1 << 9)
+ #define COETCR0_TXICMV6 (1 << 10)
+ #define COETCR0_TXIGMV6 (1 << 11)
+ #define COETCR0_TXICV6V6 (1 << 12)
+
+ #define COETCR0_DEFAULT (COETCR0_TXIP | COETCR0_TXTCP | \
+ COETCR0_TXUDP | COETCR0_TXTCPV6 | \
+ COETCR0_TXUDPV6)
+#define P4_COETCR1 (0x98)
+ #define COETCR1_TX64TE (1 << 0)
+ #define COETCR1_TXPPPE (1 << 1)
+
+#define P4_COECEDR (0x9A)
+#define P4_L2CECR (0x9C)
+
+ /* Definition of PAGE5 */
+#define P5_WFTR (0xA2)
+ #define WFTR_2MS (0x01)
+ #define WFTR_4MS (0x02)
+ #define WFTR_8MS (0x03)
+ #define WFTR_16MS (0x04)
+ #define WFTR_32MS (0x05)
+ #define WFTR_64MS (0x06)
+ #define WFTR_128MS (0x07)
+ #define WFTR_256MS (0x08)
+ #define WFTR_512MS (0x09)
+ #define WFTR_1024MS (0x0A)
+ #define WFTR_2048MS (0x0B)
+ #define WFTR_4096MS (0x0C)
+ #define WFTR_8192MS (0x0D)
+ #define WFTR_16384MS (0x0E)
+ #define WFTR_32768MS (0x0F)
+#define P5_WFCCR (0xA4)
+#define P5_WFCR03 (0xA6)
+ #define WFCR03_F0_EN (1 << 0)
+ #define WFCR03_F1_EN (1 << 4)
+ #define WFCR03_F2_EN (1 << 8)
+ #define WFCR03_F3_EN (1 << 12)
+#define P5_WFCR47 (0xA8)
+ #define WFCR47_F4_EN (1 << 0)
+ #define WFCR47_F5_EN (1 << 4)
+ #define WFCR47_F6_EN (1 << 8)
+ #define WFCR47_F7_EN (1 << 12)
+#define P5_WF0BMR0 (0xAA)
+#define P5_WF0BMR1 (0xAC)
+#define P5_WF0CR (0xAE)
+#define P5_WF0OBR (0xB0)
+#define P5_WF1BMR0 (0xB2)
+#define P5_WF1BMR1 (0xB4)
+#define P5_WF1CR (0xB6)
+#define P5_WF1OBR (0xB8)
+#define P5_WF2BMR0 (0xBA)
+#define P5_WF2BMR1 (0xBC)
+
+ /* Definition of PAGE6 */
+#define P6_WF2CR (0xC2)
+#define P6_WF2OBR (0xC4)
+#define P6_WF3BMR0 (0xC6)
+#define P6_WF3BMR1 (0xC8)
+#define P6_WF3CR (0xCA)
+#define P6_WF3OBR (0xCC)
+#define P6_WF4BMR0 (0xCE)
+#define P6_WF4BMR1 (0xD0)
+#define P6_WF4CR (0xD2)
+#define P6_WF4OBR (0xD4)
+#define P6_WF5BMR0 (0xD6)
+#define P6_WF5BMR1 (0xD8)
+#define P6_WF5CR (0xDA)
+#define P6_WF5OBR (0xDC)
+
+/* Definition of PAGE7 */
+#define P7_WF6BMR0 (0xE2)
+#define P7_WF6BMR1 (0xE4)
+#define P7_WF6CR (0xE6)
+#define P7_WF6OBR (0xE8)
+#define P7_WF7BMR0 (0xEA)
+#define P7_WF7BMR1 (0xEC)
+#define P7_WF7CR (0xEE)
+#define P7_WF7OBR (0xF0)
+#define P7_WFR01 (0xF2)
+#define P7_WFR23 (0xF4)
+#define P7_WFR45 (0xF6)
+#define P7_WFR67 (0xF8)
+#define P7_WFPC0 (0xFA)
+#define P7_WFPC1 (0xFC)
+
+#endif /*end of CONFIG_DRIVER_AX88796C_SPI*/