stm32mp: stm32prog: add MMC device
authorPatrick Delaunay <patrick.delaunay@st.com>
Wed, 18 Mar 2020 08:24:51 +0000 (09:24 +0100)
committerPatrick Delaunay <patrick.delaunay@st.com>
Thu, 14 May 2020 07:02:12 +0000 (09:02 +0200)
Add support of MMC device (based on DFU_MMC backend)
for SD card and eMMC update.

Create a GPT partitioning on the device.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
Reviewed-by: Patrice Chotard <patrice.chotard@st.com>
Reviewed-by: Patrice Chotard <patrice.chotard@st.com>
arch/arm/mach-stm32mp/Kconfig
arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
configs/stm32mp15_basic_defconfig
configs/stm32mp15_trusted_defconfig

index 00e02a318e3c276f38d316e5ad3b6d1282a8addb..bf573acff37ec779cbe28fe54921e4ca1b1d09df 100644 (file)
@@ -112,6 +112,9 @@ config CMD_STM32PROG
        select DFU
        select DFU_RAM
        select DFU_VIRT
+       select PARTITION_TYPE_GUID
+       imply CMD_GPT if MMC
+       imply DFU_MMC if MMC
        help
                activate a specific command stm32prog for STM32MP soc family
                witch update the device with the tools STM32CubeProgrammer,
index 11fe4790722b80f85069d32586280c2ff0924017..feb83670b581d3fa8712e7a6f2388f3c41bed4a5 100644 (file)
@@ -7,6 +7,7 @@
 #include <console.h>
 #include <dfu.h>
 #include <malloc.h>
+#include <mmc.h>
 #include <dm/uclass.h>
 #include <linux/list.h>
 #include <linux/list_sort.h>
@@ -14,6 +15,9 @@
 
 #include "stm32prog.h"
 
+/* Primary GPT header size for 128 entries : 17kB = 34 LBA of 512B */
+#define GPT_HEADER_SZ  34
+
 #define OPT_SELECT     BIT(0)
 #define OPT_EMPTY      BIT(1)
 
 
 #define ALT_BUF_LEN                    SZ_1K
 
+#define ROOTFS_MMC0_UUID \
+       EFI_GUID(0xE91C4E10, 0x16E6, 0x4C0E, \
+                0xBD, 0x0E, 0x77, 0xBE, 0xCF, 0x4A, 0x35, 0x82)
+
+#define ROOTFS_MMC1_UUID \
+       EFI_GUID(0x491F6117, 0x415D, 0x4F53, \
+                0x88, 0xC9, 0x6E, 0x0D, 0xE5, 0x4D, 0xEA, 0xC6)
+
+#define ROOTFS_MMC2_UUID \
+       EFI_GUID(0xFD58F1C7, 0xBE0D, 0x4338, \
+                0x88, 0xE9, 0xAD, 0x8F, 0x05, 0x0A, 0xEB, 0x18)
+
+/* RAW parttion (binary / bootloader) used Linux - reserved UUID */
+#define LINUX_RESERVED_UUID "8DA63339-0007-60C0-C436-083AC8230908"
+
+/*
+ * unique partition guid (uuid) for partition named "rootfs"
+ * on each MMC instance = SD Card or eMMC
+ * allow fixed kernel bootcmd: "rootf=PARTUID=e91c4e10-..."
+ */
+static const efi_guid_t uuid_mmc[3] = {
+       ROOTFS_MMC0_UUID,
+       ROOTFS_MMC1_UUID,
+       ROOTFS_MMC2_UUID
+};
+
 DECLARE_GLOBAL_DATA_PTR;
 
 /* order of column in flash layout file */
@@ -200,6 +230,9 @@ static int parse_ip(struct stm32prog_data *data,
        part->dev_id = 0;
        if (!strcmp(p, "none")) {
                part->target = STM32PROG_NONE;
+       } else if (!strncmp(p, "mmc", 3)) {
+               part->target = STM32PROG_MMC;
+               len = 3;
        } else {
                result = -EINVAL;
        }
@@ -424,16 +457,50 @@ static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
 static int init_device(struct stm32prog_data *data,
                       struct stm32prog_dev_t *dev)
 {
+       struct mmc *mmc = NULL;
        struct blk_desc *block_dev = NULL;
        int part_id;
        u64 first_addr = 0, last_addr = 0;
        struct stm32prog_part_t *part, *next_part;
 
        switch (dev->target) {
+#ifdef CONFIG_MMC
+       case STM32PROG_MMC:
+               mmc = find_mmc_device(dev->dev_id);
+               if (mmc_init(mmc)) {
+                       stm32prog_err("mmc device %d not found", dev->dev_id);
+                       return -ENODEV;
+               }
+               block_dev = mmc_get_blk_desc(mmc);
+               if (!block_dev) {
+                       stm32prog_err("mmc device %d not probed", dev->dev_id);
+                       return -ENODEV;
+               }
+               dev->erase_size = mmc->erase_grp_size * block_dev->blksz;
+               dev->mmc = mmc;
+
+               /* reserve a full erase group for each GTP headers */
+               if (mmc->erase_grp_size > GPT_HEADER_SZ) {
+                       first_addr = dev->erase_size;
+                       last_addr = (u64)(block_dev->lba -
+                                         mmc->erase_grp_size) *
+                                   block_dev->blksz;
+               } else {
+                       first_addr = (u64)GPT_HEADER_SZ * block_dev->blksz;
+                       last_addr = (u64)(block_dev->lba - GPT_HEADER_SZ - 1) *
+                                   block_dev->blksz;
+               }
+               pr_debug("MMC %d: lba=%ld blksz=%ld\n", dev->dev_id,
+                        block_dev->lba, block_dev->blksz);
+               pr_debug(" available address = 0x%llx..0x%llx\n",
+                        first_addr, last_addr);
+               break;
+#endif
        default:
                stm32prog_err("unknown device type = %d", dev->target);
                return -ENODEV;
        }
+       pr_debug(" erase size = 0x%x\n", dev->erase_size);
 
        /* order partition list in offset order */
        list_sort(NULL, &dev->part_list, &part_cmp);
@@ -491,6 +558,12 @@ static int init_device(struct stm32prog_data *data,
                        return -EINVAL;
                }
 
+               if ((part->addr & ((u64)part->dev->erase_size - 1)) != 0) {
+                       stm32prog_err("%s (0x%x): not aligned address : 0x%llx on erase size 0x%x",
+                                     part->name, part->id, part->addr,
+                                     part->dev->erase_size);
+                       return -EINVAL;
+               }
                pr_debug("%02d : %1d %02x %14s %02d %02d.%02d %08llx %08llx",
                         part->part_id, part->option, part->id, part->name,
                         part->part_type, part->target,
@@ -559,6 +632,118 @@ static int treat_partition_list(struct stm32prog_data *data)
        return 0;
 }
 
+static int create_partitions(struct stm32prog_data *data)
+{
+#ifdef CONFIG_MMC
+       int offset = 0;
+       const int buflen = SZ_8K;
+       char *buf;
+       char uuid[UUID_STR_LEN + 1];
+       unsigned char *uuid_bin;
+       unsigned int mmc_id;
+       int i;
+       bool rootfs_found;
+       struct stm32prog_part_t *part;
+
+       buf = malloc(buflen);
+       if (!buf)
+               return -ENOMEM;
+
+       puts("partitions : ");
+       /* initialize the selected device */
+       for (i = 0; i < data->dev_nb; i++) {
+               offset = 0;
+               rootfs_found = false;
+               memset(buf, 0, buflen);
+
+               list_for_each_entry(part, &data->dev[i].part_list, list) {
+                       /* skip Raw Image */
+                       if (part->part_type == RAW_IMAGE)
+                               continue;
+
+                       if (offset + 100 > buflen) {
+                               pr_debug("\n%s: buffer too small, %s skippped",
+                                        __func__, part->name);
+                               continue;
+                       }
+
+                       if (!offset)
+                               offset += sprintf(buf, "gpt write mmc %d \"",
+                                                 data->dev[i].dev_id);
+
+                       offset += snprintf(buf + offset, buflen - offset,
+                                          "name=%s,start=0x%llx,size=0x%llx",
+                                          part->name,
+                                          part->addr,
+                                          part->size);
+
+                       if (part->part_type == PART_BINARY)
+                               offset += snprintf(buf + offset,
+                                                  buflen - offset,
+                                                  ",type="
+                                                  LINUX_RESERVED_UUID);
+                       else
+                               offset += snprintf(buf + offset,
+                                                  buflen - offset,
+                                                  ",type=linux");
+
+                       if (part->part_type == PART_SYSTEM)
+                               offset += snprintf(buf + offset,
+                                                  buflen - offset,
+                                                  ",bootable");
+
+                       if (!rootfs_found && !strcmp(part->name, "rootfs")) {
+                               mmc_id = part->dev_id;
+                               rootfs_found = true;
+                               if (mmc_id < ARRAY_SIZE(uuid_mmc)) {
+                                       uuid_bin =
+                                         (unsigned char *)uuid_mmc[mmc_id].b;
+                                       uuid_bin_to_str(uuid_bin, uuid,
+                                                       UUID_STR_FORMAT_GUID);
+                                       offset += snprintf(buf + offset,
+                                                          buflen - offset,
+                                                          ",uuid=%s", uuid);
+                               }
+                       }
+
+                       offset += snprintf(buf + offset, buflen - offset, ";");
+               }
+
+               if (offset) {
+                       offset += snprintf(buf + offset, buflen - offset, "\"");
+                       pr_debug("\ncmd: %s\n", buf);
+                       if (run_command(buf, 0)) {
+                               stm32prog_err("GPT partitionning fail: %s",
+                                             buf);
+                               free(buf);
+
+                               return -1;
+                       }
+               }
+
+               if (data->dev[i].mmc)
+                       part_init(mmc_get_blk_desc(data->dev[i].mmc));
+
+#ifdef DEBUG
+               sprintf(buf, "gpt verify mmc %d", data->dev[i].dev_id);
+               pr_debug("\ncmd: %s", buf);
+               if (run_command(buf, 0))
+                       printf("fail !\n");
+               else
+                       printf("OK\n");
+
+               sprintf(buf, "part list mmc %d", data->dev[i].dev_id);
+               run_command(buf, 0);
+#endif
+       }
+       puts("done\n");
+
+       free(buf);
+#endif
+
+       return 0;
+}
+
 static int stm32prog_alt_add(struct stm32prog_data *data,
                             struct dfu_entity *dfu,
                             struct stm32prog_part_t *part)
@@ -596,17 +781,30 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
        if (part->part_type == RAW_IMAGE) {
                u64 dfu_size;
 
-               dfu_size = part->size;
+               if (part->dev->target == STM32PROG_MMC)
+                       dfu_size = part->size / part->dev->mmc->read_bl_len;
+               else
+                       dfu_size = part->size;
                offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
                                   "raw 0x0 0x%llx", dfu_size);
        } else {
                offset += snprintf(buf + offset,
                                   ALT_BUF_LEN - offset,
                                   "part");
+               /* dev_id requested by DFU MMC */
+               if (part->target == STM32PROG_MMC)
+                       offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
+                                          " %d", part->dev_id);
                offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
                                   " %d;", part->part_id);
        }
        switch (part->target) {
+#ifdef CONFIG_MMC
+       case STM32PROG_MMC:
+               sprintf(dfustr, "mmc");
+               sprintf(devstr, "%d", part->dev_id);
+               break;
+#endif
        default:
                stm32prog_err("invalid target: %d", part->target);
                return -ENODEV;
@@ -775,6 +973,10 @@ static void stm32prog_devices_init(struct stm32prog_data *data)
                        goto error;
        }
 
+       ret = create_partitions(data);
+       if (ret)
+               goto error;
+
        return;
 
 error:
index b44b6f89afd80782812d7bfdec91c88a1f5b1c44..228a25d37f3f4c8a0ea640fc412fab36c90d3693 100644 (file)
@@ -19,6 +19,7 @@
 
 enum stm32prog_target {
        STM32PROG_NONE,
+       STM32PROG_MMC,
 };
 
 enum stm32prog_link_t {
@@ -64,6 +65,8 @@ enum stm32prog_part_type {
 struct stm32prog_dev_t {
        enum stm32prog_target   target;
        char                    dev_id;
+       u32                     erase_size;
+       struct mmc              *mmc;
        /* list of partition for this device / ordered in offset */
        struct list_head        part_list;
 };
index 65aa3d385fa692792bfbd9df56edaa757c6161cd..c902f10491ab501fe376847fd209320910570ae1 100644 (file)
@@ -34,7 +34,6 @@ CONFIG_CMD_CLK=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_FUSE=y
 CONFIG_CMD_GPIO=y
-CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_MTD=y
@@ -67,7 +66,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
 CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_STM32_ADC=y
-CONFIG_DFU_MMC=y
 CONFIG_DFU_MTD=y
 CONFIG_SET_DFU_ALT_INFO=y
 CONFIG_USB_FUNCTION_FASTBOOT=y
index c8b9947331f208867aa6808feaa83c32502a1505..f01bfa555dab9fd6e0d268cda4921cbf755c223e 100644 (file)
@@ -23,7 +23,6 @@ CONFIG_CMD_CLK=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_FUSE=y
 CONFIG_CMD_GPIO=y
-CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_MTD=y
@@ -54,7 +53,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
 CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_STM32_ADC=y
-CONFIG_DFU_MMC=y
 CONFIG_DFU_MTD=y
 CONFIG_SET_DFU_ALT_INFO=y
 CONFIG_USB_FUNCTION_FASTBOOT=y