1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun natsemi.c: A U-Boot driver for the NatSemi DP8381x series.
3*4882a593Smuzhiyun Author: Mark A. Rakes (mark_rakes@vivato.net)
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun Adapted from an Etherboot driver written by:
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun Copyright (C) 2001 Entity Cyber, Inc.
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun This development of this Etherboot driver was funded by
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun Sicom Systems: http://www.sicompos.com/
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun Author: Marty Connor (mdc@thinguin.org)
14*4882a593Smuzhiyun Adapted from a Linux driver which was written by Donald Becker
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun This software may be used and distributed according to the terms
17*4882a593Smuzhiyun of the GNU Public License (GPL), incorporated herein by reference.
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun Original Copyright Notice:
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun Written/copyright 1999-2001 by Donald Becker.
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun This software may be used and distributed according to the terms of
24*4882a593Smuzhiyun the GNU General Public License (GPL), incorporated herein by reference.
25*4882a593Smuzhiyun Drivers based on or derived from this code fall under the GPL and must
26*4882a593Smuzhiyun retain the authorship, copyright and license notice. This file is not
27*4882a593Smuzhiyun a complete program and may only be used when the entire operating
28*4882a593Smuzhiyun system is licensed under the GPL. License for under other terms may be
29*4882a593Smuzhiyun available. Contact the original author for details.
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun The original author may be reached as becker@scyld.com, or at
32*4882a593Smuzhiyun Scyld Computing Corporation
33*4882a593Smuzhiyun 410 Severn Ave., Suite 210
34*4882a593Smuzhiyun Annapolis MD 21403
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun Support information and updates available at
37*4882a593Smuzhiyun http://www.scyld.com/network/netsemi.html
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun References:
40*4882a593Smuzhiyun http://www.scyld.com/expert/100mbps.html
41*4882a593Smuzhiyun http://www.scyld.com/expert/NWay.html
42*4882a593Smuzhiyun Datasheet is available from:
43*4882a593Smuzhiyun http://www.national.com/pf/DP/DP83815.html
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* Revision History
47*4882a593Smuzhiyun * October 2002 mar 1.0
48*4882a593Smuzhiyun * Initial U-Boot Release. Tested with Netgear FA311 board
49*4882a593Smuzhiyun * and dp83815 chipset on custom board
50*4882a593Smuzhiyun */
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /* Includes */
53*4882a593Smuzhiyun #include <common.h>
54*4882a593Smuzhiyun #include <malloc.h>
55*4882a593Smuzhiyun #include <net.h>
56*4882a593Smuzhiyun #include <netdev.h>
57*4882a593Smuzhiyun #include <asm/io.h>
58*4882a593Smuzhiyun #include <pci.h>
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* defines */
61*4882a593Smuzhiyun #define EEPROM_SIZE 0xb /*12 16-bit chunks, or 24 bytes*/
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #define DSIZE 0x00000FFF
64*4882a593Smuzhiyun #define ETH_ALEN 6
65*4882a593Smuzhiyun #define CRC_SIZE 4
66*4882a593Smuzhiyun #define TOUT_LOOP 500000
67*4882a593Smuzhiyun #define TX_BUF_SIZE 1536
68*4882a593Smuzhiyun #define RX_BUF_SIZE 1536
69*4882a593Smuzhiyun #define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* Offsets to the device registers.
72*4882a593Smuzhiyun Unlike software-only systems, device drivers interact with complex hardware.
73*4882a593Smuzhiyun It's not useful to define symbolic names for every register bit in the
74*4882a593Smuzhiyun device. */
75*4882a593Smuzhiyun enum register_offsets {
76*4882a593Smuzhiyun ChipCmd = 0x00,
77*4882a593Smuzhiyun ChipConfig = 0x04,
78*4882a593Smuzhiyun EECtrl = 0x08,
79*4882a593Smuzhiyun IntrMask = 0x14,
80*4882a593Smuzhiyun IntrEnable = 0x18,
81*4882a593Smuzhiyun TxRingPtr = 0x20,
82*4882a593Smuzhiyun TxConfig = 0x24,
83*4882a593Smuzhiyun RxRingPtr = 0x30,
84*4882a593Smuzhiyun RxConfig = 0x34,
85*4882a593Smuzhiyun ClkRun = 0x3C,
86*4882a593Smuzhiyun RxFilterAddr = 0x48,
87*4882a593Smuzhiyun RxFilterData = 0x4C,
88*4882a593Smuzhiyun SiliconRev = 0x58,
89*4882a593Smuzhiyun PCIPM = 0x44,
90*4882a593Smuzhiyun BasicControl = 0x80,
91*4882a593Smuzhiyun BasicStatus = 0x84,
92*4882a593Smuzhiyun /* These are from the spec, around page 78... on a separate table. */
93*4882a593Smuzhiyun PGSEL = 0xCC,
94*4882a593Smuzhiyun PMDCSR = 0xE4,
95*4882a593Smuzhiyun TSTDAT = 0xFC,
96*4882a593Smuzhiyun DSPCFG = 0xF4,
97*4882a593Smuzhiyun SDCFG = 0x8C
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /* Bit in ChipCmd. */
101*4882a593Smuzhiyun enum ChipCmdBits {
102*4882a593Smuzhiyun ChipReset = 0x100,
103*4882a593Smuzhiyun RxReset = 0x20,
104*4882a593Smuzhiyun TxReset = 0x10,
105*4882a593Smuzhiyun RxOff = 0x08,
106*4882a593Smuzhiyun RxOn = 0x04,
107*4882a593Smuzhiyun TxOff = 0x02,
108*4882a593Smuzhiyun TxOn = 0x01
109*4882a593Smuzhiyun };
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun enum ChipConfigBits {
112*4882a593Smuzhiyun LinkSts = 0x80000000,
113*4882a593Smuzhiyun HundSpeed = 0x40000000,
114*4882a593Smuzhiyun FullDuplex = 0x20000000,
115*4882a593Smuzhiyun TenPolarity = 0x10000000,
116*4882a593Smuzhiyun AnegDone = 0x08000000,
117*4882a593Smuzhiyun AnegEnBothBoth = 0x0000E000,
118*4882a593Smuzhiyun AnegDis100Full = 0x0000C000,
119*4882a593Smuzhiyun AnegEn100Both = 0x0000A000,
120*4882a593Smuzhiyun AnegDis100Half = 0x00008000,
121*4882a593Smuzhiyun AnegEnBothHalf = 0x00006000,
122*4882a593Smuzhiyun AnegDis10Full = 0x00004000,
123*4882a593Smuzhiyun AnegEn10Both = 0x00002000,
124*4882a593Smuzhiyun DuplexMask = 0x00008000,
125*4882a593Smuzhiyun SpeedMask = 0x00004000,
126*4882a593Smuzhiyun AnegMask = 0x00002000,
127*4882a593Smuzhiyun AnegDis10Half = 0x00000000,
128*4882a593Smuzhiyun ExtPhy = 0x00001000,
129*4882a593Smuzhiyun PhyRst = 0x00000400,
130*4882a593Smuzhiyun PhyDis = 0x00000200,
131*4882a593Smuzhiyun BootRomDisable = 0x00000004,
132*4882a593Smuzhiyun BEMode = 0x00000001,
133*4882a593Smuzhiyun };
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun enum TxConfig_bits {
136*4882a593Smuzhiyun TxDrthMask = 0x3f,
137*4882a593Smuzhiyun TxFlthMask = 0x3f00,
138*4882a593Smuzhiyun TxMxdmaMask = 0x700000,
139*4882a593Smuzhiyun TxMxdma_512 = 0x0,
140*4882a593Smuzhiyun TxMxdma_4 = 0x100000,
141*4882a593Smuzhiyun TxMxdma_8 = 0x200000,
142*4882a593Smuzhiyun TxMxdma_16 = 0x300000,
143*4882a593Smuzhiyun TxMxdma_32 = 0x400000,
144*4882a593Smuzhiyun TxMxdma_64 = 0x500000,
145*4882a593Smuzhiyun TxMxdma_128 = 0x600000,
146*4882a593Smuzhiyun TxMxdma_256 = 0x700000,
147*4882a593Smuzhiyun TxCollRetry = 0x800000,
148*4882a593Smuzhiyun TxAutoPad = 0x10000000,
149*4882a593Smuzhiyun TxMacLoop = 0x20000000,
150*4882a593Smuzhiyun TxHeartIgn = 0x40000000,
151*4882a593Smuzhiyun TxCarrierIgn = 0x80000000
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun enum RxConfig_bits {
155*4882a593Smuzhiyun RxDrthMask = 0x3e,
156*4882a593Smuzhiyun RxMxdmaMask = 0x700000,
157*4882a593Smuzhiyun RxMxdma_512 = 0x0,
158*4882a593Smuzhiyun RxMxdma_4 = 0x100000,
159*4882a593Smuzhiyun RxMxdma_8 = 0x200000,
160*4882a593Smuzhiyun RxMxdma_16 = 0x300000,
161*4882a593Smuzhiyun RxMxdma_32 = 0x400000,
162*4882a593Smuzhiyun RxMxdma_64 = 0x500000,
163*4882a593Smuzhiyun RxMxdma_128 = 0x600000,
164*4882a593Smuzhiyun RxMxdma_256 = 0x700000,
165*4882a593Smuzhiyun RxAcceptLong = 0x8000000,
166*4882a593Smuzhiyun RxAcceptTx = 0x10000000,
167*4882a593Smuzhiyun RxAcceptRunt = 0x40000000,
168*4882a593Smuzhiyun RxAcceptErr = 0x80000000
169*4882a593Smuzhiyun };
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* Bits in the RxMode register. */
172*4882a593Smuzhiyun enum rx_mode_bits {
173*4882a593Smuzhiyun AcceptErr = 0x20,
174*4882a593Smuzhiyun AcceptRunt = 0x10,
175*4882a593Smuzhiyun AcceptBroadcast = 0xC0000000,
176*4882a593Smuzhiyun AcceptMulticast = 0x00200000,
177*4882a593Smuzhiyun AcceptAllMulticast = 0x20000000,
178*4882a593Smuzhiyun AcceptAllPhys = 0x10000000,
179*4882a593Smuzhiyun AcceptMyPhys = 0x08000000
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun typedef struct _BufferDesc {
183*4882a593Smuzhiyun u32 link;
184*4882a593Smuzhiyun vu_long cmdsts;
185*4882a593Smuzhiyun u32 bufptr;
186*4882a593Smuzhiyun u32 software_use;
187*4882a593Smuzhiyun } BufferDesc;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /* Bits in network_desc.status */
190*4882a593Smuzhiyun enum desc_status_bits {
191*4882a593Smuzhiyun DescOwn = 0x80000000, DescMore = 0x40000000, DescIntr = 0x20000000,
192*4882a593Smuzhiyun DescNoCRC = 0x10000000, DescPktOK = 0x08000000,
193*4882a593Smuzhiyun DescSizeMask = 0xfff,
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun DescTxAbort = 0x04000000, DescTxFIFO = 0x02000000,
196*4882a593Smuzhiyun DescTxCarrier = 0x01000000, DescTxDefer = 0x00800000,
197*4882a593Smuzhiyun DescTxExcDefer = 0x00400000, DescTxOOWCol = 0x00200000,
198*4882a593Smuzhiyun DescTxExcColl = 0x00100000, DescTxCollCount = 0x000f0000,
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun DescRxAbort = 0x04000000, DescRxOver = 0x02000000,
201*4882a593Smuzhiyun DescRxDest = 0x01800000, DescRxLong = 0x00400000,
202*4882a593Smuzhiyun DescRxRunt = 0x00200000, DescRxInvalid = 0x00100000,
203*4882a593Smuzhiyun DescRxCRC = 0x00080000, DescRxAlign = 0x00040000,
204*4882a593Smuzhiyun DescRxLoop = 0x00020000, DesRxColl = 0x00010000,
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* Globals */
208*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
209*4882a593Smuzhiyun static int natsemi_debug = 0; /* 1 verbose debugging, 0 normal */
210*4882a593Smuzhiyun #endif
211*4882a593Smuzhiyun static u32 SavedClkRun;
212*4882a593Smuzhiyun static unsigned int cur_rx;
213*4882a593Smuzhiyun static unsigned int advertising;
214*4882a593Smuzhiyun static unsigned int rx_config;
215*4882a593Smuzhiyun static unsigned int tx_config;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun /* Note: transmit and receive buffers and descriptors must be
218*4882a593Smuzhiyun longword aligned */
219*4882a593Smuzhiyun static BufferDesc txd __attribute__ ((aligned(4)));
220*4882a593Smuzhiyun static BufferDesc rxd[NUM_RX_DESC] __attribute__ ((aligned(4)));
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(4)));
223*4882a593Smuzhiyun static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE]
224*4882a593Smuzhiyun __attribute__ ((aligned(4)));
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /* Function Prototypes */
227*4882a593Smuzhiyun #if 0
228*4882a593Smuzhiyun static void write_eeprom(struct eth_device *dev, long addr, int location,
229*4882a593Smuzhiyun short value);
230*4882a593Smuzhiyun #endif
231*4882a593Smuzhiyun static int read_eeprom(struct eth_device *dev, long addr, int location);
232*4882a593Smuzhiyun static int mdio_read(struct eth_device *dev, int phy_id, int location);
233*4882a593Smuzhiyun static int natsemi_init(struct eth_device *dev, bd_t * bis);
234*4882a593Smuzhiyun static void natsemi_reset(struct eth_device *dev);
235*4882a593Smuzhiyun static void natsemi_init_rxfilter(struct eth_device *dev);
236*4882a593Smuzhiyun static void natsemi_init_txd(struct eth_device *dev);
237*4882a593Smuzhiyun static void natsemi_init_rxd(struct eth_device *dev);
238*4882a593Smuzhiyun static void natsemi_set_rx_mode(struct eth_device *dev);
239*4882a593Smuzhiyun static void natsemi_check_duplex(struct eth_device *dev);
240*4882a593Smuzhiyun static int natsemi_send(struct eth_device *dev, void *packet, int length);
241*4882a593Smuzhiyun static int natsemi_poll(struct eth_device *dev);
242*4882a593Smuzhiyun static void natsemi_disable(struct eth_device *dev);
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun static struct pci_device_id supported[] = {
245*4882a593Smuzhiyun {PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815},
246*4882a593Smuzhiyun {}
247*4882a593Smuzhiyun };
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun #define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)dev->priv, a)
250*4882a593Smuzhiyun #define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun static inline int
INW(struct eth_device * dev,u_long addr)253*4882a593Smuzhiyun INW(struct eth_device *dev, u_long addr)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun return le16_to_cpu(*(vu_short *) (addr + dev->iobase));
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun static int
INL(struct eth_device * dev,u_long addr)259*4882a593Smuzhiyun INL(struct eth_device *dev, u_long addr)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun return le32_to_cpu(*(vu_long *) (addr + dev->iobase));
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun static inline void
OUTW(struct eth_device * dev,int command,u_long addr)265*4882a593Smuzhiyun OUTW(struct eth_device *dev, int command, u_long addr)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun *(vu_short *) ((addr + dev->iobase)) = cpu_to_le16(command);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun static inline void
OUTL(struct eth_device * dev,int command,u_long addr)271*4882a593Smuzhiyun OUTL(struct eth_device *dev, int command, u_long addr)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun *(vu_long *) ((addr + dev->iobase)) = cpu_to_le32(command);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /*
277*4882a593Smuzhiyun * Function: natsemi_initialize
278*4882a593Smuzhiyun *
279*4882a593Smuzhiyun * Description: Retrieves the MAC address of the card, and sets up some
280*4882a593Smuzhiyun * globals required by other routines, and initializes the NIC, making it
281*4882a593Smuzhiyun * ready to send and receive packets.
282*4882a593Smuzhiyun *
283*4882a593Smuzhiyun * Side effects:
284*4882a593Smuzhiyun * leaves the natsemi initialized, and ready to receive packets.
285*4882a593Smuzhiyun *
286*4882a593Smuzhiyun * Returns: struct eth_device *: pointer to NIC data structure
287*4882a593Smuzhiyun */
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun int
natsemi_initialize(bd_t * bis)290*4882a593Smuzhiyun natsemi_initialize(bd_t * bis)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun pci_dev_t devno;
293*4882a593Smuzhiyun int card_number = 0;
294*4882a593Smuzhiyun struct eth_device *dev;
295*4882a593Smuzhiyun u32 iobase, status, chip_config;
296*4882a593Smuzhiyun int i, idx = 0;
297*4882a593Smuzhiyun int prev_eedata;
298*4882a593Smuzhiyun u32 tmp;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun while (1) {
301*4882a593Smuzhiyun /* Find PCI device(s) */
302*4882a593Smuzhiyun if ((devno = pci_find_devices(supported, idx++)) < 0) {
303*4882a593Smuzhiyun break;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun pci_read_config_dword(devno, PCI_BASE_ADDRESS_0, &iobase);
307*4882a593Smuzhiyun iobase &= ~0x3; /* bit 1: unused and bit 0: I/O Space Indicator */
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun pci_write_config_dword(devno, PCI_COMMAND,
310*4882a593Smuzhiyun PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun /* Check if I/O accesses and Bus Mastering are enabled. */
313*4882a593Smuzhiyun pci_read_config_dword(devno, PCI_COMMAND, &status);
314*4882a593Smuzhiyun if (!(status & PCI_COMMAND_MEMORY)) {
315*4882a593Smuzhiyun printf("Error: Can not enable MEM access.\n");
316*4882a593Smuzhiyun continue;
317*4882a593Smuzhiyun } else if (!(status & PCI_COMMAND_MASTER)) {
318*4882a593Smuzhiyun printf("Error: Can not enable Bus Mastering.\n");
319*4882a593Smuzhiyun continue;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun dev = (struct eth_device *) malloc(sizeof *dev);
323*4882a593Smuzhiyun if (!dev) {
324*4882a593Smuzhiyun printf("natsemi: Can not allocate memory\n");
325*4882a593Smuzhiyun break;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun memset(dev, 0, sizeof(*dev));
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun sprintf(dev->name, "dp83815#%d", card_number);
330*4882a593Smuzhiyun dev->iobase = bus_to_phys(iobase);
331*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
332*4882a593Smuzhiyun printf("natsemi: NatSemi ns8381[56] @ %#x\n", dev->iobase);
333*4882a593Smuzhiyun #endif
334*4882a593Smuzhiyun dev->priv = (void *) devno;
335*4882a593Smuzhiyun dev->init = natsemi_init;
336*4882a593Smuzhiyun dev->halt = natsemi_disable;
337*4882a593Smuzhiyun dev->send = natsemi_send;
338*4882a593Smuzhiyun dev->recv = natsemi_poll;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun eth_register(dev);
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun card_number++;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun /* Set the latency timer for value. */
345*4882a593Smuzhiyun pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x20);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun udelay(10 * 1000);
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /* natsemi has a non-standard PM control register
350*4882a593Smuzhiyun * in PCI config space. Some boards apparently need
351*4882a593Smuzhiyun * to be brought to D0 in this manner. */
352*4882a593Smuzhiyun pci_read_config_dword(devno, PCIPM, &tmp);
353*4882a593Smuzhiyun if (tmp & (0x03 | 0x100)) {
354*4882a593Smuzhiyun /* D0 state, disable PME assertion */
355*4882a593Smuzhiyun u32 newtmp = tmp & ~(0x03 | 0x100);
356*4882a593Smuzhiyun pci_write_config_dword(devno, PCIPM, newtmp);
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun printf("natsemi: EEPROM contents:\n");
360*4882a593Smuzhiyun for (i = 0; i <= EEPROM_SIZE; i++) {
361*4882a593Smuzhiyun short eedata = read_eeprom(dev, EECtrl, i);
362*4882a593Smuzhiyun printf(" %04hx", eedata);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun printf("\n");
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /* get MAC address */
367*4882a593Smuzhiyun prev_eedata = read_eeprom(dev, EECtrl, 6);
368*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
369*4882a593Smuzhiyun int eedata = read_eeprom(dev, EECtrl, i + 7);
370*4882a593Smuzhiyun dev->enetaddr[i*2] = (eedata << 1) + (prev_eedata >> 15);
371*4882a593Smuzhiyun dev->enetaddr[i*2+1] = eedata >> 7;
372*4882a593Smuzhiyun prev_eedata = eedata;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun /* Reset the chip to erase any previous misconfiguration. */
376*4882a593Smuzhiyun OUTL(dev, ChipReset, ChipCmd);
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun advertising = mdio_read(dev, 1, 4);
379*4882a593Smuzhiyun chip_config = INL(dev, ChipConfig);
380*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
381*4882a593Smuzhiyun printf("%s: Transceiver status %#08X advertising %#08X\n",
382*4882a593Smuzhiyun dev->name, (int) INL(dev, BasicStatus), advertising);
383*4882a593Smuzhiyun printf("%s: Transceiver default autoneg. %s 10%s %s duplex.\n",
384*4882a593Smuzhiyun dev->name, chip_config & AnegMask ? "enabled, advertise" :
385*4882a593Smuzhiyun "disabled, force", chip_config & SpeedMask ? "0" : "",
386*4882a593Smuzhiyun chip_config & DuplexMask ? "full" : "half");
387*4882a593Smuzhiyun #endif
388*4882a593Smuzhiyun chip_config |= AnegEnBothBoth;
389*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
390*4882a593Smuzhiyun printf("%s: changed to autoneg. %s 10%s %s duplex.\n",
391*4882a593Smuzhiyun dev->name, chip_config & AnegMask ? "enabled, advertise" :
392*4882a593Smuzhiyun "disabled, force", chip_config & SpeedMask ? "0" : "",
393*4882a593Smuzhiyun chip_config & DuplexMask ? "full" : "half");
394*4882a593Smuzhiyun #endif
395*4882a593Smuzhiyun /*write new autoneg bits, reset phy*/
396*4882a593Smuzhiyun OUTL(dev, (chip_config | PhyRst), ChipConfig);
397*4882a593Smuzhiyun /*un-reset phy*/
398*4882a593Smuzhiyun OUTL(dev, chip_config, ChipConfig);
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* Disable PME:
401*4882a593Smuzhiyun * The PME bit is initialized from the EEPROM contents.
402*4882a593Smuzhiyun * PCI cards probably have PME disabled, but motherboard
403*4882a593Smuzhiyun * implementations may have PME set to enable WakeOnLan.
404*4882a593Smuzhiyun * With PME set the chip will scan incoming packets but
405*4882a593Smuzhiyun * nothing will be written to memory. */
406*4882a593Smuzhiyun SavedClkRun = INL(dev, ClkRun);
407*4882a593Smuzhiyun OUTL(dev, SavedClkRun & ~0x100, ClkRun);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun return card_number;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
413*4882a593Smuzhiyun The EEPROM code is for common 93c06/46 EEPROMs w/ 6bit addresses. */
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun /* Delay between EEPROM clock transitions.
416*4882a593Smuzhiyun No extra delay is needed with 33MHz PCI, but future 66MHz
417*4882a593Smuzhiyun access may need a delay. */
418*4882a593Smuzhiyun #define eeprom_delay(ee_addr) INL(dev, ee_addr)
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun enum EEPROM_Ctrl_Bits {
421*4882a593Smuzhiyun EE_ShiftClk = 0x04,
422*4882a593Smuzhiyun EE_DataIn = 0x01,
423*4882a593Smuzhiyun EE_ChipSelect = 0x08,
424*4882a593Smuzhiyun EE_DataOut = 0x02
425*4882a593Smuzhiyun };
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun #define EE_Write0 (EE_ChipSelect)
428*4882a593Smuzhiyun #define EE_Write1 (EE_ChipSelect | EE_DataIn)
429*4882a593Smuzhiyun /* The EEPROM commands include the alway-set leading bit. */
430*4882a593Smuzhiyun enum EEPROM_Cmds {
431*4882a593Smuzhiyun EE_WrEnCmd = (4 << 6), EE_WriteCmd = (5 << 6),
432*4882a593Smuzhiyun EE_ReadCmd = (6 << 6), EE_EraseCmd = (7 << 6),
433*4882a593Smuzhiyun };
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun #if 0
436*4882a593Smuzhiyun static void
437*4882a593Smuzhiyun write_eeprom(struct eth_device *dev, long addr, int location, short value)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun int i;
440*4882a593Smuzhiyun int ee_addr = (typeof(ee_addr))addr;
441*4882a593Smuzhiyun short wren_cmd = EE_WrEnCmd | 0x30; /*wren is 100 + 11XXXX*/
442*4882a593Smuzhiyun short write_cmd = location | EE_WriteCmd;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
445*4882a593Smuzhiyun printf("write_eeprom: %08x, %04hx, %04hx\n",
446*4882a593Smuzhiyun dev->iobase + ee_addr, write_cmd, value);
447*4882a593Smuzhiyun #endif
448*4882a593Smuzhiyun /* Shift the write enable command bits out. */
449*4882a593Smuzhiyun for (i = 9; i >= 0; i--) {
450*4882a593Smuzhiyun short cmdval = (wren_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
451*4882a593Smuzhiyun OUTL(dev, cmdval, ee_addr);
452*4882a593Smuzhiyun eeprom_delay(ee_addr);
453*4882a593Smuzhiyun OUTL(dev, cmdval | EE_ShiftClk, ee_addr);
454*4882a593Smuzhiyun eeprom_delay(ee_addr);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun OUTL(dev, 0, ee_addr); /*bring chip select low*/
458*4882a593Smuzhiyun OUTL(dev, EE_ShiftClk, ee_addr);
459*4882a593Smuzhiyun eeprom_delay(ee_addr);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun /* Shift the write command bits out. */
462*4882a593Smuzhiyun for (i = 9; i >= 0; i--) {
463*4882a593Smuzhiyun short cmdval = (write_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
464*4882a593Smuzhiyun OUTL(dev, cmdval, ee_addr);
465*4882a593Smuzhiyun eeprom_delay(ee_addr);
466*4882a593Smuzhiyun OUTL(dev, cmdval | EE_ShiftClk, ee_addr);
467*4882a593Smuzhiyun eeprom_delay(ee_addr);
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun for (i = 0; i < 16; i++) {
471*4882a593Smuzhiyun short cmdval = (value & (1 << i)) ? EE_Write1 : EE_Write0;
472*4882a593Smuzhiyun OUTL(dev, cmdval, ee_addr);
473*4882a593Smuzhiyun eeprom_delay(ee_addr);
474*4882a593Smuzhiyun OUTL(dev, cmdval | EE_ShiftClk, ee_addr);
475*4882a593Smuzhiyun eeprom_delay(ee_addr);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun OUTL(dev, 0, ee_addr); /*bring chip select low*/
479*4882a593Smuzhiyun OUTL(dev, EE_ShiftClk, ee_addr);
480*4882a593Smuzhiyun for (i = 0; i < 200000; i++) {
481*4882a593Smuzhiyun OUTL(dev, EE_Write0, ee_addr); /*poll for done*/
482*4882a593Smuzhiyun if (INL(dev, ee_addr) & EE_DataOut) {
483*4882a593Smuzhiyun break; /*finished*/
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun eeprom_delay(ee_addr);
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun /* Terminate the EEPROM access. */
489*4882a593Smuzhiyun OUTL(dev, EE_Write0, ee_addr);
490*4882a593Smuzhiyun OUTL(dev, 0, ee_addr);
491*4882a593Smuzhiyun return;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun #endif
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun static int
read_eeprom(struct eth_device * dev,long addr,int location)496*4882a593Smuzhiyun read_eeprom(struct eth_device *dev, long addr, int location)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun int i;
499*4882a593Smuzhiyun int retval = 0;
500*4882a593Smuzhiyun int ee_addr = (typeof(ee_addr))addr;
501*4882a593Smuzhiyun int read_cmd = location | EE_ReadCmd;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun OUTL(dev, EE_Write0, ee_addr);
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun /* Shift the read command bits out. */
506*4882a593Smuzhiyun for (i = 10; i >= 0; i--) {
507*4882a593Smuzhiyun short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
508*4882a593Smuzhiyun OUTL(dev, dataval, ee_addr);
509*4882a593Smuzhiyun eeprom_delay(ee_addr);
510*4882a593Smuzhiyun OUTL(dev, dataval | EE_ShiftClk, ee_addr);
511*4882a593Smuzhiyun eeprom_delay(ee_addr);
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun OUTL(dev, EE_ChipSelect, ee_addr);
514*4882a593Smuzhiyun eeprom_delay(ee_addr);
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun for (i = 0; i < 16; i++) {
517*4882a593Smuzhiyun OUTL(dev, EE_ChipSelect | EE_ShiftClk, ee_addr);
518*4882a593Smuzhiyun eeprom_delay(ee_addr);
519*4882a593Smuzhiyun retval |= (INL(dev, ee_addr) & EE_DataOut) ? 1 << i : 0;
520*4882a593Smuzhiyun OUTL(dev, EE_ChipSelect, ee_addr);
521*4882a593Smuzhiyun eeprom_delay(ee_addr);
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun /* Terminate the EEPROM access. */
525*4882a593Smuzhiyun OUTL(dev, EE_Write0, ee_addr);
526*4882a593Smuzhiyun OUTL(dev, 0, ee_addr);
527*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
528*4882a593Smuzhiyun if (natsemi_debug)
529*4882a593Smuzhiyun printf("read_eeprom: %08x, %08x, retval %08x\n",
530*4882a593Smuzhiyun dev->iobase + ee_addr, read_cmd, retval);
531*4882a593Smuzhiyun #endif
532*4882a593Smuzhiyun return retval;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun /* MII transceiver control section.
536*4882a593Smuzhiyun The 83815 series has an internal transceiver, and we present the
537*4882a593Smuzhiyun management registers as if they were MII connected. */
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun static int
mdio_read(struct eth_device * dev,int phy_id,int location)540*4882a593Smuzhiyun mdio_read(struct eth_device *dev, int phy_id, int location)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun if (phy_id == 1 && location < 32)
543*4882a593Smuzhiyun return INL(dev, BasicControl+(location<<2))&0xffff;
544*4882a593Smuzhiyun else
545*4882a593Smuzhiyun return 0xffff;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun /* Function: natsemi_init
549*4882a593Smuzhiyun *
550*4882a593Smuzhiyun * Description: resets the ethernet controller chip and configures
551*4882a593Smuzhiyun * registers and data structures required for sending and receiving packets.
552*4882a593Smuzhiyun *
553*4882a593Smuzhiyun * Arguments: struct eth_device *dev: NIC data structure
554*4882a593Smuzhiyun *
555*4882a593Smuzhiyun * returns: int.
556*4882a593Smuzhiyun */
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun static int
natsemi_init(struct eth_device * dev,bd_t * bis)559*4882a593Smuzhiyun natsemi_init(struct eth_device *dev, bd_t * bis)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun natsemi_reset(dev);
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun /* Disable PME:
565*4882a593Smuzhiyun * The PME bit is initialized from the EEPROM contents.
566*4882a593Smuzhiyun * PCI cards probably have PME disabled, but motherboard
567*4882a593Smuzhiyun * implementations may have PME set to enable WakeOnLan.
568*4882a593Smuzhiyun * With PME set the chip will scan incoming packets but
569*4882a593Smuzhiyun * nothing will be written to memory. */
570*4882a593Smuzhiyun OUTL(dev, SavedClkRun & ~0x100, ClkRun);
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun natsemi_init_rxfilter(dev);
573*4882a593Smuzhiyun natsemi_init_txd(dev);
574*4882a593Smuzhiyun natsemi_init_rxd(dev);
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun /* Configure the PCI bus bursts and FIFO thresholds. */
577*4882a593Smuzhiyun tx_config = TxAutoPad | TxCollRetry | TxMxdma_256 | (0x1002);
578*4882a593Smuzhiyun rx_config = RxMxdma_256 | 0x20;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
581*4882a593Smuzhiyun printf("%s: Setting TxConfig Register %#08X\n", dev->name, tx_config);
582*4882a593Smuzhiyun printf("%s: Setting RxConfig Register %#08X\n", dev->name, rx_config);
583*4882a593Smuzhiyun #endif
584*4882a593Smuzhiyun OUTL(dev, tx_config, TxConfig);
585*4882a593Smuzhiyun OUTL(dev, rx_config, RxConfig);
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun natsemi_check_duplex(dev);
588*4882a593Smuzhiyun natsemi_set_rx_mode(dev);
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun OUTL(dev, (RxOn | TxOn), ChipCmd);
591*4882a593Smuzhiyun return 1;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun /*
595*4882a593Smuzhiyun * Function: natsemi_reset
596*4882a593Smuzhiyun *
597*4882a593Smuzhiyun * Description: soft resets the controller chip
598*4882a593Smuzhiyun *
599*4882a593Smuzhiyun * Arguments: struct eth_device *dev: NIC data structure
600*4882a593Smuzhiyun *
601*4882a593Smuzhiyun * Returns: void.
602*4882a593Smuzhiyun */
603*4882a593Smuzhiyun static void
natsemi_reset(struct eth_device * dev)604*4882a593Smuzhiyun natsemi_reset(struct eth_device *dev)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun OUTL(dev, ChipReset, ChipCmd);
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun /* On page 78 of the spec, they recommend some settings for "optimum
609*4882a593Smuzhiyun performance" to be done in sequence. These settings optimize some
610*4882a593Smuzhiyun of the 100Mbit autodetection circuitry. Also, we only want to do
611*4882a593Smuzhiyun this for rev C of the chip. */
612*4882a593Smuzhiyun if (INL(dev, SiliconRev) == 0x302) {
613*4882a593Smuzhiyun OUTW(dev, 0x0001, PGSEL);
614*4882a593Smuzhiyun OUTW(dev, 0x189C, PMDCSR);
615*4882a593Smuzhiyun OUTW(dev, 0x0000, TSTDAT);
616*4882a593Smuzhiyun OUTW(dev, 0x5040, DSPCFG);
617*4882a593Smuzhiyun OUTW(dev, 0x008C, SDCFG);
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun /* Disable interrupts using the mask. */
620*4882a593Smuzhiyun OUTL(dev, 0, IntrMask);
621*4882a593Smuzhiyun OUTL(dev, 0, IntrEnable);
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun /* Function: natsemi_init_rxfilter
625*4882a593Smuzhiyun *
626*4882a593Smuzhiyun * Description: sets receive filter address to our MAC address
627*4882a593Smuzhiyun *
628*4882a593Smuzhiyun * Arguments: struct eth_device *dev: NIC data structure
629*4882a593Smuzhiyun *
630*4882a593Smuzhiyun * returns: void.
631*4882a593Smuzhiyun */
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun static void
natsemi_init_rxfilter(struct eth_device * dev)634*4882a593Smuzhiyun natsemi_init_rxfilter(struct eth_device *dev)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun int i;
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun for (i = 0; i < ETH_ALEN; i += 2) {
639*4882a593Smuzhiyun OUTL(dev, i, RxFilterAddr);
640*4882a593Smuzhiyun OUTW(dev, dev->enetaddr[i] + (dev->enetaddr[i + 1] << 8),
641*4882a593Smuzhiyun RxFilterData);
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun /*
646*4882a593Smuzhiyun * Function: natsemi_init_txd
647*4882a593Smuzhiyun *
648*4882a593Smuzhiyun * Description: initializes the Tx descriptor
649*4882a593Smuzhiyun *
650*4882a593Smuzhiyun * Arguments: struct eth_device *dev: NIC data structure
651*4882a593Smuzhiyun *
652*4882a593Smuzhiyun * returns: void.
653*4882a593Smuzhiyun */
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun static void
natsemi_init_txd(struct eth_device * dev)656*4882a593Smuzhiyun natsemi_init_txd(struct eth_device *dev)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun txd.link = (u32) 0;
659*4882a593Smuzhiyun txd.cmdsts = (u32) 0;
660*4882a593Smuzhiyun txd.bufptr = (u32) & txb[0];
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun /* load Transmit Descriptor Register */
663*4882a593Smuzhiyun OUTL(dev, (u32) & txd, TxRingPtr);
664*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
665*4882a593Smuzhiyun printf("natsemi_init_txd: TX descriptor reg loaded with: %#08X\n",
666*4882a593Smuzhiyun INL(dev, TxRingPtr));
667*4882a593Smuzhiyun #endif
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun /* Function: natsemi_init_rxd
671*4882a593Smuzhiyun *
672*4882a593Smuzhiyun * Description: initializes the Rx descriptor ring
673*4882a593Smuzhiyun *
674*4882a593Smuzhiyun * Arguments: struct eth_device *dev: NIC data structure
675*4882a593Smuzhiyun *
676*4882a593Smuzhiyun * Returns: void.
677*4882a593Smuzhiyun */
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun static void
natsemi_init_rxd(struct eth_device * dev)680*4882a593Smuzhiyun natsemi_init_rxd(struct eth_device *dev)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun int i;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun cur_rx = 0;
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun /* init RX descriptor */
687*4882a593Smuzhiyun for (i = 0; i < NUM_RX_DESC; i++) {
688*4882a593Smuzhiyun rxd[i].link =
689*4882a593Smuzhiyun cpu_to_le32((i + 1 <
690*4882a593Smuzhiyun NUM_RX_DESC) ? (u32) & rxd[i +
691*4882a593Smuzhiyun 1] : (u32) &
692*4882a593Smuzhiyun rxd[0]);
693*4882a593Smuzhiyun rxd[i].cmdsts = cpu_to_le32((u32) RX_BUF_SIZE);
694*4882a593Smuzhiyun rxd[i].bufptr = cpu_to_le32((u32) & rxb[i * RX_BUF_SIZE]);
695*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
696*4882a593Smuzhiyun printf
697*4882a593Smuzhiyun ("natsemi_init_rxd: rxd[%d]=%p link=%X cmdsts=%lX bufptr=%X\n",
698*4882a593Smuzhiyun i, &rxd[i], le32_to_cpu(rxd[i].link),
699*4882a593Smuzhiyun rxd[i].cmdsts, rxd[i].bufptr);
700*4882a593Smuzhiyun #endif
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun /* load Receive Descriptor Register */
704*4882a593Smuzhiyun OUTL(dev, (u32) & rxd[0], RxRingPtr);
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
707*4882a593Smuzhiyun printf("natsemi_init_rxd: RX descriptor register loaded with: %X\n",
708*4882a593Smuzhiyun INL(dev, RxRingPtr));
709*4882a593Smuzhiyun #endif
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun /* Function: natsemi_set_rx_mode
713*4882a593Smuzhiyun *
714*4882a593Smuzhiyun * Description:
715*4882a593Smuzhiyun * sets the receive mode to accept all broadcast packets and packets
716*4882a593Smuzhiyun * with our MAC address, and reject all multicast packets.
717*4882a593Smuzhiyun *
718*4882a593Smuzhiyun * Arguments: struct eth_device *dev: NIC data structure
719*4882a593Smuzhiyun *
720*4882a593Smuzhiyun * Returns: void.
721*4882a593Smuzhiyun */
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun static void
natsemi_set_rx_mode(struct eth_device * dev)724*4882a593Smuzhiyun natsemi_set_rx_mode(struct eth_device *dev)
725*4882a593Smuzhiyun {
726*4882a593Smuzhiyun u32 rx_mode = AcceptBroadcast | AcceptMyPhys;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun OUTL(dev, rx_mode, RxFilterAddr);
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun static void
natsemi_check_duplex(struct eth_device * dev)732*4882a593Smuzhiyun natsemi_check_duplex(struct eth_device *dev)
733*4882a593Smuzhiyun {
734*4882a593Smuzhiyun int duplex = INL(dev, ChipConfig) & FullDuplex ? 1 : 0;
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
737*4882a593Smuzhiyun printf("%s: Setting %s-duplex based on negotiated link"
738*4882a593Smuzhiyun " capability.\n", dev->name, duplex ? "full" : "half");
739*4882a593Smuzhiyun #endif
740*4882a593Smuzhiyun if (duplex) {
741*4882a593Smuzhiyun rx_config |= RxAcceptTx;
742*4882a593Smuzhiyun tx_config |= (TxCarrierIgn | TxHeartIgn);
743*4882a593Smuzhiyun } else {
744*4882a593Smuzhiyun rx_config &= ~RxAcceptTx;
745*4882a593Smuzhiyun tx_config &= ~(TxCarrierIgn | TxHeartIgn);
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun OUTL(dev, tx_config, TxConfig);
748*4882a593Smuzhiyun OUTL(dev, rx_config, RxConfig);
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun /* Function: natsemi_send
752*4882a593Smuzhiyun *
753*4882a593Smuzhiyun * Description: transmits a packet and waits for completion or timeout.
754*4882a593Smuzhiyun *
755*4882a593Smuzhiyun * Returns: void. */
natsemi_send(struct eth_device * dev,void * packet,int length)756*4882a593Smuzhiyun static int natsemi_send(struct eth_device *dev, void *packet, int length)
757*4882a593Smuzhiyun {
758*4882a593Smuzhiyun u32 i, status = 0;
759*4882a593Smuzhiyun u32 tx_status = 0;
760*4882a593Smuzhiyun u32 *tx_ptr = &tx_status;
761*4882a593Smuzhiyun vu_long *res = (vu_long *)tx_ptr;
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun /* Stop the transmitter */
764*4882a593Smuzhiyun OUTL(dev, TxOff, ChipCmd);
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
767*4882a593Smuzhiyun if (natsemi_debug)
768*4882a593Smuzhiyun printf("natsemi_send: sending %d bytes\n", (int) length);
769*4882a593Smuzhiyun #endif
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun /* set the transmit buffer descriptor and enable Transmit State Machine */
772*4882a593Smuzhiyun txd.link = cpu_to_le32(0);
773*4882a593Smuzhiyun txd.bufptr = cpu_to_le32(phys_to_bus((u32) packet));
774*4882a593Smuzhiyun txd.cmdsts = cpu_to_le32(DescOwn | length);
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun /* load Transmit Descriptor Register */
777*4882a593Smuzhiyun OUTL(dev, phys_to_bus((u32) & txd), TxRingPtr);
778*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
779*4882a593Smuzhiyun if (natsemi_debug)
780*4882a593Smuzhiyun printf("natsemi_send: TX descriptor register loaded with: %#08X\n",
781*4882a593Smuzhiyun INL(dev, TxRingPtr));
782*4882a593Smuzhiyun #endif
783*4882a593Smuzhiyun /* restart the transmitter */
784*4882a593Smuzhiyun OUTL(dev, TxOn, ChipCmd);
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun for (i = 0;
787*4882a593Smuzhiyun (*res = le32_to_cpu(txd.cmdsts)) & DescOwn;
788*4882a593Smuzhiyun i++) {
789*4882a593Smuzhiyun if (i >= TOUT_LOOP) {
790*4882a593Smuzhiyun printf
791*4882a593Smuzhiyun ("%s: tx error buffer not ready: txd.cmdsts == %#X\n",
792*4882a593Smuzhiyun dev->name, tx_status);
793*4882a593Smuzhiyun goto Done;
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun if (!(tx_status & DescPktOK)) {
798*4882a593Smuzhiyun printf("natsemi_send: Transmit error, Tx status %X.\n",
799*4882a593Smuzhiyun tx_status);
800*4882a593Smuzhiyun goto Done;
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun status = 1;
804*4882a593Smuzhiyun Done:
805*4882a593Smuzhiyun return status;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun /* Function: natsemi_poll
809*4882a593Smuzhiyun *
810*4882a593Smuzhiyun * Description: checks for a received packet and returns it if found.
811*4882a593Smuzhiyun *
812*4882a593Smuzhiyun * Arguments: struct eth_device *dev: NIC data structure
813*4882a593Smuzhiyun *
814*4882a593Smuzhiyun * Returns: 1 if packet was received.
815*4882a593Smuzhiyun * 0 if no packet was received.
816*4882a593Smuzhiyun *
817*4882a593Smuzhiyun * Side effects:
818*4882a593Smuzhiyun * Returns (copies) the packet to the array dev->packet.
819*4882a593Smuzhiyun * Returns the length of the packet.
820*4882a593Smuzhiyun */
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun static int
natsemi_poll(struct eth_device * dev)823*4882a593Smuzhiyun natsemi_poll(struct eth_device *dev)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun int retstat = 0;
826*4882a593Smuzhiyun int length = 0;
827*4882a593Smuzhiyun u32 rx_status = le32_to_cpu(rxd[cur_rx].cmdsts);
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun if (!(rx_status & (u32) DescOwn))
830*4882a593Smuzhiyun return retstat;
831*4882a593Smuzhiyun #ifdef NATSEMI_DEBUG
832*4882a593Smuzhiyun if (natsemi_debug)
833*4882a593Smuzhiyun printf("natsemi_poll: got a packet: cur_rx:%d, status:%X\n",
834*4882a593Smuzhiyun cur_rx, rx_status);
835*4882a593Smuzhiyun #endif
836*4882a593Smuzhiyun length = (rx_status & DSIZE) - CRC_SIZE;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun if ((rx_status & (DescMore | DescPktOK | DescRxLong)) != DescPktOK) {
839*4882a593Smuzhiyun printf
840*4882a593Smuzhiyun ("natsemi_poll: Corrupted packet received, buffer status = %X\n",
841*4882a593Smuzhiyun rx_status);
842*4882a593Smuzhiyun retstat = 0;
843*4882a593Smuzhiyun } else { /* give packet to higher level routine */
844*4882a593Smuzhiyun net_process_received_packet((rxb + cur_rx * RX_BUF_SIZE),
845*4882a593Smuzhiyun length);
846*4882a593Smuzhiyun retstat = 1;
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun /* return the descriptor and buffer to receive ring */
850*4882a593Smuzhiyun rxd[cur_rx].cmdsts = cpu_to_le32(RX_BUF_SIZE);
851*4882a593Smuzhiyun rxd[cur_rx].bufptr = cpu_to_le32((u32) & rxb[cur_rx * RX_BUF_SIZE]);
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun if (++cur_rx == NUM_RX_DESC)
854*4882a593Smuzhiyun cur_rx = 0;
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun /* re-enable the potentially idle receive state machine */
857*4882a593Smuzhiyun OUTL(dev, RxOn, ChipCmd);
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun return retstat;
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun /* Function: natsemi_disable
863*4882a593Smuzhiyun *
864*4882a593Smuzhiyun * Description: Turns off interrupts and stops Tx and Rx engines
865*4882a593Smuzhiyun *
866*4882a593Smuzhiyun * Arguments: struct eth_device *dev: NIC data structure
867*4882a593Smuzhiyun *
868*4882a593Smuzhiyun * Returns: void.
869*4882a593Smuzhiyun */
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun static void
natsemi_disable(struct eth_device * dev)872*4882a593Smuzhiyun natsemi_disable(struct eth_device *dev)
873*4882a593Smuzhiyun {
874*4882a593Smuzhiyun /* Disable interrupts using the mask. */
875*4882a593Smuzhiyun OUTL(dev, 0, IntrMask);
876*4882a593Smuzhiyun OUTL(dev, 0, IntrEnable);
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun /* Stop the chip's Tx and Rx processes. */
879*4882a593Smuzhiyun OUTL(dev, RxOff | TxOff, ChipCmd);
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun /* Restore PME enable bit */
882*4882a593Smuzhiyun OUTL(dev, SavedClkRun, ClkRun);
883*4882a593Smuzhiyun }
884