This source file includes following definitions.
- acpiec_wait
- acpiec_status
- acpiec_write_data
- acpiec_write_cmd
- acpiec_read_data
- acpiec_sci_event
- acpiec_read_1
- acpiec_write_1
- acpiec_burst_enable
- acpiec_read
- acpiec_write
- acpiec_match
- acpiec_attach
- acpiec_get_events
- acpiec_gpehandler
- acpiec_getregister
- acpiec_getcrs
- acpiec_reg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
44 u_int8_t acpiec_read_1(struct acpiec_softc *, u_int8_t);
45 void acpiec_write_1(struct acpiec_softc *, u_int8_t, u_int8_t);
46
47 void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
48 void acpiec_write(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
49
50 int acpiec_getcrs(struct acpiec_softc *,
51 struct acpi_attach_args *);
52 int acpiec_getregister(const u_int8_t *, int, int *, bus_size_t *);
53
54 void acpiec_wait(struct acpiec_softc *, u_int8_t, u_int8_t);
55 void acpiec_sci_event(struct acpiec_softc *);
56
57 void acpiec_get_events(struct acpiec_softc *);
58
59 int acpiec_gpehandler(struct acpi_softc *, int, void *);
60
61 struct aml_node *aml_find_name(struct acpi_softc *, struct aml_node *,
62 const char *);
63
64
65 #define EC_STAT_SMI_EVT 0x40
66 #define EC_STAT_SCI_EVT 0x20
67 #define EC_STAT_BURST 0x10
68 #define EC_STAT_CMD 0x08
69 #define EC_STAT_IBF 0x02
70 #define EC_STAT_OBF 0x01
71
72
73 #define EC_CMD_RD 0x80
74 #define EC_CMD_WR 0x81
75 #define EC_CMD_BE 0x82
76 #define EC_CMD_BD 0x83
77 #define EC_CMD_QR 0x84
78
79 #define REG_TYPE_EC 3
80
81 #define ACPIEC_MAX_EVENTS 256
82
83 struct acpiec_event {
84 struct aml_node *event;
85 };
86
87 struct acpiec_softc {
88 struct device sc_dev;
89
90
91 bus_space_tag_t sc_cmd_bt;
92 bus_space_handle_t sc_cmd_bh;
93
94
95 bus_space_tag_t sc_data_bt;
96 bus_space_handle_t sc_data_bh;
97
98 struct acpi_softc *sc_acpi;
99 struct aml_node *sc_devnode;
100 u_int32_t sc_gpe;
101 struct acpiec_event sc_events[ACPIEC_MAX_EVENTS];
102 int sc_gotsci;
103 };
104
105
106 int acpiec_reg(struct acpiec_softc *);
107
108 struct cfattach acpiec_ca = {
109 sizeof(struct acpiec_softc), acpiec_match, acpiec_attach
110 };
111
112 struct cfdriver acpiec_cd = {
113 NULL, "acpiec", DV_DULL
114 };
115
116
117 void
118 acpiec_wait(struct acpiec_softc *sc, u_int8_t mask, u_int8_t val)
119 {
120 u_int8_t stat;
121
122 dnprintf(40, "%s: EC wait_ns for: %b == %02x\n",
123 DEVNAME(sc), (int)mask,
124 "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF", (int)val);
125
126 while (((stat = acpiec_status(sc)) & mask) != val) {
127 if (stat & EC_STAT_SCI_EVT)
128 sc->sc_gotsci = 1;
129 if (cold)
130 delay(1);
131 else
132 tsleep(sc, PWAIT, "ecwait", 1);
133 }
134
135 dnprintf(40, "%s: EC wait_ns, stat: %b\n", DEVNAME(sc), (int)stat,
136 "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
137 }
138
139 u_int8_t
140 acpiec_status(struct acpiec_softc *sc)
141 {
142 return (bus_space_read_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0));
143 }
144
145 void
146 acpiec_write_data(struct acpiec_softc *sc, u_int8_t val)
147 {
148 acpiec_wait(sc, EC_STAT_IBF, 0);
149 dnprintf(40, "acpiec: write_data -- %d\n", (int)val);
150 bus_space_write_1(sc->sc_data_bt, sc->sc_data_bh, 0, val);
151 }
152
153 void
154 acpiec_write_cmd(struct acpiec_softc *sc, u_int8_t val)
155 {
156 acpiec_wait(sc, EC_STAT_IBF, 0);
157 dnprintf(40, "acpiec: write_cmd -- %d\n", (int)val);
158 bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, val);
159 }
160
161 u_int8_t
162 acpiec_read_data(struct acpiec_softc *sc)
163 {
164 u_int8_t val;
165
166 acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
167 dnprintf(40, "acpiec: read_data\n", (int)val);
168 val = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
169
170 return (val);
171 }
172
173 void
174 acpiec_sci_event(struct acpiec_softc *sc)
175 {
176 u_int8_t evt;
177
178 sc->sc_gotsci = 0;
179
180 acpiec_wait(sc, EC_STAT_IBF, 0);
181 bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, EC_CMD_QR);
182
183 acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
184 evt = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
185
186 if (evt) {
187 dnprintf(10, "%s: sci_event: 0x%02x\n", DEVNAME(sc), (int)evt);
188 aml_evalnode(sc->sc_acpi, sc->sc_events[evt].event, 0, NULL,
189 NULL);
190 }
191 }
192
193 u_int8_t
194 acpiec_read_1(struct acpiec_softc *sc, u_int8_t addr)
195 {
196 u_int8_t val;
197
198 if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
199 sc->sc_gotsci = 1;
200
201 acpiec_write_cmd(sc, EC_CMD_RD);
202 acpiec_write_data(sc, addr);
203
204 val = acpiec_read_data(sc);
205
206 return (val);
207 }
208
209 void
210 acpiec_write_1(struct acpiec_softc *sc, u_int8_t addr, u_int8_t data)
211 {
212 if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
213 sc->sc_gotsci = 1;
214
215 acpiec_write_cmd(sc, EC_CMD_WR);
216 acpiec_write_data(sc, addr);
217 acpiec_write_data(sc, data);
218 }
219
220 void
221 acpiec_burst_enable(struct acpiec_softc *sc)
222 {
223 acpiec_write_cmd(sc, EC_CMD_BE);
224 acpiec_read_data(sc);
225 }
226
227 void
228 acpiec_read(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer)
229 {
230 int reg;
231
232
233
234
235
236
237 acpiec_burst_enable(sc);
238 dnprintf(20, "%s: read %d, %d\n", DEVNAME(sc), (int)addr, len);
239
240 for (reg = 0; reg < len; reg++)
241 buffer[reg] = acpiec_read_1(sc, addr + reg);
242 }
243
244 void
245 acpiec_write(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer)
246 {
247 int reg;
248
249
250
251
252
253
254 acpiec_burst_enable(sc);
255 dnprintf(20, "%s: write %d, %d\n", DEVNAME(sc), (int)addr, len);
256 for (reg = 0; reg < len; reg++)
257 acpiec_write_1(sc, addr + reg, buffer[reg]);
258 }
259
260 int
261 acpiec_match(struct device *parent, void *match, void *aux)
262 {
263 struct acpi_attach_args *aa = aux;
264 struct cfdata *cf = match;
265
266
267 if (aa->aaa_name == NULL ||
268 strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
269 aa->aaa_table != NULL)
270 return (0);
271
272 return (1);
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
281 sc->sc_acpi = (struct acpi_softc *)parent;
282 sc->sc_devnode = aa->aaa_node->child;
283
284 if (sc->sc_acpi->sc_ec != NULL) {
285 printf(": Only single EC is supported!\n");
286 return;
287 }
288
289 if (acpiec_getcrs(sc, aa)) {
290 printf(": Failed to read resource settings\n");
291 return;
292 }
293
294 if (acpiec_reg(sc)) {
295 printf(": Failed to register address space\n");
296 return;
297 }
298
299 acpiec_get_events(sc);
300
301 sc->sc_acpi->sc_ec = sc;
302
303 dnprintf(10, "%s: GPE: %d\n", DEVNAME(sc), sc->sc_gpe);
304
305 #ifndef SMALL_KERNEL
306 acpi_set_gpehandler(sc->sc_acpi, sc->sc_gpe, acpiec_gpehandler,
307 sc, "acpiec");
308 #endif
309
310 printf(": %s\n", sc->sc_devnode->parent->name);
311 }
312
313 void
314 acpiec_get_events(struct acpiec_softc *sc)
315 {
316 int idx;
317 char name[16];
318
319 memset(sc->sc_events, 0, sizeof(sc->sc_events));
320 for (idx = 0; idx < ACPIEC_MAX_EVENTS; idx++) {
321 snprintf(name, sizeof(name), "_Q%02X", idx);
322 sc->sc_events[idx].event = aml_searchname(sc->sc_devnode, name);
323 if (sc->sc_events[idx].event != NULL)
324 dnprintf(10, "%s: Found event %s\n", DEVNAME(sc), name);
325 }
326 }
327
328 int
329 acpiec_gpehandler(struct acpi_softc *acpi_sc, int gpe, void *arg)
330 {
331 struct acpiec_softc *sc = arg;
332 u_int8_t mask, stat;
333
334 dnprintf(10, "ACPIEC: got gpe\n");
335
336
337 mask = (1L << (gpe & 7));
338 acpi_write_pmreg(acpi_sc, ACPIREG_GPE_STS, gpe>>3, mask);
339 acpi_write_pmreg(acpi_sc, ACPIREG_GPE_EN, gpe>>3, mask);
340
341 do {
342 if (sc->sc_gotsci)
343 acpiec_sci_event(sc);
344
345 stat = acpiec_status(sc);
346 dnprintf(40, "%s: EC interrupt, stat: %b\n",
347 DEVNAME(sc), (int)stat,
348 "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
349
350 if (stat & EC_STAT_SCI_EVT)
351 sc->sc_gotsci = 1;
352 } while (sc->sc_gotsci);
353
354 return (0);
355 }
356
357
358 int
359 acpiec_getregister(const u_int8_t *buf, int size, int *type, bus_size_t *addr)
360 {
361 int len, hlen;
362
363 #define RES_TYPE_MASK 0x80
364 #define RES_LENGTH_MASK 0x07
365 #define RES_TYPE_IOPORT 0x47
366 #define RES_TYPE_ENDTAG 0x79
367
368 if (size <= 0)
369 return (0);
370
371 if (*buf & RES_TYPE_MASK) {
372
373 if (size < 3)
374 return (1);
375 len = (int)buf[1] + 256 * (int)buf[2];
376 hlen = 3;
377 } else {
378
379 len = buf[0] & RES_LENGTH_MASK;
380 hlen = 1;
381 }
382
383
384 if (*buf != RES_TYPE_IOPORT)
385 return (0);
386
387 if (size < hlen + len)
388 return (0);
389
390
391 *type = GAS_SYSTEM_IOSPACE;
392 *addr = (int)buf[2] + 256 * (int)buf[3];
393
394 return (hlen + len);
395 }
396
397 int
398 acpiec_getcrs(struct acpiec_softc *sc, struct acpi_attach_args *aa)
399 {
400 struct aml_value res;
401 bus_size_t ec_sc, ec_data;
402 int type1, type2;
403 char *buf;
404 int size, ret;
405
406 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_GPE", 0, NULL, &res)) {
407 dnprintf(10, "%s: no _GPE\n", DEVNAME(sc));
408 return (1);
409 }
410
411 sc->sc_gpe = aml_val2int(&res);
412 aml_freevalue(&res);
413
414 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
415 dnprintf(10, "%s: no _CRS\n", DEVNAME(sc));
416 return (1);
417 }
418
419
420
421 if (res.type != AML_OBJTYPE_BUFFER) {
422 dnprintf(10, "%s: unknown _CRS type %d\n",
423 DEVNAME(sc), res.type);
424 aml_freevalue(&res);
425 return (1);
426 }
427
428 size = res.length;
429 buf = res.v_buffer;
430
431 ret = acpiec_getregister(buf, size, &type1, &ec_data);
432 if (ret <= 0) {
433 dnprintf(10, "%s: failed to read DATA from _CRS\n",
434 DEVNAME(sc));
435 aml_freevalue(&res);
436 return (1);
437 }
438
439 buf += ret;
440 size -= ret;
441
442 ret = acpiec_getregister(buf, size, &type2, &ec_sc);
443 if (ret <= 0) {
444 dnprintf(10, "%s: failed to read S/C from _CRS\n",
445 DEVNAME(sc));
446 aml_freevalue(&res);
447 return (1);
448 }
449
450 buf += ret;
451 size -= ret;
452
453 if (size != 2 || *buf != RES_TYPE_ENDTAG) {
454 dnprintf(10, "%s: no _CRS end tag\n", DEVNAME(sc));
455 aml_freevalue(&res);
456 return (1);
457 }
458 aml_freevalue(&res);
459
460
461
462 dnprintf(10, "%s: Data: 0x%x, S/C: 0x%x\n",
463 DEVNAME(sc), ec_data, ec_sc);
464
465 if (type1 == GAS_SYSTEM_IOSPACE)
466 sc->sc_cmd_bt = aa->aaa_iot;
467 else
468 sc->sc_cmd_bt = aa->aaa_memt;
469
470 if (bus_space_map(sc->sc_cmd_bt, ec_sc, 1, 0, &sc->sc_cmd_bh)) {
471 dnprintf(10, "%s: failed to map S/C reg.\n", DEVNAME(sc));
472 return (1);
473 }
474
475 if (type2 == GAS_SYSTEM_IOSPACE)
476 sc->sc_data_bt = aa->aaa_iot;
477 else
478 sc->sc_data_bt = aa->aaa_memt;
479
480 if (bus_space_map(sc->sc_data_bt, ec_data, 1, 0, &sc->sc_data_bh)) {
481 dnprintf(10, "%s: failed to map DATA reg.\n", DEVNAME(sc));
482 bus_space_unmap(sc->sc_cmd_bt, sc->sc_cmd_bh, 1);
483 return (1);
484 }
485
486 return (0);
487 }
488
489 int
490 acpiec_reg(struct acpiec_softc *sc)
491 {
492 struct aml_value arg[2];
493 struct aml_node *root;
494
495 memset(&arg, 0, sizeof(arg));
496
497 arg[0].type = AML_OBJTYPE_INTEGER;
498 arg[0].v_integer = REG_TYPE_EC;
499 arg[1].type = AML_OBJTYPE_INTEGER;
500 arg[1].v_integer = 1;
501
502 root = aml_searchname(sc->sc_devnode, "_REG");
503 if (root == NULL) {
504 dnprintf(10, "%s: no _REG method\n", DEVNAME(sc));
505 return (1);
506 }
507
508 if (aml_evalnode(sc->sc_acpi, root, 2, arg, NULL) != 0) {
509 dnprintf(10, "%s: eval method _REG failed\n", DEVNAME(sc));
510 return (1);
511 }
512
513 return (0);
514 }