From f5415e3bee3a5dbb209789405597178c24dedd7e Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Mon, 7 Dec 2015 14:27:23 +0900 Subject: [PATCH] drivers: net: introduce ax88796c spi ethernet driver This patch adds an new ax88796c spi ethernet driver. This codes were imported from asix homepage without any changes. However, we need some patches to apply them into this u-boot version. Change-Id: I3042c5eb1a1012c95ae8f1b4b6eb662384c8dc26 Signed-off-by: Chanho Park --- drivers/net/Makefile | 1 + drivers/net/ax88796c_spi.c | 672 +++++++++++++++++++++++++++++++++++++ drivers/net/ax88796c_spi.h | 454 +++++++++++++++++++++++++ 3 files changed, 1127 insertions(+) create mode 100644 drivers/net/ax88796c_spi.c create mode 100644 drivers/net/ax88796c_spi.h diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 430f90cea..c1ad3d044 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -59,6 +59,7 @@ COBJS-$(CONFIG_MVGBE) += mvgbe.o COBJS-$(CONFIG_NATSEMI) += natsemi.o COBJS-$(CONFIG_DRIVER_NE2000) += ne2000.o ne2000_base.o COBJS-$(CONFIG_DRIVER_AX88796L) += ax88796.o ne2000_base.o +COBJS-$(CONFIG_DRIVER_AX88796C_SPI) += ax88796c_spi.o COBJS-$(CONFIG_DRIVER_NETARMETH) += netarm_eth.o COBJS-$(CONFIG_NETCONSOLE) += netconsole.o COBJS-$(CONFIG_NS8382X) += ns8382x.o diff --git a/drivers/net/ax88796c_spi.c b/drivers/net/ax88796c_spi.c new file mode 100644 index 000000000..6d3776cf0 --- /dev/null +++ b/drivers/net/ax88796c_spi.c @@ -0,0 +1,672 @@ +/* + * 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 +#include +#include +#include +#include +#include +#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 */ diff --git a/drivers/net/ax88796c_spi.h b/drivers/net/ax88796c_spi.h new file mode 100644 index 000000000..3f0d165f1 --- /dev/null +++ b/drivers/net/ax88796c_spi.h @@ -0,0 +1,454 @@ +/* + * 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 +#include + +#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*/ -- 2.34.1