common: command: Rework the 'cmd is repeatable' logic
[oweals/u-boot.git] / cmd / mmc.c
index 58fdc36f084ced3eb61554f874aea21c68c5c33d..8bc3648193cf33a26d0376867cad5dfc3028bd22 100644 (file)
--- a/cmd/mmc.c
+++ b/cmd/mmc.c
@@ -1,14 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2003
  * Kyle Harris, kharris@nexus-tech.net
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <command.h>
 #include <console.h>
 #include <mmc.h>
+#include <sparse_format.h>
+#include <image-sparse.h>
 
 static int curr_device = -1;
 
@@ -100,10 +101,19 @@ static struct mmc *init_mmc_device(int dev, bool force_init)
                return NULL;
        }
 
+       if (!mmc_getcd(mmc))
+               force_init = true;
+
        if (force_init)
                mmc->has_init = 0;
        if (mmc_init(mmc))
                return NULL;
+
+#ifdef CONFIG_BLOCK_CACHE
+       struct blk_desc *bd = mmc_get_blk_desc(mmc);
+       blkcache_invalidate(bd->if_type, bd->devnum);
+#endif
+
        return mmc;
 }
 static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
@@ -127,7 +137,7 @@ static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
        return CMD_RET_SUCCESS;
 }
 
-#ifdef CONFIG_SUPPORT_EMMC_RPMB
+#if CONFIG_IS_ENABLED(CMD_MMC_RPMB)
 static int confirm_key_prog(void)
 {
        puts("Warning: Programming authentication key can be done only once !\n"
@@ -246,7 +256,7 @@ static int do_mmcrpmb(cmd_tbl_t *cmdtp, int flag,
 
        if (cp == NULL || argc > cp->maxargs)
                return CMD_RET_USAGE;
-       if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
+       if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
                return CMD_RET_SUCCESS;
 
        mmc = init_mmc_device(curr_device, false);
@@ -307,6 +317,71 @@ static int do_mmc_read(cmd_tbl_t *cmdtp, int flag,
        return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
 }
 
+#if CONFIG_IS_ENABLED(CMD_MMC_SWRITE)
+static lbaint_t mmc_sparse_write(struct sparse_storage *info, lbaint_t blk,
+                                lbaint_t blkcnt, const void *buffer)
+{
+       struct blk_desc *dev_desc = info->priv;
+
+       return blk_dwrite(dev_desc, blk, blkcnt, buffer);
+}
+
+static lbaint_t mmc_sparse_reserve(struct sparse_storage *info,
+                                  lbaint_t blk, lbaint_t blkcnt)
+{
+       return blkcnt;
+}
+
+static int do_mmc_sparse_write(cmd_tbl_t *cmdtp, int flag,
+                              int argc, char * const argv[])
+{
+       struct sparse_storage sparse;
+       struct blk_desc *dev_desc;
+       struct mmc *mmc;
+       char dest[11];
+       void *addr;
+       u32 blk;
+
+       if (argc != 3)
+               return CMD_RET_USAGE;
+
+       addr = (void *)simple_strtoul(argv[1], NULL, 16);
+       blk = simple_strtoul(argv[2], NULL, 16);
+
+       if (!is_sparse_image(addr)) {
+               printf("Not a sparse image\n");
+               return CMD_RET_FAILURE;
+       }
+
+       mmc = init_mmc_device(curr_device, false);
+       if (!mmc)
+               return CMD_RET_FAILURE;
+
+       printf("\nMMC Sparse write: dev # %d, block # %d ... ",
+              curr_device, blk);
+
+       if (mmc_getwp(mmc) == 1) {
+               printf("Error: card is write protected!\n");
+               return CMD_RET_FAILURE;
+       }
+
+       dev_desc = mmc_get_blk_desc(mmc);
+       sparse.priv = dev_desc;
+       sparse.blksz = 512;
+       sparse.start = blk;
+       sparse.size = dev_desc->lba - blk;
+       sparse.write = mmc_sparse_write;
+       sparse.reserve = mmc_sparse_reserve;
+       sparse.mssg = NULL;
+       sprintf(dest, "0x" LBAF, sparse.start * sparse.blksz);
+
+       if (write_sparse_image(&sparse, dest, addr, NULL))
+               return CMD_RET_FAILURE;
+       else
+               return CMD_RET_SUCCESS;
+}
+#endif
+
 #if CONFIG_IS_ENABLED(MMC_WRITE)
 static int do_mmc_write(cmd_tbl_t *cmdtp, int flag,
                        int argc, char * const argv[])
@@ -803,6 +878,9 @@ static cmd_tbl_t cmd_mmc[] = {
 #if CONFIG_IS_ENABLED(MMC_WRITE)
        U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""),
        U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""),
+#endif
+#if CONFIG_IS_ENABLED(CMD_MMC_SWRITE)
+       U_BOOT_CMD_MKENT(swrite, 3, 0, do_mmc_sparse_write, "", ""),
 #endif
        U_BOOT_CMD_MKENT(rescan, 1, 1, do_mmc_rescan, "", ""),
        U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
@@ -817,7 +895,7 @@ static cmd_tbl_t cmd_mmc[] = {
        U_BOOT_CMD_MKENT(partconf, 5, 0, do_mmc_partconf, "", ""),
        U_BOOT_CMD_MKENT(rst-function, 3, 0, do_mmc_rst_func, "", ""),
 #endif
-#ifdef CONFIG_SUPPORT_EMMC_RPMB
+#if CONFIG_IS_ENABLED(CMD_MMC_RPMB)
        U_BOOT_CMD_MKENT(rpmb, CONFIG_SYS_MAXARGS, 1, do_mmcrpmb, "", ""),
 #endif
        U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""),
@@ -838,7 +916,7 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
        if (cp == NULL || argc > cp->maxargs)
                return CMD_RET_USAGE;
-       if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
+       if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
                return CMD_RET_SUCCESS;
 
        if (curr_device < 0) {
@@ -858,11 +936,15 @@ U_BOOT_CMD(
        "info - display info of the current MMC device\n"
        "mmc read addr blk# cnt\n"
        "mmc write addr blk# cnt\n"
+#if CONFIG_IS_ENABLED(CMD_MMC_SWRITE)
+       "mmc swrite addr blk#\n"
+#endif
        "mmc erase blk# cnt\n"
        "mmc rescan\n"
        "mmc part - lists available partition on current mmc device\n"
        "mmc dev [dev] [part] - show or set current mmc device [partition]\n"
        "mmc list - lists available devices\n"
+#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
        "mmc hwpartition [args...] - does hardware partitioning\n"
        "  arguments (sizes in 512-byte blocks):\n"
        "    [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes\n"
@@ -870,6 +952,7 @@ U_BOOT_CMD(
        "    [check|set|complete] - mode, complete set partitioning completed\n"
        "  WARNING: Partitioning is a write-once setting once it is set to complete.\n"
        "  Power cycling is required to initialize partitions after set to complete.\n"
+#endif
 #ifdef CONFIG_SUPPORT_EMMC_BOOT
        "mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode\n"
        " - Set the BOOT_BUS_WIDTH field of the specified device\n"
@@ -881,7 +964,7 @@ U_BOOT_CMD(
        " - Change the RST_n_FUNCTION field of the specified device\n"
        "   WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.\n"
 #endif
-#ifdef CONFIG_SUPPORT_EMMC_RPMB
+#if CONFIG_IS_ENABLED(CMD_MMC_RPMB)
        "mmc rpmb read addr blk# cnt [address of auth-key] - block size is 256 bytes\n"
        "mmc rpmb write addr blk# cnt <address of auth-key> - block size is 256 bytes\n"
        "mmc rpmb key <address of auth-key> - program the RPMB authentication key.\n"