]> git.lizzy.rs Git - plan9front.git/blob - asix.c
f2ec834463f728a21b9768e942e21da50ceb7797
[plan9front.git] / asix.c
1 /*
2  * Asix USB ether adapters
3  * I got no documentation for it, thus the bits
4  * come from other systems; it's likely this is
5  * doing more than needed in some places and
6  * less than required in others.
7  */
8 #include <u.h>
9 #include <libc.h>
10 #include <thread.h>
11
12 #include "usb.h"
13 #include "dat.h"
14
15 enum
16 {
17
18         /* Asix commands */
19         Cswmii          = 0x06,         /* set sw mii */
20         Crmii           = 0x07,         /* read mii reg */
21         Cwmii           = 0x08,         /* write mii reg */
22         Chwmii          = 0x0a,         /* set hw mii */
23         Creeprom        = 0x0b,         /* read eeprom */
24         Cwdis           = 0x0e,         /* write disable */
25         Cwena           = 0x0d,         /* write enable */
26         Crrxctl         = 0x0f,         /* read rx ctl */
27         Cwrxctl         = 0x10,         /* write rx ctl */
28         Cwipg           = 0x12,         /* write ipg */
29         Crmac           = 0x13,         /* read mac addr */
30         Crphy           = 0x19,         /* read phy id */
31         Cwmedium                = 0x1b,         /* write medium mode */
32         Crgpio          = 0x1e,         /* read gpio */
33         Cwgpio          = 0x1f,         /* write gpios */
34         Creset          = 0x20,         /* reset */
35         Cwphy           = 0x22,         /* select phy */
36
37         /* reset codes */
38         Rclear          = 0x00,
39         Rprte           = 0x04,
40         Rprl            = 0x08,
41         Riprl           = 0x20,
42         Rippd           = 0x40,
43
44         Gpiogpo1en      = 0x04, /* gpio1 enable */,
45         Gpiogpo1                = 0x08, /* gpio1 value */
46         Gpiogpo2en      = 0x10, /* gpio2 enable */
47         Gpiogpo2                = 0x20, /* gpio2 value */
48         Gpiorse         = 0x80, /* gpio reload serial eeprom */
49
50         Pmask           = 0x1F,
51         Pembed          = 0x10,                 /* embedded phy */
52
53         Mfd             = 0x002,                /* media */
54         Mac             = 0x004,
55         Mrfc            = 0x010,
56         Mtfc            = 0x020,
57         Mjfe            = 0x040,
58         Mre             = 0x100,
59         Mps             = 0x200,
60         Mall772         = Mfd|Mrfc|Mtfc|Mps|Mac|Mre,
61         Mall178         = Mps|Mfd|Mac|Mrfc|Mtfc|Mjfe|Mre,
62
63         Ipgdflt         = 0x15|0x0c|0x12,       /* default ipg0, 1, 2 */
64         Rxctlso         = 0x80,
65         Rxctlab         = 0x08,
66         Rxctlsep        = 0x04,
67         Rxctlamall      = 0x02,                 /* all multicast */
68         Rxctlprom       = 0x01,                 /* promiscuous */
69
70         /* MII */
71         Miibmcr                 = 0x00,         /* basic mode ctrl reg. */
72                 Bmcrreset       = 0x8000,       /* reset */
73                 Bmcranena       = 0x1000,       /* auto neg. enable */
74                 Bmcrar          = 0x0200,       /* announce restart */
75
76         Miiad                   = 0x04,         /* advertise reg. */
77                 Adcsma          = 0x0001,
78                 Ad1000f         = 0x0200,
79                 Ad1000h         = 0x0100,
80                 Ad10h           = 0x0020,
81                 Ad10f           = 0x0040,
82                 Ad100h          = 0x0080,
83                 Ad100f          = 0x0100,
84                 Adpause         = 0x0400,
85                 Adall           = Ad10h|Ad10f|Ad100h|Ad100f,
86
87         Miimctl                 = 0x14,         /* marvell ctl */
88                 Mtxdly          = 0x02,
89                 Mrxdly          = 0x80,
90                 Mtxrxdly        = 0x82,
91
92         Miic1000                        = 0x09,
93
94 };
95
96 static uint asixphy;
97
98 static int
99 asixset(Dev *d, int c, int v)
100 {
101         int r;
102         int ec;
103
104         r = Rh2d|Rvendor|Rdev;
105         ec = usbcmd(d, r, c, v, 0, nil, 0);
106         if(ec < 0)
107                 fprint(2, "%s: asixset %x %x: %r\n", argv0, c, v);
108         return ec;
109 }
110
111 static int
112 asixget(Dev *d, int c, uchar *buf, int l)
113 {
114         int r;
115         int ec;
116
117         r = Rd2h|Rvendor|Rdev;
118         ec = usbcmd(d, r, c, 0, 0, buf, l);
119         if(ec < 0)
120                 fprint(2, "%s: asixget %x: %r\n", argv0, c);
121         return ec;
122 }
123
124 static int
125 getgpio(Dev *d)
126 {
127         uchar c;
128
129         if(asixget(d, Crgpio, &c, 1) < 0)
130                 return -1;
131         return c;
132 }
133
134 static int
135 getphy(Dev *d)
136 {
137         uchar buf[2];
138
139         if(asixget(d, Crphy, buf, sizeof(buf)) < 0)
140                 return -1;
141         return buf[1];
142 }
143
144 static int
145 getrxctl(Dev *d)
146 {
147         uchar buf[2];
148
149         memset(buf, 0, sizeof(buf));
150         if(asixget(d, Crrxctl, buf, sizeof(buf)) < 0)
151                 return -1;
152         return GET2(buf);
153 }
154
155 static int
156 miiread(Dev *d, int phy, int reg)
157 {
158         int r;
159         uchar v[2];
160
161         r = Rd2h|Rvendor|Rdev;
162         if(usbcmd(d, r, Crmii, phy, reg, v, 2) < 0){
163                 fprint(2, "%s: miiwrite: %r\n", argv0);
164                 return -1;
165         }
166         r = GET2(v);
167         if(r == 0xFFFF)
168                 return -1;
169         return r;
170 }
171
172
173 static int
174 miiwrite(Dev *d, int phy, int reg, int val)
175 {
176         int r;
177         uchar v[2];
178
179         if(asixset(d, Cswmii, 0) < 0)
180                 return -1;
181         r = Rh2d|Rvendor|Rdev;
182         PUT2(v, val);
183         if(usbcmd(d, r, Cwmii, phy, reg, v, 2) < 0){
184                 fprint(2, "%s: miiwrite: %#x %#x %r\n", argv0, reg, val);
185                 return -1;
186         }
187         if(asixset(d, Chwmii, 0) < 0)
188                 return -1;
189         return 0;
190 }
191
192 static int
193 eepromread(Dev *d, int i)
194 {
195         int r;
196         int ec;
197         uchar buf[2];
198
199         r = Rd2h|Rvendor|Rdev;
200         ec = usbcmd(d, r, Creeprom, i, 0, buf, sizeof(buf));
201         if(ec < 0)
202                 fprint(2, "%s: eepromread %d: %r\n", argv0, i);
203         ec = GET2(buf);
204         if(ec == 0xFFFF)
205                 ec = -1;
206         return ec;
207 }
208
209 static int
210 asixreceive(Dev *ep)
211 {
212         Block *b;
213         uint hd;
214         int n;
215
216         b = allocb(Maxpkt+4);
217         if((n = read(ep->dfd, b->wp, b->lim - b->base)) < 0){
218                 freeb(b);
219                 return -1;
220         }
221         b->wp += n;
222         while(BLEN(b) >= 4){
223                 hd = GET4(b->rp);
224                 b->rp += 4;
225                 n = hd & 0xFFFF;
226                 hd = (hd>>16) ^ 0xFFFF;
227                 if((n != hd) || (n > BLEN(b)))
228                         break;
229                 if(n == BLEN(b)){
230                         etheriq(b);
231                         return 0;
232                 }
233                 etheriq(copyblock(b, n));
234                 b->rp += n;
235         }
236         freeb(b);
237         return 0;
238 }
239
240 static void
241 asixtransmit(Dev *ep, Block *b)
242 {
243         uint hd;
244         int n;
245
246         n = BLEN(b);
247         hd = n | (n<<16)^0xFFFF0000;
248         b->rp -= 4;
249         PUT4(b->rp, hd);
250         n += 4;
251         if((n % ep->maxpkt) == 0){
252                 PUT4(b->wp, 0xFFFF0000);
253                 b->wp += 4;
254         }
255         write(ep->dfd, b->rp, BLEN(b));
256         freeb(b);
257 }
258
259 static int
260 asixpromiscuous(Dev *d, int on)
261 {
262         int rxctl;
263
264         rxctl = getrxctl(d);
265         if(on)
266                 rxctl |= Rxctlprom;
267         else
268                 rxctl &= ~Rxctlprom;
269         return asixset(d, Cwrxctl, rxctl);
270 }
271
272 static int
273 asixmulticast(Dev *d, uchar*, int)
274 {
275         int rxctl;
276
277         rxctl = getrxctl(d);
278         if(nmulti != 0)
279                 rxctl |= Rxctlamall;
280         else
281                 rxctl &= ~Rxctlamall;
282         return asixset(d, Cwrxctl, rxctl);
283 }
284
285 int
286 a88178init(Dev *d)
287 {
288         int bmcr;
289         int gpio;
290         int ee17;
291
292         gpio = getgpio(d);
293         if(gpio < 0)
294                 return -1;
295         asixset(d, Cwena, 0);
296         ee17 = eepromread(d, 0x0017);
297         asixset(d, Cwdis, 0);
298         asixset(d, Cwgpio, Gpiorse|Gpiogpo1|Gpiogpo1en);
299         if((ee17 >> 8) != 1){
300                 asixset(d, Cwgpio, 0x003c);
301                 asixset(d, Cwgpio, 0x001c);
302                 asixset(d, Cwgpio, 0x003c);
303         }else{
304                 asixset(d, Cwgpio, Gpiogpo1en);
305                 asixset(d, Cwgpio, Gpiogpo1|Gpiogpo1en);
306         }
307         asixset(d, Creset, Rclear);
308         sleep(150);
309         asixset(d, Creset, Rippd|Rprl);
310         sleep(150);
311         asixset(d, Cwrxctl, 0);
312         if(asixget(d, Crmac, macaddr, Eaddrlen) < 0)
313                 return -1;
314         asixphy = getphy(d);
315         if(ee17 < 0 || (ee17 & 0x7) == 0){
316                 miiwrite(d, asixphy, Miimctl, Mtxrxdly);
317                 sleep(60);
318         }
319         miiwrite(d, asixphy, Miibmcr, Bmcrreset|Bmcranena);
320         miiwrite(d, asixphy, Miiad, Adall|Adcsma|Adpause);
321         miiwrite(d, asixphy, Miic1000, Ad1000f);
322         bmcr = miiread(d, asixphy, Miibmcr);
323         if((bmcr & Bmcranena) != 0){
324                 bmcr |= Bmcrar;
325                 miiwrite(d, asixphy, Miibmcr, bmcr);
326         }
327         asixset(d, Cwmedium, Mall178);
328         asixset(d, Cwrxctl, Rxctlso|Rxctlab);
329
330         epreceive = asixreceive;
331         eptransmit = asixtransmit;
332         eppromiscuous = asixpromiscuous;
333         epmulticast = asixmulticast;
334
335         return 0;
336 }
337
338 int
339 a88772init(Dev *d)
340 {
341         int bmcr;
342         int rc;
343
344         if(asixset(d, Cwgpio, Gpiorse|Gpiogpo2|Gpiogpo2en) < 0)
345                 return -1;
346         asixphy = getphy(d);
347         if((asixphy & Pmask) == Pembed){
348                 /* embedded 10/100 ethernet */
349                 rc = asixset(d, Cwphy, 1);
350         }else
351                 rc = asixset(d, Cwphy, 0);
352         if(rc < 0)
353                 return -1;
354         if(asixset(d, Creset, Rippd|Rprl) < 0)
355                 return -1;
356         sleep(150);
357         if((asixphy & Pmask) == Pembed)
358                 rc = asixset(d, Creset, Riprl);
359         else
360                 rc = asixset(d, Creset, Rprte);
361         if(rc < 0)
362                 return -1;
363         sleep(150);
364         getrxctl(d);
365         if(asixset(d, Cwrxctl, 0) < 0)
366                 return -1;
367         if(asixget(d, Crmac, macaddr, Eaddrlen) < 0)
368                 return -1;
369         if(asixset(d, Creset, Rprl) < 0)
370                 return -1;
371         sleep(150);
372         if(asixset(d, Creset, Riprl|Rprl) < 0)
373                 return -1;
374         sleep(150);
375
376         miiwrite(d, asixphy, Miibmcr, Bmcrreset);
377         miiwrite(d, asixphy, Miiad, Adall|Adcsma);
378         bmcr = miiread(d, asixphy, Miibmcr);
379         if((bmcr & Bmcranena) != 0){
380                 bmcr |= Bmcrar;
381                 miiwrite(d, asixphy, Miibmcr, bmcr);
382         }
383         if(asixset(d, Cwmedium, Mall772) < 0)
384                 return -1;
385         if(asixset(d, Cwipg, Ipgdflt) < 0)
386                 return -1;
387         if(asixset(d, Cwrxctl, Rxctlso|Rxctlab) < 0)
388                 return -1;
389
390         epreceive = asixreceive;
391         eptransmit = asixtransmit;
392         eppromiscuous = asixpromiscuous;
393         epmulticast = asixmulticast;
394
395         return 0;
396 }