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