mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-10 01:34:12 +00:00
devicetree: Add dt utils for "ranges" based address translation
Signed-off-by: Janne Grunau <j@jannau.net>
This commit is contained in:
parent
f1664ccef4
commit
d27ca705c1
4 changed files with 96 additions and 49 deletions
1
Makefile
1
Makefile
|
@ -90,6 +90,7 @@ OBJECTS := \
|
|||
dart.o \
|
||||
dcp.o \
|
||||
dcp_iboot.o \
|
||||
devicetree.o \
|
||||
display.o \
|
||||
exception.o exception_asm.o \
|
||||
fb.o font.o font_retina.o \
|
||||
|
|
69
src/devicetree.c
Normal file
69
src/devicetree.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* 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);
|
||||
}
|
22
src/devicetree.h
Normal file
22
src/devicetree.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef DEVICETREE_H
|
||||
#define DEVICETREE_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#include "libfdt/libfdt.h"
|
||||
|
||||
#define DT_MAX_RANGES 8
|
||||
|
||||
struct dt_ranges_tbl {
|
||||
u64 start;
|
||||
u64 parent;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
void dt_parse_ranges(void *dt, int node, struct dt_ranges_tbl *ranges);
|
||||
u64 dt_translate(struct dt_ranges_tbl *ranges, const fdt64_t *reg);
|
||||
u64 dt_get_address(void *dt, int node);
|
||||
|
||||
#endif
|
53
src/kboot.c
53
src/kboot.c
|
@ -4,6 +4,7 @@
|
|||
#include "adt.h"
|
||||
#include "assert.h"
|
||||
#include "dapf.h"
|
||||
#include "devicetree.h"
|
||||
#include "exception.h"
|
||||
#include "malloc.h"
|
||||
#include "memory.h"
|
||||
|
@ -869,52 +870,6 @@ static int dt_set_atc_tunables(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_RANGES 8
|
||||
|
||||
struct ranges_tbl {
|
||||
u64 start;
|
||||
u64 parent;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
static void parse_ranges(int soc, struct ranges_tbl *ranges)
|
||||
{
|
||||
int len;
|
||||
const struct fdt_property *ranges_prop = fdt_get_property(dt, soc, "ranges", &len);
|
||||
if (ranges_prop && len > 0) {
|
||||
int idx = 0;
|
||||
int num_entries = len / sizeof(fdt64_t);
|
||||
if (num_entries > MAX_RANGES)
|
||||
num_entries = 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u64 translate(struct ranges_tbl *ranges, const fdt64_t *reg)
|
||||
{
|
||||
u64 addr = fdt64_ld(reg);
|
||||
for (int idx = 0; idx < 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;
|
||||
}
|
||||
|
||||
static int dt_disable_missing_devs(const char *adt_prefix, const char *dt_prefix, int max_devs)
|
||||
{
|
||||
int ret = -1;
|
||||
|
@ -978,8 +933,8 @@ static int dt_disable_missing_devs(const char *adt_prefix, const char *dt_prefix
|
|||
bail("FDT: %s node not found in devtree\n", path);
|
||||
|
||||
// parse ranges for address translation
|
||||
struct ranges_tbl ranges[MAX_RANGES] = {0};
|
||||
parse_ranges(soc, ranges);
|
||||
struct dt_ranges_tbl ranges[DT_MAX_RANGES] = {0};
|
||||
dt_parse_ranges(dt, soc, ranges);
|
||||
|
||||
/* Disable primary devices */
|
||||
fdt_for_each_subnode(node, dt, soc)
|
||||
|
@ -992,7 +947,7 @@ static int dt_disable_missing_devs(const char *adt_prefix, const char *dt_prefix
|
|||
if (!reg)
|
||||
bail_cleanup("FDT: failed to get reg property of %s\n", name);
|
||||
|
||||
u64 addr = translate(ranges, reg);
|
||||
u64 addr = dt_translate(ranges, reg);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < acnt; i++)
|
||||
|
|
Loading…
Reference in a new issue