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