code: plan9front

Download patch

ref: d8487e98c64cc1473e6d4158392850a9d434e418
parent: 6198954859caa0de243756291c8dad75b71dcaee
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed May 20 05:49:27 EDT 2015

etherigbe: spi eeprom support (thanks echoline)

--- a/sys/src/9/pc/etherigbe.c
+++ b/sys/src/9/pc/etherigbe.c
@@ -1572,6 +1572,12 @@
 			else
 				r = i;
 			continue;
+		case 'H':
+			eecd |= Do;
+			continue;
+		case 'h':
+			eecd &= ~Do;
+			continue;
 		case 'I':			/* assert data input */
 			eecd |= Di;
 			break;
@@ -1586,7 +1592,10 @@
 			break;
 		}
 		csr32w(ctlr, Eecd, eecd);
-		microdelay(50);
+		if (eecd & Spi)
+			microdelay(1);
+		else
+			microdelay(50);
 	}
 	if(loop >= 0)
 		return -1;
@@ -1600,18 +1609,9 @@
 	char rop[20];
 	int addr, areq, bits, data, eecd, i;
 
+	sum = 0;
 	eecd = csr32r(ctlr, Eecd);
-	if(eecd & Spi){
-		print("igbe: SPI EEPROM access not implemented\n");
-		return 0;
-	}
-	if(eecd & (Eeszaddr|Eesz256))
-		bits = 8;
-	else
-		bits = 6;
 
-	sum = 0;
-
 	switch(ctlr->id){
 	default:
 		areq = 0;
@@ -1641,23 +1641,63 @@
 		}
 		break;
 	}
-	snprint(rop, sizeof(rop), "S :%dDCc;", bits+3);
 
-	for(addr = 0; addr < 0x40; addr++){
-		/*
-		 * Read a word at address 'addr' from the Atmel AT93C46
-		 * 3-Wire Serial EEPROM or compatible. The EEPROM access is
-		 * controlled by 4 bits in Eecd. See the AT93C46 datasheet
-		 * for protocol details.
-		 */
-		if(at93c46io(ctlr, rop, (0x06<<bits)|addr) != 0){
-			print("igbe: can't set EEPROM address 0x%2.2X\n", addr);
+	if(eecd & Spi){
+		for(i = 0; i < 1000; i++){
+			at93c46io(ctlr, "H :8HDCc;", 0x05);
+			data = at93c46io(ctlr, "h :8COc;", 0);
+
+			if (!(data & 0x1))
+				break;
+
+			microdelay(5);
+			at93c46io(ctlr, "Ss", 0);
+		}
+		if(i == 1000){
+			print("igbe: SPI EEPROM not ready\n");
 			goto release;
 		}
-		data = at93c46io(ctlr, ":16COc;", 0);
-		at93c46io(ctlr, "sic", 0);
-		ctlr->eeprom[addr] = data;
-		sum += data;
+
+		at93c46io(ctlr, "Ss H :8HDCc;", 0x03);
+
+		if(eecd & Eeszaddr)
+			bits = 16;
+		else
+			bits = 8;
+		snprint(rop, sizeof(rop), "H :%dHDCc;", bits);
+		if(at93c46io(ctlr, rop, 0) != 0){
+			print("igbe: can't set EEPROM address 0x00\n");
+			goto release;
+		}
+
+		for(addr = 0; addr < 0x40; addr++){
+			data = at93c46io(ctlr, "h :16COc;", 0);
+			ctlr->eeprom[addr] = (data >> 8) | (data << 8);
+			sum += ctlr->eeprom[addr];
+		}
+	} else {
+		if(eecd & (Eeszaddr|Eesz256))
+			bits = 8;
+		else
+			bits = 6;
+		snprint(rop, sizeof(rop), "S :%dDCc;", bits+3);
+
+		for(addr = 0; addr < 0x40; addr++){
+			/*
+			 * Read a word at address 'addr' from the Atmel AT93C46
+			 * 3-Wire Serial EEPROM or compatible. The EEPROM access is
+			 * controlled by 4 bits in Eecd. See the AT93C46 datasheet
+			 * for protocol details.
+			 */
+			if(at93c46io(ctlr, rop, (0x06<<bits)|addr) != 0){
+				print("igbe: can't set EEPROM address 0x%2.2X\n", addr);
+				goto release;
+			}
+			data = at93c46io(ctlr, ":16COc;", 0);
+			at93c46io(ctlr, "sic", 0);
+			ctlr->eeprom[addr] = data;
+			sum += data;
+		}
 	}
 
 release: