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 uint32 outType = kPciRangeInvalid; 205 switch (type & fdtPciRangeTypeMask) { 206 case fdtPciRangeIoPort: 207 outType = kPciRangeIoPort; 208 break; 209 case fdtPciRangeMmio32Bit: 210 outType = kPciRangeMmio; 211 break; 212 case fdtPciRangeMmio64Bit: 213 outType = kPciRangeMmio + kPciRangeMmio64Bit; 214 break; 215 } 216 if (outType >= kPciRangeMmio && outType < kPciRangeMmioEnd 217 && (fdtPciRangePrefechable & type) != 0) 218 outType += kPciRangeMmioPrefetch; 219 220 if (outType != kPciRangeInvalid) { 221 fResourceRanges[outType].type = outType; 222 fResourceRanges[outType].host_addr = parentAdr; 223 fResourceRanges[outType].pci_addr = childAdr; 224 fResourceRanges[outType].size = len; 225 } 226 227 switch (type & fdtPciRangeTypeMask) { 228 case fdtPciRangeConfig: dprintf("CONFIG"); break; 229 case fdtPciRangeIoPort: dprintf("IOPORT"); break; 230 case fdtPciRangeMmio32Bit: dprintf("MMIO32"); break; 231 case fdtPciRangeMmio64Bit: dprintf("MMIO64"); break; 232 } 233 234 dprintf(" (0x%08" B_PRIx32 "): ", type); 235 dprintf("child: %08" B_PRIx64, childAdr); 236 dprintf(", parent: %08" B_PRIx64, parentAdr); 237 dprintf(", len: %" B_PRIx64 "\n", len); 238 } 239 return B_OK; 240 } 241 242 243 status_t 244 DWPCIController::InitDriverInt(device_node* node) 245 { 246 fNode = node; 247 dprintf("+DWPCIController::InitDriver()\n"); 248 249 CHECK_RET(ReadResourceInfo()); 250 251 DeviceNodePutter<&gDeviceManager> fdtNode(gDeviceManager->get_parent_node(node)); 252 253 fdt_device_module_info *fdtModule; 254 fdt_device* fdtDev; 255 CHECK_RET(gDeviceManager->get_driver(fdtNode.Get(), 256 (driver_module_info**)&fdtModule, (void**)&fdtDev)); 257 258 if (!fdtModule->get_reg(fdtDev, 0, &fDbiPhysBase, &fDbiSize)) 259 return B_ERROR; 260 dprintf(" DBI: %08" B_PRIx64 ", %08" B_PRIx64 "\n", fDbiPhysBase, fDbiSize); 261 262 if (!fdtModule->get_reg(fdtDev, 1, &fConfigPhysBase, &fConfigSize)) 263 return B_ERROR; 264 dprintf(" config: %08" B_PRIx64 ", %08" B_PRIx64 "\n", fConfigPhysBase, fConfigSize); 265 266 uint64 msiIrq; 267 if (!fdtModule->get_interrupt(fdtDev, 0, NULL, &msiIrq)) 268 return B_ERROR; 269 270 fDbiArea.SetTo(map_physical_memory("PCI DBI MMIO", fDbiPhysBase, fDbiSize, B_ANY_KERNEL_ADDRESS, 271 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&fDbiBase)); 272 CHECK_RET(fDbiArea.Get()); 273 274 fConfigArea.SetTo(map_physical_memory("PCI Config MMIO", fConfigPhysBase, fConfigSize, 275 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&fConfigBase)); 276 CHECK_RET(fConfigArea.Get()); 277 278 CHECK_RET(fIrqCtrl.Init(GetDbuRegs(), msiIrq)); 279 280 AtuDump(); 281 282 dprintf("-DWPCIController::InitDriver()\n"); 283 return B_OK; 284 } 285 286 287 void 288 DWPCIController::UninitDriver() 289 { 290 delete this; 291 } 292 293 294 addr_t 295 DWPCIController::ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset) 296 { 297 uint32 atuType; 298 if (bus == 0) { 299 if (device != 0 || function != 0) 300 return 0; 301 return fDbiBase + offset; 302 } else if (bus == 1) 303 atuType = kPciAtuTypeCfg0; 304 else 305 atuType = kPciAtuTypeCfg1; 306 307 uint64 address = (uint64)(PciAddress { 308 .function = function, 309 .device = device, 310 .bus = bus 311 }.val) << 8; 312 313 status_t res = AtuMap(1, kPciAtuOutbound, atuType, fConfigPhysBase, address, fConfigSize); 314 if (res < B_OK) 315 return 0; 316 317 return fConfigBase + offset; 318 } 319 320 321 //#pragma mark - PCI controller 322 323 324 status_t 325 DWPCIController::ReadConfig(uint8 bus, uint8 device, uint8 function, 326 uint16 offset, uint8 size, uint32& value) 327 { 328 InterruptsSpinLocker lock(fLock); 329 330 addr_t address = ConfigAddress(bus, device, function, offset); 331 if (address == 0) 332 return B_ERROR; 333 334 switch (size) { 335 case 1: value = ReadReg8(address); break; 336 case 2: value = ReadReg16(address); break; 337 case 4: value = *(vuint32*)address; break; 338 default: 339 return B_ERROR; 340 } 341 342 return B_OK; 343 } 344 345 346 status_t 347 DWPCIController::WriteConfig(uint8 bus, uint8 device, uint8 function, 348 uint16 offset, uint8 size, uint32 value) 349 { 350 InterruptsSpinLocker lock(fLock); 351 352 addr_t address = ConfigAddress(bus, device, function, offset); 353 if (address == 0) 354 return B_ERROR; 355 356 switch (size) { 357 case 1: WriteReg8(address, value); break; 358 case 2: WriteReg16(address, value); break; 359 case 4: *(vuint32*)address = value; break; 360 default: 361 return B_ERROR; 362 } 363 364 return B_OK; 365 } 366 367 368 status_t 369 DWPCIController::GetMaxBusDevices(int32& count) 370 { 371 count = 32; 372 return B_OK; 373 } 374 375 376 status_t 377 DWPCIController::ReadIrq(uint8 bus, uint8 device, uint8 function, 378 uint8 pin, uint8& irq) 379 { 380 return B_UNSUPPORTED; 381 } 382 383 384 status_t 385 DWPCIController::WriteIrq(uint8 bus, uint8 device, uint8 function, 386 uint8 pin, uint8 irq) 387 { 388 return B_UNSUPPORTED; 389 } 390 391 392 status_t 393 DWPCIController::GetRange(uint32 index, pci_resource_range* range) 394 { 395 if (index >= kPciRangeEnd) 396 return B_BAD_INDEX; 397 398 *range = fResourceRanges[index]; 399 return B_OK; 400 } 401 402 403 //#pragma mark - DWPCIController 404 405 406 status_t 407 DWPCIController::AtuMap(uint32 index, uint32 direction, uint32 type, uint64 parentAdr, 408 uint64 childAdr, uint32 size) 409 { 410 /* 411 dprintf("AtuMap(%" B_PRIu32 ", %" B_PRIu32 ", %#" B_PRIx64 ", %#" B_PRIx64 ", " 412 "%#" B_PRIx32 ")\n", index, type, parentAdr, childAdr, size); 413 */ 414 volatile PciAtuRegs* atu = (PciAtuRegs*)(fDbiBase + kPciAtuOffset 415 + (2 * index + direction) * sizeof(PciAtuRegs)); 416 417 atu->baseLo = (uint32)parentAdr; 418 atu->baseHi = (uint32)(parentAdr >> 32); 419 atu->limit = (uint32)(parentAdr + size - 1); 420 atu->targetLo = (uint32)childAdr; 421 atu->targetHi = (uint32)(childAdr >> 32); 422 atu->ctrl1 = type; 423 atu->ctrl2 = kPciAtuEnable; 424 425 for (;;) { 426 if ((atu->ctrl2 & kPciAtuEnable) != 0) 427 break; 428 } 429 430 return B_OK; 431 } 432 433 434 void 435 DWPCIController::AtuDump() 436 { 437 dprintf("ATU:\n"); 438 for (uint32 direction = 0; direction < 2; direction++) { 439 switch (direction) { 440 case kPciAtuOutbound: 441 dprintf(" outbound:\n"); 442 break; 443 case kPciAtuInbound: 444 dprintf(" inbound:\n"); 445 break; 446 } 447 448 for (uint32 index = 0; index < 8; index++) { 449 volatile PciAtuRegs* atu = (PciAtuRegs*)(fDbiBase 450 + kPciAtuOffset + (2 * index + direction) * sizeof(PciAtuRegs)); 451 452 dprintf(" %" B_PRIu32 ": ", index); 453 dprintf("base: %#08" B_PRIx64, atu->baseLo + ((uint64)atu->baseHi << 32)); 454 dprintf(", limit: %#08" B_PRIx32, atu->limit); 455 dprintf(", target: %#08" B_PRIx64, atu->targetLo 456 + ((uint64)atu->targetHi << 32)); 457 dprintf(", ctrl1: "); 458 uint32 ctrl1 = atu->ctrl1; 459 switch (ctrl1) { 460 case kPciAtuTypeMem: 461 dprintf("mem"); 462 break; 463 case kPciAtuTypeIo: 464 dprintf("io"); 465 break; 466 case kPciAtuTypeCfg0: 467 dprintf("cfg0"); 468 break; 469 case kPciAtuTypeCfg1: 470 dprintf("cfg1"); 471 break; 472 default: 473 dprintf("? (%#" B_PRIx32 ")", ctrl1); 474 } 475 dprintf(", ctrl2: {"); 476 uint32 ctrl2 = atu->ctrl2; 477 bool first = true; 478 for (uint32 i = 0; i < 32; i++) { 479 if (((1 << i) & ctrl2) != 0) { 480 if (first) 481 first = false; 482 else 483 dprintf(", "); 484 switch (i) { 485 case 30: 486 dprintf("barModeEnable"); 487 break; 488 case 31: 489 dprintf("enable"); 490 break; 491 default: 492 dprintf("? (%" B_PRIu32 ")", i); 493 break; 494 } 495 } 496 } 497 dprintf("}\n"); 498 } 499 } 500 } 501