]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'mmc-v4.3' of git://git.linaro.org/people/ulf.hansson/mmc
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 8 Sep 2015 23:33:16 +0000 (16:33 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 8 Sep 2015 23:33:16 +0000 (16:33 -0700)
Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Fix a race condition in the request handling
   - Skip trim commands for some buggy kingston eMMCs
   - An optimization and a correction for erase groups
   - Set CMD23 quirk for some Sandisk cards

  MMC host:
   - sdhci: Give GPIO CD higher precedence and don't poll when it's used
   - sdhci: Fix DMA memory leakage
   - sdhci: Some updates for clock management
   - sdhci-of-at91: introduce driver for the Atmel SDMMC
   - sdhci-of-arasan: Add support for sdhci-5.1
   - sdhci-esdhc-imx: Add support for imx7d which also supports HS400
   - sdhci: A collection of fixes and improvements for various sdhci hosts
   - omap_hsmmc: Modernization of the regulator code
   - dw_mmc: A couple of fixes for DMA and PIO mode
   - usdhi6rol0: A few fixes and support probe deferral for regulators
   - pxamci: Convert to use dmaengine
   - sh_mmcif: Fix the suspend process in a short term solution
   - tmio: Adjust timeout for commands
   - sunxi: Fix timeout while gating/ungating clock"

* tag 'mmc-v4.3' of git://git.linaro.org/people/ulf.hansson/mmc: (67 commits)
  mmc: android-goldfish: remove incorrect __iomem annotation
  mmc: core: fix race condition in mmc_wait_data_done
  mmc: host: omap_hsmmc: remove CONFIG_REGULATOR check
  mmc: host: omap_hsmmc: use ios->vdd for setting vmmc voltage
  mmc: host: omap_hsmmc: use regulator_is_enabled to find pbias status
  mmc: host: omap_hsmmc: enable/disable vmmc_aux regulator based on previous state
  mmc: host: omap_hsmmc: don't use ->set_power to set initial regulator state
  mmc: host: omap_hsmmc: avoid pbias regulator enable on power off
  mmc: host: omap_hsmmc: add separate function to set pbias
  mmc: host: omap_hsmmc: add separate functions for enable/disable supply
  mmc: host: omap_hsmmc: return error if any of the regulator APIs fail
  mmc: host: omap_hsmmc: remove unnecessary pbias set_voltage
  mmc: host: omap_hsmmc: use mmc_host's vmmc and vqmmc
  mmc: host: omap_hsmmc: use the ocrmask provided by the vmmc regulator
  mmc: host: omap_hsmmc: cleanup omap_hsmmc_reg_get()
  mmc: host: omap_hsmmc: return on fatal errors from omap_hsmmc_reg_get
  mmc: host: omap_hsmmc: use devm_regulator_get_optional() for vmmc
  mmc: sdhci-of-at91: fix platform_no_drv_owner.cocci warnings
  mmc: sh_mmcif: Fix suspend process
  mmc: usdhi6rol0: fix error return code
  ...

35 files changed:
Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
Documentation/devicetree/bindings/mmc/sdhci-atmel.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
MAINTAINERS
drivers/mmc/card/block.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/android-goldfish.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-esdhc.h
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-arasan.c
drivers/mmc/host/sdhci-of-at91.c [new file with mode: 0644]
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-sirf.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sunxi-mmc.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/usdhi6rol0.c
include/linux/mmc/card.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/platform_data/mmc-esdhc-imx.h

index 7e9490313d5add1f0fddf1327a3901625b1d6d55..da541c3631f81880c6e87b62e8ca2cb133d1aec4 100644 (file)
@@ -9,7 +9,7 @@ Device Tree Bindings for the Arasan SDHCI Controller
 
 Required Properties:
   - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' or
-                'arasan,sdhci-4.9a'
+                'arasan,sdhci-4.9a' or 'arasan,sdhci-5.1'
   - reg: From mmc bindings: Register location and length.
   - clocks: From clock bindings: Handles to clock inputs.
   - clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb"
index 211e7785f4d240ec2ffc7258839f740e8b614b78..dca56d6248f5944880c0e73395344217fd420daf 100644 (file)
@@ -15,6 +15,7 @@ Required properties:
               "fsl,imx6q-usdhc"
               "fsl,imx6sl-usdhc"
               "fsl,imx6sx-usdhc"
+              "fsl,imx7d-usdhc"
 
 Optional properties:
 - fsl,wp-controller : Indicate to use controller internal write protection
@@ -27,6 +28,11 @@ Optional properties:
   transparent level shifters on the outputs of the controller. Two cells are
   required, first cell specifies minimum slot voltage (mV), second cell
   specifies maximum slot voltage (mV). Several ranges could be specified.
+- fsl,tuning-step: Specify the increasing delay cell steps in tuning procedure.
+  The uSDHC use one delay cell as default increasing step to do tuning process.
+  This property allows user to change the tuning step to more than one delay
+  cells which is useful for some special boards or cards when the default
+  tuning step can't find the proper delay window within limited tuning retries.
 
 Examples:
 
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-atmel.txt b/Documentation/devicetree/bindings/mmc/sdhci-atmel.txt
new file mode 100644 (file)
index 0000000..1b662d7
--- /dev/null
@@ -0,0 +1,21 @@
+* Atmel SDHCI controller
+
+This file documents the differences between the core properties in
+Documentation/devicetree/bindings/mmc/mmc.txt and the properties used by the
+sdhci-of-at91 driver.
+
+Required properties:
+- compatible:          Must be "atmel,sama5d2-sdhci".
+- clocks:              Phandlers to the clocks.
+- clock-names:         Must be "hclock", "multclk", "baseclk";
+
+
+Example:
+
+sdmmc0: sdio-host@a0000000 {
+       compatible = "atmel,sama5d2-sdhci";
+       reg = <0xa0000000 0x300>;
+       interrupts = <31 IRQ_TYPE_LEVEL_HIGH 0>;
+       clocks = <&sdmmc0_hclk>, <&sdmmc0_gclk>, <&main>;
+       clock-names = "hclock", "multclk", "baseclk";
+};
index 76bf087bc8898fc82f9b7d48c94cce498a85be50..74166a0d460d9f162da02166a251a8be5122bb9c 100644 (file)
@@ -102,7 +102,7 @@ not every application needs SDIO irq, e.g. MMC cards.
                pinctrl-1 = <&mmc1_idle>;
                pinctrl-2 = <&mmc1_sleep>;
                ...
-               interrupts-extended = <&intc 64 &gpio2 28 0>;
+               interrupts-extended = <&intc 64 &gpio2 28 GPIO_ACTIVE_LOW>;
        };
 
        mmc1_idle : pinmux_cirq_pin {
index 8bd78080e3a81b32b01d2793672d6f18290f3e76..d8a0aad20d6f0febeea1f71efff2542377c646cf 100644 (file)
@@ -1905,6 +1905,12 @@ L:       linux-mtd@lists.infradead.org
 S:     Supported
 F:     drivers/mtd/nand/atmel_nand*
 
+ATMEL SDMMC DRIVER
+M:     Ludovic Desroches <ludovic.desroches@atmel.com>
+L:     linux-mmc@vger.kernel.org
+S:     Supported
+F:     drivers/mmc/host/sdhci-of-at91.c
+
 ATMEL SPI DRIVER
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
 S:     Supported
index a1b820fcb2a6ff60093011d696761ba4ca15e584..c742cfd7674e0eb699b2e656cff1eba288932b6f 100644 (file)
 #include "queue.h"
 
 MODULE_ALIAS("mmc:block");
+
+#ifdef KERNEL
 #ifdef MODULE_PARAM_PREFIX
 #undef MODULE_PARAM_PREFIX
 #endif
 #define MODULE_PARAM_PREFIX "mmcblk."
+#endif
 
 #define INAND_CMD38_ARG_EXT_CSD  113
 #define INAND_CMD38_ARG_ERASE    0x00
@@ -2386,6 +2389,7 @@ force_ro_fail:
 #define CID_MANFID_TOSHIBA     0x11
 #define CID_MANFID_MICRON      0x13
 #define CID_MANFID_SAMSUNG     0x15
+#define CID_MANFID_KINGSTON    0x70
 
 static const struct mmc_fixup blk_fixups[] =
 {
@@ -2408,6 +2412,10 @@ static const struct mmc_fixup blk_fixups[] =
         *
         * N.B. This doesn't affect SD cards.
         */
+       MMC_FIXUP("SDMB-32", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       MMC_FIXUP("SDM032", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
        MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
                  MMC_QUIRK_BLK_NO_CMD23),
        MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
@@ -2444,6 +2452,15 @@ static const struct mmc_fixup blk_fixups[] =
        MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
                  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
 
+       /*
+        *  On Some Kingston eMMCs, performing trim can result in
+        *  unrecoverable data conrruption occasionally due to a firmware bug.
+        */
+       MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_TRIM_BROKEN),
+       MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_TRIM_BROKEN),
+
        END_FIXUP
 };
 
index 9ad73f30f744fd3f1f5261c6a0480ea90460a036..0520064dc33beb164aa9d80642c371e227d599b1 100644 (file)
@@ -358,8 +358,10 @@ EXPORT_SYMBOL(mmc_start_bkops);
  */
 static void mmc_wait_data_done(struct mmc_request *mrq)
 {
-       mrq->host->context_info.is_done_rcv = true;
-       wake_up_interruptible(&mrq->host->context_info.wait);
+       struct mmc_context_info *context_info = &mrq->host->context_info;
+
+       context_info->is_done_rcv = true;
+       wake_up_interruptible(&context_info->wait);
 }
 
 static void mmc_wait_done(struct mmc_request *mrq)
@@ -2168,6 +2170,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
              unsigned int arg)
 {
        unsigned int rem, to = from + nr;
+       int err;
 
        if (!(card->host->caps & MMC_CAP_ERASE) ||
            !(card->csd.cmdclass & CCC_ERASE))
@@ -2218,6 +2221,22 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
        /* 'from' and 'to' are inclusive */
        to -= 1;
 
+       /*
+        * Special case where only one erase-group fits in the timeout budget:
+        * If the region crosses an erase-group boundary on this particular
+        * case, we will be trimming more than one erase-group which, does not
+        * fit in the timeout budget of the controller, so we need to split it
+        * and call mmc_do_erase() twice if necessary. This special case is
+        * identified by the card->eg_boundary flag.
+        */
+       rem = card->erase_size - (from % card->erase_size);
+       if ((arg & MMC_TRIM_ARGS) && (card->eg_boundary) && (nr > rem)) {
+               err = mmc_do_erase(card, from, from + rem - 1, arg);
+               from += rem;
+               if ((err) || (to <= from))
+                       return err;
+       }
+
        return mmc_do_erase(card, from, to, arg);
 }
 EXPORT_SYMBOL(mmc_erase);
@@ -2233,7 +2252,8 @@ EXPORT_SYMBOL(mmc_can_erase);
 
 int mmc_can_trim(struct mmc_card *card)
 {
-       if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
+       if ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) &&
+           (!(card->quirks & MMC_QUIRK_TRIM_BROKEN)))
                return 1;
        return 0;
 }
@@ -2313,16 +2333,28 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
        if (!qty)
                return 0;
 
+       /*
+        * When specifying a sector range to trim, chances are we might cross
+        * an erase-group boundary even if the amount of sectors is less than
+        * one erase-group.
+        * If we can only fit one erase-group in the controller timeout budget,
+        * we have to care that erase-group boundaries are not crossed by a
+        * single trim operation. We flag that special case with "eg_boundary".
+        * In all other cases we can just decrement qty and pretend that we
+        * always touch (qty + 1) erase-groups as a simple optimization.
+        */
        if (qty == 1)
-               return 1;
+               card->eg_boundary = 1;
+       else
+               qty--;
 
        /* Convert qty to sectors */
        if (card->erase_shift)
-               max_discard = --qty << card->erase_shift;
+               max_discard = qty << card->erase_shift;
        else if (mmc_card_sd(card))
-               max_discard = qty;
+               max_discard = qty + 1;
        else
-               max_discard = --qty * card->erase_size;
+               max_discard = qty * card->erase_size;
 
        return max_discard;
 }
index 99a9c9011c501011db0953319dc4d82b003ead6f..abd933b7029bec26b7adebbea2db8fe3be426eb6 100644 (file)
@@ -398,7 +398,7 @@ int mmc_of_parse(struct mmc_host *host)
 {
        struct device_node *np;
        u32 bus_width;
-       int len, ret;
+       int ret;
        bool cd_cap_invert, cd_gpio_invert = false;
        bool ro_cap_invert, ro_gpio_invert = false;
 
@@ -445,12 +445,12 @@ int mmc_of_parse(struct mmc_host *host)
         */
 
        /* Parse Card Detection */
-       if (of_find_property(np, "non-removable", &len)) {
+       if (of_property_read_bool(np, "non-removable")) {
                host->caps |= MMC_CAP_NONREMOVABLE;
        } else {
                cd_cap_invert = of_property_read_bool(np, "cd-inverted");
 
-               if (of_find_property(np, "broken-cd", &len))
+               if (of_property_read_bool(np, "broken-cd"))
                        host->caps |= MMC_CAP_NEEDS_POLL;
 
                ret = mmc_gpiod_request_cd(host, "cd", 0, true,
@@ -491,41 +491,41 @@ int mmc_of_parse(struct mmc_host *host)
        if (ro_cap_invert ^ ro_gpio_invert)
                host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 
-       if (of_find_property(np, "cap-sd-highspeed", &len))
+       if (of_property_read_bool(np, "cap-sd-highspeed"))
                host->caps |= MMC_CAP_SD_HIGHSPEED;
-       if (of_find_property(np, "cap-mmc-highspeed", &len))
+       if (of_property_read_bool(np, "cap-mmc-highspeed"))
                host->caps |= MMC_CAP_MMC_HIGHSPEED;
-       if (of_find_property(np, "sd-uhs-sdr12", &len))
+       if (of_property_read_bool(np, "sd-uhs-sdr12"))
                host->caps |= MMC_CAP_UHS_SDR12;
-       if (of_find_property(np, "sd-uhs-sdr25", &len))
+       if (of_property_read_bool(np, "sd-uhs-sdr25"))
                host->caps |= MMC_CAP_UHS_SDR25;
-       if (of_find_property(np, "sd-uhs-sdr50", &len))
+       if (of_property_read_bool(np, "sd-uhs-sdr50"))
                host->caps |= MMC_CAP_UHS_SDR50;
-       if (of_find_property(np, "sd-uhs-sdr104", &len))
+       if (of_property_read_bool(np, "sd-uhs-sdr104"))
                host->caps |= MMC_CAP_UHS_SDR104;
-       if (of_find_property(np, "sd-uhs-ddr50", &len))
+       if (of_property_read_bool(np, "sd-uhs-ddr50"))
                host->caps |= MMC_CAP_UHS_DDR50;
-       if (of_find_property(np, "cap-power-off-card", &len))
+       if (of_property_read_bool(np, "cap-power-off-card"))
                host->caps |= MMC_CAP_POWER_OFF_CARD;
-       if (of_find_property(np, "cap-sdio-irq", &len))
+       if (of_property_read_bool(np, "cap-sdio-irq"))
                host->caps |= MMC_CAP_SDIO_IRQ;
-       if (of_find_property(np, "full-pwr-cycle", &len))
+       if (of_property_read_bool(np, "full-pwr-cycle"))
                host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
-       if (of_find_property(np, "keep-power-in-suspend", &len))
+       if (of_property_read_bool(np, "keep-power-in-suspend"))
                host->pm_caps |= MMC_PM_KEEP_POWER;
-       if (of_find_property(np, "enable-sdio-wakeup", &len))
+       if (of_property_read_bool(np, "enable-sdio-wakeup"))
                host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
-       if (of_find_property(np, "mmc-ddr-1_8v", &len))
+       if (of_property_read_bool(np, "mmc-ddr-1_8v"))
                host->caps |= MMC_CAP_1_8V_DDR;
-       if (of_find_property(np, "mmc-ddr-1_2v", &len))
+       if (of_property_read_bool(np, "mmc-ddr-1_2v"))
                host->caps |= MMC_CAP_1_2V_DDR;
-       if (of_find_property(np, "mmc-hs200-1_8v", &len))
+       if (of_property_read_bool(np, "mmc-hs200-1_8v"))
                host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
-       if (of_find_property(np, "mmc-hs200-1_2v", &len))
+       if (of_property_read_bool(np, "mmc-hs200-1_2v"))
                host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
-       if (of_find_property(np, "mmc-hs400-1_8v", &len))
+       if (of_property_read_bool(np, "mmc-hs400-1_8v"))
                host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
-       if (of_find_property(np, "mmc-hs400-1_2v", &len))
+       if (of_property_read_bool(np, "mmc-hs400-1_2v"))
                host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
 
        host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
index 6a0f9c79be2652bdf843c40692e7dd188d76567a..8a1e3498261e9301cffad18889c5392e6751b7a6 100644 (file)
@@ -129,6 +129,14 @@ config MMC_SDHCI_OF_ARASAN
 
          If unsure, say N.
 
+config MMC_SDHCI_OF_AT91
+       tristate "SDHCI OF support for the Atmel SDMMC controller"
+       depends on MMC_SDHCI_PLTFM
+       depends on OF
+       select MMC_SDHCI_IO_ACCESSORS
+       help
+         This selects the Atmel SDMMC driver
+
 config MMC_SDHCI_OF_ESDHC
        tristate "SDHCI OF support for the Freescale eSDHC controller"
        depends on MMC_SDHCI_PLTFM
index e928d61c5f4be3d70bd4b6d37b7852fccfe70b5d..4f3452afa6ca3d0340cb67b74a874900f61bf54d 100644 (file)
@@ -67,6 +67,7 @@ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)     += sdhci-esdhc-imx.o
 obj-$(CONFIG_MMC_SDHCI_DOVE)           += sdhci-dove.o
 obj-$(CONFIG_MMC_SDHCI_TEGRA)          += sdhci-tegra.o
 obj-$(CONFIG_MMC_SDHCI_OF_ARASAN)      += sdhci-of-arasan.o
+obj-$(CONFIG_MMC_SDHCI_OF_AT91)                += sdhci-of-at91.o
 obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)       += sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)                += sdhci-of-hlwd.o
 obj-$(CONFIG_MMC_SDHCI_BCM_KONA)       += sdhci-bcm-kona.o
index b1eac719a4cca2aa95033ace18e83b0c03a749df..dca5518b01395a31e98f3a91a2df14736e063652 100644 (file)
@@ -118,7 +118,7 @@ struct goldfish_mmc_host {
        struct mmc_host         *mmc;
        struct device           *dev;
        unsigned char           id; /* 16xx chips have 2 MMC blocks */
-       void __iomem            *virt_base;
+       void                    *virt_base;
        unsigned int            phys_base;
        int                     irq;
        unsigned char           bus_mode;
index 9a39e0b7e583625e7fa8a3f24dab0179e3da880a..bf62e429f7fcc1902d2275677d41cebca8ff5cb5 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/types.h>
-#include <linux/platform_data/atmel.h>
 #include <linux/platform_data/mmc-atmel-mci.h>
 
 #include <linux/mmc/host.h>
index de15121bba7dffe07725451890100d57abba8b25..bc76aa22473ea2f6e75f8b98d96e90b60ed99538 100644 (file)
@@ -73,6 +73,9 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
        /* It is slot 8 on Rockchip SoCs */
        host->sdio_id0 = 8;
 
+       /* It needs this quirk on all Rockchip SoCs */
+       host->pdata->quirks |= DW_MCI_QUIRK_BROKEN_DTO;
+
        return 0;
 }
 
index 40e9d8e45f25c64f1cb421807ced3af1c9ad1ca7..fcbf5524fd3136f6242036ae206239f83c90db71 100644 (file)
@@ -99,6 +99,9 @@ struct idmac_desc {
 
        __le32          des3;   /* buffer 2 physical address */
 };
+
+/* Each descriptor can transfer up to 4KB of data in chained mode */
+#define DW_MCI_DESC_DATA_LENGTH        0x1000
 #endif /* CONFIG_MMC_DW_IDMAC */
 
 static bool dw_mci_reset(struct dw_mci *host);
@@ -235,8 +238,8 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
        struct dw_mci *host = slot->host;
        const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
        u32 cmdr;
-       cmd->error = -EINPROGRESS;
 
+       cmd->error = -EINPROGRESS;
        cmdr = cmd->opcode;
 
        if (cmd->opcode == MMC_STOP_TRANSMISSION ||
@@ -371,7 +374,7 @@ static void dw_mci_start_command(struct dw_mci *host,
                 cmd->arg, cmd_flags);
 
        mci_writel(host, CMDARG, cmd->arg);
-       wmb();
+       wmb(); /* drain writebuffer */
        dw_mci_wait_while_busy(host, cmd_flags);
 
        mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
@@ -380,6 +383,7 @@ static void dw_mci_start_command(struct dw_mci *host,
 static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
 {
        struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
+
        dw_mci_start_command(host, stop, host->stop_cmdr);
 }
 
@@ -462,69 +466,102 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host)
 static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
                                    unsigned int sg_len)
 {
+       unsigned int desc_len;
        int i;
+
        if (host->dma_64bit_address == 1) {
-               struct idmac_desc_64addr *desc = host->sg_cpu;
+               struct idmac_desc_64addr *desc_first, *desc_last, *desc;
 
-               for (i = 0; i < sg_len; i++, desc++) {
+               desc_first = desc_last = desc = host->sg_cpu;
+
+               for (i = 0; i < sg_len; i++) {
                        unsigned int length = sg_dma_len(&data->sg[i]);
+
                        u64 mem_addr = sg_dma_address(&data->sg[i]);
 
-                       /*
-                        * Set the OWN bit and disable interrupts for this
-                        * descriptor
-                        */
-                       desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
-                                               IDMAC_DES0_CH;
-                       /* Buffer length */
-                       IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length);
-
-                       /* Physical address to DMA to/from */
-                       desc->des4 = mem_addr & 0xffffffff;
-                       desc->des5 = mem_addr >> 32;
+                       for ( ; length ; desc++) {
+                               desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ?
+                                          length : DW_MCI_DESC_DATA_LENGTH;
+
+                               length -= desc_len;
+
+                               /*
+                                * Set the OWN bit and disable interrupts
+                                * for this descriptor
+                                */
+                               desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
+                                                       IDMAC_DES0_CH;
+
+                               /* Buffer length */
+                               IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, desc_len);
+
+                               /* Physical address to DMA to/from */
+                               desc->des4 = mem_addr & 0xffffffff;
+                               desc->des5 = mem_addr >> 32;
+
+                               /* Update physical address for the next desc */
+                               mem_addr += desc_len;
+
+                               /* Save pointer to the last descriptor */
+                               desc_last = desc;
+                       }
                }
 
                /* Set first descriptor */
-               desc = host->sg_cpu;
-               desc->des0 |= IDMAC_DES0_FD;
+               desc_first->des0 |= IDMAC_DES0_FD;
 
                /* Set last descriptor */
-               desc = host->sg_cpu + (i - 1) *
-                               sizeof(struct idmac_desc_64addr);
-               desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
-               desc->des0 |= IDMAC_DES0_LD;
+               desc_last->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
+               desc_last->des0 |= IDMAC_DES0_LD;
 
        } else {
-               struct idmac_desc *desc = host->sg_cpu;
+               struct idmac_desc *desc_first, *desc_last, *desc;
 
-               for (i = 0; i < sg_len; i++, desc++) {
+               desc_first = desc_last = desc = host->sg_cpu;
+
+               for (i = 0; i < sg_len; i++) {
                        unsigned int length = sg_dma_len(&data->sg[i]);
+
                        u32 mem_addr = sg_dma_address(&data->sg[i]);
 
-                       /*
-                        * Set the OWN bit and disable interrupts for this
-                        * descriptor
-                        */
-                       desc->des0 = cpu_to_le32(IDMAC_DES0_OWN |
-                                       IDMAC_DES0_DIC | IDMAC_DES0_CH);
-                       /* Buffer length */
-                       IDMAC_SET_BUFFER1_SIZE(desc, length);
+                       for ( ; length ; desc++) {
+                               desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ?
+                                          length : DW_MCI_DESC_DATA_LENGTH;
+
+                               length -= desc_len;
+
+                               /*
+                                * Set the OWN bit and disable interrupts
+                                * for this descriptor
+                                */
+                               desc->des0 = cpu_to_le32(IDMAC_DES0_OWN |
+                                                        IDMAC_DES0_DIC |
+                                                        IDMAC_DES0_CH);
 
-                       /* Physical address to DMA to/from */
-                       desc->des2 = cpu_to_le32(mem_addr);
+                               /* Buffer length */
+                               IDMAC_SET_BUFFER1_SIZE(desc, desc_len);
+
+                               /* Physical address to DMA to/from */
+                               desc->des2 = cpu_to_le32(mem_addr);
+
+                               /* Update physical address for the next desc */
+                               mem_addr += desc_len;
+
+                               /* Save pointer to the last descriptor */
+                               desc_last = desc;
+                       }
                }
 
                /* Set first descriptor */
-               desc = host->sg_cpu;
-               desc->des0 |= cpu_to_le32(IDMAC_DES0_FD);
+               desc_first->des0 |= cpu_to_le32(IDMAC_DES0_FD);
 
                /* Set last descriptor */
-               desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
-               desc->des0 &= cpu_to_le32(~(IDMAC_DES0_CH | IDMAC_DES0_DIC));
-               desc->des0 |= cpu_to_le32(IDMAC_DES0_LD);
+               desc_last->des0 &= cpu_to_le32(~(IDMAC_DES0_CH |
+                                              IDMAC_DES0_DIC));
+               desc_last->des0 |= cpu_to_le32(IDMAC_DES0_LD);
        }
 
-       wmb();
+       wmb(); /* drain writebuffer */
 }
 
 static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
@@ -542,6 +579,7 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
        temp |= SDMMC_CTRL_USE_IDMAC;
        mci_writel(host, CTRL, temp);
 
+       /* drain writebuffer */
        wmb();
 
        /* Enable the IDMAC */
@@ -589,7 +627,9 @@ static int dw_mci_idmac_init(struct dw_mci *host)
                host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
 
                /* Forward link the descriptor list */
-               for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) {
+               for (i = 0, p = host->sg_cpu;
+                    i < host->ring_size - 1;
+                    i++, p++) {
                        p->des3 = cpu_to_le32(host->sg_dma +
                                        (sizeof(struct idmac_desc) * (i + 1)));
                        p->des1 = 0;
@@ -718,7 +758,7 @@ static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
        u32 fifo_width = 1 << host->data_shift;
        u32 blksz_depth = blksz / fifo_width, fifoth_val;
        u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
-       int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1;
+       int idx = ARRAY_SIZE(mszs) - 1;
 
        tx_wmark = (host->fifo_depth) / 2;
        tx_wmark_invers = host->fifo_depth - tx_wmark;
@@ -843,6 +883,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
 static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
 {
        unsigned long irqflags;
+       int flags = SG_MITER_ATOMIC;
        u32 temp;
 
        data->error = -EINPROGRESS;
@@ -859,7 +900,6 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
        }
 
        if (dw_mci_submit_data_dma(host, data)) {
-               int flags = SG_MITER_ATOMIC;
                if (host->data->flags & MMC_DATA_READ)
                        flags |= SG_MITER_TO_SG;
                else
@@ -906,7 +946,7 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
        unsigned int cmd_status = 0;
 
        mci_writel(host, CMDARG, arg);
-       wmb();
+       wmb(); /* drain writebuffer */
        dw_mci_wait_while_busy(host, cmd);
        mci_writel(host, CMD, SDMMC_CMD_START | cmd);
 
@@ -1019,7 +1059,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
 
        if (data) {
                dw_mci_submit_data(host, data);
-               wmb();
+               wmb(); /* drain writebuffer */
        }
 
        dw_mci_start_command(host, cmd, cmdflags);
@@ -1384,14 +1424,15 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        struct dw_mci_slot *slot = mmc_priv(mmc);
        struct dw_mci *host = slot->host;
        const struct dw_mci_drv_data *drv_data = host->drv_data;
-       int err = -ENOSYS;
+       int err = -EINVAL;
 
        if (drv_data && drv_data->execute_tuning)
                err = drv_data->execute_tuning(slot);
        return err;
 }
 
-static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc,
+                                      struct mmc_ios *ios)
 {
        struct dw_mci_slot *slot = mmc_priv(mmc);
        struct dw_mci *host = slot->host;
@@ -1533,6 +1574,20 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
        return data->error;
 }
 
+static void dw_mci_set_drto(struct dw_mci *host)
+{
+       unsigned int drto_clks;
+       unsigned int drto_ms;
+
+       drto_clks = mci_readl(host, TMOUT) >> 8;
+       drto_ms = DIV_ROUND_UP(drto_clks, host->bus_hz / 1000);
+
+       /* add a bit spare time */
+       drto_ms += 10;
+
+       mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms));
+}
+
 static void dw_mci_tasklet_func(unsigned long priv)
 {
        struct dw_mci *host = (struct dw_mci *)priv;
@@ -1610,8 +1665,16 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        }
 
                        if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
-                                               &host->pending_events))
+                                               &host->pending_events)) {
+                               /*
+                                * If all data-related interrupts don't come
+                                * within the given time in reading data state.
+                                */
+                               if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) &&
+                                   (host->dir_status == DW_MCI_RECV_STATUS))
+                                       dw_mci_set_drto(host);
                                break;
+                       }
 
                        set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
 
@@ -1644,8 +1707,17 @@ static void dw_mci_tasklet_func(unsigned long priv)
 
                case STATE_DATA_BUSY:
                        if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
-                                               &host->pending_events))
+                                               &host->pending_events)) {
+                               /*
+                                * If data error interrupt comes but data over
+                                * interrupt doesn't come within the given time.
+                                * in reading data state.
+                                */
+                               if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) &&
+                                   (host->dir_status == DW_MCI_RECV_STATUS))
+                                       dw_mci_set_drto(host);
                                break;
+                       }
 
                        host->data = NULL;
                        set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
@@ -1743,7 +1815,7 @@ static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
 /* pull first bytes from part_buf, only use during pull */
 static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
 {
-       cnt = min(cnt, (int)host->part_buf_count);
+       cnt = min_t(int, cnt, host->part_buf_count);
        if (cnt) {
                memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
                       cnt);
@@ -1769,6 +1841,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
        /* try and push anything in the part_buf */
        if (unlikely(host->part_buf_count)) {
                int len = dw_mci_push_part_bytes(host, buf, cnt);
+
                buf += len;
                cnt -= len;
                if (host->part_buf_count == 2) {
@@ -1795,6 +1868,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
 #endif
        {
                u16 *pdata = buf;
+
                for (; cnt >= 2; cnt -= 2)
                        mci_fifo_writew(host->fifo_reg, *pdata++);
                buf = pdata;
@@ -1819,6 +1893,7 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
                        int len = min(cnt & -2, (int)sizeof(aligned_buf));
                        int items = len >> 1;
                        int i;
+
                        for (i = 0; i < items; ++i)
                                aligned_buf[i] = mci_fifo_readw(host->fifo_reg);
                        /* memcpy from aligned buffer into output buffer */
@@ -1830,6 +1905,7 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
 #endif
        {
                u16 *pdata = buf;
+
                for (; cnt >= 2; cnt -= 2)
                        *pdata++ = mci_fifo_readw(host->fifo_reg);
                buf = pdata;
@@ -1848,6 +1924,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
        /* try and push anything in the part_buf */
        if (unlikely(host->part_buf_count)) {
                int len = dw_mci_push_part_bytes(host, buf, cnt);
+
                buf += len;
                cnt -= len;
                if (host->part_buf_count == 4) {
@@ -1874,6 +1951,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
 #endif
        {
                u32 *pdata = buf;
+
                for (; cnt >= 4; cnt -= 4)
                        mci_fifo_writel(host->fifo_reg, *pdata++);
                buf = pdata;
@@ -1898,6 +1976,7 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
                        int len = min(cnt & -4, (int)sizeof(aligned_buf));
                        int items = len >> 2;
                        int i;
+
                        for (i = 0; i < items; ++i)
                                aligned_buf[i] = mci_fifo_readl(host->fifo_reg);
                        /* memcpy from aligned buffer into output buffer */
@@ -1909,6 +1988,7 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
 #endif
        {
                u32 *pdata = buf;
+
                for (; cnt >= 4; cnt -= 4)
                        *pdata++ = mci_fifo_readl(host->fifo_reg);
                buf = pdata;
@@ -1927,6 +2007,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
        /* try and push anything in the part_buf */
        if (unlikely(host->part_buf_count)) {
                int len = dw_mci_push_part_bytes(host, buf, cnt);
+
                buf += len;
                cnt -= len;
 
@@ -1954,6 +2035,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
 #endif
        {
                u64 *pdata = buf;
+
                for (; cnt >= 8; cnt -= 8)
                        mci_fifo_writeq(host->fifo_reg, *pdata++);
                buf = pdata;
@@ -1978,6 +2060,7 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
                        int len = min(cnt & -8, (int)sizeof(aligned_buf));
                        int items = len >> 3;
                        int i;
+
                        for (i = 0; i < items; ++i)
                                aligned_buf[i] = mci_fifo_readq(host->fifo_reg);
 
@@ -1990,6 +2073,7 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
 #endif
        {
                u64 *pdata = buf;
+
                for (; cnt >= 8; cnt -= 8)
                        *pdata++ = mci_fifo_readq(host->fifo_reg);
                buf = pdata;
@@ -2065,7 +2149,7 @@ static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
 done:
        sg_miter_stop(sg_miter);
        host->sg = NULL;
-       smp_wmb();
+       smp_wmb(); /* drain writebuffer */
        set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
 }
 
@@ -2119,7 +2203,7 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
 done:
        sg_miter_stop(sg_miter);
        host->sg = NULL;
-       smp_wmb();
+       smp_wmb(); /* drain writebuffer */
        set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
 }
 
@@ -2128,7 +2212,7 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
        if (!host->cmd_status)
                host->cmd_status = status;
 
-       smp_wmb();
+       smp_wmb(); /* drain writebuffer */
 
        set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
        tasklet_schedule(&host->tasklet);
@@ -2192,7 +2276,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                if (pending & DW_MCI_CMD_ERROR_FLAGS) {
                        mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
                        host->cmd_status = pending;
-                       smp_wmb();
+                       smp_wmb(); /* drain writebuffer */
                        set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
                }
 
@@ -2200,16 +2284,19 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                        /* if there is an error report DATA_ERROR */
                        mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
                        host->data_status = pending;
-                       smp_wmb();
+                       smp_wmb(); /* drain writebuffer */
                        set_bit(EVENT_DATA_ERROR, &host->pending_events);
                        tasklet_schedule(&host->tasklet);
                }
 
                if (pending & SDMMC_INT_DATA_OVER) {
+                       if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)
+                               del_timer(&host->dto_timer);
+
                        mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
                        if (!host->data_status)
                                host->data_status = pending;
-                       smp_wmb();
+                       smp_wmb(); /* drain writebuffer */
                        if (host->dir_status == DW_MCI_RECV_STATUS) {
                                if (host->sg != NULL)
                                        dw_mci_read_data_pio(host, true);
@@ -2383,27 +2470,20 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        if (ret)
                goto err_host_allocated;
 
-       if (host->pdata->blk_settings) {
-               mmc->max_segs = host->pdata->blk_settings->max_segs;
-               mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
-               mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
-               mmc->max_req_size = host->pdata->blk_settings->max_req_size;
-               mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
-       } else {
-               /* Useful defaults if platform data is unset. */
-#ifdef CONFIG_MMC_DW_IDMAC
+       /* Useful defaults if platform data is unset. */
+       if (host->use_dma) {
                mmc->max_segs = host->ring_size;
                mmc->max_blk_size = 65536;
                mmc->max_seg_size = 0x1000;
                mmc->max_req_size = mmc->max_seg_size * host->ring_size;
                mmc->max_blk_count = mmc->max_req_size / 512;
-#else
+       } else {
                mmc->max_segs = 64;
                mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
                mmc->max_blk_count = 512;
-               mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+               mmc->max_req_size = mmc->max_blk_size *
+                                   mmc->max_blk_count;
                mmc->max_seg_size = mmc->max_req_size;
-#endif /* CONFIG_MMC_DW_IDMAC */
        }
 
        if (dw_mci_get_cd(mmc))
@@ -2473,8 +2553,8 @@ static void dw_mci_init_dma(struct dw_mci *host)
        if (host->dma_ops->init && host->dma_ops->start &&
            host->dma_ops->stop && host->dma_ops->cleanup) {
                if (host->dma_ops->init(host)) {
-                       dev_err(host->dev, "%s: Unable to initialize "
-                               "DMA Controller.\n", __func__);
+                       dev_err(host->dev, "%s: Unable to initialize DMA Controller.\n",
+                               __func__);
                        goto no_dma;
                }
        } else {
@@ -2488,7 +2568,6 @@ static void dw_mci_init_dma(struct dw_mci *host)
 no_dma:
        dev_info(host->dev, "Using PIO mode.\n");
        host->use_dma = 0;
-       return;
 }
 
 static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
@@ -2542,6 +2621,7 @@ static bool dw_mci_reset(struct dw_mci *host)
                if (host->use_dma) {
                        unsigned long timeout = jiffies + msecs_to_jiffies(500);
                        u32 status;
+
                        do {
                                status = mci_readl(host, STATUS);
                                if (!(status & SDMMC_STATUS_DMA_REQ))
@@ -2551,8 +2631,8 @@ static bool dw_mci_reset(struct dw_mci *host)
 
                        if (status & SDMMC_STATUS_DMA_REQ) {
                                dev_err(host->dev,
-                                       "%s: Timeout waiting for dma_req to "
-                                       "clear during reset\n", __func__);
+                                       "%s: Timeout waiting for dma_req to clear during reset\n",
+                                       __func__);
                                goto ciu_out;
                        }
 
@@ -2563,8 +2643,8 @@ static bool dw_mci_reset(struct dw_mci *host)
        } else {
                /* if the controller reset bit did clear, then set clock regs */
                if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) {
-                       dev_err(host->dev, "%s: fifo/dma reset bits didn't "
-                               "clear but ciu was reset, doing clock update\n",
+                       dev_err(host->dev,
+                               "%s: fifo/dma reset bits didn't clear but ciu was reset, doing clock update\n",
                                __func__);
                        goto ciu_out;
                }
@@ -2598,6 +2678,28 @@ static void dw_mci_cmd11_timer(unsigned long arg)
        tasklet_schedule(&host->tasklet);
 }
 
+static void dw_mci_dto_timer(unsigned long arg)
+{
+       struct dw_mci *host = (struct dw_mci *)arg;
+
+       switch (host->state) {
+       case STATE_SENDING_DATA:
+       case STATE_DATA_BUSY:
+               /*
+                * If DTO interrupt does NOT come in sending data state,
+                * we should notify the driver to terminate current transfer
+                * and report a data timeout to the core.
+                */
+               host->data_status = SDMMC_INT_DRTO;
+               set_bit(EVENT_DATA_ERROR, &host->pending_events);
+               set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
+               tasklet_schedule(&host->tasklet);
+               break;
+       default:
+               break;
+       }
+}
+
 #ifdef CONFIG_OF
 static struct dw_mci_of_quirks {
        char *quirk;
@@ -2625,8 +2727,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
        /* find out number of slots supported */
        if (of_property_read_u32(dev->of_node, "num-slots",
                                &pdata->num_slots)) {
-               dev_info(dev, "num-slots property not found, "
-                               "assuming 1 slot is available\n");
+               dev_info(dev,
+                        "num-slots property not found, assuming 1 slot is available\n");
                pdata->num_slots = 1;
        }
 
@@ -2636,8 +2738,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
                        pdata->quirks |= of_quirks[idx].id;
 
        if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
-               dev_info(dev, "fifo-depth property not found, using "
-                               "value of FIFOTH register as default\n");
+               dev_info(dev,
+                        "fifo-depth property not found, using value of FIFOTH register as default\n");
 
        of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
 
@@ -2650,8 +2752,10 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
                        return ERR_PTR(ret);
        }
 
-       if (of_find_property(np, "supports-highspeed", NULL))
+       if (of_find_property(np, "supports-highspeed", NULL)) {
+               dev_info(dev, "supports-highspeed property is deprecated.\n");
                pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
+       }
 
        return pdata;
 }
@@ -2706,7 +2810,7 @@ int dw_mci_probe(struct dw_mci *host)
                }
        }
 
-       if (host->pdata->num_slots > 1) {
+       if (host->pdata->num_slots < 1) {
                dev_err(host->dev,
                        "Platform data must supply num_slots.\n");
                return -ENODEV;
@@ -2774,6 +2878,10 @@ int dw_mci_probe(struct dw_mci *host)
 
        host->quirks = host->pdata->quirks;
 
+       if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)
+               setup_timer(&host->dto_timer,
+                           dw_mci_dto_timer, (unsigned long)host);
+
        spin_lock_init(&host->lock);
        spin_lock_init(&host->irq_lock);
        INIT_LIST_HEAD(&host->queue);
@@ -2874,11 +2982,11 @@ int dw_mci_probe(struct dw_mci *host)
        mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
                   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
                   DW_MCI_ERROR_FLAGS);
-       mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
+       /* Enable mci interrupt */
+       mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
 
-       dev_info(host->dev, "DW MMC controller at irq %d, "
-                "%d bit host data width, "
-                "%u deep fifo\n",
+       dev_info(host->dev,
+                "DW MMC controller at irq %d,%d bit host data width,%u deep fifo\n",
                 host->irq, width, fifo_size);
 
        /* We need at least one slot to succeed */
@@ -2893,8 +3001,9 @@ int dw_mci_probe(struct dw_mci *host)
        if (init_slots) {
                dev_info(host->dev, "%d slots initialized\n", init_slots);
        } else {
-               dev_dbg(host->dev, "attempted to initialize %d slots, "
-                                       "but failed on all\n", host->num_slots);
+               dev_dbg(host->dev,
+                       "attempted to initialize %d slots, but failed on all\n",
+                       host->num_slots);
                goto err_dmaunmap;
        }
 
@@ -2992,6 +3101,7 @@ int dw_mci_resume(struct dw_mci *host)
 
        for (i = 0; i < host->num_slots; i++) {
                struct dw_mci_slot *slot = host->slot[i];
+
                if (!slot)
                        continue;
                if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
index 68dd6c79c378c8a355a36e23300eb996bfcbc720..b763b11ed9e1e72320a2d8e4a8d9e393b229766e 100644 (file)
@@ -948,6 +948,7 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
 {
        struct mmc_data *data = req->data;
        int i, use_dma = 1, block_size;
+       struct scatterlist *sg;
        unsigned sg_len;
 
        host->data = data;
@@ -972,8 +973,8 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
        sg_len = (data->blocks == 1) ? 1 : data->sg_len;
 
        /* Only do DMA for entire blocks */
-       for (i = 0; i < sg_len; i++) {
-               if ((data->sg[i].length % block_size) != 0) {
+       for_each_sg(data->sg, sg, sg_len, i) {
+               if ((sg->length % block_size) != 0) {
                        use_dma = 0;
                        break;
                }
@@ -1419,8 +1420,10 @@ static int mmc_omap_probe(struct platform_device *pdev)
        host->reg_shift = (mmc_omap7xx() ? 1 : 2);
 
        host->mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0);
-       if (!host->mmc_omap_wq)
+       if (!host->mmc_omap_wq) {
+               ret = -ENOMEM;
                goto err_plat_cleanup;
+       }
 
        for (i = 0; i < pdata->nr_slots; i++) {
                ret = mmc_omap_new_slot(host, i);
index 4d120323689043f21c522b44389757f8391d45fc..781e4db317671ce6146dea121a56f42f90e7c491 100644 (file)
@@ -181,18 +181,9 @@ struct omap_hsmmc_host {
        struct  mmc_data        *data;
        struct  clk             *fclk;
        struct  clk             *dbclk;
-       /*
-        * vcc == configured supply
-        * vcc_aux == optional
-        *   -  MMC1, supply for DAT4..DAT7
-        *   -  MMC2/MMC2, external level shifter voltage supply, for
-        *      chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
-        */
-       struct  regulator       *vcc;
-       struct  regulator       *vcc_aux;
        struct  regulator       *pbias;
-       bool                    pbias_enabled;
        void    __iomem         *base;
+       int                     vqmmc_enabled;
        resource_size_t         mapbase;
        spinlock_t              irq_lock; /* Prevent races with irq handler */
        unsigned int            dma_len;
@@ -213,7 +204,6 @@ struct omap_hsmmc_host {
        int                     context_loss;
        int                     protect_card;
        int                     reqs_blocked;
-       int                     use_reg;
        int                     req_in_progress;
        unsigned long           clk_rate;
        unsigned int            flags;
@@ -254,32 +244,133 @@ static int omap_hsmmc_get_cover_state(struct device *dev)
        return mmc_gpio_get_cd(host->mmc);
 }
 
-#ifdef CONFIG_REGULATOR
+static int omap_hsmmc_enable_supply(struct mmc_host *mmc)
+{
+       int ret;
+       struct omap_hsmmc_host *host = mmc_priv(mmc);
+       struct mmc_ios *ios = &mmc->ios;
+
+       if (mmc->supply.vmmc) {
+               ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
+               if (ret)
+                       return ret;
+       }
+
+       /* Enable interface voltage rail, if needed */
+       if (mmc->supply.vqmmc && !host->vqmmc_enabled) {
+               ret = regulator_enable(mmc->supply.vqmmc);
+               if (ret) {
+                       dev_err(mmc_dev(mmc), "vmmc_aux reg enable failed\n");
+                       goto err_vqmmc;
+               }
+               host->vqmmc_enabled = 1;
+       }
+
+       return 0;
+
+err_vqmmc:
+       if (mmc->supply.vmmc)
+               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+
+       return ret;
+}
+
+static int omap_hsmmc_disable_supply(struct mmc_host *mmc)
+{
+       int ret;
+       int status;
+       struct omap_hsmmc_host *host = mmc_priv(mmc);
+
+       if (mmc->supply.vqmmc && host->vqmmc_enabled) {
+               ret = regulator_disable(mmc->supply.vqmmc);
+               if (ret) {
+                       dev_err(mmc_dev(mmc), "vmmc_aux reg disable failed\n");
+                       return ret;
+               }
+               host->vqmmc_enabled = 0;
+       }
+
+       if (mmc->supply.vmmc) {
+               ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+               if (ret)
+                       goto err_set_ocr;
+       }
+
+       return 0;
+
+err_set_ocr:
+       if (mmc->supply.vqmmc) {
+               status = regulator_enable(mmc->supply.vqmmc);
+               if (status)
+                       dev_err(mmc_dev(mmc), "vmmc_aux re-enable failed\n");
+       }
+
+       return ret;
+}
+
+static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,
+                               int vdd)
+{
+       int ret;
+
+       if (!host->pbias)
+               return 0;
+
+       if (power_on) {
+               if (vdd <= VDD_165_195)
+                       ret = regulator_set_voltage(host->pbias, VDD_1V8,
+                                                   VDD_1V8);
+               else
+                       ret = regulator_set_voltage(host->pbias, VDD_3V0,
+                                                   VDD_3V0);
+               if (ret < 0) {
+                       dev_err(host->dev, "pbias set voltage fail\n");
+                       return ret;
+               }
+
+               if (!regulator_is_enabled(host->pbias)) {
+                       ret = regulator_enable(host->pbias);
+                       if (ret) {
+                               dev_err(host->dev, "pbias reg enable fail\n");
+                               return ret;
+                       }
+               }
+       } else {
+               if (regulator_is_enabled(host->pbias)) {
+                       ret = regulator_disable(host->pbias);
+                       if (ret) {
+                               dev_err(host->dev, "pbias reg disable fail\n");
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
 
 static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
 {
        struct omap_hsmmc_host *host =
                platform_get_drvdata(to_platform_device(dev));
+       struct mmc_host *mmc = host->mmc;
        int ret = 0;
 
+       if (mmc_pdata(host)->set_power)
+               return mmc_pdata(host)->set_power(dev, power_on, vdd);
+
        /*
         * If we don't see a Vcc regulator, assume it's a fixed
         * voltage always-on regulator.
         */
-       if (!host->vcc)
+       if (!mmc->supply.vmmc)
                return 0;
 
        if (mmc_pdata(host)->before_set_reg)
                mmc_pdata(host)->before_set_reg(dev, power_on, vdd);
 
-       if (host->pbias) {
-               if (host->pbias_enabled == 1) {
-                       ret = regulator_disable(host->pbias);
-                       if (!ret)
-                               host->pbias_enabled = 0;
-               }
-               regulator_set_voltage(host->pbias, VDD_3V0, VDD_3V0);
-       }
+       ret = omap_hsmmc_set_pbias(host, false, 0);
+       if (ret)
+               return ret;
 
        /*
         * Assume Vcc regulator is used only to power the card ... OMAP
@@ -295,129 +386,138 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
         * chips/cards need an interface voltage rail too.
         */
        if (power_on) {
-               if (host->vcc)
-                       ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
-               /* Enable interface voltage rail, if needed */
-               if (ret == 0 && host->vcc_aux) {
-                       ret = regulator_enable(host->vcc_aux);
-                       if (ret < 0 && host->vcc)
-                               ret = mmc_regulator_set_ocr(host->mmc,
-                                                       host->vcc, 0);
-               }
-       } else {
-               /* Shut down the rail */
-               if (host->vcc_aux)
-                       ret = regulator_disable(host->vcc_aux);
-               if (host->vcc) {
-                       /* Then proceed to shut down the local regulator */
-                       ret = mmc_regulator_set_ocr(host->mmc,
-                                               host->vcc, 0);
-               }
-       }
-
-       if (host->pbias) {
-               if (vdd <= VDD_165_195)
-                       ret = regulator_set_voltage(host->pbias, VDD_1V8,
-                                                               VDD_1V8);
-               else
-                       ret = regulator_set_voltage(host->pbias, VDD_3V0,
-                                                               VDD_3V0);
-               if (ret < 0)
-                       goto error_set_power;
+               ret = omap_hsmmc_enable_supply(mmc);
+               if (ret)
+                       return ret;
 
-               if (host->pbias_enabled == 0) {
-                       ret = regulator_enable(host->pbias);
-                       if (!ret)
-                               host->pbias_enabled = 1;
-               }
+               ret = omap_hsmmc_set_pbias(host, true, vdd);
+               if (ret)
+                       goto err_set_voltage;
+       } else {
+               ret = omap_hsmmc_disable_supply(mmc);
+               if (ret)
+                       return ret;
        }
 
        if (mmc_pdata(host)->after_set_reg)
                mmc_pdata(host)->after_set_reg(dev, power_on, vdd);
 
-error_set_power:
+       return 0;
+
+err_set_voltage:
+       omap_hsmmc_disable_supply(mmc);
+
        return ret;
 }
 
-static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
+static int omap_hsmmc_disable_boot_regulator(struct regulator *reg)
 {
-       struct regulator *reg;
-       int ocr_value = 0;
+       int ret;
 
-       reg = devm_regulator_get(host->dev, "vmmc");
-       if (IS_ERR(reg)) {
-               dev_err(host->dev, "unable to get vmmc regulator %ld\n",
-                       PTR_ERR(reg));
-               return PTR_ERR(reg);
-       } else {
-               host->vcc = reg;
-               ocr_value = mmc_regulator_get_ocrmask(reg);
-               if (!mmc_pdata(host)->ocr_mask) {
-                       mmc_pdata(host)->ocr_mask = ocr_value;
-               } else {
-                       if (!(mmc_pdata(host)->ocr_mask & ocr_value)) {
-                               dev_err(host->dev, "ocrmask %x is not supported\n",
-                                       mmc_pdata(host)->ocr_mask);
-                               mmc_pdata(host)->ocr_mask = 0;
-                               return -EINVAL;
-                       }
-               }
+       if (!reg)
+               return 0;
+
+       if (regulator_is_enabled(reg)) {
+               ret = regulator_enable(reg);
+               if (ret)
+                       return ret;
+
+               ret = regulator_disable(reg);
+               if (ret)
+                       return ret;
        }
-       mmc_pdata(host)->set_power = omap_hsmmc_set_power;
 
-       /* Allow an aux regulator */
-       reg = devm_regulator_get_optional(host->dev, "vmmc_aux");
-       host->vcc_aux = IS_ERR(reg) ? NULL : reg;
+       return 0;
+}
 
-       reg = devm_regulator_get_optional(host->dev, "pbias");
-       host->pbias = IS_ERR(reg) ? NULL : reg;
+static int omap_hsmmc_disable_boot_regulators(struct omap_hsmmc_host *host)
+{
+       struct mmc_host *mmc = host->mmc;
+       int ret;
 
-       /* For eMMC do not power off when not in sleep state */
-       if (mmc_pdata(host)->no_regulator_off_init)
-               return 0;
        /*
-        * To disable boot_on regulator, enable regulator
-        * to increase usecount and then disable it.
+        * disable regulators enabled during boot and get the usecount
+        * right so that regulators can be enabled/disabled by checking
+        * the return value of regulator_is_enabled
         */
-       if ((host->vcc && regulator_is_enabled(host->vcc) > 0) ||
-           (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) {
-               int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1;
+       ret = omap_hsmmc_disable_boot_regulator(mmc->supply.vmmc);
+       if (ret) {
+               dev_err(host->dev, "fail to disable boot enabled vmmc reg\n");
+               return ret;
+       }
+
+       ret = omap_hsmmc_disable_boot_regulator(mmc->supply.vqmmc);
+       if (ret) {
+               dev_err(host->dev,
+                       "fail to disable boot enabled vmmc_aux reg\n");
+               return ret;
+       }
 
-               mmc_pdata(host)->set_power(host->dev, 1, vdd);
-               mmc_pdata(host)->set_power(host->dev, 0, 0);
+       ret = omap_hsmmc_disable_boot_regulator(host->pbias);
+       if (ret) {
+               dev_err(host->dev,
+                       "failed to disable boot enabled pbias reg\n");
+               return ret;
        }
 
        return 0;
 }
 
-static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
+static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 {
-       mmc_pdata(host)->set_power = NULL;
-}
+       int ocr_value = 0;
+       int ret;
+       struct mmc_host *mmc = host->mmc;
 
-static inline int omap_hsmmc_have_reg(void)
-{
-       return 1;
-}
+       if (mmc_pdata(host)->set_power)
+               return 0;
 
-#else
+       mmc->supply.vmmc = devm_regulator_get_optional(host->dev, "vmmc");
+       if (IS_ERR(mmc->supply.vmmc)) {
+               ret = PTR_ERR(mmc->supply.vmmc);
+               if (ret != -ENODEV)
+                       return ret;
+               dev_dbg(host->dev, "unable to get vmmc regulator %ld\n",
+                       PTR_ERR(mmc->supply.vmmc));
+               mmc->supply.vmmc = NULL;
+       } else {
+               ocr_value = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
+               if (ocr_value > 0)
+                       mmc_pdata(host)->ocr_mask = ocr_value;
+       }
 
-static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
-{
-       return -EINVAL;
-}
+       /* Allow an aux regulator */
+       mmc->supply.vqmmc = devm_regulator_get_optional(host->dev, "vmmc_aux");
+       if (IS_ERR(mmc->supply.vqmmc)) {
+               ret = PTR_ERR(mmc->supply.vqmmc);
+               if (ret != -ENODEV)
+                       return ret;
+               dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n",
+                       PTR_ERR(mmc->supply.vqmmc));
+               mmc->supply.vqmmc = NULL;
+       }
 
-static inline void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
-{
-}
+       host->pbias = devm_regulator_get_optional(host->dev, "pbias");
+       if (IS_ERR(host->pbias)) {
+               ret = PTR_ERR(host->pbias);
+               if (ret != -ENODEV)
+                       return ret;
+               dev_dbg(host->dev, "unable to get pbias regulator %ld\n",
+                       PTR_ERR(host->pbias));
+               host->pbias = NULL;
+       }
+
+       /* For eMMC do not power off when not in sleep state */
+       if (mmc_pdata(host)->no_regulator_off_init)
+               return 0;
+
+       ret = omap_hsmmc_disable_boot_regulators(host);
+       if (ret)
+               return ret;
 
-static inline int omap_hsmmc_have_reg(void)
-{
        return 0;
 }
 
-#endif
-
 static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id);
 
 static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
@@ -1149,11 +1249,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
                clk_disable_unprepare(host->dbclk);
 
        /* Turn the power off */
-       ret = mmc_pdata(host)->set_power(host->dev, 0, 0);
+       ret = omap_hsmmc_set_power(host->dev, 0, 0);
 
        /* Turn the power ON with given VDD 1.8 or 3.0v */
        if (!ret)
-               ret = mmc_pdata(host)->set_power(host->dev, 1, vdd);
+               ret = omap_hsmmc_set_power(host->dev, 1, vdd);
        pm_runtime_get_sync(host->dev);
        if (host->dbclk)
                clk_prepare_enable(host->dbclk);
@@ -1552,10 +1652,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        if (ios->power_mode != host->power_mode) {
                switch (ios->power_mode) {
                case MMC_POWER_OFF:
-                       mmc_pdata(host)->set_power(host->dev, 0, 0);
+                       omap_hsmmc_set_power(host->dev, 0, 0);
                        break;
                case MMC_POWER_UP:
-                       mmc_pdata(host)->set_power(host->dev, 1, ios->vdd);
+                       omap_hsmmc_set_power(host->dev, 1, ios->vdd);
                        break;
                case MMC_POWER_ON:
                        do_send_init_stream = 1;
@@ -1953,7 +2053,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
        host->base      = base + pdata->reg_offset;
        host->power_mode = MMC_POWER_OFF;
        host->next_data.cookie = 1;
-       host->pbias_enabled = 0;
+       host->vqmmc_enabled = 0;
 
        ret = omap_hsmmc_gpio_init(mmc, host, pdata);
        if (ret)
@@ -2078,12 +2178,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
-       if (omap_hsmmc_have_reg() && !mmc_pdata(host)->set_power) {
-               ret = omap_hsmmc_reg_get(host);
-               if (ret)
-                       goto err_irq;
-               host->use_reg = 1;
-       }
+       ret = omap_hsmmc_reg_get(host);
+       if (ret)
+               goto err_irq;
 
        mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
 
@@ -2125,8 +2222,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
 
 err_slot_name:
        mmc_remove_host(mmc);
-       if (host->use_reg)
-               omap_hsmmc_reg_put(host);
 err_irq:
        device_init_wakeup(&pdev->dev, false);
        if (host->tx_chan)
@@ -2150,8 +2245,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
 
        pm_runtime_get_sync(host->dev);
        mmc_remove_host(host->mmc);
-       if (host->use_reg)
-               omap_hsmmc_reg_put(host);
 
        if (host->tx_chan)
                dma_release_channel(host->tx_chan);
index 1b6d0bfe35f53c2d474d884feda7c7b1271911c7..1420f29628c70d8e8fdedbfa3fe7d77f1ba0ae0b 100644 (file)
@@ -22,7 +22,9 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma/pxa-dma.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/mmc/host.h>
@@ -37,7 +39,6 @@
 #include <asm/sizes.h>
 
 #include <mach/hardware.h>
-#include <mach/dma.h>
 #include <linux/platform_data/mmc-pxamci.h>
 
 #include "pxamci.h"
@@ -58,7 +59,6 @@ struct pxamci_host {
        struct clk              *clk;
        unsigned long           clkrate;
        int                     irq;
-       int                     dma;
        unsigned int            clkrt;
        unsigned int            cmdat;
        unsigned int            imask;
@@ -69,8 +69,10 @@ struct pxamci_host {
        struct mmc_command      *cmd;
        struct mmc_data         *data;
 
+       struct dma_chan         *dma_chan_rx;
+       struct dma_chan         *dma_chan_tx;
+       dma_cookie_t            dma_cookie;
        dma_addr_t              sg_dma;
-       struct pxa_dma_desc     *sg_cpu;
        unsigned int            dma_len;
 
        unsigned int            dma_dir;
@@ -173,14 +175,18 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static void pxamci_dma_irq(void *param);
+
 static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 {
+       struct dma_async_tx_descriptor *tx;
+       enum dma_data_direction direction;
+       struct dma_slave_config config;
+       struct dma_chan *chan;
        unsigned int nob = data->blocks;
        unsigned long long clks;
        unsigned int timeout;
-       bool dalgn = 0;
-       u32 dcmd;
-       int i;
+       int ret;
 
        host->data = data;
 
@@ -195,54 +201,48 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
        timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
        writel((timeout + 255) / 256, host->base + MMC_RDTO);
 
+       memset(&config, 0, sizeof(config));
+       config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       config.src_addr = host->res->start + MMC_RXFIFO;
+       config.dst_addr = host->res->start + MMC_TXFIFO;
+       config.src_maxburst = 32;
+       config.dst_maxburst = 32;
+
        if (data->flags & MMC_DATA_READ) {
                host->dma_dir = DMA_FROM_DEVICE;
-               dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
-               DRCMR(host->dma_drcmrtx) = 0;
-               DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
+               direction = DMA_DEV_TO_MEM;
+               chan = host->dma_chan_rx;
        } else {
                host->dma_dir = DMA_TO_DEVICE;
-               dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
-               DRCMR(host->dma_drcmrrx) = 0;
-               DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
+               direction = DMA_MEM_TO_DEV;
+               chan = host->dma_chan_tx;
        }
 
-       dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
+       config.direction = direction;
+
+       ret = dmaengine_slave_config(chan, &config);
+       if (ret < 0) {
+               dev_err(mmc_dev(host->mmc), "dma slave config failed\n");
+               return;
+       }
 
-       host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+       host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
                                   host->dma_dir);
 
-       for (i = 0; i < host->dma_len; i++) {
-               unsigned int length = sg_dma_len(&data->sg[i]);
-               host->sg_cpu[i].dcmd = dcmd | length;
-               if (length & 31 && !(data->flags & MMC_DATA_READ))
-                       host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
-               /* Not aligned to 8-byte boundary? */
-               if (sg_dma_address(&data->sg[i]) & 0x7)
-                       dalgn = 1;
-               if (data->flags & MMC_DATA_READ) {
-                       host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
-                       host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
-               } else {
-                       host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
-                       host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
-               }
-               host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
-                                       sizeof(struct pxa_dma_desc);
+       tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction,
+                                    DMA_PREP_INTERRUPT);
+       if (!tx) {
+               dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n");
+               return;
        }
-       host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
-       wmb();
 
-       /*
-        * The PXA27x DMA controller encounters overhead when working with
-        * unaligned (to 8-byte boundaries) data, so switch on byte alignment
-        * mode only if we have unaligned data.
-        */
-       if (dalgn)
-               DALGN |= (1 << host->dma);
-       else
-               DALGN &= ~(1 << host->dma);
-       DDADR(host->dma) = host->sg_dma;
+       if (!(data->flags & MMC_DATA_READ)) {
+               tx->callback = pxamci_dma_irq;
+               tx->callback_param = host;
+       }
+
+       host->dma_cookie = dmaengine_submit(tx);
 
        /*
         * workaround for erratum #91:
@@ -251,7 +251,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
         * before starting DMA.
         */
        if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
-               DCSR(host->dma) = DCSR_RUN;
+               dma_async_issue_pending(chan);
 }
 
 static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
@@ -343,7 +343,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
                 * enable DMA late
                 */
                if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
-                       DCSR(host->dma) = DCSR_RUN;
+                       dma_async_issue_pending(host->dma_chan_tx);
        } else {
                pxamci_finish_request(host, host->mrq);
        }
@@ -354,13 +354,17 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
 static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
 {
        struct mmc_data *data = host->data;
+       struct dma_chan *chan;
 
        if (!data)
                return 0;
 
-       DCSR(host->dma) = 0;
-       dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-                    host->dma_dir);
+       if (data->flags & MMC_DATA_READ)
+               chan = host->dma_chan_rx;
+       else
+               chan = host->dma_chan_tx;
+       dma_unmap_sg(chan->device->dev,
+                    data->sg, data->sg_len, host->dma_dir);
 
        if (stat & STAT_READ_TIME_OUT)
                data->error = -ETIMEDOUT;
@@ -552,20 +556,37 @@ static const struct mmc_host_ops pxamci_ops = {
        .enable_sdio_irq        = pxamci_enable_sdio_irq,
 };
 
-static void pxamci_dma_irq(int dma, void *devid)
+static void pxamci_dma_irq(void *param)
 {
-       struct pxamci_host *host = devid;
-       int dcsr = DCSR(dma);
-       DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
+       struct pxamci_host *host = param;
+       struct dma_tx_state state;
+       enum dma_status status;
+       struct dma_chan *chan;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (!host->data)
+               goto out_unlock;
 
-       if (dcsr & DCSR_ENDINTR) {
+       if (host->data->flags & MMC_DATA_READ)
+               chan = host->dma_chan_rx;
+       else
+               chan = host->dma_chan_tx;
+
+       status = dmaengine_tx_status(chan, host->dma_cookie, &state);
+
+       if (likely(status == DMA_COMPLETE)) {
                writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
        } else {
-               pr_err("%s: DMA error on channel %d (DCSR=%#x)\n",
-                      mmc_hostname(host->mmc), dma, dcsr);
+               pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc),
+                       host->data->flags & MMC_DATA_READ ? "rx" : "tx");
                host->data->error = -EIO;
                pxamci_data_done(host, 0);
        }
+
+out_unlock:
+       spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static irqreturn_t pxamci_detect_irq(int irq, void *devid)
@@ -625,7 +646,9 @@ static int pxamci_probe(struct platform_device *pdev)
        struct mmc_host *mmc;
        struct pxamci_host *host = NULL;
        struct resource *r, *dmarx, *dmatx;
+       struct pxad_param param_rx, param_tx;
        int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
+       dma_cap_mask_t mask;
 
        ret = pxamci_of_init(pdev);
        if (ret)
@@ -671,7 +694,6 @@ static int pxamci_probe(struct platform_device *pdev)
 
        host = mmc_priv(mmc);
        host->mmc = mmc;
-       host->dma = -1;
        host->pdata = pdev->dev.platform_data;
        host->clkrt = CLKRT_OFF;
 
@@ -702,12 +724,6 @@ static int pxamci_probe(struct platform_device *pdev)
                                     MMC_CAP_SD_HIGHSPEED;
        }
 
-       host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
-       if (!host->sg_cpu) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
        spin_lock_init(&host->lock);
        host->res = r;
        host->irq = irq;
@@ -728,32 +744,45 @@ static int pxamci_probe(struct platform_device *pdev)
        writel(64, host->base + MMC_RESTO);
        writel(host->imask, host->base + MMC_I_MASK);
 
-       host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
-                                   pxamci_dma_irq, host);
-       if (host->dma < 0) {
-               ret = -EBUSY;
-               goto out;
-       }
-
        ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
        if (ret)
                goto out;
 
        platform_set_drvdata(pdev, mmc);
 
-       dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmarx) {
-               ret = -ENXIO;
+       if (!pdev->dev.of_node) {
+               dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+               dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+               if (!dmarx || !dmatx) {
+                       ret = -ENXIO;
+                       goto out;
+               }
+               param_rx.prio = PXAD_PRIO_LOWEST;
+               param_rx.drcmr = dmarx->start;
+               param_tx.prio = PXAD_PRIO_LOWEST;
+               param_tx.drcmr = dmatx->start;
+       }
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       host->dma_chan_rx =
+               dma_request_slave_channel_compat(mask, pxad_filter_fn,
+                                                &param_rx, &pdev->dev, "rx");
+       if (host->dma_chan_rx == NULL) {
+               dev_err(&pdev->dev, "unable to request rx dma channel\n");
+               ret = -ENODEV;
                goto out;
        }
-       host->dma_drcmrrx = dmarx->start;
 
-       dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!dmatx) {
-               ret = -ENXIO;
+       host->dma_chan_tx =
+               dma_request_slave_channel_compat(mask, pxad_filter_fn,
+                                                &param_tx,  &pdev->dev, "tx");
+       if (host->dma_chan_tx == NULL) {
+               dev_err(&pdev->dev, "unable to request tx dma channel\n");
+               ret = -ENODEV;
                goto out;
        }
-       host->dma_drcmrtx = dmatx->start;
 
        if (host->pdata) {
                gpio_cd = host->pdata->gpio_card_detect;
@@ -814,12 +843,12 @@ err_gpio_ro:
        gpio_free(gpio_power);
  out:
        if (host) {
-               if (host->dma >= 0)
-                       pxa_free_dma(host->dma);
+               if (host->dma_chan_rx)
+                       dma_release_channel(host->dma_chan_rx);
+               if (host->dma_chan_tx)
+                       dma_release_channel(host->dma_chan_tx);
                if (host->base)
                        iounmap(host->base);
-               if (host->sg_cpu)
-                       dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
                if (host->clk)
                        clk_put(host->clk);
        }
@@ -863,13 +892,12 @@ static int pxamci_remove(struct platform_device *pdev)
                       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
                       host->base + MMC_I_MASK);
 
-               DRCMR(host->dma_drcmrrx) = 0;
-               DRCMR(host->dma_drcmrtx) = 0;
-
                free_irq(host->irq, host);
-               pxa_free_dma(host->dma);
+               dmaengine_terminate_all(host->dma_chan_rx);
+               dmaengine_terminate_all(host->dma_chan_tx);
+               dma_release_channel(host->dma_chan_rx);
+               dma_release_channel(host->dma_chan_tx);
                iounmap(host->base);
-               dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
                clk_put(host->clk);
 
index c6b9f6492e1a2529b7f683686bc4d939229dba63..886d230f41d07357f9fe624b9a94de428789e962 100644 (file)
@@ -32,6 +32,7 @@
 #include "sdhci-esdhc.h"
 
 #define        ESDHC_CTRL_D3CD                 0x08
+#define ESDHC_BURST_LEN_EN_INCR                (1 << 27)
 /* VENDOR SPEC register */
 #define ESDHC_VENDOR_SPEC              0xc0
 #define  ESDHC_VENDOR_SPEC_SDIO_QUIRK  (1 << 1)
@@ -44,6 +45,7 @@
 #define  ESDHC_MIX_CTRL_EXE_TUNE       (1 << 22)
 #define  ESDHC_MIX_CTRL_SMPCLK_SEL     (1 << 23)
 #define  ESDHC_MIX_CTRL_FBCLK_SEL      (1 << 25)
+#define  ESDHC_MIX_CTRL_HS400_EN       (1 << 26)
 /* Bits 3 and 6 are not SDHCI standard definitions */
 #define  ESDHC_MIX_CTRL_SDHCI_MASK     0xb7
 /* Tuning bits */
 #define  ESDHC_TUNE_CTRL_MIN           0
 #define  ESDHC_TUNE_CTRL_MAX           ((1 << 7) - 1)
 
+/* strobe dll register */
+#define ESDHC_STROBE_DLL_CTRL          0x70
+#define ESDHC_STROBE_DLL_CTRL_ENABLE   (1 << 0)
+#define ESDHC_STROBE_DLL_CTRL_RESET    (1 << 1)
+#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT     3
+
+#define ESDHC_STROBE_DLL_STATUS                0x74
+#define ESDHC_STROBE_DLL_STS_REF_LOCK  (1 << 1)
+#define ESDHC_STROBE_DLL_STS_SLV_LOCK  0x1
+
 #define ESDHC_TUNING_CTRL              0xcc
 #define ESDHC_STD_TUNING_EN            (1 << 24)
 /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
 #define ESDHC_TUNING_START_TAP         0x1
+#define ESDHC_TUNING_STEP_SHIFT                16
 
 /* pinctrl state */
 #define ESDHC_PINCTRL_STATE_100MHZ     "state_100mhz"
 #define ESDHC_FLAG_ERR004536           BIT(7)
 /* The IP supports HS200 mode */
 #define ESDHC_FLAG_HS200               BIT(8)
+/* The IP supports HS400 mode */
+#define ESDHC_FLAG_HS400               BIT(9)
+
+/* A higher clock ferquency than this rate requires strobell dll control */
+#define ESDHC_STROBE_DLL_CLK_FREQ      100000000
 
 struct esdhc_soc_data {
        u32 flags;
@@ -156,6 +174,12 @@ static struct esdhc_soc_data usdhc_imx6sx_data = {
                        | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
 };
 
+static struct esdhc_soc_data usdhc_imx7d_data = {
+       .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
+                       | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
+                       | ESDHC_FLAG_HS400,
+};
+
 struct pltfm_imx_data {
        u32 scratchpad;
        struct pinctrl *pinctrl;
@@ -199,6 +223,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
        { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, },
        { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, },
        { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, },
+       { .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
@@ -274,6 +299,9 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
                                val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
                                        | SDHCI_SUPPORT_SDR50
                                        | SDHCI_USE_SDR50_TUNING;
+
+                       if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
+                               val |= SDHCI_SUPPORT_HS400;
                }
        }
 
@@ -448,6 +476,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
                        u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
                        u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
+                       u32 tuning_ctrl;
                        if (val & SDHCI_CTRL_TUNED_CLK) {
                                v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
                        } else {
@@ -458,6 +487,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                        if (val & SDHCI_CTRL_EXEC_TUNING) {
                                v |= ESDHC_MIX_CTRL_EXE_TUNE;
                                m |= ESDHC_MIX_CTRL_FBCLK_SEL;
+                               tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
+                               tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP;
+                               if (imx_data->boarddata.tuning_step)
+                                       tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
+                                       writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL);
                        } else {
                                v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
                        }
@@ -774,6 +808,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
                break;
        case MMC_TIMING_UHS_SDR104:
        case MMC_TIMING_MMC_HS200:
+       case MMC_TIMING_MMC_HS400:
                pinctrl = imx_data->pins_200mhz;
                break;
        default:
@@ -784,24 +819,68 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
        return pinctrl_select_state(imx_data->pinctrl, pinctrl);
 }
 
+/*
+ * For HS400 eMMC, there is a data_strobe line, this signal is generated
+ * by the device and used for data output and CRC status response output
+ * in HS400 mode. The frequency of this signal follows the frequency of
+ * CLK generated by host. Host receive the data which is aligned to the
+ * edge of data_strobe line. Due to the time delay between CLK line and
+ * data_strobe line, if the delay time is larger than one clock cycle,
+ * then CLK and data_strobe line will misaligned, read error shows up.
+ * So when the CLK is higher than 100MHz, each clock cycle is short enough,
+ * host should config the delay target.
+ */
+static void esdhc_set_strobe_dll(struct sdhci_host *host)
+{
+       u32 v;
+
+       if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) {
+               /* force a reset on strobe dll */
+               writel(ESDHC_STROBE_DLL_CTRL_RESET,
+                       host->ioaddr + ESDHC_STROBE_DLL_CTRL);
+               /*
+                * enable strobe dll ctrl and adjust the delay target
+                * for the uSDHC loopback read clock
+                */
+               v = ESDHC_STROBE_DLL_CTRL_ENABLE |
+                       (7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
+               writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
+               /* wait 1us to make sure strobe dll status register stable */
+               udelay(1);
+               v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS);
+               if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK))
+                       dev_warn(mmc_dev(host->mmc),
+                               "warning! HS400 strobe DLL status REF not lock!\n");
+               if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK))
+                       dev_warn(mmc_dev(host->mmc),
+                               "warning! HS400 strobe DLL status SLV not lock!\n");
+       }
+}
+
 static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 {
+       u32 m;
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
        struct esdhc_platform_data *boarddata = &imx_data->boarddata;
 
+       /* disable ddr mode and disable HS400 mode */
+       m = readl(host->ioaddr + ESDHC_MIX_CTRL);
+       m &= ~(ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN);
+       imx_data->is_ddr = 0;
+
        switch (timing) {
        case MMC_TIMING_UHS_SDR12:
        case MMC_TIMING_UHS_SDR25:
        case MMC_TIMING_UHS_SDR50:
        case MMC_TIMING_UHS_SDR104:
        case MMC_TIMING_MMC_HS200:
+               writel(m, host->ioaddr + ESDHC_MIX_CTRL);
                break;
        case MMC_TIMING_UHS_DDR50:
        case MMC_TIMING_MMC_DDR52:
-               writel(readl(host->ioaddr + ESDHC_MIX_CTRL) |
-                               ESDHC_MIX_CTRL_DDREN,
-                               host->ioaddr + ESDHC_MIX_CTRL);
+               m |= ESDHC_MIX_CTRL_DDREN;
+               writel(m, host->ioaddr + ESDHC_MIX_CTRL);
                imx_data->is_ddr = 1;
                if (boarddata->delay_line) {
                        u32 v;
@@ -813,6 +892,12 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
                        writel(v, host->ioaddr + ESDHC_DLL_CTRL);
                }
                break;
+       case MMC_TIMING_MMC_HS400:
+               m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
+               writel(m, host->ioaddr + ESDHC_MIX_CTRL);
+               imx_data->is_ddr = 1;
+               esdhc_set_strobe_dll(host);
+               break;
        }
 
        esdhc_change_pinstate(host, timing);
@@ -886,6 +971,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
        if (gpio_is_valid(boarddata->wp_gpio))
                boarddata->wp_type = ESDHC_WP_GPIO;
 
+       of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
+
        if (of_find_property(np, "no-1-8-v", NULL))
                boarddata->support_vsel = false;
        else
@@ -1073,10 +1160,26 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
         * to something insane.  Change it back here.
         */
        if (esdhc_is_usdhc(imx_data)) {
-               writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
+               writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
+
                host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
                host->mmc->caps |= MMC_CAP_1_8V_DDR;
 
+               /*
+                * ROM code will change the bit burst_length_enable setting
+                * to zero if this usdhc is choosed to boot system. Change
+                * it back here, otherwise it will impact the performance a
+                * lot. This bit is used to enable/disable the burst length
+                * for the external AHB2AXI bridge, it's usefully especially
+                * for INCR transfer because without burst length indicator,
+                * the AHB2AXI bridge does not know the burst length in
+                * advance. And without burst length indicator, AHB INCR
+                * transfer can only be converted to singles on the AXI side.
+                */
+               writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
+                       | ESDHC_BURST_LEN_EN_INCR,
+                       host->ioaddr + SDHCI_HOST_CONTROL);
+
                if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200))
                        host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
 
@@ -1100,6 +1203,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
        if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
                host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
 
+       if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
+               host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400;
+
        if (of_id)
                err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
        else
index a870c42731d7a4eea86b39e9e965d94a0603631d..163ac9974d9101dcf28220263a88cef8f43b7750 100644 (file)
@@ -21,7 +21,8 @@
 #define ESDHC_DEFAULT_QUIRKS   (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
                                SDHCI_QUIRK_NO_BUSY_IRQ | \
                                SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
-                               SDHCI_QUIRK_PIO_NEEDS_DELAY)
+                               SDHCI_QUIRK_PIO_NEEDS_DELAY | \
+                               SDHCI_QUIRK_NO_HISPD_BIT)
 
 #define ESDHC_SYSTEM_CONTROL   0x2c
 #define ESDHC_CLOCK_MASK       0x0000fff0
index 4a09f7608c66affcede7565ea7c75c41bb10f6ba..4bcee033fedaf520d95433f03e652f0d7a786924 100644 (file)
@@ -489,6 +489,11 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                goto pclk_disable;
        }
 
+       /* Vote for maximum clock rate for maximum performance */
+       ret = clk_set_rate(msm_host->clk, INT_MAX);
+       if (ret)
+               dev_warn(&pdev->dev, "core clock boost failed\n");
+
        ret = clk_prepare_enable(msm_host->clk);
        if (ret)
                goto pclk_disable;
index 21c0c08dfe54cf997e7d7031b9db5bac9ff77e64..75379cb0fb354e7aa7749852ced8fca5973d435e 100644 (file)
@@ -63,6 +63,9 @@ static struct sdhci_ops sdhci_arasan_ops = {
 
 static struct sdhci_pltfm_data sdhci_arasan_pdata = {
        .ops = &sdhci_arasan_ops,
+       .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+                       SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
 };
 
 #ifdef CONFIG_PM_SLEEP
@@ -214,6 +217,7 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
 
 static const struct of_device_id sdhci_arasan_of_match[] = {
        { .compatible = "arasan,sdhci-8.9a" },
+       { .compatible = "arasan,sdhci-5.1" },
        { .compatible = "arasan,sdhci-4.9a" },
        { }
 };
diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
new file mode 100644 (file)
index 0000000..d155664
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Atmel SDMMC controller driver.
+ *
+ * Copyright (C) 2015 Atmel,
+ *              2015 Ludovic Desroches <ludovic.desroches@atmel.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include "sdhci-pltfm.h"
+
+#define SDMMC_CACR     0x230
+#define                SDMMC_CACR_CAPWREN      BIT(0)
+#define                SDMMC_CACR_KEY          (0x46 << 8)
+
+struct sdhci_at91_priv {
+       struct clk *hclock;
+       struct clk *gck;
+       struct clk *mainck;
+};
+
+static const struct sdhci_ops sdhci_at91_sama5d2_ops = {
+       .set_clock              = sdhci_set_clock,
+       .set_bus_width          = sdhci_set_bus_width,
+       .reset                  = sdhci_reset,
+       .set_uhs_signaling      = sdhci_set_uhs_signaling,
+};
+
+static const struct sdhci_pltfm_data soc_data_sama5d2 = {
+       .ops = &sdhci_at91_sama5d2_ops,
+};
+
+static const struct of_device_id sdhci_at91_dt_match[] = {
+       { .compatible = "atmel,sama5d2-sdhci", .data = &soc_data_sama5d2 },
+       {}
+};
+
+static int sdhci_at91_probe(struct platform_device *pdev)
+{
+       const struct of_device_id       *match;
+       const struct sdhci_pltfm_data   *soc_data;
+       struct sdhci_host               *host;
+       struct sdhci_pltfm_host         *pltfm_host;
+       struct sdhci_at91_priv          *priv;
+       unsigned int                    caps0, caps1;
+       unsigned int                    clk_base, clk_mul;
+       unsigned int                    gck_rate, real_gck_rate;
+       int                             ret;
+
+       match = of_match_device(sdhci_at91_dt_match, &pdev->dev);
+       if (!match)
+               return -EINVAL;
+       soc_data = match->data;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "unable to allocate private data\n");
+               return -ENOMEM;
+       }
+
+       priv->mainck = devm_clk_get(&pdev->dev, "baseclk");
+       if (IS_ERR(priv->mainck)) {
+               dev_err(&pdev->dev, "failed to get baseclk\n");
+               return PTR_ERR(priv->mainck);
+       }
+
+       priv->hclock = devm_clk_get(&pdev->dev, "hclock");
+       if (IS_ERR(priv->hclock)) {
+               dev_err(&pdev->dev, "failed to get hclock\n");
+               return PTR_ERR(priv->hclock);
+       }
+
+       priv->gck = devm_clk_get(&pdev->dev, "multclk");
+       if (IS_ERR(priv->gck)) {
+               dev_err(&pdev->dev, "failed to get multclk\n");
+               return PTR_ERR(priv->gck);
+       }
+
+       host = sdhci_pltfm_init(pdev, soc_data, 0);
+       if (IS_ERR(host))
+               return PTR_ERR(host);
+
+       /*
+        * The mult clock is provided by as a generated clock by the PMC
+        * controller. In order to set the rate of gck, we have to get the
+        * base clock rate and the clock mult from capabilities.
+        */
+       clk_prepare_enable(priv->hclock);
+       caps0 = readl(host->ioaddr + SDHCI_CAPABILITIES);
+       caps1 = readl(host->ioaddr + SDHCI_CAPABILITIES_1);
+       clk_base = (caps0 & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+       clk_mul = (caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT;
+       gck_rate = clk_base * 1000000 * (clk_mul + 1);
+       ret = clk_set_rate(priv->gck, gck_rate);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to set gck");
+               goto hclock_disable_unprepare;
+               return -EINVAL;
+       }
+       /*
+        * We need to check if we have the requested rate for gck because in
+        * some cases this rate could be not supported. If it happens, the rate
+        * is the closest one gck can provide. We have to update the value
+        * of clk mul.
+        */
+       real_gck_rate = clk_get_rate(priv->gck);
+       if (real_gck_rate != gck_rate) {
+               clk_mul = real_gck_rate / (clk_base * 1000000) - 1;
+               caps1 &= (~SDHCI_CLOCK_MUL_MASK);
+               caps1 |= ((clk_mul << SDHCI_CLOCK_MUL_SHIFT) & SDHCI_CLOCK_MUL_MASK);
+               /* Set capabilities in r/w mode. */
+               writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN, host->ioaddr + SDMMC_CACR);
+               writel(caps1, host->ioaddr + SDHCI_CAPABILITIES_1);
+               /* Set capabilities in ro mode. */
+               writel(0, host->ioaddr + SDMMC_CACR);
+               dev_info(&pdev->dev, "update clk mul to %u as gck rate is %u Hz\n",
+                        clk_mul, real_gck_rate);
+       }
+
+       clk_prepare_enable(priv->mainck);
+       clk_prepare_enable(priv->gck);
+
+       pltfm_host = sdhci_priv(host);
+       pltfm_host->priv = priv;
+
+       ret = mmc_of_parse(host->mmc);
+       if (ret)
+               goto clocks_disable_unprepare;
+
+       sdhci_get_of_property(pdev);
+
+       ret = sdhci_add_host(host);
+       if (ret)
+               goto clocks_disable_unprepare;
+
+       return 0;
+
+clocks_disable_unprepare:
+       clk_disable_unprepare(priv->gck);
+       clk_disable_unprepare(priv->mainck);
+hclock_disable_unprepare:
+       clk_disable_unprepare(priv->hclock);
+       sdhci_pltfm_free(pdev);
+       return ret;
+}
+
+static int sdhci_at91_remove(struct platform_device *pdev)
+{
+       struct sdhci_host       *host = platform_get_drvdata(pdev);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_at91_priv  *priv = pltfm_host->priv;
+
+       sdhci_pltfm_unregister(pdev);
+
+       clk_disable_unprepare(priv->gck);
+       clk_disable_unprepare(priv->hclock);
+       clk_disable_unprepare(priv->mainck);
+
+       return 0;
+}
+
+static struct platform_driver sdhci_at91_driver = {
+       .driver         = {
+               .name   = "sdhci-at91",
+               .of_match_table = sdhci_at91_dt_match,
+               .pm     = SDHCI_PLTFM_PMOPS,
+       },
+       .probe          = sdhci_at91_probe,
+       .remove         = sdhci_at91_remove,
+};
+
+module_platform_driver(sdhci_at91_driver);
+
+MODULE_DESCRIPTION("SDHCI driver for at91");
+MODULE_AUTHOR("Ludovic Desroches <ludovic.desroches@atmel.com>");
+MODULE_LICENSE("GPL v2");
index 797be7549a15c01a0e9acda2b0adaccb0a6c9416..653f335bef1516ca9aba102e1f3ab21d99a754ce 100644 (file)
@@ -208,6 +208,12 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
        if (clock == 0)
                return;
 
+       /* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
+       temp = esdhc_readw(host, SDHCI_HOST_VERSION);
+       temp = (temp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
+       if (temp < VENDOR_V_23)
+               pre_div = 2;
+
        /* Workaround to reduce the clock frequency for p1010 esdhc */
        if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
                if (clock > 20000000)
index 94f54d2772e885b891024db94bb152890468f548..b3b0a3e4fca1652e3ceb1759c0bcbd13bcc1d22e 100644 (file)
@@ -618,6 +618,7 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
 static const struct sdhci_pci_fixes sdhci_o2 = {
        .probe = sdhci_pci_o2_probe,
        .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+       .quirks2 = SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD,
        .probe_slot = sdhci_pci_o2_probe_slot,
        .resume = sdhci_pci_o2_resume,
 };
index 0110bae25b7e8e1d6dcfb54a6a8a518c2763f122..884294576356d4c87e3869162186aadbc24b4f6a 100644 (file)
@@ -161,8 +161,8 @@ static struct sdhci_pltfm_data sdhci_sirf_pdata = {
        .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
                SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
                SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
-               SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
-               SDHCI_QUIRK_DELAY_AFTER_POWER,
+               SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 };
 
 static int sdhci_sirf_probe(struct platform_device *pdev)
index 1dbe932320309fc87f75a40cc2552ba5a784d5bd..64b7fdbd1a9ccab80034e8a38660ef944daf8bae 100644 (file)
@@ -54,8 +54,7 @@ static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
 static int sdhci_pre_dma_transfer(struct sdhci_host *host,
-                                       struct mmc_data *data,
-                                       struct sdhci_host_next *next);
+                                       struct mmc_data *data);
 static int sdhci_do_get_cd(struct sdhci_host *host);
 
 #ifdef CONFIG_PM
@@ -207,8 +206,7 @@ EXPORT_SYMBOL_GPL(sdhci_reset);
 static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
 {
        if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
-               if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
-                       SDHCI_CARD_PRESENT))
+               if (!sdhci_do_get_cd(host))
                        return;
        }
 
@@ -496,7 +494,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                goto fail;
        BUG_ON(host->align_addr & host->align_mask);
 
-       host->sg_count = sdhci_pre_dma_transfer(host, data, NULL);
+       host->sg_count = sdhci_pre_dma_transfer(host, data);
        if (host->sg_count < 0)
                goto unmap_align;
 
@@ -635,9 +633,11 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
                }
        }
 
-       if (!data->host_cookie)
+       if (data->host_cookie == COOKIE_MAPPED) {
                dma_unmap_sg(mmc_dev(host->mmc), data->sg,
                        data->sg_len, direction);
+               data->host_cookie = COOKIE_UNMAPPED;
+       }
 }
 
 static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
@@ -833,7 +833,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
                } else {
                        int sg_cnt;
 
-                       sg_cnt = sdhci_pre_dma_transfer(host, data, NULL);
+                       sg_cnt = sdhci_pre_dma_transfer(host, data);
                        if (sg_cnt <= 0) {
                                /*
                                 * This only happens when someone fed
@@ -949,11 +949,13 @@ static void sdhci_finish_data(struct sdhci_host *host)
                if (host->flags & SDHCI_USE_ADMA)
                        sdhci_adma_table_post(host, data);
                else {
-                       if (!data->host_cookie)
+                       if (data->host_cookie == COOKIE_MAPPED) {
                                dma_unmap_sg(mmc_dev(host->mmc),
                                        data->sg, data->sg_len,
                                        (data->flags & MMC_DATA_READ) ?
                                        DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                               data->host_cookie = COOKIE_UNMAPPED;
+                       }
                }
        }
 
@@ -1132,6 +1134,7 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
                break;
        case MMC_TIMING_UHS_DDR50:
+       case MMC_TIMING_MMC_DDR52:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
                break;
        case MMC_TIMING_MMC_HS400:
@@ -1152,6 +1155,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
        int real_div = div, clk_mul = 1;
        u16 clk = 0;
        unsigned long timeout;
+       bool switch_base_clk = false;
 
        host->mmc->actual_clock = 0;
 
@@ -1189,15 +1193,25 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                                        <= clock)
                                        break;
                        }
-                       /*
-                        * Set Programmable Clock Mode in the Clock
-                        * Control register.
-                        */
-                       clk = SDHCI_PROG_CLOCK_MODE;
-                       real_div = div;
-                       clk_mul = host->clk_mul;
-                       div--;
-               } else {
+                       if ((host->max_clk * host->clk_mul / div) <= clock) {
+                               /*
+                                * Set Programmable Clock Mode in the Clock
+                                * Control register.
+                                */
+                               clk = SDHCI_PROG_CLOCK_MODE;
+                               real_div = div;
+                               clk_mul = host->clk_mul;
+                               div--;
+                       } else {
+                               /*
+                                * Divisor can be too small to reach clock
+                                * speed requirement. Then use the base clock.
+                                */
+                               switch_base_clk = true;
+                       }
+               }
+
+               if (!host->clk_mul || switch_base_clk) {
                        /* Version 3.00 divisors must be a multiple of 2. */
                        if (host->max_clk <= clock)
                                div = 1;
@@ -1210,6 +1224,9 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                        }
                        real_div = div;
                        div >>= 1;
+                       if ((host->quirks2 & SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN)
+                               && !div && host->max_clk <= 25000000)
+                               div = 1;
                }
        } else {
                /* Version 2.00 divisors must be a power of 2. */
@@ -1559,7 +1576,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                                 (ios->timing == MMC_TIMING_UHS_SDR25) ||
                                 (ios->timing == MMC_TIMING_UHS_SDR50) ||
                                 (ios->timing == MMC_TIMING_UHS_SDR104) ||
-                                (ios->timing == MMC_TIMING_UHS_DDR50))) {
+                                (ios->timing == MMC_TIMING_UHS_DDR50) ||
+                                (ios->timing == MMC_TIMING_MMC_DDR52))) {
                        u16 preset;
 
                        sdhci_enable_preset_value(host, true);
@@ -1601,15 +1619,21 @@ static int sdhci_do_get_cd(struct sdhci_host *host)
        if (host->flags & SDHCI_DEVICE_DEAD)
                return 0;
 
-       /* If polling/nonremovable, assume that the card is always present. */
-       if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
-           (host->mmc->caps & MMC_CAP_NONREMOVABLE))
+       /* If nonremovable, assume that the card is always present. */
+       if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
                return 1;
 
-       /* Try slot gpio detect */
+       /*
+        * Try slot gpio detect, if defined it take precedence
+        * over build in controller functionality
+        */
        if (!IS_ERR_VALUE(gpio_cd))
                return !!gpio_cd;
 
+       /* If polling, assume that the card is always present. */
+       if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+               return 1;
+
        /* Host native card detect */
        return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
 }
@@ -2097,49 +2121,36 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
        struct mmc_data *data = mrq->data;
 
        if (host->flags & SDHCI_REQ_USE_DMA) {
-               if (data->host_cookie)
+               if (data->host_cookie == COOKIE_GIVEN ||
+                               data->host_cookie == COOKIE_MAPPED)
                        dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
                                         data->flags & MMC_DATA_WRITE ?
                                         DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               mrq->data->host_cookie = 0;
+               data->host_cookie = COOKIE_UNMAPPED;
        }
 }
 
 static int sdhci_pre_dma_transfer(struct sdhci_host *host,
-                                      struct mmc_data *data,
-                                      struct sdhci_host_next *next)
+                                      struct mmc_data *data)
 {
        int sg_count;
 
-       if (!next && data->host_cookie &&
-           data->host_cookie != host->next_data.cookie) {
-               pr_debug(DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n",
-                       __func__, data->host_cookie, host->next_data.cookie);
-               data->host_cookie = 0;
+       if (data->host_cookie == COOKIE_MAPPED) {
+               data->host_cookie = COOKIE_GIVEN;
+               return data->sg_count;
        }
 
-       /* Check if next job is already prepared */
-       if (next ||
-           (!next && data->host_cookie != host->next_data.cookie)) {
-               sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg,
-                                    data->sg_len,
-                                    data->flags & MMC_DATA_WRITE ?
-                                    DMA_TO_DEVICE : DMA_FROM_DEVICE);
-
-       } else {
-               sg_count = host->next_data.sg_count;
-               host->next_data.sg_count = 0;
-       }
+       WARN_ON(data->host_cookie == COOKIE_GIVEN);
 
+       sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+                               data->flags & MMC_DATA_WRITE ?
+                               DMA_TO_DEVICE : DMA_FROM_DEVICE);
 
        if (sg_count == 0)
-               return -EINVAL;
+               return -ENOSPC;
 
-       if (next) {
-               next->sg_count = sg_count;
-               data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
-       } else
-               host->sg_count = sg_count;
+       data->sg_count = sg_count;
+       data->host_cookie = COOKIE_MAPPED;
 
        return sg_count;
 }
@@ -2149,16 +2160,10 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
 {
        struct sdhci_host *host = mmc_priv(mmc);
 
-       if (mrq->data->host_cookie) {
-               mrq->data->host_cookie = 0;
-               return;
-       }
+       mrq->data->host_cookie = COOKIE_UNMAPPED;
 
        if (host->flags & SDHCI_REQ_USE_DMA)
-               if (sdhci_pre_dma_transfer(host,
-                                       mrq->data,
-                                       &host->next_data) < 0)
-                       mrq->data->host_cookie = 0;
+               sdhci_pre_dma_transfer(host, mrq->data);
 }
 
 static void sdhci_card_event(struct mmc_host *mmc)
@@ -3030,7 +3035,6 @@ int sdhci_add_host(struct sdhci_host *host)
                host->max_clk = host->ops->get_max_clock(host);
        }
 
-       host->next_data.cookie = 1;
        /*
         * In case of Host Controller v3.00, find out whether clock
         * multiplier is supported.
@@ -3126,7 +3130,8 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
-           !(mmc->caps & MMC_CAP_NONREMOVABLE))
+           !(mmc->caps & MMC_CAP_NONREMOVABLE) &&
+           IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc)))
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        /* If there are external regulators, get them */
index 5521d29368e466d0d752839e34210a452823d62f..7c02ff46c8ac3ecdaf37e792fd6bcb43c9bd029e 100644 (file)
@@ -309,9 +309,10 @@ struct sdhci_adma2_64_desc {
  */
 #define SDHCI_MAX_SEGS         128
 
-struct sdhci_host_next {
-       unsigned int    sg_count;
-       s32             cookie;
+enum sdhci_cookie {
+       COOKIE_UNMAPPED,
+       COOKIE_MAPPED,
+       COOKIE_GIVEN,
 };
 
 struct sdhci_host {
@@ -409,6 +410,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_SUPPORT_SINGLE                    (1<<13)
 /* Controller broken with using ACMD23 */
 #define SDHCI_QUIRK2_ACMD23_BROKEN                     (1<<14)
+/* Broken Clock divider zero in controller */
+#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN             (1<<15)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
@@ -503,7 +506,6 @@ struct sdhci_host {
        unsigned int            tuning_mode;    /* Re-tuning mode supported by host */
 #define SDHCI_TUNING_MODE_1    0
 
-       struct sdhci_host_next  next_data;
        unsigned long private[0] ____cacheline_aligned;
 };
 
index 5a1fdd405b1af14ff1725a8b9d9a3ab83e84b15a..ad9ffea7d659d28e057f13c1b7912ca7243743ac 100644 (file)
@@ -1632,7 +1632,9 @@ static int sh_mmcif_suspend(struct device *dev)
 {
        struct sh_mmcif_host *host = dev_get_drvdata(dev);
 
+       pm_runtime_get_sync(dev);
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+       pm_runtime_put(dev);
 
        return 0;
 }
index 4d3e1ffe5508273fc1f9f91b7b5c3218bed1ea07..a7b7a67715986d748d9f880088cc2ae069bd2283 100644 (file)
@@ -595,7 +595,7 @@ static irqreturn_t sunxi_mmc_handle_manual_stop(int irq, void *dev_id)
 
 static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
 {
-       unsigned long expire = jiffies + msecs_to_jiffies(250);
+       unsigned long expire = jiffies + msecs_to_jiffies(750);
        u32 rval;
 
        rval = mmc_readl(host, REG_CLKCR);
index e3dcf31a8bd6a04e8abd174c964313db584fe1a1..a10fde40b6c3ddbed98e05a693336ea6b1bb1c65 100644 (file)
@@ -83,6 +83,8 @@ static int tmio_mmc_next_sg(struct tmio_mmc_host *host)
        return --host->sg_len;
 }
 
+#define CMDREQ_TIMEOUT 5000
+
 #ifdef CONFIG_MMC_DEBUG
 
 #define STATUS_TO_TEXT(a, status, i) \
@@ -230,7 +232,7 @@ static void tmio_mmc_reset_work(struct work_struct *work)
         */
        if (IS_ERR_OR_NULL(mrq)
            || time_is_after_jiffies(host->last_req_ts +
-               msecs_to_jiffies(2000))) {
+               msecs_to_jiffies(CMDREQ_TIMEOUT))) {
                spin_unlock_irqrestore(&host->lock, flags);
                return;
        }
@@ -818,7 +820,7 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        ret = tmio_mmc_start_command(host, mrq->cmd);
        if (!ret) {
                schedule_delayed_work(&host->delayed_reset_work,
-                                     msecs_to_jiffies(2000));
+                                     msecs_to_jiffies(CMDREQ_TIMEOUT));
                return;
        }
 
index 54b082b1804a5c05973a16e196d3dbd40f1c1779..4498e92116b808d2a62f6e146f33f3b41838ee33 100644 (file)
@@ -1611,7 +1611,7 @@ static irqreturn_t usdhi6_cd(int irq, void *dev_id)
                return IRQ_NONE;
 
        /* Ack */
-       usdhi6_write(host, USDHI6_SD_INFO1, !status);
+       usdhi6_write(host, USDHI6_SD_INFO1, ~status);
 
        if (!work_pending(&mmc->detect.work) &&
            (((status & USDHI6_SD_INFO1_CARD_INSERT) &&
@@ -1634,6 +1634,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
        struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work);
        struct mmc_request *mrq = host->mrq;
        struct mmc_data *data = mrq ? mrq->data : NULL;
+       struct scatterlist *sg = host->sg ?: data->sg;
 
        dev_warn(mmc_dev(host->mmc),
                 "%s timeout wait %u CMD%d: IRQ 0x%08x:0x%08x, last IRQ 0x%08x\n",
@@ -1669,7 +1670,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
                        "%c: page #%u @ +0x%zx %ux%u in SG%u. Current SG %u bytes @ %u\n",
                        data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx,
                        host->offset, data->blocks, data->blksz, data->sg_len,
-                       sg_dma_len(host->sg), host->sg->offset);
+                       sg_dma_len(sg), sg->offset);
                usdhi6_sg_unmap(host, true);
                /*
                 * If USDHI6_WAIT_FOR_DATA_END times out, we have already unmapped
@@ -1715,12 +1716,14 @@ static int usdhi6_probe(struct platform_device *pdev)
        if (!mmc)
                return -ENOMEM;
 
+       ret = mmc_regulator_get_supply(mmc);
+       if (ret == -EPROBE_DEFER)
+               goto e_free_mmc;
+
        ret = mmc_of_parse(mmc);
        if (ret < 0)
                goto e_free_mmc;
 
-       mmc_regulator_get_supply(mmc);
-
        host            = mmc_priv(mmc);
        host->mmc       = mmc;
        host->wait      = USDHI6_WAIT_FOR_REQUEST;
@@ -1734,8 +1737,10 @@ static int usdhi6_probe(struct platform_device *pdev)
        }
 
        host->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(host->clk))
+       if (IS_ERR(host->clk)) {
+               ret = PTR_ERR(host->clk);
                goto e_free_mmc;
+       }
 
        host->imclk = clk_get_rate(host->clk);
 
index 4d3776d25925a14d6140ce681911dd5c1a5bc133..fdd0779ccdfa52309f5e99aeeadd84b356c1a472 100644 (file)
@@ -279,10 +279,13 @@ struct mmc_card {
 #define MMC_QUIRK_LONG_READ_TIME (1<<9)                /* Data read time > CSD says */
 #define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10)        /* Skip secure for erase/trim */
 #define MMC_QUIRK_BROKEN_IRQ_POLLING   (1<<11) /* Polling SDIO_CCCR_INTx could create a fake interrupt */
+#define MMC_QUIRK_TRIM_BROKEN  (1<<12)         /* Skip trim */
+
 
        unsigned int            erase_size;     /* erase size in sectors */
        unsigned int            erase_shift;    /* if erase unit is power 2 */
        unsigned int            pref_erase;     /* in sectors */
+       unsigned int            eg_boundary;    /* don't cross erase-group boundaries */
        u8                      erased_byte;    /* value of erased bytes */
 
        u32                     raw_cid[4];     /* raw card CID */
index 5be97676f1fa029a9e0b40418bc1c37b83105d44..134c57422740944fb8d1d004c2f8126b2bdeb604 100644 (file)
@@ -98,6 +98,7 @@ struct mmc_data;
  * @irq_flags: The flags to be passed to request_irq.
  * @irq: The irq value to be passed to request_irq.
  * @sdio_id0: Number of slot0 in the SDIO interrupt registers.
+ * @dto_timer: Timer for broken data transfer over scheme.
  *
  * Locking
  * =======
@@ -153,11 +154,7 @@ struct dw_mci {
        dma_addr_t              sg_dma;
        void                    *sg_cpu;
        const struct dw_mci_dma_ops     *dma_ops;
-#ifdef CONFIG_MMC_DW_IDMAC
        unsigned int            ring_size;
-#else
-       struct dw_mci_dma_data  *dma_data;
-#endif
        u32                     cmd_status;
        u32                     data_status;
        u32                     stop_cmdr;
@@ -204,6 +201,7 @@ struct dw_mci {
        int                     sdio_id0;
 
        struct timer_list       cmd11_timer;
+       struct timer_list       dto_timer;
 };
 
 /* DMA ops for Internal/External DMAC interface */
@@ -226,6 +224,8 @@ struct dw_mci_dma_ops {
 #define DW_MCI_QUIRK_HIGHSPEED                 BIT(2)
 /* Unreliable card detection */
 #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION     BIT(3)
+/* Timer for broken data transfer over scheme */
+#define DW_MCI_QUIRK_BROKEN_DTO                        BIT(4)
 
 struct dma_pdata;
 
@@ -259,7 +259,6 @@ struct dw_mci_board {
 
        struct dw_mci_dma_ops *dma_ops;
        struct dma_pdata *data;
-       struct block_settings *blk_settings;
 };
 
 #endif /* LINUX_MMC_DW_MMC_H */
index 1369e54faeb7e2ee8ef3d49481751249c70bbcbd..83b81fd865f3bba12e7bc7d4c0ac8091ca067c09 100644 (file)
@@ -412,7 +412,8 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
        host->ops->enable_sdio_irq(host, 0);
        host->sdio_irq_pending = true;
-       wake_up_process(host->sdio_irq_thread);
+       if (host->sdio_irq_thread)
+               wake_up_process(host->sdio_irq_thread);
 }
 
 void sdio_run_irqs(struct mmc_host *host);
index e1571efa3f2b28e01642e08f6709d7c7c8dc141a..95ccab3f454a9511a27acc7cf351eac52a5dbdb5 100644 (file)
@@ -45,5 +45,6 @@ struct esdhc_platform_data {
        int max_bus_width;
        bool support_vsel;
        unsigned int delay_line;
+       unsigned int tuning_step;       /* The delay cell steps in tuning procedure */
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */