From eeb739a6fde6e926b389b253668b2a8fd09a58c7 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Thu, 26 Jan 2023 10:24:17 +0100 Subject: mmc: Check support for TRIM operations When secure/insecure TRIM operations are supported. When used as erase command argument it applies the erase operation to write blocks instead of erase groups. Signed-off-by: Loic Poulain Reviewed-by: Simon Glass Reviewed-by: Jaehoon Chung --- drivers/mmc/mmc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index dde251c87bc..1af6af82e6b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2432,6 +2432,9 @@ static int mmc_startup_v4(struct mmc *mmc) mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; + mmc->can_trim = + !!(ext_csd[EXT_CSD_SEC_FEATURE] & EXT_CSD_SEC_FEATURE_TRIM_EN); + return 0; error: if (mmc->ext_csd) { -- cgit v1.3.1 From 67642c1254fc7b1392c2745ead609255345f2d25 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Thu, 26 Jan 2023 10:24:18 +0100 Subject: mmc: erase: Use TRIM erase when available The default erase command applies on erase group unit, and simply round down to erase group size. When the start block is not aligned to erase group size (e.g. erasing partition) it causes unwanted erasing of the previous blocks, part of the same erase group (e.g. owned by other logical partition, or by the partition table itself). To prevent this issue, a simple solution is to use TRIM as argument of the Erase command, which is usually supported with eMMC > 4.0, and allow to apply erase operation to write blocks instead of erase group Signed-off-by: Loic Poulain Reviewed-by: Simon Glass --- drivers/mmc/mmc_write.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index 5b7aeeb0121..a6f93380dd0 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -15,7 +15,7 @@ #include #include "mmc_private.h" -static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) +static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt, u32 args) { struct mmc_cmd cmd; ulong end; @@ -52,7 +52,7 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) goto err_out; cmd.cmdidx = MMC_CMD_ERASE; - cmd.cmdarg = MMC_ERASE_ARG; + cmd.cmdarg = args ? args : MMC_ERASE_ARG; cmd.resp_type = MMC_RSP_R1b; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -77,7 +77,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) #endif int dev_num = block_dev->devnum; int err = 0; - u32 start_rem, blkcnt_rem; + u32 start_rem, blkcnt_rem, erase_args = 0; struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; int timeout_ms = 1000; @@ -97,13 +97,25 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) */ err = div_u64_rem(start, mmc->erase_grp_size, &start_rem); err = div_u64_rem(blkcnt, mmc->erase_grp_size, &blkcnt_rem); - if (start_rem || blkcnt_rem) - printf("\n\nCaution! Your devices Erase group is 0x%x\n" - "The erase range would be change to " - "0x" LBAF "~0x" LBAF "\n\n", - mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1), - ((start + blkcnt + mmc->erase_grp_size - 1) - & ~(mmc->erase_grp_size - 1)) - 1); + if (start_rem || blkcnt_rem) { + if (mmc->can_trim) { + /* Trim function applies the erase operation to write + * blocks instead of erase groups. + */ + erase_args = MMC_TRIM_ARG; + } else { + /* The card ignores all LSB's below the erase group + * size, rounding down the addess to a erase group + * boundary. + */ + printf("\n\nCaution! Your devices Erase group is 0x%x\n" + "The erase range would be change to " + "0x" LBAF "~0x" LBAF "\n\n", + mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1), + ((start + blkcnt + mmc->erase_grp_size - 1) + & ~(mmc->erase_grp_size - 1)) - 1); + } + } while (blk < blkcnt) { if (IS_SD(mmc) && mmc->ssr.au) { @@ -113,7 +125,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? mmc->erase_grp_size : (blkcnt - blk); } - err = mmc_erase_t(mmc, start + blk, blk_r); + err = mmc_erase_t(mmc, start + blk, blk_r, erase_args); if (err) break; -- cgit v1.3.1 From 46beaec835d9828ceaafe070401cb4efb80b4fe3 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 10 Feb 2023 13:23:50 +0100 Subject: mmc: mv_sdhci: Simplify call to sdhci_mvebu_mbus_config() This driver already depends on CONFIG_ARCH_MVEBU, so there is no need to have some checks for this Kconfig symbol in the driver itself. Let's remove these superfluous checks. Signed-off-by: Stefan Roese Cc: Tom Rini Cc: Simon Glass Cc: Peng Fan Cc: Jaehoon Chung Reviewed-by: Jaehoon Chung --- drivers/mmc/mv_sdhci.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c index 336ebf14102..50d03b703ed 100644 --- a/drivers/mmc/mv_sdhci.c +++ b/drivers/mmc/mv_sdhci.c @@ -64,10 +64,8 @@ int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks) host->ops = &mv_ops; #endif - if (CONFIG_IS_ENABLED(ARCH_MVEBU)) { - /* Configure SDHCI MBUS mbus bridge windows */ - sdhci_mvebu_mbus_config((void __iomem *)regbase); - } + /* Configure SDHCI MBUS mbus bridge windows */ + sdhci_mvebu_mbus_config((void __iomem *)regbase); return add_sdhci(host, 0, min_clk); } @@ -103,10 +101,8 @@ static int mv_sdhci_probe(struct udevice *dev) if (ret) return ret; - if (CONFIG_IS_ENABLED(ARCH_MVEBU)) { - /* Configure SDHCI MBUS mbus bridge windows */ - sdhci_mvebu_mbus_config(host->ioaddr); - } + /* Configure SDHCI MBUS mbus bridge windows */ + sdhci_mvebu_mbus_config(host->ioaddr); upriv->mmc = host->mmc; -- cgit v1.3.1 From c06a568473d46f5cab64591fde7b56da1facb7c2 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 10 Feb 2023 13:23:51 +0100 Subject: mmc: mv_sdhci: Remove CONFIG_MMC_SDHCI_IO_ACCESSORS support CONFIG_MMC_SDHCI_IO_ACCESSORS is not supported and/or used by this driver so let's remove these unused parts completely. Signed-off-by: Stefan Roese Cc: Tom Rini Cc: Simon Glass Cc: Peng Fan Cc: Jaehoon Chung Reviewed-by: Jaehoon Chung --- drivers/mmc/mv_sdhci.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c index 50d03b703ed..42fa735f316 100644 --- a/drivers/mmc/mv_sdhci.c +++ b/drivers/mmc/mv_sdhci.c @@ -42,10 +42,6 @@ static void sdhci_mvebu_mbus_config(void __iomem *base) #ifndef CONFIG_DM_MMC -#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS -static struct sdhci_ops mv_ops; -#endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */ - int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks) { struct sdhci_host *host = NULL; @@ -59,10 +55,6 @@ int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks) host->ioaddr = (void *)regbase; host->quirks = quirks; host->max_clk = max_clk; -#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS - memset(&mv_ops, 0, sizeof(struct sdhci_ops)); - host->ops = &mv_ops; -#endif /* Configure SDHCI MBUS mbus bridge windows */ sdhci_mvebu_mbus_config((void __iomem *)regbase); -- cgit v1.3.1 From 8af21b094d92f671bd2f6483a15be5b3c33baca6 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 10 Feb 2023 13:23:52 +0100 Subject: mmc: mv_sdhci: Depend on DM_MMC All build targets using this driver already use DM_MMC. So let's depend this driver on this Kconfig symbol and remove the non-DM driver part. Signed-off-by: Stefan Roese Cc: Tom Rini Cc: Simon Glass Cc: Peng Fan Cc: Jaehoon Chung Reviewed-by: Simon Glass Reviewed-by: Jaehoon Chung --- drivers/mmc/Kconfig | 1 + drivers/mmc/mv_sdhci.c | 39 +++++++-------------------------------- 2 files changed, 8 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 80641e13930..59fb0fb50fb 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -621,6 +621,7 @@ config MMC_SDHCI_MV bool "SDHCI support on Marvell platform" depends on ARCH_MVEBU depends on MMC_SDHCI + depends on DM_MMC help This selects the Secure Digital Host Controller Interface on Marvell platform. diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c index 42fa735f316..dbdd671c88b 100644 --- a/drivers/mmc/mv_sdhci.c +++ b/drivers/mmc/mv_sdhci.c @@ -15,6 +15,13 @@ #define SDHCI_WINDOW_CTRL(win) (0x4080 + ((win) << 4)) #define SDHCI_WINDOW_BASE(win) (0x4084 + ((win) << 4)) +DECLARE_GLOBAL_DATA_PTR; + +struct mv_sdhci_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + static void sdhci_mvebu_mbus_config(void __iomem *base) { const struct mbus_dram_target_info *dram; @@ -40,37 +47,6 @@ static void sdhci_mvebu_mbus_config(void __iomem *base) } } -#ifndef CONFIG_DM_MMC - -int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks) -{ - struct sdhci_host *host = NULL; - host = calloc(1, sizeof(*host)); - if (!host) { - printf("sdh_host malloc fail!\n"); - return -ENOMEM; - } - - host->name = MVSDH_NAME; - host->ioaddr = (void *)regbase; - host->quirks = quirks; - host->max_clk = max_clk; - - /* Configure SDHCI MBUS mbus bridge windows */ - sdhci_mvebu_mbus_config((void __iomem *)regbase); - - return add_sdhci(host, 0, min_clk); -} - -#else - -DECLARE_GLOBAL_DATA_PTR; - -struct mv_sdhci_plat { - struct mmc_config cfg; - struct mmc mmc; -}; - static int mv_sdhci_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); @@ -123,4 +99,3 @@ U_BOOT_DRIVER(mv_sdhci_drv) = { .priv_auto = sizeof(struct sdhci_host), .plat_auto = sizeof(struct mv_sdhci_plat), }; -#endif /* CONFIG_DM_MMC */ -- cgit v1.3.1