[PATCH u-boot-dm + u-boot-spi v2 3/7] mtd: add support for parsing partitions defined in OF
Pali Rohár
pali at kernel.org
Wed Feb 10 10:54:37 CET 2021
On Tuesday 09 February 2021 15:44:48 Marek Behún wrote:
> 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 at nic.cz>
> Cc: Simon Glass <sjg at chromium.org>
> Cc: Heiko Schocher <hs at denx.de>
> Cc: Jagan Teki <jagan at amarulasolutions.com>
> ---
> drivers/mtd/mtd_uboot.c | 106 +++++++++++++++++++++++-----------------
> drivers/mtd/mtdpart.c | 60 +++++++++++++++++++++++
> include/linux/mtd/mtd.h | 9 ++++
> 3 files changed, 131 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c
> index 9360d4ed17..7fb72eb1f4 100644
> --- a/drivers/mtd/mtd_uboot.c
> +++ b/drivers/mtd/mtd_uboot.c
> @@ -197,53 +197,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;
> @@ -342,6 +300,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.
> diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
> index d064ac3048..2ebbf74d92 100644
> --- a/drivers/mtd/mtdpart.c
> +++ b/drivers/mtd/mtdpart.c
> @@ -892,6 +892,66 @@ int add_mtd_partitions(struct mtd_info *master,
> return 0;
> }
>
> +#ifdef CONFIG_DM
> +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;
> +
> + if (ofnode_get_property(child, "compatible", NULL))
> + continue;
I think this check is incorrect. Partition node may have another
"compatible" property with another node. Linux kernel supports defining
partitions on partitions. E.g.
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition at 0 {
label = "bootloader";
reg = <0x000000 0x100000>;
read-only;
};
firmware at 100000 {
compatible = "brcm,trx";
label = "firmware";
reg = <0x100000 0xe00000>;
};
calibration at f00000 {
compatible = "fixed-partitions";
label = "calibration";
reg = <0xf00000 0x100000>;
ranges = <0 0xf00000 0x100000>;
#address-cells = <1>;
#size-cells = <1>;
partition at 0 {
label = "wifi0";
reg = <0x000000 0x080000>;
};
partition at 80000 {
label = "wifi1";
reg = <0x080000 0x080000>;
};
};
};
See Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml
> +
> + 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");
> +
> + if (ofnode_read_bool(child, "read-only"))
> + part.mask_flags |= MTD_WRITEABLE;
> + if (ofnode_read_bool(child, "lock"))
> + part.mask_flags |= MTD_POWERUP_LOCK;
I would suggest to add some explanation why setting these two mask flags
according to those DT properties is correct as it is not obvious.
mask_flags contains flags which have to be removed from partition.
DT "read-only" means that partition is read-only, so removing writable
is correct. DR "lock" means to *not* unlock the partition at
initialization time and MTD_POWERUP_LOCK means that partition is always
locked after reset and needs to be (always) unlocked. So masking this
flag means that it is never unlocked.
> +
> + 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
> +
> #ifndef __UBOOT__
> static DEFINE_SPINLOCK(part_parser_lock);
> static LIST_HEAD(part_parsers);
> diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> index 927854950a..ec9331b804 100644
> --- a/include/linux/mtd/mtd.h
> +++ b/include/linux/mtd/mtd.h
> @@ -581,6 +581,15 @@ static inline int del_mtd_partitions(struct mtd_info *mtd)
> }
> #endif
>
> +#if defined(CONFIG_MTD_PARTITIONS) && defined(CONFIG_DM)
> +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); \
> --
> 2.26.2
>
More information about the U-Boot
mailing list