From ee02543561d4d776b15ad1ad2f6430b361414102 Mon Sep 17 00:00:00 2001 From: Stephen Carlson Date: Tue, 17 Aug 2021 12:46:40 -0700 Subject: [PATCH 1/6] drivers: mmc: Add wait_dat0 support for Freescale eSDHC driver Adds an implementation of the wait_dat0 MMC operation for the Freescale eSHDC driver, allowing the driver to continue when the card is ready rather than waiting for the worst case time on each MMC switch operation. Signed-off-by: Stephen Carlson Reviewed-by: Jaehoon Chung Signed-off-by: Jaehoon Chung --- drivers/mmc/fsl_esdhc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index ebb307e950..05a6d0ce15 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -1138,6 +1139,20 @@ int fsl_esdhc_hs400_prepare_ddr(struct udevice *dev) return 0; } +static int fsl_esdhc_wait_dat0(struct udevice *dev, int state, + int timeout_us) +{ + int ret; + u32 tmp; + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + struct fsl_esdhc *regs = priv->esdhc_regs; + + ret = readx_poll_timeout(esdhc_read32, ®s->prsstat, tmp, + !!(tmp & PRSSTAT_DAT0) == !!state, + timeout_us); + return ret; +} + static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, @@ -1147,6 +1162,7 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { #endif .reinit = fsl_esdhc_reinit, .hs400_prepare_ddr = fsl_esdhc_hs400_prepare_ddr, + .wait_dat0 = fsl_esdhc_wait_dat0, }; static const struct udevice_id fsl_esdhc_ids[] = { From 40e6f52454fc9adb6269ef8089c1fd2ded85fee8 Mon Sep 17 00:00:00 2001 From: Stephen Carlson Date: Tue, 17 Aug 2021 12:46:41 -0700 Subject: [PATCH 2/6] drivers: mmc: Add wait_dat0 support for sdhci driver Adds an implementation of the wait_dat0 MMC operation for the DM SDHCI driver, allowing the driver to continue when the card is ready rather than waiting for the worst case time on each MMC switch operation. Signed-off-by: Stephen Carlson Signed-off-by: Jaehoon Chung --- drivers/mmc/sdhci.c | 20 ++++++++++++++++++++ include/sdhci.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 03bfd9d18a..766e4a6b0c 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -780,6 +780,25 @@ static int sdhci_get_cd(struct udevice *dev) return value; } +static int sdhci_wait_dat0(struct udevice *dev, int state, + int timeout_us) +{ + int tmp; + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct sdhci_host *host = mmc->priv; + unsigned long timeout = timer_get_us() + timeout_us; + + // readx_poll_timeout is unsuitable because sdhci_readl accepts + // two arguments + do { + tmp = sdhci_readl(host, SDHCI_PRESENT_STATE); + if (!!(tmp & SDHCI_DATA_0_LVL_MASK) == !!state) + return 0; + } while (!timeout_us || !time_after(timer_get_us(), timeout)); + + return -ETIMEDOUT; +} + const struct dm_mmc_ops sdhci_ops = { .send_cmd = sdhci_send_command, .set_ios = sdhci_set_ios, @@ -788,6 +807,7 @@ const struct dm_mmc_ops sdhci_ops = { #ifdef MMC_SUPPORTS_TUNING .execute_tuning = sdhci_execute_tuning, #endif + .wait_dat0 = sdhci_wait_dat0, }; #else static const struct mmc_ops sdhci_ops = { diff --git a/include/sdhci.h b/include/sdhci.h index 44a0d84e5a..c718dd7206 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -65,6 +65,8 @@ #define SDHCI_CARD_STATE_STABLE BIT(17) #define SDHCI_CARD_DETECT_PIN_LEVEL BIT(18) #define SDHCI_WRITE_PROTECT BIT(19) +#define SDHCI_DATA_LVL_MASK 0x00F00000 +#define SDHCI_DATA_0_LVL_MASK BIT(20) #define SDHCI_HOST_CONTROL 0x28 #define SDHCI_CTRL_LED BIT(0) From f702dc1e1f123e9dcd4048d180cdc33b3f58c62d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 15 Sep 2021 11:43:13 +0200 Subject: [PATCH 3/6] cmd: mmc: Support mmc hwpartition user enh start - Add option to extend the hardware partition to the maximum size by using the '-' dash sign instead of $cnt parameter. This is useful in case we want to switch the entire eMMC user area into pSLC mode, especially in case the device may be populated with different size eMMCs. With this change, we do not have to calculate the number of blocks of the user area manually. To switch the pSLC mode for user area, use e.g. the following. WARNING: This is a one-time irreversible change. => mmc hwpartition user enh 0 - wrrel on complete Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Jaehoon Chung Cc: Peng Fan Cc: Stefano Babic Signed-off-by: Jaehoon Chung --- cmd/mmc.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/cmd/mmc.c b/cmd/mmc.c index f1e30d0cf6..64e6be7280 100644 --- a/cmd/mmc.c +++ b/cmd/mmc.c @@ -593,7 +593,33 @@ static int do_mmc_list(struct cmd_tbl *cmdtp, int flag, } #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) -static int parse_hwpart_user(struct mmc_hwpart_conf *pconf, +static void parse_hwpart_user_enh_size(struct mmc *mmc, + struct mmc_hwpart_conf *pconf, + char *argv) +{ + int ret; + + pconf->user.enh_size = 0; + + if (!strcmp(argv, "-")) { /* The rest of eMMC */ + ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); + ret = mmc_send_ext_csd(mmc, ext_csd); + if (ret) + return; + /* This value is in 512B block units */ + pconf->user.enh_size = + ((ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 2] << 16) + + (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 1] << 8) + + ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]) * 1024 * + ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * + ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; + pconf->user.enh_size -= pconf->user.enh_start; + } else { + pconf->user.enh_size = dectoul(argv, NULL); + } +} + +static int parse_hwpart_user(struct mmc *mmc, struct mmc_hwpart_conf *pconf, int argc, char *const argv[]) { int i = 0; @@ -606,8 +632,7 @@ static int parse_hwpart_user(struct mmc_hwpart_conf *pconf, return -1; pconf->user.enh_start = dectoul(argv[i + 1], NULL); - pconf->user.enh_size = - dectoul(argv[i + 2], NULL); + parse_hwpart_user_enh_size(mmc, pconf, argv[i + 2]); i += 3; } else if (!strcmp(argv[i], "wrrel")) { if (i + 1 >= argc) @@ -679,7 +704,7 @@ static int do_mmc_hwpartition(struct cmd_tbl *cmdtp, int flag, while (i < argc) { if (!strcmp(argv[i], "user")) { i++; - r = parse_hwpart_user(&pconf, argc-i, &argv[i]); + r = parse_hwpart_user(mmc, &pconf, argc - i, &argv[i]); if (r < 0) return CMD_RET_USAGE; i += r; From 0d453c84bae95174ca3bd94c72a46112580b24c8 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 24 Sep 2021 09:23:34 +0900 Subject: [PATCH 4/6] cmd: mmc: check whether card is SD or eMMC before hwpartition It doesn't need to follow more sequence to do the hwparititioning, because SD doesn't support hwpartitioning feature. Signed-off-by: Jaehoon Chung Reviewed-by: Peng Fan Signed-off-by: Jaehoon Chung --- cmd/mmc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/mmc.c b/cmd/mmc.c index 64e6be7280..96d81ffdf3 100644 --- a/cmd/mmc.c +++ b/cmd/mmc.c @@ -698,6 +698,11 @@ static int do_mmc_hwpartition(struct cmd_tbl *cmdtp, int flag, if (!mmc) return CMD_RET_FAILURE; + if (IS_SD(mmc)) { + puts("SD doesn't support partitioning\n"); + return CMD_RET_FAILURE; + } + if (argc < 1) return CMD_RET_USAGE; i = 1; From 44645f87de513468a8c8082d057704df0495d7a4 Mon Sep 17 00:00:00 2001 From: Kirill Kapranov Date: Sat, 9 Oct 2021 23:49:59 +0300 Subject: [PATCH 5/6] mmc: Fix mmc_switch excessive timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix branching to avoid premature falling back on a long timeout instead of continuation of the initialization attempt. Clear of the comment to avoid the ambiguity. Signed-off-by: Kirill Kapranov Cc: Pantelis Antoniou Cc: Ye Li Reviewed-by: Marek BehĂșn Tested-by: Marek BehĂșn Signed-off-by: Jaehoon Chung --- drivers/mmc/mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index ba54b19c14..4d9871d69f 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -819,11 +819,11 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, return ret; /* - * In cases when not allowed to poll by using CMD13 or because we aren't + * In cases when neiter allowed to poll by using CMD13 nor we are * capable of polling by using mmc_wait_dat0, then rely on waiting the * stated timeout to be sufficient. */ - if (ret == -ENOSYS || !send_status) { + if (ret == -ENOSYS && !send_status) { mdelay(timeout_ms); return 0; } From c95b0297e95613fc68b1d92118ee64720d142f8c Mon Sep 17 00:00:00 2001 From: Usama Arif Date: Tue, 19 Oct 2021 15:49:48 +0100 Subject: [PATCH 6/6] mmc: arm_pl180_mmci: Enable HWFC for specific versions of MCI There are 4 registers (PERIPHID{0-3}) that contain the ID of MCI. For MMCs' with peripheral id 0x02041180 and 0x03041180, H/W flow control needs to be enabled for multi block writes (MMC CMD 18). Signed-off-by: Usama Arif Reviewed-by: Jaehoon Chung Signed-off-by: Jaehoon Chung --- drivers/mmc/arm_pl180_mmci.c | 14 ++++++++++++++ drivers/mmc/arm_pl180_mmci.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index f99b5f997e..9c5d48e90c 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -282,6 +282,14 @@ static int host_request(struct mmc *dev, return result; } +static int check_peripheral_id(struct pl180_mmc_host *host, u32 periph_id) +{ + return readl(&host->base->periph_id0) == (periph_id & 0xFF) && + readl(&host->base->periph_id1) == ((periph_id >> 8) & 0xFF) && + readl(&host->base->periph_id2) == ((periph_id >> 16) & 0xFF) && + readl(&host->base->periph_id3) == ((periph_id >> 24) & 0xFF); +} + static int host_set_ios(struct mmc *dev) { struct pl180_mmc_host *host = dev->priv; @@ -337,6 +345,12 @@ static int host_set_ios(struct mmc *dev) sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK); sdi_clkcr |= buswidth; } + /* For MMCs' with peripheral id 0x02041180 and 0x03041180, H/W flow control + * needs to be enabled for multi block writes (MMC CMD 18). + */ + if (check_peripheral_id(host, 0x02041180) || + check_peripheral_id(host, 0x03041180)) + sdi_clkcr |= SDI_CLKCR_HWFCEN; writel(sdi_clkcr, &host->base->clock); udelay(CLK_CHANGE_DELAY); diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h index 15c29beadb..fca15910a8 100644 --- a/drivers/mmc/arm_pl180_mmci.h +++ b/drivers/mmc/arm_pl180_mmci.h @@ -43,6 +43,7 @@ #define SDI_CLKCR_CLKEN 0x00000100 #define SDI_CLKCR_PWRSAV 0x00000200 #define SDI_CLKCR_BYPASS 0x00000400 +#define SDI_CLKCR_HWFCEN 0x00001000 #define SDI_CLKCR_WIDBUS_MASK 0x00001800 #define SDI_CLKCR_WIDBUS_1 0x00000000 #define SDI_CLKCR_WIDBUS_4 0x00000800