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/mmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 20 |
5 files changed, 53 insertions, 2 deletions
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index f99b5f997e2..9c5d48e90cd 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 15c29beadbc..fca15910a8d 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 ebb307e9506..05a6d0ce156 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/mmc.c b/drivers/mmc/mmc.c index ba54b19c140..4d9871d69f2 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 03bfd9d18ae..766e4a6b0c5 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 = { |