xref: /OK3568_Linux_fs/u-boot/drivers/net/natsemi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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