|
@@ -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;
|
|
@@ -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;
|
|
@@ -451,6 +470,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) {
|
|
@@ -514,9 +535,17 @@ 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);
|
|
|
+
|
|
|
+#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;
|
|
@@ -534,8 +563,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 {
|
|
@@ -552,6 +584,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)
|
|
@@ -564,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;
|
|
|
}
|
|
|
|
|
@@ -575,27 +618,11 @@ 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
|
|
|
-
|
|
|
- if (sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk)) {
|
|
|
- printf("%s: Hardware doesn't specify base clock frequency\n",
|
|
|
- __func__);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ int ret;
|
|
|
|
|
|
- if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
|
|
|
- host->cfg.voltages |= host->voltages;
|
|
|
-
|
|
|
- sdhci_reset(host, SDHCI_RESET_ALL);
|
|
|
+ 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) {
|