spi: cadence_qspi: Use #define for bits instead of bit shifts
[oweals/u-boot.git] / drivers / mmc / sdhci.c
index 504f2d29accb55be8001ac61ef486836cb70fc7b..766e9eef84a964df4e4762be5b864dd2743dcabf 100644 (file)
@@ -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;
@@ -242,6 +242,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
 
        sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);
 #ifdef CONFIG_MMC_SDMA
+       trans_bytes = ALIGN(trans_bytes, CONFIG_SYS_CACHELINE_SIZE);
        flush_cache(start_addr, trans_bytes);
 #endif
        sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
@@ -294,7 +295,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;
@@ -303,7 +304,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--;
@@ -318,14 +319,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 +356,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;
@@ -352,7 +375,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);
@@ -455,7 +478,7 @@ static int sdhci_init(struct mmc *mmc)
                if (!aligned_buffer) {
                        printf("%s: Aligned buffer alloc failed!!!\n",
                               __func__);
-                       return -1;
+                       return -ENOMEM;
                }
        }
 
@@ -513,7 +536,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);
 
@@ -524,7 +547,11 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
                return -EINVAL;
        }
 #endif
-       host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+       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
@@ -577,6 +604,16 @@ 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.
+        */
+       if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
+               caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+               host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >>
+                               SDHCI_CLOCK_MUL_SHIFT;
+       }
+
        return 0;
 }
 
@@ -597,7 +634,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
        host->mmc = mmc_create(&host->cfg, host);
        if (host->mmc == NULL) {
                printf("%s: mmc create fail!\n", __func__);
-               return -1;
+               return -ENOMEM;
        }
 
        return 0;