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