diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/arm_pl180_mmci.c | 14 | ||||
-rw-r--r-- | drivers/mmc/arm_pl180_mmci.h | 1 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc.c | 16 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc_imx.c | 17 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 20 | ||||
-rw-r--r-- | drivers/mmc/sunxi_mmc.c | 2 |
7 files changed, 68 insertions, 6 deletions
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, ®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[] = { diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 5dfd484ef9..4c06361bee 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -727,17 +727,20 @@ static void esdhc_set_strobe_dll(struct mmc *mmc) if (priv->clock > ESDHC_STROBE_DLL_CLK_FREQ) { esdhc_write32(®s->strobe_dllctrl, ESDHC_STROBE_DLL_CTRL_RESET); + /* clear the reset bit on strobe dll before any setting */ + esdhc_write32(®s->strobe_dllctrl, 0); /* * enable strobe dll ctrl and adjust the delay target * for the uSDHC loopback read clock */ val = ESDHC_STROBE_DLL_CTRL_ENABLE | + ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT | (priv->strobe_dll_delay_target << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); esdhc_write32(®s->strobe_dllctrl, val); - /* wait 1us to make sure strobe dll status register stable */ - mdelay(1); + /* wait 5us to make sure strobe dll status register stable */ + mdelay(5); val = esdhc_read32(®s->strobe_dllstat); if (!(val & ESDHC_STROBE_DLL_STS_REF_LOCK)) pr_warn("HS400 strobe DLL status REF not lock!\n"); @@ -971,7 +974,6 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) if (priv->clock != clock) set_sysctl(priv, mmc, clock); -#ifdef MMC_SUPPORTS_TUNING if (mmc->clk_disable) { #ifdef CONFIG_FSL_USDHC esdhc_clrbits32(®s->vendorspec, VENDORSPEC_CKEN); @@ -987,6 +989,7 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) #endif } +#ifdef MMC_SUPPORTS_TUNING /* * For HS400/HS400ES mode, make sure set the strobe dll in the * target clock rate. So call esdhc_set_strobe_dll() after the @@ -1707,6 +1710,12 @@ static struct esdhc_soc_data usdhc_imx7d_data = { | ESDHC_FLAG_HS400, }; +static struct esdhc_soc_data usdhc_imx7ulp_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 + | ESDHC_FLAG_HS400, +}; + static struct esdhc_soc_data usdhc_imx8qm_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | @@ -1721,7 +1730,7 @@ static const struct udevice_id fsl_esdhc_ids[] = { { .compatible = "fsl,imx6sl-usdhc", }, { .compatible = "fsl,imx6q-usdhc", }, { .compatible = "fsl,imx7d-usdhc", .data = (ulong)&usdhc_imx7d_data,}, - { .compatible = "fsl,imx7ulp-usdhc", }, + { .compatible = "fsl,imx7ulp-usdhc", .data = (ulong)&usdhc_imx7ulp_data,}, { .compatible = "fsl,imx8qm-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, { .compatible = "fsl,imx8mm-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, { .compatible = "fsl,imx8mn-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, 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/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index c170c16d5a..4bf8a9b92c 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -72,10 +72,12 @@ static int mmc_resource_init(int sdc_no) priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE; priv->mclkreg = &ccm->sd1_clk_cfg; break; +#ifdef SUNXI_MMC2_BASE case 2: priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE; priv->mclkreg = &ccm->sd2_clk_cfg; break; +#endif #ifdef SUNXI_MMC3_BASE case 3: priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE; |