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