1 /* 2 * Copyright 2022, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "DWPCIController.h" 8 #include <bus/FDT.h> 9 10 #include <AutoDeleterDrivers.h> 11 #include <util/AutoLock.h> 12 13 #include <string.h> 14 #include <new> 15 16 17 static uint32 18 ReadReg8(addr_t adr) 19 { 20 uint32 ofs = adr % 4; 21 adr = adr / 4 * 4; 22 union { 23 uint32 in; 24 uint8 out[4]; 25 } val{.in = *(vuint32*)adr}; 26 return val.out[ofs]; 27 } 28 29 30 static uint32 31 ReadReg16(addr_t adr) 32 { 33 uint32 ofs = adr / 2 % 2; 34 adr = adr / 4 * 4; 35 union { 36 uint32 in; 37 uint16 out[2]; 38 } val{.in = *(vuint32*)adr}; 39 return val.out[ofs]; 40 } 41 42 43 static void 44 WriteReg8(addr_t adr, uint32 value) 45 { 46 uint32 ofs = adr % 4; 47 adr = adr / 4 * 4; 48 union { 49 uint32 in; 50 uint8 out[4]; 51 } val{.in = *(vuint32*)adr}; 52 val.out[ofs] = (uint8)value; 53 *(vuint32*)adr = val.in; 54 } 55 56 57 static void 58 WriteReg16(addr_t adr, uint32 value) 59 { 60 uint32 ofs = adr / 2 % 2; 61 adr = adr / 4 * 4; 62 union { 63 uint32 in; 64 uint16 out[2]; 65 } val{.in = *(vuint32*)adr}; 66 val.out[ofs] = (uint16)value; 67 *(vuint32*)adr = val.in; 68 } 69 70 71 //#pragma mark - driver 72 73 74 float 75 DWPCIController::SupportsDevice(device_node* parent) 76 { 77 const char* bus; 78 status_t status = gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false); 79 if (status < B_OK) 80 return -1.0f; 81 82 if (strcmp(bus, "fdt") != 0) 83 return 0.0f; 84 85 const char* compatible; 86 status = gDeviceManager->get_attr_string(parent, "fdt/compatible", &compatible, false); 87 if (status < B_OK) 88 return -1.0f; 89 90 // Support only a variant used in HiFive Unmatched board. 91 // TODO: Support more Synapsis Designware IP core based PCIe host controllers. 92 if (strcmp(compatible, "sifive,fu740-pcie") != 0) 93 return 0.0f; 94 95 return 1.0f; 96 } 97 98 99 status_t 100 DWPCIController::RegisterDevice(device_node* parent) 101 { 102 device_attr attrs[] = { 103 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Designware PCI Host Controller"} }, 104 { B_DEVICE_FIXED_CHILD, B_STRING_TYPE, {.string = "bus_managers/pci/root/driver_v1"} }, 105 {} 106 }; 107 108 return gDeviceManager->register_node(parent, DESIGNWARE_PCI_DRIVER_MODULE_NAME, attrs, NULL, 109 NULL); 110 } 111 112 113 status_t 114 DWPCIController::InitDriver(device_node* node, DWPCIController*& outDriver) 115 { 116 ObjectDeleter<DWPCIController> driver(new(std::nothrow) DWPCIController()); 117 if (!driver.IsSet()) 118 return B_NO_MEMORY; 119 120 CHECK_RET(driver->InitDriverInt(node)); 121 outDriver = driver.Detach(); 122 return B_OK; 123 } 124 125 126 status_t 127 DWPCIController::ReadResourceInfo() 128 { 129 DeviceNodePutter<&gDeviceManager> fdtNode(gDeviceManager->get_parent_node(fNode)); 130 131 const char* bus; 132 CHECK_RET(gDeviceManager->get_attr_string(fdtNode.Get(), B_DEVICE_BUS, &bus, false)); 133 if (strcmp(bus, "fdt") != 0) 134 return B_ERROR; 135 136 fdt_device_module_info *fdtModule; 137 fdt_device* fdtDev; 138 CHECK_RET(gDeviceManager->get_driver(fdtNode.Get(), 139 (driver_module_info**)&fdtModule, (void**)&fdtDev)); 140 141 const void* prop; 142 int propLen; 143 144 prop = fdtModule->get_prop(fdtDev, "bus-range", &propLen); 145 if (prop != NULL && propLen == 8) { 146 uint32 busBeg = B_BENDIAN_TO_HOST_INT32(*((uint32*)prop + 0)); 147 uint32 busEnd = B_BENDIAN_TO_HOST_INT32(*((uint32*)prop + 1)); 148 dprintf(" bus-range: %" B_PRIu32 " - %" B_PRIu32 "\n", busBeg, busEnd); 149 } 150 151 prop = fdtModule->get_prop(fdtDev, "interrupt-map-mask", &propLen); 152 if (prop == NULL || propLen != 4 * 4) { 153 dprintf(" \"interrupt-map-mask\" property not found or invalid"); 154 return B_ERROR; 155 } 156 fInterruptMapMask.childAdr = B_BENDIAN_TO_HOST_INT32(*((uint32*)prop + 0)); 157 fInterruptMapMask.childIrq = B_BENDIAN_TO_HOST_INT32(*((uint32*)prop + 3)); 158 159 prop = fdtModule->get_prop(fdtDev, "interrupt-map", &propLen); 160 fInterruptMapLen = (uint32)propLen / (6 * 4); 161 fInterruptMap.SetTo(new(std::nothrow) InterruptMap[fInterruptMapLen]); 162 if (!fInterruptMap.IsSet()) 163 return B_NO_MEMORY; 164 165 for (uint32_t *it = (uint32_t*)prop; (uint8_t*)it - (uint8_t*)prop < propLen; it += 6) { 166 size_t i = (it - (uint32_t*)prop) / 6; 167 168 fInterruptMap[i].childAdr = B_BENDIAN_TO_HOST_INT32(*(it + 0)); 169 fInterruptMap[i].childIrq = B_BENDIAN_TO_HOST_INT32(*(it + 3)); 170 fInterruptMap[i].parentIrqCtrl = B_BENDIAN_TO_HOST_INT32(*(it + 4)); 171 fInterruptMap[i].parentIrq = B_BENDIAN_TO_HOST_INT32(*(it + 5)); 172 } 173 174 dprintf(" interrupt-map:\n"); 175 for (size_t i = 0; i < fInterruptMapLen; i++) { 176 dprintf(" "); 177 // child unit address 178 PciAddress pciAddress{.val = fInterruptMap[i].childAdr}; 179 dprintf("bus: %" B_PRIu32, pciAddress.bus); 180 dprintf(", dev: %" B_PRIu32, pciAddress.device); 181 dprintf(", fn: %" B_PRIu32, pciAddress.function); 182 183 dprintf(", childIrq: %" B_PRIu32, fInterruptMap[i].childIrq); 184 dprintf(", parentIrq: (%" B_PRIu32, fInterruptMap[i].parentIrqCtrl); 185 dprintf(", %" B_PRIu32, fInterruptMap[i].parentIrq); 186 dprintf(")\n"); 187 if (i % 4 == 3 && (i + 1 < fInterruptMapLen)) 188 dprintf("\n"); 189 } 190 191 prop = fdtModule->get_prop(fdtDev, "ranges", &propLen); 192 if (prop == NULL) { 193 dprintf(" \"ranges\" property not found"); 194 return B_ERROR; 195 } 196 dprintf(" ranges:\n"); 197 for (uint32_t *it = (uint32_t*)prop; (uint8_t*)it - (uint8_t*)prop < propLen; it += 7) { 198 dprintf(" "); 199 uint32_t type = B_BENDIAN_TO_HOST_INT32(*(it + 0)); 200 uint64_t childAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 1)); 201 uint64_t parentAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 3)); 202 uint64_t len = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 5)); 203 204 pci_resource_range range = {}; 205 range.host_address = parentAdr; 206 range.pci_address = childAdr; 207 range.size = len; 208 209 if ((type & fdtPciRangePrefechable) != 0) 210 range.address_type |= PCI_address_prefetchable; 211 212 switch (type & fdtPciRangeTypeMask) { 213 case fdtPciRangeIoPort: 214 range.type = B_IO_PORT; 215 fResourceRanges.Add(range); 216 break; 217 case fdtPciRangeMmio32Bit: 218 range.type = B_IO_MEMORY; 219 range.address_type |= PCI_address_type_32; 220 fResourceRanges.Add(range); 221 break; 222 case fdtPciRangeMmio64Bit: 223 range.type = B_IO_MEMORY; 224 range.address_type |= PCI_address_type_64; 225 fResourceRanges.Add(range); 226 break; 227 } 228 229 switch (type & fdtPciRangeTypeMask) { 230 case fdtPciRangeConfig: dprintf("CONFIG"); break; 231 case fdtPciRangeIoPort: dprintf("IOPORT"); break; 232 case fdtPciRangeMmio32Bit: dprintf("MMIO32"); break; 233 case fdtPciRangeMmio64Bit: dprintf("MMIO64"); break; 234 } 235 236 dprintf(" (0x%08" B_PRIx32 "): ", type); 237 dprintf("child: %08" B_PRIx64, childAdr); 238 dprintf(", parent: %08" B_PRIx64, parentAdr); 239 dprintf(", len: %" B_PRIx64 "\n", len); 240 } 241 return B_OK; 242 } 243 244 245 status_t 246 DWPCIController::InitDriverInt(device_node* node) 247 { 248 fNode = node; 249 dprintf("+DWPCIController::InitDriver()\n"); 250 251 CHECK_RET(ReadResourceInfo()); 252 253 DeviceNodePutter<&gDeviceManager> fdtNode(gDeviceManager->get_parent_node(node)); 254 255 fdt_device_module_info *fdtModule; 256 fdt_device* fdtDev; 257 CHECK_RET(gDeviceManager->get_driver(fdtNode.Get(), 258 (driver_module_info**)&fdtModule, (void**)&fdtDev)); 259 260 if (!fdtModule->get_reg(fdtDev, 0, &fDbiPhysBase, &fDbiSize)) 261 return B_ERROR; 262 dprintf(" DBI: %08" B_PRIx64 ", %08" B_PRIx64 "\n", fDbiPhysBase, fDbiSize); 263 264 if (!fdtModule->get_reg(fdtDev, 1, &fConfigPhysBase, &fConfigSize)) 265 return B_ERROR; 266 dprintf(" config: %08" B_PRIx64 ", %08" B_PRIx64 "\n", fConfigPhysBase, fConfigSize); 267 268 uint64 msiIrq; 269 if (!fdtModule->get_interrupt(fdtDev, 0, NULL, &msiIrq)) 270 return B_ERROR; 271 272 fDbiArea.SetTo(map_physical_memory("PCI DBI MMIO", fDbiPhysBase, fDbiSize, B_ANY_KERNEL_ADDRESS, 273 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&fDbiBase)); 274 CHECK_RET(fDbiArea.Get()); 275 276 fConfigArea.SetTo(map_physical_memory("PCI Config MMIO", fConfigPhysBase, fConfigSize, 277 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&fConfigBase)); 278 CHECK_RET(fConfigArea.Get()); 279 280 CHECK_RET(fIrqCtrl.Init(GetDbuRegs(), msiIrq)); 281 282 AtuDump(); 283 284 dprintf("-DWPCIController::InitDriver()\n"); 285 return B_OK; 286 } 287 288 289 void 290 DWPCIController::UninitDriver() 291 { 292 delete this; 293 } 294 295 296 addr_t 297 DWPCIController::ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset) 298 { 299 uint32 atuType; 300 if (bus == 0) { 301 if (device != 0 || function != 0) 302 return 0; 303 return fDbiBase + offset; 304 } else if (bus == 1) 305 atuType = kPciAtuTypeCfg0; 306 else 307 atuType = kPciAtuTypeCfg1; 308 309 uint64 address = (uint64)(PciAddress { 310 .function = function, 311 .device = device, 312 .bus = bus 313 }.val) << 8; 314 315 status_t res = AtuMap(1, kPciAtuOutbound, atuType, fConfigPhysBase, address, fConfigSize); 316 if (res < B_OK) 317 return 0; 318 319 return fConfigBase + offset; 320 } 321 322 323 //#pragma mark - PCI controller 324 325 326 status_t 327 DWPCIController::ReadConfig(uint8 bus, uint8 device, uint8 function, 328 uint16 offset, uint8 size, uint32& value) 329 { 330 InterruptsSpinLocker lock(fLock); 331 332 addr_t address = ConfigAddress(bus, device, function, offset); 333 if (address == 0) 334 return ERANGE; 335 336 switch (size) { 337 case 1: value = ReadReg8(address); break; 338 case 2: value = ReadReg16(address); break; 339 case 4: value = *(vuint32*)address; break; 340 default: 341 return B_BAD_VALUE; 342 } 343 344 return B_OK; 345 } 346 347 348 status_t 349 DWPCIController::WriteConfig(uint8 bus, uint8 device, uint8 function, 350 uint16 offset, uint8 size, uint32 value) 351 { 352 InterruptsSpinLocker lock(fLock); 353 354 addr_t address = ConfigAddress(bus, device, function, offset); 355 if (address == 0) 356 return ERANGE; 357 358 switch (size) { 359 case 1: WriteReg8(address, value); break; 360 case 2: WriteReg16(address, value); break; 361 case 4: *(vuint32*)address = value; break; 362 default: 363 return B_BAD_VALUE; 364 } 365 366 return B_OK; 367 } 368 369 370 status_t 371 DWPCIController::GetMaxBusDevices(int32& count) 372 { 373 count = 32; 374 return B_OK; 375 } 376 377 378 status_t 379 DWPCIController::ReadIrq(uint8 bus, uint8 device, uint8 function, 380 uint8 pin, uint8& irq) 381 { 382 return B_UNSUPPORTED; 383 } 384 385 386 status_t 387 DWPCIController::WriteIrq(uint8 bus, uint8 device, uint8 function, 388 uint8 pin, uint8 irq) 389 { 390 return B_UNSUPPORTED; 391 } 392 393 394 status_t 395 DWPCIController::GetRange(uint32 index, pci_resource_range* range) 396 { 397 if (index >= (uint32)fResourceRanges.Count()) 398 return B_BAD_INDEX; 399 400 *range = fResourceRanges[index]; 401 return B_OK; 402 } 403 404 405 //#pragma mark - DWPCIController 406 407 408 status_t 409 DWPCIController::AtuMap(uint32 index, uint32 direction, uint32 type, uint64 parentAdr, 410 uint64 childAdr, uint32 size) 411 { 412 /* 413 dprintf("AtuMap(%" B_PRIu32 ", %" B_PRIu32 ", %#" B_PRIx64 ", %#" B_PRIx64 ", " 414 "%#" B_PRIx32 ")\n", index, type, parentAdr, childAdr, size); 415 */ 416 volatile PciAtuRegs* atu = (PciAtuRegs*)(fDbiBase + kPciAtuOffset 417 + (2 * index + direction) * sizeof(PciAtuRegs)); 418 419 atu->baseLo = (uint32)parentAdr; 420 atu->baseHi = (uint32)(parentAdr >> 32); 421 atu->limit = (uint32)(parentAdr + size - 1); 422 atu->targetLo = (uint32)childAdr; 423 atu->targetHi = (uint32)(childAdr >> 32); 424 atu->ctrl1 = type; 425 atu->ctrl2 = kPciAtuEnable; 426 427 for (;;) { 428 if ((atu->ctrl2 & kPciAtuEnable) != 0) 429 break; 430 } 431 432 return B_OK; 433 } 434 435 436 void 437 DWPCIController::AtuDump() 438 { 439 dprintf("ATU:\n"); 440 for (uint32 direction = 0; direction < 2; direction++) { 441 switch (direction) { 442 case kPciAtuOutbound: 443 dprintf(" outbound:\n"); 444 break; 445 case kPciAtuInbound: 446 dprintf(" inbound:\n"); 447 break; 448 } 449 450 for (uint32 index = 0; index < 8; index++) { 451 volatile PciAtuRegs* atu = (PciAtuRegs*)(fDbiBase 452 + kPciAtuOffset + (2 * index + direction) * sizeof(PciAtuRegs)); 453 454 dprintf(" %" B_PRIu32 ": ", index); 455 dprintf("base: %#08" B_PRIx64, atu->baseLo + ((uint64)atu->baseHi << 32)); 456 dprintf(", limit: %#08" B_PRIx32, atu->limit); 457 dprintf(", target: %#08" B_PRIx64, atu->targetLo 458 + ((uint64)atu->targetHi << 32)); 459 dprintf(", ctrl1: "); 460 uint32 ctrl1 = atu->ctrl1; 461 switch (ctrl1) { 462 case kPciAtuTypeMem: 463 dprintf("mem"); 464 break; 465 case kPciAtuTypeIo: 466 dprintf("io"); 467 break; 468 case kPciAtuTypeCfg0: 469 dprintf("cfg0"); 470 break; 471 case kPciAtuTypeCfg1: 472 dprintf("cfg1"); 473 break; 474 default: 475 dprintf("? (%#" B_PRIx32 ")", ctrl1); 476 } 477 dprintf(", ctrl2: {"); 478 uint32 ctrl2 = atu->ctrl2; 479 bool first = true; 480 for (uint32 i = 0; i < 32; i++) { 481 if (((1 << i) & ctrl2) != 0) { 482 if (first) 483 first = false; 484 else 485 dprintf(", "); 486 switch (i) { 487 case 30: 488 dprintf("barModeEnable"); 489 break; 490 case 31: 491 dprintf("enable"); 492 break; 493 default: 494 dprintf("? (%" B_PRIu32 ")", i); 495 break; 496 } 497 } 498 } 499 dprintf("}\n"); 500 } 501 } 502 } 503