commonlib/device_tree.c: Add read reg property helper

Add a helper function to read the reg property from an unflattened
device tree.
It also factors out the common code into a new function called
`read_reg_prop`.

Signed-off-by: Maximilian Brune <maximilian.brune@9elements.com>
Change-Id: I7846eb8af390d709b0757262025cb819e9988699
Reviewed-on: https://review.coreboot.org/c/coreboot/+/83457
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
Maximilian Brune
2024-07-13 23:53:48 +02:00
committed by Lean Sheng Tan
parent 2c9a12b588
commit 7dae497495
2 changed files with 73 additions and 26 deletions

View File

@@ -59,10 +59,49 @@ static struct device_tree_property *alloc_prop(void)
return xzalloc(sizeof(struct device_tree_property));
}
/*
* internal functions used by both unflattened and flattened device tree variants
*/
static size_t read_reg_prop(struct fdt_property *prop, u32 addr_cells, u32 size_cells,
struct device_tree_region regions[], size_t regions_count)
{
// we found the reg property, no need to parse all regions in 'reg'
size_t count = prop->size / (4 * addr_cells + 4 * size_cells);
if (count > regions_count) {
printk(BIOS_ERR, "reg property has more entries (%zd) than regions array can hold (%zd)\n", count, regions_count);
count = regions_count;
}
if (addr_cells > 2 || size_cells > 2) {
printk(BIOS_ERR, "addr_cells (%d) or size_cells (%d) bigger than 2\n",
addr_cells, size_cells);
return 0;
}
uint32_t *ptr = prop->data;
for (int i = 0; i < count; i++) {
if (addr_cells == 1)
regions[i].addr = be32dec(ptr);
else if (addr_cells == 2)
regions[i].addr = be64dec(ptr);
ptr += addr_cells;
if (size_cells == 1)
regions[i].size = be32dec(ptr);
else if (size_cells == 2)
regions[i].size = be64dec(ptr);
ptr += size_cells;
}
return count; // return the number of regions found in the reg property
}
/*
* Functions for picking apart flattened trees.
*/
static int fdt_skip_nops(const void *blob, uint32_t offset)
{
uint32_t *ptr = (uint32_t *)(((uint8_t *)blob) + offset);
@@ -203,32 +242,7 @@ u32 fdt_read_reg_prop(const void *blob, u32 node_offset, u32 addr_cells, u32 siz
return 0;
}
// we found the reg property, now need to parse all regions in 'reg'
size_t count = prop.size / (4 * addr_cells + 4 * size_cells);
if (count > regions_count) {
printk(BIOS_ERR, "reg property at node_offset: %x has more entries (%zd) than regions array can hold (%zd)\n", node_offset, count, regions_count);
count = regions_count;
}
if (addr_cells > 2 || size_cells > 2) {
printk(BIOS_ERR, "addr_cells (%d) or size_cells (%d) bigger than 2\n",
addr_cells, size_cells);
return 0;
}
uint32_t *ptr = prop.data;
for (int i = 0; i < count; i++) {
if (addr_cells == 1)
regions[i].addr = be32dec(ptr);
else if (addr_cells == 2)
regions[i].addr = be64dec(ptr);
ptr += addr_cells;
if (size_cells == 1)
regions[i].size = be32dec(ptr);
else if (size_cells == 2)
regions[i].size = be64dec(ptr);
ptr += size_cells;
}
return count; // return the number of regions found in the reg property
return read_reg_prop(&prop, addr_cells, size_cells, regions, regions_count);
}
static u32 fdt_read_cell_props(const void *blob, u32 node_offset, u32 *addrcp, u32 *sizecp)
@@ -980,6 +994,37 @@ void dt_print_node(const struct device_tree_node *node)
* Functions for reading and manipulating an unflattened device tree.
*/
/*
* dt_read_reg_prop reads the reg property inside a node
*
* @params node device tree node to read reg property from
* @params addr_cells number of cells used for one address
* @params size_cells number of cells used for one size
* @params regions all regions that are read inside the reg property are saved inside
* this array
* @params regions_count maximum number of entries that can be saved inside the regions array.
*
* Returns: Either 0 on error or returns the number of regions put into the regions array.
*/
size_t dt_read_reg_prop(struct device_tree_node *node, u32 addr_cells, u32 size_cells,
struct device_tree_region regions[], size_t regions_count)
{
struct device_tree_property *prop;
bool found = false;
list_for_each(prop, node->properties, list_node) {
if (!strcmp("reg", prop->prop.name)) {
found = true;
break;
}
}
if (!found) {
printk(BIOS_DEBUG, "no reg property found\n");
return 0;
}
return read_reg_prop(&prop->prop, addr_cells, size_cells, regions, regions_count);
}
/*
* Read #address-cells and #size-cells properties from a node.
*

View File

@@ -147,6 +147,8 @@ uint32_t dt_flat_size(const struct device_tree *tree);
/* Flatten a device tree into the buffer pointed to by dest. */
void dt_flatten(const struct device_tree *tree, void *dest);
void dt_print_node(const struct device_tree_node *node);
size_t dt_read_reg_prop(struct device_tree_node *node, u32 addr_cells, u32 size_cells,
struct device_tree_region regions[], size_t regions_count);
/* Read #address-cells and #size-cells properties from a node. */
void dt_read_cell_props(const struct device_tree_node *node, u32 *addrcp,
u32 *sizecp);