From 63c3f9c31ac11fdea37fc651104935b05c44b757 Mon Sep 17 00:00:00 2001
From: Przemyslaw Marczak
Date: Mon, 28 Jul 2014 11:16:47 +0200
Subject: [PATCH] fdtdec: add function: fdtdec_decode_memory()
This function can be used for decode memory node from device tree file.
Currently supports decoding of a single memory node with a multiple ranges
specified by the reg property with size of address and size cells specified
in a root node.
Function parameters:
- blob: ptr to device tree
- start: ptr to banks start address array
- size: ptr to banks size array
- max_banks: max number of banks to fill
Two of args: start or size can be NULL e.g. if only each bank size is needed.
Sample use case:
memory {
device_type = "memory";
reg = <0x40000000 ... 0x10000000 ...
0x50000000 ... 0x10000000 ...
... ... ... ...>;
};
Change-Id: I2f3defb89cf62d81377fb7882dbbae79b4472af2
Signed-off-by: Przemyslaw Marczak
---
include/dm/of_extra.h | 12 ++++
include/fdtdec.h | 45 ++++++++++++++
lib/fdtdec.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 218 insertions(+)
diff --git a/include/dm/of_extra.h b/include/dm/of_extra.h
index ca15df2..a3d878d 100644
--- a/include/dm/of_extra.h
+++ b/include/dm/of_extra.h
@@ -86,4 +86,16 @@ int ofnode_decode_memory_region(ofnode config_node, const char *mem_type,
const char *suffix, fdt_addr_t *basep,
fdt_size_t *sizep);
+/**
+ * Read a flash entry from the fdt
+ *
+ * @param blob FDT blob
+ * @param node Offset of node to read
+ * @param name Name of node being read
+ * @param entry Place to put offset and size of this node
+ * @return 0 if ok, -ve on error
+ */
+int fdtdec_read_fmap_entry(const void *blob, int node, const char *name,
+ struct fmap_entry *entry);
+
#endif
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 152eb07..94c152b 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -813,6 +813,51 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node,
const char *prop_name, int count);
/**
+ * Look up a property in a node which contains a memory region address and
+ * size. Then return a pointer to this address.
+ *
+ * The property must hold one address with a length. This is only tested on
+ * 32-bit machines.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param basep Returns base address of region
+ * @param size Returns size of region
+ * @return 0 if ok, -1 on error (property not found)
+ */
+int fdtdec_decode_region(const void *blob, int node, const char *prop_name,
+ fdt_addr_t *basep, fdt_size_t *sizep);
+
+/**
+ * fdt_decode_memory: Find a memory node, fill start, size arrays,
+ * and return filled banks number.
+ *
+ * @blob: ptr to device tree
+ * @start: ptr to banks start address array
+ * @size: ptr to banks size array
+ * @max_banks: max number of banks to fill
+ *
+ * @Returns number of filled banks or 0 on error.
+ *
+ * To get the size of each memory bank only, the @start pointer can be NULL.
+ * The same with bank start address if the @size pointer is NULL.
+ *
+ * Currently supports a single memory node with multiple ranges
+ * specified by the reg property with address and size cells size
+ * specified in a root node.
+ * memory {
+ * device_type = "memory";
+ * reg = <0x40000000 0x10000000 ...
+ * 0x50000000 0x10000000 ...
+ * ... ... >;
+ * };
+ *
+*/
+int fdtdec_decode_memory(const void *blob, uint64_t start[], uint64_t size[],
+ int max_banks);
+
+/**
* Obtain an indexed resource from a device property.
*
* @param fdt FDT blob
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index c6fcfc2..83bb135 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
DECLARE_GLOBAL_DATA_PTR;
@@ -897,6 +898,166 @@ char *fdtdec_get_config_string(const void *blob, const char *prop_name)
return (char *)nodep;
}
+int fdtdec_decode_region(const void *blob, int node, const char *prop_name,
+ fdt_addr_t *basep, fdt_size_t *sizep)
+{
+ const fdt_addr_t *cell;
+ int len;
+
+ debug("%s: %s: %s\n", __func__, fdt_get_name(blob, node, NULL),
+ prop_name);
+ cell = fdt_getprop(blob, node, prop_name, &len);
+ if (!cell || (len < sizeof(fdt_addr_t) * 2)) {
+ debug("cell=%p, len=%d\n", cell, len);
+ return -1;
+ }
+
+ *basep = fdt_addr_to_cpu(*cell);
+ *sizep = fdt_size_to_cpu(cell[1]);
+ debug("%s: base=%08lx, size=%lx\n", __func__, (ulong)*basep,
+ (ulong)*sizep);
+
+ return 0;
+}
+
+int fdtdec_decode_memory(const void *blob, uint64_t start[],
+ uint64_t size[], int max_banks)
+{
+ const fdt32_t *reg;
+ const fdt32_t *cell;
+ uint64_t val;
+ int node_off;
+ int reg_len, reg_cells;
+ int addr_len, addr_cells, size_len, size_cells;
+ int bank_len, bank_cells, bank_count, reg_banks;
+ int cell_off;
+ int err, i;
+
+ debug("# DBG: start: %s\n", __func__);
+
+ if (!start && !size)
+ return 0;
+
+ /* Get parent address bytes len */
+ cell = fdt_getprop(blob, 0, "#address-cells", NULL);
+ if (cell)
+ addr_cells = fdt32_to_cpu(*cell);
+ else
+ addr_cells = 1;
+
+ cell = fdt_getprop(blob, 0, "#size-cells", NULL);
+ if (cell)
+ size_cells = fdt32_to_cpu(*cell);
+ else
+ size_cells = 1;
+
+ bank_cells = addr_cells + size_cells;
+
+ /* Get len in bytes */
+ addr_len = addr_cells << 2;
+ size_len = size_cells << 2;
+ bank_len = addr_len + size_len;
+
+ debug("# DBG: parent: addr_cells: %x size_cells: %x\n", addr_cells,
+ size_cells);
+ debug("# DBG: parent: addr_len:%x [B] size_len:%x [B]\n", addr_len,
+ size_len);
+ debug("# DBG: bank: len: %x [B] cells: %x\n", bank_len, bank_cells);
+
+ /* Check if memory node exists */
+ node_off = fdt_path_offset(blob, "/memory");
+ debug("# DBG: fdt path offset: %d\n", node_off);
+
+ if (node_off < 0) {
+ debug("# DBG: fdt path not found: error: %x\n", node_off);
+ return 0;
+ }
+
+ reg = (uint32_t *)fdt_getprop(blob, node_off, "reg", ®_len);
+ if (!reg) {
+ debug("# DBG: fdt prop: reg - not found.\n");
+ return 0;
+ }
+ reg_banks = reg_len / bank_len;
+ reg_cells = reg_banks * bank_cells;
+ debug("# DBG: Reg: len: %d [B]; cells: %d; banks:%d\n", reg_len,
+ reg_cells,
+ reg_banks);
+
+ if (reg_banks > max_banks) {
+ bank_count = max_banks;
+ debug("# DBG: Warning! Can init only:%d banks!", bank_count);
+ } else {
+ bank_count = reg_banks;
+ debug("# DBG: Warning! Found:%d banks!", bank_count);
+ }
+
+ debug("\n# DBG: setting banks info:\n");
+
+ cell_off = 0;
+ for (i = 0; i < bank_count; i++) {
+ if (start) {
+ err = fdt_read_prop(reg, reg_cells, cell_off, &val,
+ addr_cells);
+ if (err)
+ return 0;
+
+ start[i] = val;
+ debug("# DBG: start: %#llx\n", val);
+ }
+
+ cell_off += addr_cells;
+
+ if (size) {
+ err = fdt_read_prop(reg, reg_cells, cell_off, &val,
+ size_cells);
+ if (err)
+ return 0;
+
+ size[i] = val;
+ debug("# DBG: size: %#llx\n", val);
+ }
+
+ cell_off += size_cells;
+ }
+
+ debug("# DBG: %s: finished\n", __func__);
+
+ return i;
+}
+
+/**
+ * Read a flash entry from the fdt
+ *
+ * @param blob FDT blob
+ * @param node Offset of node to read
+ * @param name Name of node being read
+ * @param entry Place to put offset and size of this node
+ * @return 0 if ok, -ve on error
+ */
+int fdtdec_read_fmap_entry(const void *blob, int node, const char *name,
+ struct fmap_entry *entry)
+{
+ const char *prop;
+ u32 reg[2];
+
+ if (fdtdec_get_int_array(blob, node, "reg", reg, 2)) {
+ debug("Node '%s' has bad/missing 'reg' property\n", name);
+ return -FDT_ERR_NOTFOUND;
+ }
+ entry->offset = reg[0];
+ entry->length = reg[1];
+ entry->used = fdtdec_get_int(blob, node, "used", entry->length);
+ prop = fdt_getprop(blob, node, "compress", NULL);
+ entry->compress_algo = prop && !strcmp(prop, "lzo") ?
+ FMAP_COMPRESS_LZ4 : FMAP_COMPRESS_NONE;
+ prop = fdt_getprop(blob, node, "hash", &entry->hash_size);
+ entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE;
+ entry->hash = (uint8_t *)prop;
+
+ return 0;
+}
+
u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells)
{
u64 number = 0;
--
2.7.4