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