xref: /openbsd-src/sys/dev/acpi/acpiec.c (revision f3831b10f5c5f9b8fe11bc146b4c5b74a92fc5ba)
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