mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-10 01:34:12 +00:00
d27ca705c1
Signed-off-by: Janne Grunau <j@jannau.net>
69 lines
1.8 KiB
C
69 lines
1.8 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
|
|
#include "devicetree.h"
|
|
|
|
#include "libfdt/libfdt.h"
|
|
|
|
void dt_parse_ranges(void *dt, int node, struct dt_ranges_tbl *ranges)
|
|
{
|
|
int len;
|
|
const struct fdt_property *ranges_prop = fdt_get_property(dt, node, "ranges", &len);
|
|
if (ranges_prop && len > 0) {
|
|
int idx = 0;
|
|
int num_entries = len / sizeof(fdt64_t);
|
|
if (num_entries > DT_MAX_RANGES)
|
|
num_entries = DT_MAX_RANGES;
|
|
|
|
const fdt64_t *entry = (const fdt64_t *)ranges_prop->data;
|
|
for (int i = 0; i < num_entries; ++i) {
|
|
u64 start = fdt64_ld(entry++);
|
|
u64 parent = fdt64_ld(entry++);
|
|
u64 size = fdt64_ld(entry++);
|
|
if (size) {
|
|
ranges[idx].start = start;
|
|
ranges[idx].parent = parent;
|
|
ranges[idx].size = size;
|
|
idx++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
u64 dt_translate(struct dt_ranges_tbl *ranges, const fdt64_t *reg)
|
|
{
|
|
u64 addr = fdt64_ld(reg);
|
|
for (int idx = 0; idx < DT_MAX_RANGES; ++idx) {
|
|
if (ranges[idx].size == 0)
|
|
break;
|
|
if (addr >= ranges[idx].start && addr < ranges[idx].start + ranges[idx].size)
|
|
return ranges[idx].parent - ranges[idx].start + addr;
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
|
|
u64 dt_get_address(void *dt, int node)
|
|
{
|
|
int parent = fdt_parent_offset(dt, node);
|
|
|
|
// find parent with "ranges" property
|
|
while (parent >= 0) {
|
|
if (fdt_getprop(dt, parent, "ranges", NULL))
|
|
break;
|
|
|
|
parent = fdt_parent_offset(dt, parent);
|
|
}
|
|
|
|
if (parent < 0)
|
|
return 0;
|
|
|
|
// parse ranges for address translation
|
|
struct dt_ranges_tbl ranges[DT_MAX_RANGES] = {0};
|
|
dt_parse_ranges(dt, parent, ranges);
|
|
|
|
const fdt64_t *reg = fdt_getprop(dt, node, "reg", NULL);
|
|
if (!reg)
|
|
return 0;
|
|
|
|
return dt_translate(ranges, reg);
|
|
}
|