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:
Marek Behún 2021-05-26 14:08:19 +02:00 committed by Jagan Teki
parent 0e116bea52
commit dc339bf784
3 changed files with 135 additions and 44 deletions

View file

@ -198,53 +198,11 @@ static void mtd_del_all_parts(void)
} while (ret > 0);
}
int mtd_probe_devices(void)
static int parse_mtdparts(const char *mtdparts, const char *mtdids)
{
static char *old_mtdparts;
static char *old_mtdids;
const char *mtdparts = get_mtdparts();
const char *mtdids = get_mtdids();
const char *mtdparts_next = mtdparts;
const char *mtdparts_next;
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 */
if (!strncmp(mtdparts, "mtdparts=", sizeof("mtdparts=") - 1))
mtdparts += 9;
@ -343,6 +301,66 @@ int mtd_probe_devices(void)
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
* parts registration loop.

View file

@ -892,6 +892,69 @@ int add_mtd_partitions(struct mtd_info *master,
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__
static DEFINE_SPINLOCK(part_parser_lock);
static LIST_HEAD(part_parsers);

View file

@ -581,6 +581,16 @@ static inline int del_mtd_partitions(struct mtd_info *mtd)
}
#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);
#define mtd_for_each_device(mtd) \
for ((mtd) = __mtd_next_device(0); \