diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-11-10 00:04:37 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-11-10 00:04:37 +0100 |
commit | bcb67353c1ae559d6f91ab0669a06db52000b15d (patch) | |
tree | e2e6e9b26b7f13e234315c5753982bca4100dd22 | |
parent | b18a6413975a0a8d06e6d310072a0ff90b1ed541 (diff) |
pc, pc64: provide access to embedded controller with #P/ec file
-rw-r--r-- | sys/man/3/arch | 5 | ||||
-rw-r--r-- | sys/src/9/pc/archacpi.c | 27 | ||||
-rw-r--r-- | sys/src/9/pc/devarch.c | 28 | ||||
-rw-r--r-- | sys/src/9/pc/ec.c | 138 | ||||
-rw-r--r-- | sys/src/9/pc/fns.h | 3 | ||||
-rw-r--r-- | sys/src/9/pc/pccpuf | 1 | ||||
-rw-r--r-- | sys/src/9/pc/pcf | 1 | ||||
-rw-r--r-- | sys/src/9/pc64/fns.h | 3 | ||||
-rw-r--r-- | sys/src/9/pc64/pc64 | 1 |
9 files changed, 205 insertions, 2 deletions
diff --git a/sys/man/3/arch b/sys/man/3/arch index 6640399be..7593904db 100644 --- a/sys/man/3/arch +++ b/sys/man/3/arch @@ -8,6 +8,7 @@ arch \- architecture-specific information and control .B /dev/acpitbls .B /dev/archctl .B /dev/cputype +.B /dev/ec .B /dev/ioalloc .B /dev/iob .B /dev/iol @@ -128,6 +129,10 @@ Reads and writes to .I msr go to the P4/P6/Core/Core2/AMD64 MSRs. .PP +Reads and writes to +.I ec +transfer bytes from and to the embedded controller. +.PP Reads from .I acpitbls return a concatenation of system ACPI tables. Each table diff --git a/sys/src/9/pc/archacpi.c b/sys/src/9/pc/archacpi.c index 7f9a52e51..6805f5c87 100644 --- a/sys/src/9/pc/archacpi.c +++ b/sys/src/9/pc/archacpi.c @@ -453,6 +453,30 @@ enumprt(void *dot, void *) return 1; } +static int +enumec(void *dot, void *) +{ + int cmdport, dataport; + uchar *b; + void *x; + char *id; + + b = nil; + id = eisaid(amlval(amlwalk(dot, "^_HID"))); + if(id == nil || strcmp(id, "PNP0C09") != 0) + return 1; + if((x = amlwalk(dot, "^_CRS")) == nil) + return 1; + if(amleval(x, "", &b) < 0 || amltag(b) != 'b' || amllen(b) < 16) + return 1; + if(b[0] != 0x47 || b[8] != 0x47) /* two i/o port descriptors */ + return 1; + dataport = b[0+2] | b[0+3]<<8; + cmdport = b[8+2] | b[8+3]<<8; + ecinit(cmdport, dataport); + return 1; +} + static void acpiinit(void) { @@ -589,6 +613,9 @@ Foundapic: for(i=0; i<16; i++) addirq(i, BusISA, 0, i, 0); + /* find embedded controller */ + amlenum(amlroot, "_HID", enumec, nil); + /* free the AML interpreter */ amlexit(); diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c index 9265e2696..3d3ef0c1b 100644 --- a/sys/src/9/pc/devarch.c +++ b/sys/src/9/pc/devarch.c @@ -34,6 +34,7 @@ enum { Qiow, Qiol, Qmsr, + Qec, Qbase, Qmax = 16, @@ -62,7 +63,8 @@ static Dirtab archdir[Qmax] = { "iob", { Qiob, 0 }, 0, 0660, "iow", { Qiow, 0 }, 0, 0660, "iol", { Qiol, 0 }, 0, 0660, - "msr", { Qmsr, 0}, 0, 0660, + "msr", { Qmsr, 0 }, 0, 0660, + "ec", { Qec, 0 }, 0, 0660, }; Lock archwlock; /* the lock is only for changing archdir */ int narchdir = Qbase; @@ -361,7 +363,7 @@ static long archread(Chan *c, void *a, long n, vlong offset) { char *buf, *p; - int port; + int port, v; ushort *sp; ulong *lp; vlong *vp; @@ -407,6 +409,19 @@ archread(Chan *c, void *a, long n, vlong offset) error(Ebadarg); return n; + case Qec: + if(offset >= 256) + error(Ebadarg); + if(offset+n > 256) + n = 256 - offset; + p = a; + for(port = offset; port < offset+n; port++){ + if((v = ecread(port)) < 0) + error(Eio); + *p++ = v; + } + return n; + case Qioalloc: break; @@ -486,6 +501,15 @@ archwrite(Chan *c, void *a, long n, vlong offset) error(Ebadarg); return n; + case Qec: + if(offset+n > 256) + error(Ebadarg); + p = a; + for(port = offset; port < offset+n; port++) + if(ecwrite(port, *p++) < 0) + error(Eio); + return n; + default: if(c->qid.path < narchdir && (fn = writefn[c->qid.path])) return fn(c, a, n, offset); diff --git a/sys/src/9/pc/ec.c b/sys/src/9/pc/ec.c new file mode 100644 index 000000000..c42356af7 --- /dev/null +++ b/sys/src/9/pc/ec.c @@ -0,0 +1,138 @@ +/* + * embedded controller (usually at ports 0x66/0x62) + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +enum { + /* registers */ + EC_SC = 0, + EC_DATA, + + /* Embedded Controller Status, EC_SC (R) */ + OBF = 1<<0, + IBF = 1<<1, + CMD = 1<<3, + BURST = 1<<4, + SCI_EVT = 1<<5, + SMI_EVT = 1<<6, + + /* Embedded Controller Command Set */ + RD_EC = 0x80, + WR_EC = 0x81, + BE_EC = 0x82, + BD_EC = 0x83, + QR_EC = 0x84, +}; + +static struct { + Lock; + int init; + int port[2]; /* EC_SC and EC_DATA */ +} ec; + +static uchar +ecrr(int reg) +{ + return inb(ec.port[reg]); +} +static void +ecwr(int reg, uchar val) +{ + outb(ec.port[reg], val); +} + +static int +ecwait(uchar mask, uchar val) +{ + int i, s; + + s = 0; + for(i=0; i<1000; i++){ + s = ecrr(EC_SC); + if((s & mask) == val) + return 0; + delay(1); + } + print("ec: wait timeout status=%x pc=%#p\n", s, getcallerpc(&mask)); + return -1; +} + +int +ecinit(int cmdport, int dataport) +{ + print("ec: cmd %X, data %X\n", cmdport, dataport); + + if(ioalloc(cmdport, 1, 0, "ec.sc") < 0){ + print("ec: cant allocate cmd port %X\n", cmdport); + return -1; + } + if(ioalloc(dataport, 1, 0, "ec.data") < 0){ + print("ec: cant allocate data port %X\n", dataport); + iofree(cmdport); + return -1; + } + + lock(&ec); + ec.port[EC_SC] = cmdport; + ec.port[EC_DATA] = dataport; + ec.init = 1; + unlock(&ec); + + return 0; +} + +int +ecread(uchar addr) +{ + int r; + + r = -1; + lock(&ec); + if(!ec.init) + goto out; + if(ecwait(BURST|CMD, 0)) + goto out; + ecwr(EC_SC, RD_EC); + if(ecwait(IBF, 0)) + goto out; + ecwr(EC_DATA, addr); + if(ecwait(OBF, OBF)) + goto out; + r = ecrr(EC_DATA); + ecwait(OBF, 0); +out: + unlock(&ec); + return r; +} + +int +ecwrite(uchar addr, uchar val) +{ + int r; + + r = -1; + lock(&ec); + if(!ec.init) + goto out; + if(ecwait(BURST|CMD, 0)) + goto out; + ecwr(EC_SC, WR_EC); + if(ecwait(IBF, 0)) + goto out; + ecwr(EC_DATA, addr); + if(ecwait(IBF, 0)) + goto out; + ecwr(EC_DATA, val); + if(ecwait(IBF, 0)) + goto out; + r = 0; +out: + unlock(&ec); + return r; +} diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h index 93178a000..ccf5ea092 100644 --- a/sys/src/9/pc/fns.h +++ b/sys/src/9/pc/fns.h @@ -30,6 +30,9 @@ int dmainit(int, int); #define DMALOOP 2 long dmasetup(int, void*, long, int); void dumpmcregs(void); +int ecinit(int cmdport, int dataport); +int ecread(uchar addr); +int ecwrite(uchar addr, uchar val); #define evenaddr(x) /* x86 doesn't care */ void fpclear(void); void fpenv(FPsave*); diff --git a/sys/src/9/pc/pccpuf b/sys/src/9/pc/pccpuf index c4bf61db6..4956ac541 100644 --- a/sys/src/9/pc/pccpuf +++ b/sys/src/9/pc/pccpuf @@ -85,6 +85,7 @@ misc archacpi mp apic squidboy archmp mp apic squidboy mtrr + ec uarti8250 uartisa diff --git a/sys/src/9/pc/pcf b/sys/src/9/pc/pcf index 27060708d..71e0baebb 100644 --- a/sys/src/9/pc/pcf +++ b/sys/src/9/pc/pcf @@ -87,6 +87,7 @@ misc archacpi mp apic squidboy archmp mp apic squidboy mtrr + ec sdaoe sdide pci sdscsi diff --git a/sys/src/9/pc64/fns.h b/sys/src/9/pc64/fns.h index 15eb1a0f5..652d07737 100644 --- a/sys/src/9/pc64/fns.h +++ b/sys/src/9/pc64/fns.h @@ -30,6 +30,9 @@ int dmainit(int, int); #define DMALOOP 2 long dmasetup(int, void*, long, int); void dumpmcregs(void); +int ecinit(int cmdport, int dataport); +int ecread(uchar addr); +int ecwrite(uchar addr, uchar val); #define evenaddr(x) /* x86 doesn't care */ void (*fprestore)(FPsave*); void (*fpsave)(FPsave*); diff --git a/sys/src/9/pc64/pc64 b/sys/src/9/pc64/pc64 index 25101e768..e1018fa84 100644 --- a/sys/src/9/pc64/pc64 +++ b/sys/src/9/pc64/pc64 @@ -85,6 +85,7 @@ misc archacpi mp apic squidboy archmp mp apic squidboy mtrr + ec # sdaoe sdide pci sdscsi |