xref: /plan9-contrib/sys/src/9/bcm/ethermii.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
1*5c47fe09SDavid du Colombier #include "u.h"
2*5c47fe09SDavid du Colombier #include "../port/lib.h"
3*5c47fe09SDavid du Colombier #include "mem.h"
4*5c47fe09SDavid du Colombier #include "dat.h"
5*5c47fe09SDavid du Colombier #include "fns.h"
6*5c47fe09SDavid du Colombier #include "io.h"
7*5c47fe09SDavid du Colombier #include "../port/error.h"
8*5c47fe09SDavid du Colombier #include "../port/netif.h"
9*5c47fe09SDavid du Colombier #include "etherif.h"
10*5c47fe09SDavid du Colombier 
11*5c47fe09SDavid du Colombier #include "ethermii.h"
12*5c47fe09SDavid du Colombier 
13*5c47fe09SDavid du Colombier int
mii(Mii * mii,int mask)14*5c47fe09SDavid du Colombier mii(Mii* mii, int mask)
15*5c47fe09SDavid du Colombier {
16*5c47fe09SDavid du Colombier 	MiiPhy *miiphy;
17*5c47fe09SDavid du Colombier 	int bit, oui, phyno, rmask;
18*5c47fe09SDavid du Colombier 	u32int id;
19*5c47fe09SDavid du Colombier 
20*5c47fe09SDavid du Colombier 	/*
21*5c47fe09SDavid du Colombier 	 * Probe through mii for PHYs in mask;
22*5c47fe09SDavid du Colombier 	 * return the mask of those found in the current probe.
23*5c47fe09SDavid du Colombier 	 * If the PHY has not already been probed, update
24*5c47fe09SDavid du Colombier 	 * the Mii information.
25*5c47fe09SDavid du Colombier 	 */
26*5c47fe09SDavid du Colombier 	rmask = 0;
27*5c47fe09SDavid du Colombier 	for(phyno = 0; phyno < NMiiPhy; phyno++){
28*5c47fe09SDavid du Colombier 		bit = 1<<phyno;
29*5c47fe09SDavid du Colombier 		if(!(mask & bit))
30*5c47fe09SDavid du Colombier 			continue;
31*5c47fe09SDavid du Colombier 		if(mii->mask & bit){
32*5c47fe09SDavid du Colombier 			rmask |= bit;
33*5c47fe09SDavid du Colombier 			continue;
34*5c47fe09SDavid du Colombier 		}
35*5c47fe09SDavid du Colombier 		if(mii->mir(mii, phyno, Bmsr) == -1)
36*5c47fe09SDavid du Colombier 			continue;
37*5c47fe09SDavid du Colombier 		id = mii->mir(mii, phyno, Phyidr1) << 16;
38*5c47fe09SDavid du Colombier 		id |= mii->mir(mii, phyno, Phyidr2);
39*5c47fe09SDavid du Colombier 		oui = (id & 0x3FFFFC00)>>10;
40*5c47fe09SDavid du Colombier 		if(oui == 0xFFFFF || oui == 0)
41*5c47fe09SDavid du Colombier 			continue;
42*5c47fe09SDavid du Colombier 
43*5c47fe09SDavid du Colombier 		if((miiphy = malloc(sizeof(MiiPhy))) == nil)
44*5c47fe09SDavid du Colombier 			continue;
45*5c47fe09SDavid du Colombier 
46*5c47fe09SDavid du Colombier 		miiphy->mii = mii;
47*5c47fe09SDavid du Colombier 		miiphy->id = id;
48*5c47fe09SDavid du Colombier 		miiphy->oui = oui;
49*5c47fe09SDavid du Colombier 		miiphy->phyno = phyno;
50*5c47fe09SDavid du Colombier 
51*5c47fe09SDavid du Colombier 		miiphy->anar = ~0;
52*5c47fe09SDavid du Colombier 		miiphy->fc = ~0;
53*5c47fe09SDavid du Colombier 		miiphy->mscr = ~0;
54*5c47fe09SDavid du Colombier 
55*5c47fe09SDavid du Colombier 		mii->phy[phyno] = miiphy;
56*5c47fe09SDavid du Colombier 		if(mii->curphy == nil)
57*5c47fe09SDavid du Colombier 			mii->curphy = miiphy;
58*5c47fe09SDavid du Colombier 		mii->mask |= bit;
59*5c47fe09SDavid du Colombier 		mii->nphy++;
60*5c47fe09SDavid du Colombier 
61*5c47fe09SDavid du Colombier 		rmask |= bit;
62*5c47fe09SDavid du Colombier 	}
63*5c47fe09SDavid du Colombier 	return rmask;
64*5c47fe09SDavid du Colombier }
65*5c47fe09SDavid du Colombier 
66*5c47fe09SDavid du Colombier int
miimir(Mii * mii,int r)67*5c47fe09SDavid du Colombier miimir(Mii* mii, int r)
68*5c47fe09SDavid du Colombier {
69*5c47fe09SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
70*5c47fe09SDavid du Colombier 		return -1;
71*5c47fe09SDavid du Colombier 	return mii->mir(mii, mii->curphy->phyno, r);
72*5c47fe09SDavid du Colombier }
73*5c47fe09SDavid du Colombier 
74*5c47fe09SDavid du Colombier int
miimiw(Mii * mii,int r,int data)75*5c47fe09SDavid du Colombier miimiw(Mii* mii, int r, int data)
76*5c47fe09SDavid du Colombier {
77*5c47fe09SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
78*5c47fe09SDavid du Colombier 		return -1;
79*5c47fe09SDavid du Colombier 	return mii->miw(mii, mii->curphy->phyno, r, data);
80*5c47fe09SDavid du Colombier }
81*5c47fe09SDavid du Colombier 
82*5c47fe09SDavid du Colombier int
miireset(Mii * mii)83*5c47fe09SDavid du Colombier miireset(Mii* mii)
84*5c47fe09SDavid du Colombier {
85*5c47fe09SDavid du Colombier 	int bmcr;
86*5c47fe09SDavid du Colombier 
87*5c47fe09SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
88*5c47fe09SDavid du Colombier 		return -1;
89*5c47fe09SDavid du Colombier 	bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr);
90*5c47fe09SDavid du Colombier 	bmcr |= BmcrR;
91*5c47fe09SDavid du Colombier 	mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr);
92*5c47fe09SDavid du Colombier 	microdelay(1);
93*5c47fe09SDavid du Colombier 
94*5c47fe09SDavid du Colombier 	return 0;
95*5c47fe09SDavid du Colombier }
96*5c47fe09SDavid du Colombier 
97*5c47fe09SDavid du Colombier int
miiane(Mii * mii,int a,int p,int e)98*5c47fe09SDavid du Colombier miiane(Mii* mii, int a, int p, int e)
99*5c47fe09SDavid du Colombier {
100*5c47fe09SDavid du Colombier 	int anar, bmsr, mscr, r, phyno;
101*5c47fe09SDavid du Colombier 
102*5c47fe09SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
103*5c47fe09SDavid du Colombier 		return -1;
104*5c47fe09SDavid du Colombier 	phyno = mii->curphy->phyno;
105*5c47fe09SDavid du Colombier 
106*5c47fe09SDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
107*5c47fe09SDavid du Colombier 	if(!(bmsr & BmsrAna))
108*5c47fe09SDavid du Colombier 		return -1;
109*5c47fe09SDavid du Colombier 
110*5c47fe09SDavid du Colombier 	if(a != ~0)
111*5c47fe09SDavid du Colombier 		anar = (AnaTXFD|AnaTXHD|Ana10FD|Ana10HD) & a;
112*5c47fe09SDavid du Colombier 	else if(mii->curphy->anar != ~0)
113*5c47fe09SDavid du Colombier 		anar = mii->curphy->anar;
114*5c47fe09SDavid du Colombier 	else{
115*5c47fe09SDavid du Colombier 		anar = mii->mir(mii, phyno, Anar);
116*5c47fe09SDavid du Colombier 		anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
117*5c47fe09SDavid du Colombier 		if(bmsr & Bmsr10THD)
118*5c47fe09SDavid du Colombier 			anar |= Ana10HD;
119*5c47fe09SDavid du Colombier 		if(bmsr & Bmsr10TFD)
120*5c47fe09SDavid du Colombier 			anar |= Ana10FD;
121*5c47fe09SDavid du Colombier 		if(bmsr & Bmsr100TXHD)
122*5c47fe09SDavid du Colombier 			anar |= AnaTXHD;
123*5c47fe09SDavid du Colombier 		if(bmsr & Bmsr100TXFD)
124*5c47fe09SDavid du Colombier 			anar |= AnaTXFD;
125*5c47fe09SDavid du Colombier 	}
126*5c47fe09SDavid du Colombier 	mii->curphy->anar = anar;
127*5c47fe09SDavid du Colombier 
128*5c47fe09SDavid du Colombier 	if(p != ~0)
129*5c47fe09SDavid du Colombier 		anar |= (AnaAP|AnaP) & p;
130*5c47fe09SDavid du Colombier 	else if(mii->curphy->fc != ~0)
131*5c47fe09SDavid du Colombier 		anar |= mii->curphy->fc;
132*5c47fe09SDavid du Colombier 	mii->curphy->fc = (AnaAP|AnaP) & anar;
133*5c47fe09SDavid du Colombier 
134*5c47fe09SDavid du Colombier 	if(bmsr & BmsrEs){
135*5c47fe09SDavid du Colombier 		mscr = mii->mir(mii, phyno, Mscr);
136*5c47fe09SDavid du Colombier 		mscr &= ~(Mscr1000TFD|Mscr1000THD);
137*5c47fe09SDavid du Colombier 		if(e != ~0)
138*5c47fe09SDavid du Colombier 			mscr |= (Mscr1000TFD|Mscr1000THD) & e;
139*5c47fe09SDavid du Colombier 		else if(mii->curphy->mscr != ~0)
140*5c47fe09SDavid du Colombier 			mscr = mii->curphy->mscr;
141*5c47fe09SDavid du Colombier 		else{
142*5c47fe09SDavid du Colombier 			r = mii->mir(mii, phyno, Esr);
143*5c47fe09SDavid du Colombier 			if(r & Esr1000THD)
144*5c47fe09SDavid du Colombier 				mscr |= Mscr1000THD;
145*5c47fe09SDavid du Colombier 			if(r & Esr1000TFD)
146*5c47fe09SDavid du Colombier 				mscr |= Mscr1000TFD;
147*5c47fe09SDavid du Colombier 		}
148*5c47fe09SDavid du Colombier 		mii->curphy->mscr = mscr;
149*5c47fe09SDavid du Colombier 		mii->miw(mii, phyno, Mscr, mscr);
150*5c47fe09SDavid du Colombier 	}
151*5c47fe09SDavid du Colombier 	mii->miw(mii, phyno, Anar, anar);
152*5c47fe09SDavid du Colombier 
153*5c47fe09SDavid du Colombier 	r = mii->mir(mii, phyno, Bmcr);
154*5c47fe09SDavid du Colombier 	if(!(r & BmcrR)){
155*5c47fe09SDavid du Colombier 		r |= BmcrAne|BmcrRan;
156*5c47fe09SDavid du Colombier 		mii->miw(mii, phyno, Bmcr, r);
157*5c47fe09SDavid du Colombier 	}
158*5c47fe09SDavid du Colombier 
159*5c47fe09SDavid du Colombier 	return 0;
160*5c47fe09SDavid du Colombier }
161*5c47fe09SDavid du Colombier 
162*5c47fe09SDavid du Colombier int
miistatus(Mii * mii)163*5c47fe09SDavid du Colombier miistatus(Mii* mii)
164*5c47fe09SDavid du Colombier {
165*5c47fe09SDavid du Colombier 	MiiPhy *phy;
166*5c47fe09SDavid du Colombier 	int anlpar, bmsr, p, r, phyno;
167*5c47fe09SDavid du Colombier 
168*5c47fe09SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
169*5c47fe09SDavid du Colombier 		return -1;
170*5c47fe09SDavid du Colombier 	phy = mii->curphy;
171*5c47fe09SDavid du Colombier 	phyno = phy->phyno;
172*5c47fe09SDavid du Colombier 
173*5c47fe09SDavid du Colombier 	/*
174*5c47fe09SDavid du Colombier 	 * Check Auto-Negotiation is complete and link is up.
175*5c47fe09SDavid du Colombier 	 * (Read status twice as the Ls bit is sticky).
176*5c47fe09SDavid du Colombier 	 */
177*5c47fe09SDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
178*5c47fe09SDavid du Colombier 	if(!(bmsr & (BmsrAnc|BmsrAna))) {
179*5c47fe09SDavid du Colombier 		// print("miistatus: auto-neg incomplete\n");
180*5c47fe09SDavid du Colombier 		return -1;
181*5c47fe09SDavid du Colombier 	}
182*5c47fe09SDavid du Colombier 
183*5c47fe09SDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
184*5c47fe09SDavid du Colombier 	if(!(bmsr & BmsrLs)){
185*5c47fe09SDavid du Colombier 		// print("miistatus: link down\n");
186*5c47fe09SDavid du Colombier 		phy->link = 0;
187*5c47fe09SDavid du Colombier 		return -1;
188*5c47fe09SDavid du Colombier 	}
189*5c47fe09SDavid du Colombier 
190*5c47fe09SDavid du Colombier 	phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
191*5c47fe09SDavid du Colombier 	if(phy->mscr){
192*5c47fe09SDavid du Colombier 		r = mii->mir(mii, phyno, Mssr);
193*5c47fe09SDavid du Colombier 		if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
194*5c47fe09SDavid du Colombier 			phy->speed = 1000;
195*5c47fe09SDavid du Colombier 			phy->fd = 1;
196*5c47fe09SDavid du Colombier 		}
197*5c47fe09SDavid du Colombier 		else if((phy->mscr & Mscr1000THD) && (r & Mssr1000THD))
198*5c47fe09SDavid du Colombier 			phy->speed = 1000;
199*5c47fe09SDavid du Colombier 	}
200*5c47fe09SDavid du Colombier 
201*5c47fe09SDavid du Colombier 	anlpar = mii->mir(mii, phyno, Anlpar);
202*5c47fe09SDavid du Colombier 	if(phy->speed == 0){
203*5c47fe09SDavid du Colombier 		r = phy->anar & anlpar;
204*5c47fe09SDavid du Colombier 		if(r & AnaTXFD){
205*5c47fe09SDavid du Colombier 			phy->speed = 100;
206*5c47fe09SDavid du Colombier 			phy->fd = 1;
207*5c47fe09SDavid du Colombier 		}
208*5c47fe09SDavid du Colombier 		else if(r & AnaTXHD)
209*5c47fe09SDavid du Colombier 			phy->speed = 100;
210*5c47fe09SDavid du Colombier 		else if(r & Ana10FD){
211*5c47fe09SDavid du Colombier 			phy->speed = 10;
212*5c47fe09SDavid du Colombier 			phy->fd = 1;
213*5c47fe09SDavid du Colombier 		}
214*5c47fe09SDavid du Colombier 		else if(r & Ana10HD)
215*5c47fe09SDavid du Colombier 			phy->speed = 10;
216*5c47fe09SDavid du Colombier 	}
217*5c47fe09SDavid du Colombier 	if(phy->speed == 0) {
218*5c47fe09SDavid du Colombier 		// print("miistatus: phy speed 0\n");
219*5c47fe09SDavid du Colombier 		return -1;
220*5c47fe09SDavid du Colombier 	}
221*5c47fe09SDavid du Colombier 
222*5c47fe09SDavid du Colombier 	if(phy->fd){
223*5c47fe09SDavid du Colombier 		p = phy->fc;
224*5c47fe09SDavid du Colombier 		r = anlpar & (AnaAP|AnaP);
225*5c47fe09SDavid du Colombier 		if(p == AnaAP && r == (AnaAP|AnaP))
226*5c47fe09SDavid du Colombier 			phy->tfc = 1;
227*5c47fe09SDavid du Colombier 		else if(p == (AnaAP|AnaP) && r == AnaAP)
228*5c47fe09SDavid du Colombier 			phy->rfc = 1;
229*5c47fe09SDavid du Colombier 		else if((p & AnaP) && (r & AnaP))
230*5c47fe09SDavid du Colombier 			phy->rfc = phy->tfc = 1;
231*5c47fe09SDavid du Colombier 	}
232*5c47fe09SDavid du Colombier 
233*5c47fe09SDavid du Colombier 	phy->link = 1;
234*5c47fe09SDavid du Colombier 
235*5c47fe09SDavid du Colombier 	return 0;
236*5c47fe09SDavid du Colombier }
237*5c47fe09SDavid du Colombier 
238*5c47fe09SDavid du Colombier int
miimmdr(Mii * mii,int a,int r)239*5c47fe09SDavid du Colombier miimmdr(Mii* mii, int a, int r)
240*5c47fe09SDavid du Colombier {
241*5c47fe09SDavid du Colombier 	a &= 0x1F;
242*5c47fe09SDavid du Colombier 	if(miimiw(mii, Mmdctrl, a) == -1)
243*5c47fe09SDavid du Colombier 		return -1;
244*5c47fe09SDavid du Colombier 	if(miimiw(mii, Mmddata, r) == -1)
245*5c47fe09SDavid du Colombier 		return -1;
246*5c47fe09SDavid du Colombier 	if(miimiw(mii, Mmdctrl, a | 0x4000) == -1)
247*5c47fe09SDavid du Colombier 		return -1;
248*5c47fe09SDavid du Colombier 	return miimir(mii, Mmddata);
249*5c47fe09SDavid du Colombier }
250*5c47fe09SDavid du Colombier 
251*5c47fe09SDavid du Colombier int
miimmdw(Mii * mii,int a,int r,int data)252*5c47fe09SDavid du Colombier miimmdw(Mii* mii, int a, int r, int data)
253*5c47fe09SDavid du Colombier {
254*5c47fe09SDavid du Colombier 	a &= 0x1F;
255*5c47fe09SDavid du Colombier 	if(miimiw(mii, Mmdctrl, a) == -1)
256*5c47fe09SDavid du Colombier 		return -1;
257*5c47fe09SDavid du Colombier 	if(miimiw(mii, Mmddata, r) == -1)
258*5c47fe09SDavid du Colombier 		return -1;
259*5c47fe09SDavid du Colombier 	if(miimiw(mii, Mmdctrl, a | 0x4000) == -1)
260*5c47fe09SDavid du Colombier 		return -1;
261*5c47fe09SDavid du Colombier 	return miimiw(mii, Mmddata, data);
262*5c47fe09SDavid du Colombier }
263