mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +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);
|
||||
}
|
||||
|
||||
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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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); \
|
||||
|
|
Loading…
Reference in a new issue