summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2014-11-10 00:04:37 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2014-11-10 00:04:37 +0100
commitbcb67353c1ae559d6f91ab0669a06db52000b15d (patch)
treee2e6e9b26b7f13e234315c5753982bca4100dd22
parentb18a6413975a0a8d06e6d310072a0ff90b1ed541 (diff)
pc, pc64: provide access to embedded controller with #P/ec file
-rw-r--r--sys/man/3/arch5
-rw-r--r--sys/src/9/pc/archacpi.c27
-rw-r--r--sys/src/9/pc/devarch.c28
-rw-r--r--sys/src/9/pc/ec.c138
-rw-r--r--sys/src/9/pc/fns.h3
-rw-r--r--sys/src/9/pc/pccpuf1
-rw-r--r--sys/src/9/pc/pcf1
-rw-r--r--sys/src/9/pc64/fns.h3
-rw-r--r--sys/src/9/pc64/pc641
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