]> git.sur5r.net Git - u-boot/blobdiff - drivers/mmc/sdhci.c
mmc/dw_mmc: Fix DMA descriptor corruption
[u-boot] / drivers / mmc / sdhci.c
index 932987427c3d60c79a3a3f63f914f412bd43cc6f..14fe41f6c4cc91aa2e300a203eb0f62fe8635100 100644 (file)
@@ -2,23 +2,7 @@
  * Copyright 2011, Marvell Semiconductor Inc.
  * Lei Wen <leiwen@marvell.com>
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0+
  *
  * Back ported to the 8xx platform (from the 8260 platform) by
  * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
@@ -82,6 +66,13 @@ 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 = 1000000;
        rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
@@ -233,6 +224,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 +254,7 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
        if (clock == 0)
                return 0;
 
-       if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) {
+       if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
                /* Version 3.00 divisors must be a multiple of 2. */
                if (mmc->f_max <= clock)
                        div = 1;
@@ -330,6 +324,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);
@@ -350,10 +347,11 @@ 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_VER_MASK) >= SDHCI_SPEC_300)
+               if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ||
+                               (host->quirks & SDHCI_QUIRK_USE_WIDE8))
                        ctrl |= SDHCI_CTRL_8BITBUS;
        } else {
-               if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
+               if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
                        ctrl &= ~SDHCI_CTRL_8BITBUS;
                if (mmc->bus_width == 4)
                        ctrl |= SDHCI_CTRL_4BITBUS;
@@ -399,9 +397,11 @@ int sdhci_init(struct mmc *mmc)
                        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);
+       /* Enable only interrupts served by the SD controller */
+       sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK
+                    , SDHCI_INT_ENABLE);
+       /* Mask all sdhci interrupt sources */
+       sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
 
        return 0;
 }
@@ -425,6 +425,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
        mmc->set_ios = sdhci_set_ios;
        mmc->init = sdhci_init;
        mmc->getcd = NULL;
+       mmc->getwp = NULL;
 
        caps = sdhci_readl(host, SDHCI_CAPABILITIES);
 #ifdef CONFIG_MMC_SDMA
@@ -437,7 +438,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_VER_MASK) >= SDHCI_SPEC_300)
+               if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
                        mmc->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK)
                                >> SDHCI_CLOCK_BASE_SHIFT;
                else
@@ -452,7 +453,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_VER_MASK) >= SDHCI_SPEC_300)
+               if (SDHCI_GET_VERSION(host) >= 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;
@@ -470,8 +471,10 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
                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 (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
+               if (caps & SDHCI_CAN_DO_8BIT)
+                       mmc->host_caps |= MMC_MODE_8BIT;
+       }
        if (host->host_caps)
                mmc->host_caps |= host->host_caps;