xref: /openbsd-src/sys/dev/acpi/acpiec.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /* $OpenBSD: acpiec.c,v 1.46 2012/07/13 10:37:40 pirofti 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 /* EC Status bits */
63 #define		EC_STAT_SMI_EVT	0x40	/* SMI event pending */
64 #define		EC_STAT_SCI_EVT	0x20	/* SCI event pending */
65 #define		EC_STAT_BURST	0x10	/* Controller in burst mode */
66 #define		EC_STAT_CMD	0x08	/* data is command */
67 #define		EC_STAT_IBF	0x02	/* input buffer full */
68 #define		EC_STAT_OBF	0x01	/* output buffer full */
69 
70 /* EC Commands */
71 #define		EC_CMD_RD	0x80	/* Read */
72 #define		EC_CMD_WR	0x81	/* Write */
73 #define		EC_CMD_BE	0x82	/* Burst Enable */
74 #define		EC_CMD_BD	0x83	/* Burst Disable */
75 #define		EC_CMD_QR	0x84	/* Query */
76 
77 #define		REG_TYPE_EC	3
78 
79 int	acpiec_reg(struct acpiec_softc *);
80 
81 struct cfattach acpiec_ca = {
82 	sizeof(struct acpiec_softc), acpiec_match, acpiec_attach
83 };
84 
85 struct cfdriver acpiec_cd = {
86 	NULL, "acpiec", DV_DULL
87 };
88 
89 const char *acpiec_hids[] = { ACPI_DEV_ECD, 0 };
90 
91 void
92 acpiec_wait(struct acpiec_softc *sc, u_int8_t mask, u_int8_t val)
93 {
94 	static int acpiecnowait;
95 	u_int8_t		stat;
96 
97 	dnprintf(40, "%s: EC wait_ns for: %b == %02x\n",
98 	    DEVNAME(sc), (int)mask,
99 	    "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF", (int)val);
100 
101 	while (((stat = acpiec_status(sc)) & mask) != val) {
102 		if (stat & EC_STAT_SCI_EVT)
103 			sc->sc_gotsci = 1;
104 		if (cold || (stat & EC_STAT_BURST))
105 			delay(1);
106 		else
107 			tsleep(&acpiecnowait, PWAIT, "acpiec", 1);
108 	}
109 
110 	dnprintf(40, "%s: EC wait_ns, stat: %b\n", DEVNAME(sc), (int)stat,
111 	    "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
112 }
113 
114 u_int8_t
115 acpiec_status(struct acpiec_softc *sc)
116 {
117 	return (bus_space_read_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0));
118 }
119 
120 void
121 acpiec_write_data(struct acpiec_softc *sc, u_int8_t val)
122 {
123 	acpiec_wait(sc, EC_STAT_IBF, 0);
124 	dnprintf(40, "acpiec: write_data -- %d\n", (int)val);
125 	bus_space_write_1(sc->sc_data_bt, sc->sc_data_bh, 0, val);
126 }
127 
128 void
129 acpiec_write_cmd(struct acpiec_softc *sc, u_int8_t val)
130 {
131 	acpiec_wait(sc, EC_STAT_IBF, 0);
132 	dnprintf(40, "acpiec: write_cmd -- %d\n", (int)val);
133 	bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, val);
134 }
135 
136 u_int8_t
137 acpiec_read_data(struct acpiec_softc *sc)
138 {
139 	u_int8_t		val;
140 
141 	acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
142 	dnprintf(40, "acpiec: read_data\n", (int)val);
143 	val = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
144 
145 	return (val);
146 }
147 
148 void
149 acpiec_sci_event(struct acpiec_softc *sc)
150 {
151 	u_int8_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 u_int8_t
169 acpiec_read_1(struct acpiec_softc *sc, u_int8_t addr)
170 {
171 	u_int8_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, u_int8_t addr, u_int8_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 	acpiec_write_cmd(sc, EC_CMD_BE);
199 	acpiec_read_data(sc);
200 }
201 
202 void
203 acpiec_burst_disable(struct acpiec_softc *sc)
204 {
205 	if ((acpiec_status(sc) & EC_STAT_BURST) == EC_STAT_BURST)
206 		acpiec_write_cmd(sc, EC_CMD_BD);
207 }
208 
209 void
210 acpiec_read(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer)
211 {
212 	int			reg;
213 
214 	/*
215 	 * this works because everything runs in the acpi thread context.
216 	 * at some point add a lock to deal with concurrency so that a
217 	 * transaction does not get interrupted.
218 	 */
219 	dnprintf(20, "%s: read %d, %d\n", DEVNAME(sc), (int)addr, len);
220 	sc->sc_ecbusy = 1;
221 	acpiec_burst_enable(sc);
222 	for (reg = 0; reg < len; reg++)
223 		buffer[reg] = acpiec_read_1(sc, addr + reg);
224 	acpiec_burst_disable(sc);
225 	sc->sc_ecbusy = 0;
226 }
227 
228 void
229 acpiec_write(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer)
230 {
231 	int			reg;
232 
233 	/*
234 	 * this works because everything runs in the acpi thread context.
235 	 * at some point add a lock to deal with concurrency so that a
236 	 * transaction does not get interrupted.
237 	 */
238 	dnprintf(20, "%s: write %d, %d\n", DEVNAME(sc), (int)addr, len);
239 	sc->sc_ecbusy = 1;
240 	acpiec_burst_enable(sc);
241 	for (reg = 0; reg < len; reg++)
242 		acpiec_write_1(sc, addr + reg, buffer[reg]);
243 	acpiec_burst_disable(sc);
244 	sc->sc_ecbusy = 0;
245 }
246 
247 int
248 acpiec_match(struct device *parent, void *match, void *aux)
249 {
250 	struct acpi_attach_args	*aa = aux;
251 	struct cfdata		*cf = match;
252 	struct acpi_ecdt	*ecdt = aa->aaa_table;
253 	struct acpi_softc	*acpisc = (struct acpi_softc *)parent;
254 
255 	/* Check for early ECDT table attach */
256 	if (ecdt &&
257 	    !memcmp(ecdt->hdr.signature, ECDT_SIG, sizeof(ECDT_SIG) - 1))
258 		return (1);
259 	if (acpisc->sc_ec)
260 		return (0);
261 
262 	/* sanity */
263 	return (acpi_matchhids(aa, acpiec_hids, cf->cf_driver->cd_name));
264 }
265 
266 void
267 acpiec_attach(struct device *parent, struct device *self, void *aux)
268 {
269 	struct acpiec_softc	*sc = (struct acpiec_softc *)self;
270 	struct acpi_attach_args *aa = aux;
271 	struct aml_value res;
272 
273 	sc->sc_acpi = (struct acpi_softc *)parent;
274 	sc->sc_devnode = aa->aaa_node;
275 
276 	if (acpiec_getcrs(sc, aa)) {
277 		printf(": Failed to read resource settings\n");
278 		return;
279 	}
280 
281 	sc->sc_acpi->sc_ec = sc;
282 
283 	if (acpiec_reg(sc)) {
284 		printf(": Failed to register address space\n");
285 		return;
286 	}
287 
288 	acpiec_get_events(sc);
289 
290 	dnprintf(10, "%s: GPE: %d\n", DEVNAME(sc), sc->sc_gpe);
291 
292 #ifndef SMALL_KERNEL
293 	acpi_set_gpehandler(sc->sc_acpi, sc->sc_gpe, acpiec_gpehandler,
294 	    sc, 1);
295 #endif
296 
297 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_GLK", 0, NULL, &res))
298 		sc->sc_glk = 0;
299 	else if (res.type != AML_OBJTYPE_INTEGER)
300 		sc->sc_glk = 0;
301 	else
302 		sc->sc_glk = res.v_integer ? 1 : 0;
303 
304 	printf("\n");
305 }
306 
307 void
308 acpiec_get_events(struct acpiec_softc *sc)
309 {
310 	int			idx;
311 	char			name[16];
312 
313 	memset(sc->sc_events, 0, sizeof(sc->sc_events));
314 	for (idx = 0; idx < ACPIEC_MAX_EVENTS; idx++) {
315 		snprintf(name, sizeof(name), "_Q%02X", idx);
316 		sc->sc_events[idx].event = aml_searchname(sc->sc_devnode, name);
317 		if (sc->sc_events[idx].event != NULL)
318 			dnprintf(10, "%s: Found event %s\n", DEVNAME(sc), name);
319 	}
320 }
321 
322 int
323 acpiec_gpehandler(struct acpi_softc *acpi_sc, int gpe, void *arg)
324 {
325 	struct acpiec_softc	*sc = arg;
326 	u_int8_t		mask, stat, en;
327 	int			s;
328 
329 	KASSERT(sc->sc_ecbusy == 0);
330 	dnprintf(10, "ACPIEC: got gpe\n");
331 
332 	do {
333 		if (sc->sc_gotsci)
334 			acpiec_sci_event(sc);
335 
336 		stat = acpiec_status(sc);
337 		dnprintf(40, "%s: EC interrupt, stat: %b\n",
338 		    DEVNAME(sc), (int)stat,
339 		    "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
340 
341 		if (stat & EC_STAT_SCI_EVT)
342 			sc->sc_gotsci = 1;
343 	} while (sc->sc_gotsci);
344 
345 	/* Unmask the GPE which was blocked at interrupt time */
346 	s = spltty();
347 	mask = (1L << (gpe & 7));
348 	en = acpi_read_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3);
349 	acpi_write_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3, en | mask);
350 	splx(s);
351 
352 	return (0);
353 }
354 
355 /* parse the resource buffer to get a 'register' value */
356 int
357 acpiec_getregister(const u_int8_t *buf, int size, int *type, bus_size_t *addr)
358 {
359 	int			len, hlen;
360 
361 #define RES_TYPE_MASK 0x80
362 #define RES_LENGTH_MASK 0x07
363 #define RES_TYPE_IOPORT	0x47
364 #define RES_TYPE_ENDTAG	0x79
365 
366 	if (size <= 0)
367 		return (0);
368 
369 	if (*buf & RES_TYPE_MASK) {
370 		/* large resource */
371 		if (size < 3)
372 			return (1);
373 		len = (int)buf[1] + 256 * (int)buf[2];
374 		hlen = 3;
375 	} else {
376 		/* small resource */
377 		len = buf[0] & RES_LENGTH_MASK;
378 		hlen = 1;
379 	}
380 
381 	/* XXX todo: decode other types */
382 	if (*buf != RES_TYPE_IOPORT)
383 		return (0);
384 
385 	if (size < hlen + len)
386 		return (0);
387 
388 	/* XXX validate? */
389 	*type = GAS_SYSTEM_IOSPACE;
390 	*addr = (int)buf[2] + 256 * (int)buf[3];
391 
392 	return (hlen + len);
393 }
394 
395 int
396 acpiec_getcrs(struct acpiec_softc *sc, struct acpi_attach_args *aa)
397 {
398 	struct aml_value	res;
399 	bus_size_t		ec_sc, ec_data;
400 	int			dtype, ctype;
401 	char			*buf;
402 	int			size, ret;
403 	int64_t			gpe;
404 	struct acpi_ecdt	*ecdt = aa->aaa_table;
405 	extern struct aml_node	aml_root;
406 
407 	/* Check if this is ECDT initialization */
408 	if (ecdt) {
409 		/* Get GPE, Data and Control segments */
410 		sc->sc_gpe = ecdt->gpe_bit;
411 
412 		ctype = ecdt->ec_control.address_space_id;
413 		ec_sc = ecdt->ec_control.address;
414 
415 		dtype = ecdt->ec_data.address_space_id;
416 		ec_data = ecdt->ec_data.address;
417 
418 		/* Get devnode from header */
419 		sc->sc_devnode = aml_searchname(&aml_root, ecdt->ec_id);
420 
421 		goto ecdtdone;
422 	}
423 
424 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_GPE", 0, NULL, &gpe)) {
425 		dnprintf(10, "%s: no _GPE\n", DEVNAME(sc));
426 		return (1);
427 	}
428 
429 	sc->sc_gpe = gpe;
430 
431 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
432 		dnprintf(10, "%s: no _CRS\n", DEVNAME(sc));
433 		return (1);
434 	}
435 
436 	/* Parse CRS to get control and data registers */
437 
438 	if (res.type != AML_OBJTYPE_BUFFER) {
439 		dnprintf(10, "%s: unknown _CRS type %d\n",
440 		    DEVNAME(sc), res.type);
441 		aml_freevalue(&res);
442 		return (1);
443 	}
444 
445 	size = res.length;
446 	buf = res.v_buffer;
447 
448 	ret = acpiec_getregister(buf, size, &dtype, &ec_data);
449 	if (ret <= 0) {
450 		dnprintf(10, "%s: failed to read DATA from _CRS\n",
451 		    DEVNAME(sc));
452 		aml_freevalue(&res);
453 		return (1);
454 	}
455 
456 	buf += ret;
457 	size -= ret;
458 
459 	ret = acpiec_getregister(buf, size, &ctype, &ec_sc);
460 	if (ret <= 0) {
461 		dnprintf(10, "%s: failed to read S/C from _CRS\n",
462 		    DEVNAME(sc));
463 		aml_freevalue(&res);
464 		return (1);
465 	}
466 
467 	buf += ret;
468 	size -= ret;
469 
470 	if (size != 2 || *buf != RES_TYPE_ENDTAG) {
471 		dnprintf(10, "%s: no _CRS end tag\n", DEVNAME(sc));
472 		aml_freevalue(&res);
473 		return (1);
474 	}
475 	aml_freevalue(&res);
476 
477 	/* XXX: todo - validate _CRS checksum? */
478 ecdtdone:
479 
480 	dnprintf(10, "%s: Data: 0x%x, S/C: 0x%x\n",
481 	    DEVNAME(sc), ec_data, ec_sc);
482 
483 	if (ctype == GAS_SYSTEM_IOSPACE)
484 		sc->sc_cmd_bt = aa->aaa_iot;
485 	else
486 		sc->sc_cmd_bt = aa->aaa_memt;
487 
488 	if (bus_space_map(sc->sc_cmd_bt, ec_sc, 1, 0, &sc->sc_cmd_bh)) {
489 		dnprintf(10, "%s: failed to map S/C reg.\n", DEVNAME(sc));
490 		return (1);
491 	}
492 
493 	if (dtype == GAS_SYSTEM_IOSPACE)
494 		sc->sc_data_bt = aa->aaa_iot;
495 	else
496 		sc->sc_data_bt = aa->aaa_memt;
497 
498 	if (bus_space_map(sc->sc_data_bt, ec_data, 1, 0, &sc->sc_data_bh)) {
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 = REG_TYPE_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