summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-10-29 15:27:32 +0300
committerTom Rini <trini@konsulko.com>2021-10-29 15:27:32 +0300
commita09929cc6c5a108f89e91660f37d745ed119385b (patch)
tree9d1b3a9dddc72198f5f823135d60bed7b358faf3
parentaafc378a6caef453a40f2f9f3d6bef69e592c28d (diff)
parentc95b0297e95613fc68b1d92118ee64720d142f8c (diff)
downloadu-boot-a09929cc6c5a108f89e91660f37d745ed119385b.tar.xz
Merge https://source.denx.de/u-boot/custodians/u-boot-mmc
- Fix mmc_switch timeout - Update mmc hwpartitiion command - Support wait_dat0 for Freescale eSDHC/sdhci drivers
-rw-r--r--cmd/mmc.c38
-rw-r--r--drivers/mmc/arm_pl180_mmci.c14
-rw-r--r--drivers/mmc/arm_pl180_mmci.h1
-rw-r--r--drivers/mmc/fsl_esdhc.c16
-rw-r--r--drivers/mmc/mmc.c4
-rw-r--r--drivers/mmc/sdhci.c20
-rw-r--r--include/sdhci.h2
7 files changed, 89 insertions, 6 deletions
diff --git a/cmd/mmc.c b/cmd/mmc.c
index f1e30d0cf6..96d81ffdf3 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)
@@ -673,13 +698,18 @@ 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;
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;
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
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 <dm/device_compat.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/iopoll.h>
#include <linux/dma-mapping.h>
#include <sdhci.h>
@@ -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, &regs->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[] = {
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;
}
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)