1 /* 2 * Copyright 2020, Jérôme Duval, jerome.duval@gmail.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <new> 8 #include <stdio.h> 9 #include <string.h> 10 11 #include <ACPI.h> 12 #include <ByteOrder.h> 13 #include <condition_variable.h> 14 #include <bus/PCI.h> 15 16 17 #include "pch_i2c.h" 18 19 20 device_manager_info* gDeviceManager; 21 i2c_for_controller_interface* gI2c; 22 acpi_module_info* gACPI; 23 24 25 static void 26 enable_device(pch_i2c_sim_info* bus, bool enable) 27 { 28 uint32 status = enable ? 1 : 0; 29 for (int tries = 100; tries >= 0; tries--) { 30 write32(bus->registers + PCH_IC_ENABLE, status); 31 if ((read32(bus->registers + PCH_IC_ENABLE_STATUS) & 1) == status) 32 return; 33 snooze(25); 34 } 35 36 ERROR("enable_device failed\n"); 37 } 38 39 40 static int32 41 pch_i2c_interrupt_handler(pch_i2c_sim_info* bus) 42 { 43 int32 handled = B_HANDLED_INTERRUPT; 44 45 // Check if this interrupt is ours 46 uint32 enable = read32(bus->registers + PCH_IC_ENABLE); 47 if (enable == 0) 48 return B_UNHANDLED_INTERRUPT; 49 50 uint32 status = read32(bus->registers + PCH_IC_INTR_STAT); 51 if ((status & PCH_IC_INTR_STAT_RX_UNDER) != 0) 52 write32(bus->registers + PCH_IC_CLR_RX_UNDER, 0); 53 if ((status & PCH_IC_INTR_STAT_RX_OVER) != 0) 54 write32(bus->registers + PCH_IC_CLR_RX_OVER, 0); 55 if ((status & PCH_IC_INTR_STAT_TX_OVER) != 0) 56 write32(bus->registers + PCH_IC_CLR_TX_OVER, 0); 57 if ((status & PCH_IC_INTR_STAT_RD_REQ) != 0) 58 write32(bus->registers + PCH_IC_CLR_RD_REQ, 0); 59 if ((status & PCH_IC_INTR_STAT_TX_ABRT) != 0) 60 write32(bus->registers + PCH_IC_CLR_TX_ABRT, 0); 61 if ((status & PCH_IC_INTR_STAT_RX_DONE) != 0) 62 write32(bus->registers + PCH_IC_CLR_RX_DONE, 0); 63 if ((status & PCH_IC_INTR_STAT_ACTIVITY) != 0) 64 write32(bus->registers + PCH_IC_CLR_ACTIVITY, 0); 65 if ((status & PCH_IC_INTR_STAT_STOP_DET) != 0) 66 write32(bus->registers + PCH_IC_CLR_STOP_DET, 0); 67 if ((status & PCH_IC_INTR_STAT_START_DET) != 0) 68 write32(bus->registers + PCH_IC_CLR_START_DET, 0); 69 if ((status & PCH_IC_INTR_STAT_GEN_CALL) != 0) 70 write32(bus->registers + PCH_IC_CLR_GEN_CALL, 0); 71 72 TRACE("pch_i2c_interrupt_handler %" B_PRIx32 "\n", status); 73 74 if ((status & ~PCH_IC_INTR_STAT_ACTIVITY) == 0) 75 return handled; 76 /*if ((status & PCH_IC_INTR_STAT_TX_ABRT) != 0) 77 tx error */ 78 if ((status & PCH_IC_INTR_STAT_RX_FULL) != 0) 79 ConditionVariable::NotifyAll(&bus->readwait, B_OK); 80 if ((status & PCH_IC_INTR_STAT_TX_EMPTY) != 0) 81 ConditionVariable::NotifyAll(&bus->writewait, B_OK); 82 if ((status & PCH_IC_INTR_STAT_STOP_DET) != 0) { 83 bus->busy = 0; 84 ConditionVariable::NotifyAll(&bus->busy, B_OK); 85 } 86 87 return handled; 88 } 89 90 91 // #pragma mark - 92 93 94 static void 95 set_sim(i2c_bus_cookie cookie, i2c_bus sim) 96 { 97 CALLED(); 98 pch_i2c_sim_info* bus = (pch_i2c_sim_info*)cookie; 99 bus->sim = sim; 100 } 101 102 103 static status_t 104 exec_command(i2c_bus_cookie cookie, i2c_op op, i2c_addr slaveAddress, 105 const void *cmdBuffer, size_t cmdLength, void* dataBuffer, 106 size_t dataLength) 107 { 108 CALLED(); 109 pch_i2c_sim_info* bus = (pch_i2c_sim_info*)cookie; 110 111 if (atomic_test_and_set(&bus->busy, 1, 0) != 0) 112 return B_BUSY; 113 114 TRACE("exec_command: acquired busy flag\n"); 115 116 uint32 status = 0; 117 for (int tries = 100; tries >= 0; tries--) { 118 status = read32(bus->registers + PCH_IC_STATUS); 119 if ((status & PCH_IC_STATUS_ACTIVITY) == 0) 120 break; 121 snooze(1000); 122 } 123 124 if ((status & PCH_IC_STATUS_ACTIVITY) != 0) { 125 bus->busy = 0; 126 return B_BUSY; 127 } 128 129 TRACE("exec_command: write slave address\n"); 130 131 enable_device(bus, false); 132 write32(bus->registers + PCH_IC_CON, 133 read32(bus->registers + PCH_IC_CON) & ~PCH_IC_CON_10BIT_ADDR_MASTER); 134 write32(bus->registers + PCH_IC_TAR, slaveAddress); 135 136 write32(bus->registers + PCH_IC_INTR_MASK, 0); 137 read32(bus->registers + PCH_IC_CLR_INTR); 138 139 enable_device(bus, true); 140 141 read32(bus->registers + PCH_IC_CLR_INTR); 142 write32(bus->registers + PCH_IC_INTR_MASK, PCH_IC_INTR_STAT_TX_EMPTY); 143 144 // wait for write 145 // wait_lock 146 147 if (cmdLength > 0) { 148 TRACE("exec_command: write command buffer\n"); 149 uint16 txLimit = bus->tx_fifo_depth 150 - read32(bus->registers + PCH_IC_TXFLR); 151 if (cmdLength > txLimit) { 152 ERROR("exec_command can't write, cmd too long %" B_PRIuSIZE 153 " (max %d)\n", cmdLength, txLimit); 154 bus->busy = 0; 155 return B_BAD_VALUE; 156 } 157 158 uint8* buffer = (uint8*)cmdBuffer; 159 for (size_t i = 0; i < cmdLength; i++) { 160 uint32 cmd = buffer[i]; 161 if (i == cmdLength - 1 && dataLength == 0 && IS_STOP_OP(op)) 162 cmd |= PCH_IC_DATA_CMD_STOP; 163 write32(bus->registers + PCH_IC_DATA_CMD, cmd); 164 } 165 } 166 167 TRACE("exec_command: processing buffer %" B_PRIuSIZE " bytes\n", 168 dataLength); 169 uint16 txLimit = bus->tx_fifo_depth 170 - read32(bus->registers + PCH_IC_TXFLR); 171 uint8* buffer = (uint8*)dataBuffer; 172 size_t readPos = 0; 173 size_t i = 0; 174 while (i < dataLength) { 175 uint32 cmd = PCH_IC_DATA_CMD_READ; 176 if (IS_WRITE_OP(op)) 177 cmd = buffer[i]; 178 179 if (i == 0 && cmdLength > 0 && IS_READ_OP(op)) 180 cmd |= PCH_IC_DATA_CMD_RESTART; 181 182 if (i == (dataLength - 1) && IS_STOP_OP(op)) 183 cmd |= PCH_IC_DATA_CMD_STOP; 184 185 write32(bus->registers + PCH_IC_DATA_CMD, cmd); 186 187 if (IS_READ_OP(op) && IS_BLOCK_OP(op) && readPos == 0) 188 txLimit = 1; 189 txLimit--; 190 i++; 191 192 // here read the data if needed 193 while (IS_READ_OP(op) && (txLimit == 0 || i == dataLength)) { 194 write32(bus->registers + PCH_IC_INTR_MASK, 195 PCH_IC_INTR_STAT_RX_FULL); 196 197 // sleep until wake up by intr handler 198 struct ConditionVariable condition; 199 condition.Publish(&bus->readwait, "pch_i2c"); 200 ConditionVariableEntry variableEntry; 201 status_t status = variableEntry.Wait(&bus->readwait, 202 B_RELATIVE_TIMEOUT, 500000L); 203 condition.Unpublish(); 204 if (status != B_OK) 205 ERROR("exec_command timed out waiting for read\n"); 206 uint32 rxBytes = read32(bus->registers + PCH_IC_RXFLR); 207 if (rxBytes == 0) { 208 ERROR("exec_command timed out reading %" B_PRIuSIZE " bytes\n", 209 dataLength - readPos); 210 bus->busy = 0; 211 return B_ERROR; 212 } 213 for (; rxBytes > 0; rxBytes--) { 214 uint32 read = read32(bus->registers + PCH_IC_DATA_CMD); 215 if (readPos < dataLength) 216 buffer[readPos++] = read; 217 } 218 219 if (IS_BLOCK_OP(op) && readPos > 0 && dataLength > buffer[0]) 220 dataLength = buffer[0] + 1; 221 if (readPos >= dataLength) 222 break; 223 224 TRACE("exec_command %" B_PRIuSIZE" bytes to be read\n", 225 dataLength - readPos); 226 txLimit = bus->tx_fifo_depth 227 - read32(bus->registers + PCH_IC_TXFLR); 228 } 229 } 230 231 status_t err = B_OK; 232 if (IS_STOP_OP(op) && IS_WRITE_OP(op)) { 233 TRACE("exec_command: waiting busy condition\n"); 234 while (bus->busy == 1) { 235 write32(bus->registers + PCH_IC_INTR_MASK, 236 PCH_IC_INTR_STAT_STOP_DET); 237 238 // sleep until wake up by intr handler 239 struct ConditionVariable condition; 240 condition.Publish(&bus->busy, "pch_i2c"); 241 ConditionVariableEntry variableEntry; 242 err = variableEntry.Wait(&bus->busy, B_RELATIVE_TIMEOUT, 243 500000L); 244 condition.Unpublish(); 245 if (err != B_OK) 246 ERROR("exec_command timed out waiting for busy\n"); 247 } 248 } 249 TRACE("exec_command: processing done\n"); 250 251 bus->busy = 0; 252 253 return err; 254 } 255 256 257 static acpi_status 258 pch_i2c_scan_parse_callback(ACPI_RESOURCE *res, void *context) 259 { 260 struct pch_i2c_crs* crs = (struct pch_i2c_crs*)context; 261 262 if (res->Type == ACPI_RESOURCE_TYPE_SERIAL_BUS && 263 res->Data.CommonSerialBus.Type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { 264 crs->i2c_addr = B_LENDIAN_TO_HOST_INT16( 265 res->Data.I2cSerialBus.SlaveAddress); 266 return AE_CTRL_TERMINATE; 267 } else if (res->Type == ACPI_RESOURCE_TYPE_IRQ) { 268 crs->irq = res->Data.Irq.Interrupts[0]; 269 crs->irq_triggering = res->Data.Irq.Triggering; 270 crs->irq_polarity = res->Data.Irq.Polarity; 271 crs->irq_shareable = res->Data.Irq.Shareable; 272 } else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { 273 crs->irq = res->Data.ExtendedIrq.Interrupts[0]; 274 crs->irq_triggering = res->Data.ExtendedIrq.Triggering; 275 crs->irq_polarity = res->Data.ExtendedIrq.Polarity; 276 crs->irq_shareable = res->Data.ExtendedIrq.Shareable; 277 } 278 279 return B_OK; 280 } 281 282 283 static status_t 284 acpi_GetInteger(acpi_handle acpiCookie, 285 const char* path, int64* number) 286 { 287 acpi_data buf; 288 acpi_object_type object; 289 buf.pointer = &object; 290 buf.length = sizeof(acpi_object_type); 291 292 // Assume that what we've been pointed at is an Integer object, or 293 // a method that will return an Integer. 294 status_t status = gACPI->evaluate_method(acpiCookie, path, NULL, &buf); 295 if (status == B_OK) { 296 if (object.object_type == ACPI_TYPE_INTEGER) 297 *number = object.integer.integer; 298 else 299 status = B_BAD_VALUE; 300 } 301 return status; 302 } 303 304 305 acpi_status 306 pch_i2c_scan_bus_callback(acpi_handle object, uint32 nestingLevel, 307 void *context, void** returnValue) 308 { 309 pch_i2c_sim_info* bus = (pch_i2c_sim_info*)context; 310 TRACE("pch_i2c_scan_bus_callback %p\n", object); 311 312 // skip absent devices 313 int64 sta; 314 status_t status = acpi_GetInteger(object, "_STA", &sta); 315 if (status == B_OK && (sta & ACPI_STA_DEVICE_PRESENT) == 0) 316 return B_OK; 317 318 // Attach devices for I2C resources 319 struct pch_i2c_crs crs; 320 status = gACPI->walk_resources(object, (ACPI_STRING)"_CRS", 321 pch_i2c_scan_parse_callback, &crs); 322 if (status != B_OK) { 323 ERROR("Error while getting I2C devices\n"); 324 return status; 325 } 326 327 TRACE("pch_i2c_scan_bus_callback deviceAddress %x\n", crs.i2c_addr); 328 329 acpi_data buffer; 330 buffer.pointer = NULL; 331 buffer.length = ACPI_ALLOCATE_BUFFER; 332 status = gACPI->ns_handle_to_pathname(object, &buffer); 333 if (status != B_OK) { 334 ERROR("pch_i2c_scan_bus_callback ns_handle_to_pathname failed\n"); 335 return status; 336 } 337 338 char* hid = NULL; 339 char* cidList[8] = { NULL }; 340 status = gACPI->get_device_info((const char*)buffer.pointer, &hid, 341 (char**)&cidList, 8, NULL); 342 if (status != B_OK) { 343 ERROR("pch_i2c_scan_bus_callback get_device_info failed\n"); 344 return status; 345 } 346 347 status = gI2c->register_device(bus->sim, crs.i2c_addr, hid, cidList, 348 object); 349 free(hid); 350 for (int i = 0; cidList[i] != NULL; i++) 351 free(cidList[i]); 352 free(buffer.pointer); 353 354 TRACE("pch_i2c_scan_bus_callback registered device: %s\n", strerror(status)); 355 356 return status; 357 } 358 359 360 static status_t 361 scan_bus(i2c_bus_cookie cookie) 362 { 363 CALLED(); 364 pch_i2c_sim_info* bus = (pch_i2c_sim_info*)cookie; 365 if (bus->scan_bus != NULL) 366 return bus->scan_bus(bus); 367 return B_OK; 368 } 369 370 371 static status_t 372 acquire_bus(i2c_bus_cookie cookie) 373 { 374 CALLED(); 375 pch_i2c_sim_info* bus = (pch_i2c_sim_info*)cookie; 376 return mutex_lock(&bus->lock); 377 } 378 379 380 static void 381 release_bus(i2c_bus_cookie cookie) 382 { 383 CALLED(); 384 pch_i2c_sim_info* bus = (pch_i2c_sim_info*)cookie; 385 mutex_unlock(&bus->lock); 386 } 387 388 389 // #pragma mark - 390 391 392 static status_t 393 init_bus(device_node* node, void** bus_cookie) 394 { 395 CALLED(); 396 status_t status = B_OK; 397 398 driver_module_info* driver; 399 pch_i2c_sim_info* bus; 400 device_node* parent = gDeviceManager->get_parent_node(node); 401 gDeviceManager->get_driver(parent, &driver, (void**)&bus); 402 gDeviceManager->put_node(parent); 403 404 TRACE_ALWAYS("init_bus() addr 0x%" B_PRIxPHYSADDR " size 0x%" B_PRIx64 405 " irq 0x%x\n", bus->base_addr, bus->map_size, bus->irq); 406 407 bus->registersArea = map_physical_memory("PCHI2C memory mapped registers", 408 bus->base_addr, bus->map_size, B_ANY_KERNEL_ADDRESS, 409 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 410 (void **)&bus->registers); 411 // init bus 412 bus->capabilities = read32(bus->registers + PCH_SUP_CAPABLITIES); 413 TRACE_ALWAYS("init_bus() 0x%" B_PRIx32 " (0x%" B_PRIx32 ")\n", 414 (bus->capabilities >> PCH_SUP_CAPABLITIES_TYPE_SHIFT) 415 & PCH_SUP_CAPABLITIES_TYPE_MASK, 416 bus->capabilities); 417 if (((bus->capabilities >> PCH_SUP_CAPABLITIES_TYPE_SHIFT) 418 & PCH_SUP_CAPABLITIES_TYPE_MASK) != 0) { 419 status = B_ERROR; 420 ERROR("init_bus() device type not supported\n"); 421 goto err; 422 } 423 424 write32(bus->registers + PCH_SUP_RESETS, 0); 425 write32(bus->registers + PCH_SUP_RESETS, 426 PCH_SUP_RESETS_FUNC | PCH_SUP_RESETS_IDMA); 427 428 if (bus->ss_hcnt == 0) 429 bus->ss_hcnt = read32(bus->registers + PCH_IC_SS_SCL_HCNT); 430 if (bus->ss_lcnt == 0) 431 bus->ss_lcnt = read32(bus->registers + PCH_IC_SS_SCL_LCNT); 432 if (bus->fs_hcnt == 0) 433 bus->fs_hcnt = read32(bus->registers + PCH_IC_FS_SCL_HCNT); 434 if (bus->fs_lcnt == 0) 435 bus->fs_lcnt = read32(bus->registers + PCH_IC_FS_SCL_LCNT); 436 if (bus->sda_hold_time == 0) 437 bus->sda_hold_time = read32(bus->registers + PCH_IC_SDA_HOLD); 438 TRACE_ALWAYS("init_bus() 0x%04" B_PRIx16 " 0x%04" B_PRIx16 " 0x%04" B_PRIx16 439 " 0x%04" B_PRIx16 " 0x%08" B_PRIx32 "\n", bus->ss_hcnt, bus->ss_lcnt, 440 bus->fs_hcnt, bus->fs_lcnt, bus->sda_hold_time); 441 442 enable_device(bus, false); 443 444 write32(bus->registers + PCH_IC_SS_SCL_HCNT, bus->ss_hcnt); 445 write32(bus->registers + PCH_IC_SS_SCL_LCNT, bus->ss_lcnt); 446 write32(bus->registers + PCH_IC_FS_SCL_HCNT, bus->fs_hcnt); 447 write32(bus->registers + PCH_IC_FS_SCL_LCNT, bus->fs_lcnt); 448 if (bus->hs_hcnt > 0) 449 write32(bus->registers + PCH_IC_HS_SCL_HCNT, bus->hs_hcnt); 450 if (bus->hs_lcnt > 0) 451 write32(bus->registers + PCH_IC_HS_SCL_LCNT, bus->hs_lcnt); 452 { 453 uint32 reg = read32(bus->registers + PCH_IC_COMP_VERSION); 454 if (reg >= PCH_IC_COMP_VERSION_MIN) 455 write32(bus->registers + PCH_IC_SDA_HOLD, bus->sda_hold_time); 456 } 457 458 { 459 bus->tx_fifo_depth = 32; 460 bus->rx_fifo_depth = 32; 461 uint32 reg = read32(bus->registers + PCH_IC_COMP_PARAM1); 462 uint8 rx_fifo_depth = PCH_IC_COMP_PARAM1_RX(reg); 463 uint8 tx_fifo_depth = PCH_IC_COMP_PARAM1_TX(reg); 464 if (rx_fifo_depth > 1 && rx_fifo_depth < bus->rx_fifo_depth) 465 bus->rx_fifo_depth = rx_fifo_depth; 466 if (tx_fifo_depth > 1 && tx_fifo_depth < bus->tx_fifo_depth) 467 bus->tx_fifo_depth = tx_fifo_depth; 468 write32(bus->registers + PCH_IC_RX_TL, 0); 469 write32(bus->registers + PCH_IC_TX_TL, bus->tx_fifo_depth / 2); 470 } 471 472 bus->masterConfig = PCH_IC_CON_MASTER | PCH_IC_CON_SLAVE_DISABLE | 473 PCH_IC_CON_RESTART_EN | PCH_IC_CON_SPEED_FAST; 474 write32(bus->registers + PCH_IC_CON, bus->masterConfig); 475 476 write32(bus->registers + PCH_IC_INTR_MASK, 0); 477 read32(bus->registers + PCH_IC_CLR_INTR); 478 479 status = install_io_interrupt_handler(bus->irq, 480 (interrupt_handler)pch_i2c_interrupt_handler, bus, 0); 481 if (status != B_OK) { 482 ERROR("install interrupt handler failed\n"); 483 goto err; 484 } 485 486 mutex_init(&bus->lock, "pch_i2c"); 487 *bus_cookie = bus; 488 return status; 489 490 err: 491 if (bus->registersArea >= 0) 492 delete_area(bus->registersArea); 493 return status; 494 } 495 496 497 static void 498 uninit_bus(void* bus_cookie) 499 { 500 pch_i2c_sim_info* bus = (pch_i2c_sim_info*)bus_cookie; 501 502 mutex_destroy(&bus->lock); 503 remove_io_interrupt_handler(bus->irq, 504 (interrupt_handler)pch_i2c_interrupt_handler, bus); 505 if (bus->registersArea >= 0) 506 delete_area(bus->registersArea); 507 508 } 509 510 511 // #pragma mark - 512 513 514 module_dependency module_dependencies[] = { 515 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, 516 { B_ACPI_MODULE_NAME, (module_info**)&gACPI }, 517 { I2C_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gI2c }, 518 {} 519 }; 520 521 522 static i2c_sim_interface sPchI2cDeviceModule = { 523 { 524 { 525 PCH_I2C_SIM_MODULE_NAME, 526 0, 527 NULL 528 }, 529 530 NULL, // supports device 531 NULL, // register device 532 init_bus, 533 uninit_bus, 534 NULL, // register child devices 535 NULL, // rescan 536 NULL, // device removed 537 }, 538 539 set_sim, 540 exec_command, 541 scan_bus, 542 acquire_bus, 543 release_bus, 544 }; 545 546 547 module_info* modules[] = { 548 (module_info* )&gPchI2cAcpiDevice, 549 (module_info* )&gPchI2cPciDevice, 550 (module_info* )&sPchI2cDeviceModule, 551 NULL 552 }; 553