1*f3831b10Skettenis /* $OpenBSD: acpiec.c,v 1.66 2024/06/25 11:57:10 kettenis Exp $ */
2ee9aaac4Scanacar /*
3ee9aaac4Scanacar * Copyright (c) 2006 Can Erkin Acar <canacar@openbsd.org>
4ee9aaac4Scanacar *
5ee9aaac4Scanacar * Permission to use, copy, modify, and distribute this software for any
6ee9aaac4Scanacar * purpose with or without fee is hereby granted, provided that the above
7ee9aaac4Scanacar * copyright notice and this permission notice appear in all copies.
8ee9aaac4Scanacar *
9ee9aaac4Scanacar * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10ee9aaac4Scanacar * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11ee9aaac4Scanacar * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12ee9aaac4Scanacar * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13ee9aaac4Scanacar * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ee9aaac4Scanacar * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15ee9aaac4Scanacar * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16ee9aaac4Scanacar */
17ee9aaac4Scanacar
18ee9aaac4Scanacar #include <sys/param.h>
19ee9aaac4Scanacar #include <sys/signalvar.h>
20ee9aaac4Scanacar #include <sys/systm.h>
21ee9aaac4Scanacar #include <sys/device.h>
22ee9aaac4Scanacar
23ee9aaac4Scanacar #include <machine/bus.h>
24ee9aaac4Scanacar
25ee9aaac4Scanacar #include <dev/acpi/acpireg.h>
26ee9aaac4Scanacar #include <dev/acpi/acpivar.h>
27ee9aaac4Scanacar #include <dev/acpi/acpidev.h>
28ee9aaac4Scanacar #include <dev/acpi/amltypes.h>
29ee9aaac4Scanacar #include <dev/acpi/dsdt.h>
30ee9aaac4Scanacar
31ee9aaac4Scanacar #include <sys/sensors.h>
32ee9aaac4Scanacar
33ee9aaac4Scanacar int acpiec_match(struct device *, void *, void *);
34ee9aaac4Scanacar void acpiec_attach(struct device *, struct device *, void *);
35ee9aaac4Scanacar
36d2eaebe9Skettenis uint8_t acpiec_status(struct acpiec_softc *);
37d2eaebe9Skettenis uint8_t acpiec_read_data(struct acpiec_softc *);
38d2eaebe9Skettenis void acpiec_write_cmd(struct acpiec_softc *, uint8_t);
39d2eaebe9Skettenis void acpiec_write_data(struct acpiec_softc *, uint8_t);
40ee9aaac4Scanacar void acpiec_burst_enable(struct acpiec_softc *sc);
412375deb0Sderaadt void acpiec_burst_disable(struct acpiec_softc *sc);
42ee9aaac4Scanacar
43d2eaebe9Skettenis uint8_t acpiec_read_1(struct acpiec_softc *, uint8_t);
44d2eaebe9Skettenis void acpiec_write_1(struct acpiec_softc *, uint8_t, uint8_t);
45ee9aaac4Scanacar
46d2eaebe9Skettenis void acpiec_read(struct acpiec_softc *, uint8_t, int, uint8_t *);
47d2eaebe9Skettenis void acpiec_write(struct acpiec_softc *, uint8_t, int, uint8_t *);
48ee9aaac4Scanacar
49dde8d959Smarco int acpiec_getcrs(struct acpiec_softc *,
50dde8d959Smarco struct acpi_attach_args *);
5111acbd79Spirofti int acpiec_parse_resources(int, union acpi_resource *, void *);
52ee9aaac4Scanacar
53d2eaebe9Skettenis void acpiec_wait(struct acpiec_softc *, uint8_t, uint8_t);
54ee9aaac4Scanacar void acpiec_sci_event(struct acpiec_softc *);
55ee9aaac4Scanacar
56ee9aaac4Scanacar void acpiec_get_events(struct acpiec_softc *);
57ee9aaac4Scanacar
58a296d278Sjordan int acpiec_gpehandler(struct acpi_softc *, int, void *);
59a296d278Sjordan
603f2d012cSmk /* EC Status bits */
61ee9aaac4Scanacar #define EC_STAT_SMI_EVT 0x40 /* SMI event pending */
62ee9aaac4Scanacar #define EC_STAT_SCI_EVT 0x20 /* SCI event pending */
63ee9aaac4Scanacar #define EC_STAT_BURST 0x10 /* Controller in burst mode */
64ee9aaac4Scanacar #define EC_STAT_CMD 0x08 /* data is command */
65ee9aaac4Scanacar #define EC_STAT_IBF 0x02 /* input buffer full */
66ee9aaac4Scanacar #define EC_STAT_OBF 0x01 /* output buffer full */
67ee9aaac4Scanacar
68ee9aaac4Scanacar /* EC Commands */
69ee9aaac4Scanacar #define EC_CMD_RD 0x80 /* Read */
70ee9aaac4Scanacar #define EC_CMD_WR 0x81 /* Write */
71ee9aaac4Scanacar #define EC_CMD_BE 0x82 /* Burst Enable */
72ee9aaac4Scanacar #define EC_CMD_BD 0x83 /* Burst Disable */
73ee9aaac4Scanacar #define EC_CMD_QR 0x84 /* Query */
74ee9aaac4Scanacar
75ee9aaac4Scanacar int acpiec_reg(struct acpiec_softc *);
76ee9aaac4Scanacar
77471aeecfSnaddy const struct cfattach acpiec_ca = {
78ee9aaac4Scanacar sizeof(struct acpiec_softc), acpiec_match, acpiec_attach
79ee9aaac4Scanacar };
80ee9aaac4Scanacar
81ee9aaac4Scanacar struct cfdriver acpiec_cd = {
82ee9aaac4Scanacar NULL, "acpiec", DV_DULL
83ee9aaac4Scanacar };
84ee9aaac4Scanacar
85128e94b2Smlarkin const char *acpiec_hids[] = {
86128e94b2Smlarkin ACPI_DEV_ECD,
87128e94b2Smlarkin NULL
88128e94b2Smlarkin };
89ee9aaac4Scanacar
90ee9aaac4Scanacar void
acpiec_wait(struct acpiec_softc * sc,uint8_t mask,uint8_t val)91d2eaebe9Skettenis acpiec_wait(struct acpiec_softc *sc, uint8_t mask, uint8_t val)
92ee9aaac4Scanacar {
9328e3ab93Sderaadt static int acpiecnowait;
94d2eaebe9Skettenis uint8_t stat;
9518fb8c9bSmarco
96dde8d959Smarco dnprintf(40, "%s: EC wait_ns for: %b == %02x\n",
97dde8d959Smarco DEVNAME(sc), (int)mask,
98ee9aaac4Scanacar "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF", (int)val);
99ee9aaac4Scanacar
1009575742dScanacar while (((stat = acpiec_status(sc)) & mask) != val) {
1019575742dScanacar if (stat & EC_STAT_SCI_EVT)
1029575742dScanacar sc->sc_gotsci = 1;
1032375deb0Sderaadt if (cold || (stat & EC_STAT_BURST))
104ee9aaac4Scanacar delay(1);
10592b64f3bSmarco else
10628e3ab93Sderaadt tsleep(&acpiecnowait, PWAIT, "acpiec", 1);
1079575742dScanacar }
108eb05ff3aSmarco
109ee9aaac4Scanacar dnprintf(40, "%s: EC wait_ns, stat: %b\n", DEVNAME(sc), (int)stat,
110ee9aaac4Scanacar "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
111ee9aaac4Scanacar }
112ee9aaac4Scanacar
113d2eaebe9Skettenis uint8_t
acpiec_status(struct acpiec_softc * sc)114ee9aaac4Scanacar acpiec_status(struct acpiec_softc *sc)
115ee9aaac4Scanacar {
116eb05ff3aSmarco return (bus_space_read_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0));
117ee9aaac4Scanacar }
118ee9aaac4Scanacar
119ee9aaac4Scanacar void
acpiec_write_data(struct acpiec_softc * sc,uint8_t val)120d2eaebe9Skettenis acpiec_write_data(struct acpiec_softc *sc, uint8_t val)
121ee9aaac4Scanacar {
122eb05ff3aSmarco acpiec_wait(sc, EC_STAT_IBF, 0);
123ee9aaac4Scanacar dnprintf(40, "acpiec: write_data -- %d\n", (int)val);
124ee9aaac4Scanacar bus_space_write_1(sc->sc_data_bt, sc->sc_data_bh, 0, val);
125ee9aaac4Scanacar }
126ee9aaac4Scanacar
127ee9aaac4Scanacar void
acpiec_write_cmd(struct acpiec_softc * sc,uint8_t val)128d2eaebe9Skettenis acpiec_write_cmd(struct acpiec_softc *sc, uint8_t val)
129ee9aaac4Scanacar {
130eb05ff3aSmarco acpiec_wait(sc, EC_STAT_IBF, 0);
131ee9aaac4Scanacar dnprintf(40, "acpiec: write_cmd -- %d\n", (int)val);
132ee9aaac4Scanacar bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, val);
133ee9aaac4Scanacar }
134ee9aaac4Scanacar
135d2eaebe9Skettenis uint8_t
acpiec_read_data(struct acpiec_softc * sc)136ee9aaac4Scanacar acpiec_read_data(struct acpiec_softc *sc)
137ee9aaac4Scanacar {
138d2eaebe9Skettenis uint8_t val;
139eb05ff3aSmarco
140eb05ff3aSmarco acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
141ee9aaac4Scanacar val = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
142ee9aaac4Scanacar
1437a27271eSmlarkin dnprintf(40, "acpiec: read_data %d\n", (int)val);
1447a27271eSmlarkin
145eb05ff3aSmarco return (val);
146ee9aaac4Scanacar }
147ee9aaac4Scanacar
148ee9aaac4Scanacar void
acpiec_sci_event(struct acpiec_softc * sc)149ee9aaac4Scanacar acpiec_sci_event(struct acpiec_softc *sc)
150ee9aaac4Scanacar {
151d2eaebe9Skettenis uint8_t evt;
152ee9aaac4Scanacar
1539575742dScanacar sc->sc_gotsci = 0;
1549575742dScanacar
155eb05ff3aSmarco acpiec_wait(sc, EC_STAT_IBF, 0);
156ee9aaac4Scanacar bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, EC_CMD_QR);
157ee9aaac4Scanacar
158eb05ff3aSmarco acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
159ee9aaac4Scanacar evt = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
160ee9aaac4Scanacar
1619575742dScanacar if (evt) {
162ee9aaac4Scanacar dnprintf(10, "%s: sci_event: 0x%02x\n", DEVNAME(sc), (int)evt);
1639ed432d2Smarco aml_evalnode(sc->sc_acpi, sc->sc_events[evt].event, 0, NULL,
1649ed432d2Smarco NULL);
1659ed432d2Smarco }
166ee9aaac4Scanacar }
167ee9aaac4Scanacar
168d2eaebe9Skettenis uint8_t
acpiec_read_1(struct acpiec_softc * sc,uint8_t addr)169d2eaebe9Skettenis acpiec_read_1(struct acpiec_softc *sc, uint8_t addr)
170ee9aaac4Scanacar {
171d2eaebe9Skettenis uint8_t val;
172ee9aaac4Scanacar
173ee9aaac4Scanacar if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
1749575742dScanacar sc->sc_gotsci = 1;
175ee9aaac4Scanacar
176ee9aaac4Scanacar acpiec_write_cmd(sc, EC_CMD_RD);
177ee9aaac4Scanacar acpiec_write_data(sc, addr);
178ee9aaac4Scanacar
179ee9aaac4Scanacar val = acpiec_read_data(sc);
180ee9aaac4Scanacar
181eb05ff3aSmarco return (val);
182ee9aaac4Scanacar }
183ee9aaac4Scanacar
184ee9aaac4Scanacar void
acpiec_write_1(struct acpiec_softc * sc,uint8_t addr,uint8_t data)185d2eaebe9Skettenis acpiec_write_1(struct acpiec_softc *sc, uint8_t addr, uint8_t data)
186ee9aaac4Scanacar {
187ee9aaac4Scanacar if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
1889575742dScanacar sc->sc_gotsci = 1;
189ee9aaac4Scanacar
190ee9aaac4Scanacar acpiec_write_cmd(sc, EC_CMD_WR);
191ee9aaac4Scanacar acpiec_write_data(sc, addr);
192ee9aaac4Scanacar acpiec_write_data(sc, data);
193ee9aaac4Scanacar }
194ee9aaac4Scanacar
195ee9aaac4Scanacar void
acpiec_burst_enable(struct acpiec_softc * sc)196ee9aaac4Scanacar acpiec_burst_enable(struct acpiec_softc *sc)
197ee9aaac4Scanacar {
19880aee224Sbentley if (sc->sc_cantburst)
19980aee224Sbentley return;
20080aee224Sbentley
201ee9aaac4Scanacar acpiec_write_cmd(sc, EC_CMD_BE);
202ee9aaac4Scanacar acpiec_read_data(sc);
203ee9aaac4Scanacar }
204ee9aaac4Scanacar
205ee9aaac4Scanacar void
acpiec_burst_disable(struct acpiec_softc * sc)2062375deb0Sderaadt acpiec_burst_disable(struct acpiec_softc *sc)
2072375deb0Sderaadt {
20880aee224Sbentley if (sc->sc_cantburst)
20980aee224Sbentley return;
21080aee224Sbentley
2112375deb0Sderaadt if ((acpiec_status(sc) & EC_STAT_BURST) == EC_STAT_BURST)
2122375deb0Sderaadt acpiec_write_cmd(sc, EC_CMD_BD);
2132375deb0Sderaadt }
2142375deb0Sderaadt
2152375deb0Sderaadt void
acpiec_read(struct acpiec_softc * sc,uint8_t addr,int len,uint8_t * buffer)216d2eaebe9Skettenis acpiec_read(struct acpiec_softc *sc, uint8_t addr, int len, uint8_t *buffer)
217ee9aaac4Scanacar {
218ee9aaac4Scanacar int reg;
2199ed432d2Smarco
2209ed432d2Smarco /*
2219ed432d2Smarco * this works because everything runs in the acpi thread context.
2229ed432d2Smarco * at some point add a lock to deal with concurrency so that a
2239ed432d2Smarco * transaction does not get interrupted.
2249ed432d2Smarco */
225ee9aaac4Scanacar dnprintf(20, "%s: read %d, %d\n", DEVNAME(sc), (int)addr, len);
226abde4af0Smarco sc->sc_ecbusy = 1;
2272375deb0Sderaadt acpiec_burst_enable(sc);
228ee9aaac4Scanacar for (reg = 0; reg < len; reg++)
229ee9aaac4Scanacar buffer[reg] = acpiec_read_1(sc, addr + reg);
2302375deb0Sderaadt acpiec_burst_disable(sc);
231abde4af0Smarco sc->sc_ecbusy = 0;
232ee9aaac4Scanacar }
233ee9aaac4Scanacar
234ee9aaac4Scanacar void
acpiec_write(struct acpiec_softc * sc,uint8_t addr,int len,uint8_t * buffer)235d2eaebe9Skettenis acpiec_write(struct acpiec_softc *sc, uint8_t addr, int len, uint8_t *buffer)
236ee9aaac4Scanacar {
237ee9aaac4Scanacar int reg;
2389ed432d2Smarco
2399ed432d2Smarco /*
2409ed432d2Smarco * this works because everything runs in the acpi thread context.
2419ed432d2Smarco * at some point add a lock to deal with concurrency so that a
2429ed432d2Smarco * transaction does not get interrupted.
2439ed432d2Smarco */
244ee9aaac4Scanacar dnprintf(20, "%s: write %d, %d\n", DEVNAME(sc), (int)addr, len);
245abde4af0Smarco sc->sc_ecbusy = 1;
2462375deb0Sderaadt acpiec_burst_enable(sc);
247ee9aaac4Scanacar for (reg = 0; reg < len; reg++)
248ee9aaac4Scanacar acpiec_write_1(sc, addr + reg, buffer[reg]);
2492375deb0Sderaadt acpiec_burst_disable(sc);
250abde4af0Smarco sc->sc_ecbusy = 0;
251ee9aaac4Scanacar }
252ee9aaac4Scanacar
253ee9aaac4Scanacar int
acpiec_match(struct device * parent,void * match,void * aux)254ee9aaac4Scanacar acpiec_match(struct device *parent, void *match, void *aux)
255ee9aaac4Scanacar {
256ee9aaac4Scanacar struct acpi_attach_args *aa = aux;
257ee9aaac4Scanacar struct cfdata *cf = match;
2584cfbe391Sjordan struct acpi_ecdt *ecdt = aa->aaa_table;
259a0549a30Sderaadt struct acpi_softc *acpisc = (struct acpi_softc *)parent;
2604cfbe391Sjordan
2614cfbe391Sjordan /* Check for early ECDT table attach */
262d6d5f422Spirofti if (ecdt &&
263d6d5f422Spirofti !memcmp(ecdt->hdr.signature, ECDT_SIG, sizeof(ECDT_SIG) - 1))
2644cfbe391Sjordan return (1);
265a0549a30Sderaadt if (acpisc->sc_ec)
266a0549a30Sderaadt return (0);
267ee9aaac4Scanacar
268ee9aaac4Scanacar /* sanity */
2697df90d51Smarco return (acpi_matchhids(aa, acpiec_hids, cf->cf_driver->cd_name));
270ee9aaac4Scanacar }
271ee9aaac4Scanacar
272ee9aaac4Scanacar void
acpiec_attach(struct device * parent,struct device * self,void * aux)273ee9aaac4Scanacar acpiec_attach(struct device *parent, struct device *self, void *aux)
274ee9aaac4Scanacar {
275ee9aaac4Scanacar struct acpiec_softc *sc = (struct acpiec_softc *)self;
276ee9aaac4Scanacar struct acpi_attach_args *aa = aux;
277*f3831b10Skettenis #ifndef SMALL_KERNEL
278*f3831b10Skettenis struct acpi_wakeq *wq;
279*f3831b10Skettenis #endif
280d6d5f422Spirofti struct aml_value res;
28135c4c4e9Skettenis int64_t st;
282ee9aaac4Scanacar
283ee9aaac4Scanacar sc->sc_acpi = (struct acpi_softc *)parent;
2843b455a03Smarco sc->sc_devnode = aa->aaa_node;
28580aee224Sbentley sc->sc_cantburst = 0;
286ee9aaac4Scanacar
28735c4c4e9Skettenis if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &st))
28835c4c4e9Skettenis st = STA_PRESENT | STA_ENABLED | STA_DEV_OK;
28935c4c4e9Skettenis if ((st & STA_PRESENT) == 0) {
29035c4c4e9Skettenis printf(": not present\n");
29135c4c4e9Skettenis return;
29235c4c4e9Skettenis }
29335c4c4e9Skettenis
29411acbd79Spirofti printf("\n");
295ee9aaac4Scanacar if (acpiec_getcrs(sc, aa)) {
29611acbd79Spirofti printf("%s: Failed to read resource settings\n", DEVNAME(sc));
297ee9aaac4Scanacar return;
298ee9aaac4Scanacar }
299ee9aaac4Scanacar
3002e9b22c8Skettenis sc->sc_acpi->sc_ec = sc;
3012e9b22c8Skettenis
302ee9aaac4Scanacar if (acpiec_reg(sc)) {
30311acbd79Spirofti printf("%s: Failed to register address space\n", DEVNAME(sc));
304ee9aaac4Scanacar return;
305ee9aaac4Scanacar }
306ee9aaac4Scanacar
30780aee224Sbentley /*
30880aee224Sbentley * Some Chromebooks using the Google EC do not support burst mode and
30980aee224Sbentley * cause us to spin forever waiting for the acknowledgment. Don't use
31080aee224Sbentley * burst mode at all on these machines.
31180aee224Sbentley */
31280aee224Sbentley if (hw_vendor != NULL && hw_prod != NULL &&
31380aee224Sbentley strcmp(hw_vendor, "GOOGLE") == 0 &&
31480aee224Sbentley strcmp(hw_prod, "Samus") == 0)
31580aee224Sbentley sc->sc_cantburst = 1;
31680aee224Sbentley
317ee9aaac4Scanacar acpiec_get_events(sc);
318ee9aaac4Scanacar
3194a00f4b8Sjordan dnprintf(10, "%s: GPE: %d\n", DEVNAME(sc), sc->sc_gpe);
320ee9aaac4Scanacar
321fd9ceb67Smarco #ifndef SMALL_KERNEL
32218fb8c9bSmarco acpi_set_gpehandler(sc->sc_acpi, sc->sc_gpe, acpiec_gpehandler,
3236e53388aSjcs sc, GPE_EDGE);
324*f3831b10Skettenis
325*f3831b10Skettenis /*
326*f3831b10Skettenis * On many machines the EC is not listed as a wakeup device
327*f3831b10Skettenis * but is necessary to wake up from S0i.
328*f3831b10Skettenis */
329*f3831b10Skettenis wq = malloc(sizeof(struct acpi_wakeq), M_DEVBUF, M_WAITOK | M_ZERO);
330*f3831b10Skettenis wq->q_node = sc->sc_devnode;
331*f3831b10Skettenis wq->q_gpe = sc->sc_gpe;
332*f3831b10Skettenis wq->q_state = ACPI_STATE_S0;
333*f3831b10Skettenis wq->q_enabled = 1;
334*f3831b10Skettenis SIMPLEQ_INSERT_TAIL(&sc->sc_acpi->sc_wakedevs, wq, q_next);
335fd9ceb67Smarco #endif
336a296d278Sjordan
337d6d5f422Spirofti if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_GLK", 0, NULL, &res))
338d6d5f422Spirofti sc->sc_glk = 0;
339d6d5f422Spirofti else if (res.type != AML_OBJTYPE_INTEGER)
340d6d5f422Spirofti sc->sc_glk = 0;
341d6d5f422Spirofti else
342d6d5f422Spirofti sc->sc_glk = res.v_integer ? 1 : 0;
343ee9aaac4Scanacar }
344ee9aaac4Scanacar
345ee9aaac4Scanacar void
acpiec_get_events(struct acpiec_softc * sc)346ee9aaac4Scanacar acpiec_get_events(struct acpiec_softc *sc)
347ee9aaac4Scanacar {
348ee9aaac4Scanacar int idx;
349ee9aaac4Scanacar char name[16];
350ee9aaac4Scanacar
351ee9aaac4Scanacar memset(sc->sc_events, 0, sizeof(sc->sc_events));
352ee9aaac4Scanacar for (idx = 0; idx < ACPIEC_MAX_EVENTS; idx++) {
353ee9aaac4Scanacar snprintf(name, sizeof(name), "_Q%02X", idx);
354ee9aaac4Scanacar sc->sc_events[idx].event = aml_searchname(sc->sc_devnode, name);
355ee9aaac4Scanacar if (sc->sc_events[idx].event != NULL)
356ee9aaac4Scanacar dnprintf(10, "%s: Found event %s\n", DEVNAME(sc), name);
357ee9aaac4Scanacar }
358ee9aaac4Scanacar }
359ee9aaac4Scanacar
360a296d278Sjordan int
acpiec_gpehandler(struct acpi_softc * acpi_sc,int gpe,void * arg)361ee776520Sjordan acpiec_gpehandler(struct acpi_softc *acpi_sc, int gpe, void *arg)
362a296d278Sjordan {
363ee776520Sjordan struct acpiec_softc *sc = arg;
364d2eaebe9Skettenis uint8_t mask, stat, en;
3654fd192ceSderaadt int s;
366ee776520Sjordan
367581083c2Skettenis KASSERT(sc->sc_ecbusy == 0);
368a296d278Sjordan dnprintf(10, "ACPIEC: got gpe\n");
369ee776520Sjordan
3709575742dScanacar do {
371581083c2Skettenis if (sc->sc_gotsci)
3729575742dScanacar acpiec_sci_event(sc);
3739575742dScanacar
3749575742dScanacar stat = acpiec_status(sc);
375dde8d959Smarco dnprintf(40, "%s: EC interrupt, stat: %b\n",
376dde8d959Smarco DEVNAME(sc), (int)stat,
3779575742dScanacar "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
378dde8d959Smarco
3799575742dScanacar if (stat & EC_STAT_SCI_EVT)
3809575742dScanacar sc->sc_gotsci = 1;
3819ee25852Skettenis else
3829ee25852Skettenis sc->sc_gotsci = 0;
3839575742dScanacar } while (sc->sc_gotsci);
3849575742dScanacar
3854fd192ceSderaadt /* Unmask the GPE which was blocked at interrupt time */
386ad7f7af0Sderaadt s = splbio();
3874fd192ceSderaadt mask = (1L << (gpe & 7));
3884fd192ceSderaadt en = acpi_read_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3);
3894fd192ceSderaadt acpi_write_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3, en | mask);
3904fd192ceSderaadt splx(s);
3914fd192ceSderaadt
392a296d278Sjordan return (0);
393a296d278Sjordan }
394a296d278Sjordan
395ee9aaac4Scanacar int
acpiec_parse_resources(int crsidx,union acpi_resource * crs,void * arg)39611acbd79Spirofti acpiec_parse_resources(int crsidx, union acpi_resource *crs, void *arg)
397ee9aaac4Scanacar {
39811acbd79Spirofti struct acpiec_softc *sc = arg;
39911acbd79Spirofti int type = AML_CRSTYPE(crs);
400ee9aaac4Scanacar
40111acbd79Spirofti switch (crsidx) {
40211acbd79Spirofti case 0:
40311acbd79Spirofti if (type != SR_IOPORT) {
40411acbd79Spirofti printf("%s: Unexpected resource #%d type %d\n",
40511acbd79Spirofti DEVNAME(sc), crsidx, type);
40611acbd79Spirofti break;
40711acbd79Spirofti }
40811acbd79Spirofti sc->sc_data_bt = sc->sc_acpi->sc_iot;
40911acbd79Spirofti sc->sc_ec_data = crs->sr_ioport._max;
41011acbd79Spirofti break;
41111acbd79Spirofti case 1:
41211acbd79Spirofti if (type != SR_IOPORT) {
41311acbd79Spirofti printf("%s: Unexpected resource #%d type %d\n",
41411acbd79Spirofti DEVNAME(sc), crsidx, type);
41511acbd79Spirofti break;
41611acbd79Spirofti }
41711acbd79Spirofti sc->sc_cmd_bt = sc->sc_acpi->sc_iot;
41811acbd79Spirofti sc->sc_ec_sc = crs->sr_ioport._max;
41911acbd79Spirofti break;
42011acbd79Spirofti case 2:
42111acbd79Spirofti if (!sc->sc_acpi->sc_hw_reduced) {
42211acbd79Spirofti printf("%s: Not running on HW-Reduced ACPI type %d\n",
42311acbd79Spirofti DEVNAME(sc), type);
42411acbd79Spirofti break;
42511acbd79Spirofti }
42611acbd79Spirofti /* XXX: handle SCI GPIO */
42711acbd79Spirofti break;
42811acbd79Spirofti default:
42911acbd79Spirofti printf("%s: invalid resource #%d type %d\n",
43011acbd79Spirofti DEVNAME(sc), crsidx, type);
431ee9aaac4Scanacar }
432ee9aaac4Scanacar
43311acbd79Spirofti return 0;
434ee9aaac4Scanacar }
435ee9aaac4Scanacar
436ee9aaac4Scanacar int
acpiec_getcrs(struct acpiec_softc * sc,struct acpi_attach_args * aa)437ee9aaac4Scanacar acpiec_getcrs(struct acpiec_softc *sc, struct acpi_attach_args *aa)
438ee9aaac4Scanacar {
4396ab98c39Sjordan struct aml_value res;
440a95d1b72Sjordan int64_t gpe;
4414cfbe391Sjordan struct acpi_ecdt *ecdt = aa->aaa_table;
44211acbd79Spirofti int rc;
4434cfbe391Sjordan
4444cfbe391Sjordan /* Check if this is ECDT initialization */
4454cfbe391Sjordan if (ecdt) {
4464cfbe391Sjordan /* Get GPE, Data and Control segments */
4474cfbe391Sjordan sc->sc_gpe = ecdt->gpe_bit;
4484cfbe391Sjordan
44911acbd79Spirofti if (ecdt->ec_control.address_space_id == GAS_SYSTEM_IOSPACE)
45011acbd79Spirofti sc->sc_cmd_bt = sc->sc_acpi->sc_iot;
45111acbd79Spirofti else
45211acbd79Spirofti sc->sc_cmd_bt = sc->sc_acpi->sc_memt;
45311acbd79Spirofti sc->sc_ec_sc = ecdt->ec_control.address;
4544cfbe391Sjordan
45511acbd79Spirofti if (ecdt->ec_data.address_space_id == GAS_SYSTEM_IOSPACE)
45611acbd79Spirofti sc->sc_data_bt = sc->sc_acpi->sc_iot;
45711acbd79Spirofti else
45811acbd79Spirofti sc->sc_data_bt = sc->sc_acpi->sc_memt;
45911acbd79Spirofti sc->sc_ec_data = ecdt->ec_data.address;
4604cfbe391Sjordan
4614cfbe391Sjordan /* Get devnode from header */
4629108e412Spatrick sc->sc_devnode = aml_searchname(sc->sc_acpi->sc_root,
4639108e412Spatrick ecdt->ec_id);
4644cfbe391Sjordan
4654cfbe391Sjordan goto ecdtdone;
4664cfbe391Sjordan }
467ee9aaac4Scanacar
46811acbd79Spirofti rc = aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
46911acbd79Spirofti "_GPE", 0, NULL, &gpe);
47011acbd79Spirofti if (rc) {
471ee9aaac4Scanacar dnprintf(10, "%s: no _GPE\n", DEVNAME(sc));
472ee9aaac4Scanacar return (1);
473ee9aaac4Scanacar }
474ee9aaac4Scanacar
475a95d1b72Sjordan sc->sc_gpe = gpe;
476ee9aaac4Scanacar
477852d9418Scanacar if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
478ee9aaac4Scanacar dnprintf(10, "%s: no _CRS\n", DEVNAME(sc));
479ee9aaac4Scanacar return (1);
480ee9aaac4Scanacar }
481ee9aaac4Scanacar
482ee9aaac4Scanacar /* Parse CRS to get control and data registers */
483ee9aaac4Scanacar
484ee9aaac4Scanacar if (res.type != AML_OBJTYPE_BUFFER) {
485ee9aaac4Scanacar dnprintf(10, "%s: unknown _CRS type %d\n",
486ee9aaac4Scanacar DEVNAME(sc), res.type);
4876ab98c39Sjordan aml_freevalue(&res);
488ee9aaac4Scanacar return (1);
489ee9aaac4Scanacar }
490ee9aaac4Scanacar
49111acbd79Spirofti aml_parse_resource(&res, acpiec_parse_resources, sc);
4926ab98c39Sjordan aml_freevalue(&res);
49311acbd79Spirofti if (sc->sc_ec_data == 0 || sc->sc_ec_sc == 0) {
49411acbd79Spirofti printf("%s: failed to read from _CRS\n", DEVNAME(sc));
495ee9aaac4Scanacar return (1);
496ee9aaac4Scanacar }
497ee9aaac4Scanacar
4984cfbe391Sjordan ecdtdone:
499ee9aaac4Scanacar
5007a27271eSmlarkin dnprintf(10, "%s: Data: 0x%lx, S/C: 0x%lx\n",
50111acbd79Spirofti DEVNAME(sc), sc->sc_ec_data, sc->sc_ec_sc);
502ee9aaac4Scanacar
50311acbd79Spirofti if (bus_space_map(sc->sc_cmd_bt, sc->sc_ec_sc, 1, 0, &sc->sc_cmd_bh)) {
504ee9aaac4Scanacar dnprintf(10, "%s: failed to map S/C reg.\n", DEVNAME(sc));
505ee9aaac4Scanacar return (1);
506ee9aaac4Scanacar }
507ee9aaac4Scanacar
50811acbd79Spirofti rc = bus_space_map(sc->sc_data_bt, sc->sc_ec_data, 1, 0,
50911acbd79Spirofti &sc->sc_data_bh);
51011acbd79Spirofti if (rc) {
511ee9aaac4Scanacar dnprintf(10, "%s: failed to map DATA reg.\n", DEVNAME(sc));
512ee9aaac4Scanacar bus_space_unmap(sc->sc_cmd_bt, sc->sc_cmd_bh, 1);
513ee9aaac4Scanacar return (1);
514ee9aaac4Scanacar }
515ee9aaac4Scanacar
516ee9aaac4Scanacar return (0);
517ee9aaac4Scanacar }
518ee9aaac4Scanacar
519ee9aaac4Scanacar int
acpiec_reg(struct acpiec_softc * sc)520ee9aaac4Scanacar acpiec_reg(struct acpiec_softc *sc)
521ee9aaac4Scanacar {
5224a00f4b8Sjordan struct aml_value arg[2];
52318a9e96cSkettenis struct aml_node *node;
524ee9aaac4Scanacar
525ee9aaac4Scanacar memset(&arg, 0, sizeof(arg));
526ee9aaac4Scanacar arg[0].type = AML_OBJTYPE_INTEGER;
527de93333bSkettenis arg[0].v_integer = ACPI_OPREG_EC;
528ee9aaac4Scanacar arg[1].type = AML_OBJTYPE_INTEGER;
529ee9aaac4Scanacar arg[1].v_integer = 1;
530ee9aaac4Scanacar
53118a9e96cSkettenis node = aml_searchname(sc->sc_devnode, "_REG");
53218a9e96cSkettenis if (node && aml_evalnode(sc->sc_acpi, node, 2, arg, NULL)) {
53351fb5d6bSmarco dnprintf(10, "%s: eval method _REG failed\n", DEVNAME(sc));
534e3fff84aSjordan printf("acpiec _REG failed, broken BIOS\n");
535ee9aaac4Scanacar }
536ee9aaac4Scanacar
537ee9aaac4Scanacar return (0);
538ee9aaac4Scanacar }
539