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