xref: /openbsd/sys/dev/acpi/acpiec.c (revision 4bdff4be)
1 /* $OpenBSD: acpiec.c,v 1.65 2022/08/10 16:58:16 patrick Exp $ */
2 /*
3  * Copyright (c) 2006 Can Erkin Acar <canacar@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/signalvar.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22 
23 #include <machine/bus.h>
24 
25 #include <dev/acpi/acpireg.h>
26 #include <dev/acpi/acpivar.h>
27 #include <dev/acpi/acpidev.h>
28 #include <dev/acpi/amltypes.h>
29 #include <dev/acpi/dsdt.h>
30 
31 #include <sys/sensors.h>
32 
33 int		acpiec_match(struct device *, void *, void *);
34 void		acpiec_attach(struct device *, struct device *, void *);
35 
36 uint8_t		acpiec_status(struct acpiec_softc *);
37 uint8_t		acpiec_read_data(struct acpiec_softc *);
38 void		acpiec_write_cmd(struct acpiec_softc *, uint8_t);
39 void		acpiec_write_data(struct acpiec_softc *, uint8_t);
40 void		acpiec_burst_enable(struct acpiec_softc *sc);
41 void		acpiec_burst_disable(struct acpiec_softc *sc);
42 
43 uint8_t		acpiec_read_1(struct acpiec_softc *, uint8_t);
44 void		acpiec_write_1(struct acpiec_softc *, uint8_t, uint8_t);
45 
46 void		acpiec_read(struct acpiec_softc *, uint8_t, int, uint8_t *);
47 void		acpiec_write(struct acpiec_softc *, uint8_t, int, uint8_t *);
48 
49 int		acpiec_getcrs(struct acpiec_softc *,
50 		    struct acpi_attach_args *);
51 int		acpiec_parse_resources(int, union acpi_resource *, void *);
52 
53 void		acpiec_wait(struct acpiec_softc *, uint8_t, uint8_t);
54 void		acpiec_sci_event(struct acpiec_softc *);
55 
56 void		acpiec_get_events(struct acpiec_softc *);
57 
58 int		acpiec_gpehandler(struct acpi_softc *, int, void *);
59 
60 /* EC Status bits */
61 #define		EC_STAT_SMI_EVT	0x40	/* SMI event pending */
62 #define		EC_STAT_SCI_EVT	0x20	/* SCI event pending */
63 #define		EC_STAT_BURST	0x10	/* Controller in burst mode */
64 #define		EC_STAT_CMD	0x08	/* data is command */
65 #define		EC_STAT_IBF	0x02	/* input buffer full */
66 #define		EC_STAT_OBF	0x01	/* output buffer full */
67 
68 /* EC Commands */
69 #define		EC_CMD_RD	0x80	/* Read */
70 #define		EC_CMD_WR	0x81	/* Write */
71 #define		EC_CMD_BE	0x82	/* Burst Enable */
72 #define		EC_CMD_BD	0x83	/* Burst Disable */
73 #define		EC_CMD_QR	0x84	/* Query */
74 
75 int	acpiec_reg(struct acpiec_softc *);
76 
77 const struct cfattach acpiec_ca = {
78 	sizeof(struct acpiec_softc), acpiec_match, acpiec_attach
79 };
80 
81 struct cfdriver acpiec_cd = {
82 	NULL, "acpiec", DV_DULL
83 };
84 
85 const char *acpiec_hids[] = {
86 	ACPI_DEV_ECD,
87 	NULL
88 };
89 
90 void
91 acpiec_wait(struct acpiec_softc *sc, uint8_t mask, uint8_t val)
92 {
93 	static int acpiecnowait;
94 	uint8_t		stat;
95 
96 	dnprintf(40, "%s: EC wait_ns for: %b == %02x\n",
97 	    DEVNAME(sc), (int)mask,
98 	    "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF", (int)val);
99 
100 	while (((stat = acpiec_status(sc)) & mask) != val) {
101 		if (stat & EC_STAT_SCI_EVT)
102 			sc->sc_gotsci = 1;
103 		if (cold || (stat & EC_STAT_BURST))
104 			delay(1);
105 		else
106 			tsleep(&acpiecnowait, PWAIT, "acpiec", 1);
107 	}
108 
109 	dnprintf(40, "%s: EC wait_ns, stat: %b\n", DEVNAME(sc), (int)stat,
110 	    "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
111 }
112 
113 uint8_t
114 acpiec_status(struct acpiec_softc *sc)
115 {
116 	return (bus_space_read_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0));
117 }
118 
119 void
120 acpiec_write_data(struct acpiec_softc *sc, uint8_t val)
121 {
122 	acpiec_wait(sc, EC_STAT_IBF, 0);
123 	dnprintf(40, "acpiec: write_data -- %d\n", (int)val);
124 	bus_space_write_1(sc->sc_data_bt, sc->sc_data_bh, 0, val);
125 }
126 
127 void
128 acpiec_write_cmd(struct acpiec_softc *sc, uint8_t val)
129 {
130 	acpiec_wait(sc, EC_STAT_IBF, 0);
131 	dnprintf(40, "acpiec: write_cmd -- %d\n", (int)val);
132 	bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, val);
133 }
134 
135 uint8_t
136 acpiec_read_data(struct acpiec_softc *sc)
137 {
138 	uint8_t		val;
139 
140 	acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
141 	val = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
142 
143 	dnprintf(40, "acpiec: read_data %d\n", (int)val);
144 
145 	return (val);
146 }
147 
148 void
149 acpiec_sci_event(struct acpiec_softc *sc)
150 {
151 	uint8_t		evt;
152 
153 	sc->sc_gotsci = 0;
154 
155 	acpiec_wait(sc, EC_STAT_IBF, 0);
156 	bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, EC_CMD_QR);
157 
158 	acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
159 	evt = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
160 
161 	if (evt) {
162 		dnprintf(10, "%s: sci_event: 0x%02x\n", DEVNAME(sc), (int)evt);
163 		aml_evalnode(sc->sc_acpi, sc->sc_events[evt].event, 0, NULL,
164 		    NULL);
165 	}
166 }
167 
168 uint8_t
169 acpiec_read_1(struct acpiec_softc *sc, uint8_t addr)
170 {
171 	uint8_t		val;
172 
173 	if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
174 		sc->sc_gotsci = 1;
175 
176 	acpiec_write_cmd(sc, EC_CMD_RD);
177 	acpiec_write_data(sc, addr);
178 
179 	val = acpiec_read_data(sc);
180 
181 	return (val);
182 }
183 
184 void
185 acpiec_write_1(struct acpiec_softc *sc, uint8_t addr, uint8_t data)
186 {
187 	if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
188 		sc->sc_gotsci = 1;
189 
190 	acpiec_write_cmd(sc, EC_CMD_WR);
191 	acpiec_write_data(sc, addr);
192 	acpiec_write_data(sc, data);
193 }
194 
195 void
196 acpiec_burst_enable(struct acpiec_softc *sc)
197 {
198 	if (sc->sc_cantburst)
199 		return;
200 
201 	acpiec_write_cmd(sc, EC_CMD_BE);
202 	acpiec_read_data(sc);
203 }
204 
205 void
206 acpiec_burst_disable(struct acpiec_softc *sc)
207 {
208 	if (sc->sc_cantburst)
209 		return;
210 
211 	if ((acpiec_status(sc) & EC_STAT_BURST) == EC_STAT_BURST)
212 		acpiec_write_cmd(sc, EC_CMD_BD);
213 }
214 
215 void
216 acpiec_read(struct acpiec_softc *sc, uint8_t addr, int len, uint8_t *buffer)
217 {
218 	int			reg;
219 
220 	/*
221 	 * this works because everything runs in the acpi thread context.
222 	 * at some point add a lock to deal with concurrency so that a
223 	 * transaction does not get interrupted.
224 	 */
225 	dnprintf(20, "%s: read %d, %d\n", DEVNAME(sc), (int)addr, len);
226 	sc->sc_ecbusy = 1;
227 	acpiec_burst_enable(sc);
228 	for (reg = 0; reg < len; reg++)
229 		buffer[reg] = acpiec_read_1(sc, addr + reg);
230 	acpiec_burst_disable(sc);
231 	sc->sc_ecbusy = 0;
232 }
233 
234 void
235 acpiec_write(struct acpiec_softc *sc, uint8_t addr, int len, uint8_t *buffer)
236 {
237 	int			reg;
238 
239 	/*
240 	 * this works because everything runs in the acpi thread context.
241 	 * at some point add a lock to deal with concurrency so that a
242 	 * transaction does not get interrupted.
243 	 */
244 	dnprintf(20, "%s: write %d, %d\n", DEVNAME(sc), (int)addr, len);
245 	sc->sc_ecbusy = 1;
246 	acpiec_burst_enable(sc);
247 	for (reg = 0; reg < len; reg++)
248 		acpiec_write_1(sc, addr + reg, buffer[reg]);
249 	acpiec_burst_disable(sc);
250 	sc->sc_ecbusy = 0;
251 }
252 
253 int
254 acpiec_match(struct device *parent, void *match, void *aux)
255 {
256 	struct acpi_attach_args	*aa = aux;
257 	struct cfdata		*cf = match;
258 	struct acpi_ecdt	*ecdt = aa->aaa_table;
259 	struct acpi_softc	*acpisc = (struct acpi_softc *)parent;
260 
261 	/* Check for early ECDT table attach */
262 	if (ecdt &&
263 	    !memcmp(ecdt->hdr.signature, ECDT_SIG, sizeof(ECDT_SIG) - 1))
264 		return (1);
265 	if (acpisc->sc_ec)
266 		return (0);
267 
268 	/* sanity */
269 	return (acpi_matchhids(aa, acpiec_hids, cf->cf_driver->cd_name));
270 }
271 
272 void
273 acpiec_attach(struct device *parent, struct device *self, void *aux)
274 {
275 	struct acpiec_softc	*sc = (struct acpiec_softc *)self;
276 	struct acpi_attach_args *aa = aux;
277 	struct aml_value res;
278 	int64_t st;
279 
280 	sc->sc_acpi = (struct acpi_softc *)parent;
281 	sc->sc_devnode = aa->aaa_node;
282 	sc->sc_cantburst = 0;
283 
284 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &st))
285 		st = STA_PRESENT | STA_ENABLED | STA_DEV_OK;
286 	if ((st & STA_PRESENT) == 0) {
287 		printf(": not present\n");
288 		return;
289 	}
290 
291 	printf("\n");
292 	if (acpiec_getcrs(sc, aa)) {
293 		printf("%s: Failed to read resource settings\n", DEVNAME(sc));
294 		return;
295 	}
296 
297 	sc->sc_acpi->sc_ec = sc;
298 
299 	if (acpiec_reg(sc)) {
300 		printf("%s: Failed to register address space\n", DEVNAME(sc));
301 		return;
302 	}
303 
304 	/*
305 	 * Some Chromebooks using the Google EC do not support burst mode and
306 	 * cause us to spin forever waiting for the acknowledgment.  Don't use
307 	 * burst mode at all on these machines.
308 	 */
309 	if (hw_vendor != NULL && hw_prod != NULL &&
310 	    strcmp(hw_vendor, "GOOGLE") == 0 &&
311 	    strcmp(hw_prod, "Samus") == 0)
312 		sc->sc_cantburst = 1;
313 
314 	acpiec_get_events(sc);
315 
316 	dnprintf(10, "%s: GPE: %d\n", DEVNAME(sc), sc->sc_gpe);
317 
318 #ifndef SMALL_KERNEL
319 	acpi_set_gpehandler(sc->sc_acpi, sc->sc_gpe, acpiec_gpehandler,
320 	    sc, GPE_EDGE);
321 #endif
322 
323 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_GLK", 0, NULL, &res))
324 		sc->sc_glk = 0;
325 	else if (res.type != AML_OBJTYPE_INTEGER)
326 		sc->sc_glk = 0;
327 	else
328 		sc->sc_glk = res.v_integer ? 1 : 0;
329 }
330 
331 void
332 acpiec_get_events(struct acpiec_softc *sc)
333 {
334 	int			idx;
335 	char			name[16];
336 
337 	memset(sc->sc_events, 0, sizeof(sc->sc_events));
338 	for (idx = 0; idx < ACPIEC_MAX_EVENTS; idx++) {
339 		snprintf(name, sizeof(name), "_Q%02X", idx);
340 		sc->sc_events[idx].event = aml_searchname(sc->sc_devnode, name);
341 		if (sc->sc_events[idx].event != NULL)
342 			dnprintf(10, "%s: Found event %s\n", DEVNAME(sc), name);
343 	}
344 }
345 
346 int
347 acpiec_gpehandler(struct acpi_softc *acpi_sc, int gpe, void *arg)
348 {
349 	struct acpiec_softc	*sc = arg;
350 	uint8_t			mask, stat, en;
351 	int			s;
352 
353 	KASSERT(sc->sc_ecbusy == 0);
354 	dnprintf(10, "ACPIEC: got gpe\n");
355 
356 	do {
357 		if (sc->sc_gotsci)
358 			acpiec_sci_event(sc);
359 
360 		stat = acpiec_status(sc);
361 		dnprintf(40, "%s: EC interrupt, stat: %b\n",
362 		    DEVNAME(sc), (int)stat,
363 		    "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
364 
365 		if (stat & EC_STAT_SCI_EVT)
366 			sc->sc_gotsci = 1;
367 		else
368 			sc->sc_gotsci = 0;
369 	} while (sc->sc_gotsci);
370 
371 	/* Unmask the GPE which was blocked at interrupt time */
372 	s = splbio();
373 	mask = (1L << (gpe & 7));
374 	en = acpi_read_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3);
375 	acpi_write_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3, en | mask);
376 	splx(s);
377 
378 	return (0);
379 }
380 
381 int
382 acpiec_parse_resources(int crsidx, union acpi_resource *crs, void *arg)
383 {
384 	struct acpiec_softc *sc = arg;
385 	int type = AML_CRSTYPE(crs);
386 
387 	switch (crsidx) {
388 	case 0:
389 		if (type != SR_IOPORT) {
390 			printf("%s: Unexpected resource #%d type %d\n",
391 			    DEVNAME(sc), crsidx, type);
392 			break;
393 		}
394 		sc->sc_data_bt = sc->sc_acpi->sc_iot;
395 		sc->sc_ec_data = crs->sr_ioport._max;
396 		break;
397 	case 1:
398 		if (type != SR_IOPORT) {
399 			printf("%s: Unexpected resource #%d type %d\n",
400 			    DEVNAME(sc), crsidx, type);
401 			break;
402 		}
403 		sc->sc_cmd_bt = sc->sc_acpi->sc_iot;
404 		sc->sc_ec_sc = crs->sr_ioport._max;
405 		break;
406 	case 2:
407 		if (!sc->sc_acpi->sc_hw_reduced) {
408 			printf("%s: Not running on HW-Reduced ACPI type %d\n",
409 			    DEVNAME(sc), type);
410 			break;
411 		}
412 		/* XXX: handle SCI GPIO  */
413 		break;
414 	default:
415 		printf("%s: invalid resource #%d type %d\n",
416 		    DEVNAME(sc), crsidx, type);
417 	}
418 
419 	return 0;
420 }
421 
422 int
423 acpiec_getcrs(struct acpiec_softc *sc, struct acpi_attach_args *aa)
424 {
425 	struct aml_value	res;
426 	int64_t			gpe;
427 	struct acpi_ecdt	*ecdt = aa->aaa_table;
428 	int			rc;
429 
430 	/* Check if this is ECDT initialization */
431 	if (ecdt) {
432 		/* Get GPE, Data and Control segments */
433 		sc->sc_gpe = ecdt->gpe_bit;
434 
435 		if (ecdt->ec_control.address_space_id == GAS_SYSTEM_IOSPACE)
436 			sc->sc_cmd_bt = sc->sc_acpi->sc_iot;
437 		else
438 			sc->sc_cmd_bt = sc->sc_acpi->sc_memt;
439 		sc->sc_ec_sc = ecdt->ec_control.address;
440 
441 		if (ecdt->ec_data.address_space_id == GAS_SYSTEM_IOSPACE)
442 			sc->sc_data_bt = sc->sc_acpi->sc_iot;
443 		else
444 			sc->sc_data_bt = sc->sc_acpi->sc_memt;
445 		sc->sc_ec_data = ecdt->ec_data.address;
446 
447 		/* Get devnode from header */
448 		sc->sc_devnode = aml_searchname(sc->sc_acpi->sc_root,
449 		    ecdt->ec_id);
450 
451 		goto ecdtdone;
452 	}
453 
454 	rc = aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
455 	    "_GPE", 0, NULL, &gpe);
456 	if (rc) {
457 		dnprintf(10, "%s: no _GPE\n", DEVNAME(sc));
458 		return (1);
459 	}
460 
461 	sc->sc_gpe = gpe;
462 
463 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
464 		dnprintf(10, "%s: no _CRS\n", DEVNAME(sc));
465 		return (1);
466 	}
467 
468 	/* Parse CRS to get control and data registers */
469 
470 	if (res.type != AML_OBJTYPE_BUFFER) {
471 		dnprintf(10, "%s: unknown _CRS type %d\n",
472 		    DEVNAME(sc), res.type);
473 		aml_freevalue(&res);
474 		return (1);
475 	}
476 
477 	aml_parse_resource(&res, acpiec_parse_resources, sc);
478 	aml_freevalue(&res);
479 	if (sc->sc_ec_data == 0 || sc->sc_ec_sc == 0) {
480 		printf("%s: failed to read from _CRS\n", DEVNAME(sc));
481 		return (1);
482 	}
483 
484 ecdtdone:
485 
486 	dnprintf(10, "%s: Data: 0x%lx, S/C: 0x%lx\n",
487 	    DEVNAME(sc), sc->sc_ec_data, sc->sc_ec_sc);
488 
489 	if (bus_space_map(sc->sc_cmd_bt, sc->sc_ec_sc, 1, 0, &sc->sc_cmd_bh)) {
490 		dnprintf(10, "%s: failed to map S/C reg.\n", DEVNAME(sc));
491 		return (1);
492 	}
493 
494 	rc = bus_space_map(sc->sc_data_bt, sc->sc_ec_data, 1, 0,
495 	    &sc->sc_data_bh);
496 	if (rc) {
497 		dnprintf(10, "%s: failed to map DATA reg.\n", DEVNAME(sc));
498 		bus_space_unmap(sc->sc_cmd_bt, sc->sc_cmd_bh, 1);
499 		return (1);
500 	}
501 
502 	return (0);
503 }
504 
505 int
506 acpiec_reg(struct acpiec_softc *sc)
507 {
508 	struct aml_value arg[2];
509 	struct aml_node *node;
510 
511 	memset(&arg, 0, sizeof(arg));
512 	arg[0].type = AML_OBJTYPE_INTEGER;
513 	arg[0].v_integer = ACPI_OPREG_EC;
514 	arg[1].type = AML_OBJTYPE_INTEGER;
515 	arg[1].v_integer = 1;
516 
517 	node = aml_searchname(sc->sc_devnode, "_REG");
518 	if (node && aml_evalnode(sc->sc_acpi, node, 2, arg, NULL)) {
519 		dnprintf(10, "%s: eval method _REG failed\n", DEVNAME(sc));
520 		printf("acpiec _REG failed, broken BIOS\n");
521 	}
522 
523 	return (0);
524 }
525