arm64: discover PCI from FDT

see:
https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt

Change-Id: I0c35de0c0e08ab04a00101cb3a60df283c685e7f
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5559
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: John Scipione <[email protected]>
Reviewed-by: David Karoly <[email protected]>
This commit is contained in:
David Karoly
2022-08-21 17:31:04 +00:00
parent bf4748d695
commit 1ef08da5a0
2 changed files with 83 additions and 0 deletions
@@ -16,6 +16,7 @@
#include <ACPI.h> // module
#include <acpi.h>
#include <drivers/bus/FDT.h>
#include "acpi_irq_routing_table.h"
@@ -120,6 +121,79 @@ pci_controller_init(void)
if (gDeviceManager->get_attr_string(parent.Get(), B_DEVICE_BUS, &bus, false) < B_OK)
return B_ERROR;
if (strcmp(bus, "fdt") == 0) {
dprintf("initialize PCI controller from FDT\n");
status_t res;
fdt_device_module_info* parentModule;
fdt_device* parentDev;
res = gDeviceManager->get_driver(parent.Get(),
(driver_module_info**)&parentModule, (void**)&parentDev);
if (res != B_OK) {
dprintf("can't get parent node driver\n");
return B_ERROR;
}
uint64 configRegs = 0;
uint64 configRegsLen = 0;
parentModule->get_reg(parentDev, 0, &configRegs, &configRegsLen);
dprintf(" configRegs: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n",
configRegs, configRegsLen);
area_id area = map_physical_memory("pci config",
configRegs, configRegsLen, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gPCIeBase);
if (area < 0)
return B_ERROR;
sRanges = new Vector<PciRange>();
int rangesLen;
const void* rangesAddr = parentModule->get_prop(parentDev, "ranges",
&rangesLen);
if (rangesAddr == NULL) {
dprintf(" ranges property not found\n");
return B_ERROR;
}
for (uint32_t *it = (uint32_t*)rangesAddr;
(uint8_t*)it - (uint8_t*)rangesAddr < rangesLen; it += 7) {
uint32_t kind = B_BENDIAN_TO_HOST_INT32(*(it + 0));
uint64_t childAddr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 1));
uint64_t parentAddr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 3));
uint64_t len = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 5));
PciRange range;
range.type = ((kind & 0x03000000) == 0x01000000) ? RANGE_IO : RANGE_MEM;
range.hostAddr = parentAddr;
range.pciAddr = childAddr;
range.length = len;
sRanges->PushBack(range);
if ((kind & 0x03000000) != 0x01000000)
continue;
dprintf(" (0x%08" B_PRIx32 "): ", kind);
dprintf("child: %08" B_PRIx64, childAddr);
dprintf(", parent: %08" B_PRIx64, parentAddr);
dprintf(", len: %" B_PRIx64 "\n", len);
area_id area = map_physical_memory("pci io",
parentAddr, len, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gPCIioBase);
if (area < 0)
return B_ERROR;
}
gStartBusNumber = 0;
gEndBusNumber = 0xff;
return pci_controller_add(&pci_controller_ecam, NULL);
}
if (strcmp(bus, "acpi") == 0) {
dprintf("initialize PCI controller from ACPI\n");
@@ -43,6 +43,15 @@ pci_root_supports_device(device_node* parent)
}
}
#elif defined(__aarch64__)
if (strcmp(bus, "fdt") == 0) {
const char* compatible;
if (gDeviceManager->get_attr_string(parent, "fdt/compatible", &compatible, false) < B_OK)
return -1.0f;
if (strcmp(compatible, "pci-host-ecam-generic") == 0)
return 1.0f;
}
if (strcmp(bus, "acpi") == 0) {
const char* hid;
if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid, false) < B_OK)