xref: /inferno-os/os/boot/puma/ether8900.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1*74a4d8c2SCharles.Forsyth /*
2*74a4d8c2SCharles.Forsyth  * Crystal CS8900 ethernet controller
3*74a4d8c2SCharles.Forsyth  * Specifically for the Teralogic Puma architecture
4*74a4d8c2SCharles.Forsyth  */
5*74a4d8c2SCharles.Forsyth 
6*74a4d8c2SCharles.Forsyth #include "u.h"
7*74a4d8c2SCharles.Forsyth #include "lib.h"
8*74a4d8c2SCharles.Forsyth #include "mem.h"
9*74a4d8c2SCharles.Forsyth #include "dat.h"
10*74a4d8c2SCharles.Forsyth #include "fns.h"
11*74a4d8c2SCharles.Forsyth #include "io.h"
12*74a4d8c2SCharles.Forsyth 
13*74a4d8c2SCharles.Forsyth #include "ether.h"
14*74a4d8c2SCharles.Forsyth #include "puma.h"
15*74a4d8c2SCharles.Forsyth 
16*74a4d8c2SCharles.Forsyth /*
17*74a4d8c2SCharles.Forsyth  * On the Puma board the CS8900 can be addressed from either
18*74a4d8c2SCharles.Forsyth  * ISA I/O space or ISA memory space at the following locations.
19*74a4d8c2SCharles.Forsyth  * The cs8900 address pins are shifted by 1 relative to the CPU.
20*74a4d8c2SCharles.Forsyth  */
21*74a4d8c2SCharles.Forsyth enum {
22*74a4d8c2SCharles.Forsyth 	IsaIOBase		= 0xf0000000,
23*74a4d8c2SCharles.Forsyth 	IsaMemBase	= 0xe0000000,
24*74a4d8c2SCharles.Forsyth 
25*74a4d8c2SCharles.Forsyth 	IOBase		= 0x300,
26*74a4d8c2SCharles.Forsyth 	MemBase		= 0xc0000,
27*74a4d8c2SCharles.Forsyth };
28*74a4d8c2SCharles.Forsyth 
29*74a4d8c2SCharles.Forsyth /* I/O accesses */
30*74a4d8c2SCharles.Forsyth #define	out16(port, val)	(*((ushort *)IsaIOBase + IOBase + (port)) = (val))
31*74a4d8c2SCharles.Forsyth #define	in16(port)			*((ushort *)IsaIOBase + IOBase + (port))
32*74a4d8c2SCharles.Forsyth #define	in8(port)			*((uchar *)IsaIOBase + ((IOBase+(port))<<1))
33*74a4d8c2SCharles.Forsyth #define	regIOw(reg, val)	 do {out16(PpPtr, (reg)|0x3000); out16(PpData, val);} while(0)
34*74a4d8c2SCharles.Forsyth #define	regIOr(reg)		(out16(PpPtr, (reg)|0x3000), in16(PpData))
35*74a4d8c2SCharles.Forsyth #define	regIOr1(reg)		(out16(PpPtr, (reg)|0x3000), in16(PpData1))
36*74a4d8c2SCharles.Forsyth 
37*74a4d8c2SCharles.Forsyth /* Memory accesses */
38*74a4d8c2SCharles.Forsyth #define	regw(reg, val)		*((ushort *)IsaMemBase + MemBase + (reg)) = (val)
39*74a4d8c2SCharles.Forsyth #define	regr(reg)			*((ushort *)IsaMemBase + MemBase + (reg))
40*74a4d8c2SCharles.Forsyth 
41*74a4d8c2SCharles.Forsyth /* Puma frame copying */
42*74a4d8c2SCharles.Forsyth #define	copyout(src, len)	{ \
43*74a4d8c2SCharles.Forsyth 						int _len = (len); \
44*74a4d8c2SCharles.Forsyth 						ushort *_src = (ushort *)(src); \
45*74a4d8c2SCharles.Forsyth 						ushort *_dst = (ushort *)IsaMemBase + MemBase + TxFrame; \
46*74a4d8c2SCharles.Forsyth 						while(_len > 0) { \
47*74a4d8c2SCharles.Forsyth 							*_dst++ = *_src++; \
48*74a4d8c2SCharles.Forsyth 							_dst++; \
49*74a4d8c2SCharles.Forsyth 							_len -= 2; \
50*74a4d8c2SCharles.Forsyth 						} \
51*74a4d8c2SCharles.Forsyth 					}
52*74a4d8c2SCharles.Forsyth #define	copyoutIO(src, len)	{ \
53*74a4d8c2SCharles.Forsyth 						int _len = (len); \
54*74a4d8c2SCharles.Forsyth 						ushort *_src = (ushort *)(src); \
55*74a4d8c2SCharles.Forsyth 						while(_len > 0) { \
56*74a4d8c2SCharles.Forsyth 							out16(RxTxData, *_src); \
57*74a4d8c2SCharles.Forsyth 							_src++; \
58*74a4d8c2SCharles.Forsyth 							_len -= 2; \
59*74a4d8c2SCharles.Forsyth 						} \
60*74a4d8c2SCharles.Forsyth 					}
61*74a4d8c2SCharles.Forsyth #define	copyin(dst, len)	{ \
62*74a4d8c2SCharles.Forsyth 						int _len = (len), _len2 = (len)&~1; \
63*74a4d8c2SCharles.Forsyth 						ushort *_src = (ushort *)IsaMemBase + MemBase + RxFrame; \
64*74a4d8c2SCharles.Forsyth 						ushort *_dst = (ushort *)(dst); \
65*74a4d8c2SCharles.Forsyth 						while(_len2 > 0) { \
66*74a4d8c2SCharles.Forsyth 							*_dst++ = *_src++; \
67*74a4d8c2SCharles.Forsyth 							_src++; \
68*74a4d8c2SCharles.Forsyth 							_len2 -= 2; \
69*74a4d8c2SCharles.Forsyth 						} \
70*74a4d8c2SCharles.Forsyth 						if(_len&1) \
71*74a4d8c2SCharles.Forsyth 							*(uchar*)_dst = (*_src)&0xff; \
72*74a4d8c2SCharles.Forsyth 					}
73*74a4d8c2SCharles.Forsyth #define	copyinIO(dst, len)	{ \
74*74a4d8c2SCharles.Forsyth 						int _i, _len = (len), _len2 = (len)&~1; \
75*74a4d8c2SCharles.Forsyth 						ushort *_dst = (ushort *)(dst); \
76*74a4d8c2SCharles.Forsyth 						_i = in16(RxTxData); USED(_i); /* RxStatus */ \
77*74a4d8c2SCharles.Forsyth 						_i = in16(RxTxData); USED(_i); /* RxLen */ \
78*74a4d8c2SCharles.Forsyth 						while(_len2 > 0) { \
79*74a4d8c2SCharles.Forsyth 							*_dst++ = in16(RxTxData); \
80*74a4d8c2SCharles.Forsyth 							_len2 -= 2; \
81*74a4d8c2SCharles.Forsyth 						} \
82*74a4d8c2SCharles.Forsyth 						if(_len&1) \
83*74a4d8c2SCharles.Forsyth 							*(uchar*)_dst = (in16(RxTxData))&0xff; \
84*74a4d8c2SCharles.Forsyth 					}
85*74a4d8c2SCharles.Forsyth 
86*74a4d8c2SCharles.Forsyth 
87*74a4d8c2SCharles.Forsyth 
88*74a4d8c2SCharles.Forsyth enum {					/* I/O Mode Register Offsets */
89*74a4d8c2SCharles.Forsyth 	RxTxData	= 0x00,		/* receive/transmit data - port 0 */
90*74a4d8c2SCharles.Forsyth 	TxCmdIO = 0x04,		/* transmit command */
91*74a4d8c2SCharles.Forsyth 	TxLenIO	= 0x06,		/* transmit length */
92*74a4d8c2SCharles.Forsyth 	IsqIO	= 0x08,		/* Interrupt status queue */
93*74a4d8c2SCharles.Forsyth 	PpPtr	= 0x0a,		/* packet page pointer */
94*74a4d8c2SCharles.Forsyth 	PpData	= 0x0c,		/* packet page data */
95*74a4d8c2SCharles.Forsyth 	PpData1	= 0x0e,		/* packet page data - port 1*/
96*74a4d8c2SCharles.Forsyth };
97*74a4d8c2SCharles.Forsyth 
98*74a4d8c2SCharles.Forsyth enum {					/* Memory Mode Register Offsets */
99*74a4d8c2SCharles.Forsyth 	/* Bus Interface Registers */
100*74a4d8c2SCharles.Forsyth 	Ern		= 0x0000,		/* EISA registration numberion */
101*74a4d8c2SCharles.Forsyth 	Pic		= 0x0002,		/* Product identification code */
102*74a4d8c2SCharles.Forsyth 	Iob		= 0x0020,		/* I/O base address */
103*74a4d8c2SCharles.Forsyth 	Intr		= 0x0022,		/* interrupt number */
104*74a4d8c2SCharles.Forsyth 	Mba		= 0x002c,		/* memory base address */
105*74a4d8c2SCharles.Forsyth 
106*74a4d8c2SCharles.Forsyth 	Ecr		= 0x0040,		/* EEPROM command register */
107*74a4d8c2SCharles.Forsyth 	Edw		= 0x0042,		/* EEPROM data word */
108*74a4d8c2SCharles.Forsyth 	Rbc		= 0x0050,		/* receive frame byte counter */
109*74a4d8c2SCharles.Forsyth 
110*74a4d8c2SCharles.Forsyth 	/* Status and Control Registers */
111*74a4d8c2SCharles.Forsyth 	RxCfg	= 0x0102,
112*74a4d8c2SCharles.Forsyth 	RxCtl	= 0x0104,
113*74a4d8c2SCharles.Forsyth 	TxCfg	= 0x0106,
114*74a4d8c2SCharles.Forsyth 	BufCfg	= 0x010a,
115*74a4d8c2SCharles.Forsyth 	LineCtl	= 0x0112,
116*74a4d8c2SCharles.Forsyth 	SelfCtl	= 0x0114,
117*74a4d8c2SCharles.Forsyth 	BusCtl	= 0x0116,
118*74a4d8c2SCharles.Forsyth 	TestCtl	= 0x0118,
119*74a4d8c2SCharles.Forsyth 	Isq		= 0x0120,
120*74a4d8c2SCharles.Forsyth 	RxEvent	= 0x0124,
121*74a4d8c2SCharles.Forsyth 	TxEvent	= 0x0128,
122*74a4d8c2SCharles.Forsyth 	BufEvent	= 0x012c,
123*74a4d8c2SCharles.Forsyth 	RxMISS	= 0x0130,
124*74a4d8c2SCharles.Forsyth 	TxCol	= 0x0132,
125*74a4d8c2SCharles.Forsyth 	LineSt	= 0x0134,
126*74a4d8c2SCharles.Forsyth 	SelfSt	= 0x0136,
127*74a4d8c2SCharles.Forsyth 	BusSt	= 0x0138,
128*74a4d8c2SCharles.Forsyth 	Tdr		= 0x013c,
129*74a4d8c2SCharles.Forsyth 
130*74a4d8c2SCharles.Forsyth 	/* Initiate Transmit Registers */
131*74a4d8c2SCharles.Forsyth 	TxCmd	= 0x0144,		/* transmit command */
132*74a4d8c2SCharles.Forsyth 	TxLen	= 0x0146,		/* transmit length */
133*74a4d8c2SCharles.Forsyth 
134*74a4d8c2SCharles.Forsyth 	/* Address Filter Registers */
135*74a4d8c2SCharles.Forsyth 	IndAddr	= 0x0158,		/* individual address registers */
136*74a4d8c2SCharles.Forsyth 
137*74a4d8c2SCharles.Forsyth 	/* Frame Location */
138*74a4d8c2SCharles.Forsyth 	RxStatus	= 0x0400,		/* receive status */
139*74a4d8c2SCharles.Forsyth 	RxLen	= 0x0402,		/* receive length */
140*74a4d8c2SCharles.Forsyth 	RxFrame	= 0x0404,		/* receive frame location */
141*74a4d8c2SCharles.Forsyth 	TxFrame	= 0x0a00,		/* transmit frame location */
142*74a4d8c2SCharles.Forsyth };
143*74a4d8c2SCharles.Forsyth 
144*74a4d8c2SCharles.Forsyth enum {					/* Ecr */
145*74a4d8c2SCharles.Forsyth 	Addr			= 0x00ff,		/* EEPROM word address (field) */
146*74a4d8c2SCharles.Forsyth 	Opcode		= 0x0300,		/* command opcode (field) */
147*74a4d8c2SCharles.Forsyth };
148*74a4d8c2SCharles.Forsyth 
149*74a4d8c2SCharles.Forsyth enum {					/* Isq */
150*74a4d8c2SCharles.Forsyth 	Regnum		= 0x003f,		/* register number held by Isq (field) */
151*74a4d8c2SCharles.Forsyth 		IsqRxEvent	= 0x04,
152*74a4d8c2SCharles.Forsyth 		IsqTxEvent	= 0x08,
153*74a4d8c2SCharles.Forsyth 		IsqBufEvent	= 0x0c,
154*74a4d8c2SCharles.Forsyth 		IsqRxMiss		= 0x10,
155*74a4d8c2SCharles.Forsyth 		IsqTxCol		= 0x12,
156*74a4d8c2SCharles.Forsyth 	RegContent 	= 0xffc0,		/* register data contents (field) */
157*74a4d8c2SCharles.Forsyth };
158*74a4d8c2SCharles.Forsyth 
159*74a4d8c2SCharles.Forsyth enum {					/* RxCfg */
160*74a4d8c2SCharles.Forsyth 	Skip_1		= 0x0040,
161*74a4d8c2SCharles.Forsyth 	StreamE		= 0x0080,
162*74a4d8c2SCharles.Forsyth 	RxOKiE		= 0x0100,
163*74a4d8c2SCharles.Forsyth 	RxDMAonly	= 0x0200,
164*74a4d8c2SCharles.Forsyth 	AutoRxDMAE	= 0x0400,
165*74a4d8c2SCharles.Forsyth 	BufferCRC		= 0x0800,
166*74a4d8c2SCharles.Forsyth 	CRCerroriE	= 0x1000,
167*74a4d8c2SCharles.Forsyth 	RuntiE		= 0x2000,
168*74a4d8c2SCharles.Forsyth 	ExtradataiE	= 0x4000,
169*74a4d8c2SCharles.Forsyth };
170*74a4d8c2SCharles.Forsyth 
171*74a4d8c2SCharles.Forsyth enum {					/* RxEvent */
172*74a4d8c2SCharles.Forsyth 	IAHash		= 0x0040,
173*74a4d8c2SCharles.Forsyth 	Dribblebits	= 0x0080,
174*74a4d8c2SCharles.Forsyth 	RxOK		= 0x0100,
175*74a4d8c2SCharles.Forsyth 	Hashed		= 0x0200,
176*74a4d8c2SCharles.Forsyth 	IndividualAdr	= 0x0400,
177*74a4d8c2SCharles.Forsyth 	Broadcast		= 0x0800,
178*74a4d8c2SCharles.Forsyth 	CRCerror		= 0x1000,
179*74a4d8c2SCharles.Forsyth 	Runt			= 0x2000,
180*74a4d8c2SCharles.Forsyth 	Extradata		= 0x4000,
181*74a4d8c2SCharles.Forsyth };
182*74a4d8c2SCharles.Forsyth 
183*74a4d8c2SCharles.Forsyth enum {					/* RxCtl */
184*74a4d8c2SCharles.Forsyth 	IAHashA		= 0x0040,
185*74a4d8c2SCharles.Forsyth 	PromiscuousA	= 0x0080,
186*74a4d8c2SCharles.Forsyth 	RxOKA		= 0x0100,
187*74a4d8c2SCharles.Forsyth 	MulticastA	= 0x0200,
188*74a4d8c2SCharles.Forsyth 	IndividualA	= 0x0400,
189*74a4d8c2SCharles.Forsyth 	BroadcastA	= 0x0800,
190*74a4d8c2SCharles.Forsyth 	CRCerrorA	= 0x1000,
191*74a4d8c2SCharles.Forsyth 	RuntA		= 0x2000,
192*74a4d8c2SCharles.Forsyth 	ExtradataA	= 0x4000,
193*74a4d8c2SCharles.Forsyth };
194*74a4d8c2SCharles.Forsyth 
195*74a4d8c2SCharles.Forsyth enum {					/* TxCfg */
196*74a4d8c2SCharles.Forsyth 	LossofCRSiE	= 0x0040,
197*74a4d8c2SCharles.Forsyth 	SQEerroriE	= 0x0080,
198*74a4d8c2SCharles.Forsyth 	TxOKiE		= 0x0100,
199*74a4d8c2SCharles.Forsyth 	OutofWindowiE	= 0x0200,
200*74a4d8c2SCharles.Forsyth 	JabberiE		= 0x0400,
201*74a4d8c2SCharles.Forsyth 	AnycolliE		= 0x0800,
202*74a4d8c2SCharles.Forsyth 	Coll16iE		= 0x8000,
203*74a4d8c2SCharles.Forsyth };
204*74a4d8c2SCharles.Forsyth 
205*74a4d8c2SCharles.Forsyth enum {					/* TxEvent */
206*74a4d8c2SCharles.Forsyth 	LossofCRS	= 0x0040,
207*74a4d8c2SCharles.Forsyth 	SQEerror		= 0x0080,
208*74a4d8c2SCharles.Forsyth 	TxOK		= 0x0100,
209*74a4d8c2SCharles.Forsyth 	OutofWindow	= 0x0200,
210*74a4d8c2SCharles.Forsyth 	Jabber		= 0x0400,
211*74a4d8c2SCharles.Forsyth 	NTxCols		= 0x7800,		/* number of Tx collisions (field) */
212*74a4d8c2SCharles.Forsyth 	coll16		= 0x8000,
213*74a4d8c2SCharles.Forsyth };
214*74a4d8c2SCharles.Forsyth 
215*74a4d8c2SCharles.Forsyth enum {					/* BufCfg */
216*74a4d8c2SCharles.Forsyth 	SWintX		= 0x0040,
217*74a4d8c2SCharles.Forsyth 	RxDMAiE		= 0x0080,
218*74a4d8c2SCharles.Forsyth 	Rdy4TxiE		= 0x0100,
219*74a4d8c2SCharles.Forsyth 	TxUnderruniE	= 0x0200,
220*74a4d8c2SCharles.Forsyth 	RxMissiE		= 0x0400,
221*74a4d8c2SCharles.Forsyth 	Rx128iE		= 0x0800,
222*74a4d8c2SCharles.Forsyth 	TxColOvfiE	= 0x1000,
223*74a4d8c2SCharles.Forsyth 	MissOvfloiE	= 0x2000,
224*74a4d8c2SCharles.Forsyth 	RxDestiE		= 0x8000,
225*74a4d8c2SCharles.Forsyth };
226*74a4d8c2SCharles.Forsyth 
227*74a4d8c2SCharles.Forsyth enum {					/* BufEvent */
228*74a4d8c2SCharles.Forsyth 	SWint		= 0x0040,
229*74a4d8c2SCharles.Forsyth 	RxDMAFrame	= 0x0080,
230*74a4d8c2SCharles.Forsyth 	Rdy4Tx		= 0x0100,
231*74a4d8c2SCharles.Forsyth 	TxUnderrun	= 0x0200,
232*74a4d8c2SCharles.Forsyth 	RxMiss		= 0x0400,
233*74a4d8c2SCharles.Forsyth 	Rx128		= 0x0800,
234*74a4d8c2SCharles.Forsyth 	RxDest		= 0x8000,
235*74a4d8c2SCharles.Forsyth };
236*74a4d8c2SCharles.Forsyth 
237*74a4d8c2SCharles.Forsyth enum {					/* RxMiss */
238*74a4d8c2SCharles.Forsyth 	MissCount	= 0xffc0,
239*74a4d8c2SCharles.Forsyth };
240*74a4d8c2SCharles.Forsyth 
241*74a4d8c2SCharles.Forsyth enum {					/* TxCol */
242*74a4d8c2SCharles.Forsyth 	ColCount	= 0xffc0,
243*74a4d8c2SCharles.Forsyth };
244*74a4d8c2SCharles.Forsyth 
245*74a4d8c2SCharles.Forsyth enum {					/* LineCtl */
246*74a4d8c2SCharles.Forsyth 	SerRxOn		= 0x0040,
247*74a4d8c2SCharles.Forsyth 	SerTxOn		= 0x0080,
248*74a4d8c2SCharles.Forsyth 	Iface			= 0x0300,		/* (field) 01 - AUI, 00 - 10BASE-T, 10 - Auto select */
249*74a4d8c2SCharles.Forsyth 	ModBackoffE	= 0x0800,
250*74a4d8c2SCharles.Forsyth 	PolarityDis	= 0x1000,
251*74a4d8c2SCharles.Forsyth 	DefDis		= 0x2000,
252*74a4d8c2SCharles.Forsyth 	LoRxSquelch	= 0x4000,
253*74a4d8c2SCharles.Forsyth };
254*74a4d8c2SCharles.Forsyth 
255*74a4d8c2SCharles.Forsyth enum {					/* LineSt */
256*74a4d8c2SCharles.Forsyth 	LinkOK		= 0x0080,
257*74a4d8c2SCharles.Forsyth 	AUI			= 0x0100,
258*74a4d8c2SCharles.Forsyth 	TenBT		= 0x0200,
259*74a4d8c2SCharles.Forsyth 	PolarityOK	= 0x1000,
260*74a4d8c2SCharles.Forsyth 	CRS			= 0x4000,
261*74a4d8c2SCharles.Forsyth };
262*74a4d8c2SCharles.Forsyth 
263*74a4d8c2SCharles.Forsyth enum {					/* SelfCtl */
264*74a4d8c2SCharles.Forsyth 	RESET		= 0x0040,
265*74a4d8c2SCharles.Forsyth 	SWSuspend	= 0x0100,
266*74a4d8c2SCharles.Forsyth 	HWSleepE		= 0x0200,
267*74a4d8c2SCharles.Forsyth 	HWStandbyE	= 0x0400,
268*74a4d8c2SCharles.Forsyth };
269*74a4d8c2SCharles.Forsyth 
270*74a4d8c2SCharles.Forsyth enum {					/* SelfSt */
271*74a4d8c2SCharles.Forsyth 	INITD		= 0x0080,
272*74a4d8c2SCharles.Forsyth 	SIBUSY		= 0x0100,
273*74a4d8c2SCharles.Forsyth 	EepromPresent	= 0x0200,
274*74a4d8c2SCharles.Forsyth 	EepromOK	= 0x0400,
275*74a4d8c2SCharles.Forsyth 	ElPresent		= 0x0800,
276*74a4d8c2SCharles.Forsyth 	EeSize		= 0x1000,
277*74a4d8c2SCharles.Forsyth };
278*74a4d8c2SCharles.Forsyth 
279*74a4d8c2SCharles.Forsyth enum {					/* BusCtl */
280*74a4d8c2SCharles.Forsyth 	ResetRxDMA	= 0x0040,
281*74a4d8c2SCharles.Forsyth 	UseSA		= 0x0200,
282*74a4d8c2SCharles.Forsyth 	MemoryE		= 0x0400,
283*74a4d8c2SCharles.Forsyth 	DMABurst		= 0x0800,
284*74a4d8c2SCharles.Forsyth 	EnableIRQ		= 0x8000,
285*74a4d8c2SCharles.Forsyth };
286*74a4d8c2SCharles.Forsyth 
287*74a4d8c2SCharles.Forsyth enum {					/* BusST */
288*74a4d8c2SCharles.Forsyth 	TxBidErr		= 0x0080,
289*74a4d8c2SCharles.Forsyth 	Rdy4TxNOW	= 0x0100,
290*74a4d8c2SCharles.Forsyth };
291*74a4d8c2SCharles.Forsyth 
292*74a4d8c2SCharles.Forsyth enum {					/* TestCtl */
293*74a4d8c2SCharles.Forsyth 	FDX			= 0x4000,		/* full duplex */
294*74a4d8c2SCharles.Forsyth };
295*74a4d8c2SCharles.Forsyth 
296*74a4d8c2SCharles.Forsyth enum {					/* TxCmd */
297*74a4d8c2SCharles.Forsyth 	TxStart		= 0x00c0,		/* bytes before transmit starts (field) */
298*74a4d8c2SCharles.Forsyth 		TxSt5	= 0x0000,		/* start after 5 bytes */
299*74a4d8c2SCharles.Forsyth 		TxSt381	= 0x0040,		/* start after 381 bytes */
300*74a4d8c2SCharles.Forsyth 		TxSt1021	= 0x0080,		/* start after 1021 bytes */
301*74a4d8c2SCharles.Forsyth 		TxStAll	= 0x00c0,		/* start after the entire frame is in the cs8900 */
302*74a4d8c2SCharles.Forsyth 	Force		= 0x0100,
303*74a4d8c2SCharles.Forsyth 	Onecoll		= 0x0200,
304*74a4d8c2SCharles.Forsyth 	InhibitCRC	= 0x1000,
305*74a4d8c2SCharles.Forsyth 	TxPadDis		= 0x2000,
306*74a4d8c2SCharles.Forsyth };
307*74a4d8c2SCharles.Forsyth 
308*74a4d8c2SCharles.Forsyth static Queue *pendingTx[MaxEther];
309*74a4d8c2SCharles.Forsyth 
310*74a4d8c2SCharles.Forsyth static void
attach(Ctlr * ctlr)311*74a4d8c2SCharles.Forsyth attach(Ctlr *ctlr)
312*74a4d8c2SCharles.Forsyth {
313*74a4d8c2SCharles.Forsyth 	int reg;
314*74a4d8c2SCharles.Forsyth 
315*74a4d8c2SCharles.Forsyth 	USED(ctlr);
316*74a4d8c2SCharles.Forsyth 	/* enable transmit and receive */
317*74a4d8c2SCharles.Forsyth 	reg = regr(BusCtl);
318*74a4d8c2SCharles.Forsyth 	regw(BusCtl, reg|EnableIRQ);
319*74a4d8c2SCharles.Forsyth 	reg = regr(LineCtl);
320*74a4d8c2SCharles.Forsyth 	regw(LineCtl, reg|SerRxOn|SerTxOn);
321*74a4d8c2SCharles.Forsyth }
322*74a4d8c2SCharles.Forsyth 
323*74a4d8c2SCharles.Forsyth static char pbuf[200];
324*74a4d8c2SCharles.Forsyth int
sprintx(void * f,char * to,int count)325*74a4d8c2SCharles.Forsyth sprintx(void *f, char *to, int count)
326*74a4d8c2SCharles.Forsyth {
327*74a4d8c2SCharles.Forsyth 	int i, printable;
328*74a4d8c2SCharles.Forsyth 	char *start = to;
329*74a4d8c2SCharles.Forsyth 	uchar *from = f;
330*74a4d8c2SCharles.Forsyth 
331*74a4d8c2SCharles.Forsyth 	if(count < 0) {
332*74a4d8c2SCharles.Forsyth 		print("BAD DATA COUNT %d\n", count);
333*74a4d8c2SCharles.Forsyth 		return 0;
334*74a4d8c2SCharles.Forsyth 	}
335*74a4d8c2SCharles.Forsyth 	printable = 1;
336*74a4d8c2SCharles.Forsyth 	if(count > 40)
337*74a4d8c2SCharles.Forsyth 		count = 40;
338*74a4d8c2SCharles.Forsyth 	for(i=0; i<count && printable; i++)
339*74a4d8c2SCharles.Forsyth 		if((from[i]<32 && from[i] !='\n' && from[i] !='\r' && from[i] !='\b' && from[i] !='\t') || from[i]>127)
340*74a4d8c2SCharles.Forsyth 			printable = 0;
341*74a4d8c2SCharles.Forsyth 	*to++ = '\'';
342*74a4d8c2SCharles.Forsyth 	if(printable){
343*74a4d8c2SCharles.Forsyth 		memmove(to, from, count);
344*74a4d8c2SCharles.Forsyth 		to += count;
345*74a4d8c2SCharles.Forsyth 	}else{
346*74a4d8c2SCharles.Forsyth 		for(i=0; i<count; i++){
347*74a4d8c2SCharles.Forsyth 			if(i>0 && i%4==0)
348*74a4d8c2SCharles.Forsyth 				*to++ = ' ';
349*74a4d8c2SCharles.Forsyth 			sprint(to, "%2.2ux", from[i]);
350*74a4d8c2SCharles.Forsyth 			to += 2;
351*74a4d8c2SCharles.Forsyth 		}
352*74a4d8c2SCharles.Forsyth 	}
353*74a4d8c2SCharles.Forsyth 	*to++ = '\'';
354*74a4d8c2SCharles.Forsyth 	*to = 0;
355*74a4d8c2SCharles.Forsyth 	return to - start;
356*74a4d8c2SCharles.Forsyth }
357*74a4d8c2SCharles.Forsyth 
358*74a4d8c2SCharles.Forsyth static void
transmit(Ctlr * ctlr)359*74a4d8c2SCharles.Forsyth transmit(Ctlr *ctlr)
360*74a4d8c2SCharles.Forsyth {
361*74a4d8c2SCharles.Forsyth 	int len, status;
362*74a4d8c2SCharles.Forsyth 	Block *b;
363*74a4d8c2SCharles.Forsyth 
364*74a4d8c2SCharles.Forsyth 	for(;;){
365*74a4d8c2SCharles.Forsyth 		/* is TxCmd pending ? - check */
366*74a4d8c2SCharles.Forsyth 		if(qlen(pendingTx[ctlr->ctlrno]) > 0)
367*74a4d8c2SCharles.Forsyth 			break;
368*74a4d8c2SCharles.Forsyth 		b = qget(ctlr->oq);
369*74a4d8c2SCharles.Forsyth 		if(b == 0)
370*74a4d8c2SCharles.Forsyth 			break;
371*74a4d8c2SCharles.Forsyth 		len = BLEN(b);
372*74a4d8c2SCharles.Forsyth 		regw(TxCmd, TxSt381);
373*74a4d8c2SCharles.Forsyth 		regw(TxLen, len);
374*74a4d8c2SCharles.Forsyth 		status = regr(BusSt);
375*74a4d8c2SCharles.Forsyth 		if((status & Rdy4TxNOW) == 0) {
376*74a4d8c2SCharles.Forsyth 			qbwrite(pendingTx[ctlr->ctlrno], b);
377*74a4d8c2SCharles.Forsyth 			break;
378*74a4d8c2SCharles.Forsyth 		}
379*74a4d8c2SCharles.Forsyth 		/*
380*74a4d8c2SCharles.Forsyth 		 * Copy the packet to the transmit buffer.
381*74a4d8c2SCharles.Forsyth 		 */
382*74a4d8c2SCharles.Forsyth 		copyout(b->rp, len);
383*74a4d8c2SCharles.Forsyth 		freeb(b);
384*74a4d8c2SCharles.Forsyth 	}
385*74a4d8c2SCharles.Forsyth }
386*74a4d8c2SCharles.Forsyth 
387*74a4d8c2SCharles.Forsyth static void
interrupt(Ureg *,Ctlr * ctlr)388*74a4d8c2SCharles.Forsyth interrupt(Ureg*, Ctlr *ctlr)
389*74a4d8c2SCharles.Forsyth {
390*74a4d8c2SCharles.Forsyth 	int len, events, status;
391*74a4d8c2SCharles.Forsyth 	Block *b;
392*74a4d8c2SCharles.Forsyth 	Queue *q;
393*74a4d8c2SCharles.Forsyth 
394*74a4d8c2SCharles.Forsyth 	while((events = regr(Isq)) != 0) {
395*74a4d8c2SCharles.Forsyth 		status = events&RegContent;
396*74a4d8c2SCharles.Forsyth 
397*74a4d8c2SCharles.Forsyth 		switch(events&Regnum) {
398*74a4d8c2SCharles.Forsyth 
399*74a4d8c2SCharles.Forsyth 		case IsqBufEvent:
400*74a4d8c2SCharles.Forsyth 			if(status&Rdy4Tx) {
401*74a4d8c2SCharles.Forsyth 				if(qlen(pendingTx[ctlr->ctlrno]) > 0)
402*74a4d8c2SCharles.Forsyth 					q = pendingTx[ctlr->ctlrno];
403*74a4d8c2SCharles.Forsyth 				else
404*74a4d8c2SCharles.Forsyth 					q = ctlr->oq;
405*74a4d8c2SCharles.Forsyth 				b = qget(q);
406*74a4d8c2SCharles.Forsyth 				if(b == 0)
407*74a4d8c2SCharles.Forsyth 					break;
408*74a4d8c2SCharles.Forsyth 				len = BLEN(b);
409*74a4d8c2SCharles.Forsyth 				copyout(b->rp, len);
410*74a4d8c2SCharles.Forsyth 				freeb(b);
411*74a4d8c2SCharles.Forsyth 			} else
412*74a4d8c2SCharles.Forsyth 			if(status&TxUnderrun) {
413*74a4d8c2SCharles.Forsyth 				print("TxUnderrun\n");
414*74a4d8c2SCharles.Forsyth 			} else
415*74a4d8c2SCharles.Forsyth 			if(status&RxMiss) {
416*74a4d8c2SCharles.Forsyth 				print("RxMiss\n");
417*74a4d8c2SCharles.Forsyth 			} else {
418*74a4d8c2SCharles.Forsyth 				print("IsqBufEvent status = %ux\n", status);
419*74a4d8c2SCharles.Forsyth 			}
420*74a4d8c2SCharles.Forsyth 			break;
421*74a4d8c2SCharles.Forsyth 
422*74a4d8c2SCharles.Forsyth 		case IsqRxEvent:
423*74a4d8c2SCharles.Forsyth 			if(status&RxOK) {
424*74a4d8c2SCharles.Forsyth 				len = regr(RxLen);
425*74a4d8c2SCharles.Forsyth 				if((b = iallocb(len)) != 0) {
426*74a4d8c2SCharles.Forsyth 					copyin(b->wp, len);
427*74a4d8c2SCharles.Forsyth 					b->wp += len;
428*74a4d8c2SCharles.Forsyth 					etheriq(ctlr, b, 1);
429*74a4d8c2SCharles.Forsyth 				}
430*74a4d8c2SCharles.Forsyth 			} else {
431*74a4d8c2SCharles.Forsyth 				print("IsqRxEvent status = %ux\n", status);
432*74a4d8c2SCharles.Forsyth 			}
433*74a4d8c2SCharles.Forsyth 			break;
434*74a4d8c2SCharles.Forsyth 
435*74a4d8c2SCharles.Forsyth 		case IsqTxEvent:
436*74a4d8c2SCharles.Forsyth 			if(status&TxOK) {
437*74a4d8c2SCharles.Forsyth 				if(qlen(pendingTx[ctlr->ctlrno]) > 0)
438*74a4d8c2SCharles.Forsyth 					q = pendingTx[ctlr->ctlrno];
439*74a4d8c2SCharles.Forsyth 				else
440*74a4d8c2SCharles.Forsyth 					q = ctlr->oq;
441*74a4d8c2SCharles.Forsyth 				b = qget(q);
442*74a4d8c2SCharles.Forsyth 				if(b == 0)
443*74a4d8c2SCharles.Forsyth 					break;
444*74a4d8c2SCharles.Forsyth 				len = BLEN(b);
445*74a4d8c2SCharles.Forsyth 				regw(TxCmd, TxSt381);
446*74a4d8c2SCharles.Forsyth 				regw(TxLen, len);
447*74a4d8c2SCharles.Forsyth if((regr(BusSt) & Rdy4TxNOW) == 0) {
448*74a4d8c2SCharles.Forsyth 	print("IsqTxEvent and Rdy4TxNow == 0\n");
449*74a4d8c2SCharles.Forsyth }
450*74a4d8c2SCharles.Forsyth 				copyout(b->rp, len);
451*74a4d8c2SCharles.Forsyth 				freeb(b);
452*74a4d8c2SCharles.Forsyth 			} else {
453*74a4d8c2SCharles.Forsyth 				print("IsqTxEvent status = %ux\n", status);
454*74a4d8c2SCharles.Forsyth 			}
455*74a4d8c2SCharles.Forsyth 			break;
456*74a4d8c2SCharles.Forsyth 		case IsqRxMiss:
457*74a4d8c2SCharles.Forsyth 			break;
458*74a4d8c2SCharles.Forsyth 		case IsqTxCol:
459*74a4d8c2SCharles.Forsyth 			break;
460*74a4d8c2SCharles.Forsyth 		}
461*74a4d8c2SCharles.Forsyth 	}
462*74a4d8c2SCharles.Forsyth }
463*74a4d8c2SCharles.Forsyth 
464*74a4d8c2SCharles.Forsyth int
cs8900reset(Ctlr * ctlr)465*74a4d8c2SCharles.Forsyth cs8900reset(Ctlr* ctlr)
466*74a4d8c2SCharles.Forsyth {
467*74a4d8c2SCharles.Forsyth 	int i, reg;
468*74a4d8c2SCharles.Forsyth 	uchar ea[Eaddrlen];
469*74a4d8c2SCharles.Forsyth 
470*74a4d8c2SCharles.Forsyth 	ctlr->card.irq = V_ETHERNET;
471*74a4d8c2SCharles.Forsyth 	pendingTx[ctlr->ctlrno] = qopen(16*1024, 1, 0, 0);
472*74a4d8c2SCharles.Forsyth 
473*74a4d8c2SCharles.Forsyth 	/*
474*74a4d8c2SCharles.Forsyth 	 * If the Ethernet address is not set in the plan9.ini file
475*74a4d8c2SCharles.Forsyth 	 * a) try reading from the Puma board ROM. The ether address is found in
476*74a4d8c2SCharles.Forsyth 	 * 	bytes 4-9 of the ROM. The Teralogic Organizational Unique Id (OUI)
477*74a4d8c2SCharles.Forsyth 	 *	is in bytes 4-6 and should be 00 10 8a.
478*74a4d8c2SCharles.Forsyth 	 */
479*74a4d8c2SCharles.Forsyth 	memset(ea, 0, Eaddrlen);
480*74a4d8c2SCharles.Forsyth 	if(memcmp(ea, ctlr->card.ea, Eaddrlen) == 0) {
481*74a4d8c2SCharles.Forsyth 		uchar *rom = (uchar *)EPROM_BASE;
482*74a4d8c2SCharles.Forsyth 		if(rom[4] != 0x00 || rom[5] != 0x10 || rom[6] != 0x8a)
483*74a4d8c2SCharles.Forsyth 			panic("no ether address");
484*74a4d8c2SCharles.Forsyth 		memmove(ea, &rom[4], Eaddrlen);
485*74a4d8c2SCharles.Forsyth 	}
486*74a4d8c2SCharles.Forsyth 	memmove(ctlr->card.ea, ea, Eaddrlen);
487*74a4d8c2SCharles.Forsyth 
488*74a4d8c2SCharles.Forsyth 	/*
489*74a4d8c2SCharles.Forsyth 	 * Identify the chip by reading the Pic register.
490*74a4d8c2SCharles.Forsyth 	 * The EISA registration number is in the low word
491*74a4d8c2SCharles.Forsyth 	 * and the product identification code in the high code.
492*74a4d8c2SCharles.Forsyth 	 * The ERN for Crystal Semiconductor is 0x630e.
493*74a4d8c2SCharles.Forsyth 	 * Bits 0-7 and 13-15 of the Pic should be zero for a CS8900.
494*74a4d8c2SCharles.Forsyth 	 */
495*74a4d8c2SCharles.Forsyth 	if(regIOr(Ern) != 0x630e || (regIOr(Pic) & 0xe0ff) != 0)
496*74a4d8c2SCharles.Forsyth 		panic("no cs8900 found");
497*74a4d8c2SCharles.Forsyth 
498*74a4d8c2SCharles.Forsyth 	/*
499*74a4d8c2SCharles.Forsyth 	 * Reset the chip and ensure 16-bit mode operation
500*74a4d8c2SCharles.Forsyth 	 */
501*74a4d8c2SCharles.Forsyth 	regIOw(SelfCtl, RESET);
502*74a4d8c2SCharles.Forsyth 	delay(10);
503*74a4d8c2SCharles.Forsyth 	i=in8(PpPtr); 	USED(i);
504*74a4d8c2SCharles.Forsyth 	i=in8(PpPtr+1); USED(i);
505*74a4d8c2SCharles.Forsyth 	i=in8(PpPtr); 	USED(i);
506*74a4d8c2SCharles.Forsyth 	i=in8(PpPtr+1);	USED(i);
507*74a4d8c2SCharles.Forsyth 
508*74a4d8c2SCharles.Forsyth 	/*
509*74a4d8c2SCharles.Forsyth 	 * Wait for initialisation and EEPROM reads to complete
510*74a4d8c2SCharles.Forsyth 	 */
511*74a4d8c2SCharles.Forsyth 	i=0;
512*74a4d8c2SCharles.Forsyth 	for(;;) {
513*74a4d8c2SCharles.Forsyth 		short st = regIOr(SelfSt);
514*74a4d8c2SCharles.Forsyth 		if((st&SIBUSY) == 0 && st&INITD)
515*74a4d8c2SCharles.Forsyth 			break;
516*74a4d8c2SCharles.Forsyth 		if(i++ > 1000000)
517*74a4d8c2SCharles.Forsyth 			panic("cs8900: initialisation failed");
518*74a4d8c2SCharles.Forsyth 	}
519*74a4d8c2SCharles.Forsyth 
520*74a4d8c2SCharles.Forsyth 	/*
521*74a4d8c2SCharles.Forsyth 	 * Enable memory mode operation.
522*74a4d8c2SCharles.Forsyth 	 */
523*74a4d8c2SCharles.Forsyth 	regIOw(Mba, MemBase & 0xffff);
524*74a4d8c2SCharles.Forsyth 	regIOw(Mba+2, MemBase >> 16);
525*74a4d8c2SCharles.Forsyth 	regIOw(BusCtl, MemoryE|UseSA);
526*74a4d8c2SCharles.Forsyth 
527*74a4d8c2SCharles.Forsyth 	/*
528*74a4d8c2SCharles.Forsyth 	 * Enable 10BASE-T half duplex, transmit in interrupt mode
529*74a4d8c2SCharles.Forsyth 	 */
530*74a4d8c2SCharles.Forsyth 	reg = regr(LineCtl);
531*74a4d8c2SCharles.Forsyth 	regw(LineCtl, reg&~Iface);
532*74a4d8c2SCharles.Forsyth 	reg = regr(TestCtl);
533*74a4d8c2SCharles.Forsyth 	regw(TestCtl, reg&~FDX);
534*74a4d8c2SCharles.Forsyth 	regw(BufCfg, Rdy4TxiE|TxUnderruniE|RxMissiE);
535*74a4d8c2SCharles.Forsyth 	regw(TxCfg, TxOKiE|JabberiE|Coll16iE);
536*74a4d8c2SCharles.Forsyth 	regw(RxCfg, RxOKiE);
537*74a4d8c2SCharles.Forsyth 	regw(RxCtl, RxOKA|IndividualA|BroadcastA);
538*74a4d8c2SCharles.Forsyth 
539*74a4d8c2SCharles.Forsyth 	for(i=0; i<Eaddrlen; i+=2)
540*74a4d8c2SCharles.Forsyth 		regw(IndAddr+i, ea[i] | (ea[i+1] << 8));
541*74a4d8c2SCharles.Forsyth 
542*74a4d8c2SCharles.Forsyth 	/* Puma IRQ tied to INTRQ0 */
543*74a4d8c2SCharles.Forsyth 	regw(Intr, 0);
544*74a4d8c2SCharles.Forsyth 
545*74a4d8c2SCharles.Forsyth 	ctlr->card.reset = cs8900reset;
546*74a4d8c2SCharles.Forsyth 	ctlr->card.port = 0x300;
547*74a4d8c2SCharles.Forsyth 	ctlr->card.attach = attach;
548*74a4d8c2SCharles.Forsyth 	ctlr->card.transmit = transmit;
549*74a4d8c2SCharles.Forsyth 	ctlr->card.intr = interrupt;
550*74a4d8c2SCharles.Forsyth 
551*74a4d8c2SCharles.Forsyth 	print("Ether reset...\n");uartwait();
552*74a4d8c2SCharles.Forsyth 
553*74a4d8c2SCharles.Forsyth 	return 0;
554*74a4d8c2SCharles.Forsyth }
555*74a4d8c2SCharles.Forsyth 
556