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