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