From: Michael Pratt <mpr...@chromium.org> Support a default memory bank, specified in reg, as well as board-specific memory banks in subtree board-id nodes.
This allows memory information to be provided in the device tree, rather than hard-coded in, which will make it simpler to handle similar devices with different memory banks, as the board-id values or masks can be used to match devices. Signed-off-by: Michael Pratt <mpr...@chromium.org> Signed-off-by: Simon Glass <s...@chromium.org> Reviewed-by: Vadim Bendebury <vben...@chromium.org> --- Changes in v2: None common/fdt_support.c | 2 +- doc/device-tree-bindings/memory/memory.txt | 67 ++++++++++++++++++ include/fdtdec.h | 33 +++++++++ lib/fdtdec.c | 107 +++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/memory/memory.txt diff --git a/common/fdt_support.c b/common/fdt_support.c index 46a15e7..6da5297 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -382,7 +382,7 @@ void do_fixup_by_compat_u32(void *fdt, const char *compat, /* * fdt_pack_reg - pack address and size array into the "reg"-suitable stream */ -static int fdt_pack_reg(const void *fdt, void *buf, uint64_t *address, +int fdt_pack_reg(const void *fdt, void *buf, uint64_t *address, uint64_t *size, int n) { int i; diff --git a/doc/device-tree-bindings/memory/memory.txt b/doc/device-tree-bindings/memory/memory.txt new file mode 100644 index 0000000..321894e --- /dev/null +++ b/doc/device-tree-bindings/memory/memory.txt @@ -0,0 +1,67 @@ +* Memory binding + +The memory binding for U-Boot is as in the ePAPR with the following additions: + +Optional subnodes can be used defining the memory layout for different board +ID masks. To match a set of board ids, a board-id node may define match-mask +and match-value ints to define a mask to apply to the board id, and the value +that the result should have for the match to be considered valid. The mask +defaults to -1, meaning that the value must fully match the board id. + +If subnodes are present, then the /memory node must define these properties: + +- #address-cells: should be 1. +- #size-cells: should be 0. + +Each subnode must define + + reg - board ID or mask for this subnode + memory-banks - list of memory banks in the same format as normal + +Each subnode may optionally define: + + match-mask - A mask to apply to the board id. This must be accompanied by + match-value. + match-value - The required resulting value of the board id mask for the given + node to be considered a match. + auto-size - Indicates that the value given for a bank is the maximum size, + each bank is probed to determine its actual size, which may be + smaller + + +The board id determination is up to the vendor and is not defined by this +binding. + +Example: + +memory { + #address-cells = <1>; + #size-cells = <1>; + reg = <0x20000000 0x20000000 + 0x40000000 0x20000000 + 0x60000000 0x20000000 + 0x80000000 0x20000000>; + auto-size; + board-id@0 { + match-value = <17>; + reg = <0x20000000 0x20000000 + 0x40000000 0x20000000>; + }; + board-id@1 { + match-mask = <2>; + match-value = <2>; + reg = <0x20000000 0x20000000 + 0x40000000 0x20000000 + 0x60000000 0x20000000 + 0x80000000 0x20000000 + 0xa0000000 0x20000000 + 0xc0000000 0x20000000 + 0xe0000000 0x20000000>; + }; +}; + + +This shows a system with the following properties: +* Default of 2GB of memory, auto-sized, so could be smaller +* 3.5GB of memory (with no auto-size) if (board id & 2) is 2 +* 1GB of memory (with no auto-size) if board id is 17. diff --git a/include/fdtdec.h b/include/fdtdec.h index 4ae77be..5fb86b0 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -661,4 +661,37 @@ int fdt_get_named_resource(const void *fdt, int node, const char *property, */ int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf); +/** + * Decode the size of memory + * + * RAM size is normally set in a /memory node and consists of a list of + * (base, size) cells in the 'reg' property. This information is used to + * determine the total available memory as well as the address and size + * of each bank. + * + * Optionally the memory configuration can vary depending on a board id, + * typically read from strapping resistors or an EEPROM on the board. + * + * Finally, memory size can be detected (within certain limits) by probing + * the available memory. It is safe to do so within the limits provides by + * the board's device tree information. This makes it possible to produce + * boards with different memory sizes, where the device tree specifies the + * maximum memory configuration, and the smaller memory configuration is + * probed. + * + * This function decodes that information, returning the memory base address, + * size and bank information. See the memory.txt binding for full + * documentation. + * + * @param blob Device tree blob + * @param area Name of node to check (NULL means "/memory") + * @param board_id Board ID to look up + * @param basep Returns base address of first memory bank (NULL to + * ignore) + * @param sizep Returns total memory size (NULL to ignore) + * @param bd Updated with the memory bank information (NULL to skip) + * @return 0 if OK, -ve on error + */ +int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id, + phys_addr_t *basep, phys_size_t *sizep, bd_t *bd); #endif diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 9714620..d5a6a3e 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -6,10 +6,12 @@ #ifndef USE_HOSTCC #include <common.h> #include <errno.h> +#include <fdt_support.h> #include <serial.h> #include <libfdt.h> #include <fdtdec.h> #include <linux/ctype.h> +#include <asm/types.h> #include <asm/gpio.h> @@ -780,4 +782,109 @@ int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf) return 0; } + +int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id, + phys_addr_t *basep, phys_size_t *sizep, bd_t *bd) +{ + int addr_cells, size_cells; + const u32 *cell, *end; + u64 total_size, size, addr; + int node, child; + bool auto_size; + int bank; + int len; + + debug("%s: board_id=%d\n", __func__, board_id); + if (!area) + area = "/memory"; + node = fdt_path_offset(blob, area); + if (node < 0) { + debug("No %s node found\n", area); + return -ENOENT; + } + + cell = fdt_getprop(blob, node, "reg", &len); + if (!cell) { + debug("No reg property found\n"); + return -ENOENT; + } + + addr_cells = fdt_address_cells(blob, node); + size_cells = fdt_size_cells(blob, node); + + /* Check the board id and mask */ + for (child = fdt_first_subnode(blob, node); + child >= 0; + child = fdt_next_subnode(blob, child)) { + int match_mask, match_value; + + match_mask = fdtdec_get_int(blob, child, "match-mask", -1); + match_value = fdtdec_get_int(blob, child, "match-value", -1); + + if (match_value >= 0 && + ((board_id & match_mask) == match_value)) { + /* Found matching mask */ + debug("Found matching mask %d\n", match_mask); + node = child; + cell = fdt_getprop(blob, node, "reg", &len); + if (!cell) { + debug("No memory-banks property found\n"); + return -EINVAL; + } + break; + } + } + /* Note: if no matching subnode was found we use the parent node */ + + if (bd) { + memset(bd->bi_dram, '\0', sizeof(bd->bi_dram[0]) * + CONFIG_NR_DRAM_BANKS); + } + + auto_size = fdtdec_get_bool(blob, node, "auto-size"); + + total_size = 0; + end = cell + len / 4 - addr_cells - size_cells; + debug("cell at %p, end %p\n", cell, end); + for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { + if (cell > end) + break; + addr = 0; + if (addr_cells == 2) + addr += (u64)fdt32_to_cpu(*cell++) << 32UL; + addr += fdt32_to_cpu(*cell++); + if (bd) + bd->bi_dram[bank].start = addr; + if (basep && !bank) + *basep = (phys_addr_t)addr; + + size = 0; + if (size_cells == 2) + size += (u64)fdt32_to_cpu(*cell++) << 32UL; + size += fdt32_to_cpu(*cell++); + + if (auto_size) { + u64 new_size; + + debug("Auto-sizing %llx, size %llx: ", addr, size); + new_size = get_ram_size((long *)(uintptr_t)addr, size); + if (new_size == size) { + debug("OK\n"); + } else { + debug("sized to %llx\n", new_size); + size = new_size; + } + } + + if (bd) + bd->bi_dram[bank].size = size; + total_size += size; + } + + debug("Memory size %llu\n", total_size); + if (sizep) + *sizep = (phys_size_t)total_size; + + return 0; +} #endif -- 2.1.0.rc2.206.gedb03e5 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot