fdt_support: add partitions fixup in mtd node
Allow overwriting defined partitions in the device tree blob using partition info defined in the 'mtdparts' environment variable. Signed-off-by: Anatolij Gustschin <agust@denx.de> Cc: Gerald Van Baren <vanbaren@cideas.com>
This commit is contained in:
parent
d611295032
commit
3c950e2ebf
@ -776,7 +776,7 @@ static int device_del(struct mtd_device *dev)
|
||||
* @param num device number
|
||||
* @return NULL if requested device does not exist
|
||||
*/
|
||||
static struct mtd_device* device_find(u8 type, u8 num)
|
||||
struct mtd_device *device_find(u8 type, u8 num)
|
||||
{
|
||||
struct list_head *entry;
|
||||
struct mtd_device *dev_tmp;
|
||||
|
@ -757,3 +757,222 @@ int fdt_fixup_nor_flash_size(void *blob, int cs, u32 size)
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FDT_FIXUP_PARTITIONS
|
||||
#include <jffs2/load_kernel.h>
|
||||
#include <mtd_node.h>
|
||||
|
||||
struct reg_cell {
|
||||
unsigned int r0;
|
||||
unsigned int r1;
|
||||
};
|
||||
|
||||
int fdt_del_subnodes(const void *blob, int parent_offset)
|
||||
{
|
||||
int off, ndepth;
|
||||
int ret;
|
||||
|
||||
for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth);
|
||||
(off >= 0) && (ndepth > 0);
|
||||
off = fdt_next_node(blob, off, &ndepth)) {
|
||||
if (ndepth == 1) {
|
||||
debug("delete %s: offset: %x\n",
|
||||
fdt_get_name(blob, off, 0), off);
|
||||
ret = fdt_del_node((void *)blob, off);
|
||||
if (ret < 0) {
|
||||
printf("Can't delete node: %s\n",
|
||||
fdt_strerror(ret));
|
||||
return ret;
|
||||
} else {
|
||||
ndepth = 0;
|
||||
off = parent_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_increase_size(void *fdt, int add_len)
|
||||
{
|
||||
int newlen;
|
||||
|
||||
newlen = fdt_totalsize(fdt) + add_len;
|
||||
|
||||
/* Open in place with a new len */
|
||||
return fdt_open_into(fdt, fdt, newlen);
|
||||
}
|
||||
|
||||
int fdt_del_partitions(void *blob, int parent_offset)
|
||||
{
|
||||
const void *prop;
|
||||
int ndepth = 0;
|
||||
int off;
|
||||
int ret;
|
||||
|
||||
off = fdt_next_node(blob, parent_offset, &ndepth);
|
||||
if (off > 0 && ndepth == 1) {
|
||||
prop = fdt_getprop(blob, off, "label", NULL);
|
||||
if (prop == NULL) {
|
||||
/*
|
||||
* Could not find label property, nand {}; node?
|
||||
* Check subnode, delete partitions there if any.
|
||||
*/
|
||||
return fdt_del_partitions(blob, off);
|
||||
} else {
|
||||
ret = fdt_del_subnodes(blob, parent_offset);
|
||||
if (ret < 0) {
|
||||
printf("Can't remove subnodes: %s\n",
|
||||
fdt_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_node_set_part_info(void *blob, int parent_offset,
|
||||
struct mtd_device *dev)
|
||||
{
|
||||
struct list_head *pentry;
|
||||
struct part_info *part;
|
||||
struct reg_cell cell;
|
||||
int off, ndepth = 0;
|
||||
int part_num, ret;
|
||||
char buf[64];
|
||||
|
||||
ret = fdt_del_partitions(blob, parent_offset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Check if it is nand {}; subnode, adjust
|
||||
* the offset in this case
|
||||
*/
|
||||
off = fdt_next_node(blob, parent_offset, &ndepth);
|
||||
if (off > 0 && ndepth == 1)
|
||||
parent_offset = off;
|
||||
|
||||
part_num = 0;
|
||||
list_for_each_prev(pentry, &dev->parts) {
|
||||
int newoff;
|
||||
|
||||
part = list_entry(pentry, struct part_info, link);
|
||||
|
||||
debug("%2d: %-20s0x%08x\t0x%08x\t%d\n",
|
||||
part_num, part->name, part->size,
|
||||
part->offset, part->mask_flags);
|
||||
|
||||
sprintf(buf, "partition@%x", part->offset);
|
||||
add_sub:
|
||||
ret = fdt_add_subnode(blob, parent_offset, buf);
|
||||
if (ret == -FDT_ERR_NOSPACE) {
|
||||
ret = fdt_increase_size(blob, 512);
|
||||
if (!ret)
|
||||
goto add_sub;
|
||||
else
|
||||
goto err_size;
|
||||
} else if (ret < 0) {
|
||||
printf("Can't add partition node: %s\n",
|
||||
fdt_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
newoff = ret;
|
||||
|
||||
/* Check MTD_WRITEABLE_CMD flag */
|
||||
if (part->mask_flags & 1) {
|
||||
add_ro:
|
||||
ret = fdt_setprop(blob, newoff, "read_only", NULL, 0);
|
||||
if (ret == -FDT_ERR_NOSPACE) {
|
||||
ret = fdt_increase_size(blob, 512);
|
||||
if (!ret)
|
||||
goto add_ro;
|
||||
else
|
||||
goto err_size;
|
||||
} else if (ret < 0)
|
||||
goto err_prop;
|
||||
}
|
||||
|
||||
cell.r0 = cpu_to_fdt32(part->offset);
|
||||
cell.r1 = cpu_to_fdt32(part->size);
|
||||
add_reg:
|
||||
ret = fdt_setprop(blob, newoff, "reg", &cell, sizeof(cell));
|
||||
if (ret == -FDT_ERR_NOSPACE) {
|
||||
ret = fdt_increase_size(blob, 512);
|
||||
if (!ret)
|
||||
goto add_reg;
|
||||
else
|
||||
goto err_size;
|
||||
} else if (ret < 0)
|
||||
goto err_prop;
|
||||
|
||||
add_label:
|
||||
ret = fdt_setprop_string(blob, newoff, "label", part->name);
|
||||
if (ret == -FDT_ERR_NOSPACE) {
|
||||
ret = fdt_increase_size(blob, 512);
|
||||
if (!ret)
|
||||
goto add_label;
|
||||
else
|
||||
goto err_size;
|
||||
} else if (ret < 0)
|
||||
goto err_prop;
|
||||
|
||||
part_num++;
|
||||
}
|
||||
return 0;
|
||||
err_size:
|
||||
printf("Can't increase blob size: %s\n", fdt_strerror(ret));
|
||||
return ret;
|
||||
err_prop:
|
||||
printf("Can't add property: %s\n", fdt_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update partitions in nor/nand nodes using info from
|
||||
* mtdparts environment variable. The nodes to update are
|
||||
* specified by node_info structure which contains mtd device
|
||||
* type and compatible string: E. g. the board code in
|
||||
* ft_board_setup() could use:
|
||||
*
|
||||
* struct node_info nodes[] = {
|
||||
* { "fsl,mpc5121-nfc", MTD_DEV_TYPE_NAND, },
|
||||
* { "cfi-flash", MTD_DEV_TYPE_NOR, },
|
||||
* };
|
||||
*
|
||||
* fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
|
||||
*/
|
||||
void fdt_fixup_mtdparts(void *blob, void *node_info, int node_info_size)
|
||||
{
|
||||
struct node_info *ni = node_info;
|
||||
struct mtd_device *dev;
|
||||
char *parts;
|
||||
int i, idx;
|
||||
int noff;
|
||||
|
||||
parts = getenv("mtdparts");
|
||||
if (!parts)
|
||||
return;
|
||||
|
||||
if (mtdparts_init() != 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < node_info_size; i++) {
|
||||
idx = 0;
|
||||
noff = fdt_node_offset_by_compatible(blob, -1, ni[i].compat);
|
||||
while (noff != -FDT_ERR_NOTFOUND) {
|
||||
debug("%s: %s, mtd dev type %d\n",
|
||||
fdt_get_name(blob, noff, 0),
|
||||
ni[i].compat, ni[i].type);
|
||||
dev = device_find(ni[i].type, idx++);
|
||||
if (dev) {
|
||||
if (fdt_node_set_part_info(blob, noff, dev))
|
||||
return; /* return on error */
|
||||
}
|
||||
|
||||
/* Jump to next flash node */
|
||||
noff = fdt_node_offset_by_compatible(blob, noff,
|
||||
ni[i].compat);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -81,5 +81,7 @@ int fdt_resize(void *blob);
|
||||
|
||||
int fdt_fixup_nor_flash_size(void *blob, int cs, u32 size);
|
||||
|
||||
void fdt_fixup_mtdparts(void *fdt, void *node_info, int node_info_size);
|
||||
|
||||
#endif /* ifdef CONFIG_OF_LIBFDT */
|
||||
#endif /* ifndef __FDT_SUPPORT_H */
|
||||
|
@ -78,5 +78,6 @@ struct mtdids {
|
||||
extern int mtdparts_init(void);
|
||||
extern int find_dev_and_part(const char *id, struct mtd_device **dev,
|
||||
u8 *part_num, struct part_info **part);
|
||||
extern struct mtd_device *device_find(u8 type, u8 num);
|
||||
|
||||
#endif /* load_kernel_h */
|
||||
|
11
include/mtd_node.h
Normal file
11
include/mtd_node.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _NODE_INFO
|
||||
#define _NODE_INFO
|
||||
|
||||
/*
|
||||
* Info we use to search for a flash node in DTB.
|
||||
*/
|
||||
struct node_info {
|
||||
const char *compat; /* compatible string */
|
||||
int type; /* mtd flash type */
|
||||
};
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user