changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: nusb/ether: add support for lan78xx (raspi3) (thanks richard miller)

changeset 6828: a803b93706b8
parent 6827: 7b448156e427
child 6829: 9632658d8671
author: cinap_lenrek@felloff.net
date: Sat, 20 Oct 2018 19:30:16 +0200
files: sys/src/cmd/nusb/ether/ether.c sys/src/cmd/nusb/ether/lan78xx.c sys/src/cmd/nusb/ether/mkfile
description: nusb/ether: add support for lan78xx (raspi3) (thanks richard miller)
     1.1--- a/sys/src/cmd/nusb/ether/ether.c
     1.2+++ b/sys/src/cmd/nusb/ether/ether.c
     1.3@@ -886,6 +886,7 @@ extern int aueinit(Dev *);
     1.4 extern int a88178init(Dev *);
     1.5 extern int a88772init(Dev *);
     1.6 extern int smscinit(Dev *);
     1.7+extern int lan78xxinit(Dev *);
     1.8 extern int cdcinit(Dev *);
     1.9 extern int urlinit(Dev *);
    1.10 extern int rndisinit(Dev *);
    1.11@@ -896,6 +897,7 @@ static struct {
    1.12 } ethertype[] = {
    1.13 	"cdc",		cdcinit,
    1.14 	"smsc",		smscinit,
    1.15+	"lan78xx",	lan78xxinit,
    1.16 	"a88178",	a88178init,
    1.17 	"a88772",	a88772init,
    1.18 	"aue",		aueinit,
    1.19@@ -921,7 +923,8 @@ threadmain(int argc, char **argv)
    1.20 		break;
    1.21 	case 'a':
    1.22 		setmac = 1;
    1.23-		parseether(macaddr, EARGF(usage()));
    1.24+		if(parseether(macaddr, EARGF(usage())) != 0)
    1.25+			usage();
    1.26 		break;
    1.27 	case 't':
    1.28 		t = EARGF(usage());
     2.1new file mode 100644
     2.2--- /dev/null
     2.3+++ b/sys/src/cmd/nusb/ether/lan78xx.c
     2.4@@ -0,0 +1,366 @@
     2.5+/*
     2.6+ * Microchip (ex SMSC) LAN78XX
     2.7+ *	 Also used as ethernet core in LAN7515 usb hub + ethernet
     2.8+ */
     2.9+
    2.10+#include <u.h>
    2.11+#include <libc.h>
    2.12+#include <thread.h>
    2.13+
    2.14+#include "usb.h"
    2.15+#include "dat.h"
    2.16+
    2.17+enum {
    2.18+	Doburst		= 1,
    2.19+	Resettime	= 1000,
    2.20+	E2pbusytime	= 1000,
    2.21+	Hsburst		= 32,
    2.22+	Defbulkdly	= 1000,
    2.23+	Rxfifosize	= (12*1024),
    2.24+	Txfifosize	= (12*1024),
    2.25+
    2.26+	MACoffset 	= 1,
    2.27+	PHYinternal	= 1,
    2.28+	Rxerror		= 0x00400000,
    2.29+	Txfcs		= 1<<22,
    2.30+
    2.31+	/* USB vendor requests */
    2.32+	Writereg	= 0xA0,
    2.33+	Readreg		= 0xA1,
    2.34+
    2.35+	/* device registers */
    2.36+	Idrev		= 0x00,
    2.37+	Intsts		= 0x0C,
    2.38+	Hwcfg		= 0x10,
    2.39+		Led0en	= 1<<20,
    2.40+		Led1en	= 1<<21,
    2.41+		Mef	= 1<<4,
    2.42+		Lrst	= 1<<1,
    2.43+	Pmctrl		= 0x14,
    2.44+		Ready	= 1<<7,
    2.45+		Phyrst	= 1<<4,
    2.46+	Gpiocfg0	= 0x18,
    2.47+	Gpiocfg1	= 0x1C,
    2.48+	E2pcmd		= 0x40,
    2.49+		Busy	= 1<<31,
    2.50+		Timeout	= 1<<10,
    2.51+		Loaded	= 1<<9,
    2.52+		Read	= 0,
    2.53+	E2pdata		= 0x44,
    2.54+	Burstcap	= 0x90,
    2.55+	Intepctl	= 0x98,
    2.56+		Phyint	= 1<<17,
    2.57+	Bulkdelay	= 0x94,
    2.58+	Rfectl		= 0xB0,
    2.59+		Rxcoe	= 0xF<<11,
    2.60+		Ab		= 1<<10,
    2.61+		Am		= 1<<9,
    2.62+		Au		= 1<<8,
    2.63+		Dpf		= 1<<1,
    2.64+	Usbcfg0		= 0x80,
    2.65+		Bir	= 1<<6,
    2.66+		Bce	= 1<<5,
    2.67+	Usbcfg1		= 0x84,
    2.68+	Rxfifoctl		= 0xC0,
    2.69+		Rxen	= 1<<31,	
    2.70+	Txfifoctl		= 0xC4,
    2.71+		Txen	= 1<<31,
    2.72+	Rxfifo		= 0xC8,
    2.73+	Txfifo		= 0xCc,
    2.74+	Fctflow		= 0xD0,
    2.75+	Maccr		= 0x100,
    2.76+		Add		= 1<<12,
    2.77+		Asd		= 1<<11,
    2.78+	Macrx		= 0x104,
    2.79+		Macfcs	= 1<<4,
    2.80+		Macrxen	= 1<<0,
    2.81+	Mactx		= 0x108,
    2.82+		Mactxen	= 1<<0,
    2.83+	Addrh		= 0x118,
    2.84+	Addrl		= 0x11C,
    2.85+	MIIaddr		= 0x120,
    2.86+		MIIwrite= 1<<1,
    2.87+		MIIread	= 0<<1,
    2.88+		MIIbusy	= 1<<0,
    2.89+	MIIdata		= 0x124,
    2.90+	Flow		= 0x10C,
    2.91+	Addrfilth	= 0x400,
    2.92+		Afvalid	= 1<<31,
    2.93+	Addrfiltl	= 0x404,
    2.94+
    2.95+	/* MII registers */
    2.96+	Bmcr		= 0,
    2.97+		Bmcrreset= 1<<15,
    2.98+		Speed100= 1<<13,
    2.99+		Anenable= 1<<12,
   2.100+		Anrestart= 1<<9,
   2.101+		Fulldpx	= 1<<8,
   2.102+		Speed1000= 1<<6,
   2.103+	Bmsr		= 1,
   2.104+	Advertise	= 4,
   2.105+		Adcsma	= 0x0001,
   2.106+		Ad10h	= 0x0020,
   2.107+		Ad10f	= 0x0040,
   2.108+		Ad100h	= 0x0080,
   2.109+		Ad100f	= 0x0100,
   2.110+		Adpause	= 0x0400,
   2.111+		Adpauseasym= 0x0800,
   2.112+		Adall	= Ad10h|Ad10f|Ad100h|Ad100f,
   2.113+	Lpa		= 5,
   2.114+	Ctrl1000	= 9,
   2.115+		Ad1000h = 0x0400,
   2.116+		Ad1000f = 0x0200,
   2.117+	Ledmodes	= 29,
   2.118+		Led0shift = 0,
   2.119+		Led1shift = 4,
   2.120+		Linkact = 0x0,
   2.121+		Link1000 = 0x1,
   2.122+	Phyintmask	= 25,
   2.123+		Anegcomp= 1<<10,
   2.124+		Linkchg = 1<<13,
   2.125+};
   2.126+
   2.127+static int burstcap = Hsburst, bulkdelay = Defbulkdly;
   2.128+
   2.129+static int
   2.130+wr(Dev *d, int reg, int val)
   2.131+{
   2.132+	int ret;
   2.133+
   2.134+	ret = usbcmd(d, Rh2d|Rvendor|Rdev, Writereg, 0, reg,
   2.135+		(uchar*)&val, sizeof(val));
   2.136+	if(ret < 0)
   2.137+		fprint(2, "%s: wr(%x, %x): %r", argv0, reg, val);
   2.138+	return ret;
   2.139+}
   2.140+
   2.141+static int
   2.142+rr(Dev *d, int reg)
   2.143+{
   2.144+	int ret, rval;
   2.145+
   2.146+	ret = usbcmd(d, Rd2h|Rvendor|Rdev, Readreg, 0, reg,
   2.147+		(uchar*)&rval, sizeof(rval));
   2.148+	if(ret < 0){
   2.149+		fprint(2, "%s: rr(%x): %r", argv0, reg);
   2.150+		return 0;
   2.151+	}
   2.152+	return rval;
   2.153+}
   2.154+
   2.155+static int
   2.156+miird(Dev *d, int idx)
   2.157+{
   2.158+	while(rr(d, MIIaddr) & MIIbusy)
   2.159+		;
   2.160+	wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIread | MIIbusy);
   2.161+	while(rr(d, MIIaddr) & MIIbusy)
   2.162+		;
   2.163+	return rr(d, MIIdata);
   2.164+}
   2.165+
   2.166+static void
   2.167+miiwr(Dev *d, int idx, int val)
   2.168+{
   2.169+	while(rr(d, MIIaddr) & MIIbusy)
   2.170+		;
   2.171+	wr(d, MIIdata, val);
   2.172+	wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIwrite | MIIbusy);
   2.173+	while(rr(d, MIIaddr) & MIIbusy)
   2.174+		;
   2.175+}
   2.176+
   2.177+static int
   2.178+eepromr(Dev *d, int off, uchar *buf, int len)
   2.179+{
   2.180+	int i, v;
   2.181+
   2.182+	for(i = 0; i < E2pbusytime; i++)
   2.183+		if((rr(d, E2pcmd) & Busy) == 0)
   2.184+			break;
   2.185+	if(i == E2pbusytime)
   2.186+		return -1;
   2.187+	for(i = 0; i < len; i++){
   2.188+		wr(d, E2pcmd, Busy|Read|(i+off));
   2.189+		while((v = rr(d, E2pcmd) & (Busy|Timeout)) == Busy)
   2.190+			;
   2.191+		if(v & Timeout)
   2.192+			return -1;
   2.193+		buf[i] = rr(d, E2pdata);
   2.194+	}
   2.195+	return 0;
   2.196+}
   2.197+
   2.198+static void
   2.199+phyinit(Dev *d)
   2.200+{
   2.201+	int i;
   2.202+
   2.203+	miiwr(d, Bmcr, Bmcrreset|Anenable);
   2.204+	for(i = 0; i < Resettime/10; i++){
   2.205+		if((miird(d, Bmcr) & Bmcrreset) == 0)
   2.206+			break;
   2.207+		sleep(10);
   2.208+	}
   2.209+	miiwr(d, Advertise, Adcsma|Adall|Adpause|Adpauseasym);
   2.210+	miiwr(d, Ctrl1000, Ad1000f);
   2.211+	miiwr(d, Phyintmask, 0);
   2.212+	miiwr(d, Ledmodes, (Linkact<<Led1shift) | (Link1000<<Led0shift));
   2.213+	miiwr(d, Bmcr, miird(d, Bmcr)|Anenable|Anrestart);
   2.214+}
   2.215+
   2.216+
   2.217+static int
   2.218+doreset(Dev *d, int reg, int bit)
   2.219+{
   2.220+	int i;
   2.221+
   2.222+	if(wr(d, reg, bit) < 0)
   2.223+		return -1;
   2.224+	for(i = 0; i < Resettime/10; i++){
   2.225+		 if((rr(d, reg) & bit) == 0)
   2.226+			return 1;
   2.227+		sleep(10);
   2.228+	}
   2.229+	return 0;
   2.230+}
   2.231+
   2.232+static int
   2.233+lan78xxreceive(Dev *ep)
   2.234+{
   2.235+	Block *b;
   2.236+	uint hd;
   2.237+	int n;
   2.238+
   2.239+	n = Doburst? burstcap*512: Maxpkt;
   2.240+	b = allocb(n);
   2.241+	if((n = read(ep->dfd, b->wp, n)) < 10){
   2.242+		freeb(b);
   2.243+		return -1;
   2.244+	}
   2.245+	b->wp += n;
   2.246+	while(BLEN(b) >= 10){
   2.247+		hd = GET4(b->rp);
   2.248+		b->rp += 10;
   2.249+		n = hd & 0x3FFF;
   2.250+		if(n > BLEN(b))
   2.251+			break;
   2.252+		if((hd & Rxerror) == 0){
   2.253+			if(n == BLEN(b)){
   2.254+				etheriq(b);
   2.255+				return 0;
   2.256+			}
   2.257+			etheriq(copyblock(b, n));
   2.258+		}
   2.259+		b->rp = (uchar*)(((uintptr)b->rp + n + 3)&~3);
   2.260+	}
   2.261+	freeb(b);
   2.262+	return 0;
   2.263+}
   2.264+
   2.265+static void
   2.266+lan78xxtransmit(Dev *ep, Block *b)
   2.267+{
   2.268+	int n = BLEN(b) & 0xFFFFF;
   2.269+	b->rp -= 8;
   2.270+	PUT4(b->rp, n | Txfcs);
   2.271+	PUT4(b->rp+4, n);
   2.272+	write(ep->dfd, b->rp, BLEN(b));
   2.273+	freeb(b);
   2.274+}
   2.275+
   2.276+static int
   2.277+lan78xxpromiscuous(Dev *d, int on)
   2.278+{
   2.279+	int rxctl;
   2.280+
   2.281+	rxctl = rr(d, Rfectl);
   2.282+	if(on)
   2.283+		rxctl |= Am|Au;
   2.284+	else {
   2.285+		rxctl &= ~Au;
   2.286+		if(nmulti == 0)
   2.287+			rxctl &= ~Am;
   2.288+	}
   2.289+	return wr(d, Rfectl, rxctl);
   2.290+}
   2.291+
   2.292+static int
   2.293+lan78xxmulticast(Dev *d, uchar *, int)
   2.294+{
   2.295+	int rxctl;
   2.296+
   2.297+	rxctl = rr(d, Rfectl);
   2.298+	if(nmulti != 0)
   2.299+		rxctl |= Am;
   2.300+	else
   2.301+		rxctl &= ~Am;
   2.302+	return wr(d, Rfectl, rxctl);
   2.303+}
   2.304+
   2.305+int
   2.306+lan78xxinit(Dev *d)
   2.307+{
   2.308+	u32int a;
   2.309+	int i;
   2.310+
   2.311+	if(!doreset(d, Hwcfg, Lrst) || !doreset(d, Pmctrl, Phyrst))
   2.312+		return -1;
   2.313+	for(i = 0; i < Resettime/10; i++){
   2.314+		 if(rr(d, Pmctrl) & Ready)
   2.315+			break;
   2.316+		sleep(10);
   2.317+	}
   2.318+	if((rr(d, Pmctrl) & Ready) == 0){
   2.319+		fprint(2, "%s: device not ready after reset\n", argv0);
   2.320+		return -1;
   2.321+	}
   2.322+
   2.323+	if(!setmac)
   2.324+		if(eepromr(d, MACoffset, macaddr, Eaddrlen) < 0)
   2.325+			fprint(2, "%s: can't read etheraddr from EEPROM\n", argv0);
   2.326+
   2.327+	a = GET4(macaddr);
   2.328+	wr(d, Addrl, a);
   2.329+	wr(d, Addrfiltl, a);
   2.330+	a = GET2(macaddr+4);
   2.331+	wr(d, Addrh, a);
   2.332+	wr(d, Addrfilth, a|Afvalid);
   2.333+
   2.334+	wr(d, Usbcfg0, rr(d, Usbcfg0) | Bir);
   2.335+	if(Doburst){
   2.336+		wr(d, Hwcfg, rr(d, Hwcfg)|Mef);
   2.337+		wr(d, Usbcfg0, rr(d, Usbcfg0)|Bce);
   2.338+		wr(d, Burstcap, burstcap);
   2.339+		wr(d, Bulkdelay, bulkdelay);
   2.340+	}else{
   2.341+		wr(d, Hwcfg, rr(d, Hwcfg)&~Mef);
   2.342+		wr(d, Usbcfg0, rr(d, Usbcfg0)&~Bce);
   2.343+		wr(d, Burstcap, 0);
   2.344+		wr(d, Bulkdelay, 0);
   2.345+	}
   2.346+	wr(d, Rxfifo, (Rxfifosize-512)/512);
   2.347+	wr(d, Txfifo, (Txfifosize-512)/512);
   2.348+	wr(d, Intsts, ~0);
   2.349+	wr(d, Hwcfg, rr(d, Hwcfg) | Led0en|Led1en);
   2.350+	wr(d, Flow, 0);
   2.351+	wr(d, Fctflow, 0);
   2.352+	wr(d, Rfectl, (rr(d, Rfectl) & ~Rxcoe) | Ab|Dpf); /* TODO could offload checksums? */
   2.353+
   2.354+	phyinit(d);
   2.355+
   2.356+	wr(d, Maccr, rr(d,Maccr)|Add|Asd);
   2.357+
   2.358+	wr(d, Intepctl, rr(d, Intepctl)|Phyint);
   2.359+	wr(d, Mactx, Mactxen);
   2.360+	wr(d, Macrx, rr(d, Macrx) | Macfcs|Macrxen);
   2.361+	wr(d, Txfifoctl, Txen);
   2.362+	wr(d, Rxfifoctl, Rxen);
   2.363+
   2.364+	eptransmit = lan78xxtransmit;
   2.365+	epreceive = lan78xxreceive;
   2.366+	eppromiscuous = lan78xxpromiscuous;
   2.367+	epmulticast = lan78xxmulticast;
   2.368+
   2.369+	return 0;
   2.370+}
     3.1--- a/sys/src/cmd/nusb/ether/mkfile
     3.2+++ b/sys/src/cmd/nusb/ether/mkfile
     3.3@@ -5,7 +5,7 @@ LIB=../lib/usb.a$O
     3.4 
     3.5 TARG=ether
     3.6 HFILES=../lib/usb.h dat.h
     3.7-OFILES=ether.$O cdc.$O smsc.$O asix.$O aue.$O url.$O rndis.$O
     3.8+OFILES=ether.$O cdc.$O smsc.$O lan78xx.$O asix.$O aue.$O url.$O rndis.$O
     3.9 
    3.10 </sys/src/cmd/mkone
    3.11