mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-19 03:15:00 +00:00
mtd: add support for parsing partitions defined in OF
Add support for parsing partitions defined in device-trees via the `partitions` node with `fixed-partitions` compatible. The `mtdparts`/`mtdids` mechanism takes precedence. If some partitions are defined for a MTD device via this mechanism, the code won't register partitions for that MTD device from OF, even if they are defined. Signed-off-by: Marek Behún <marek.behun@nic.cz> Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com> Tested-by: Patrice Chotard <patrice.chotard@foss.st.com> Reviewed-by: Jagan Teki <jagan@amarulasolutions.com> Cc: Simon Glass <sjg@chromium.org> Cc: Heiko Schocher <hs@denx.de> Cc: Patrick Delaunay <patrick.delaunay@st.com>
This commit is contained in:
parent
0e116bea52
commit
dc339bf784
3 changed files with 135 additions and 44 deletions
|
@ -198,53 +198,11 @@ static void mtd_del_all_parts(void)
|
||||||
} while (ret > 0);
|
} while (ret > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mtd_probe_devices(void)
|
static int parse_mtdparts(const char *mtdparts, const char *mtdids)
|
||||||
{
|
{
|
||||||
static char *old_mtdparts;
|
const char *mtdparts_next;
|
||||||
static char *old_mtdids;
|
|
||||||
const char *mtdparts = get_mtdparts();
|
|
||||||
const char *mtdids = get_mtdids();
|
|
||||||
const char *mtdparts_next = mtdparts;
|
|
||||||
struct mtd_info *mtd;
|
struct mtd_info *mtd;
|
||||||
|
|
||||||
mtd_probe_uclass_mtd_devs();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if mtdparts/mtdids changed, if the MTD dev list was updated
|
|
||||||
* or if our previous attempt to delete existing partititions failed.
|
|
||||||
* In any of these cases we want to update the partitions, otherwise,
|
|
||||||
* everything is up-to-date and we can return 0 directly.
|
|
||||||
*/
|
|
||||||
if ((!mtdparts && !old_mtdparts && !mtdids && !old_mtdids) ||
|
|
||||||
(mtdparts && old_mtdparts && mtdids && old_mtdids &&
|
|
||||||
!mtd_dev_list_updated() && !mtd_del_all_parts_failed &&
|
|
||||||
!strcmp(mtdparts, old_mtdparts) &&
|
|
||||||
!strcmp(mtdids, old_mtdids)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Update the local copy of mtdparts */
|
|
||||||
free(old_mtdparts);
|
|
||||||
free(old_mtdids);
|
|
||||||
old_mtdparts = strdup(mtdparts);
|
|
||||||
old_mtdids = strdup(mtdids);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove all old parts. Note that partition removal can fail in case
|
|
||||||
* one of the partition is still being used by an MTD user, so this
|
|
||||||
* does not guarantee that all old partitions are gone.
|
|
||||||
*/
|
|
||||||
mtd_del_all_parts();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call mtd_dev_list_updated() to clear updates generated by our own
|
|
||||||
* parts removal loop.
|
|
||||||
*/
|
|
||||||
mtd_dev_list_updated();
|
|
||||||
|
|
||||||
/* If either mtdparts or mtdids is empty, then exit */
|
|
||||||
if (!mtdparts || !mtdids)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */
|
/* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */
|
||||||
if (!strncmp(mtdparts, "mtdparts=", sizeof("mtdparts=") - 1))
|
if (!strncmp(mtdparts, "mtdparts=", sizeof("mtdparts=") - 1))
|
||||||
mtdparts += 9;
|
mtdparts += 9;
|
||||||
|
@ -343,6 +301,66 @@ int mtd_probe_devices(void)
|
||||||
put_mtd_device(mtd);
|
put_mtd_device(mtd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtd_probe_devices(void)
|
||||||
|
{
|
||||||
|
static char *old_mtdparts;
|
||||||
|
static char *old_mtdids;
|
||||||
|
const char *mtdparts = get_mtdparts();
|
||||||
|
const char *mtdids = get_mtdids();
|
||||||
|
struct mtd_info *mtd;
|
||||||
|
|
||||||
|
mtd_probe_uclass_mtd_devs();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if mtdparts/mtdids changed, if the MTD dev list was updated
|
||||||
|
* or if our previous attempt to delete existing partititions failed.
|
||||||
|
* In any of these cases we want to update the partitions, otherwise,
|
||||||
|
* everything is up-to-date and we can return 0 directly.
|
||||||
|
*/
|
||||||
|
if ((!mtdparts && !old_mtdparts && !mtdids && !old_mtdids) ||
|
||||||
|
(mtdparts && old_mtdparts && mtdids && old_mtdids &&
|
||||||
|
!mtd_dev_list_updated() && !mtd_del_all_parts_failed &&
|
||||||
|
!strcmp(mtdparts, old_mtdparts) &&
|
||||||
|
!strcmp(mtdids, old_mtdids)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Update the local copy of mtdparts */
|
||||||
|
free(old_mtdparts);
|
||||||
|
free(old_mtdids);
|
||||||
|
old_mtdparts = strdup(mtdparts);
|
||||||
|
old_mtdids = strdup(mtdids);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove all old parts. Note that partition removal can fail in case
|
||||||
|
* one of the partition is still being used by an MTD user, so this
|
||||||
|
* does not guarantee that all old partitions are gone.
|
||||||
|
*/
|
||||||
|
mtd_del_all_parts();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call mtd_dev_list_updated() to clear updates generated by our own
|
||||||
|
* parts removal loop.
|
||||||
|
*/
|
||||||
|
mtd_dev_list_updated();
|
||||||
|
|
||||||
|
/* If both mtdparts and mtdids are non-empty, parse */
|
||||||
|
if (mtdparts && mtdids) {
|
||||||
|
if (parse_mtdparts(mtdparts, mtdids) < 0)
|
||||||
|
printf("Failed parsing MTD partitions from mtdparts!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fallback to OF partitions */
|
||||||
|
mtd_for_each_device(mtd) {
|
||||||
|
if (list_empty(&mtd->partitions)) {
|
||||||
|
if (add_mtd_partitions_of(mtd) < 0)
|
||||||
|
printf("Failed parsing MTD %s OF partitions!\n",
|
||||||
|
mtd->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call mtd_dev_list_updated() to clear updates generated by our own
|
* Call mtd_dev_list_updated() to clear updates generated by our own
|
||||||
* parts registration loop.
|
* parts registration loop.
|
||||||
|
|
|
@ -892,6 +892,69 @@ int add_mtd_partitions(struct mtd_info *master,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(OF_CONTROL)
|
||||||
|
int add_mtd_partitions_of(struct mtd_info *master)
|
||||||
|
{
|
||||||
|
ofnode parts, child;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (!master->dev)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
parts = ofnode_find_subnode(mtd_get_ofnode(master), "partitions");
|
||||||
|
if (!ofnode_valid(parts) || !ofnode_is_available(parts) ||
|
||||||
|
!ofnode_device_is_compatible(parts, "fixed-partitions"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ofnode_for_each_subnode(child, parts) {
|
||||||
|
struct mtd_partition part = { 0 };
|
||||||
|
struct mtd_info *slave;
|
||||||
|
fdt_addr_t offset, size;
|
||||||
|
|
||||||
|
if (!ofnode_is_available(child))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
offset = ofnode_get_addr_size_index_notrans(child, 0, &size);
|
||||||
|
if (offset == FDT_ADDR_T_NONE || !size) {
|
||||||
|
debug("Missing partition offset/size on \"%s\" partition\n",
|
||||||
|
master->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
part.name = ofnode_read_string(child, "label");
|
||||||
|
if (!part.name)
|
||||||
|
part.name = ofnode_read_string(child, "name");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* .mask_flags is used to remove flags in allocate_partition(),
|
||||||
|
* so when "read-only" is present, we add MTD_WRITABLE to the
|
||||||
|
* mask, and so MTD_WRITABLE will be removed on partition
|
||||||
|
* allocation
|
||||||
|
*/
|
||||||
|
if (ofnode_read_bool(child, "read-only"))
|
||||||
|
part.mask_flags |= MTD_WRITEABLE;
|
||||||
|
if (ofnode_read_bool(child, "lock"))
|
||||||
|
part.mask_flags |= MTD_POWERUP_LOCK;
|
||||||
|
|
||||||
|
part.offset = offset;
|
||||||
|
part.size = size;
|
||||||
|
part.ecclayout = master->ecclayout;
|
||||||
|
|
||||||
|
slave = allocate_partition(master, &part, i++, 0);
|
||||||
|
if (IS_ERR(slave))
|
||||||
|
return PTR_ERR(slave);
|
||||||
|
|
||||||
|
mutex_lock(&mtd_partitions_mutex);
|
||||||
|
list_add_tail(&slave->node, &master->partitions);
|
||||||
|
mutex_unlock(&mtd_partitions_mutex);
|
||||||
|
|
||||||
|
add_mtd_device(slave);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(OF_CONTROL) */
|
||||||
|
|
||||||
#ifndef __UBOOT__
|
#ifndef __UBOOT__
|
||||||
static DEFINE_SPINLOCK(part_parser_lock);
|
static DEFINE_SPINLOCK(part_parser_lock);
|
||||||
static LIST_HEAD(part_parsers);
|
static LIST_HEAD(part_parsers);
|
||||||
|
|
|
@ -581,6 +581,16 @@ static inline int del_mtd_partitions(struct mtd_info *mtd)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_MTD_PARTITIONS) && CONFIG_IS_ENABLED(DM) && \
|
||||||
|
CONFIG_IS_ENABLED(OF_CONTROL)
|
||||||
|
int add_mtd_partitions_of(struct mtd_info *master);
|
||||||
|
#else
|
||||||
|
static inline int add_mtd_partitions_of(struct mtd_info *master)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct mtd_info *__mtd_next_device(int i);
|
struct mtd_info *__mtd_next_device(int i);
|
||||||
#define mtd_for_each_device(mtd) \
|
#define mtd_for_each_device(mtd) \
|
||||||
for ((mtd) = __mtd_next_device(0); \
|
for ((mtd) = __mtd_next_device(0); \
|
||||||
|
|
Loading…
Add table
Reference in a new issue