xref: /openbsd-src/sys/dev/acpi/dwiic_acpi.c (revision d1df930ffab53da22f3324c32bed7ac5709915e6)
1 /* $OpenBSD: dwiic_acpi.c,v 1.8 2018/07/01 11:37:11 kettenis Exp $ */
2 /*
3  * Synopsys DesignWare I2C controller
4  *
5  * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org>
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/kernel.h>
23 #include <sys/kthread.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 <dev/ic/dwiicvar.h>
32 
33 struct dwiic_crs {
34 	int irq_int;
35 	uint8_t irq_flags;
36 	uint32_t addr_min;
37 	uint32_t addr_bas;
38 	uint32_t addr_len;
39 	uint16_t i2c_addr;
40 	struct aml_node *devnode;
41 	struct aml_node *gpio_int_node;
42 	uint16_t gpio_int_pin;
43 	uint16_t gpio_int_flags;
44 };
45 
46 int		dwiic_acpi_match(struct device *, void *, void *);
47 void		dwiic_acpi_attach(struct device *, struct device *, void *);
48 
49 int		dwiic_acpi_parse_crs(int, union acpi_resource *, void *);
50 int		dwiic_acpi_found_ihidev(struct dwiic_softc *,
51 		    struct aml_node *, char *, struct dwiic_crs);
52 int		dwiic_acpi_found_iatp(struct dwiic_softc *, struct aml_node *,
53 		    char *, struct dwiic_crs);
54 void		dwiic_acpi_get_params(struct dwiic_softc *, char *, uint16_t *,
55 		    uint16_t *, uint32_t *);
56 void		dwiic_acpi_power(struct dwiic_softc *, int);
57 void		dwiic_acpi_bus_scan(struct device *,
58 		    struct i2cbus_attach_args *, void *);
59 
60 struct cfattach dwiic_acpi_ca = {
61 	sizeof(struct dwiic_softc),
62 	dwiic_acpi_match,
63 	dwiic_acpi_attach,
64 	NULL,
65 	dwiic_activate
66 };
67 
68 const char *dwiic_hids[] = {
69 	"INT33C2",
70 	"INT33C3",
71 	"INT3432",
72 	"INT3433",
73 	"80860F41",
74 	"808622C1",
75 	NULL
76 };
77 
78 const char *ihidev_hids[] = {
79 	"PNP0C50",
80 	"ACPI0C50",
81 	NULL
82 };
83 
84 const char *iatp_hids[] = {
85 	"ATML0000",
86 	"ATML0001",
87 	NULL
88 };
89 
90 int
91 dwiic_acpi_match(struct device *parent, void *match, void *aux)
92 {
93 	struct acpi_attach_args *aaa = aux;
94 	struct cfdata *cf = match;
95 
96 	return acpi_matchhids(aaa, dwiic_hids, cf->cf_driver->cd_name);
97 }
98 
99 void
100 dwiic_acpi_attach(struct device *parent, struct device *self, void *aux)
101 {
102 	struct dwiic_softc *sc = (struct dwiic_softc *)self;
103 	struct acpi_attach_args *aa = aux;
104 	struct aml_value res;
105 	struct dwiic_crs crs;
106 
107 	sc->sc_acpi = (struct acpi_softc *)parent;
108 	sc->sc_devnode = aa->aaa_node;
109 	memcpy(&sc->sc_hid, aa->aaa_dev, sizeof(sc->sc_hid));
110 
111 	printf(" %s", sc->sc_devnode->name);
112 
113 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
114 		printf(", no _CRS method\n");
115 		return;
116 	}
117 	if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
118 		printf(", invalid _CRS object (type %d len %d)\n",
119 		    res.type, res.length);
120 		aml_freevalue(&res);
121 		return;
122 	}
123 	memset(&crs, 0, sizeof(crs));
124 	crs.devnode = sc->sc_devnode;
125 	aml_parse_resource(&res, dwiic_acpi_parse_crs, &crs);
126 	aml_freevalue(&res);
127 
128 	if (crs.addr_bas == 0) {
129 		printf(", can't find address\n");
130 		return;
131 	}
132 
133 	printf(" addr 0x%x/0x%x", crs.addr_bas, crs.addr_len);
134 
135 	sc->sc_iot = aa->aaa_memt;
136 	if (bus_space_map(sc->sc_iot, crs.addr_bas, crs.addr_len, 0,
137 	    &sc->sc_ioh)) {
138 		printf(", failed mapping at 0x%x\n", crs.addr_bas);
139 		return;
140 	}
141 
142 	/* power up the controller */
143 	dwiic_acpi_power(sc, 1);
144 
145 	/* fetch timing parameters */
146 	sc->ss_hcnt = dwiic_read(sc, DW_IC_SS_SCL_HCNT);
147 	sc->ss_lcnt = dwiic_read(sc, DW_IC_SS_SCL_LCNT);
148 	sc->fs_hcnt = dwiic_read(sc, DW_IC_FS_SCL_HCNT);
149 	sc->fs_lcnt = dwiic_read(sc, DW_IC_FS_SCL_LCNT);
150 	sc->sda_hold_time = dwiic_read(sc, DW_IC_SDA_HOLD);
151 	dwiic_acpi_get_params(sc, "SSCN", &sc->ss_hcnt, &sc->ss_lcnt, NULL);
152 	dwiic_acpi_get_params(sc, "FMCN", &sc->fs_hcnt, &sc->fs_lcnt,
153 	    &sc->sda_hold_time);
154 
155 	if (dwiic_init(sc)) {
156 		printf(", failed initializing\n");
157 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, crs.addr_len);
158 		return;
159 	}
160 
161 	/* leave the controller disabled */
162 	dwiic_write(sc, DW_IC_INTR_MASK, 0);
163 	dwiic_enable(sc, 0);
164 	dwiic_read(sc, DW_IC_CLR_INTR);
165 
166 	/* try to register interrupt with apic, but not fatal without it */
167 	if (crs.irq_int > 0) {
168 		printf(" irq %d", crs.irq_int);
169 
170 		sc->sc_ih = acpi_intr_establish(crs.irq_int, crs.irq_flags,
171 		    IPL_BIO, dwiic_intr, sc, sc->sc_dev.dv_xname);
172 		if (sc->sc_ih == NULL)
173 			printf(", can't establish interrupt");
174 	}
175 
176 	printf("\n");
177 
178 	rw_init(&sc->sc_i2c_lock, "iiclk");
179 
180 	/* setup and attach iic bus */
181 	sc->sc_i2c_tag.ic_cookie = sc;
182 	sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus;
183 	sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus;
184 	sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
185 	sc->sc_i2c_tag.ic_intr_establish = dwiic_i2c_intr_establish;
186 	sc->sc_i2c_tag.ic_intr_string = dwiic_i2c_intr_string;
187 
188 	bzero(&sc->sc_iba, sizeof(sc->sc_iba));
189 	sc->sc_iba.iba_name = "iic";
190 	sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
191 	sc->sc_iba.iba_bus_scan = dwiic_acpi_bus_scan;
192 	sc->sc_iba.iba_bus_scan_arg = sc;
193 
194 	config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
195 
196 #ifndef SMALL_KERNEL
197 	sc->sc_devnode->i2c = &sc->sc_i2c_tag;
198 	acpi_register_gsb(sc->sc_acpi, sc->sc_devnode);
199 #endif
200 
201 	return;
202 }
203 
204 int
205 dwiic_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
206 {
207 	struct dwiic_crs *sc_crs = arg;
208 	struct aml_node *node;
209 	uint16_t pin;
210 
211 	switch (AML_CRSTYPE(crs)) {
212 	case SR_IRQ:
213 		sc_crs->irq_int = ffs(letoh16(crs->sr_irq.irq_mask)) - 1;
214 		sc_crs->irq_flags = crs->sr_irq.irq_flags;
215 		break;
216 
217 	case LR_EXTIRQ:
218 		sc_crs->irq_int = letoh32(crs->lr_extirq.irq[0]);
219 		sc_crs->irq_flags = crs->lr_extirq.flags;
220 		break;
221 
222 	case LR_GPIO:
223 		node = aml_searchname(sc_crs->devnode,
224 		    (char *)&crs->pad[crs->lr_gpio.res_off]);
225 		pin = *(uint16_t *)&crs->pad[crs->lr_gpio.pin_off];
226 		if (crs->lr_gpio.type == LR_GPIO_INT) {
227 			sc_crs->gpio_int_node = node;
228 			sc_crs->gpio_int_pin = pin;
229 			sc_crs->gpio_int_flags = crs->lr_gpio.tflags;
230 		}
231 		break;
232 
233 	case LR_MEM32:
234 		sc_crs->addr_min = letoh32(crs->lr_m32._min);
235 		sc_crs->addr_len = letoh32(crs->lr_m32._len);
236 		break;
237 
238 	case LR_MEM32FIXED:
239 		sc_crs->addr_bas = letoh32(crs->lr_m32fixed._bas);
240 		sc_crs->addr_len = letoh32(crs->lr_m32fixed._len);
241 		break;
242 
243 	case LR_SERBUS:
244 		if (crs->lr_serbus.type == LR_SERBUS_I2C)
245 			sc_crs->i2c_addr = letoh16(crs->lr_i2cbus._adr);
246 		break;
247 
248 	default:
249 		DPRINTF(("%s: unknown resource type %d\n", __func__,
250 		    AML_CRSTYPE(crs)));
251 	}
252 
253 	return 0;
254 }
255 
256 void
257 dwiic_acpi_get_params(struct dwiic_softc *sc, char *method, uint16_t *hcnt,
258     uint16_t *lcnt, uint32_t *sda_hold_time)
259 {
260 	struct aml_value res;
261 
262 	if (!aml_searchname(sc->sc_devnode, method))
263 		return;
264 
265 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, method, 0, NULL, &res)) {
266 		printf(": eval of %s at %s failed", method,
267 		    aml_nodename(sc->sc_devnode));
268 		return;
269 	}
270 
271 	if (res.type != AML_OBJTYPE_PACKAGE) {
272 		printf(": %s is not a package (%d)", method, res.type);
273 		aml_freevalue(&res);
274 		return;
275 	}
276 
277 	if (res.length <= 2) {
278 		printf(": %s returned package of len %d", method, res.length);
279 		aml_freevalue(&res);
280 		return;
281 	}
282 
283 	*hcnt = aml_val2int(res.v_package[0]);
284 	*lcnt = aml_val2int(res.v_package[1]);
285 	if (sda_hold_time)
286 		*sda_hold_time = aml_val2int(res.v_package[2]);
287 	aml_freevalue(&res);
288 }
289 
290 void
291 dwiic_acpi_bus_scan(struct device *iic, struct i2cbus_attach_args *iba,
292     void *aux)
293 {
294 	struct dwiic_softc *sc = (struct dwiic_softc *)aux;
295 
296 	sc->sc_iic = iic;
297 	aml_find_node(sc->sc_devnode, "_HID", dwiic_acpi_found_hid, sc);
298 }
299 
300 void *
301 dwiic_i2c_intr_establish(void *cookie, void *ih, int level,
302     int (*func)(void *), void *arg, const char *name)
303 {
304 	struct dwiic_crs *crs = ih;
305 
306 	if (crs->gpio_int_node && crs->gpio_int_node->gpio) {
307 		struct acpi_gpio *gpio = crs->gpio_int_node->gpio;
308 		gpio->intr_establish(gpio->cookie, crs->gpio_int_pin,
309 				     crs->gpio_int_flags, func, arg);
310 		return ih;
311 	}
312 
313 	return acpi_intr_establish(crs->irq_int, crs->irq_flags,
314 	    level, func, arg, name);
315 }
316 
317 const char *
318 dwiic_i2c_intr_string(void *cookie, void *ih)
319 {
320 	struct dwiic_crs *crs = ih;
321 	static char irqstr[64];
322 
323 	if (crs->gpio_int_node && crs->gpio_int_node->gpio)
324 		snprintf(irqstr, sizeof(irqstr), "gpio %d", crs->gpio_int_pin);
325 	else
326 		snprintf(irqstr, sizeof(irqstr), "irq %d", crs->irq_int);
327 
328 	return irqstr;
329 }
330 
331 int
332 dwiic_matchhids(const char *hid, const char *hids[])
333 {
334 	int i;
335 
336 	for (i = 0; hids[i]; i++)
337 		if (!strcmp(hid, hids[i]))
338 			return (1);
339 
340 	return (0);
341 }
342 
343 int
344 dwiic_acpi_found_hid(struct aml_node *node, void *arg)
345 {
346 	struct dwiic_softc *sc = (struct dwiic_softc *)arg;
347 	struct dwiic_crs crs;
348 	struct aml_value res;
349 	int64_t sta;
350 	char cdev[16], dev[16];
351 	struct i2c_attach_args ia;
352 
353 	/* Skip our own _HID. */
354 	if (node->parent == sc->sc_devnode)
355 		return 0;
356 
357 	if (acpi_parsehid(node, arg, cdev, dev, 16) != 0)
358 		return 0;
359 
360 	if (aml_evalinteger(acpi_softc, node->parent, "_STA", 0, NULL, &sta))
361 		sta = STA_PRESENT | STA_ENABLED | STA_DEV_OK | 0x1000;
362 
363 	if ((sta & STA_PRESENT) == 0)
364 		return 0;
365 
366 	DPRINTF(("%s: found HID %s at %s\n", sc->sc_dev.dv_xname, dev,
367 	    aml_nodename(node)));
368 
369 	if (aml_evalname(acpi_softc, node->parent, "_CRS", 0, NULL, &res)) {
370 		printf("%s: no _CRS method at %s\n", sc->sc_dev.dv_xname,
371 		    aml_nodename(node->parent));
372 		return (0);
373 	}
374 	if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
375 		printf("%s: invalid _CRS object (type %d len %d)\n",
376 		    sc->sc_dev.dv_xname, res.type, res.length);
377 		aml_freevalue(&res);
378 		return (0);
379 	}
380 	memset(&crs, 0, sizeof(crs));
381 	crs.devnode = sc->sc_devnode;
382 	aml_parse_resource(&res, dwiic_acpi_parse_crs, &crs);
383 	aml_freevalue(&res);
384 
385 	acpi_attach_deps(acpi_softc, node->parent);
386 
387 	if (dwiic_matchhids(cdev, ihidev_hids))
388 		return dwiic_acpi_found_ihidev(sc, node, dev, crs);
389 	else if (dwiic_matchhids(dev, iatp_hids))
390 		return dwiic_acpi_found_iatp(sc, node, dev, crs);
391 
392 	memset(&ia, 0, sizeof(ia));
393 	ia.ia_tag = sc->sc_iba.iba_tag;
394 	ia.ia_name = dev;
395 	ia.ia_addr = crs.i2c_addr;
396 	ia.ia_cookie = node->parent;
397 
398 	if (crs.irq_int != 0 || crs.gpio_int_node != NULL)
399 		ia.ia_intr = &crs;
400 
401 	config_found(sc->sc_iic, &ia, dwiic_i2c_print);
402 	node->parent->attached = 1;
403 
404 	return 0;
405 }
406 
407 int
408 dwiic_acpi_found_ihidev(struct dwiic_softc *sc, struct aml_node *node,
409     char *dev, struct dwiic_crs crs)
410 {
411 	struct i2c_attach_args ia;
412 	struct aml_value cmd[4], res;
413 
414 	/* 3cdff6f7-4267-4555-ad05-b30a3d8938de */
415 	static uint8_t i2c_hid_guid[] = {
416 		0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45,
417 		0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
418 	};
419 
420 	if (!aml_searchname(node->parent, "_DSM")) {
421 		printf("%s: couldn't find _DSM at %s\n", sc->sc_dev.dv_xname,
422 		    aml_nodename(node->parent));
423 		return 0;
424 	}
425 
426 	bzero(&cmd, sizeof(cmd));
427 	cmd[0].type = AML_OBJTYPE_BUFFER;
428 	cmd[0].v_buffer = (uint8_t *)&i2c_hid_guid;
429 	cmd[0].length = sizeof(i2c_hid_guid);
430 	/* rev */
431 	cmd[1].type = AML_OBJTYPE_INTEGER;
432 	cmd[1].v_integer = 1;
433 	cmd[1].length = 1;
434 	/* func */
435 	cmd[2].type = AML_OBJTYPE_INTEGER;
436 	cmd[2].v_integer = 1; /* HID */
437 	cmd[2].length = 1;
438 	/* not used */
439 	cmd[3].type = AML_OBJTYPE_PACKAGE;
440 	cmd[3].length = 0;
441 
442 	if (aml_evalname(acpi_softc, node->parent, "_DSM", 4, cmd, &res)) {
443 		printf("%s: eval of _DSM at %s failed\n",
444 		    sc->sc_dev.dv_xname, aml_nodename(node->parent));
445 		return 0;
446 	}
447 
448 	if (res.type != AML_OBJTYPE_INTEGER) {
449 		printf("%s: bad _DSM result at %s: %d\n",
450 		    sc->sc_dev.dv_xname, aml_nodename(node->parent), res.type);
451 		aml_freevalue(&res);
452 		return 0;
453 	}
454 
455 	memset(&ia, 0, sizeof(ia));
456 	ia.ia_tag = sc->sc_iba.iba_tag;
457 	ia.ia_size = 1;
458 	ia.ia_name = "ihidev";
459 	ia.ia_size = aml_val2int(&res); /* hid descriptor address */
460 	ia.ia_addr = crs.i2c_addr;
461 	ia.ia_cookie = dev;
462 
463 	aml_freevalue(&res);
464 
465 	if (!sc->sc_poll_ihidev &&
466 	    !(crs.irq_int == 0 && crs.gpio_int_node == NULL))
467 		ia.ia_intr = &crs;
468 
469 	if (config_found(sc->sc_iic, &ia, dwiic_i2c_print)) {
470 		node->parent->attached = 1;
471 		return 0;
472 	}
473 
474 	return 1;
475 }
476 
477 int
478 dwiic_acpi_found_iatp(struct dwiic_softc *sc, struct aml_node *node, char *dev,
479     struct dwiic_crs crs)
480 {
481 	struct i2c_attach_args ia;
482 	struct aml_value res;
483 
484 	if (aml_evalname(acpi_softc, node->parent, "GPIO", 0, NULL, &res))
485 		/* no gpio, assume this is the bootloader interface */
486 		return (0);
487 
488 	memset(&ia, 0, sizeof(ia));
489 	ia.ia_tag = sc->sc_iba.iba_tag;
490 	ia.ia_size = 1;
491 	ia.ia_name = "iatp";
492 	ia.ia_addr = crs.i2c_addr;
493 	ia.ia_cookie = dev;
494 
495 	if (crs.irq_int <= 0 && crs.gpio_int_node == NULL) {
496 		printf("%s: couldn't find irq for %s\n", sc->sc_dev.dv_xname,
497 		   aml_nodename(node->parent));
498 		return 0;
499 	}
500 	ia.ia_intr = &crs;
501 
502 	if (config_found(sc->sc_iic, &ia, dwiic_i2c_print)) {
503 		node->parent->attached = 1;
504 		return 0;
505 	}
506 
507 	return 1;
508 }
509 
510 void
511 dwiic_acpi_power(struct dwiic_softc *sc, int power)
512 {
513 	char ps[] = "_PS0";
514 
515 	if (!power)
516 		ps[3] = '3';
517 
518 	if (aml_searchname(sc->sc_devnode, ps)) {
519 		if (aml_evalname(sc->sc_acpi, sc->sc_devnode, ps, 0, NULL,
520 		    NULL)) {
521 			printf("%s: failed powering %s with %s\n",
522 			    sc->sc_dev.dv_xname, power ? "on" : "off",
523 			    ps);
524 			return;
525 		}
526 
527 		DELAY(10000); /* 10 milliseconds */
528 	} else
529 		DPRINTF(("%s: no %s method\n", sc->sc_dev.dv_xname, ps));
530 
531 	if (strcmp(sc->sc_hid, "INT3432") == 0 ||
532 	    strcmp(sc->sc_hid, "INT3433") == 0) {
533 		/*
534 		 * XXX: broadwell i2c devices may need this for initial power
535 		 * up and/or after s3 resume.
536 		 *
537 		 * linux does this write via LPSS -> clk_register_gate ->
538 		 * clk_gate_enable -> clk_gate_endisable -> clk_writel
539 		 */
540 		dwiic_write(sc, 0x800, 1);
541 	}
542 }
543