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 typedef struct { 22 pch_i2c_sim_info info; 23 pci_device_module_info* pci; 24 pci_device* device; 25 pch_i2c_irq_type irq_type; 26 27 pci_info pciinfo; 28 } pch_i2c_pci_sim_info; 29 30 31 static pci_x86_module_info* sPCIx86Module; 32 33 34 // #pragma mark - 35 36 37 static status_t 38 pci_scan_bus(i2c_bus_cookie cookie) 39 { 40 CALLED(); 41 pch_i2c_pci_sim_info* bus = (pch_i2c_pci_sim_info*)cookie; 42 device_node *acpiNode = NULL; 43 44 pci_info *pciInfo = &bus->pciinfo; 45 46 // search ACPI I2C nodes for this device 47 { 48 device_node* deviceRoot = gDeviceManager->get_root_node(); 49 uint32 addr = (pciInfo->device << 16) | pciInfo->function; 50 device_attr acpiAttrs[] = { 51 { B_DEVICE_BUS, B_STRING_TYPE, { .string = "acpi" }}, 52 { ACPI_DEVICE_ADDR_ITEM, B_UINT32_TYPE, {.ui32 = addr}}, 53 { NULL } 54 }; 55 if (addr != 0 && gDeviceManager->find_child_node(deviceRoot, acpiAttrs, 56 &acpiNode) != B_OK) { 57 ERROR("init_bus() acpi device not found\n"); 58 return B_DEV_CONFIGURATION_ERROR; 59 } 60 } 61 62 TRACE("init_bus() find_child_node() found %x %x %p\n", 63 pciInfo->device, pciInfo->function, acpiNode); 64 // TODO eventually check timings on acpi 65 acpi_device_module_info *acpi; 66 acpi_device acpiDevice; 67 if (gDeviceManager->get_driver(acpiNode, (driver_module_info **)&acpi, 68 (void **)&acpiDevice) == B_OK) { 69 // find out I2C device nodes 70 acpi->walk_namespace(acpiDevice, ACPI_TYPE_DEVICE, 1, 71 pch_i2c_scan_bus_callback, NULL, bus, NULL); 72 } 73 74 return B_OK; 75 } 76 77 78 static status_t 79 register_child_devices(void* cookie) 80 { 81 CALLED(); 82 83 pch_i2c_pci_sim_info* bus = (pch_i2c_pci_sim_info*)cookie; 84 device_node* node = bus->info.driver_node; 85 86 char prettyName[25]; 87 sprintf(prettyName, "PCH I2C Controller %" B_PRIu16, 0); 88 89 device_attr attrs[] = { 90 // properties of this controller for i2c bus manager 91 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, 92 { .string = prettyName }}, 93 { B_DEVICE_FIXED_CHILD, B_STRING_TYPE, 94 { .string = I2C_FOR_CONTROLLER_MODULE_NAME }}, 95 96 // private data to identify the device 97 { NULL } 98 }; 99 100 return gDeviceManager->register_node(node, PCH_I2C_SIM_MODULE_NAME, 101 attrs, NULL, NULL); 102 } 103 104 105 static status_t 106 init_device(device_node* node, void** device_cookie) 107 { 108 CALLED(); 109 status_t status = B_OK; 110 111 pch_i2c_pci_sim_info* bus = (pch_i2c_pci_sim_info*)calloc(1, 112 sizeof(pch_i2c_pci_sim_info)); 113 if (bus == NULL) 114 return B_NO_MEMORY; 115 116 pci_device_module_info* pci; 117 pci_device* device; 118 { 119 device_node* pciParent = gDeviceManager->get_parent_node(node); 120 gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci, 121 (void**)&device); 122 gDeviceManager->put_node(pciParent); 123 } 124 125 bus->pci = pci; 126 bus->device = device; 127 bus->info.driver_node = node; 128 bus->info.scan_bus = pci_scan_bus; 129 130 pci_info *pciInfo = &bus->pciinfo; 131 pci->get_pci_info(device, pciInfo); 132 133 bus->info.base_addr = pciInfo->u.h0.base_registers[0]; 134 bus->info.map_size = pciInfo->u.h0.base_register_sizes[0]; 135 if ((pciInfo->u.h0.base_register_flags[0] & PCI_address_type) 136 == PCI_address_type_64) { 137 bus->info.base_addr |= (uint64)pciInfo->u.h0.base_registers[1] << 32; 138 bus->info.map_size |= (uint64)pciInfo->u.h0.base_register_sizes[1] << 32; 139 } 140 141 if (bus->info.base_addr == 0) { 142 ERROR("PCI BAR not assigned\n"); 143 free(bus); 144 return B_ERROR; 145 } 146 147 // enable power 148 pci->set_powerstate(device, PCI_pm_state_d0); 149 150 // enable bus master and memory 151 uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2); 152 pcicmd |= PCI_command_master | PCI_command_memory; 153 pci->write_pci_config(device, PCI_command, 2, pcicmd); 154 155 if (get_module(B_PCI_X86_MODULE_NAME, (module_info**)&sPCIx86Module) 156 != B_OK) { 157 sPCIx86Module = NULL; 158 } 159 160 if (sPCIx86Module != NULL) { 161 // try MSI-X 162 uint8 msixCount = sPCIx86Module->get_msix_count( 163 pciInfo->bus, pciInfo->device, pciInfo->function); 164 if (msixCount >= 1) { 165 uint8 vector; 166 if (sPCIx86Module->configure_msix(pciInfo->bus, pciInfo->device, 167 pciInfo->function, 1, &vector) == B_OK 168 && sPCIx86Module->enable_msix(pciInfo->bus, pciInfo->device, 169 pciInfo->function) == B_OK) { 170 TRACE_ALWAYS("using MSI-X vector %u\n", vector); 171 bus->info.irq = vector; 172 bus->irq_type = PCH_I2C_IRQ_MSI_X_SHARED; 173 } else { 174 ERROR("couldn't use MSI-X SHARED\n"); 175 } 176 } else if (sPCIx86Module->get_msi_count( 177 pciInfo->bus, pciInfo->device, pciInfo->function) >= 1) { 178 // try MSI 179 uint8 vector; 180 if (sPCIx86Module->configure_msi(pciInfo->bus, pciInfo->device, 181 pciInfo->function, 1, &vector) == B_OK 182 && sPCIx86Module->enable_msi(pciInfo->bus, pciInfo->device, 183 pciInfo->function) == B_OK) { 184 TRACE_ALWAYS("using MSI vector %u\n", vector); 185 bus->info.irq = vector; 186 bus->irq_type = PCH_I2C_IRQ_MSI; 187 } else { 188 ERROR("couldn't use MSI\n"); 189 } 190 } 191 } 192 if (bus->irq_type == PCH_I2C_IRQ_LEGACY) { 193 bus->info.irq = pciInfo->u.h0.interrupt_line; 194 TRACE_ALWAYS("using legacy interrupt %u\n", bus->info.irq); 195 } 196 if (bus->info.irq == 0 || bus->info.irq == 0xff) { 197 ERROR("PCI IRQ not assigned\n"); 198 status = B_ERROR; 199 goto err; 200 } 201 202 *device_cookie = bus; 203 return B_OK; 204 205 err: 206 free(bus); 207 return status; 208 } 209 210 211 static void 212 uninit_device(void* device_cookie) 213 { 214 pch_i2c_pci_sim_info* bus = (pch_i2c_pci_sim_info*)device_cookie; 215 if (bus->irq_type != PCH_I2C_IRQ_LEGACY) { 216 if (sPCIx86Module != NULL) { 217 sPCIx86Module->disable_msi(bus->pciinfo.bus, 218 bus->pciinfo.device, bus->pciinfo.function); 219 sPCIx86Module->unconfigure_msi(bus->pciinfo.bus, 220 bus->pciinfo.device, bus->pciinfo.function); 221 } 222 } 223 if (sPCIx86Module != NULL) { 224 put_module(B_PCI_X86_MODULE_NAME); 225 sPCIx86Module = NULL; 226 } 227 free(bus); 228 } 229 230 231 static status_t 232 register_device(device_node* parent) 233 { 234 device_attr attrs[] = { 235 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "PCH I2C PCI"}}, 236 {} 237 }; 238 239 return gDeviceManager->register_node(parent, 240 PCH_I2C_PCI_DEVICE_MODULE_NAME, attrs, NULL, NULL); 241 } 242 243 244 static float 245 supports_device(device_node* parent) 246 { 247 CALLED(); 248 const char* bus; 249 uint16 vendorID, deviceID; 250 251 // make sure parent is a PCH I2C PCI device node 252 if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) 253 < B_OK || gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID, 254 &vendorID, false) < B_OK 255 || gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID, 256 false) < B_OK) { 257 return -1; 258 } 259 260 if (strcmp(bus, "pci") != 0) 261 return 0.0f; 262 263 if (vendorID == 0x8086) { 264 switch (deviceID) { 265 case 0x02c5: 266 case 0x02c6: 267 case 0x02e8: 268 case 0x02e9: 269 case 0x02ea: 270 case 0x02eb: 271 case 0x06e8: 272 case 0x06e9: 273 case 0x06ea: 274 case 0x06eb: 275 case 0x0aac: 276 case 0x0aae: 277 case 0x0ab0: 278 case 0x0ab2: 279 case 0x0ab4: 280 case 0x0ab6: 281 case 0x0ab8: 282 case 0x0aba: 283 case 0x1aac: 284 case 0x1aae: 285 286 case 0x1ab0: 287 case 0x1ab2: 288 case 0x1ab4: 289 case 0x1ab6: 290 case 0x1ab8: 291 case 0x1aba: 292 293 case 0x31ac: 294 case 0x31ae: 295 case 0x31b0: 296 case 0x31b2: 297 case 0x31b4: 298 case 0x31b6: 299 case 0x31b8: 300 case 0x31ba: 301 302 case 0x34c5: 303 case 0x34c6: 304 case 0x34e8: 305 case 0x34e9: 306 case 0x34ea: 307 case 0x34eb: 308 309 case 0x43ad: 310 case 0x43ae: 311 case 0x43d8: 312 313 case 0x43e8: 314 case 0x43e9: 315 case 0x43ea: 316 case 0x43eb: 317 318 case 0x4b44: 319 case 0x4b45: 320 case 0x4b4b: 321 case 0x4b4c: 322 case 0x4b78: 323 case 0x4b79: 324 case 0x4b7a: 325 case 0x4b7b: 326 327 case 0x4dc5: 328 case 0x4dc6: 329 case 0x4de8: 330 case 0x4de9: 331 case 0x4dea: 332 case 0x4deb: 333 334 case 0x51c5: 335 case 0x51c6: 336 case 0x51d8: 337 case 0x51d9: 338 case 0x51e8: 339 case 0x51e9: 340 case 0x51ea: 341 case 0x51eb: 342 343 case 0x54c5: 344 case 0x54c6: 345 case 0x54e8: 346 case 0x54e9: 347 case 0x54ea: 348 case 0x54eb: 349 350 case 0x5aac: 351 case 0x5aae: 352 case 0x5ab0: 353 case 0x5ab2: 354 case 0x5ab4: 355 case 0x5ab6: 356 case 0x5ab8: 357 case 0x5aba: 358 359 case 0x7a4c: 360 case 0x7a4d: 361 case 0x7a4e: 362 case 0x7a4f: 363 case 0x7a7c: 364 case 0x7a7d: 365 366 case 0x7acc: 367 case 0x7acd: 368 case 0x7ace: 369 case 0x7acf: 370 case 0x7afc: 371 case 0x7afd: 372 373 case 0x7e50: 374 case 0x7e51: 375 case 0x7e78: 376 case 0x7e79: 377 case 0x7e7a: 378 case 0x7e7b: 379 380 case 0x98c5: 381 case 0x98c6: 382 case 0x98e8: 383 case 0x98e9: 384 case 0x98ea: 385 case 0x98eb: 386 387 case 0x9d60: 388 case 0x9d61: 389 case 0x9d62: 390 case 0x9d63: 391 case 0x9d64: 392 case 0x9d65: 393 394 case 0x9dc5: 395 case 0x9dc6: 396 case 0x9de8: 397 case 0x9de9: 398 case 0x9dea: 399 case 0x9deb: 400 401 case 0xa0c5: 402 case 0xa0c6: 403 case 0xa0d8: 404 case 0xa0d9: 405 case 0xa0e8: 406 case 0xa0e9: 407 case 0xa0ea: 408 case 0xa0eb: 409 410 case 0xa160: 411 case 0xa161: 412 case 0xa162: 413 414 case 0xa2e0: 415 case 0xa2e1: 416 case 0xa2e2: 417 case 0xa2e3: 418 419 case 0xa368: 420 case 0xa369: 421 case 0xa36a: 422 case 0xa36b: 423 424 case 0xa3e0: 425 case 0xa3e1: 426 case 0xa3e2: 427 case 0xa3e3: 428 break; 429 default: 430 return 0.0f; 431 } 432 pci_device_module_info* pci; 433 pci_device* device; 434 gDeviceManager->get_driver(parent, (driver_module_info**)&pci, 435 (void**)&device); 436 #ifdef TRACE_PCH_I2C 437 uint8 pciSubDeviceId = pci->read_pci_config(device, PCI_revision, 438 1); 439 440 TRACE("PCH I2C device found! vendor 0x%04x, device 0x%04x, subdevice 0x%02x\n", vendorID, 441 deviceID, pciSubDeviceId); 442 #endif 443 return 0.8f; 444 } 445 446 return 0.0f; 447 } 448 449 450 // #pragma mark - 451 452 453 driver_module_info gPchI2cPciDevice = { 454 { 455 PCH_I2C_PCI_DEVICE_MODULE_NAME, 456 0, 457 NULL 458 }, 459 460 supports_device, 461 register_device, 462 init_device, 463 uninit_device, 464 register_child_devices, 465 NULL, // rescan 466 NULL, // device removed 467 }; 468 469