work in progress. - add power button, and number of gpes to acpictl - only turn on the sci if it's off (as per spec) - only intrenable sci if successful, - clear pm1sts before calling power button fn. - use configured pm1ctl values for S5 state (soft power off) - read *all* of the pm1 banked register to prevent read tearing. (bug: not locked; bug: need to apply to other banked registers.) Reference: /n/atom/patch/applied2013/devacpicfg Date: Tue Oct 22 08:15:14 CES 2013 Signed-off-by: quanstro@quanstro.net --- /sys/src/nix/k10/devacpi.c Tue Oct 22 08:15:11 2013 +++ /sys/src/nix/k10/devacpi.c Tue Oct 22 08:15:12 2013 @@ -46,7 +46,7 @@ Qdir = 0, Qctl, - Qtbl, + Qevent, }; static Cmdtab ctls[] = { @@ -58,11 +58,11 @@ static Dirtab acpidir[]={ ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "acpictl", {Qctl}, 0, 0666, - "acpitbl", {Qtbl}, 0, 0444, + "acpievent", {Qevent}, 0, 0444, }; static Gpe* gpes; /* General purpose events */ -static int ngpes; +static int ngpe; static Aconf aconf; static int @@ -149,32 +149,47 @@ return r; } +/* + * we must read the register group *as a whole* + */ static uint getpm1ctl(void) { return getbanked(fadt.pm1acntblk, fadt.pm1bcntblk, fadt.pm1cntlen); } -static void -setpm1sts(uint v) -{ - DBG("acpi: setpm1sts %#ux\n", v); - setbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen/2, v); -} - static uint getpm1sts(void) { - return getbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen/2); + return getbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen) & 0xffff; } static uint getpm1en(void) { - int sz; + return getbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen)>>16; +} + +static void +setpm1en(uint v) +{ + u32int r; - sz = fadt.pm1evtlen/2; - return getbanked(fadt.pm1aevtblk+sz, fadt.pm1bevtblk+sz, sz); + r = getbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen); + r &= 0xffff; + setbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen, r | v<<16); +} + +static void +setpm1sts(uint v) +{ + u32int r; + + DBG("acpi: setpm1sts %#ux\n", v); + + r = getbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen); + r &= 0xffff0000; + setbanked(fadt.pm1aevtblk, fadt.pm1bevtblk, fadt.pm1evtlen, r | v); } static int @@ -209,14 +224,16 @@ } static void -setpm1ctl(uint u) +setpm1ctl(uint a, uint b) { - setbanked(fadt.pm1acntblk, fadt.pm1bcntblk, fadt.pm1cntlen, u); + setbanked(fadt.pm1acntblk, 0, fadt.pm1cntlen, a); + setbanked(0, fadt.pm1bcntblk, fadt.pm1cntlen, b); } void acpipoweroff(void) { + uint *t; enum { Go = 1<<13, Sstate = 1<<10, @@ -226,7 +243,8 @@ /* * bug: we're assuming that this is a fixed function */ - setpm1ctl(7*Sstate| Go); + t = acpicfg.sval[5]; + setpm1ctl(t[0]*Sstate | Go, t[1]*Sstate | Go); } void @@ -269,7 +287,7 @@ int i; uint sts, en; - for(i = 0; i < ngpes; i++) + for(i = 0; i < ngpe; i++) if(getgpests(i)){ iprint("gpe %d on\n", i); en = getgpeen(i); @@ -283,11 +301,13 @@ en = getpm1en(); iprint("acpinitr: pm1sts %#ux pm1en %#ux\n", sts, en); if(sts&en){ - iprint("acpinitr: have enabled events\n"); + iprint("acpinitr: enabled: %#ux\n", sts&en); } - setpm1sts(sts); - if(sts&Epowerbtn) + setpm1sts(sts); + if(sts&Epowerbtn){ aconf.powerbutton(); + // qiwrite(event.q, "power"); + } } static void @@ -297,8 +317,8 @@ n0 = fadt.gpe0blklen/2; n1 = fadt.gpe1blklen/2; - ngpes = n0 + n1; - gpes = mallocz(sizeof(Gpe) * ngpes, 1); + ngpe = n0 + n1; + gpes = mallocz(sizeof(Gpe) * ngpe, 1); for(i = 0; i < n0; i++){ gpes[i].nb = i; gpes[i].stsbit = i&7; @@ -306,14 +326,14 @@ gpes[i].enbit = (n0 + i)&7; gpes[i].enio = fadt.gpe0blk + ((n0 + i)>>3); } - for(i = 0; i + n0 < ngpes; i++){ + for(i = 0; i + n0 < ngpe; i++){ gpes[i + n0].nb = fadt.gp1base + i; gpes[i + n0].stsbit = i&7; gpes[i + n0].stsio = fadt.gpe1blk + (i>>3); gpes[i + n0].enbit = (n1 + i)&7; gpes[i + n0].enio = fadt.gpe1blk + ((n1 + i)>>3); } - for(i = 0; i < ngpes; i++){ + for(i = 0; i < ngpe; i++){ setgpeen(i, 0); clrgpests(i); } @@ -354,18 +374,25 @@ * This starts ACPI, which requires we handle * power mgmt events ourselves. */ - print("acpi: enable interrupt\n"); - outb(fadt.smicmd, fadt.acpienable); - for(i = 0;; i++){ - if(i == 10){ - print("acpi: failed to enable\n"); - return; + if(fadt.sciint == 0) + return; + if((getpm1ctl() & Pm1SciEn) == 0){ + outb(fadt.smicmd, fadt.acpienable); + for(i = 0;; i++){ + if(i == 10){ + print("acpi: failed to enable\n"); + outb(fadt.smicmd, fadt.acpidisable); + return; + } + if(getpm1ctl() & Pm1SciEn) + break; } - if(getpm1ctl() & Pm1SciEn) - break; } - if(fadt.sciint != 0) - intrenable(fadt.sciint, acpiintr, 0, BUSUNKNOWN, "acpi"); + + print("acpi: enable interrupt\n"); + setpm1sts(getpm1sts()); + setpm1en(Epowerbtn); + intrenable(fadt.sciint, acpiintr, 0, BUSUNKNOWN, "acpi"); } static Chan* @@ -420,10 +447,12 @@ s = "??"; else s = pwrbuttab[i].name; - seprint(p, e, "powerbutton %s\n", s); + p = seprint(p, e, "powerbutton %s\n", s); + p = seprint(p, e, "ngpe %d\n", ngpe); + USED(p); return readstr(off, a, n, buf); - case Qtbl: + case Qevent: s = ""; return readstr(off, a, n, s); } @@ -450,7 +479,7 @@ switch(ct->index){ case CMgpe: i = strtoul(cb->f[1], nil, 0); - if(i >= ngpes) + if(i >= ngpe) error("gpe out of range"); kstrdup(&gpes[i].obj, cb->f[2]); DBG("gpe %d %s\n", i, gpes[i].obj);