From 81fae63497d2f43ab6ec5f1370d6fc579971fe04 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 24 Sep 2011 19:41:40 +0200 Subject: oftree: add fixup for memory nodes Thanks to a common memory handling barebox knows the sdram banks and sizes, so we can add a common fixup functions for the nodes in the devicetree. Signed-off-by: Sascha Hauer --- common/memory.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'common/memory.c') diff --git a/common/memory.c b/common/memory.c index 4d59f15fec..0ba9a18e88 100644 --- a/common/memory.c +++ b/common/memory.c @@ -22,6 +22,9 @@ #include #include +#include +#include +#include /* * Begin and End of memory area for malloc(), and current "brk" @@ -87,3 +90,80 @@ void barebox_add_memory_bank(const char *name, resource_size_t start, list_add_tail(&bank->list, &memory_banks); } + +#ifdef CONFIG_OFTREE + +/* + * Get cells len in bytes + * if #NNNN-cells property is 2 then len is 8 + * otherwise len is 4 + */ +static int get_cells_len(struct fdt_header *fdt, char *nr_cells_name) +{ + const u32 *cell; + + cell = fdt_getprop(fdt, 0, nr_cells_name, NULL); + if (cell && *cell == 2) + return 8; + + return 4; +} + +/* + * Write a 4 or 8 byte big endian cell + */ +static void write_cell(u8 *addr, u64 val, int size) +{ + int shift = (size - 1) * 8; + + while (size-- > 0) { + *addr++ = (val >> shift) & 0xff; + shift -= 8; + } +} + +static int of_memory_fixup(struct fdt_header *fdt) +{ + struct memory_bank *bank; + int err, nodeoffset; + int addr_cell_len, size_cell_len, len = 0; + u8 tmp[16 * 16]; /* Up to 64-bit address + 64-bit size */ + + /* update, or add and update /memory node */ + nodeoffset = fdt_get_path_or_create(fdt, "/memory"); + if (nodeoffset < 0) + return nodeoffset; + + err = fdt_setprop(fdt, nodeoffset, "device_type", "memory", + sizeof("memory")); + if (err < 0) { + printf("WARNING: could not set %s %s.\n", "device_type", + fdt_strerror(err)); + return err; + } + + addr_cell_len = get_cells_len(fdt, "#address-cells"); + size_cell_len = get_cells_len(fdt, "#size-cells"); + + for_each_memory_bank(bank) { + write_cell(tmp + len, bank->start, addr_cell_len); + len += addr_cell_len; + write_cell(tmp + len, bank->size, size_cell_len); + len += size_cell_len; + } + + err = fdt_setprop(fdt, nodeoffset, "reg", tmp, len); + if (err < 0) { + printf("WARNING: could not set %s %s.\n", + "reg", fdt_strerror(err)); + return err; + } + return 0; +} + +static int of_register_memory_fixup(void) +{ + return of_register_fixup(of_memory_fixup); +} +late_initcall(of_register_memory_fixup); +#endif -- cgit v1.2.3