diff options
| author | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-10-20 19:30:16 +0200 |
|---|---|---|
| committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-10-20 19:30:16 +0200 |
| commit | 86a9f92f47f9cb5d9eb3806e458d856b0ee81b08 (patch) | |
| tree | 9109c91831f864dee4dd03ebf0a1e7c2cf4a6de7 | |
| parent | 29865005f9c90b6addc423221afa421bf555c84e (diff) | |
| download | plan9front-86a9f92f47f9cb5d9eb3806e458d856b0ee81b08.tar.xz | |
nusb/ether: add support for lan78xx (raspi3) (thanks richard miller)
| -rw-r--r-- | sys/src/cmd/nusb/ether/ether.c | 5 | ||||
| -rw-r--r-- | sys/src/cmd/nusb/ether/lan78xx.c | 366 | ||||
| -rw-r--r-- | sys/src/cmd/nusb/ether/mkfile | 2 |
3 files changed, 371 insertions, 2 deletions
diff --git a/sys/src/cmd/nusb/ether/ether.c b/sys/src/cmd/nusb/ether/ether.c index 9c3d7626e..6e6c3059c 100644 --- a/sys/src/cmd/nusb/ether/ether.c +++ b/sys/src/cmd/nusb/ether/ether.c @@ -886,6 +886,7 @@ extern int aueinit(Dev *); extern int a88178init(Dev *); extern int a88772init(Dev *); extern int smscinit(Dev *); +extern int lan78xxinit(Dev *); extern int cdcinit(Dev *); extern int urlinit(Dev *); extern int rndisinit(Dev *); @@ -896,6 +897,7 @@ static struct { } ethertype[] = { "cdc", cdcinit, "smsc", smscinit, + "lan78xx", lan78xxinit, "a88178", a88178init, "a88772", a88772init, "aue", aueinit, @@ -921,7 +923,8 @@ threadmain(int argc, char **argv) break; case 'a': setmac = 1; - parseether(macaddr, EARGF(usage())); + if(parseether(macaddr, EARGF(usage())) != 0) + usage(); break; case 't': t = EARGF(usage()); diff --git a/sys/src/cmd/nusb/ether/lan78xx.c b/sys/src/cmd/nusb/ether/lan78xx.c new file mode 100644 index 000000000..6dea7d7e8 --- /dev/null +++ b/sys/src/cmd/nusb/ether/lan78xx.c @@ -0,0 +1,366 @@ +/* + * Microchip (ex SMSC) LAN78XX + * Also used as ethernet core in LAN7515 usb hub + ethernet + */ + +#include <u.h> +#include <libc.h> +#include <thread.h> + +#include "usb.h" +#include "dat.h" + +enum { + Doburst = 1, + Resettime = 1000, + E2pbusytime = 1000, + Hsburst = 32, + Defbulkdly = 1000, + Rxfifosize = (12*1024), + Txfifosize = (12*1024), + + MACoffset = 1, + PHYinternal = 1, + Rxerror = 0x00400000, + Txfcs = 1<<22, + + /* USB vendor requests */ + Writereg = 0xA0, + Readreg = 0xA1, + + /* device registers */ + Idrev = 0x00, + Intsts = 0x0C, + Hwcfg = 0x10, + Led0en = 1<<20, + Led1en = 1<<21, + Mef = 1<<4, + Lrst = 1<<1, + Pmctrl = 0x14, + Ready = 1<<7, + Phyrst = 1<<4, + Gpiocfg0 = 0x18, + Gpiocfg1 = 0x1C, + E2pcmd = 0x40, + Busy = 1<<31, + Timeout = 1<<10, + Loaded = 1<<9, + Read = 0, + E2pdata = 0x44, + Burstcap = 0x90, + Intepctl = 0x98, + Phyint = 1<<17, + Bulkdelay = 0x94, + Rfectl = 0xB0, + Rxcoe = 0xF<<11, + Ab = 1<<10, + Am = 1<<9, + Au = 1<<8, + Dpf = 1<<1, + Usbcfg0 = 0x80, + Bir = 1<<6, + Bce = 1<<5, + Usbcfg1 = 0x84, + Rxfifoctl = 0xC0, + Rxen = 1<<31, + Txfifoctl = 0xC4, + Txen = 1<<31, + Rxfifo = 0xC8, + Txfifo = 0xCc, + Fctflow = 0xD0, + Maccr = 0x100, + Add = 1<<12, + Asd = 1<<11, + Macrx = 0x104, + Macfcs = 1<<4, + Macrxen = 1<<0, + Mactx = 0x108, + Mactxen = 1<<0, + Addrh = 0x118, + Addrl = 0x11C, + MIIaddr = 0x120, + MIIwrite= 1<<1, + MIIread = 0<<1, + MIIbusy = 1<<0, + MIIdata = 0x124, + Flow = 0x10C, + Addrfilth = 0x400, + Afvalid = 1<<31, + Addrfiltl = 0x404, + + /* MII registers */ + Bmcr = 0, + Bmcrreset= 1<<15, + Speed100= 1<<13, + Anenable= 1<<12, + Anrestart= 1<<9, + Fulldpx = 1<<8, + Speed1000= 1<<6, + Bmsr = 1, + Advertise = 4, + Adcsma = 0x0001, + Ad10h = 0x0020, + Ad10f = 0x0040, + Ad100h = 0x0080, + Ad100f = 0x0100, + Adpause = 0x0400, + Adpauseasym= 0x0800, + Adall = Ad10h|Ad10f|Ad100h|Ad100f, + Lpa = 5, + Ctrl1000 = 9, + Ad1000h = 0x0400, + Ad1000f = 0x0200, + Ledmodes = 29, + Led0shift = 0, + Led1shift = 4, + Linkact = 0x0, + Link1000 = 0x1, + Phyintmask = 25, + Anegcomp= 1<<10, + Linkchg = 1<<13, +}; + +static int burstcap = Hsburst, bulkdelay = Defbulkdly; + +static int +wr(Dev *d, int reg, int val) +{ + int ret; + + ret = usbcmd(d, Rh2d|Rvendor|Rdev, Writereg, 0, reg, + (uchar*)&val, sizeof(val)); + if(ret < 0) + fprint(2, "%s: wr(%x, %x): %r", argv0, reg, val); + return ret; +} + +static int +rr(Dev *d, int reg) +{ + int ret, rval; + + ret = usbcmd(d, Rd2h|Rvendor|Rdev, Readreg, 0, reg, + (uchar*)&rval, sizeof(rval)); + if(ret < 0){ + fprint(2, "%s: rr(%x): %r", argv0, reg); + return 0; + } + return rval; +} + +static int +miird(Dev *d, int idx) +{ + while(rr(d, MIIaddr) & MIIbusy) + ; + wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIread | MIIbusy); + while(rr(d, MIIaddr) & MIIbusy) + ; + return rr(d, MIIdata); +} + +static void +miiwr(Dev *d, int idx, int val) +{ + while(rr(d, MIIaddr) & MIIbusy) + ; + wr(d, MIIdata, val); + wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIwrite | MIIbusy); + while(rr(d, MIIaddr) & MIIbusy) + ; +} + +static int +eepromr(Dev *d, int off, uchar *buf, int len) +{ + int i, v; + + for(i = 0; i < E2pbusytime; i++) + if((rr(d, E2pcmd) & Busy) == 0) + break; + if(i == E2pbusytime) + return -1; + for(i = 0; i < len; i++){ + wr(d, E2pcmd, Busy|Read|(i+off)); + while((v = rr(d, E2pcmd) & (Busy|Timeout)) == Busy) + ; + if(v & Timeout) + return -1; + buf[i] = rr(d, E2pdata); + } + return 0; +} + +static void +phyinit(Dev *d) +{ + int i; + + miiwr(d, Bmcr, Bmcrreset|Anenable); + for(i = 0; i < Resettime/10; i++){ + if((miird(d, Bmcr) & Bmcrreset) == 0) + break; + sleep(10); + } + miiwr(d, Advertise, Adcsma|Adall|Adpause|Adpauseasym); + miiwr(d, Ctrl1000, Ad1000f); + miiwr(d, Phyintmask, 0); + miiwr(d, Ledmodes, (Linkact<<Led1shift) | (Link1000<<Led0shift)); + miiwr(d, Bmcr, miird(d, Bmcr)|Anenable|Anrestart); +} + + +static int +doreset(Dev *d, int reg, int bit) +{ + int i; + + if(wr(d, reg, bit) < 0) + return -1; + for(i = 0; i < Resettime/10; i++){ + if((rr(d, reg) & bit) == 0) + return 1; + sleep(10); + } + return 0; +} + +static int +lan78xxreceive(Dev *ep) +{ + Block *b; + uint hd; + int n; + + n = Doburst? burstcap*512: Maxpkt; + b = allocb(n); + if((n = read(ep->dfd, b->wp, n)) < 10){ + freeb(b); + return -1; + } + b->wp += n; + while(BLEN(b) >= 10){ + hd = GET4(b->rp); + b->rp += 10; + n = hd & 0x3FFF; + if(n > BLEN(b)) + break; + if((hd & Rxerror) == 0){ + if(n == BLEN(b)){ + etheriq(b); + return 0; + } + etheriq(copyblock(b, n)); + } + b->rp = (uchar*)(((uintptr)b->rp + n + 3)&~3); + } + freeb(b); + return 0; +} + +static void +lan78xxtransmit(Dev *ep, Block *b) +{ + int n = BLEN(b) & 0xFFFFF; + b->rp -= 8; + PUT4(b->rp, n | Txfcs); + PUT4(b->rp+4, n); + write(ep->dfd, b->rp, BLEN(b)); + freeb(b); +} + +static int +lan78xxpromiscuous(Dev *d, int on) +{ + int rxctl; + + rxctl = rr(d, Rfectl); + if(on) + rxctl |= Am|Au; + else { + rxctl &= ~Au; + if(nmulti == 0) + rxctl &= ~Am; + } + return wr(d, Rfectl, rxctl); +} + +static int +lan78xxmulticast(Dev *d, uchar *, int) +{ + int rxctl; + + rxctl = rr(d, Rfectl); + if(nmulti != 0) + rxctl |= Am; + else + rxctl &= ~Am; + return wr(d, Rfectl, rxctl); +} + +int +lan78xxinit(Dev *d) +{ + u32int a; + int i; + + if(!doreset(d, Hwcfg, Lrst) || !doreset(d, Pmctrl, Phyrst)) + return -1; + for(i = 0; i < Resettime/10; i++){ + if(rr(d, Pmctrl) & Ready) + break; + sleep(10); + } + if((rr(d, Pmctrl) & Ready) == 0){ + fprint(2, "%s: device not ready after reset\n", argv0); + return -1; + } + + if(!setmac) + if(eepromr(d, MACoffset, macaddr, Eaddrlen) < 0) + fprint(2, "%s: can't read etheraddr from EEPROM\n", argv0); + + a = GET4(macaddr); + wr(d, Addrl, a); + wr(d, Addrfiltl, a); + a = GET2(macaddr+4); + wr(d, Addrh, a); + wr(d, Addrfilth, a|Afvalid); + + wr(d, Usbcfg0, rr(d, Usbcfg0) | Bir); + if(Doburst){ + wr(d, Hwcfg, rr(d, Hwcfg)|Mef); + wr(d, Usbcfg0, rr(d, Usbcfg0)|Bce); + wr(d, Burstcap, burstcap); + wr(d, Bulkdelay, bulkdelay); + }else{ + wr(d, Hwcfg, rr(d, Hwcfg)&~Mef); + wr(d, Usbcfg0, rr(d, Usbcfg0)&~Bce); + wr(d, Burstcap, 0); + wr(d, Bulkdelay, 0); + } + wr(d, Rxfifo, (Rxfifosize-512)/512); + wr(d, Txfifo, (Txfifosize-512)/512); + wr(d, Intsts, ~0); + wr(d, Hwcfg, rr(d, Hwcfg) | Led0en|Led1en); + wr(d, Flow, 0); + wr(d, Fctflow, 0); + wr(d, Rfectl, (rr(d, Rfectl) & ~Rxcoe) | Ab|Dpf); /* TODO could offload checksums? */ + + phyinit(d); + + wr(d, Maccr, rr(d,Maccr)|Add|Asd); + + wr(d, Intepctl, rr(d, Intepctl)|Phyint); + wr(d, Mactx, Mactxen); + wr(d, Macrx, rr(d, Macrx) | Macfcs|Macrxen); + wr(d, Txfifoctl, Txen); + wr(d, Rxfifoctl, Rxen); + + eptransmit = lan78xxtransmit; + epreceive = lan78xxreceive; + eppromiscuous = lan78xxpromiscuous; + epmulticast = lan78xxmulticast; + + return 0; +} diff --git a/sys/src/cmd/nusb/ether/mkfile b/sys/src/cmd/nusb/ether/mkfile index f1db03b44..180ab1854 100644 --- a/sys/src/cmd/nusb/ether/mkfile +++ b/sys/src/cmd/nusb/ether/mkfile @@ -5,7 +5,7 @@ LIB=../lib/usb.a$O TARG=ether HFILES=../lib/usb.h dat.h -OFILES=ether.$O cdc.$O smsc.$O asix.$O aue.$O url.$O rndis.$O +OFILES=ether.$O cdc.$O smsc.$O lan78xx.$O asix.$O aue.$O url.$O rndis.$O </sys/src/cmd/mkone |
