15b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/*
25b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        Driver for the National Semiconductor DP83810 Ethernet controller.
35b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
45b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        Portions Copyright (C) 2001 Inprimis Technologies, Inc.
55b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        http://www.inprimis.com/
65b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
75b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        This driver is based (heavily) on the Linux driver for this chip
85b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        which is copyright 1999-2001 by Donald Becker.
95b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        This software has no warranties expressed or implied for any
115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        purpose.
125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        This software may be used and distributed according to the terms of
145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        the GNU General Public License (GPL), incorporated herein by reference.
155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        Drivers based on or derived from this code fall under the GPL and must
165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        retain the authorship, copyright and license notice.  This file is not
175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        a complete program and may only be used when the entire operating
185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        system is licensed under the GPL.  License for under other terms may be
195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        available.  Contact the original author for details.
205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        The original author may be reached as becker@scyld.com, or at
225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        Scyld Computing Corporation
235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        410 Severn Ave., Suite 210
245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        Annapolis MD 21403
255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project*/
265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projecttypedef unsigned char  u8;
295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projecttypedef   signed char  s8;
305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projecttypedef unsigned short u16;
315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projecttypedef   signed short s16;
325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projecttypedef unsigned int   u32;
335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projecttypedef   signed int   s32;
345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "etherboot.h"
365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "nic.h"
375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "pci.h"
385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#undef	virt_to_bus
405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define	virt_to_bus(x)          ((unsigned long)x)
415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define cpu_to_le32(val)        (val)
425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define le32_to_cpu(val)        (val)
435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define TX_RING_SIZE 1
475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define RX_RING_SIZE 4
485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define TIME_OUT     1000000
495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define PKT_BUF_SZ   1536
505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Offsets to the device registers. */
525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum register_offsets {
535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, PCIBusCfg=0x0C,
545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18,
555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    TxRingPtr=0x20, TxConfig=0x24,
565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    RxRingPtr=0x30, RxConfig=0x34,
575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C,
585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60,
595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64,
605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project};
615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Bit in ChipCmd. */
635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum ChipCmdBits {
645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    ChipReset=0x100, RxReset=0x20, TxReset=0x10, RxOff=0x08, RxOn=0x04,
655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    TxOff=0x02, TxOn=0x01,
665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project};
675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Bits in the interrupt status/mask registers. */
695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum intr_status_bits {
705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008,
715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    IntrRxIdle=0x0010, IntrRxOverrun=0x0020,
725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100,
735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    IntrTxIdle=0x0200, IntrTxUnderrun=0x0400,
745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    StatsMax=0x0800, LinkChange=0x4000,	WOLPkt=0x2000,
755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    RxResetDone=0x1000000, TxResetDone=0x2000000,
765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    IntrPCIErr=0x00f00000, IntrNormalSummary=0x0251, IntrAbnormalSummary=0xED20,
775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project};
785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Bits in the RxMode register. */
805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum rx_mode_bits {
815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0xC0000000,
825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000,
835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000,
845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project};
855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Bits in network_desc.status */
875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum desc_status_bits {
885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    DescOwn=0x80000000, DescMore=0x40000000, DescIntr=0x20000000,
895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    DescNoCRC=0x10000000,
905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    DescPktOK=0x08000000, RxTooLong=0x00400000,
915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project};
925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* The Rx and Tx buffer descriptors. */
945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstruct netdev_desc {
955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    u32 next_desc;
965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    s32 cmd_status;
975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    u32 addr;
985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project};
995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic struct FA311_DEV {
1015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned int    ioaddr;
1025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned short  vendor;
1035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned short  device;
1045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned int    cur_rx;
1055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned int    cur_tx;
1065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned int    rx_buf_sz;
1075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    volatile struct netdev_desc *rx_head_desc;
1085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    volatile struct netdev_desc rx_ring[RX_RING_SIZE] __attribute__ ((aligned (4)));
1095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    volatile struct netdev_desc tx_ring[TX_RING_SIZE] __attribute__ ((aligned (4)));
1105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} fa311_dev;
1115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int  eeprom_read(long ioaddr, int location);
1135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void init_ring(struct FA311_DEV *dev);
1145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void fa311_reset(struct nic *nic);
1155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int  fa311_poll(struct nic *nic);
1165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void fa311_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p);
1175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void fa311_disable(struct nic *nic);
1185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic char rx_packet[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned (4)));
1205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic char tx_packet[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned (4)));
1215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstruct nic * fa311_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
1235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{
1245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint            prev_eedata;
1255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint            i;
1265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint            duplex;
1275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint            tx_config;
1285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint            rx_config;
1295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectunsigned char  macaddr[6];
1305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectunsigned char  mactest;
1315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectunsigned char  pci_bus = 0;
1325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstruct FA311_DEV* dev = &fa311_dev;
1335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    if (io_addrs == 0 || *io_addrs == 0)
1355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        return (0);
1365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    memset(dev, 0, sizeof(*dev));
1375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    dev->vendor = pci->vendor;
1385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    dev->device = pci->dev_id;
1395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    dev->ioaddr = pci->membase;
1405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    /* Work around the dropped serial bit. */
1425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    prev_eedata = eeprom_read(dev->ioaddr, 6);
1435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    for (i = 0; i < 3; i++) {
1445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        int eedata = eeprom_read(dev->ioaddr, i + 7);
1455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        macaddr[i*2] = (eedata << 1) + (prev_eedata >> 15);
1465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        macaddr[i*2+1] = eedata >> 7;
1475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        prev_eedata = eedata;
1485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
1495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    mactest = 0;
1505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    for (i = 0; i < 6; i++)
1515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        mactest |= macaddr[i];
1525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    if (mactest == 0)
1535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        return (0);
1545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    for (i = 0; i < 6; i++)
1555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        nic->node_addr[i] = macaddr[i];
1565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    printf("%! ", nic->node_addr);
1575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    adjust_pci_device(pci);
1595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    fa311_reset(nic);
1615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    nic->reset = fa311_reset;
1635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    nic->disable = fa311_disable;
1645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    nic->poll = fa311_poll;
1655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    nic->transmit = fa311_transmit;
1665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    init_ring(dev);
1685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writel(virt_to_bus(dev->rx_ring), dev->ioaddr + RxRingPtr);
1705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writel(virt_to_bus(dev->tx_ring), dev->ioaddr + TxRingPtr);
1715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    for (i = 0; i < 6; i += 2)
1735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
1745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        writel(i, dev->ioaddr + RxFilterAddr);
1755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        writew(macaddr[i] + (macaddr[i+1] << 8),
1765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project               dev->ioaddr + RxFilterData);
1775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
1785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    /* Initialize other registers. */
1805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    /* Configure for standard, in-spec Ethernet. */
1815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    if (readl(dev->ioaddr + ChipConfig) & 0x20000000)
1825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {    /* Full duplex */
1835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        tx_config = 0xD0801002;
1845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        rx_config = 0x10000020;
1855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
1865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    else
1875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
1885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        tx_config = 0x10801002;
1895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        rx_config = 0x0020;
1905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
1915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writel(tx_config, dev->ioaddr + TxConfig);
1925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writel(rx_config, dev->ioaddr + RxConfig);
1935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    duplex = readl(dev->ioaddr + ChipConfig) & 0x20000000 ? 1 : 0;
1955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    if (duplex) {
1965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        rx_config |= 0x10000000;
1975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        tx_config |= 0xC0000000;
1985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    } else {
1995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        rx_config &= ~0x10000000;
2005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        tx_config &= ~0xC0000000;
2015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
2025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writew(tx_config, dev->ioaddr + TxConfig);
2035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writew(rx_config, dev->ioaddr + RxConfig);
2045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writel(AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys,
2065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project           dev->ioaddr + RxFilterAddr);
2075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writel(RxOn | TxOn, dev->ioaddr + ChipCmd);
2095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writel(4, dev->ioaddr + StatsCtrl);              /* Clear Stats */
2105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    return nic;
2115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}
2135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void fa311_reset(struct nic *nic)
2155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{
2165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectu32 chip_config;
2175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstruct FA311_DEV* dev = &fa311_dev;
2185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    /* Reset the chip to erase previous misconfiguration. */
2205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    outl(ChipReset, dev->ioaddr + ChipCmd);
2215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    if ((readl(dev->ioaddr + ChipConfig) & 0xe000) != 0xe000)
2235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
2245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        chip_config = readl(dev->ioaddr + ChipConfig);
2255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
2265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}
2275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int fa311_poll(struct nic *nic)
2295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{
2305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projects32 desc_status;
2315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint to;
2325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint entry;
2335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint retcode;
2345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstruct FA311_DEV* dev = &fa311_dev;
2355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    retcode = 0;
2375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    entry = dev->cur_rx;
2385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    to = TIME_OUT;
2395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    while (to != 0)
2405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
2415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        desc_status = dev->rx_ring[entry].cmd_status;
2425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        if ((desc_status & DescOwn) != 0)
2435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project            break;
2445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        else
2455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project            --to;
2465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
2475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    if (to != 0)
2485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
2495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        readl(dev->ioaddr + IntrStatus);         /* clear interrrupt bits */
2505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        /* driver owns the next entry it's a new packet. Send it up. */
2515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        if ((desc_status & (DescMore|DescPktOK|RxTooLong)) == DescPktOK)
2525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        {
2535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project            nic->packetlen = (desc_status & 0x0fff) - 4;    /* Omit CRC size. */
2545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project            memcpy(nic->packet, (char*)(dev->rx_ring[entry].addr), nic->packetlen);
2555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project            retcode = 1;
2565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        }
2575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        /* Give the descriptor back to the chip */
2585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        dev->rx_ring[entry].cmd_status = cpu_to_le32(dev->rx_buf_sz);
2595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        dev->cur_rx++;
2605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        if (dev->cur_rx >= RX_RING_SIZE)
2615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project            dev->cur_rx = 0;
2625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        dev->rx_head_desc = &dev->rx_ring[dev->cur_rx];
2635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
2645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    /* Restart Rx engine if stopped. */
2655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writel(RxOn, dev->ioaddr + ChipCmd);
2665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    return retcode;
2675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}
2685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void fa311_transmit(struct nic *nic, const char *destaddr, unsigned int type, unsigned int len, const char *data)
2705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{
2715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectunsigned short nstype;
2725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projects32            desc_status;
2735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint            to;
2745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint            entry;
2755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectchar*          txp;
2765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectunsigned char* s;
2775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstruct FA311_DEV* dev = &fa311_dev;
2785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    /* Calculate the next Tx descriptor entry. */
2805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    entry = dev->cur_tx;
2815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    txp = (char*)(dev->tx_ring[entry].addr);
2825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    memcpy(txp, destaddr, ETH_ALEN);
2845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    memcpy(txp + ETH_ALEN, nic->node_addr, ETH_ALEN);
2855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    nstype = htons(type);
2865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    memcpy(txp + 12, (char*)&nstype, 2);
2875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    memcpy(txp + ETH_HLEN, data, len);
2885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    len += ETH_HLEN;
2895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    /* pad frame */
2905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    if (len <  ETH_ZLEN)
2915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
2925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        s = (unsigned char*)(txp+len);
2935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        while (s < (unsigned char*)(txp+ETH_ZLEN))
2945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project            *s++ = 0;
2955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        len = ETH_ZLEN;
2965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
2975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    dev->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | len);
2985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    dev->cur_tx++;
2995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    if (dev->cur_tx >= TX_RING_SIZE)
3005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        dev->cur_tx = 0;
3015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    /* Wake the potentially-idle transmit channel. */
3035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writel(TxOn, dev->ioaddr + ChipCmd);
3045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    /* wait for tranmission to complete */
3065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    to = TIME_OUT;
3075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    while (to != 0)
3085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
3095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        desc_status = dev->tx_ring[entry].cmd_status;
3105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        if ((desc_status & DescOwn) == 0)
3115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project            break;
3125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        else
3135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project            --to;
3145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
3155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    readl(dev->ioaddr + IntrStatus);         /* clear interrrupt bits */
3175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    return;
3185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}
3195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void fa311_disable(struct nic *nic)
3215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{
3225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstruct FA311_DEV* dev = &fa311_dev;
3235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    /* Stop the chip's Tx and Rx processes. */
3255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    writel(RxOff | TxOff, dev->ioaddr + ChipCmd);
3265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}
3275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
3305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. */
3315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Delay between EEPROM clock transitions.
3335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
3345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   a delay.  Note that pre-2.0.34 kernels had a cache-alignment bug that
3355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   made udelay() unreliable.
3365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
3375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   depricated.
3385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project*/
3395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define eeprom_delay(ee_addr)	inl(ee_addr)
3405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum EEPROM_Ctrl_Bits {
3425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02,
3435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project};
3445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_Write0 (EE_ChipSelect)
3455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define EE_Write1 (EE_ChipSelect | EE_DataIn)
3465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* The EEPROM commands include the alway-set leading bit. */
3485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectenum EEPROM_Cmds {
3495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
3505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project};
3515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int eeprom_read(long addr, int location)
3545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{
3555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	int i;
3565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	int retval = 0;
3575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	int ee_addr = addr + EECtrl;
3585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	int read_cmd = location | EE_ReadCmd;
3595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	writel(EE_Write0, ee_addr);
3605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	/* Shift the read command bits out. */
3625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	for (i = 10; i >= 0; i--) {
3635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
3645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		writel(dataval, ee_addr);
3655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		eeprom_delay(ee_addr);
3665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		writel(dataval | EE_ShiftClk, ee_addr);
3675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		eeprom_delay(ee_addr);
3685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	}
3695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	writel(EE_ChipSelect, ee_addr);
3705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	eeprom_delay(ee_addr);
3715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	for (i = 0; i < 16; i++) {
3735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
3745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		eeprom_delay(ee_addr);
3755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		retval |= (readl(ee_addr) & EE_DataOut) ? 1 << i : 0;
3765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		writel(EE_ChipSelect, ee_addr);
3775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		eeprom_delay(ee_addr);
3785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	}
3795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	/* Terminate the EEPROM access. */
3815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	writel(EE_Write0, ee_addr);
3825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	writel(0, ee_addr);
3835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	return retval;
3845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}
3855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
3875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void init_ring(struct FA311_DEV *dev)
3885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{
3895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	int i;
3905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	dev->cur_rx = 0;
3925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    dev->cur_tx = 0;
3935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	dev->rx_buf_sz = PKT_BUF_SZ;
3955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	dev->rx_head_desc = &dev->rx_ring[0];
3965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	/* Initialize all Rx descriptors. */
3985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	for (i = 0; i < RX_RING_SIZE; i++) {
3995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		dev->rx_ring[i].next_desc = virt_to_le32desc(&dev->rx_ring[i+1]);
4005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		dev->rx_ring[i].cmd_status = DescOwn;
4015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	}
4025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	/* Mark the last entry as wrapping the ring. */
4035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	dev->rx_ring[i-1].next_desc = virt_to_le32desc(&dev->rx_ring[0]);
4045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
4055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
4065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	for (i = 0; i < RX_RING_SIZE; i++) {
4075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		dev->rx_ring[i].addr = (u32)(&rx_packet[PKT_BUF_SZ * i]);
4085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    dev->rx_ring[i].cmd_status = cpu_to_le32(dev->rx_buf_sz);
4095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	}
4105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
4115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	for (i = 0; i < TX_RING_SIZE; i++) {
4125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		dev->tx_ring[i].next_desc = virt_to_le32desc(&dev->tx_ring[i+1]);
4135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		dev->tx_ring[i].cmd_status = 0;
4145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	}
4155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	dev->tx_ring[i-1].next_desc = virt_to_le32desc(&dev->tx_ring[0]);
4165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
4175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	for (i = 0; i < TX_RING_SIZE; i++)
4185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		dev->tx_ring[i].addr = (u32)(&tx_packet[PKT_BUF_SZ * i]);
4195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	return;
4205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}
4215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
422