1 /* $OpenBSD: qciic.c,v 1.7 2024/10/02 21:21:32 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 22 #include <machine/intr.h> 23 #include <machine/bus.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 #define _I2C_PRIVATE 32 #include <dev/i2c/i2cvar.h> 33 34 /* Registers */ 35 #define GENI_I2C_TX_TRANS_LEN 0x26c 36 #define GENI_I2C_RX_TRANS_LEN 0x270 37 #define GENI_M_CMD0 0x600 38 #define GENI_M_CMD0_OPCODE_I2C_WRITE (0x1 << 27) 39 #define GENI_M_CMD0_OPCODE_I2C_READ (0x2 << 27) 40 #define GENI_M_CMD0_SLV_ADDR_SHIFT 9 41 #define GENI_M_CMD0_STOP_STRETCH (1 << 2) 42 #define GENI_M_IRQ_STATUS 0x610 43 #define GENI_M_IRQ_CLEAR 0x618 44 #define GENI_M_IRQ_CMD_DONE (1 << 0) 45 #define GENI_TX_FIFO 0x700 46 #define GENI_RX_FIFO 0x780 47 #define GENI_TX_FIFO_STATUS 0x800 48 #define GENI_RX_FIFO_STATUS 0x804 49 #define GENI_RX_FIFO_STATUS_WC(val) ((val) & 0xffffff) 50 51 #define HREAD4(sc, reg) \ 52 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 53 #define HWRITE4(sc, reg, val) \ 54 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 55 56 struct qciic_softc { 57 struct device sc_dev; 58 bus_space_tag_t sc_iot; 59 bus_space_handle_t sc_ioh; 60 61 struct acpi_softc *sc_acpi; 62 struct aml_node *sc_node; 63 struct device *sc_iic; 64 65 struct i2c_controller sc_ic; 66 }; 67 68 struct qciic_crs { 69 uint16_t i2c_addr; 70 struct aml_node *i2c_bus; 71 int irq_int; 72 uint8_t irq_flags; 73 struct aml_node *gpio_int_node; 74 uint16_t gpio_int_pin; 75 uint16_t gpio_int_flags; 76 struct aml_node *node; 77 int skip; 78 }; 79 80 int qciic_acpi_match(struct device *, void *, void *); 81 void qciic_acpi_attach(struct device *, struct device *, void *); 82 83 const struct cfattach qciic_acpi_ca = { 84 sizeof (struct qciic_softc), qciic_acpi_match, qciic_acpi_attach 85 }; 86 87 struct cfdriver qciic_cd = { 88 NULL, "qciic", DV_DULL 89 }; 90 91 int qciic_acquire_bus(void *, int); 92 void qciic_release_bus(void *, int); 93 int qciic_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, 94 void *, size_t, int); 95 96 void *qciic_i2c_intr_establish(void *, void *, int, int (*)(void *), 97 void *, const char *); 98 void qciic_i2c_intr_disestablish(void *, void *); 99 const char *qciic_i2c_intr_string(void *, void *); 100 101 int qciic_acpi_parse_crs(int, union acpi_resource *, void *); 102 void qciic_acpi_bus_scan(struct device *, struct i2cbus_attach_args *, 103 void *); 104 int qciic_acpi_found_hid(struct aml_node *, void *); 105 int qciic_acpi_found_ihidev(struct qciic_softc *, 106 struct aml_node *, char *, struct qciic_crs); 107 108 const char *qciic_hids[] = { 109 "QCOM0610", 110 "QCOM0811", 111 "QCOM0C10", 112 NULL 113 }; 114 115 int 116 qciic_acpi_match(struct device *parent, void *match, void *aux) 117 { 118 struct acpi_attach_args *aaa = aux; 119 struct cfdata *cf = match; 120 121 if (aaa->aaa_naddr < 1) 122 return 0; 123 return acpi_matchhids(aaa, qciic_hids, cf->cf_driver->cd_name); 124 } 125 126 void 127 qciic_acpi_attach(struct device *parent, struct device *self, void *aux) 128 { 129 struct qciic_softc *sc = (struct qciic_softc *)self; 130 struct acpi_attach_args *aaa = aux; 131 struct i2cbus_attach_args iba; 132 133 sc->sc_acpi = (struct acpi_softc *)parent; 134 sc->sc_node = aaa->aaa_node; 135 printf(" %s", aaa->aaa_node->name); 136 137 printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]); 138 139 sc->sc_iot = aaa->aaa_bst[0]; 140 if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0], 141 0, &sc->sc_ioh)) { 142 printf(": can't map registers\n"); 143 return; 144 } 145 146 printf("\n"); 147 148 sc->sc_ic.ic_cookie = sc; 149 sc->sc_ic.ic_acquire_bus = qciic_acquire_bus; 150 sc->sc_ic.ic_release_bus = qciic_release_bus; 151 sc->sc_ic.ic_exec = qciic_exec; 152 sc->sc_ic.ic_intr_establish = qciic_i2c_intr_establish; 153 sc->sc_ic.ic_intr_disestablish = qciic_i2c_intr_disestablish; 154 sc->sc_ic.ic_intr_string = qciic_i2c_intr_string; 155 156 #ifndef SMALL_KERNEL 157 /* 158 * XXX Registering the I2C9 node with ACPI leads to AML 159 * executing I2C transaction that fail and spin with the 160 * kernel lock held until they fail. 161 */ 162 if (strcmp(aaa->aaa_dev, "QCOM0610") != 0) { 163 sc->sc_node->i2c = &sc->sc_ic; 164 acpi_register_gsb(sc->sc_acpi, sc->sc_node); 165 } 166 #endif 167 168 memset(&iba, 0, sizeof(iba)); 169 iba.iba_name = "iic"; 170 iba.iba_tag = &sc->sc_ic; 171 iba.iba_bus_scan = qciic_acpi_bus_scan; 172 iba.iba_bus_scan_arg = sc; 173 config_found(&sc->sc_dev, &iba, iicbus_print); 174 } 175 176 int 177 qciic_acquire_bus(void *cookie, int flags) 178 { 179 return 0; 180 } 181 182 void 183 qciic_release_bus(void *cookie, int flags) 184 { 185 } 186 187 int 188 qciic_wait(struct qciic_softc *sc, uint32_t bits) 189 { 190 uint32_t stat; 191 int timo; 192 193 for (timo = 50000; timo > 0; timo--) { 194 stat = HREAD4(sc, GENI_M_IRQ_STATUS); 195 if (stat & bits) 196 break; 197 delay(10); 198 } 199 if (timo == 0) 200 return ETIMEDOUT; 201 202 return 0; 203 } 204 205 int 206 qciic_read(struct qciic_softc *sc, uint8_t *buf, size_t len) 207 { 208 uint32_t stat, word; 209 int timo, i; 210 211 word = 0; 212 for (i = 0; i < len; i++) { 213 if ((i % 4) == 0) { 214 for (timo = 50000; timo > 0; timo--) { 215 stat = HREAD4(sc, GENI_RX_FIFO_STATUS); 216 if (GENI_RX_FIFO_STATUS_WC(stat) > 0) 217 break; 218 delay(10); 219 } 220 if (timo == 0) 221 return ETIMEDOUT; 222 word = HREAD4(sc, GENI_RX_FIFO); 223 } 224 buf[i] = word >> ((i % 4) * 8); 225 } 226 227 return 0; 228 } 229 230 int 231 qciic_write(struct qciic_softc *sc, const uint8_t *buf, size_t len) 232 { 233 uint32_t stat, word; 234 int timo, i; 235 236 word = 0; 237 for (i = 0; i < len; i++) { 238 word |= buf[i] << ((i % 4) * 8); 239 if ((i % 4) == 3 || i == (len - 1)) { 240 for (timo = 50000; timo > 0; timo--) { 241 stat = HREAD4(sc, GENI_TX_FIFO_STATUS); 242 if (stat < 16) 243 break; 244 delay(10); 245 } 246 if (timo == 0) 247 return ETIMEDOUT; 248 HWRITE4(sc, GENI_TX_FIFO, word); 249 word = 0; 250 } 251 } 252 253 return 0; 254 } 255 256 int 257 qciic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd, 258 size_t cmdlen, void *buf, size_t buflen, int flags) 259 { 260 struct qciic_softc *sc = cookie; 261 uint32_t m_cmd, m_param, stat; 262 int error; 263 264 m_param = addr << GENI_M_CMD0_SLV_ADDR_SHIFT; 265 m_param |= GENI_M_CMD0_STOP_STRETCH; 266 267 if (buflen == 0 && I2C_OP_STOP_P(op)) 268 m_param &= ~GENI_M_CMD0_STOP_STRETCH; 269 270 if (cmdlen > 0) { 271 stat = HREAD4(sc, GENI_M_IRQ_STATUS); 272 HWRITE4(sc, GENI_M_IRQ_CLEAR, stat); 273 HWRITE4(sc, GENI_I2C_TX_TRANS_LEN, cmdlen); 274 m_cmd = GENI_M_CMD0_OPCODE_I2C_WRITE | m_param; 275 HWRITE4(sc, GENI_M_CMD0, m_cmd); 276 277 error = qciic_write(sc, cmd, cmdlen); 278 if (error) 279 return error; 280 281 error = qciic_wait(sc, GENI_M_IRQ_CMD_DONE); 282 if (error) 283 return error; 284 } 285 286 if (buflen == 0) 287 return 0; 288 289 if (I2C_OP_STOP_P(op)) 290 m_param &= ~GENI_M_CMD0_STOP_STRETCH; 291 292 if (I2C_OP_READ_P(op)) { 293 stat = HREAD4(sc, GENI_M_IRQ_STATUS); 294 HWRITE4(sc, GENI_M_IRQ_CLEAR, stat); 295 HWRITE4(sc, GENI_I2C_RX_TRANS_LEN, buflen); 296 m_cmd = GENI_M_CMD0_OPCODE_I2C_READ | m_param; 297 HWRITE4(sc, GENI_M_CMD0, m_cmd); 298 299 error = qciic_read(sc, buf, buflen); 300 if (error) 301 return error; 302 303 error = qciic_wait(sc, GENI_M_IRQ_CMD_DONE); 304 if (error) 305 return error; 306 } else { 307 stat = HREAD4(sc, GENI_M_IRQ_STATUS); 308 HWRITE4(sc, GENI_M_IRQ_CLEAR, stat); 309 HWRITE4(sc, GENI_I2C_TX_TRANS_LEN, buflen); 310 m_cmd = GENI_M_CMD0_OPCODE_I2C_WRITE | m_param; 311 HWRITE4(sc, GENI_M_CMD0, m_cmd); 312 313 error = qciic_write(sc, buf, buflen); 314 if (error) 315 return error; 316 317 error = qciic_wait(sc, GENI_M_IRQ_CMD_DONE); 318 if (error) 319 return error; 320 } 321 322 return 0; 323 } 324 325 void * 326 qciic_i2c_intr_establish(void *cookie, void *ih, int level, 327 int (*func)(void *), void *arg, const char *name) 328 { 329 struct qciic_crs *crs = ih; 330 331 if (crs->gpio_int_node) { 332 if (!crs->gpio_int_node->gpio) 333 /* found ACPI device but no driver for it */ 334 return NULL; 335 336 struct acpi_gpio *gpio = crs->gpio_int_node->gpio; 337 gpio->intr_establish(gpio->cookie, crs->gpio_int_pin, 338 crs->gpio_int_flags, func, arg); 339 return ih; 340 } 341 342 return acpi_intr_establish(crs->irq_int, crs->irq_flags, 343 level, func, arg, name); 344 } 345 346 void 347 qciic_i2c_intr_disestablish(void *cookie, void *ih) 348 { 349 /* XXX GPIO interrupts */ 350 acpi_intr_disestablish(ih); 351 } 352 353 const char * 354 qciic_i2c_intr_string(void *cookie, void *ih) 355 { 356 struct qciic_crs *crs = ih; 357 static char irqstr[64]; 358 359 if (crs->gpio_int_node) { 360 if (crs->gpio_int_node->gpio) 361 snprintf(irqstr, sizeof(irqstr), "gpio %d", 362 crs->gpio_int_pin); 363 } else 364 snprintf(irqstr, sizeof(irqstr), "irq %d", crs->irq_int); 365 366 return irqstr; 367 } 368 369 int 370 qciic_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg) 371 { 372 struct qciic_crs *sc_crs = arg; 373 struct aml_node *node; 374 uint16_t pin; 375 376 switch (AML_CRSTYPE(crs)) { 377 case LR_MEM32FIXED: 378 /* An MMIO address means this is not an I2C device. */ 379 sc_crs->skip = 1; 380 break; 381 382 case LR_SERBUS: 383 if (crs->lr_serbus.type == LR_SERBUS_I2C) { 384 sc_crs->i2c_addr = crs->lr_i2cbus._adr; 385 sc_crs->i2c_bus = aml_searchname(sc_crs->node, 386 &crs->lr_i2cbus.vdata[crs->lr_i2cbus.tlength - 6]); 387 } 388 break; 389 390 case LR_GPIO: 391 node = aml_searchname(sc_crs->node, 392 (char *)&crs->pad[crs->lr_gpio.res_off]); 393 pin = *(uint16_t *)&crs->pad[crs->lr_gpio.pin_off]; 394 if (crs->lr_gpio.type == LR_GPIO_INT) { 395 sc_crs->gpio_int_node = node; 396 sc_crs->gpio_int_pin = pin; 397 sc_crs->gpio_int_flags = crs->lr_gpio.tflags; 398 } 399 break; 400 } 401 402 return 0; 403 } 404 405 void 406 qciic_acpi_bus_scan(struct device *iic, struct i2cbus_attach_args *iba, 407 void *aux) 408 { 409 struct qciic_softc *sc = aux; 410 411 sc->sc_iic = iic; 412 aml_find_node(acpi_softc->sc_root, "_HID", qciic_acpi_found_hid, sc); 413 } 414 415 int 416 qciic_acpi_found_hid(struct aml_node *node, void *arg) 417 { 418 struct qciic_softc *sc = arg; 419 struct qciic_crs crs; 420 struct aml_value res; 421 int64_t sta; 422 char cdev[16], dev[16]; 423 struct i2c_attach_args ia; 424 425 /* Skip our own _HID. */ 426 if (node->parent == sc->sc_node) 427 return 0; 428 429 if (acpi_parsehid(node, arg, cdev, dev, 16) != 0) 430 return 0; 431 432 sta = acpi_getsta(acpi_softc, node->parent); 433 if ((sta & STA_PRESENT) == 0) 434 return 0; 435 436 if (aml_evalname(acpi_softc, node->parent, "_CRS", 0, NULL, &res)) 437 return 0; 438 439 if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) { 440 aml_freevalue(&res); 441 return 0; 442 } 443 memset(&crs, 0, sizeof(crs)); 444 crs.node = node->parent; 445 aml_parse_resource(&res, qciic_acpi_parse_crs, &crs); 446 aml_freevalue(&res); 447 448 /* Skip if not using this bus. */ 449 if (crs.skip || crs.i2c_bus != sc->sc_node) 450 return 0; 451 452 acpi_attach_deps(acpi_softc, node->parent); 453 454 if (strcmp(dev, "PNP0C50") == 0 || strcmp(cdev, "PNP0C50") == 0) 455 return qciic_acpi_found_ihidev(sc, node, dev, crs); 456 457 memset(&ia, 0, sizeof(ia)); 458 ia.ia_tag = &sc->sc_ic; 459 ia.ia_name = dev; 460 ia.ia_addr = crs.i2c_addr; 461 ia.ia_cookie = node->parent; 462 463 config_found(sc->sc_iic, &ia, iic_print); 464 node->parent->attached = 1; 465 466 return 0; 467 } 468 469 int 470 qciic_acpi_found_ihidev(struct qciic_softc *sc, struct aml_node *node, 471 char *dev, struct qciic_crs crs) 472 { 473 struct i2c_attach_args ia; 474 struct aml_value cmd[4], res; 475 476 /* 3cdff6f7-4267-4555-ad05-b30a3d8938de */ 477 static uint8_t i2c_hid_guid[] = { 478 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, 479 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, 480 }; 481 482 if (!aml_searchname(node->parent, "_DSM")) { 483 printf("%s: couldn't find _DSM at %s\n", sc->sc_dev.dv_xname, 484 aml_nodename(node->parent)); 485 return 0; 486 } 487 488 memset(&cmd, 0, sizeof(cmd)); 489 cmd[0].type = AML_OBJTYPE_BUFFER; 490 cmd[0].v_buffer = (uint8_t *)&i2c_hid_guid; 491 cmd[0].length = sizeof(i2c_hid_guid); 492 /* rev */ 493 cmd[1].type = AML_OBJTYPE_INTEGER; 494 cmd[1].v_integer = 1; 495 cmd[1].length = 1; 496 /* func */ 497 cmd[2].type = AML_OBJTYPE_INTEGER; 498 cmd[2].v_integer = 1; /* HID */ 499 cmd[2].length = 1; 500 /* not used */ 501 cmd[3].type = AML_OBJTYPE_PACKAGE; 502 cmd[3].length = 0; 503 504 if (aml_evalname(acpi_softc, node->parent, "_DSM", 4, cmd, &res)) { 505 printf("%s: eval of _DSM at %s failed\n", 506 sc->sc_dev.dv_xname, aml_nodename(node->parent)); 507 return 0; 508 } 509 510 if (res.type != AML_OBJTYPE_INTEGER) { 511 printf("%s: bad _DSM result at %s: %d\n", 512 sc->sc_dev.dv_xname, aml_nodename(node->parent), res.type); 513 aml_freevalue(&res); 514 return 0; 515 } 516 517 memset(&ia, 0, sizeof(ia)); 518 ia.ia_tag = &sc->sc_ic; 519 ia.ia_name = "ihidev"; 520 ia.ia_size = aml_val2int(&res); /* hid descriptor address */ 521 ia.ia_addr = crs.i2c_addr; 522 ia.ia_cookie = dev; 523 524 aml_freevalue(&res); 525 526 if (!(crs.irq_int == 0 && crs.gpio_int_node == NULL)) 527 ia.ia_intr = &crs; 528 529 if (config_found(sc->sc_iic, &ia, iic_print)) { 530 node->parent->attached = 1; 531 return 0; 532 } 533 534 return 1; 535 } 536