X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fmmc%2Fsdhci.c;h=837c53842b3802700ca192692c9ead0e2d220590;hb=2cb5d67c1aceb758033954cc06382367ac89e6ac;hp=91cc8b22daa5633abb7d860cce886db7d798ac25;hpb=8d549b61dc1b3a99a47738bd258813d336f6475b;p=u-boot diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 91cc8b22da..837c53842b 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -87,7 +87,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, if (stat & SDHCI_INT_ERROR) { printf("%s: Error detected in status(0x%X)!\n", __func__, stat); - return -1; + return -EIO; } if (stat & rdy) { if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)) @@ -110,7 +110,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, udelay(10); else { printf("%s: Transfer data timeout\n", __func__); - return -1; + return -ETIMEDOUT; } } while (!(stat & SDHCI_INT_DATA_END)); return 0; @@ -121,13 +121,10 @@ 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 CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT 100 +#define SDHCI_CMD_MAX_TIMEOUT 3200 +#define SDHCI_CMD_DEFAULT_TIMEOUT 100 #define SDHCI_READ_STATUS_TIMEOUT 1000 #ifdef CONFIG_DM_MMC_OPS @@ -151,7 +148,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; @@ -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); @@ -297,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; @@ -306,7 +303,7 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if (timeout == 0) { printf("%s: Timeout to wait cmd & data inhibit\n", __func__); - return -1; + return -EBUSY; } timeout--; @@ -321,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. */ @@ -336,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; @@ -355,7 +374,7 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if (timeout == 0) { printf("%s: Internal clock never stabilised.\n", __func__); - return -1; + return -EBUSY; } timeout--; udelay(1000); @@ -458,7 +477,7 @@ static int sdhci_init(struct mmc *mmc) if (!aligned_buffer) { printf("%s: Aligned buffer alloc failed!!!\n", __func__); - return -1; + return -ENOMEM; } } @@ -516,10 +535,22 @@ 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); - host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + +#ifdef CONFIG_MMC_SDMA + if (!(caps & SDHCI_CAN_DO_SDMA)) { + printf("%s: Your controller doesn't support SDMA!!\n", + __func__); + return -EINVAL; + } +#endif + if (host->quirks & SDHCI_QUIRK_REG32_RW) + host->version = + sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16; + else + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); cfg->name = host->name; #ifndef CONFIG_DM_MMC_OPS @@ -536,8 +567,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 { @@ -554,6 +588,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) @@ -566,6 +603,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; } @@ -577,30 +622,16 @@ 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) { -#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 + int ret; - if (sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk)) { - printf("%s: Hardware doesn't specify base clock frequency\n", - __func__); - return -EINVAL; - } - - if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) - host->cfg.voltages |= host->voltages; + ret = sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk); + if (ret) + return ret; host->mmc = mmc_create(&host->cfg, host); if (host->mmc == NULL) { printf("%s: mmc create fail!\n", __func__); - return -1; + return -ENOMEM; } return 0;