[U-Boot] [PATCH 04/11] fdt: Add device tree memory bindings
Simon Glass
sjg at chromium.org
Wed Oct 15 10:05:34 CEST 2014
From: Michael Pratt <mpratt at 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 <mpratt at chromium.org>
Signed-off-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb at chromium.org>
---
common/fdt_support.c | 2 +-
doc/device-tree-bindings/memory/memory.txt | 67 ++++++++++++++++++
include/fdtdec.h | 34 +++++++++
lib/fdtdec.c | 107 +++++++++++++++++++++++++++++
4 files changed, 209 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 dc41222..b792bb4 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -372,7 +372,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 at 0 {
+ match-value = <17>;
+ reg = <0x20000000 0x20000000
+ 0x40000000 0x20000000>;
+ };
+ board-id at 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 2590d30..926485e 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -597,4 +597,38 @@ struct fmap_entry {
*/
int fdtdec_read_fmap_entry(const void *blob, int node, const char *name,
struct fmap_entry *entry);
+
+/**
+ * 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 06d4542..fd9ef2c 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>
@@ -708,4 +710,109 @@ int fdtdec_read_fmap_entry(const void *blob, int node, const char *name,
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
More information about the U-Boot
mailing list