fdtdec: add function: fdtdec_decode_memory()
authorPrzemyslaw Marczak <p.marczak@samsung.com>
Mon, 28 Jul 2014 09:16:47 +0000 (11:16 +0200)
committerJaehoon Chung <jh80.chung@samsung.com>
Tue, 20 Oct 2020 00:43:30 +0000 (09:43 +0900)
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 <p.marczak@samsung.com>
include/dm/of_extra.h
include/fdtdec.h
lib/fdtdec.c

index ca15df2..a3d878d 100644 (file)
@@ -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
index 152eb07..94c152b 100644 (file)
@@ -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
index c6fcfc2..83bb135 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/ctype.h>
 #include <linux/lzo.h>
 #include <linux/ioport.h>
+#include <fdt_support.h>
 
 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", &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;