瀏覽代碼

Merge tag 'mmc-2021-9-13' of https://source.denx.de/u-boot/custodians/u-boot-mmc

Support using mmc command for enumerating mmc card in a given mode
Fix device_remove in mmc
Fix switch issue with send_status disabled
Drop 1ms delay in fsl_esdhc command sending
Revert "mmc: sdhci: set to INT_DATA_END when there are data"
Tom Rini 2 年之前
父節點
當前提交
7958292f5f
共有 8 個文件被更改,包括 135 次插入25 次删除
  1. 10 0
      cmd/Kconfig
  2. 44 8
      cmd/mmc.c
  3. 47 2
      doc/usage/mmc.rst
  4. 0 7
      drivers/mmc/fsl_esdhc.c
  5. 4 1
      drivers/mmc/mmc-uclass.c
  6. 27 5
      drivers/mmc/mmc.c
  7. 1 2
      drivers/mmc/sdhci.c
  8. 2 0
      include/mmc.h

+ 10 - 0
cmd/Kconfig

@@ -2389,4 +2389,14 @@ config CMD_UBIFS
 	help
 	help
 	  UBIFS is a file system for flash devices which works on top of UBI.
 	  UBIFS is a file system for flash devices which works on top of UBI.
 
 
+config MMC_SPEED_MODE_SET
+	bool "set speed mode using mmc command"
+	depends on CMD_MMC
+	default n
+	help
+	  Enable setting speed mode using mmc rescan and mmc dev commands.
+	  The speed mode is provided as the last argument in these commands
+	  and is indicated using the index from enum bus_mode in
+	  include/mmc.h. A speed mode can be set only if it has already
+	  been enabled in the device tree.
 endmenu
 endmenu

+ 44 - 8
cmd/mmc.c

@@ -120,7 +120,9 @@ static void print_mmcinfo(struct mmc *mmc)
 		}
 		}
 	}
 	}
 }
 }
-static struct mmc *init_mmc_device(int dev, bool force_init)
+
+static struct mmc *__init_mmc_device(int dev, bool force_init,
+				     enum bus_mode speed_mode)
 {
 {
 	struct mmc *mmc;
 	struct mmc *mmc;
 	mmc = find_mmc_device(dev);
 	mmc = find_mmc_device(dev);
@@ -134,6 +136,10 @@ static struct mmc *init_mmc_device(int dev, bool force_init)
 
 
 	if (force_init)
 	if (force_init)
 		mmc->has_init = 0;
 		mmc->has_init = 0;
+
+	if (IS_ENABLED(CONFIG_MMC_SPEED_MODE_SET))
+		mmc->user_speed_mode = speed_mode;
+
 	if (mmc_init(mmc))
 	if (mmc_init(mmc))
 		return NULL;
 		return NULL;
 
 
@@ -145,6 +151,11 @@ static struct mmc *init_mmc_device(int dev, bool force_init)
 	return mmc;
 	return mmc;
 }
 }
 
 
+static struct mmc *init_mmc_device(int dev, bool force_init)
+{
+	return __init_mmc_device(dev, force_init, MMC_MODES_END);
+}
+
 static int do_mmcinfo(struct cmd_tbl *cmdtp, int flag, int argc,
 static int do_mmcinfo(struct cmd_tbl *cmdtp, int flag, int argc,
 		      char *const argv[])
 		      char *const argv[])
 {
 {
@@ -482,8 +493,17 @@ static int do_mmc_rescan(struct cmd_tbl *cmdtp, int flag,
 			 int argc, char *const argv[])
 			 int argc, char *const argv[])
 {
 {
 	struct mmc *mmc;
 	struct mmc *mmc;
+	enum bus_mode speed_mode = MMC_MODES_END;
+
+	if (argc == 1) {
+		mmc = init_mmc_device(curr_device, true);
+	} else if (argc == 2) {
+		speed_mode = (int)dectoul(argv[1], NULL);
+		mmc = __init_mmc_device(curr_device, true, speed_mode);
+	} else {
+		return CMD_RET_USAGE;
+	}
 
 
-	mmc = init_mmc_device(curr_device, true);
 	if (!mmc)
 	if (!mmc)
 		return CMD_RET_FAILURE;
 		return CMD_RET_FAILURE;
 
 
@@ -515,11 +535,14 @@ static int do_mmc_dev(struct cmd_tbl *cmdtp, int flag,
 {
 {
 	int dev, part = 0, ret;
 	int dev, part = 0, ret;
 	struct mmc *mmc;
 	struct mmc *mmc;
+	enum bus_mode speed_mode = MMC_MODES_END;
 
 
 	if (argc == 1) {
 	if (argc == 1) {
 		dev = curr_device;
 		dev = curr_device;
+		mmc = init_mmc_device(dev, true);
 	} else if (argc == 2) {
 	} else if (argc == 2) {
-		dev = dectoul(argv[1], NULL);
+		dev = (int)dectoul(argv[1], NULL);
+		mmc = init_mmc_device(dev, true);
 	} else if (argc == 3) {
 	} else if (argc == 3) {
 		dev = (int)dectoul(argv[1], NULL);
 		dev = (int)dectoul(argv[1], NULL);
 		part = (int)dectoul(argv[2], NULL);
 		part = (int)dectoul(argv[2], NULL);
@@ -528,11 +551,21 @@ static int do_mmc_dev(struct cmd_tbl *cmdtp, int flag,
 			       PART_ACCESS_MASK);
 			       PART_ACCESS_MASK);
 			return CMD_RET_FAILURE;
 			return CMD_RET_FAILURE;
 		}
 		}
+		mmc = init_mmc_device(dev, true);
+	} else if (argc == 4) {
+		dev = (int)dectoul(argv[1], NULL);
+		part = (int)dectoul(argv[2], NULL);
+		if (part > PART_ACCESS_MASK) {
+			printf("#part_num shouldn't be larger than %d\n",
+			       PART_ACCESS_MASK);
+			return CMD_RET_FAILURE;
+		}
+		speed_mode = (int)dectoul(argv[3], NULL);
+		mmc = __init_mmc_device(dev, true, speed_mode);
 	} else {
 	} else {
 		return CMD_RET_USAGE;
 		return CMD_RET_USAGE;
 	}
 	}
 
 
-	mmc = init_mmc_device(dev, true);
 	if (!mmc)
 	if (!mmc)
 		return CMD_RET_FAILURE;
 		return CMD_RET_FAILURE;
 
 
@@ -983,9 +1016,9 @@ static struct cmd_tbl cmd_mmc[] = {
 #if CONFIG_IS_ENABLED(CMD_MMC_SWRITE)
 #if CONFIG_IS_ENABLED(CMD_MMC_SWRITE)
 	U_BOOT_CMD_MKENT(swrite, 3, 0, do_mmc_sparse_write, "", ""),
 	U_BOOT_CMD_MKENT(swrite, 3, 0, do_mmc_sparse_write, "", ""),
 #endif
 #endif
-	U_BOOT_CMD_MKENT(rescan, 1, 1, do_mmc_rescan, "", ""),
+	U_BOOT_CMD_MKENT(rescan, 2, 1, do_mmc_rescan, "", ""),
 	U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
 	U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
-	U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""),
+	U_BOOT_CMD_MKENT(dev, 4, 0, do_mmc_dev, "", ""),
 	U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
 	U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
 #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
 #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
 	U_BOOT_CMD_MKENT(hwpartition, 28, 0, do_mmc_hwpartition, "", ""),
 	U_BOOT_CMD_MKENT(hwpartition, 28, 0, do_mmc_hwpartition, "", ""),
@@ -1042,9 +1075,12 @@ U_BOOT_CMD(
 	"mmc swrite addr blk#\n"
 	"mmc swrite addr blk#\n"
 #endif
 #endif
 	"mmc erase blk# cnt\n"
 	"mmc erase blk# cnt\n"
-	"mmc rescan\n"
+	"mmc rescan [mode]\n"
 	"mmc part - lists available partition on current mmc device\n"
 	"mmc part - lists available partition on current mmc device\n"
-	"mmc dev [dev] [part] - show or set current mmc device [partition]\n"
+	"mmc dev [dev] [part] [mode] - show or set current mmc device [partition] and set mode\n"
+	"  - the required speed mode is passed as the index from the following list\n"
+	"    [MMC_LEGACY, MMC_HS, SD_HS, MMC_HS_52, MMC_DDR_52, UHS_SDR12, UHS_SDR25,\n"
+	"    UHS_SDR50, UHS_DDR50, UHS_SDR104, MMC_HS_200, MMC_HS_400, MMC_HS_400_ES]\n"
 	"mmc list - lists available devices\n"
 	"mmc list - lists available devices\n"
 	"mmc wp - power on write protect boot partitions\n"
 	"mmc wp - power on write protect boot partitions\n"
 #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
 #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)

+ 47 - 2
doc/usage/mmc.rst

@@ -12,9 +12,9 @@ Synopsis
     mmc read addr blk# cnt
     mmc read addr blk# cnt
     mmc write addr blk# cnt
     mmc write addr blk# cnt
     mmc erase blk# cnt
     mmc erase blk# cnt
-    mmc rescan
+    mmc rescan [mode]
     mmc part
     mmc part
-    mmc dev [dev] [part]
+    mmc dev [dev] [part] [mode]
     mmc list
     mmc list
     mmc wp
     mmc wp
     mmc bootbus <dev> <boot_bus_width> <reset_boot_bus_width> <boot_mode>
     mmc bootbus <dev> <boot_bus_width> <reset_boot_bus_width> <boot_mode>
@@ -49,6 +49,27 @@ The 'mmc erase' command erases *cnt* blocks on the MMC device starting at block
 
 
 The 'mmc rescan' command scans the available MMC device.
 The 'mmc rescan' command scans the available MMC device.
 
 
+   mode
+       speed mode to set.
+       CONFIG_MMC_SPEED_MODE_SET should be enabled. The required speed mode is
+       passed as the index from the following list.
+
+       0   - MMC_LEGACY
+       1   - MMC_HS
+       2   - SD_HS
+       3   - MMC_HS_52
+       4   - MMC_DDR_52
+       5   - UHS_SDR12
+       6   - UHS_SDR25
+       7   - UHS_SDR50
+       8   - UHS_DDR50
+       9   - UHS_SDR104
+       10  - MMC_HS_200
+       11  - MMC_HS_400
+       12  - MMC_HS_400_ES
+
+       A speed mode can be set only if it has already been enabled in the device tree
+
 The 'mmc part' command displays the list available partition on current mmc device.
 The 'mmc part' command displays the list available partition on current mmc device.
 
 
 The 'mmc dev' command shows or set current mmc device.
 The 'mmc dev' command shows or set current mmc device.
@@ -58,6 +79,27 @@ The 'mmc dev' command shows or set current mmc device.
     part
     part
         partition number to change
         partition number to change
 
 
+   mode
+       speed mode to set.
+       CONFIG_MMC_SPEED_MODE_SET should be enabled. The required speed mode is
+       passed as the index from the following list.
+
+       0   - MMC_LEGACY
+       1   - MMC_HS
+       2   - SD_HS
+       3   - MMC_HS_52
+       4   - MMC_DDR_52
+       5   - UHS_SDR12
+       6   - UHS_SDR25
+       7   - UHS_SDR50
+       8   - UHS_DDR50
+       9   - UHS_SDR104
+       10  - MMC_HS_200
+       11  - MMC_HS_400
+       12  - MMC_HS_400_ES
+
+       A speed mode can be set only if it has already been enabled in the device tree
+
 The 'mmc list' command displays the list available devices.
 The 'mmc list' command displays the list available devices.
 
 
 The 'mmc wp' command enables "power on write protect" function for boot partitions.
 The 'mmc wp' command enables "power on write protect" function for boot partitions.
@@ -194,6 +236,9 @@ The current device can be shown or set via 'mmc dev' command:
     => mmc dev 2 0
     => mmc dev 2 0
     switch to partitions #0, OK
     switch to partitions #0, OK
     mmc2 is current device
     mmc2 is current device
+    => mmc dev 0 1 4
+    switch to partitions #1, OK
+    mmc0(part 1) is current device
 
 
 The list of available devices can be shown via 'mmc list' command:
 The list of available devices can be shown via 'mmc list' command:
 ::
 ::

+ 0 - 7
drivers/mmc/fsl_esdhc.c

@@ -361,13 +361,6 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,
 	while (esdhc_read32(&regs->prsstat) & PRSSTAT_DLA)
 	while (esdhc_read32(&regs->prsstat) & PRSSTAT_DLA)
 		;
 		;
 
 
-	/* Wait at least 8 SD clock cycles before the next command */
-	/*
-	 * Note: This is way more than 8 cycles, but 1ms seems to
-	 * resolve timing issues with some cards
-	 */
-	udelay(1000);
-
 	/* Set up for a data transfer if we have one */
 	/* Set up for a data transfer if we have one */
 	if (data) {
 	if (data) {
 		err = esdhc_setup_data(priv, mmc, data);
 		err = esdhc_setup_data(priv, mmc, data);

+ 4 - 1
drivers/mmc/mmc-uclass.c

@@ -342,6 +342,9 @@ void mmc_do_preinit(void)
 
 
 		if (!m)
 		if (!m)
 			continue;
 			continue;
+
+		m->user_speed_mode = MMC_MODES_END;  /* Initialising user set speed mode */
+
 		if (m->preinit)
 		if (m->preinit)
 			mmc_start_init(m);
 			mmc_start_init(m);
 	}
 	}
@@ -414,7 +417,7 @@ int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
 	/* setup initial part type */
 	/* setup initial part type */
 	bdesc->part_type = cfg->part_type;
 	bdesc->part_type = cfg->part_type;
 	mmc->dev = dev;
 	mmc->dev = dev;
-
+	mmc->user_speed_mode = MMC_MODES_END;
 	return 0;
 	return 0;
 }
 }
 
 

+ 27 - 5
drivers/mmc/mmc.c

@@ -823,7 +823,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
 	 * capable of polling by using mmc_wait_dat0, then rely on waiting the
 	 * capable of polling by using mmc_wait_dat0, then rely on waiting the
 	 * stated timeout to be sufficient.
 	 * stated timeout to be sufficient.
 	 */
 	 */
-	if (ret == -ENOSYS && !send_status) {
+	if (ret == -ENOSYS || !send_status) {
 		mdelay(timeout_ms);
 		mdelay(timeout_ms);
 		return 0;
 		return 0;
 	}
 	}
@@ -2092,14 +2092,16 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
 	}
 	}
 
 
 #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
 #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
-    CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+    CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) || \
+    CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
 	/*
 	/*
 	 * In case the eMMC is in HS200/HS400 mode, downgrade to HS mode
 	 * In case the eMMC is in HS200/HS400 mode, downgrade to HS mode
 	 * before doing anything else, since a transition from either of
 	 * before doing anything else, since a transition from either of
 	 * the HS200/HS400 mode directly to legacy mode is not supported.
 	 * the HS200/HS400 mode directly to legacy mode is not supported.
 	 */
 	 */
 	if (mmc->selected_mode == MMC_HS_200 ||
 	if (mmc->selected_mode == MMC_HS_200 ||
-	    mmc->selected_mode == MMC_HS_400)
+	    mmc->selected_mode == MMC_HS_400 ||
+	    mmc->selected_mode == MMC_HS_400_ES)
 		mmc_set_card_speed(mmc, MMC_HS, true);
 		mmc_set_card_speed(mmc, MMC_HS, true);
 	else
 	else
 #endif
 #endif
@@ -2862,7 +2864,25 @@ int mmc_start_init(struct mmc *mmc)
 	 * timings.
 	 * timings.
 	 */
 	 */
 	mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(MMC_LEGACY) |
 	mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(MMC_LEGACY) |
-			 MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
+			 MMC_MODE_1BIT;
+
+	if (IS_ENABLED(CONFIG_MMC_SPEED_MODE_SET)) {
+		if (mmc->user_speed_mode != MMC_MODES_END) {
+			int i;
+			/* set host caps */
+			if (mmc->host_caps & MMC_CAP(mmc->user_speed_mode)) {
+				/* Remove all existing speed capabilities */
+				for (i = MMC_LEGACY; i < MMC_MODES_END; i++)
+					mmc->host_caps &= ~MMC_CAP(i);
+				mmc->host_caps |= (MMC_CAP(mmc->user_speed_mode)
+						   | MMC_CAP(MMC_LEGACY) |
+						   MMC_MODE_1BIT);
+			} else {
+				pr_err("bus_mode requested is not supported\n");
+				return -EINVAL;
+			}
+		}
+	}
 #if CONFIG_IS_ENABLED(DM_MMC)
 #if CONFIG_IS_ENABLED(DM_MMC)
 	mmc_deferred_probe(mmc);
 	mmc_deferred_probe(mmc);
 #endif
 #endif
@@ -2952,7 +2972,7 @@ int mmc_deinit(struct mmc *mmc)
 		return sd_select_mode_and_width(mmc, caps_filtered);
 		return sd_select_mode_and_width(mmc, caps_filtered);
 	} else {
 	} else {
 		caps_filtered = mmc->card_caps &
 		caps_filtered = mmc->card_caps &
-			~(MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_HS_400));
+			~(MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_HS_400) | MMC_CAP(MMC_HS_400_ES));
 
 
 		return mmc_select_mode_and_width(mmc, caps_filtered);
 		return mmc_select_mode_and_width(mmc, caps_filtered);
 	}
 	}
@@ -3060,6 +3080,8 @@ int mmc_init_device(int num)
 	}
 	}
 
 
 	m = mmc_get_mmc_dev(dev);
 	m = mmc_get_mmc_dev(dev);
+	m->user_speed_mode = MMC_MODES_END; /* Initialising user set speed mode */
+
 	if (!m)
 	if (!m)
 		return 0;
 		return 0;
 	if (m->preinit)
 	if (m->preinit)

+ 1 - 2
drivers/mmc/sdhci.c

@@ -258,8 +258,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
 		flags = SDHCI_CMD_RESP_LONG;
 		flags = SDHCI_CMD_RESP_LONG;
 	else if (cmd->resp_type & MMC_RSP_BUSY) {
 	else if (cmd->resp_type & MMC_RSP_BUSY) {
 		flags = SDHCI_CMD_RESP_SHORT_BUSY;
 		flags = SDHCI_CMD_RESP_SHORT_BUSY;
-		if (data)
-			mask |= SDHCI_INT_DATA_END;
+		mask |= SDHCI_INT_DATA_END;
 	} else
 	} else
 		flags = SDHCI_CMD_RESP_SHORT;
 		flags = SDHCI_CMD_RESP_SHORT;
 
 

+ 2 - 0
include/mmc.h

@@ -726,6 +726,8 @@ struct mmc {
 				  */
 				  */
 	u32 quirks;
 	u32 quirks;
 	u8 hs400_tuning;
 	u8 hs400_tuning;
+
+	enum bus_mode user_speed_mode; /* input speed mode from user */
 };
 };
 
 
 #if CONFIG_IS_ENABLED(DM_MMC)
 #if CONFIG_IS_ENABLED(DM_MMC)