arm/fdt: Add code to navigate FDT.

* This isn't be best long-term place for this code,
  will likely move to some generic FDT support code.
* We pass a path like "/soc/gpio" and get back the
  base physical register address in memory minus
  the range offset.
This commit is contained in:
Alexander von Gluck IV 2015-03-13 23:46:54 -05:00
parent 1a8d852f25
commit 59ef0db249

View File

@ -580,6 +580,43 @@ mmu_init_for_kernel(void)
} }
static status_t
fdt_get_cell_count(int32 pathOffset, int32 &addressCells, int32 &sizeCells)
{
// It would be nice if libfdt provided this.
// Memory base addresses are provided in 32 or 64 bit flavors
// #address-cells and #size-cells matches the number of 32-bit 'cells'
// representing the length of the base address and size fields
// TODO: assert !gFDT || !pathOffset?
int len;
if (!pathOffset) {
TRACE(("%s: Invalid FDT pathOffset provided!\n", __func__));
return B_ERROR;
}
const void *prop;
prop = fdt_getprop(gFDT, pathOffset, "#address-cells", &len);
if (prop && len == sizeof(uint32))
addressCells = fdt32_to_cpu(*(uint32_t *)prop);
prop = fdt_getprop(gFDT, pathOffset, "#size-cells", &len);
if (prop && len == sizeof(uint32))
sizeCells = fdt32_to_cpu(*(uint32_t *)prop);
// NOTE : Cells over 2 is possible in theory...
if (addressCells > 2 || sizeCells > 2) {
panic("%s: Unsupported FDT cell count detected.\n"
"Address Cells: %" B_PRId32 "; Size Cells: %" B_PRId32
" (CPU > 64bit?).\n", __func__, addressCells, sizeCells);
return B_ERROR;
}
return B_OK;
}
//TODO:move this to generic/ ? //TODO:move this to generic/ ?
static status_t static status_t
find_physical_memory_ranges(uint64 &total) find_physical_memory_ranges(uint64 &total)
@ -596,27 +633,9 @@ find_physical_memory_ranges(uint64 &total)
total = 0; total = 0;
// Memory base addresses are provided in 32 or 64 bit flavors
// #address-cells and #size-cells matches the number of 32-bit 'cells'
// representing the length of the base address and size fields
int root = fdt_path_offset(gFDT, "/");
int32 regAddressCells = 1; int32 regAddressCells = 1;
int32 regSizeCells = 1; int32 regSizeCells = 1;
prop = fdt_getprop(gFDT, root, "#address-cells", &len); fdt_get_cell_count(node, regAddressCells, regSizeCells);
if (prop && len == sizeof(uint32))
regAddressCells = fdt32_to_cpu(*(uint32_t *)prop);
prop = fdt_getprop(gFDT, root, "#size-cells", &len);
if (prop && len == sizeof(uint32))
regSizeCells = fdt32_to_cpu(*(uint32_t *)prop);
// NOTE : Size Cells of 2 is possible in theory... but I haven't seen it yet.
if (regAddressCells > 2 || regSizeCells > 1) {
panic("%s: Unsupported FDT cell count detected.\n"
"Address Cells: %" B_PRId32 "; Size Cells: %" B_PRId32
" (CPU > 64bit?).\n", __func__, regAddressCells, regSizeCells);
return B_ERROR;
}
prop = fdt_getprop(gFDT, node, "reg", &len); prop = fdt_getprop(gFDT, node, "reg", &len);
if (prop == NULL) { if (prop == NULL) {
@ -661,6 +680,96 @@ find_physical_memory_ranges(uint64 &total)
} }
static uint64
fdt_get_range_offset(int32 node)
{
int depth = fdt_node_depth(gFDT, node);
int32 examineNode = node;
uint64 pathOffset = 0x0;
while (depth > 0) {
int len;
const void* prop;
prop = fdt_getprop(gFDT, examineNode, "ranges", &len);
if (prop) {
int32 regAddressCells = 1;
int32 regSizeCells = 1;
fdt_get_cell_count(examineNode, regAddressCells, regSizeCells);
const uint32 *p = (const uint32 *)prop;
// soc base address cells
if (regAddressCells == 2)
pathOffset = fdt64_to_cpu(*(uint64_t *)p);
else
pathOffset = fdt32_to_cpu(*(uint32_t *)p);
break;
}
int32 parentNode = fdt_parent_offset(gFDT, examineNode);
depth = fdt_node_depth(gFDT, parentNode);
examineNode = parentNode;
}
dprintf("%s: range offset: 0x%" B_PRIx64 "\n", __func__, pathOffset);
return pathOffset;
}
static status_t
fdt_get_device_base(const char* device)
{
int node;
const void *prop;
int len;
// Find device in FDT
node = fdt_path_offset(gFDT, device);
int32 regAddressCells = 1;
int32 regSizeCells = 1;
fdt_get_cell_count(node, regAddressCells, regSizeCells);
if (node < 0) {
dprintf("%s: %s not found in FDT!\n", __func__, device);
return B_ERROR;
}
prop = fdt_getprop(gFDT, node, "reg", &len);
if (prop < 0) {
dprintf("%s: reg property not found on device %s in FDT!\n", __func__,
device);
return B_ERROR;
}
const uint32 *p = (const uint32 *)prop;
uint64 baseDevice = 0x0;
uint64 size = 0x0;
// soc base address cells
if (regAddressCells == 2)
baseDevice = fdt64_to_cpu(*(uint64_t *)p);
else
baseDevice = fdt32_to_cpu(*(uint32_t *)p);
p += regAddressCells;
// size
if (regSizeCells == 2)
size = fdt64_to_cpu(*(uint64_t *)p);
else if (regSizeCells == 1)
size = fdt32_to_cpu(*(uint32_t *)p);
//p += regSizeCells;
dprintf("%s: before: %" B_PRIx64 "\n", __func__, baseDevice);
baseDevice -= fdt_get_range_offset(node);
dprintf("%s: %s found @ 0x%" B_PRIx64 " , size: 0x%" B_PRIx64 "\n",
__func__, device, baseDevice, size);
return B_OK;
}
extern "C" void extern "C" void
mmu_init(void) mmu_init(void)
{ {
@ -687,6 +796,8 @@ mmu_init(void)
dprintf("total physical memory = %" B_PRId64 "MB\n", total / (1024 * 1024)); dprintf("total physical memory = %" B_PRId64 "MB\n", total / (1024 * 1024));
} }
fdt_get_device_base("/soc/gpio");
// see if subpages are disabled // see if subpages are disabled
if (mmu_read_C1() & (1 << 23)) if (mmu_read_C1() & (1 << 23))
sSmallPageType = ARM_MMU_L2_TYPE_SMALLNEW; sSmallPageType = ARM_MMU_L2_TYPE_SMALLNEW;