From 8d549b61dc1b3a99a47738bd258813d336f6475b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 25 Aug 2016 16:07:34 +0900 Subject: mmc: sdhci: move sdhci_reset() call to sdhci_init() If CONFIG_BLK is enabled, add_sdhci() is never called. So, sdhci_reset() is not called, either. This is a problem for my board as it needs the reset to start from a sane state. Move the add_sdhci() call to sdhci_init(), which is visited by both of the with/without CONFIG_BLK cases. Signed-off-by: Masahiro Yamada --- drivers/mmc/sdhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 7ddb549..91cc8b2 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -451,6 +451,8 @@ static int sdhci_init(struct mmc *mmc) { struct sdhci_host *host = mmc->priv; + sdhci_reset(host, SDHCI_RESET_ALL); + if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { aligned_buffer = memalign(8, 512*1024); if (!aligned_buffer) { @@ -595,8 +597,6 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) host->cfg.voltages |= host->voltages; - sdhci_reset(host, SDHCI_RESET_ALL); - host->mmc = mmc_create(&host->cfg, host); if (host->mmc == NULL) { printf("%s: mmc create fail!\n", __func__); -- cgit v1.1 From 6c67954c93ea09bccc5bbc984ff60a2c28eeb733 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 25 Aug 2016 16:07:35 +0900 Subject: mmc: sdhci: move error message to more relevant place "Hardware doesn't specify base clock frequency" may not be only the error case of sdhci_setup_cfg(). It is better to print this where the corresponding error is triggered. Signed-off-by: Masahiro Yamada --- drivers/mmc/sdhci.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 91cc8b2..d886777 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -536,8 +536,11 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, SDHCI_CLOCK_BASE_SHIFT; cfg->f_max *= 1000000; } - if (cfg->f_max == 0) + if (cfg->f_max == 0) { + printf("%s: Hardware doesn't specify base clock frequency\n", + __func__); return -EINVAL; + } if (min_clk) cfg->f_min = min_clk; else { @@ -577,6 +580,8 @@ int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg) #else int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) { + int ret; + #ifdef CONFIG_MMC_SDMA unsigned int caps; @@ -588,11 +593,9 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) } #endif - if (sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk)) { - printf("%s: Hardware doesn't specify base clock frequency\n", - __func__); - return -EINVAL; - } + ret = sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk); + if (ret) + return ret; if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) host->cfg.voltages |= host->voltages; -- cgit v1.1 From 3137e645e2f697df88dca08b7631c6363093bcf4 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 25 Aug 2016 16:07:36 +0900 Subject: mmc: sdhci: move broken voltage quirk handling to sdhci_setup_cfg() If CONFIG_BLK is enabled, add_sdhci() is never called. Move this quirk handling to sdhci_setup_cfg(), which is now the central place for hardware capability checks. Signed-off-by: Masahiro Yamada --- drivers/mmc/sdhci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index d886777..c66151c 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -557,6 +557,9 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, if (caps & SDHCI_CAN_VDD_180) cfg->voltages |= MMC_VDD_165_195; + if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) + cfg->voltages |= host->voltages; + cfg->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT; if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { if (caps & SDHCI_CAN_DO_8BIT) @@ -597,9 +600,6 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) if (ret) return ret; - if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) - host->cfg.voltages |= host->voltages; - host->mmc = mmc_create(&host->cfg, host); if (host->mmc == NULL) { printf("%s: mmc create fail!\n", __func__); -- cgit v1.1 From 15bd09959fddd2782484683818bf05fb154237cb Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 25 Aug 2016 16:07:37 +0900 Subject: mmc: sdhci: move SDMA capability check to sdhci_setup_cfg() If CONFIG_BLK is enabled, add_sdhci() is never called. Move this quirk handling to sdhci_setup_cfg(), which is now the central place for hardware capability checks. Signed-off-by: Masahiro Yamada --- drivers/mmc/sdhci.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index c66151c..da73653 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -519,6 +519,14 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, u32 caps; caps = sdhci_readl(host, SDHCI_CAPABILITIES); + +#ifdef CONFIG_MMC_SDMA + if (!(caps & SDHCI_CAN_DO_SDMA)) { + printf("%s: Your controller doesn't support SDMA!!\n", + __func__); + return -EINVAL; + } +#endif host->version = sdhci_readw(host, SDHCI_HOST_VERSION); cfg->name = host->name; @@ -585,17 +593,6 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) { int ret; -#ifdef CONFIG_MMC_SDMA - unsigned int caps; - - caps = sdhci_readl(host, SDHCI_CAPABILITIES); - if (!(caps & SDHCI_CAN_DO_SDMA)) { - printf("%s: Your controller doesn't support SDMA!!\n", - __func__); - return -1; - } -#endif - ret = sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk); if (ret) return ret; -- cgit v1.1 From d8ce77b28cdcb15f3c35e59c887ca5e15e704df3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 25 Aug 2016 16:07:38 +0900 Subject: mmc: sdhci: drop CONFIG_ from CONFIG_SDHCI_CMD_DEFAULT_TIME This CONFIG is not configurable since it is not guarded by #ifndef. Nobody has complained about that, so there is no need to keep it as a CONFIG option. Signed-off-by: Masahiro Yamada --- drivers/mmc/sdhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index da73653..d486082 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -127,7 +127,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, #ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT #define CONFIG_SDHCI_CMD_MAX_TIMEOUT 3200 #endif -#define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT 100 +#define SDHCI_CMD_DEFAULT_TIMEOUT 100 #define SDHCI_READ_STATUS_TIMEOUT 1000 #ifdef CONFIG_DM_MMC_OPS @@ -151,7 +151,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, unsigned start = get_timer(0); /* Timeout unit - ms */ - static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT; + static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT; sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; -- cgit v1.1 From 65a25b2086a77cfdd9c727d749c18341b1161f71 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 25 Aug 2016 16:07:39 +0900 Subject: mmc: sdhci: drop CONFIG_ from CONFIG_SDHCI_CMD_MAX_TIMEOUT No need for per-SoC adjustment for this parameter. It should be determined by the slowest hardware. Currently, no board overrides this CONFIG, so 3.2 sec is large enough. (If not, we can make it even larger.) Signed-off-by: Masahiro Yamada --- drivers/mmc/sdhci.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index d486082..504f2d2 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -121,12 +121,9 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, * for card ready state. * Every time when card is busy after timeout then (last) timeout value will be * increased twice but only if it doesn't exceed global defined maximum. - * Each function call will use last timeout value. Max timeout can be redefined - * in board config file. + * Each function call will use last timeout value. */ -#ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT -#define CONFIG_SDHCI_CMD_MAX_TIMEOUT 3200 -#endif +#define SDHCI_CMD_MAX_TIMEOUT 3200 #define SDHCI_CMD_DEFAULT_TIMEOUT 100 #define SDHCI_READ_STATUS_TIMEOUT 1000 @@ -164,7 +161,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (time >= cmd_timeout) { printf("%s: MMC: %d busy ", __func__, mmc_dev); - if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) { + if (2 * cmd_timeout <= SDHCI_CMD_MAX_TIMEOUT) { cmd_timeout += cmd_timeout; printf("timeout increasing to: %u ms.\n", cmd_timeout); -- cgit v1.1 From 3697e5992f89c923aca17d7d9174739da28cb3cd Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 1 Sep 2016 11:13:38 +0800 Subject: mmc: sd: extracting erase related information from sd status Add function to read SD_STATUS information. According to the information, get erase_timeout/erase_size/erase_offset. Add a structure sd_ssr to include the erase related information. Signed-off-by: Peng Fan Cc: Jaehoon Chung Cc: Simon Glass Cc: Bin Meng Cc: Stefan Wahren Cc: Clemens Gruber Cc: Kever Yang Cc: Eric Nelson Cc: Stephen Warren --- drivers/mmc/mmc.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/mmc.h | 9 ++++++++ 2 files changed, 77 insertions(+) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 43ea0bb..0312da9 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -21,6 +21,14 @@ #include #include "mmc_private.h" +static const unsigned int sd_au_size[] = { + 0, SZ_16K / 512, SZ_32K / 512, + SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, + SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, + SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, + SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512, +}; + #ifndef CONFIG_DM_MMC_OPS __weak int board_mmc_getwp(struct mmc *mmc) { @@ -945,6 +953,62 @@ retry_scr: return 0; } +static int sd_read_ssr(struct mmc *mmc) +{ + int err, i; + struct mmc_cmd cmd; + ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); + struct mmc_data data; + int timeout = 3; + unsigned int au, eo, et, es; + + cmd.cmdidx = MMC_CMD_APP_CMD; + cmd.resp_type = MMC_RSP_R1; + cmd.cmdarg = mmc->rca << 16; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + return err; + + cmd.cmdidx = SD_CMD_APP_SD_STATUS; + cmd.resp_type = MMC_RSP_R1; + cmd.cmdarg = 0; + +retry_ssr: + data.dest = (char *)ssr; + data.blocksize = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + if (err) { + if (timeout--) + goto retry_ssr; + + return err; + } + + for (i = 0; i < 16; i++) + ssr[i] = be32_to_cpu(ssr[i]); + + au = (ssr[2] >> 12) & 0xF; + if ((au <= 9) || (mmc->version == SD_VERSION_3)) { + mmc->ssr.au = sd_au_size[au]; + es = (ssr[3] >> 24) & 0xFF; + es |= (ssr[2] & 0xFF) << 8; + et = (ssr[3] >> 18) & 0x3F; + if (es && et) { + eo = (ssr[3] >> 16) & 0x3; + mmc->ssr.erase_timeout = (et * 1000) / es; + mmc->ssr.erase_offset = eo * 1000; + } + } else { + debug("Invalid Allocation Unit Size.\n"); + } + + return 0; +} + /* frequency bases */ /* divided by 10 to be nice to platforms without floating point */ static const int fbase[] = { @@ -1350,6 +1414,10 @@ static int mmc_startup(struct mmc *mmc) mmc_set_bus_width(mmc, 4); } + err = sd_read_ssr(mmc); + if (err) + return err; + if (mmc->card_caps & MMC_MODE_HS) mmc->tran_speed = 50000000; else diff --git a/include/mmc.h b/include/mmc.h index aa6d5d1..e815eb3 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -11,6 +11,7 @@ #define _MMC_H_ #include +#include #include #include @@ -102,6 +103,7 @@ #define SD_CMD_SWITCH_UHS18V 11 #define SD_CMD_APP_SET_BUS_WIDTH 6 +#define SD_CMD_APP_SD_STATUS 13 #define SD_CMD_ERASE_WR_BLK_START 32 #define SD_CMD_ERASE_WR_BLK_END 33 #define SD_CMD_APP_SEND_OP_COND 41 @@ -392,6 +394,12 @@ struct mmc_config { unsigned char part_type; }; +struct sd_ssr { + unsigned int au; /* In sectors */ + unsigned int erase_timeout; /* In milliseconds */ + unsigned int erase_offset; /* In milliseconds */ +}; + /* * With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device * with mmc_get_mmc_dev(). @@ -426,6 +434,7 @@ struct mmc { uint write_bl_len; uint erase_grp_size; /* in 512-byte sectors */ uint hc_wp_grp_size; /* in 512-byte sectors */ + struct sd_ssr ssr; /* SD status register */ u64 capacity; u64 capacity_user; u64 capacity_boot; -- cgit v1.1 From e492dbb41e025ac1a7d7934b1df52b2f0485f8dd Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 1 Sep 2016 11:13:39 +0800 Subject: mmc: sd: optimize erase To SD, there is no erase group, then the value erase_grp_size will be default 1. When erasing SD blocks, the blocks will be erased one by one, which is time consuming. We use AU_SIZE as a group to speed up the erasing. Erasing 4MB with a SD2.0 Card with AU_SIZE 4MB. `time mmc erase 0x100000 0x2000` time: 44.856 seconds (before optimization) time: 0.335 seconds (after optimization) Signed-off-by: Peng Fan Cc: Jaehoon Chung Cc: Simon Glass Cc: Bin Meng Cc: Stefan Wahren Cc: Clemens Gruber Cc: Kever Yang Cc: Eric Nelson Cc: Stephen Warren --- drivers/mmc/mmc_write.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index 0f8b5c7..2289640 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -100,8 +100,13 @@ unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start, & ~(mmc->erase_grp_size - 1)) - 1); while (blk < blkcnt) { - blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? - mmc->erase_grp_size : (blkcnt - blk); + if (IS_SD(mmc) && mmc->ssr.au) { + blk_r = ((blkcnt - blk) > mmc->ssr.au) ? + mmc->ssr.au : (blkcnt - blk); + } else { + blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? + mmc->erase_grp_size : (blkcnt - blk); + } err = mmc_erase_t(mmc, start + blk, blk_r); if (err) break; -- cgit v1.1 From 6dffdbc3a5911e768be21850a612bfb4871a23ef Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Sun, 18 Sep 2016 09:01:22 +0800 Subject: mmc: sdhci: Add the programmable clock mode support Add the programmable clock mode for the clock generator. Signed-off-by: Wenyou Yang --- drivers/mmc/sdhci.c | 50 ++++++++++++++++++++++++++++++++++++++++---------- include/sdhci.h | 2 ++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 504f2d2..b2bf5a0 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -294,7 +294,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv; - unsigned int div, clk, timeout, reg; + unsigned int div, clk = 0, timeout, reg; /* Wait max 20 ms */ timeout = 200; @@ -318,14 +318,36 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) return 0; if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { - /* Version 3.00 divisors must be a multiple of 2. */ - if (mmc->cfg->f_max <= clock) - div = 1; - else { - for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { - if ((mmc->cfg->f_max / div) <= clock) + /* + * Check if the Host Controller supports Programmable Clock + * Mode. + */ + if (host->clk_mul) { + for (div = 1; div <= 1024; div++) { + if ((mmc->cfg->f_max * host->clk_mul / div) + <= clock) break; } + + /* + * Set Programmable Clock Mode in the Clock + * Control register. + */ + clk = SDHCI_PROG_CLOCK_MODE; + div--; + } else { + /* Version 3.00 divisors must be a multiple of 2. */ + if (mmc->cfg->f_max <= clock) { + div = 1; + } else { + for (div = 2; + div < SDHCI_MAX_DIV_SPEC_300; + div += 2) { + if ((mmc->cfg->f_max / div) <= clock) + break; + } + } + div >>= 1; } } else { /* Version 2.00 divisors must be a power of 2. */ @@ -333,13 +355,13 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if ((mmc->cfg->f_max / div) <= clock) break; } + div >>= 1; } - div >>= 1; if (host->set_clock) host->set_clock(host->index, div); - clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; + clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; clk |= SDHCI_CLOCK_INT_EN; @@ -513,7 +535,7 @@ static const struct mmc_ops sdhci_ops = { int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, u32 max_clk, u32 min_clk) { - u32 caps; + u32 caps, caps_1; caps = sdhci_readl(host, SDHCI_CAPABILITIES); @@ -577,6 +599,14 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + /* + * In case of Host Controller v3.00, find out whether clock + * multiplier is supported. + */ + caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); + host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> + SDHCI_CLOCK_MUL_SHIFT; + return 0; } diff --git a/include/sdhci.h b/include/sdhci.h index 6844c73..144570f 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -97,6 +97,7 @@ #define SDHCI_DIV_MASK 0xFF #define SDHCI_DIV_MASK_LEN 8 #define SDHCI_DIV_HI_MASK 0x300 +#define SDHCI_PROG_CLOCK_MODE 0x0020 #define SDHCI_CLOCK_CARD_EN 0x0004 #define SDHCI_CLOCK_INT_STABLE 0x0002 #define SDHCI_CLOCK_INT_EN 0x0001 @@ -242,6 +243,7 @@ struct sdhci_host { unsigned int quirks; unsigned int host_caps; unsigned int version; + unsigned int clk_mul; /* Clock Multiplier value */ unsigned int clock; struct mmc *mmc; const struct sdhci_ops *ops; -- cgit v1.1 From 2b42903397b4d6b68fe2af95565a8953b08ab96e Mon Sep 17 00:00:00 2001 From: Jacob Chen Date: Mon, 19 Sep 2016 10:16:50 +0800 Subject: mmc: dw_mmc: push/pop all FIFO data if any data request When DTO interrupt occurred, there are any remaining data still in FIFO due to RX FIFO threshold is larger than remaining data. It also causes that dwmmc didn't trigger RXDR interrupt, so is TX. It's responsibility of driver to read remaining bytes on seeing DTO interrupt. Signed-off-by: Jacob Chen Signed-off-by: Ziyuan Xu --- drivers/mmc/dw_mmc.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index afc674d..074f86c 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -120,9 +120,9 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) if (host->fifo_mode && size) { len = 0; - if (data->flags == MMC_DATA_READ) { - if ((dwmci_readl(host, DWMCI_RINTSTS) & - DWMCI_INTMSK_RXDR)) { + if (data->flags == MMC_DATA_READ && + (mask & DWMCI_INTMSK_RXDR)) { + while (size) { len = dwmci_readl(host, DWMCI_STATUS); len = (len >> DWMCI_FIFO_SHIFT) & DWMCI_FIFO_MASK; @@ -130,12 +130,13 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) for (i = 0; i < len; i++) *buf++ = dwmci_readl(host, DWMCI_DATA); - dwmci_writel(host, DWMCI_RINTSTS, - DWMCI_INTMSK_RXDR); + size = size > len ? (size - len) : 0; } - } else { - if ((dwmci_readl(host, DWMCI_RINTSTS) & - DWMCI_INTMSK_TXDR)) { + dwmci_writel(host, DWMCI_RINTSTS, + DWMCI_INTMSK_RXDR); + } else if (data->flags == MMC_DATA_WRITE && + (mask & DWMCI_INTMSK_TXDR)) { + while (size) { len = dwmci_readl(host, DWMCI_STATUS); len = fifo_depth - ((len >> DWMCI_FIFO_SHIFT) & @@ -144,11 +145,11 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) for (i = 0; i < len; i++) dwmci_writel(host, DWMCI_DATA, *buf++); - dwmci_writel(host, DWMCI_RINTSTS, - DWMCI_INTMSK_TXDR); + size = size > len ? (size - len) : 0; } + dwmci_writel(host, DWMCI_RINTSTS, + DWMCI_INTMSK_TXDR); } - size = size > len ? (size - len) : 0; } /* Data arrived correctly. */ -- cgit v1.1