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