]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/mmc/sdhci.c
serial_sh: Add support Renesas SH7752
[karo-tx-uboot.git] / drivers / mmc / sdhci.c
index 7790a1e8da6b59c40fdf5233fd43e66112420092..b9cbe34f1f12f728471514ceac568576fe696b9c 100644 (file)
@@ -82,8 +82,15 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
                                unsigned int start_addr)
 {
        unsigned int stat, rdy, mask, timeout, block = 0;
+#ifdef CONFIG_MMC_SDMA
+       unsigned char ctrl;
+       ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL);
+       ctrl &= ~SDHCI_CTRL_DMA_MASK;
+       ctrl |= SDHCI_CTRL_SDMA;
+       sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL);
+#endif
 
-       timeout = 10000;
+       timeout = 1000000;
        rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
        mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE;
        do {
@@ -233,6 +240,9 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
        if (!ret && data)
                ret = sdhci_transfer_data(host, data, start_addr);
 
+       if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD)
+               udelay(1000);
+
        stat = sdhci_readl(host, SDHCI_INT_STATUS);
        sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
        if (!ret) {
@@ -260,7 +270,7 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
        if (clock == 0)
                return 0;
 
-       if (host->version >= SDHCI_SPEC_300) {
+       if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) {
                /* Version 3.00 divisors must be a multiple of 2. */
                if (mmc->f_max <= clock)
                        div = 1;
@@ -279,6 +289,9 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
        }
        div >>= 1;
 
+       if (host->set_clock)
+               host->set_clock(host->index, div);
+
        clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
        clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
                << SDHCI_DIVIDER_HI_SHIFT;
@@ -327,6 +340,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
                return;
        }
 
+       if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
+               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
        pwr |= SDHCI_POWER_ON;
 
        sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
@@ -337,6 +353,9 @@ void sdhci_set_ios(struct mmc *mmc)
        u32 ctrl;
        struct sdhci_host *host = (struct sdhci_host *)mmc->priv;
 
+       if (host->set_control_reg)
+               host->set_control_reg(host);
+
        if (mmc->clock != host->clock)
                sdhci_set_clock(mmc, mmc->clock);
 
@@ -344,10 +363,10 @@ void sdhci_set_ios(struct mmc *mmc)
        ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
        if (mmc->bus_width == 8) {
                ctrl &= ~SDHCI_CTRL_4BITBUS;
-               if (host->version >= SDHCI_SPEC_300)
+               if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
                        ctrl |= SDHCI_CTRL_8BITBUS;
        } else {
-               if (host->version >= SDHCI_SPEC_300)
+               if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
                        ctrl &= ~SDHCI_CTRL_8BITBUS;
                if (mmc->bus_width == 4)
                        ctrl |= SDHCI_CTRL_4BITBUS;
@@ -360,6 +379,9 @@ void sdhci_set_ios(struct mmc *mmc)
        else
                ctrl &= ~SDHCI_CTRL_HISPD;
 
+       if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)
+               ctrl &= ~SDHCI_CTRL_HISPD;
+
        sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 }
 
@@ -375,12 +397,25 @@ int sdhci_init(struct mmc *mmc)
                }
        }
 
+       sdhci_set_power(host, fls(mmc->voltages) - 1);
+
+       if (host->quirks & SDHCI_QUIRK_NO_CD) {
+               unsigned int status;
+
+               sdhci_writel(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST,
+                       SDHCI_HOST_CONTROL);
+
+               status = sdhci_readl(host, SDHCI_PRESENT_STATE);
+               while ((!(status & SDHCI_CARD_PRESENT)) ||
+                   (!(status & SDHCI_CARD_STATE_STABLE)) ||
+                   (!(status & SDHCI_CARD_DETECT_PIN_LEVEL)))
+                       status = sdhci_readl(host, SDHCI_PRESENT_STATE);
+       }
+
        /* Eable all state */
        sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_ENABLE);
        sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_SIGNAL_ENABLE);
 
-       sdhci_set_power(host, fls(mmc->voltages) - 1);
-
        return 0;
 }
 
@@ -415,7 +450,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
        if (max_clk)
                mmc->f_max = max_clk;
        else {
-               if (host->version >= SDHCI_SPEC_300)
+               if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
                        mmc->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK)
                                >> SDHCI_CLOCK_BASE_SHIFT;
                else
@@ -430,7 +465,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
        if (min_clk)
                mmc->f_min = min_clk;
        else {
-               if (host->version >= SDHCI_SPEC_300)
+               if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
                        mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_300;
                else
                        mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_200;
@@ -443,9 +478,15 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
                mmc->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
        if (caps & SDHCI_CAN_VDD_180)
                mmc->voltages |= MMC_VDD_165_195;
+
+       if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
+               mmc->voltages |= host->voltages;
+
        mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
        if (caps & SDHCI_CAN_DO_8BIT)
                mmc->host_caps |= MMC_MODE_8BIT;
+       if (host->host_caps)
+               mmc->host_caps |= host->host_caps;
 
        sdhci_reset(host, SDHCI_RESET_ALL);
        mmc_register(mmc);