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