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