diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-02-16 21:16:05 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-02-16 21:16:05 +0100 |
commit | c5c9233c3d807342b28ad063ecd3840003a857b5 (patch) | |
tree | 488fc8f780cd012ab46e29d6b85e310218614cca /sys/src/9/pc/etheriwl.c | |
parent | f6290afb148261aa382d0db1d9c1a3d3f52a09f4 (diff) |
etheriwl: add otp rom initialization (for 1000er series, untested)
Diffstat (limited to 'sys/src/9/pc/etheriwl.c')
-rw-r--r-- | sys/src/9/pc/etheriwl.c | 76 |
1 files changed, 75 insertions, 1 deletions
diff --git a/sys/src/9/pc/etheriwl.c b/sys/src/9/pc/etheriwl.c index 4d49450c6..ffc5a4b1f 100644 --- a/sys/src/9/pc/etheriwl.c +++ b/sys/src/9/pc/etheriwl.c @@ -69,6 +69,7 @@ enum { EepromIo = 0x02c, /* EEPROM i/o register */ EepromGp = 0x030, + OtpromGp = 0x034, DevSelOtp = 1<<16, RelativeAccess = 1<<17, @@ -105,6 +106,7 @@ enum { AnaPll = 0x20c, Dbghpetmem = 0x240, + Dbglinkpwrmgmt = 0x250, MemRaddr = 0x40c, MemWaddr = 0x410, @@ -355,6 +357,9 @@ struct Ctlr { } rfcfg; struct { + int otp; + uint off; + uchar version; uchar type; u16int volt; @@ -542,10 +547,11 @@ static char* eepromread(Ctlr *ctlr, void *data, int count, uint off) { uchar *out = data; - u32int w; + u32int w, s; int i; w = 0; + off += ctlr->eeprom.off; for(; count > 0; count -= 2, off++){ csr32w(ctlr, EepromIo, off << 2); for(i=0; i<10; i++){ @@ -556,6 +562,13 @@ eepromread(Ctlr *ctlr, void *data, int count, uint off) } if(i == 10) return "eepromread: timeout"; + if(ctlr->eeprom.otp){ + s = csr32r(ctlr, OtpromGp); + if(s & EccUncorrStts) + return "eepromread: otprom ecc error"; + if(s & EccCorrStts) + csr32w(ctlr, OtpromGp, s); + } *out++ = w >> 16; if(count > 1) *out++ = w >> 24; @@ -728,6 +741,65 @@ poweroff(Ctlr *ctlr) ctlr->power = 0; } +static char* +rominit(Ctlr *ctlr) +{ + uchar buf[2]; + char *err; + uint off; + int i; + + ctlr->eeprom.otp = 0; + ctlr->eeprom.off = 0; + if(ctlr->type < Type1000 || (csr32r(ctlr, OtpromGp) & DevSelOtp) == 0) + return nil; + + /* Wait for clock stabilization before accessing prph. */ + if((err = clockwait(ctlr)) != nil) + return err; + + if((err = niclock(ctlr)) != nil) + return err; + prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | ResetReq); + delay(5); + prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) & ~ResetReq); + nicunlock(ctlr); + + /* Set auto clock gate disable bit for HW with OTP shadow RAM. */ + if(ctlr->type != Type1000) + csr32w(ctlr, Dbglinkpwrmgmt, csr32r(ctlr, Dbglinkpwrmgmt) | (1<<31)); + + csr32w(ctlr, EepromGp, csr32r(ctlr, EepromGp) & ~0x00000180); + + /* Clear ECC status. */ + csr32w(ctlr, OtpromGp, csr32r(ctlr, OtpromGp) | (EccCorrStts | EccUncorrStts)); + + ctlr->eeprom.otp = 1; + if(ctlr->type != Type1000) + return nil; + + /* Switch to absolute addressing mode. */ + csr32w(ctlr, OtpromGp, csr32r(ctlr, OtpromGp) & ~RelativeAccess); + + /* + * Find the block before last block (contains the EEPROM image) + * for HW without OTP shadow RAM. + */ + off = 0; + for(i=0; i<3; i++){ + if((err = eepromread(ctlr, buf, 2, off)) != nil) + return err; + if(get16(buf) == 0) + break; + off = get16(buf); + } + if(i == 0 || i >= 3) + return "rominit: missing eeprom image"; + + ctlr->eeprom.off = off+1; + return nil; +} + static int iwlinit(Ether *edev) { @@ -747,6 +819,8 @@ iwlinit(Ether *edev) } if((err = eepromlock(ctlr)) != nil) goto Err; + if((err = rominit(ctlr)) != nil) + goto Err2; if((err = eepromread(ctlr, edev->ea, sizeof(edev->ea), 0x15)) != nil){ eepromunlock(ctlr); goto Err; |