pc, pc64: provide access to embedded controller with #P/ec file
This commit is contained in:
parent
b18a641397
commit
bcb67353c1
9 changed files with 205 additions and 2 deletions
|
@ -8,6 +8,7 @@ arch \- architecture-specific information and control
|
||||||
.B /dev/acpitbls
|
.B /dev/acpitbls
|
||||||
.B /dev/archctl
|
.B /dev/archctl
|
||||||
.B /dev/cputype
|
.B /dev/cputype
|
||||||
|
.B /dev/ec
|
||||||
.B /dev/ioalloc
|
.B /dev/ioalloc
|
||||||
.B /dev/iob
|
.B /dev/iob
|
||||||
.B /dev/iol
|
.B /dev/iol
|
||||||
|
@ -128,6 +129,10 @@ Reads and writes to
|
||||||
.I msr
|
.I msr
|
||||||
go to the P4/P6/Core/Core2/AMD64 MSRs.
|
go to the P4/P6/Core/Core2/AMD64 MSRs.
|
||||||
.PP
|
.PP
|
||||||
|
Reads and writes to
|
||||||
|
.I ec
|
||||||
|
transfer bytes from and to the embedded controller.
|
||||||
|
.PP
|
||||||
Reads from
|
Reads from
|
||||||
.I acpitbls
|
.I acpitbls
|
||||||
return a concatenation of system ACPI tables. Each table
|
return a concatenation of system ACPI tables. Each table
|
||||||
|
|
|
@ -453,6 +453,30 @@ enumprt(void *dot, void *)
|
||||||
return 1;
|
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
|
static void
|
||||||
acpiinit(void)
|
acpiinit(void)
|
||||||
{
|
{
|
||||||
|
@ -589,6 +613,9 @@ Foundapic:
|
||||||
for(i=0; i<16; i++)
|
for(i=0; i<16; i++)
|
||||||
addirq(i, BusISA, 0, i, 0);
|
addirq(i, BusISA, 0, i, 0);
|
||||||
|
|
||||||
|
/* find embedded controller */
|
||||||
|
amlenum(amlroot, "_HID", enumec, nil);
|
||||||
|
|
||||||
/* free the AML interpreter */
|
/* free the AML interpreter */
|
||||||
amlexit();
|
amlexit();
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ enum {
|
||||||
Qiow,
|
Qiow,
|
||||||
Qiol,
|
Qiol,
|
||||||
Qmsr,
|
Qmsr,
|
||||||
|
Qec,
|
||||||
Qbase,
|
Qbase,
|
||||||
|
|
||||||
Qmax = 16,
|
Qmax = 16,
|
||||||
|
@ -62,7 +63,8 @@ static Dirtab archdir[Qmax] = {
|
||||||
"iob", { Qiob, 0 }, 0, 0660,
|
"iob", { Qiob, 0 }, 0, 0660,
|
||||||
"iow", { Qiow, 0 }, 0, 0660,
|
"iow", { Qiow, 0 }, 0, 0660,
|
||||||
"iol", { Qiol, 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 */
|
Lock archwlock; /* the lock is only for changing archdir */
|
||||||
int narchdir = Qbase;
|
int narchdir = Qbase;
|
||||||
|
@ -361,7 +363,7 @@ static long
|
||||||
archread(Chan *c, void *a, long n, vlong offset)
|
archread(Chan *c, void *a, long n, vlong offset)
|
||||||
{
|
{
|
||||||
char *buf, *p;
|
char *buf, *p;
|
||||||
int port;
|
int port, v;
|
||||||
ushort *sp;
|
ushort *sp;
|
||||||
ulong *lp;
|
ulong *lp;
|
||||||
vlong *vp;
|
vlong *vp;
|
||||||
|
@ -407,6 +409,19 @@ archread(Chan *c, void *a, long n, vlong offset)
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
return n;
|
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:
|
case Qioalloc:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -486,6 +501,15 @@ archwrite(Chan *c, void *a, long n, vlong offset)
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
return n;
|
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:
|
default:
|
||||||
if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
|
if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
|
||||||
return fn(c, a, n, offset);
|
return fn(c, a, n, offset);
|
||||||
|
|
138
sys/src/9/pc/ec.c
Normal file
138
sys/src/9/pc/ec.c
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -30,6 +30,9 @@ int dmainit(int, int);
|
||||||
#define DMALOOP 2
|
#define DMALOOP 2
|
||||||
long dmasetup(int, void*, long, int);
|
long dmasetup(int, void*, long, int);
|
||||||
void dumpmcregs(void);
|
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 */
|
#define evenaddr(x) /* x86 doesn't care */
|
||||||
void fpclear(void);
|
void fpclear(void);
|
||||||
void fpenv(FPsave*);
|
void fpenv(FPsave*);
|
||||||
|
|
|
@ -85,6 +85,7 @@ misc
|
||||||
archacpi mp apic squidboy
|
archacpi mp apic squidboy
|
||||||
archmp mp apic squidboy
|
archmp mp apic squidboy
|
||||||
mtrr
|
mtrr
|
||||||
|
ec
|
||||||
|
|
||||||
uarti8250
|
uarti8250
|
||||||
uartisa
|
uartisa
|
||||||
|
|
|
@ -87,6 +87,7 @@ misc
|
||||||
archacpi mp apic squidboy
|
archacpi mp apic squidboy
|
||||||
archmp mp apic squidboy
|
archmp mp apic squidboy
|
||||||
mtrr
|
mtrr
|
||||||
|
ec
|
||||||
|
|
||||||
sdaoe
|
sdaoe
|
||||||
sdide pci sdscsi
|
sdide pci sdscsi
|
||||||
|
|
|
@ -30,6 +30,9 @@ int dmainit(int, int);
|
||||||
#define DMALOOP 2
|
#define DMALOOP 2
|
||||||
long dmasetup(int, void*, long, int);
|
long dmasetup(int, void*, long, int);
|
||||||
void dumpmcregs(void);
|
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 */
|
#define evenaddr(x) /* x86 doesn't care */
|
||||||
void (*fprestore)(FPsave*);
|
void (*fprestore)(FPsave*);
|
||||||
void (*fpsave)(FPsave*);
|
void (*fpsave)(FPsave*);
|
||||||
|
|
|
@ -85,6 +85,7 @@ misc
|
||||||
archacpi mp apic squidboy
|
archacpi mp apic squidboy
|
||||||
archmp mp apic squidboy
|
archmp mp apic squidboy
|
||||||
mtrr
|
mtrr
|
||||||
|
ec
|
||||||
|
|
||||||
# sdaoe
|
# sdaoe
|
||||||
sdide pci sdscsi
|
sdide pci sdscsi
|
||||||
|
|
Loading…
Reference in a new issue