]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'mmc-v4.8' of git://git.linaro.org/people/ulf.hansson/mmc
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 1 Aug 2016 01:36:58 +0000 (21:36 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 1 Aug 2016 01:36:58 +0000 (21:36 -0400)
Pull MMC updates from Ulf Hansson:
 "MMC core:
   - A couple of changes to improve the support for erase/discard/trim cmds
   - Add eMMC HS400 enhanced strobe support
   - Show OCR and DSR registers in SYSFS for MMC/SD cards
   - Correct and improve busy detection logic for MMC switch (CMD6) cmds
   - Disable HPI cmds for certain broken Hynix eMMC cards
   - Allow MMC hosts to specify non-support for SD and MMC cmds
   - Some minor additional fixes

  MMC host:
   - sdhci: Re-works, fixes and clean-ups
   - sdhci: Add HW auto re-tuning support
   - sdhci: Re-factor code to prepare for adding support for eMMC CMDQ
   - sdhci-esdhc-imx: Fixes and clean-ups
   - sdhci-esdhc-imx: Update system PM support
   - sdhci-esdhc-imx: Enable HW auto re-tuning
   - sdhci-bcm2835: Remove driver as sdhci-iproc is used instead
   - sdhci-brcmstb: Add new driver for Broadcom BRCMSTB SoCs
   - sdhci-msm: Add support for UHS cards
   - sdhci-tegra: Improve support for UHS cards
   - sdhci-of-arasan: Update phy support for Rockchip SoCs
   - sdhci-of-arasan: Deploy enhanced strobe support
   - dw_mmc: Some fixes and clean-ups
   - dw_mmc: Enable support for erase/discard/trim cmds
   - dw_mmc: Enable CMD23 support
   - mediatek: Some fixes related to the eMMC HS400 support
   - sh_mmcif: Improve support for HW busy detection
   - rtsx_pci: Enable support for erase/discard/trim cmds"

* tag 'mmc-v4.8' of git://git.linaro.org/people/ulf.hansson/mmc: (135 commits)
  mmc: rtsx_pci: Remove deprecated create_singlethread_workqueue
  mmc: rtsx_pci: Enable MMC_CAP_ERASE to allow erase/discard/trim requests
  mmc: rtsx_pci: Use the provided busy timeout from the mmc core
  mmc: sdhci-pltfm: Drop define for SDHCI_PLTFM_PMOPS
  mmc: sdhci-pltfm: Convert to use the SET_SYSTEM_SLEEP_PM_OPS
  mmc: sdhci-pltfm: Make sdhci_pltfm_suspend|resume() static
  mmc: sdhci-esdhc-imx: Use common sdhci_suspend|resume_host()
  mmc: sdhci-esdhc-imx: Assign system PM ops within #ifdef CONFIG_PM_SLEEP
  mmc: sdhci-sirf: Remove non needed #ifdef CONFIG_PM* for dev_pm_ops
  mmc: sdhci-s3c: Remove non needed #ifdef CONFIG_PM for dev_pm_ops
  mmc: sdhci-pxav3: Remove non needed #ifdef CONFIG_PM for dev_pm_ops
  mmc: sdhci-of-esdhc: Simplify code by using SIMPLE_DEV_PM_OPS
  mmc: sdhci-acpi: Simplify code by using SET_SYSTEM_SLEEP_PM_OPS
  mmc: sdhci-pci-core: Simplify code by using SET_SYSTEM_SLEEP_PM_OPS
  mmc: Change the max discard sectors and erase response when HW busy detect
  phy: rockchip-emmc: Wait even longer for the DLL to lock
  phy: rockchip-emmc: Be tolerant to card clock of 0 in power on
  mmc: sdhci-of-arasan: Revert: Always power the PHY off/on when clock changes
  mmc: sdhci-msm: Add support for UHS cards
  mmc: sdhci-msm: Add set_uhs_signaling() implementation
  ...

65 files changed:
Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
Documentation/devicetree/bindings/mmc/brcm,bcm2835-sdhci.txt [deleted file]
Documentation/devicetree/bindings/mmc/brcm,bcm7425-sdhci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/phy/rockchip-emmc-phy.txt
Documentation/mmc/mmc-dev-attrs.txt
MAINTAINERS
drivers/mmc/card/block.c
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/debugfs.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/quirks.c
drivers/mmc/core/sd.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc-k3.c
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/s3cmci.h
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-bcm-kona.c
drivers/mmc/host/sdhci-bcm2835.c [deleted file]
drivers/mmc/host/sdhci-brcmstb.c [new file with mode: 0644]
drivers/mmc/host/sdhci-cns3xxx.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-iproc.c
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-arasan.c
drivers/mmc/host/sdhci-of-at91.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-of-hlwd.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci-pci.h
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-pltfm.h
drivers/mmc/host/sdhci-pxav2.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-sirf.c
drivers/mmc/host/sdhci-st.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sdhci_f_sdh30.c
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_pio.c
drivers/phy/phy-rockchip-emmc.c
include/linux/mmc/card.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/platform_data/mmc-esdhc-imx.h

index 31b35c3a5e478191cb5faa427b5aaec57ec87fff..3404afa9b9384b278d4596acbd3eff126ba0fa25 100644 (file)
@@ -9,8 +9,12 @@ Device Tree Bindings for the Arasan SDHCI Controller
   [4] Documentation/devicetree/bindings/phy/phy-bindings.txt
 
 Required Properties:
-  - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' or
-                'arasan,sdhci-4.9a' or 'arasan,sdhci-5.1'
+  - compatible: Compatibility string.  One of:
+    - "arasan,sdhci-8.9a": generic Arasan SDHCI 8.9a PHY
+    - "arasan,sdhci-4.9a": generic Arasan SDHCI 4.9a PHY
+    - "arasan,sdhci-5.1": generic Arasan SDHCI 5.1 PHY
+    - "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY
+      For this device it is strongly suggested to include arasan,soc-ctl-syscon.
   - 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"
@@ -22,6 +26,17 @@ Required Properties for "arasan,sdhci-5.1":
   - phys: From PHY bindings: Phandle for the Generic PHY for arasan.
   - phy-names:  MUST be "phy_arasan".
 
+Optional Properties:
+  - arasan,soc-ctl-syscon: A phandle to a syscon device (see ../mfd/syscon.txt)
+    used to access core corecfg registers.  Offsets of registers in this
+    syscon are determined based on the main compatible string for the device.
+  - clock-output-names: If specified, this will be the name of the card clock
+    which will be exposed by this device.  Required if #clock-cells is
+    specified.
+  - #clock-cells: If specified this should be the value <0>.  With this property
+    in place we will export a clock representing the Card Clock.  This clock
+    is expected to be consumed by our PHY.  You must also specify
+
 Example:
        sdhci@e0100000 {
                compatible = "arasan,sdhci-8.9a";
@@ -42,3 +57,19 @@ Example:
                phys = <&emmc_phy>;
                phy-names = "phy_arasan";
        } ;
+
+       sdhci: sdhci@fe330000 {
+               compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
+               reg = <0x0 0xfe330000 0x0 0x10000>;
+               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
+               clock-names = "clk_xin", "clk_ahb";
+               arasan,soc-ctl-syscon = <&grf>;
+               assigned-clocks = <&cru SCLK_EMMC>;
+               assigned-clock-rates = <200000000>;
+               clock-output-names = "emmc_cardclock";
+               phys = <&emmc_phy>;
+               phy-names = "phy_arasan";
+               #clock-cells = <0>;
+               status = "disabled";
+       };
diff --git a/Documentation/devicetree/bindings/mmc/brcm,bcm2835-sdhci.txt b/Documentation/devicetree/bindings/mmc/brcm,bcm2835-sdhci.txt
deleted file mode 100644 (file)
index 59476fb..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-Broadcom BCM2835 SDHCI controller
-
-This file documents differences between the core properties described
-by mmc.txt and the properties that represent the BCM2835 controller.
-
-Required properties:
-- compatible : Should be "brcm,bcm2835-sdhci".
-- clocks : The clock feeding the SDHCI controller.
-
-Example:
-
-sdhci: sdhci {
-       compatible = "brcm,bcm2835-sdhci";
-       reg = <0x7e300000 0x100>;
-       interrupts = <2 30>;
-       clocks = <&clk_mmc>;
-       bus-width = <4>;
-};
diff --git a/Documentation/devicetree/bindings/mmc/brcm,bcm7425-sdhci.txt b/Documentation/devicetree/bindings/mmc/brcm,bcm7425-sdhci.txt
new file mode 100644 (file)
index 0000000..8284717
--- /dev/null
@@ -0,0 +1,36 @@
+* BROADCOM BRCMSTB/BMIPS SDHCI Controller
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the sdhci-brcmstb driver.
+
+NOTE: The driver disables all UHS speed modes by default and depends
+on Device Tree properties to enable them for SoC/Board combinations
+that support them.
+
+Required properties:
+- compatible: "brcm,bcm7425-sdhci"
+
+Refer to clocks/clock-bindings.txt for generic clock consumer properties.
+
+Example:
+
+       sdhci@f03e0100 {
+               compatible = "brcm,bcm7425-sdhci";
+               reg = <0xf03e0000 0x100>;
+               interrupts = <0x0 0x26 0x0>;
+               sdhci,auto-cmd12;
+               clocks = <&sw_sdio>;
+               sd-uhs-sdr50;
+               sd-uhs-ddr50;
+       };
+
+       sdhci@f03e0300 {
+               non-removable;
+               bus-width = <0x8>;
+               compatible = "brcm,bcm7425-sdhci";
+               reg = <0xf03e0200 0x100>;
+               interrupts = <0x0 0x27 0x0>;
+               sdhci,auto-cmd12;
+               clocks = <sw_sdio>;
+               mmc-hs200-1_8v;
+       };
index dca56d6248f5944880c0e73395344217fd420daf..3e29050ec769653e54c7631c96e8dc698a2eb150 100644 (file)
@@ -28,6 +28,8 @@ 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-start-tap: Specify the start dealy cell point when send first CMD19
+  in tuning procedure.
 - 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
index ed23b9bedfdc05425fe7f01486a4f5ed7c7f8e95..22d1e1f3f38bbf2bf86da4f8139a0288c7778c28 100644 (file)
@@ -46,8 +46,12 @@ Optional properties:
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 - mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
 - mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
+- mmc-hs400-enhanced-strobe: eMMC HS400 enhanced strobe mode is supported
 - dsr: Value the card's (optional) Driver Stage Register (DSR) should be
   programmed with. Valid range: [0 .. 0xffff].
+- no-sdio: controller is limited to send sdio cmd during initialization
+- no-sd: controller is limited to send sd cmd during initialization
+- no-mmc: controller is limited to send mmc cmd during initialization
 
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
 polarity properties, we have to fix the meaning of the "normal" and "inverted"
index 555cb0f406908a0fc5ebfc995a8df97af8a2dcba..e3ea55763b0ac5945b108d6f1d6a4fb443a8d9b2 100644 (file)
@@ -7,6 +7,13 @@ Required properties:
  - reg: PHY register address offset and length in "general
    register files"
 
+Optional clocks using the clock bindings (see ../clock/clock-bindings.txt),
+specified by name:
+ - clock-names: Should contain "emmcclk".  Although this is listed as optional
+               (because most boards can get basic functionality without having
+               access to it), it is strongly suggested.
+ - clocks: Should have a phandle to the card clock exported by the SDHCI driver.
+
 Example:
 
 
@@ -20,6 +27,8 @@ grf: syscon@ff770000 {
        emmcphy: phy@f780 {
                compatible = "rockchip,rk3399-emmc-phy";
                reg = <0xf780 0x20>;
+               clocks = <&sdhci>;
+               clock-names = "emmcclk";
                #phy-cells = <0>;
        };
 };
index caa555706f8931dddf8cab3c88763b42d3d2c4d8..404a0e9e92b0c8ea5823271eecc06c965ffaed35 100644 (file)
@@ -28,6 +28,8 @@ All attributes are read-only.
        preferred_erase_size    Preferred erase size
        raw_rpmb_size_mult      RPMB partition size
        rel_sectors             Reliable write sector count
+       ocr                     Operation Conditions Register
+       dsr                     Driver Stage Register
 
 Note on Erase Size and Preferred Erase Size:
 
index 0868ea5de46500e0510e88bd358782bceb4991d2..72f77035c5620f62f99e40696d60679f79e2177e 100644 (file)
@@ -7863,6 +7863,7 @@ M:        Ulf Hansson <ulf.hansson@linaro.org>
 L:     linux-mmc@vger.kernel.org
 T:     git git://git.linaro.org/people/ulf.hansson/mmc.git
 S:     Maintained
+F:     Documentation/devicetree/bindings/mmc/
 F:     drivers/mmc/
 F:     include/linux/mmc/
 F:     include/uapi/linux/mmc/
@@ -10355,6 +10356,13 @@ F:     tools/testing/selftests/seccomp/*
 K:     \bsecure_computing
 K:     \bTIF_SECCOMP\b
 
+SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) Broadcom BRCMSTB DRIVER
+M:     Al Cooper <alcooperx@gmail.com>
+L:     linux-mmc@vger.kernel.org
+L:     bcm-kernel-feedback-list@broadcom.com
+S:     Maintained
+F:     drivers/mmc/host/sdhci-brcmstb*
+
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
 M:     Ben Dooks <ben-linux@fluff.org>
 M:     Jaehoon Chung <jh80.chung@samsung.com>
index 10b553765ee7ecf8a80595236152db232074585c..48a5dd740f3ba38b854ac8bfbbdfa93de4820f6a 100644 (file)
@@ -1801,8 +1801,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
                do_data_tag = (card->ext_csd.data_tag_unit_size) &&
                        (prq->cmd_flags & REQ_META) &&
                        (rq_data_dir(prq) == WRITE) &&
-                       ((brq->data.blocks * brq->data.blksz) >=
-                        card->ext_csd.data_tag_unit_size);
+                       blk_rq_bytes(prq) >= card->ext_csd.data_tag_unit_size;
                /* Argument of CMD23 */
                packed_cmd_hdr[(i * 2)] = cpu_to_le32(
                        (do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
@@ -1977,8 +1976,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
                         * When 4KB native sector is enabled, only 8 blocks
                         * multiple read or write is allowed
                         */
-                       if ((brq->data.blocks & 0x07) &&
-                           (card->ext_csd.data_sector_size == 4096)) {
+                       if (mmc_large_sector(card) &&
+                               !IS_ALIGNED(blk_rq_sectors(rqc), 8)) {
                                pr_err("%s: Transfer size is not 4KB sector size aligned\n",
                                        req->rq_disk->disk_name);
                                mq_rq = mq->mqrq_cur;
@@ -2501,12 +2500,6 @@ force_ro_fail:
        return ret;
 }
 
-#define CID_MANFID_SANDISK     0x2
-#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[] =
 {
        MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
index 4bc48f10452fb02dc7ada8d6a8fd4cef11fde41f..c64266f5a399b3c6ee2535d2b8539460a75ed5e2 100644 (file)
@@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
                        mmc_card_ddr52(card) ? "DDR " : "",
                        type);
        } else {
-               pr_info("%s: new %s%s%s%s%s card at address %04x\n",
+               pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
                        mmc_hostname(card->host),
                        mmc_card_uhs(card) ? "ultra high speed " :
                        (mmc_card_hs(card) ? "high speed " : ""),
                        mmc_card_hs400(card) ? "HS400 " :
                        (mmc_card_hs200(card) ? "HS200 " : ""),
+                       mmc_card_hs400es(card) ? "Enhanced strobe " : "",
                        mmc_card_ddr52(card) ? "DDR " : "",
                        uhs_bus_speed_mode, type, card->rca);
        }
index 8b4dfd45433b73c1ccf6fe4cd4f9ca3338546cff..e55cde6d436dddae261c69ef36ca4de93eaa01ac 100644 (file)
@@ -1127,6 +1127,15 @@ void mmc_set_initial_state(struct mmc_host *host)
        host->ios.bus_width = MMC_BUS_WIDTH_1;
        host->ios.timing = MMC_TIMING_LEGACY;
        host->ios.drv_type = 0;
+       host->ios.enhanced_strobe = false;
+
+       /*
+        * Make sure we are in non-enhanced strobe mode before we
+        * actually enable it in ext_csd.
+        */
+       if ((host->caps2 & MMC_CAP2_HS400_ES) &&
+            host->ops->hs400_enhanced_strobe)
+               host->ops->hs400_enhanced_strobe(host, &host->ios);
 
        mmc_set_ios(host);
 }
@@ -1925,17 +1934,15 @@ void mmc_init_erase(struct mmc_card *card)
         * to that size and alignment.
         *
         * For SD cards that define Allocation Unit size, limit erases to one
-        * Allocation Unit at a time.  For MMC cards that define High Capacity
-        * Erase Size, whether it is switched on or not, limit to that size.
-        * Otherwise just have a stab at a good value.  For modern cards it
-        * will end up being 4MiB.  Note that if the value is too small, it
-        * can end up taking longer to erase.
+        * Allocation Unit at a time.
+        * For MMC, have a stab at ai good value and for modern cards it will
+        * end up being 4MiB. Note that if the value is too small, it can end
+        * up taking longer to erase. Also note, erase_size is already set to
+        * High Capacity Erase Size if available when this function is called.
         */
        if (mmc_card_sd(card) && card->ssr.au) {
                card->pref_erase = card->ssr.au;
                card->erase_shift = ffs(card->ssr.au) - 1;
-       } else if (card->ext_csd.hc_erase_size) {
-               card->pref_erase = card->ext_csd.hc_erase_size;
        } else if (card->erase_size) {
                sz = (card->csd.capacity << (card->csd.read_blkbits - 9)) >> 11;
                if (sz < 128)
@@ -2060,7 +2067,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                        unsigned int to, unsigned int arg)
 {
        struct mmc_command cmd = {0};
-       unsigned int qty = 0;
+       unsigned int qty = 0, busy_timeout = 0;
+       bool use_r1b_resp = false;
        unsigned long timeout;
        int err;
 
@@ -2128,8 +2136,22 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        memset(&cmd, 0, sizeof(struct mmc_command));
        cmd.opcode = MMC_ERASE;
        cmd.arg = arg;
-       cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-       cmd.busy_timeout = mmc_erase_timeout(card, arg, qty);
+       busy_timeout = mmc_erase_timeout(card, arg, qty);
+       /*
+        * If the host controller supports busy signalling and the timeout for
+        * the erase operation does not exceed the max_busy_timeout, we should
+        * use R1B response. Or we need to prevent the host from doing hw busy
+        * detection, which is done by converting to a R1 response instead.
+        */
+       if (card->host->max_busy_timeout &&
+           busy_timeout > card->host->max_busy_timeout) {
+               cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+       } else {
+               cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+               cmd.busy_timeout = busy_timeout;
+               use_r1b_resp = true;
+       }
+
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err) {
                pr_err("mmc_erase: erase error %d, status %#x\n",
@@ -2141,7 +2163,14 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        if (mmc_host_is_spi(card->host))
                goto out;
 
-       timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
+       /*
+        * In case of when R1B + MMC_CAP_WAIT_WHILE_BUSY is used, the polling
+        * shall be avoided.
+        */
+       if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
+               goto out;
+
+       timeout = jiffies + msecs_to_jiffies(busy_timeout);
        do {
                memset(&cmd, 0, sizeof(struct mmc_command));
                cmd.opcode = MMC_SEND_STATUS;
@@ -2321,23 +2350,41 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
                                            unsigned int arg)
 {
        struct mmc_host *host = card->host;
-       unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
+       unsigned int max_discard, x, y, qty = 0, max_qty, min_qty, timeout;
        unsigned int last_timeout = 0;
 
-       if (card->erase_shift)
+       if (card->erase_shift) {
                max_qty = UINT_MAX >> card->erase_shift;
-       else if (mmc_card_sd(card))
+               min_qty = card->pref_erase >> card->erase_shift;
+       } else if (mmc_card_sd(card)) {
                max_qty = UINT_MAX;
-       else
+               min_qty = card->pref_erase;
+       } else {
                max_qty = UINT_MAX / card->erase_size;
+               min_qty = card->pref_erase / card->erase_size;
+       }
 
-       /* Find the largest qty with an OK timeout */
+       /*
+        * We should not only use 'host->max_busy_timeout' as the limitation
+        * when deciding the max discard sectors. We should set a balance value
+        * to improve the erase speed, and it can not get too long timeout at
+        * the same time.
+        *
+        * Here we set 'card->pref_erase' as the minimal discard sectors no
+        * matter what size of 'host->max_busy_timeout', but if the
+        * 'host->max_busy_timeout' is large enough for more discard sectors,
+        * then we can continue to increase the max discard sectors until we
+        * get a balance value.
+        */
        do {
                y = 0;
                for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
                        timeout = mmc_erase_timeout(card, arg, qty + x);
-                       if (timeout > host->max_busy_timeout)
+
+                       if (qty + x > min_qty &&
+                           timeout > host->max_busy_timeout)
                                break;
+
                        if (timeout < last_timeout)
                                break;
                        last_timeout = timeout;
@@ -2491,17 +2538,21 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
 
        mmc_go_idle(host);
 
-       mmc_send_if_cond(host, host->ocr_avail);
+       if (!(host->caps2 & MMC_CAP2_NO_SD))
+               mmc_send_if_cond(host, host->ocr_avail);
 
        /* Order's important: probe SDIO, then SD, then MMC */
        if (!(host->caps2 & MMC_CAP2_NO_SDIO))
                if (!mmc_attach_sdio(host))
                        return 0;
 
-       if (!mmc_attach_sd(host))
-               return 0;
-       if (!mmc_attach_mmc(host))
-               return 0;
+       if (!(host->caps2 & MMC_CAP2_NO_SD))
+               if (!mmc_attach_sd(host))
+                       return 0;
+
+       if (!(host->caps2 & MMC_CAP2_NO_MMC))
+               if (!mmc_attach_mmc(host))
+                       return 0;
 
        mmc_power_off(host);
        return -EIO;
index 9382a57a5aa496f19c22353521fe475e1d253c91..c8451ce557ae69da2d01aed9a06c9ca6efbc556f 100644 (file)
@@ -148,7 +148,8 @@ static int mmc_ios_show(struct seq_file *s, void *data)
                str = "mmc HS200";
                break;
        case MMC_TIMING_MMC_HS400:
-               str = "mmc HS400";
+               str = mmc_card_hs400es(host->card) ?
+                       "mmc HS400 enhanced strobe" : "mmc HS400";
                break;
        default:
                str = "invalid";
index 1be42fab1a3051a77523abf093bb3cbf057bc32c..98f25ffb42583a1f5c70258fd2f4bd9c55d6f00e 100644 (file)
@@ -313,6 +313,14 @@ int mmc_of_parse(struct mmc_host *host)
                host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
        if (of_property_read_bool(np, "mmc-hs400-1_2v"))
                host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
+       if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
+               host->caps2 |= MMC_CAP2_HS400_ES;
+       if (of_property_read_bool(np, "no-sdio"))
+               host->caps2 |= MMC_CAP2_NO_SDIO;
+       if (of_property_read_bool(np, "no-sd"))
+               host->caps2 |= MMC_CAP2_NO_SD;
+       if (of_property_read_bool(np, "no-mmc"))
+               host->caps2 |= MMC_CAP2_NO_MMC;
 
        host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
        if (host->dsr_req && (host->dsr & ~0xffff)) {
index 5d438ad3ee32c994eab11f33c267d7d0d62dbbae..f2d185cf8a8ba52e8f68651c2c517e55313c9d57 100644 (file)
@@ -45,6 +45,17 @@ static const unsigned int tacc_mant[] = {
        35,     40,     45,     50,     55,     60,     70,     80,
 };
 
+static const struct mmc_fixup mmc_ext_csd_fixups[] = {
+       /*
+        * Certain Hynix eMMC 4.41 cards might get broken when HPI feature
+        * is used so disable the HPI feature for such buggy cards.
+        */
+       MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
+                             0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
+
+       END_FIXUP
+};
+
 #define UNSTUFF_BITS(resp,start,size)                                  \
        ({                                                              \
                const int __size = size;                                \
@@ -235,6 +246,11 @@ static void mmc_select_card_type(struct mmc_card *card)
                avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
        }
 
+       if ((caps2 & MMC_CAP2_HS400_ES) &&
+           card->ext_csd.strobe_support &&
+           (avail_type & EXT_CSD_CARD_TYPE_HS400))
+               avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
+
        card->ext_csd.hs_max_dtr = hs_max_dtr;
        card->ext_csd.hs200_max_dtr = hs200_max_dtr;
        card->mmc_avail_type = avail_type;
@@ -370,6 +386,9 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
         */
        card->ext_csd.rev = ext_csd[EXT_CSD_REV];
 
+       /* fixup device after ext_csd revision field is updated */
+       mmc_fixup_device(card, mmc_ext_csd_fixups);
+
        card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
        card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
        card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
@@ -386,6 +405,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
                        mmc_card_set_blockaddr(card);
        }
 
+       card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
        card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
        mmc_select_card_type(card);
 
@@ -500,7 +520,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
                        card->cid.year += 16;
 
                /* check whether the eMMC card supports BKOPS */
-               if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
+               if (!mmc_card_broken_hpi(card) &&
+                   ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
                        card->ext_csd.bkops = 1;
                        card->ext_csd.man_bkops_en =
                                        (ext_csd[EXT_CSD_BKOPS_EN] &
@@ -513,7 +534,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
                }
 
                /* check whether the eMMC card supports HPI */
-               if (!broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) {
+               if (!mmc_card_broken_hpi(card) &&
+                   !broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) {
                        card->ext_csd.hpi = 1;
                        if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
                                card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
@@ -727,6 +749,7 @@ MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
 MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
 MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
 MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
+MMC_DEV_ATTR(ocr, "%08x\n", card->ocr);
 
 static ssize_t mmc_fwrev_show(struct device *dev,
                              struct device_attribute *attr,
@@ -744,6 +767,22 @@ static ssize_t mmc_fwrev_show(struct device *dev,
 
 static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL);
 
+static ssize_t mmc_dsr_show(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct mmc_card *card = mmc_dev_to_card(dev);
+       struct mmc_host *host = card->host;
+
+       if (card->csd.dsr_imp && host->dsr_req)
+               return sprintf(buf, "0x%x\n", host->dsr);
+       else
+               /* return default DSR value */
+               return sprintf(buf, "0x%x\n", 0x404);
+}
+
+static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
+
 static struct attribute *mmc_std_attrs[] = {
        &dev_attr_cid.attr,
        &dev_attr_csd.attr,
@@ -762,6 +801,8 @@ static struct attribute *mmc_std_attrs[] = {
        &dev_attr_enhanced_area_size.attr,
        &dev_attr_raw_rpmb_size_mult.attr,
        &dev_attr_rel_sectors.attr,
+       &dev_attr_ocr.attr,
+       &dev_attr_dsr.attr,
        NULL,
 };
 ATTRIBUTE_GROUPS(mmc_std);
@@ -959,6 +1000,19 @@ static int mmc_select_bus_width(struct mmc_card *card)
        return err;
 }
 
+/* Caller must hold re-tuning */
+static int mmc_switch_status(struct mmc_card *card)
+{
+       u32 status;
+       int err;
+
+       err = mmc_send_status(card, &status);
+       if (err)
+               return err;
+
+       return mmc_switch_status_error(card->host, status);
+}
+
 /*
  * Switch to the high-speed mode
  */
@@ -969,9 +1023,11 @@ static int mmc_select_hs(struct mmc_card *card)
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                           EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
                           card->ext_csd.generic_cmd6_time,
-                          true, true, true);
-       if (!err)
+                          true, false, true);
+       if (!err) {
                mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+               err = mmc_switch_status(card);
+       }
 
        return err;
 }
@@ -1047,23 +1103,9 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
        return err;
 }
 
-/* Caller must hold re-tuning */
-static int mmc_switch_status(struct mmc_card *card)
-{
-       u32 status;
-       int err;
-
-       err = mmc_send_status(card, &status);
-       if (err)
-               return err;
-
-       return mmc_switch_status_error(card->host, status);
-}
-
 static int mmc_select_hs400(struct mmc_card *card)
 {
        struct mmc_host *host = card->host;
-       bool send_status = true;
        unsigned int max_dtr;
        int err = 0;
        u8 val;
@@ -1075,19 +1117,12 @@ static int mmc_select_hs400(struct mmc_card *card)
              host->ios.bus_width == MMC_BUS_WIDTH_8))
                return 0;
 
-       if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
-               send_status = false;
-
-       /* Reduce frequency to HS frequency */
-       max_dtr = card->ext_csd.hs_max_dtr;
-       mmc_set_clock(host, max_dtr);
-
        /* Switch card to HS mode */
        val = EXT_CSD_TIMING_HS;
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                           EXT_CSD_HS_TIMING, val,
                           card->ext_csd.generic_cmd6_time,
-                          true, send_status, true);
+                          true, false, true);
        if (err) {
                pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
                        mmc_hostname(host), err);
@@ -1097,11 +1132,13 @@ static int mmc_select_hs400(struct mmc_card *card)
        /* Set host controller to HS timing */
        mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 
-       if (!send_status) {
-               err = mmc_switch_status(card);
-               if (err)
-                       goto out_err;
-       }
+       /* Reduce frequency to HS frequency */
+       max_dtr = card->ext_csd.hs_max_dtr;
+       mmc_set_clock(host, max_dtr);
+
+       err = mmc_switch_status(card);
+       if (err)
+               goto out_err;
 
        /* Switch card to DDR */
        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -1120,7 +1157,7 @@ static int mmc_select_hs400(struct mmc_card *card)
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                           EXT_CSD_HS_TIMING, val,
                           card->ext_csd.generic_cmd6_time,
-                          true, send_status, true);
+                          true, false, true);
        if (err) {
                pr_err("%s: switch to hs400 failed, err:%d\n",
                         mmc_hostname(host), err);
@@ -1131,11 +1168,9 @@ static int mmc_select_hs400(struct mmc_card *card)
        mmc_set_timing(host, MMC_TIMING_MMC_HS400);
        mmc_set_bus_speed(card);
 
-       if (!send_status) {
-               err = mmc_switch_status(card);
-               if (err)
-                       goto out_err;
-       }
+       err = mmc_switch_status(card);
+       if (err)
+               goto out_err;
 
        return 0;
 
@@ -1153,14 +1188,10 @@ int mmc_hs200_to_hs400(struct mmc_card *card)
 int mmc_hs400_to_hs200(struct mmc_card *card)
 {
        struct mmc_host *host = card->host;
-       bool send_status = true;
        unsigned int max_dtr;
        int err;
        u8 val;
 
-       if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
-               send_status = false;
-
        /* Reduce frequency to HS */
        max_dtr = card->ext_csd.hs_max_dtr;
        mmc_set_clock(host, max_dtr);
@@ -1169,49 +1200,43 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
        val = EXT_CSD_TIMING_HS;
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
                           val, card->ext_csd.generic_cmd6_time,
-                          true, send_status, true);
+                          true, false, true);
        if (err)
                goto out_err;
 
        mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
 
-       if (!send_status) {
-               err = mmc_switch_status(card);
-               if (err)
-                       goto out_err;
-       }
+       err = mmc_switch_status(card);
+       if (err)
+               goto out_err;
 
        /* Switch HS DDR to HS */
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
                           EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
-                          true, send_status, true);
+                          true, false, true);
        if (err)
                goto out_err;
 
        mmc_set_timing(host, MMC_TIMING_MMC_HS);
 
-       if (!send_status) {
-               err = mmc_switch_status(card);
-               if (err)
-                       goto out_err;
-       }
+       err = mmc_switch_status(card);
+       if (err)
+               goto out_err;
 
        /* Switch HS to HS200 */
        val = EXT_CSD_TIMING_HS200 |
              card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
-                          val, card->ext_csd.generic_cmd6_time, true,
-                          send_status, true);
+                          val, card->ext_csd.generic_cmd6_time,
+                          true, false, true);
        if (err)
                goto out_err;
 
        mmc_set_timing(host, MMC_TIMING_MMC_HS200);
 
-       if (!send_status) {
-               err = mmc_switch_status(card);
-               if (err)
-                       goto out_err;
-       }
+       err = mmc_switch_status(card);
+       if (err)
+               goto out_err;
 
        mmc_set_bus_speed(card);
 
@@ -1223,6 +1248,78 @@ out_err:
        return err;
 }
 
+static int mmc_select_hs400es(struct mmc_card *card)
+{
+       struct mmc_host *host = card->host;
+       int err = 0;
+       u8 val;
+
+       if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
+               err = -ENOTSUPP;
+               goto out_err;
+       }
+
+       err = mmc_select_bus_width(card);
+       if (err < 0)
+               goto out_err;
+
+       /* Switch card to HS mode */
+       err = mmc_select_hs(card);
+       if (err) {
+               pr_err("%s: switch to high-speed failed, err:%d\n",
+                       mmc_hostname(host), err);
+               goto out_err;
+       }
+
+       err = mmc_switch_status(card);
+       if (err)
+               goto out_err;
+
+       /* Switch card to DDR with strobe bit */
+       val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
+       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                        EXT_CSD_BUS_WIDTH,
+                        val,
+                        card->ext_csd.generic_cmd6_time);
+       if (err) {
+               pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
+                       mmc_hostname(host), err);
+               goto out_err;
+       }
+
+       /* Switch card to HS400 */
+       val = EXT_CSD_TIMING_HS400 |
+             card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+       err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                          EXT_CSD_HS_TIMING, val,
+                          card->ext_csd.generic_cmd6_time,
+                          true, false, true);
+       if (err) {
+               pr_err("%s: switch to hs400es failed, err:%d\n",
+                       mmc_hostname(host), err);
+               goto out_err;
+       }
+
+       /* Set host controller to HS400 timing and frequency */
+       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+
+       /* Controller enable enhanced strobe function */
+       host->ios.enhanced_strobe = true;
+       if (host->ops->hs400_enhanced_strobe)
+               host->ops->hs400_enhanced_strobe(host, &host->ios);
+
+       err = mmc_switch_status(card);
+       if (err)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
+              __func__, err);
+       return err;
+}
+
 static void mmc_select_driver_type(struct mmc_card *card)
 {
        int card_drv_type, drive_strength, drv_type;
@@ -1250,7 +1347,6 @@ static void mmc_select_driver_type(struct mmc_card *card)
 static int mmc_select_hs200(struct mmc_card *card)
 {
        struct mmc_host *host = card->host;
-       bool send_status = true;
        unsigned int old_timing, old_signal_voltage;
        int err = -EINVAL;
        u8 val;
@@ -1268,34 +1364,30 @@ static int mmc_select_hs200(struct mmc_card *card)
 
        mmc_select_driver_type(card);
 
-       if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
-               send_status = false;
-
        /*
         * Set the bus width(4 or 8) with host's support and
         * switch to HS200 mode if bus width is set successfully.
         */
        err = mmc_select_bus_width(card);
-       if (err >= 0) {
+       if (err > 0) {
                val = EXT_CSD_TIMING_HS200 |
                      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
                err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                   EXT_CSD_HS_TIMING, val,
                                   card->ext_csd.generic_cmd6_time,
-                                  true, send_status, true);
+                                  true, false, true);
                if (err)
                        goto err;
                old_timing = host->ios.timing;
                mmc_set_timing(host, MMC_TIMING_MMC_HS200);
-               if (!send_status) {
-                       err = mmc_switch_status(card);
-                       /*
-                        * mmc_select_timing() assumes timing has not changed if
-                        * it is a switch error.
-                        */
-                       if (err == -EBADMSG)
-                               mmc_set_timing(host, old_timing);
-               }
+
+               err = mmc_switch_status(card);
+               /*
+                * mmc_select_timing() assumes timing has not changed if
+                * it is a switch error.
+                */
+               if (err == -EBADMSG)
+                       mmc_set_timing(host, old_timing);
        }
 err:
        if (err) {
@@ -1310,7 +1402,7 @@ err:
 }
 
 /*
- * Activate High Speed or HS200 mode if supported.
+ * Activate High Speed, HS200 or HS400ES mode if supported.
  */
 static int mmc_select_timing(struct mmc_card *card)
 {
@@ -1319,7 +1411,9 @@ static int mmc_select_timing(struct mmc_card *card)
        if (!mmc_can_ext_csd(card))
                goto bus_speed;
 
-       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
+               err = mmc_select_hs400es(card);
+       else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
                err = mmc_select_hs200(card);
        else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
                err = mmc_select_hs(card);
@@ -1583,7 +1677,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        } else if (mmc_card_hs(card)) {
                /* Select the desired bus width optionally */
                err = mmc_select_bus_width(card);
-               if (err >= 0) {
+               if (err > 0) {
                        err = mmc_select_hs_ddr(card);
                        if (err)
                                goto free_card;
@@ -1616,7 +1710,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         * If cache size is higher than 0, this indicates
         * the existence of cache and it can be turned on.
         */
-       if (card->ext_csd.cache_size > 0) {
+       if (!mmc_card_broken_hpi(card) &&
+           card->ext_csd.cache_size > 0) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                EXT_CSD_CACHE_CTRL, 1,
                                card->ext_csd.generic_cmd6_time);
index 62355bda608f2ec598597df6b4be800e51eeb7c3..ad6e9798e9491f32ef6b7b9957c9853d2a251a0f 100644 (file)
@@ -480,6 +480,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
        u32 status = 0;
        bool use_r1b_resp = use_busy_signal;
        bool expired = false;
+       bool busy = false;
 
        mmc_retune_hold(host);
 
@@ -533,21 +534,26 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                timeout_ms = MMC_OPS_TIMEOUT_MS;
 
        /* Must check status to be sure of no errors. */
-       timeout = jiffies + msecs_to_jiffies(timeout_ms);
+       timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
        do {
+               /*
+                * Due to the possibility of being preempted after
+                * sending the status command, check the expiration
+                * time first.
+                */
+               expired = time_after(jiffies, timeout);
                if (send_status) {
-                       /*
-                        * Due to the possibility of being preempted after
-                        * sending the status command, check the expiration
-                        * time first.
-                        */
-                       expired = time_after(jiffies, timeout);
                        err = __mmc_send_status(card, &status, ignore_crc);
                        if (err)
                                goto out;
                }
                if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
                        break;
+               if (host->ops->card_busy) {
+                       if (!host->ops->card_busy(host))
+                               break;
+                       busy = true;
+               }
                if (mmc_host_is_spi(host))
                        break;
 
@@ -556,19 +562,20 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                 * does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
                 * rely on waiting for the stated timeout to be sufficient.
                 */
-               if (!send_status) {
+               if (!send_status && !host->ops->card_busy) {
                        mmc_delay(timeout_ms);
                        goto out;
                }
 
                /* Timeout if the device never leaves the program state. */
-               if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) {
+               if (expired &&
+                   (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy)) {
                        pr_err("%s: Card stuck in programming state! %s\n",
                                mmc_hostname(host), __func__);
                        err = -ETIMEDOUT;
                        goto out;
                }
-       } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
+       } while (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy);
 
        err = mmc_switch_status_error(host, status);
 out:
index fad660b95809224e3a06abde0709be3d50acf307..ca9cade317c7eccee354bb1a075b091f59a62de1 100644 (file)
@@ -72,6 +72,8 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
                     f->cis_vendor == (u16) SDIO_ANY_ID) &&
                    (f->cis_device == card->cis.device ||
                     f->cis_device == (u16) SDIO_ANY_ID) &&
+                   (f->ext_csd_rev == EXT_CSD_REV_ANY ||
+                    f->ext_csd_rev == card->ext_csd.rev) &&
                    rev >= f->rev_start && rev <= f->rev_end) {
                        dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup);
                        f->vendor_fixup(card, f->data);
index b95bd24d92f415f4c8da8d622da62be6e6a61b5e..0123936241b06320cf15abb5463b87399c999838 100644 (file)
@@ -675,8 +675,25 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
 MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
 MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
 MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
+MMC_DEV_ATTR(ocr, "%08x\n", card->ocr);
 
 
+static ssize_t mmc_dsr_show(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct mmc_card *card = mmc_dev_to_card(dev);
+       struct mmc_host *host = card->host;
+
+       if (card->csd.dsr_imp && host->dsr_req)
+               return sprintf(buf, "0x%x\n", host->dsr);
+       else
+               /* return default DSR value */
+               return sprintf(buf, "0x%x\n", 0x404);
+}
+
+static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
+
 static struct attribute *sd_std_attrs[] = {
        &dev_attr_cid.attr,
        &dev_attr_csd.attr,
@@ -690,6 +707,8 @@ static struct attribute *sd_std_attrs[] = {
        &dev_attr_name.attr,
        &dev_attr_oemid.attr,
        &dev_attr_serial.attr,
+       &dev_attr_ocr.attr,
+       &dev_attr_dsr.attr,
        NULL,
 };
 ATTRIBUTE_GROUPS(sd_std);
index 0aa484c10c0a9b93a4aedc885235d95ffe6872e6..5274f503a39ad9c034e23b634ff0ec6634cbbd78 100644 (file)
@@ -122,6 +122,7 @@ config MMC_SDHCI_OF_ARASAN
        tristate "SDHCI OF support for the Arasan SDHCI controllers"
        depends on MMC_SDHCI_PLTFM
        depends on OF
+       depends on COMMON_CLK
        help
          This selects the Arasan Secure Digital Host Controller Interface
          (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC.
@@ -296,17 +297,6 @@ config MMC_SDHCI_BCM_KONA
 
          If you have a controller with this interface, say Y or M here.
 
-config MMC_SDHCI_BCM2835
-       tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
-       depends on ARCH_BCM2835
-       depends on MMC_SDHCI_PLTFM
-       select MMC_SDHCI_IO_ACCESSORS
-       help
-         This selects the BCM2835 SD/MMC controller. If you have a BCM2835
-         platform with SD or MMC devices, say Y or M here.
-
-         If unsure, say N.
-
 config MMC_SDHCI_F_SDH30
        tristate "SDHCI support for Fujitsu Semiconductor F_SDH30"
        depends on MMC_SDHCI_PLTFM
@@ -798,3 +788,13 @@ config MMC_SDHCI_MICROCHIP_PIC32
           If you have a controller with this interface, say Y or M here.
 
           If unsure, say N.
+config MMC_SDHCI_BRCMSTB
+       tristate "Broadcom SDIO/SD/MMC support"
+       depends on ARCH_BRCMSTB || BMIPS_GENERIC
+       depends on MMC_SDHCI_PLTFM
+       default y
+       help
+         This selects support for the SDIO/SD/MMC Host Controller on
+         Broadcom STB SoCs.
+
+         If unsure, say Y.
index af918d261ff9625d1d42146da1173031cd9917dd..e2bdaaf431841535b936600af56b8e38f52f9845 100644 (file)
@@ -71,11 +71,11 @@ 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
-obj-$(CONFIG_MMC_SDHCI_BCM2835)                += sdhci-bcm2835.o
 obj-$(CONFIG_MMC_SDHCI_IPROC)          += sdhci-iproc.o
 obj-$(CONFIG_MMC_SDHCI_MSM)            += sdhci-msm.o
 obj-$(CONFIG_MMC_SDHCI_ST)             += sdhci-st.o
 obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32)        += sdhci-pic32.o
+obj-$(CONFIG_MMC_SDHCI_BRCMSTB)                += sdhci-brcmstb.o
 
 ifeq ($(CONFIG_CB710_DEBUG),y)
        CFLAGS-cb710-mmc        += -DDEBUG
index 7e3a3247b852d76f8521d93cdf5d9d6cef73ccba..da0ef1765735fe48a69a5faf72236598ce1a5cf2 100644 (file)
@@ -157,7 +157,7 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
         * HOLD register should be bypassed in case there is no phase shift
         * applied on CMD/DATA that is sent to the card.
         */
-       if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel))
+       if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->cur_slot)
                set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags);
 }
 
index 63c2e2ed12886abc83e516861b331ea9c3871c28..8e9d886bfcda3780cf5be23f17c7e2d0f7cc5922 100644 (file)
@@ -32,6 +32,12 @@ struct k3_priv {
        struct regmap   *reg;
 };
 
+static unsigned long dw_mci_hi6220_caps[] = {
+       MMC_CAP_CMD23,
+       MMC_CAP_CMD23,
+       0
+};
+
 static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 {
        int ret;
@@ -126,6 +132,7 @@ static void dw_mci_hi6220_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 }
 
 static const struct dw_mci_drv_data hi6220_data = {
+       .caps                   = dw_mci_hi6220_caps,
        .switch_voltage         = dw_mci_hi6220_switch_voltage,
        .set_ios                = dw_mci_hi6220_set_ios,
        .parse_dt               = dw_mci_hi6220_parse_dt,
index 358b0dc853b064c1f640201c1503faee97bc4e6b..25eae359a5ea181b00986a0aabe8cd3a5a76bd8b 100644 (file)
@@ -285,9 +285,6 @@ 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;
-
        if (of_device_is_compatible(host->dev->of_node,
                                    "rockchip,rk3288-dw-mshc"))
                host->bus_hz /= RK3288_CLKGEN_DIV;
@@ -297,10 +294,10 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
 
 /* Common capabilities of RK3288 SoC */
 static unsigned long dw_mci_rk3288_dwmmc_caps[4] = {
-       MMC_CAP_ERASE | MMC_CAP_CMD23,
-       MMC_CAP_ERASE | MMC_CAP_CMD23,
-       MMC_CAP_ERASE | MMC_CAP_CMD23,
-       MMC_CAP_ERASE | MMC_CAP_CMD23,
+       MMC_CAP_CMD23,
+       MMC_CAP_CMD23,
+       MMC_CAP_CMD23,
+       MMC_CAP_CMD23,
 };
 
 static const struct dw_mci_drv_data rk2928_drv_data = {
index 2cc6123b1df98a0c188d3a7626fa8f72424e4f22..32380d5d4f6b15440497b952b035cfe3b76b74ea 100644 (file)
 /* Common flag combinations */
 #define DW_MCI_DATA_ERROR_FLAGS        (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
                                 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
-                                SDMMC_INT_EBE)
+                                SDMMC_INT_EBE | SDMMC_INT_HLE)
 #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \
-                                SDMMC_INT_RESP_ERR)
+                                SDMMC_INT_RESP_ERR | SDMMC_INT_HLE)
 #define DW_MCI_ERROR_FLAGS     (DW_MCI_DATA_ERROR_FLAGS | \
-                                DW_MCI_CMD_ERROR_FLAGS  | SDMMC_INT_HLE)
+                                DW_MCI_CMD_ERROR_FLAGS)
 #define DW_MCI_SEND_STATUS     1
 #define DW_MCI_RECV_STATUS     2
 #define DW_MCI_DMA_THRESHOLD   16
@@ -92,7 +92,7 @@ struct idmac_desc {
 
        __le32          des1;   /* Buffer sizes */
 #define IDMAC_SET_BUFFER1_SIZE(d, s) \
-       ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
+       ((d)->des1 = ((d)->des1 & cpu_to_le32(0x03ffe000)) | (cpu_to_le32((s) & 0x1fff)))
 
        __le32          des2;   /* buffer 1 physical address */
 
@@ -105,6 +105,7 @@ struct idmac_desc {
 static bool dw_mci_reset(struct dw_mci *host);
 static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
 static int dw_mci_card_busy(struct mmc_host *mmc);
+static int dw_mci_get_cd(struct mmc_host *mmc);
 
 #if defined(CONFIG_DEBUG_FS)
 static int dw_mci_req_show(struct seq_file *s, void *v)
@@ -898,23 +899,35 @@ done:
        mci_writel(host, FIFOTH, fifoth_val);
 }
 
-static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
+static void dw_mci_ctrl_thld(struct dw_mci *host, struct mmc_data *data)
 {
        unsigned int blksz = data->blksz;
        u32 blksz_depth, fifo_depth;
        u16 thld_size;
-
-       WARN_ON(!(data->flags & MMC_DATA_READ));
+       u8 enable;
 
        /*
         * CDTHRCTL doesn't exist prior to 240A (in fact that register offset is
         * in the FIFO region, so we really shouldn't access it).
         */
-       if (host->verid < DW_MMC_240A)
+       if (host->verid < DW_MMC_240A ||
+               (host->verid < DW_MMC_280A && data->flags & MMC_DATA_WRITE))
+               return;
+
+       /*
+        * Card write Threshold is introduced since 2.80a
+        * It's used when HS400 mode is enabled.
+        */
+       if (data->flags & MMC_DATA_WRITE &&
+               !(host->timing != MMC_TIMING_MMC_HS400))
                return;
 
+       if (data->flags & MMC_DATA_WRITE)
+               enable = SDMMC_CARD_WR_THR_EN;
+       else
+               enable = SDMMC_CARD_RD_THR_EN;
+
        if (host->timing != MMC_TIMING_MMC_HS200 &&
-           host->timing != MMC_TIMING_MMC_HS400 &&
            host->timing != MMC_TIMING_UHS_SDR104)
                goto disable;
 
@@ -930,11 +943,11 @@ static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
         * Currently just choose blksz.
         */
        thld_size = blksz;
-       mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1));
+       mci_writel(host, CDTHRCTL, SDMMC_SET_THLD(thld_size, enable));
        return;
 
 disable:
-       mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0));
+       mci_writel(host, CDTHRCTL, 0);
 }
 
 static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
@@ -1005,12 +1018,12 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
        host->sg = NULL;
        host->data = data;
 
-       if (data->flags & MMC_DATA_READ) {
+       if (data->flags & MMC_DATA_READ)
                host->dir_status = DW_MCI_RECV_STATUS;
-               dw_mci_ctrl_rd_thld(host, data);
-       } else {
+       else
                host->dir_status = DW_MCI_SEND_STATUS;
-       }
+
+       dw_mci_ctrl_thld(host, data);
 
        if (dw_mci_submit_data_dma(host, data)) {
                if (host->data->flags & MMC_DATA_READ)
@@ -1099,12 +1112,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
 
                div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
 
-               if ((clock << div) != slot->__clk_old || force_clkinit)
-                       dev_info(&slot->mmc->class_dev,
-                                "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
-                                slot->id, host->bus_hz, clock,
-                                div ? ((host->bus_hz / div) >> 1) :
-                                host->bus_hz, div);
+               dev_info(&slot->mmc->class_dev,
+                        "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
+                        slot->id, host->bus_hz, clock,
+                        div ? ((host->bus_hz / div) >> 1) :
+                        host->bus_hz, div);
 
                /* disable clock */
                mci_writel(host, CLKENA, 0);
@@ -1127,9 +1139,6 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
 
                /* inform CIU */
                mci_send_cmd(slot, sdmmc_cmd_bits, 0);
-
-               /* keep the clock with reflecting clock dividor */
-               slot->__clk_old = clock << div;
        }
 
        host->current_speed = clock;
@@ -1253,15 +1262,15 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
         * atomic, otherwise the card could be removed in between and the
         * request wouldn't fail until another card was inserted.
         */
-       spin_lock_bh(&host->lock);
 
-       if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
-               spin_unlock_bh(&host->lock);
+       if (!dw_mci_get_cd(mmc)) {
                mrq->cmd->error = -ENOMEDIUM;
                mmc_request_done(mmc, mrq);
                return;
        }
 
+       spin_lock_bh(&host->lock);
+
        dw_mci_queue_request(host, slot, mrq);
 
        spin_unlock_bh(&host->lock);
@@ -1451,8 +1460,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
        int gpio_cd = mmc_gpio_get_cd(mmc);
 
        /* Use platform get_cd function, else try onboard card detect */
-       if ((mmc->caps & MMC_CAP_NEEDS_POLL) ||
-           (mmc->caps & MMC_CAP_NONREMOVABLE))
+       if ((mmc->caps & MMC_CAP_NEEDS_POLL) || !mmc_card_is_removable(mmc))
                present = 1;
        else if (gpio_cd >= 0)
                present = gpio_cd;
@@ -1761,6 +1769,33 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        }
 
                        if (cmd->data && err) {
+                               /*
+                                * During UHS tuning sequence, sending the stop
+                                * command after the response CRC error would
+                                * throw the system into a confused state
+                                * causing all future tuning phases to report
+                                * failure.
+                                *
+                                * In such case controller will move into a data
+                                * transfer state after a response error or
+                                * response CRC error. Let's let that finish
+                                * before trying to send a stop, so we'll go to
+                                * STATE_SENDING_DATA.
+                                *
+                                * Although letting the data transfer take place
+                                * will waste a bit of time (we already know
+                                * the command was bad), it can't cause any
+                                * errors since it's possible it would have
+                                * taken place anyway if this tasklet got
+                                * delayed. Allowing the transfer to take place
+                                * avoids races and keeps things simple.
+                                */
+                               if ((err != -ETIMEDOUT) &&
+                                   (cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
+                                       state = STATE_SENDING_DATA;
+                                       continue;
+                               }
+
                                dw_mci_stop_dma(host);
                                send_stop_abort(host, data);
                                state = STATE_SENDING_STOP;
@@ -1801,8 +1836,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                 * 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))
+                               if (host->dir_status == DW_MCI_RECV_STATUS)
                                        dw_mci_set_drto(host);
                                break;
                        }
@@ -1844,8 +1878,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                 * 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))
+                               if (host->dir_status == DW_MCI_RECV_STATUS)
                                        dw_mci_set_drto(host);
                                break;
                        }
@@ -2411,8 +2444,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                }
 
                if (pending & SDMMC_INT_DATA_OVER) {
-                       if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)
-                               del_timer(&host->dto_timer);
+                       del_timer(&host->dto_timer);
 
                        mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
                        if (!host->data_status)
@@ -2474,7 +2506,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                        mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |
                                                        SDMMC_IDMAC_INT_RI);
                        mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI);
-                       host->dma_ops->complete((void *)host);
+                       if (!test_bit(EVENT_DATA_ERROR, &host->pending_events))
+                               host->dma_ops->complete((void *)host);
                }
        } else {
                pending = mci_readl(host, IDSTS);
@@ -2482,7 +2515,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                        mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |
                                                        SDMMC_IDMAC_INT_RI);
                        mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
-                       host->dma_ops->complete((void *)host);
+                       if (!test_bit(EVENT_DATA_ERROR, &host->pending_events))
+                               host->dma_ops->complete((void *)host);
                }
        }
 
@@ -2570,6 +2604,12 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        if (host->pdata->caps)
                mmc->caps = host->pdata->caps;
 
+       /*
+        * Support MMC_CAP_ERASE by default.
+        * It needs to use trim/discard/erase commands.
+        */
+       mmc->caps |= MMC_CAP_ERASE;
+
        if (host->pdata->pm_caps)
                mmc->pm_caps = host->pdata->pm_caps;
 
@@ -2616,10 +2656,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
                mmc->max_seg_size = mmc->max_req_size;
        }
 
-       if (dw_mci_get_cd(mmc))
-               set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-       else
-               clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+       dw_mci_get_cd(mmc);
 
        ret = mmc_add_host(mmc);
        if (ret)
@@ -3006,11 +3043,8 @@ int dw_mci_probe(struct dw_mci *host)
        setup_timer(&host->cmd11_timer,
                    dw_mci_cmd11_timer, (unsigned long)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);
+       setup_timer(&host->dto_timer,
+                   dw_mci_dto_timer, (unsigned long)host);
 
        spin_lock_init(&host->lock);
        spin_lock_init(&host->irq_lock);
index 1e8d8380f9cff7d27d7dfa6b71acd6b509364ceb..9e740bc232a8bed09ef7ee668a8a3abdef6e93d1 100644 (file)
@@ -15,6 +15,7 @@
 #define _DW_MMC_H_
 
 #define DW_MMC_240A            0x240a
+#define DW_MMC_280A            0x280a
 
 #define SDMMC_CTRL             0x000
 #define SDMMC_PWREN            0x004
 /* Version ID register define */
 #define SDMMC_GET_VERID(x)             ((x) & 0xFFFF)
 /* Card read threshold */
-#define SDMMC_SET_RD_THLD(v, x)                (((v) & 0xFFF) << 16 | (x))
+#define SDMMC_SET_THLD(v, x)           (((v) & 0xFFF) << 16 | (x))
+#define SDMMC_CARD_WR_THR_EN           BIT(2)
+#define SDMMC_CARD_RD_THR_EN           BIT(0)
+/* UHS-1 register defines */
 #define SDMMC_UHS_18V                  BIT(0)
 /* All ctrl reset bits */
 #define SDMMC_CTRL_ALL_RESET_FLAGS \
@@ -245,9 +249,6 @@ extern int dw_mci_resume(struct dw_mci *host);
  * @queue_node: List node for placing this node in the @queue list of
  *     &struct dw_mci.
  * @clock: Clock rate configured by set_ios(). Protected by host->lock.
- * @__clk_old: The last updated clock with reflecting clock divider.
- *     Keeping track of this helps us to avoid spamming the console
- *     with CONFIG_MMC_CLKGATE.
  * @flags: Random state bits associated with the slot.
  * @id: Number of this slot.
  * @sdio_id: Number of this slot in the SDIO interrupt registers.
@@ -262,7 +263,6 @@ struct dw_mci_slot {
        struct list_head        queue_node;
 
        unsigned int            clock;
-       unsigned int            __clk_old;
 
        unsigned long           flags;
 #define DW_MMC_CARD_PRESENT    0
index 5642f71f8bf0d04b01cdedfa7b861556556100b7..84e9afcb5c099bd73f080f3c8660fd7780bc3d02 100644 (file)
@@ -287,6 +287,11 @@ struct msdc_save_para {
        u32 emmc50_cfg0;
 };
 
+struct msdc_tune_para {
+       u32 iocon;
+       u32 pad_tune;
+};
+
 struct msdc_delay_phase {
        u8 maxlen;
        u8 start;
@@ -326,7 +331,10 @@ struct msdc_host {
        unsigned char timing;
        bool vqmmc_enabled;
        u32 hs400_ds_delay;
+       bool hs400_mode;        /* current eMMC will run at hs400 mode */
        struct msdc_save_para save_para; /* used when gate HCLK */
+       struct msdc_tune_para def_tune_para; /* default tune setting */
+       struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
 };
 
 static void sdr_set_bits(void __iomem *reg, u32 bs)
@@ -582,6 +590,18 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
        msdc_set_timeout(host, host->timeout_ns, host->timeout_clks);
        sdr_set_bits(host->base + MSDC_INTEN, flags);
 
+       /*
+        * mmc_select_hs400() will drop to 50Mhz and High speed mode,
+        * tune result of hs200/200Mhz is not suitable for 50Mhz
+        */
+       if (host->sclk <= 52000000) {
+               writel(host->def_tune_para.iocon, host->base + MSDC_IOCON);
+               writel(host->def_tune_para.pad_tune, host->base + MSDC_PAD_TUNE);
+       } else {
+               writel(host->saved_tune_para.iocon, host->base + MSDC_IOCON);
+               writel(host->saved_tune_para.pad_tune, host->base + MSDC_PAD_TUNE);
+       }
+
        dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->sclk, timing);
 }
 
@@ -781,7 +801,13 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
        }
 
        if (!sbc_error && !(events & MSDC_INT_CMDRDY)) {
-               msdc_reset_hw(host);
+               if (cmd->opcode != MMC_SEND_TUNING_BLOCK &&
+                   cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)
+                       /*
+                        * should not clear fifo/interrupt as the tune data
+                        * may have alreay come.
+                        */
+                       msdc_reset_hw(host);
                if (events & MSDC_INT_RSPCRCERR) {
                        cmd->error = -EILSEQ;
                        host->error |= REQ_CMD_EIO;
@@ -865,7 +891,11 @@ static void msdc_start_command(struct msdc_host *host,
 static void msdc_cmd_next(struct msdc_host *host,
                struct mmc_request *mrq, struct mmc_command *cmd)
 {
-       if (cmd->error || (mrq->sbc && mrq->sbc->error))
+       if ((cmd->error &&
+           !(cmd->error == -EILSEQ &&
+             (cmd->opcode == MMC_SEND_TUNING_BLOCK ||
+              cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200))) ||
+           (mrq->sbc && mrq->sbc->error))
                msdc_request_done(host, mrq);
        else if (cmd == mrq->sbc)
                msdc_start_command(host, mrq, mrq->cmd);
@@ -1158,6 +1188,8 @@ static void msdc_init_hw(struct msdc_host *host)
        /* Configure to default data timeout */
        sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
 
+       host->def_tune_para.iocon = readl(host->base + MSDC_IOCON);
+       host->def_tune_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
        dev_dbg(host->dev, "init hardware done!");
 }
 
@@ -1296,7 +1328,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
 {
        struct msdc_host *host = mmc_priv(mmc);
        u32 rise_delay = 0, fall_delay = 0;
-       struct msdc_delay_phase final_rise_delay, final_fall_delay;
+       struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
        u8 final_delay, final_maxlen;
        int cmd_err;
        int i;
@@ -1309,6 +1341,11 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
                if (!cmd_err)
                        rise_delay |= (1 << i);
        }
+       final_rise_delay = get_best_delay(host, rise_delay);
+       /* if rising edge has enough margin, then do not scan falling edge */
+       if (final_rise_delay.maxlen >= 10 ||
+           (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
+               goto skip_fall;
 
        sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
        for (i = 0; i < PAD_DELAY_MAX; i++) {
@@ -1318,10 +1355,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
                if (!cmd_err)
                        fall_delay |= (1 << i);
        }
-
-       final_rise_delay = get_best_delay(host, rise_delay);
        final_fall_delay = get_best_delay(host, fall_delay);
 
+skip_fall:
        final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
        if (final_maxlen == final_rise_delay.maxlen) {
                sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
@@ -1342,7 +1378,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
 {
        struct msdc_host *host = mmc_priv(mmc);
        u32 rise_delay = 0, fall_delay = 0;
-       struct msdc_delay_phase final_rise_delay, final_fall_delay;
+       struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
        u8 final_delay, final_maxlen;
        int i, ret;
 
@@ -1355,6 +1391,11 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
                if (!ret)
                        rise_delay |= (1 << i);
        }
+       final_rise_delay = get_best_delay(host, rise_delay);
+       /* if rising edge has enough margin, then do not scan falling edge */
+       if (final_rise_delay.maxlen >= 10 ||
+           (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
+               goto skip_fall;
 
        sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
        sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
@@ -1365,14 +1406,10 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
                if (!ret)
                        fall_delay |= (1 << i);
        }
-
-       final_rise_delay = get_best_delay(host, rise_delay);
        final_fall_delay = get_best_delay(host, fall_delay);
 
+skip_fall:
        final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
-       /* Rising edge is more stable, prefer to use it */
-       if (final_rise_delay.maxlen >= 10)
-               final_maxlen = final_rise_delay.maxlen;
        if (final_maxlen == final_rise_delay.maxlen) {
                sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
                sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
@@ -1402,16 +1439,21 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
                dev_err(host->dev, "Tune response fail!\n");
                return ret;
        }
-       ret = msdc_tune_data(mmc, opcode);
-       if (ret == -EIO)
-               dev_err(host->dev, "Tune data fail!\n");
+       if (host->hs400_mode == false) {
+               ret = msdc_tune_data(mmc, opcode);
+               if (ret == -EIO)
+                       dev_err(host->dev, "Tune data fail!\n");
+       }
 
+       host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON);
+       host->saved_tune_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
        return ret;
 }
 
 static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct msdc_host *host = mmc_priv(mmc);
+       host->hs400_mode = true;
 
        writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE);
        return 0;
index 3d1ea5e0e54952821f730cc26e89a3aeeecb0c78..fb3ca8296273d5895118a95a85db94c5ab643dbc 100644 (file)
@@ -1065,7 +1065,7 @@ static int mxcmci_probe(struct platform_device *pdev)
 
        if (pdata)
                dat3_card_detect = pdata->dat3_card_detect;
-       else if (!(mmc->caps & MMC_CAP_NONREMOVABLE)
+       else if (mmc_card_is_removable(mmc)
                        && !of_property_read_bool(pdev->dev.of_node, "cd-gpios"))
                dat3_card_detect = true;
 
index 93137483ecde93fc509328c9445b8c61c65f8a48..396c9b7e4121b063f3248af0e5c239a2592b635f 100644 (file)
@@ -38,7 +38,6 @@ struct realtek_pci_sdmmc {
        struct rtsx_pcr         *pcr;
        struct mmc_host         *mmc;
        struct mmc_request      *mrq;
-       struct workqueue_struct *workq;
 #define SDMMC_WORKQ_NAME       "rtsx_pci_sdmmc_workq"
 
        struct work_struct      work;
@@ -244,7 +243,7 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
        stat_idx = sd_status_index(rsp_type);
 
        if (rsp_type == SD_RSP_TYPE_R1b)
-               timeout = 3000;
+               timeout = cmd->busy_timeout ? cmd->busy_timeout : 3000;
 
        if (cmd->opcode == SD_SWITCH_VOLTAGE) {
                err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
@@ -885,7 +884,7 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        if (sd_rw_cmd(mrq->cmd) || sdio_extblock_cmd(mrq->cmd, data))
                host->using_cookie = sd_pre_dma_transfer(host, data, false);
 
-       queue_work(host->workq, &host->work);
+       schedule_work(&host->work);
 }
 
 static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
@@ -1360,7 +1359,7 @@ static void realtek_init_host(struct realtek_pci_sdmmc *host)
        mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
        mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
                MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
-               MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
+               MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_ERASE;
        mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE;
        mmc->max_current_330 = 400;
        mmc->max_current_180 = 800;
@@ -1404,11 +1403,6 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        host = mmc_priv(mmc);
-       host->workq = create_singlethread_workqueue(SDMMC_WORKQ_NAME);
-       if (!host->workq) {
-               mmc_free_host(mmc);
-               return -ENOMEM;
-       }
        host->pcr = pcr;
        host->mmc = mmc;
        host->pdev = pdev;
@@ -1462,9 +1456,7 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
        mmc_remove_host(mmc);
        host->eject = true;
 
-       flush_workqueue(host->workq);
-       destroy_workqueue(host->workq);
-       host->workq = NULL;
+       flush_work(&host->work);
 
        mmc_free_host(mmc);
 
index 39814f3dc96f652c46fb4abec59a8dc25503de51..c531deef3258a8bccfa66e88cb351cb7ef17b08e 100644 (file)
@@ -1365,7 +1365,7 @@ static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
         .no_detect = 1,
 };
 
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
 
 static int s3cmci_cpufreq_transition(struct notifier_block *nb,
                                     unsigned long val, void *data)
index cc2e46cb5c643b07c791543852cd62f7eb29f1ad..30c2c0dd1bc8acad424380ca7f22948557cb21d2 100644 (file)
@@ -74,7 +74,7 @@ struct s3cmci_host {
        struct dentry           *debug_regs;
 #endif
 
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
        struct notifier_block   freq_transition;
 #endif
 };
index 008709c5cb09d907065984762fb497164fdec531..8fe0756c8e1e750647b32a7ca417537742a145c0 100644 (file)
@@ -532,11 +532,6 @@ static int sdhci_acpi_resume(struct device *dev)
        return sdhci_resume_host(c->host);
 }
 
-#else
-
-#define sdhci_acpi_suspend     NULL
-#define sdhci_acpi_resume      NULL
-
 #endif
 
 #ifdef CONFIG_PM
@@ -560,8 +555,7 @@ static int sdhci_acpi_runtime_resume(struct device *dev)
 #endif
 
 static const struct dev_pm_ops sdhci_acpi_pm_ops = {
-       .suspend                = sdhci_acpi_suspend,
-       .resume                 = sdhci_acpi_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(sdhci_acpi_suspend, sdhci_acpi_resume)
        SET_RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend,
                        sdhci_acpi_runtime_resume, NULL)
 };
index 00a8a40a372954fdcbbb1d4cd92b3ab1cc953765..e5c634bdfdd909f20b6468c9fefc5b6ecca909c7 100644 (file)
@@ -264,12 +264,12 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
        }
 
        dev_dbg(dev, "non-removable=%c\n",
-               (host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N');
+               mmc_card_is_removable(host->mmc) ? 'N' : 'Y');
        dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n",
                (mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N',
                (mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N');
 
-       if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+       if (!mmc_card_is_removable(host->mmc))
                host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
 
        dev_dbg(dev, "is_8bit=%c\n",
@@ -288,7 +288,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
        }
 
        /* if device is eMMC, emulate card insert right here */
-       if (host->mmc->caps & MMC_CAP_NONREMOVABLE) {
+       if (!mmc_card_is_removable(host->mmc)) {
                ret = sdhci_bcm_kona_sd_card_emulate(host, 1);
                if (ret) {
                        dev_err(dev,
@@ -326,7 +326,7 @@ err_pltfm_free:
 static struct platform_driver sdhci_bcm_kona_driver = {
        .driver         = {
                .name   = "sdhci-kona",
-               .pm     = SDHCI_PLTFM_PMOPS,
+               .pm     = &sdhci_pltfm_pmops,
                .of_match_table = sdhci_bcm_kona_of_match,
        },
        .probe          = sdhci_bcm_kona_probe,
diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c
deleted file mode 100644 (file)
index 4a6a1d1..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * BCM2835 SDHCI
- * Copyright (C) 2012 Stephen Warren
- * Based on U-Boot's MMC driver for the BCM2835 by Oleksandr Tymoshenko & me
- * Portions of the code there were obviously based on the Linux kernel at:
- * git://github.com/raspberrypi/linux.git rpi-3.6.y
- * commit f5b930b "Main bcm2708 linux port" signed-off-by Dom Cobley.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/mmc/host.h>
-#include "sdhci-pltfm.h"
-
-/*
- * 400KHz is max freq for card ID etc. Use that as min card clock. We need to
- * know the min to enable static calculation of max BCM2835_SDHCI_WRITE_DELAY.
- */
-#define MIN_FREQ 400000
-
-/*
- * The Arasan has a bugette whereby it may lose the content of successive
- * writes to registers that are within two SD-card clock cycles of each other
- * (a clock domain crossing problem). It seems, however, that the data
- * register does not have this problem, which is just as well - otherwise we'd
- * have to nobble the DMA engine too.
- *
- * This should probably be dynamically calculated based on the actual card
- * frequency. However, this is the longest we'll have to wait, and doesn't
- * seem to slow access down too much, so the added complexity doesn't seem
- * worth it for now.
- *
- * 1/MIN_FREQ is (max) time per tick of eMMC clock.
- * 2/MIN_FREQ is time for two ticks.
- * Multiply by 1000000 to get uS per two ticks.
- * *1000000 for uSecs.
- * +1 for hack rounding.
- */
-#define BCM2835_SDHCI_WRITE_DELAY      (((2 * 1000000) / MIN_FREQ) + 1)
-
-struct bcm2835_sdhci {
-       u32 shadow;
-};
-
-static void bcm2835_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
-{
-       writel(val, host->ioaddr + reg);
-
-       udelay(BCM2835_SDHCI_WRITE_DELAY);
-}
-
-static inline u32 bcm2835_sdhci_readl(struct sdhci_host *host, int reg)
-{
-       u32 val = readl(host->ioaddr + reg);
-
-       if (reg == SDHCI_CAPABILITIES)
-               val |= SDHCI_CAN_VDD_330;
-
-       return val;
-}
-
-static void bcm2835_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
-{
-       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct bcm2835_sdhci *bcm2835_host = sdhci_pltfm_priv(pltfm_host);
-       u32 oldval = (reg == SDHCI_COMMAND) ? bcm2835_host->shadow :
-               bcm2835_sdhci_readl(host, reg & ~3);
-       u32 word_num = (reg >> 1) & 1;
-       u32 word_shift = word_num * 16;
-       u32 mask = 0xffff << word_shift;
-       u32 newval = (oldval & ~mask) | (val << word_shift);
-
-       if (reg == SDHCI_TRANSFER_MODE)
-               bcm2835_host->shadow = newval;
-       else
-               bcm2835_sdhci_writel(host, newval, reg & ~3);
-}
-
-static u16 bcm2835_sdhci_readw(struct sdhci_host *host, int reg)
-{
-       u32 val = bcm2835_sdhci_readl(host, (reg & ~3));
-       u32 word_num = (reg >> 1) & 1;
-       u32 word_shift = word_num * 16;
-       u32 word = (val >> word_shift) & 0xffff;
-
-       return word;
-}
-
-static void bcm2835_sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
-{
-       u32 oldval = bcm2835_sdhci_readl(host, reg & ~3);
-       u32 byte_num = reg & 3;
-       u32 byte_shift = byte_num * 8;
-       u32 mask = 0xff << byte_shift;
-       u32 newval = (oldval & ~mask) | (val << byte_shift);
-
-       bcm2835_sdhci_writel(host, newval, reg & ~3);
-}
-
-static u8 bcm2835_sdhci_readb(struct sdhci_host *host, int reg)
-{
-       u32 val = bcm2835_sdhci_readl(host, (reg & ~3));
-       u32 byte_num = reg & 3;
-       u32 byte_shift = byte_num * 8;
-       u32 byte = (val >> byte_shift) & 0xff;
-
-       return byte;
-}
-
-static unsigned int bcm2835_sdhci_get_min_clock(struct sdhci_host *host)
-{
-       return MIN_FREQ;
-}
-
-static const struct sdhci_ops bcm2835_sdhci_ops = {
-       .write_l = bcm2835_sdhci_writel,
-       .write_w = bcm2835_sdhci_writew,
-       .write_b = bcm2835_sdhci_writeb,
-       .read_l = bcm2835_sdhci_readl,
-       .read_w = bcm2835_sdhci_readw,
-       .read_b = bcm2835_sdhci_readb,
-       .set_clock = sdhci_set_clock,
-       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
-       .get_min_clock = bcm2835_sdhci_get_min_clock,
-       .set_bus_width = sdhci_set_bus_width,
-       .reset = sdhci_reset,
-       .set_uhs_signaling = sdhci_set_uhs_signaling,
-};
-
-static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {
-       .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
-                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
-       .ops = &bcm2835_sdhci_ops,
-};
-
-static int bcm2835_sdhci_probe(struct platform_device *pdev)
-{
-       struct sdhci_host *host;
-       struct bcm2835_sdhci *bcm2835_host;
-       struct sdhci_pltfm_host *pltfm_host;
-       int ret;
-
-       host = sdhci_pltfm_init(pdev, &bcm2835_sdhci_pdata,
-                               sizeof(*bcm2835_host));
-       if (IS_ERR(host))
-               return PTR_ERR(host);
-
-       pltfm_host = sdhci_priv(host);
-
-       pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(pltfm_host->clk)) {
-               ret = PTR_ERR(pltfm_host->clk);
-               goto err;
-       }
-       ret = clk_prepare_enable(pltfm_host->clk);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to enable host clk\n");
-               goto err;
-       }
-
-       ret = sdhci_add_host(host);
-       if (ret)
-               goto err_clk;
-
-       return 0;
-err_clk:
-       clk_disable_unprepare(pltfm_host->clk);
-err:
-       sdhci_pltfm_free(pdev);
-       return ret;
-}
-
-static const struct of_device_id bcm2835_sdhci_of_match[] = {
-       { .compatible = "brcm,bcm2835-sdhci" },
-       { }
-};
-MODULE_DEVICE_TABLE(of, bcm2835_sdhci_of_match);
-
-static struct platform_driver bcm2835_sdhci_driver = {
-       .driver = {
-               .name = "sdhci-bcm2835",
-               .of_match_table = bcm2835_sdhci_of_match,
-               .pm = SDHCI_PLTFM_PMOPS,
-       },
-       .probe = bcm2835_sdhci_probe,
-       .remove = sdhci_pltfm_unregister,
-};
-module_platform_driver(bcm2835_sdhci_driver);
-
-MODULE_DESCRIPTION("BCM2835 SDHCI driver");
-MODULE_AUTHOR("Stephen Warren");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c
new file mode 100644 (file)
index 0000000..cce10fe
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * sdhci-brcmstb.c Support for SDHCI on Broadcom BRCMSTB SoC's
+ *
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/io.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include "sdhci-pltfm.h"
+
+#ifdef CONFIG_PM_SLEEP
+
+static int sdhci_brcmstb_suspend(struct device *dev)
+{
+       struct sdhci_host *host = dev_get_drvdata(dev);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       int res;
+
+       res = sdhci_suspend_host(host);
+       if (res)
+               return res;
+       clk_disable_unprepare(pltfm_host->clk);
+       return res;
+}
+
+static int sdhci_brcmstb_resume(struct device *dev)
+{
+       struct sdhci_host *host = dev_get_drvdata(dev);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       int err;
+
+       err = clk_prepare_enable(pltfm_host->clk);
+       if (err)
+               return err;
+       return sdhci_resume_host(host);
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(sdhci_brcmstb_pmops, sdhci_brcmstb_suspend,
+                       sdhci_brcmstb_resume);
+
+static const struct sdhci_ops sdhci_brcmstb_ops = {
+       .set_clock = sdhci_set_clock,
+       .set_bus_width = sdhci_set_bus_width,
+       .reset = sdhci_reset,
+       .set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static struct sdhci_pltfm_data sdhci_brcmstb_pdata = {
+       .ops = &sdhci_brcmstb_ops,
+};
+
+static int sdhci_brcmstb_probe(struct platform_device *pdev)
+{
+       struct sdhci_host *host;
+       struct sdhci_pltfm_host *pltfm_host;
+       struct clk *clk;
+       int res;
+
+       clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "Clock not found in Device Tree\n");
+               clk = NULL;
+       }
+       res = clk_prepare_enable(clk);
+       if (res)
+               return res;
+
+       host = sdhci_pltfm_init(pdev, &sdhci_brcmstb_pdata, 0);
+       if (IS_ERR(host)) {
+               res = PTR_ERR(host);
+               goto err_clk;
+       }
+
+       /* Enable MMC_CAP2_HC_ERASE_SZ for better max discard calculations */
+       host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
+
+       sdhci_get_of_property(pdev);
+       mmc_of_parse(host->mmc);
+
+       /*
+        * Supply the existing CAPS, but clear the UHS modes. This
+        * will allow these modes to be specified by device tree
+        * properties through mmc_of_parse().
+        */
+       host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+       host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+       host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
+                       SDHCI_SUPPORT_DDR50);
+       host->quirks |= SDHCI_QUIRK_MISSING_CAPS |
+               SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+
+       res = sdhci_add_host(host);
+       if (res)
+               goto err;
+
+       pltfm_host = sdhci_priv(host);
+       pltfm_host->clk = clk;
+       return res;
+
+err:
+       sdhci_pltfm_free(pdev);
+err_clk:
+       clk_disable_unprepare(clk);
+       return res;
+}
+
+static const struct of_device_id sdhci_brcm_of_match[] = {
+       { .compatible = "brcm,bcm7425-sdhci" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
+
+static struct platform_driver sdhci_brcmstb_driver = {
+       .driver         = {
+               .name   = "sdhci-brcmstb",
+               .owner  = THIS_MODULE,
+               .pm     = &sdhci_brcmstb_pmops,
+               .of_match_table = of_match_ptr(sdhci_brcm_of_match),
+       },
+       .probe          = sdhci_brcmstb_probe,
+       .remove         = sdhci_pltfm_unregister,
+};
+
+module_platform_driver(sdhci_brcmstb_driver);
+
+MODULE_DESCRIPTION("SDHCI driver for Broadcom BRCMSTB SoCs");
+MODULE_AUTHOR("Broadcom");
+MODULE_LICENSE("GPL v2");
index 59f2923f80547d37f2dd5d8f43d3aeacb49854ce..bd286db7f9af54e8c0884a2c34b080e5e712e8d2 100644 (file)
@@ -101,7 +101,7 @@ static int sdhci_cns3xxx_probe(struct platform_device *pdev)
 static struct platform_driver sdhci_cns3xxx_driver = {
        .driver         = {
                .name   = "sdhci-cns3xxx",
-               .pm     = SDHCI_PLTFM_PMOPS,
+               .pm     = &sdhci_pltfm_pmops,
        },
        .probe          = sdhci_cns3xxx_probe,
        .remove         = sdhci_pltfm_unregister,
index 407c21f152b2dacad43706db77b8a2c5a97c08e8..de9f9603dbdcb21e848ccee5fe9e0093cdeb0da7 100644 (file)
@@ -117,7 +117,7 @@ MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table);
 static struct platform_driver sdhci_dove_driver = {
        .driver         = {
                .name   = "sdhci-dove",
-               .pm     = SDHCI_PLTFM_PMOPS,
+               .pm     = &sdhci_pltfm_pmops,
                .of_match_table = sdhci_dove_of_match_table,
        },
        .probe          = sdhci_dove_probe,
index 9d3ae1f4bd3cc799b6716355f19dbbbec2ceeda4..99e0b334f9dfad6345a8a23e47d5c183bc018a90 100644 (file)
 #define  ESDHC_VENDOR_SPEC_VSELECT     (1 << 1)
 #define  ESDHC_VENDOR_SPEC_FRC_SDCLK_ON        (1 << 8)
 #define ESDHC_WTMK_LVL                 0x44
+#define  ESDHC_WTMK_DEFAULT_VAL                0x10401040
 #define ESDHC_MIX_CTRL                 0x48
 #define  ESDHC_MIX_CTRL_DDREN          (1 << 3)
 #define  ESDHC_MIX_CTRL_AC23EN         (1 << 7)
 #define  ESDHC_MIX_CTRL_EXE_TUNE       (1 << 22)
 #define  ESDHC_MIX_CTRL_SMPCLK_SEL     (1 << 23)
+#define  ESDHC_MIX_CTRL_AUTO_TUNE_EN   (1 << 24)
 #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 */
@@ -75,7 +77,8 @@
 #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_START_TAP_DEFAULT 0x1
+#define ESDHC_TUNING_START_TAP_MASK    0xff
 #define ESDHC_TUNING_STEP_MASK         0x00070000
 #define ESDHC_TUNING_STEP_SHIFT                16
 
@@ -299,7 +302,8 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
                                /* imx6q/dl does not have cap_1 register, fake one */
                                val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
                                        | SDHCI_SUPPORT_SDR50
-                                       | SDHCI_USE_SDR50_TUNING;
+                                       | SDHCI_USE_SDR50_TUNING
+                                       | (SDHCI_TUNING_MODE_3 << SDHCI_RETUNING_MODE_SHIFT);
 
                        if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
                                val |= SDHCI_SUPPORT_HS400;
@@ -469,32 +473,29 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
                if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
                        new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
-                       if (val & SDHCI_CTRL_TUNED_CLK)
+                       if (val & SDHCI_CTRL_TUNED_CLK) {
                                new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL;
-                       else
+                               new_val |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
+                       } else {
                                new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+                               new_val &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
+                       }
                        writel(new_val , host->ioaddr + ESDHC_MIX_CTRL);
                } 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 {
                                v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
                                m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
+                               m &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
                        }
 
                        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 &= ~ESDHC_TUNING_STEP_MASK;
-                                       tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
-                               }
-                               writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL);
+                               m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
                        } else {
                                v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
                        }
@@ -751,6 +752,7 @@ static void esdhc_post_tuning(struct sdhci_host *host)
 
        reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
        reg &= ~ESDHC_MIX_CTRL_EXE_TUNE;
+       reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
        writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
 }
 
@@ -838,6 +840,11 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
        u32 v;
 
        if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) {
+               /* disable clock before enabling strobe dll */
+               writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
+                      ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
+                      host->ioaddr + ESDHC_VENDOR_SPEC);
+
                /* force a reset on strobe dll */
                writel(ESDHC_STROBE_DLL_CTRL_RESET,
                        host->ioaddr + ESDHC_STROBE_DLL_CTRL);
@@ -899,6 +906,8 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
                m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
                writel(m, host->ioaddr + ESDHC_MIX_CTRL);
                imx_data->is_ddr = 1;
+               /* update clock after enable DDR for strobe DLL lock */
+               host->ops->set_clock(host, host->clock);
                esdhc_set_strobe_dll(host);
                break;
        }
@@ -957,6 +966,62 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
        .ops = &sdhci_esdhc_ops,
 };
 
+static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+       int tmp;
+
+       if (esdhc_is_usdhc(imx_data)) {
+               /*
+                * The imx6q ROM code will change the default watermark
+                * level setting to something insane.  Change it back here.
+                */
+               writel(ESDHC_WTMK_DEFAULT_VAL, host->ioaddr + ESDHC_WTMK_LVL);
+
+               /*
+                * 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);
+               /*
+               * errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
+               * TO1.1, it's harmless for MX6SL
+               */
+               writel(readl(host->ioaddr + 0x6c) | BIT(7),
+                       host->ioaddr + 0x6c);
+
+               /* disable DLL_CTRL delay line settings */
+               writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
+
+               if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
+                       tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
+                       tmp |= ESDHC_STD_TUNING_EN |
+                               ESDHC_TUNING_START_TAP_DEFAULT;
+                       if (imx_data->boarddata.tuning_start_tap) {
+                               tmp &= ~ESDHC_TUNING_START_TAP_MASK;
+                               tmp |= imx_data->boarddata.tuning_start_tap;
+                       }
+
+                       if (imx_data->boarddata.tuning_step) {
+                               tmp &= ~ESDHC_TUNING_STEP_MASK;
+                               tmp |= imx_data->boarddata.tuning_step
+                                       << ESDHC_TUNING_STEP_SHIFT;
+                       }
+                       writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
+               }
+       }
+}
+
 #ifdef CONFIG_OF
 static int
 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
@@ -975,6 +1040,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
                boarddata->wp_type = ESDHC_WP_GPIO;
 
        of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
+       of_property_read_u32(np, "fsl,tuning-start-tap",
+                            &boarddata->tuning_start_tap);
 
        if (of_find_property(np, "no-1-8-v", NULL))
                boarddata->support_vsel = false;
@@ -1147,58 +1214,27 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
        if (IS_ERR(imx_data->pins_default))
                dev_warn(mmc_dev(host->mmc), "could not get default state\n");
 
-       host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
-
        if (imx_data->socdata->flags & ESDHC_FLAG_ENGCM07207)
                /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
                host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
                        | SDHCI_QUIRK_BROKEN_ADMA;
 
-       /*
-        * The imx6q ROM code will change the default watermark level setting
-        * to something insane.  Change it back here.
-        */
        if (esdhc_is_usdhc(imx_data)) {
-               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;
 
-               /*
-               * errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
-               * TO1.1, it's harmless for MX6SL
-               */
-               writel(readl(host->ioaddr + 0x6c) | BIT(7),
-                       host->ioaddr + 0x6c);
+               /* clear tuning bits in case ROM has set it already */
+               writel(0x0, host->ioaddr + ESDHC_MIX_CTRL);
+               writel(0x0, host->ioaddr + SDHCI_ACMD12_ERR);
+               writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
        }
 
        if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
                sdhci_esdhc_ops.platform_execute_tuning =
                                        esdhc_executing_tuning;
 
-       if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
-               writel(readl(host->ioaddr + ESDHC_TUNING_CTRL) |
-                       ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP,
-                       host->ioaddr + ESDHC_TUNING_CTRL);
-
        if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
                host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
 
@@ -1212,6 +1248,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
        if (err)
                goto disable_clk;
 
+       sdhci_esdhc_imx_hwinit(host);
+
        err = sdhci_add_host(host);
        if (err)
                goto disable_clk;
@@ -1255,6 +1293,25 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int sdhci_esdhc_suspend(struct device *dev)
+{
+       struct sdhci_host *host = dev_get_drvdata(dev);
+
+       return sdhci_suspend_host(host);
+}
+
+static int sdhci_esdhc_resume(struct device *dev)
+{
+       struct sdhci_host *host = dev_get_drvdata(dev);
+
+       /* re-initialize hw state in case it's lost in low power mode */
+       sdhci_esdhc_imx_hwinit(host);
+
+       return sdhci_resume_host(host);
+}
+#endif
+
 #ifdef CONFIG_PM
 static int sdhci_esdhc_runtime_suspend(struct device *dev)
 {
@@ -1291,7 +1348,7 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
 #endif
 
 static const struct dev_pm_ops sdhci_esdhc_pmops = {
-       SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_pltfm_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume)
        SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
                                sdhci_esdhc_runtime_resume, NULL)
 };
index 1110f73b08aa6334b931373e402896a038df8c0a..72624666585008866dfea479b74112a642dd9059 100644 (file)
@@ -164,8 +164,17 @@ static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = {
 
 static const struct sdhci_iproc_data iproc_data = {
        .pdata = &sdhci_iproc_pltfm_data,
-       .caps = 0x05E90000,
-       .caps1 = 0x00000064,
+       .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT)
+                       & SDHCI_MAX_BLOCK_MASK) |
+               SDHCI_CAN_VDD_330 |
+               SDHCI_CAN_VDD_180 |
+               SDHCI_CAN_DO_SUSPEND |
+               SDHCI_CAN_DO_HISPD |
+               SDHCI_CAN_DO_ADMA2 |
+               SDHCI_CAN_DO_SDMA,
+       .caps1 = SDHCI_DRIVER_TYPE_C |
+                SDHCI_DRIVER_TYPE_D |
+                SDHCI_SUPPORT_DDR50,
        .mmc_caps = MMC_CAP_1_8V_DDR,
 };
 
@@ -251,7 +260,7 @@ static struct platform_driver sdhci_iproc_driver = {
        .driver = {
                .name = "sdhci-iproc",
                .of_match_table = sdhci_iproc_of_match,
-               .pm = SDHCI_PLTFM_PMOPS,
+               .pm = &sdhci_pltfm_pmops,
        },
        .probe = sdhci_iproc_probe,
        .remove = sdhci_pltfm_unregister,
index 0653fe730150cab10d08a90dc953b3546f5cb08a..8ef44a2a2fd94b6572e0cc5feda1efd0b698f7a6 100644 (file)
 #define CORE_POWER             0x0
 #define CORE_SW_RST            BIT(7)
 
+#define CORE_PWRCTL_STATUS     0xdc
+#define CORE_PWRCTL_MASK       0xe0
+#define CORE_PWRCTL_CLEAR      0xe4
+#define CORE_PWRCTL_CTL                0xe8
+#define CORE_PWRCTL_BUS_OFF    BIT(0)
+#define CORE_PWRCTL_BUS_ON     BIT(1)
+#define CORE_PWRCTL_IO_LOW     BIT(2)
+#define CORE_PWRCTL_IO_HIGH    BIT(3)
+#define CORE_PWRCTL_BUS_SUCCESS BIT(0)
+#define CORE_PWRCTL_IO_SUCCESS BIT(2)
+#define REQ_BUS_OFF            BIT(0)
+#define REQ_BUS_ON             BIT(1)
+#define REQ_IO_LOW             BIT(2)
+#define REQ_IO_HIGH            BIT(3)
+#define INT_MASK               0xf
 #define MAX_PHASES             16
 #define CORE_DLL_LOCK          BIT(7)
 #define CORE_DLL_EN            BIT(16)
@@ -56,6 +71,7 @@
 struct sdhci_msm_host {
        struct platform_device *pdev;
        void __iomem *core_mem; /* MSM SDCC mapped address */
+       int pwr_irq;            /* power irq */
        struct clk *clk;        /* main SD/MMC bus clock */
        struct clk *pclk;       /* SDHC peripheral bus clock */
        struct clk *bus_clk;    /* SDHC bus voter clock */
@@ -410,6 +426,85 @@ retry:
        return rc;
 }
 
+static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
+                                       unsigned int uhs)
+{
+       struct mmc_host *mmc = host->mmc;
+       u16 ctrl_2;
+
+       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       /* Select Bus Speed Mode for host */
+       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+       switch (uhs) {
+       case MMC_TIMING_UHS_SDR12:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+               break;
+       case MMC_TIMING_UHS_SDR25:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+               break;
+       case MMC_TIMING_UHS_SDR50:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+               break;
+       case MMC_TIMING_MMC_HS200:
+       case MMC_TIMING_UHS_SDR104:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+               break;
+       case MMC_TIMING_UHS_DDR50:
+       case MMC_TIMING_MMC_DDR52:
+               ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+               break;
+       }
+
+       /*
+        * When clock frequency is less than 100MHz, the feedback clock must be
+        * provided and DLL must not be used so that tuning can be skipped. To
+        * provide feedback clock, the mode selection can be any value less
+        * than 3'b011 in bits [2:0] of HOST CONTROL2 register.
+        */
+       if (host->clock <= 100000000 &&
+           (uhs == MMC_TIMING_MMC_HS400 ||
+            uhs == MMC_TIMING_MMC_HS200 ||
+            uhs == MMC_TIMING_UHS_SDR104))
+               ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+
+       dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n",
+               mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
+       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+
+static void sdhci_msm_voltage_switch(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       u32 irq_status, irq_ack = 0;
+
+       irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+       irq_status &= INT_MASK;
+
+       writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
+
+       if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
+               irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+       if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
+               irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+
+       /*
+        * The driver has to acknowledge the interrupt, switch voltages and
+        * report back if it succeded or not to this register. The voltage
+        * switches are handled by the sdhci core, so just report success.
+        */
+       writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
+}
+
+static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
+{
+       struct sdhci_host *host = (struct sdhci_host *)data;
+
+       sdhci_msm_voltage_switch(host);
+
+       return IRQ_HANDLED;
+}
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
        { .compatible = "qcom,sdhci-msm-v4" },
        {},
@@ -422,11 +517,13 @@ static const struct sdhci_ops sdhci_msm_ops = {
        .reset = sdhci_reset,
        .set_clock = sdhci_set_clock,
        .set_bus_width = sdhci_set_bus_width,
-       .set_uhs_signaling = sdhci_set_uhs_signaling,
+       .set_uhs_signaling = sdhci_msm_set_uhs_signaling,
+       .voltage_switch = sdhci_msm_voltage_switch,
 };
 
 static const struct sdhci_pltfm_data sdhci_msm_pdata = {
        .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+                 SDHCI_QUIRK_NO_CARD_NO_RESET |
                  SDHCI_QUIRK_SINGLE_POWER_WRITE,
        .ops = &sdhci_msm_ops,
 };
@@ -473,7 +570,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        msm_host->pclk = devm_clk_get(&pdev->dev, "iface");
        if (IS_ERR(msm_host->pclk)) {
                ret = PTR_ERR(msm_host->pclk);
-               dev_err(&pdev->dev, "Perpheral clk setup failed (%d)\n", ret);
+               dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret);
                goto bus_clk_disable;
        }
 
@@ -545,6 +642,22 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                               CORE_VENDOR_SPEC_CAPABILITIES0);
        }
 
+       /* Setup IRQ for handling power/voltage tasks with PMIC */
+       msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
+       if (msm_host->pwr_irq < 0) {
+               dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n",
+                       msm_host->pwr_irq);
+               goto clk_disable;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
+                                       sdhci_msm_pwr_irq, IRQF_ONESHOT,
+                                       dev_name(&pdev->dev), host);
+       if (ret) {
+               dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret);
+               goto clk_disable;
+       }
+
        ret = sdhci_add_host(host);
        if (ret)
                goto clk_disable;
index b6f4c1d4163624ac5e38dc2caa3e525b8d83d011..e0f193f7e3e50c9f41efe074da079895199b6ca8 100644 (file)
  * your option) any later version.
  */
 
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/phy/phy.h>
+#include <linux/regmap.h>
 #include "sdhci-pltfm.h"
 
 #define SDHCI_ARASAN_CLK_CTRL_OFFSET   0x2c
+#define SDHCI_ARASAN_VENDOR_REGISTER   0x78
 
+#define VENDOR_ENHANCED_STROBE         BIT(0)
 #define CLK_CTRL_TIMEOUT_SHIFT         16
 #define CLK_CTRL_TIMEOUT_MASK          (0xf << CLK_CTRL_TIMEOUT_SHIFT)
 #define CLK_CTRL_TIMEOUT_MIN_EXP       13
 
+/*
+ * On some SoCs the syscon area has a feature where the upper 16-bits of
+ * each 32-bit register act as a write mask for the lower 16-bits.  This allows
+ * atomic updates of the register without locking.  This macro is used on SoCs
+ * that have that feature.
+ */
+#define HIWORD_UPDATE(val, mask, shift) \
+               ((val) << (shift) | (mask) << ((shift) + 16))
+
+/**
+ * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map
+ *
+ * @reg:       Offset within the syscon of the register containing this field
+ * @width:     Number of bits for this field
+ * @shift:     Bit offset within @reg of this field (or -1 if not avail)
+ */
+struct sdhci_arasan_soc_ctl_field {
+       u32 reg;
+       u16 width;
+       s16 shift;
+};
+
+/**
+ * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers
+ *
+ * It's up to the licensee of the Arsan IP block to make these available
+ * somewhere if needed.  Presumably these will be scattered somewhere that's
+ * accessible via the syscon API.
+ *
+ * @baseclkfreq:       Where to find corecfg_baseclkfreq
+ * @hiword_update:     If true, use HIWORD_UPDATE to access the syscon
+ */
+struct sdhci_arasan_soc_ctl_map {
+       struct sdhci_arasan_soc_ctl_field       baseclkfreq;
+       bool                                    hiword_update;
+};
+
 /**
  * struct sdhci_arasan_data
- * @clk_ahb:   Pointer to the AHB clock
- * @phy: Pointer to the generic phy
+ * @host:              Pointer to the main SDHCI host structure.
+ * @clk_ahb:           Pointer to the AHB clock
+ * @phy:               Pointer to the generic phy
+ * @sdcardclk_hw:      Struct for the clock we might provide to a PHY.
+ * @sdcardclk:         Pointer to normal 'struct clock' for sdcardclk_hw.
+ * @soc_ctl_base:      Pointer to regmap for syscon for soc_ctl registers.
+ * @soc_ctl_map:       Map to get offsets into soc_ctl registers.
  */
 struct sdhci_arasan_data {
+       struct sdhci_host *host;
        struct clk      *clk_ahb;
        struct phy      *phy;
+
+       struct clk_hw   sdcardclk_hw;
+       struct clk      *sdcardclk;
+
+       struct regmap   *soc_ctl_base;
+       const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
+};
+
+static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
+       .baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 },
+       .hiword_update = true,
 };
 
+/**
+ * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers
+ *
+ * This function allows writing to fields in sdhci_arasan_soc_ctl_map.
+ * Note that if a field is specified as not available (shift < 0) then
+ * this function will silently return an error code.  It will be noisy
+ * and print errors for any other (unexpected) errors.
+ *
+ * @host:      The sdhci_host
+ * @fld:       The field to write to
+ * @val:       The value to write
+ */
+static int sdhci_arasan_syscon_write(struct sdhci_host *host,
+                                  const struct sdhci_arasan_soc_ctl_field *fld,
+                                  u32 val)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
+       struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base;
+       u32 reg = fld->reg;
+       u16 width = fld->width;
+       s16 shift = fld->shift;
+       int ret;
+
+       /*
+        * Silently return errors for shift < 0 so caller doesn't have
+        * to check for fields which are optional.  For fields that
+        * are required then caller needs to do something special
+        * anyway.
+        */
+       if (shift < 0)
+               return -EINVAL;
+
+       if (sdhci_arasan->soc_ctl_map->hiword_update)
+               ret = regmap_write(soc_ctl_base, reg,
+                                  HIWORD_UPDATE(val, GENMASK(width, 0),
+                                                shift));
+       else
+               ret = regmap_update_bits(soc_ctl_base, reg,
+                                        GENMASK(shift + width, shift),
+                                        val << shift);
+
+       /* Yell about (unexpected) regmap errors */
+       if (ret)
+               pr_warn("%s: Regmap write fail: %d\n",
+                        mmc_hostname(host->mmc), ret);
+
+       return ret;
+}
+
 static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
 {
        u32 div;
@@ -79,6 +188,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
        }
 }
 
+static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
+                                       struct mmc_ios *ios)
+{
+       u32 vendor;
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
+       if (ios->enhanced_strobe)
+               vendor |= VENDOR_ENHANCED_STROBE;
+       else
+               vendor &= ~VENDOR_ENHANCED_STROBE;
+
+       writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
+}
+
 static struct sdhci_ops sdhci_arasan_ops = {
        .set_clock = sdhci_arasan_set_clock,
        .get_max_clock = sdhci_pltfm_clk_get_max_clock,
@@ -172,9 +296,168 @@ static int sdhci_arasan_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
                         sdhci_arasan_resume);
 
+static const struct of_device_id sdhci_arasan_of_match[] = {
+       /* SoC-specific compatible strings w/ soc_ctl_map */
+       {
+               .compatible = "rockchip,rk3399-sdhci-5.1",
+               .data = &rk3399_soc_ctl_map,
+       },
+
+       /* Generic compatible below here */
+       { .compatible = "arasan,sdhci-8.9a" },
+       { .compatible = "arasan,sdhci-5.1" },
+       { .compatible = "arasan,sdhci-4.9a" },
+
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
+
+/**
+ * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate
+ *
+ * Return the current actual rate of the SD card clock.  This can be used
+ * to communicate with out PHY.
+ *
+ * @hw:                        Pointer to the hardware clock structure.
+ * @parent_rate                The parent rate (should be rate of clk_xin).
+ * Returns the card clock rate.
+ */
+static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw,
+                                                     unsigned long parent_rate)
+
+{
+       struct sdhci_arasan_data *sdhci_arasan =
+               container_of(hw, struct sdhci_arasan_data, sdcardclk_hw);
+       struct sdhci_host *host = sdhci_arasan->host;
+
+       return host->mmc->actual_clock;
+}
+
+static const struct clk_ops arasan_sdcardclk_ops = {
+       .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
+};
+
+/**
+ * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq
+ *
+ * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin.  This
+ * function can be used to make that happen.
+ *
+ * NOTES:
+ * - Many existing devices don't seem to do this and work fine.  To keep
+ *   compatibility for old hardware where the device tree doesn't provide a
+ *   register map, this function is a noop if a soc_ctl_map hasn't been provided
+ *   for this platform.
+ * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider
+ *   to achieve lower clock rates.  That means that this function is called once
+ *   at probe time and never called again.
+ *
+ * @host:              The sdhci_host
+ */
+static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
+       const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
+               sdhci_arasan->soc_ctl_map;
+       u32 mhz = DIV_ROUND_CLOSEST(clk_get_rate(pltfm_host->clk), 1000000);
+
+       /* Having a map is optional */
+       if (!soc_ctl_map)
+               return;
+
+       /* If we have a map, we expect to have a syscon */
+       if (!sdhci_arasan->soc_ctl_base) {
+               pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
+                       mmc_hostname(host->mmc));
+               return;
+       }
+
+       sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz);
+}
+
+/**
+ * sdhci_arasan_register_sdclk - Register the sdclk for a PHY to use
+ *
+ * Some PHY devices need to know what the actual card clock is.  In order for
+ * them to find out, we'll provide a clock through the common clock framework
+ * for them to query.
+ *
+ * Note: without seriously re-architecting SDHCI's clock code and testing on
+ * all platforms, there's no way to create a totally beautiful clock here
+ * with all clock ops implemented.  Instead, we'll just create a clock that can
+ * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock
+ * framework that we're doing things behind its back.  This should be sufficient
+ * to create nice clean device tree bindings and later (if needed) we can try
+ * re-architecting SDHCI if we see some benefit to it.
+ *
+ * @sdhci_arasan:      Our private data structure.
+ * @clk_xin:           Pointer to the functional clock
+ * @dev:               Pointer to our struct device.
+ * Returns 0 on success and error value on error
+ */
+static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan,
+                                      struct clk *clk_xin,
+                                      struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct clk_init_data sdcardclk_init;
+       const char *parent_clk_name;
+       int ret;
+
+       /* Providing a clock to the PHY is optional; no error if missing */
+       if (!of_find_property(np, "#clock-cells", NULL))
+               return 0;
+
+       ret = of_property_read_string_index(np, "clock-output-names", 0,
+                                           &sdcardclk_init.name);
+       if (ret) {
+               dev_err(dev, "DT has #clock-cells but no clock-output-names\n");
+               return ret;
+       }
+
+       parent_clk_name = __clk_get_name(clk_xin);
+       sdcardclk_init.parent_names = &parent_clk_name;
+       sdcardclk_init.num_parents = 1;
+       sdcardclk_init.flags = CLK_GET_RATE_NOCACHE;
+       sdcardclk_init.ops = &arasan_sdcardclk_ops;
+
+       sdhci_arasan->sdcardclk_hw.init = &sdcardclk_init;
+       sdhci_arasan->sdcardclk =
+               devm_clk_register(dev, &sdhci_arasan->sdcardclk_hw);
+       sdhci_arasan->sdcardclk_hw.init = NULL;
+
+       ret = of_clk_add_provider(np, of_clk_src_simple_get,
+                                 sdhci_arasan->sdcardclk);
+       if (ret)
+               dev_err(dev, "Failed to add clock provider\n");
+
+       return ret;
+}
+
+/**
+ * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk()
+ *
+ * Should be called any time we're exiting and sdhci_arasan_register_sdclk()
+ * returned success.
+ *
+ * @dev:               Pointer to our struct device.
+ */
+static void sdhci_arasan_unregister_sdclk(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+
+       if (!of_find_property(np, "#clock-cells", NULL))
+               return;
+
+       of_clk_del_provider(dev->of_node);
+}
+
 static int sdhci_arasan_probe(struct platform_device *pdev)
 {
        int ret;
+       const struct of_device_id *match;
+       struct device_node *node;
        struct clk *clk_xin;
        struct sdhci_host *host;
        struct sdhci_pltfm_host *pltfm_host;
@@ -187,6 +470,24 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
 
        pltfm_host = sdhci_priv(host);
        sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
+       sdhci_arasan->host = host;
+
+       match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node);
+       sdhci_arasan->soc_ctl_map = match->data;
+
+       node = of_parse_phandle(pdev->dev.of_node, "arasan,soc-ctl-syscon", 0);
+       if (node) {
+               sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node);
+               of_node_put(node);
+
+               if (IS_ERR(sdhci_arasan->soc_ctl_base)) {
+                       ret = PTR_ERR(sdhci_arasan->soc_ctl_base);
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(&pdev->dev, "Can't get syscon: %d\n",
+                                       ret);
+                       goto err_pltfm_free;
+               }
+       }
 
        sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb");
        if (IS_ERR(sdhci_arasan->clk_ahb)) {
@@ -217,10 +518,16 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
        sdhci_get_of_property(pdev);
        pltfm_host->clk = clk_xin;
 
+       sdhci_arasan_update_baseclkfreq(host);
+
+       ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, &pdev->dev);
+       if (ret)
+               goto clk_disable_all;
+
        ret = mmc_of_parse(host->mmc);
        if (ret) {
                dev_err(&pdev->dev, "parsing dt failed (%u)\n", ret);
-               goto clk_disable_all;
+               goto unreg_clk;
        }
 
        sdhci_arasan->phy = ERR_PTR(-ENODEV);
@@ -231,13 +538,13 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
                if (IS_ERR(sdhci_arasan->phy)) {
                        ret = PTR_ERR(sdhci_arasan->phy);
                        dev_err(&pdev->dev, "No phy for arasan,sdhci-5.1.\n");
-                       goto clk_disable_all;
+                       goto unreg_clk;
                }
 
                ret = phy_init(sdhci_arasan->phy);
                if (ret < 0) {
                        dev_err(&pdev->dev, "phy_init err.\n");
-                       goto clk_disable_all;
+                       goto unreg_clk;
                }
 
                ret = phy_power_on(sdhci_arasan->phy);
@@ -245,6 +552,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "phy_power_on err.\n");
                        goto err_phy_power;
                }
+
+               host->mmc_host_ops.hs400_enhanced_strobe =
+                                       sdhci_arasan_hs400_enhanced_strobe;
        }
 
        ret = sdhci_add_host(host);
@@ -259,6 +569,8 @@ err_add_host:
 err_phy_power:
        if (!IS_ERR(sdhci_arasan->phy))
                phy_exit(sdhci_arasan->phy);
+unreg_clk:
+       sdhci_arasan_unregister_sdclk(&pdev->dev);
 clk_disable_all:
        clk_disable_unprepare(clk_xin);
 clk_dis_ahb:
@@ -281,6 +593,8 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
                phy_exit(sdhci_arasan->phy);
        }
 
+       sdhci_arasan_unregister_sdclk(&pdev->dev);
+
        ret = sdhci_pltfm_unregister(pdev);
 
        clk_disable_unprepare(clk_ahb);
@@ -288,14 +602,6 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
        return ret;
 }
 
-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" },
-       { }
-};
-MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
-
 static struct platform_driver sdhci_arasan_driver = {
        .driver = {
                .name = "sdhci-arasan",
index d4cef713d246451c9187af6f314f2183db2a9353..a9b7fc06c434326a05c77dfc2e4f6cce32317d30 100644 (file)
@@ -288,7 +288,7 @@ static int sdhci_at91_probe(struct platform_device *pdev)
         * Disable SDHCI_QUIRK_BROKEN_CARD_DETECTION to be sure nobody tries
         * to enable polling via device tree with broken-cd property.
         */
-       if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) &&
+       if (mmc_card_is_removable(host->mmc) &&
            mmc_gpio_get_cd(host->mmc) < 0) {
                host->mmc->caps |= MMC_CAP_NEEDS_POLL;
                host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
index 3f34d354f1fc2720b70c5527c1be695d68734de1..239be2fde242fdfc6e0d7607d22fb9aa6c50de88 100644 (file)
@@ -481,7 +481,7 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
        sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static u32 esdhc_proctl;
 static int esdhc_of_suspend(struct device *dev)
 {
@@ -504,16 +504,12 @@ static int esdhc_of_resume(struct device *dev)
        }
        return ret;
 }
-
-static const struct dev_pm_ops esdhc_pmops = {
-       .suspend        = esdhc_of_suspend,
-       .resume         = esdhc_of_resume,
-};
-#define ESDHC_PMOPS (&esdhc_pmops)
-#else
-#define ESDHC_PMOPS NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops,
+                       esdhc_of_suspend,
+                       esdhc_of_resume);
+
 static const struct sdhci_ops sdhci_esdhc_be_ops = {
        .read_l = esdhc_be_readl,
        .read_w = esdhc_be_readw,
@@ -657,7 +653,7 @@ static struct platform_driver sdhci_esdhc_driver = {
        .driver = {
                .name = "sdhci-esdhc",
                .of_match_table = sdhci_esdhc_of_match,
-               .pm = ESDHC_PMOPS,
+               .pm = &esdhc_of_dev_pm_ops,
        },
        .probe = sdhci_esdhc_probe,
        .remove = sdhci_pltfm_unregister,
index 4079a96ad37e46e23522e11682f232191c50613d..ac00c5efb2a3279cf56c01b67bdbd7736d67e2e4 100644 (file)
@@ -85,7 +85,7 @@ static struct platform_driver sdhci_hlwd_driver = {
        .driver = {
                .name = "sdhci-hlwd",
                .of_match_table = sdhci_hlwd_of_match,
-               .pm = SDHCI_PLTFM_PMOPS,
+               .pm = &sdhci_pltfm_pmops,
        },
        .probe = sdhci_hlwd_probe,
        .remove = sdhci_pltfm_unregister,
index a4dbf7421edc7f9342a18fa7f19cb033d05a0fa8..897cfd24ca2e834c16906fcc2442e5a37bb581e9 100644 (file)
@@ -419,13 +419,13 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
 };
 
 /* Define Host controllers for Intel Merrifield platform */
-#define INTEL_MRFL_EMMC_0      0
-#define INTEL_MRFL_EMMC_1      1
+#define INTEL_MRFLD_EMMC_0     0
+#define INTEL_MRFLD_EMMC_1     1
 
-static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot)
+static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot)
 {
-       if ((PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_0) &&
-           (PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_1))
+       if ((PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFLD_EMMC_0) &&
+           (PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFLD_EMMC_1))
                /* SD support is not ready yet */
                return -ENODEV;
 
@@ -435,12 +435,12 @@ static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot)
        return 0;
 }
 
-static const struct sdhci_pci_fixes sdhci_intel_mrfl_mmc = {
+static const struct sdhci_pci_fixes sdhci_intel_mrfld_mmc = {
        .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .quirks2        = SDHCI_QUIRK2_BROKEN_HS200 |
                        SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
        .allow_runtime_pm = true,
-       .probe_slot     = intel_mrfl_mmc_probe_slot,
+       .probe_slot     = intel_mrfld_mmc_probe_slot,
 };
 
 /* O2Micro extra registers */
@@ -1104,10 +1104,10 @@ static const struct pci_device_id pci_ids[] = {
 
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_MRFL_MMC,
+               .device         = PCI_DEVICE_ID_INTEL_MRFLD_MMC,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
-               .driver_data    = (kernel_ulong_t)&sdhci_intel_mrfl_mmc,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mrfld_mmc,
        },
 
        {
@@ -1413,8 +1413,7 @@ static const struct sdhci_ops sdhci_pci_ops = {
  *                                                                           *
 \*****************************************************************************/
 
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
 static int sdhci_pci_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -1496,7 +1495,9 @@ static int sdhci_pci_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
+#ifdef CONFIG_PM
 static int sdhci_pci_runtime_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -1562,17 +1563,10 @@ static int sdhci_pci_runtime_resume(struct device *dev)
 
        return 0;
 }
-
-#else /* CONFIG_PM */
-
-#define sdhci_pci_suspend NULL
-#define sdhci_pci_resume NULL
-
-#endif /* CONFIG_PM */
+#endif
 
 static const struct dev_pm_ops sdhci_pci_pm_ops = {
-       .suspend = sdhci_pci_suspend,
-       .resume = sdhci_pci_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(sdhci_pci_suspend, sdhci_pci_resume)
        SET_RUNTIME_PM_OPS(sdhci_pci_runtime_suspend,
                        sdhci_pci_runtime_resume, NULL)
 };
@@ -1760,11 +1754,12 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
 
 static void sdhci_pci_runtime_pm_allow(struct device *dev)
 {
-       pm_runtime_put_noidle(dev);
-       pm_runtime_allow(dev);
+       pm_suspend_ignore_children(dev, 1);
        pm_runtime_set_autosuspend_delay(dev, 50);
        pm_runtime_use_autosuspend(dev);
-       pm_suspend_ignore_children(dev, 1);
+       pm_runtime_allow(dev);
+       /* Stay active until mmc core scans for a card */
+       pm_runtime_put_noidle(dev);
 }
 
 static void sdhci_pci_runtime_pm_forbid(struct device *dev)
@@ -1810,15 +1805,13 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
                return -ENODEV;
        }
 
-       ret = pci_enable_device(pdev);
+       ret = pcim_enable_device(pdev);
        if (ret)
                return ret;
 
-       chip = kzalloc(sizeof(struct sdhci_pci_chip), GFP_KERNEL);
-       if (!chip) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
 
        chip->pdev = pdev;
        chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
@@ -1834,7 +1827,7 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
        if (chip->fixes && chip->fixes->probe) {
                ret = chip->fixes->probe(chip);
                if (ret)
-                       goto free;
+                       return ret;
        }
 
        slots = chip->num_slots;        /* Quirk may have changed this */
@@ -1844,8 +1837,7 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
                if (IS_ERR(slot)) {
                        for (i--; i >= 0; i--)
                                sdhci_pci_remove_slot(chip->slots[i]);
-                       ret = PTR_ERR(slot);
-                       goto free;
+                       return PTR_ERR(slot);
                }
 
                chip->slots[i] = slot;
@@ -1855,35 +1847,18 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
                sdhci_pci_runtime_pm_allow(&pdev->dev);
 
        return 0;
-
-free:
-       pci_set_drvdata(pdev, NULL);
-       kfree(chip);
-
-err:
-       pci_disable_device(pdev);
-       return ret;
 }
 
 static void sdhci_pci_remove(struct pci_dev *pdev)
 {
        int i;
-       struct sdhci_pci_chip *chip;
+       struct sdhci_pci_chip *chip = pci_get_drvdata(pdev);
 
-       chip = pci_get_drvdata(pdev);
-
-       if (chip) {
-               if (chip->allow_runtime_pm)
-                       sdhci_pci_runtime_pm_forbid(&pdev->dev);
-
-               for (i = 0; i < chip->num_slots; i++)
-                       sdhci_pci_remove_slot(chip->slots[i]);
-
-               pci_set_drvdata(pdev, NULL);
-               kfree(chip);
-       }
+       if (chip->allow_runtime_pm)
+               sdhci_pci_runtime_pm_forbid(&pdev->dev);
 
-       pci_disable_device(pdev);
+       for (i = 0; i < chip->num_slots; i++)
+               sdhci_pci_remove_slot(chip->slots[i]);
 }
 
 static struct pci_driver sdhci_driver = {
index 89e7151684a1fea26c35f27fee1c5ae2332e4eb8..7e0788712e1a1668e4cf8d5cbda1d2a6ee982f6a 100644 (file)
@@ -14,7 +14,7 @@
 #define PCI_DEVICE_ID_INTEL_BSW_EMMC   0x2294
 #define PCI_DEVICE_ID_INTEL_BSW_SDIO   0x2295
 #define PCI_DEVICE_ID_INTEL_BSW_SD     0x2296
-#define PCI_DEVICE_ID_INTEL_MRFL_MMC   0x1190
+#define PCI_DEVICE_ID_INTEL_MRFLD_MMC  0x1190
 #define PCI_DEVICE_ID_INTEL_CLV_SDIO0  0x08f9
 #define PCI_DEVICE_ID_INTEL_CLV_SDIO1  0x08fa
 #define PCI_DEVICE_ID_INTEL_CLV_SDIO2  0x08fb
index 64f287a03cd34a38aa3c66cb25e26cd2cab7b4f4..1d17dcfc3ffb59913f0f59ae5a880dbd9e0947d6 100644 (file)
@@ -215,29 +215,26 @@ int sdhci_pltfm_unregister(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister);
 
-#ifdef CONFIG_PM
-int sdhci_pltfm_suspend(struct device *dev)
+#ifdef CONFIG_PM_SLEEP
+static int sdhci_pltfm_suspend(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
 
        return sdhci_suspend_host(host);
 }
-EXPORT_SYMBOL_GPL(sdhci_pltfm_suspend);
 
-int sdhci_pltfm_resume(struct device *dev)
+static int sdhci_pltfm_resume(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
 
        return sdhci_resume_host(host);
 }
-EXPORT_SYMBOL_GPL(sdhci_pltfm_resume);
+#endif
 
 const struct dev_pm_ops sdhci_pltfm_pmops = {
-       .suspend        = sdhci_pltfm_suspend,
-       .resume         = sdhci_pltfm_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_pltfm_resume)
 };
 EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
-#endif /* CONFIG_PM */
 
 static int __init sdhci_pltfm_drv_init(void)
 {
index d38053bf9e4da46113d9a64918511bcd0af8f54c..3280f207795939138ff5ec0d2689184e0f48f172 100644 (file)
@@ -109,13 +109,6 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
        return (void *)host->private;
 }
 
-#ifdef CONFIG_PM
-extern int sdhci_pltfm_suspend(struct device *dev);
-extern int sdhci_pltfm_resume(struct device *dev);
 extern const struct dev_pm_ops sdhci_pltfm_pmops;
-#define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
-#else
-#define SDHCI_PLTFM_PMOPS NULL
-#endif
 
 #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
index 1d8dd35406361bd3aa5cdf85928d41227b21f714..347eae2d7b6a7b5d05acee8a66fd85cb14c45735 100644 (file)
@@ -252,7 +252,7 @@ static struct platform_driver sdhci_pxav2_driver = {
        .driver         = {
                .name   = "sdhci-pxav2",
                .of_match_table = of_match_ptr(sdhci_pxav2_of_match),
-               .pm     = SDHCI_PLTFM_PMOPS,
+               .pm     = &sdhci_pltfm_pmops,
        },
        .probe          = sdhci_pxav2_probe,
        .remove         = sdhci_pxav2_remove,
index 30132500aa1c83aec0c501354d7b9fb4c1fae1a7..dd1938d341f7ae2af1de80bfa4f39678b865441d 100644 (file)
@@ -583,24 +583,17 @@ static int sdhci_pxav3_runtime_resume(struct device *dev)
 }
 #endif
 
-#ifdef CONFIG_PM
 static const struct dev_pm_ops sdhci_pxav3_pmops = {
        SET_SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume)
        SET_RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend,
                sdhci_pxav3_runtime_resume, NULL)
 };
 
-#define SDHCI_PXAV3_PMOPS (&sdhci_pxav3_pmops)
-
-#else
-#define SDHCI_PXAV3_PMOPS NULL
-#endif
-
 static struct platform_driver sdhci_pxav3_driver = {
        .driver         = {
                .name   = "sdhci-pxav3",
                .of_match_table = of_match_ptr(sdhci_pxav3_of_match),
-               .pm     = SDHCI_PXAV3_PMOPS,
+               .pm     = &sdhci_pxav3_pmops,
        },
        .probe          = sdhci_pxav3_probe,
        .remove         = sdhci_pxav3_remove,
index 70c724bc6fc7844a9e559e72a0a74f7d33d60e66..784c5a848fb4fb9e7f4581cfce5e8aac6e04aa83 100644 (file)
@@ -714,19 +714,12 @@ static int sdhci_s3c_runtime_resume(struct device *dev)
 }
 #endif
 
-#ifdef CONFIG_PM
 static const struct dev_pm_ops sdhci_s3c_pmops = {
        SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume)
        SET_RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume,
                           NULL)
 };
 
-#define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops)
-
-#else
-#define SDHCI_S3C_PMOPS NULL
-#endif
-
 #if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
 static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
        .no_divider = true,
@@ -765,7 +758,7 @@ static struct platform_driver sdhci_s3c_driver = {
        .driver         = {
                .name   = "s3c-sdhci",
                .of_match_table = of_match_ptr(sdhci_s3c_dt_match),
-               .pm     = SDHCI_S3C_PMOPS,
+               .pm     = &sdhci_s3c_pmops,
        },
 };
 
index 34866f668dd7b7aee1b943d2001355ea9652c9d2..5d068639dd3f94fc862e8fcefe1609791c18fbd5 100644 (file)
@@ -260,9 +260,9 @@ static int sdhci_sirf_resume(struct device *dev)
 
        return sdhci_resume_host(host);
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume);
-#endif
 
 static const struct of_device_id sdhci_sirf_of_match[] = {
        { .compatible = "sirf,prima2-sdhc" },
@@ -274,9 +274,7 @@ static struct platform_driver sdhci_sirf_driver = {
        .driver         = {
                .name   = "sdhci-sirf",
                .of_match_table = sdhci_sirf_of_match,
-#ifdef CONFIG_PM_SLEEP
                .pm     = &sdhci_sirf_pm_ops,
-#endif
        },
        .probe          = sdhci_sirf_probe,
        .remove         = sdhci_pltfm_unregister,
index 320e1c2f8853effc37d98eeec7f50510ebe6823a..c95ba83366a0f2d95b1b45a70824327069f6b79d 100644 (file)
@@ -183,7 +183,7 @@ static void st_mmcss_cconfig(struct device_node *np, struct sdhci_host *host)
 
        writel_relaxed(cconf2, host->ioaddr + ST_MMC_CCONFIG_REG_2);
 
-       if (mhost->caps & MMC_CAP_NONREMOVABLE)
+       if (!mmc_card_is_removable(mhost))
                cconf3 |= ST_MMC_CCONFIG_EMMC_SLOT_TYPE;
        else
                /* CARD _D ET_CTRL */
index bcc0de47fe7e1833254c1e8fcb95eed112c42031..1e93dc4e303e4f5a31dae97d48955d4dd8bfa7a6 100644 (file)
@@ -148,28 +148,37 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
                return;
 
        misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
-       /* Erratum: Enable SDHCI spec v3.00 support */
-       if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
-               misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
-       /* Advertise UHS modes as supported by host */
-       if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50)
-               misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50;
-       else
-               misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50;
-       if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
-               misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50;
-       else
-               misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50;
-       if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104)
-               misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104;
-       else
-               misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104;
-       sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
-
        clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+
+       misc_ctrl &= ~(SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 |
+                      SDHCI_MISC_CTRL_ENABLE_SDR50 |
+                      SDHCI_MISC_CTRL_ENABLE_DDR50 |
+                      SDHCI_MISC_CTRL_ENABLE_SDR104);
+
        clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE;
-       if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50)
-               clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE;
+
+       /*
+        * If the board does not define a regulator for the SDHCI
+        * IO voltage, then don't advertise support for UHS modes
+        * even if the device supports it because the IO voltage
+        * cannot be configured.
+        */
+       if (!IS_ERR(host->mmc->supply.vqmmc)) {
+               /* Erratum: Enable SDHCI spec v3.00 support */
+               if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
+                       misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
+               /* Advertise UHS modes as supported by host */
+               if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50)
+                       misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50;
+               if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
+                       misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50;
+               if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104)
+                       misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104;
+               if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50)
+                       clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE;
+       }
+
+       sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
        sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
 
        if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB)
@@ -474,7 +483,7 @@ static struct platform_driver sdhci_tegra_driver = {
        .driver         = {
                .name   = "sdhci-tegra",
                .of_match_table = sdhci_tegra_dt_match,
-               .pm     = SDHCI_PLTFM_PMOPS,
+               .pm     = &sdhci_pltfm_pmops,
        },
        .probe          = sdhci_tegra_probe,
        .remove         = sdhci_pltfm_unregister,
index 0e3d7c056cb135dfc1408dd30950f4327ccd84ba..cd65d474afa2bc300064f1214a0e478e90a7366d 100644 (file)
@@ -45,65 +45,62 @@ static unsigned int debug_quirks2;
 
 static void sdhci_finish_data(struct sdhci_host *);
 
-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_get_cd(struct mmc_host *mmc);
 
 static void sdhci_dumpregs(struct sdhci_host *host)
 {
-       pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
-               mmc_hostname(host->mmc));
-
-       pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
-               sdhci_readl(host, SDHCI_DMA_ADDRESS),
-               sdhci_readw(host, SDHCI_HOST_VERSION));
-       pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
-               sdhci_readw(host, SDHCI_BLOCK_SIZE),
-               sdhci_readw(host, SDHCI_BLOCK_COUNT));
-       pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
-               sdhci_readl(host, SDHCI_ARGUMENT),
-               sdhci_readw(host, SDHCI_TRANSFER_MODE));
-       pr_debug(DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
-               sdhci_readl(host, SDHCI_PRESENT_STATE),
-               sdhci_readb(host, SDHCI_HOST_CONTROL));
-       pr_debug(DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
-               sdhci_readb(host, SDHCI_POWER_CONTROL),
-               sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
-       pr_debug(DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
-               sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
-               sdhci_readw(host, SDHCI_CLOCK_CONTROL));
-       pr_debug(DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
-               sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
-               sdhci_readl(host, SDHCI_INT_STATUS));
-       pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
-               sdhci_readl(host, SDHCI_INT_ENABLE),
-               sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
-       pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
-               sdhci_readw(host, SDHCI_ACMD12_ERR),
-               sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
-       pr_debug(DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n",
-               sdhci_readl(host, SDHCI_CAPABILITIES),
-               sdhci_readl(host, SDHCI_CAPABILITIES_1));
-       pr_debug(DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
-               sdhci_readw(host, SDHCI_COMMAND),
-               sdhci_readl(host, SDHCI_MAX_CURRENT));
-       pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
-               sdhci_readw(host, SDHCI_HOST_CONTROL2));
+       pr_err(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
+              mmc_hostname(host->mmc));
+
+       pr_err(DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
+              sdhci_readl(host, SDHCI_DMA_ADDRESS),
+              sdhci_readw(host, SDHCI_HOST_VERSION));
+       pr_err(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
+              sdhci_readw(host, SDHCI_BLOCK_SIZE),
+              sdhci_readw(host, SDHCI_BLOCK_COUNT));
+       pr_err(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
+              sdhci_readl(host, SDHCI_ARGUMENT),
+              sdhci_readw(host, SDHCI_TRANSFER_MODE));
+       pr_err(DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
+              sdhci_readl(host, SDHCI_PRESENT_STATE),
+              sdhci_readb(host, SDHCI_HOST_CONTROL));
+       pr_err(DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
+              sdhci_readb(host, SDHCI_POWER_CONTROL),
+              sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
+       pr_err(DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
+              sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
+              sdhci_readw(host, SDHCI_CLOCK_CONTROL));
+       pr_err(DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
+              sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
+              sdhci_readl(host, SDHCI_INT_STATUS));
+       pr_err(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
+              sdhci_readl(host, SDHCI_INT_ENABLE),
+              sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
+       pr_err(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
+              sdhci_readw(host, SDHCI_ACMD12_ERR),
+              sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
+       pr_err(DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n",
+              sdhci_readl(host, SDHCI_CAPABILITIES),
+              sdhci_readl(host, SDHCI_CAPABILITIES_1));
+       pr_err(DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
+              sdhci_readw(host, SDHCI_COMMAND),
+              sdhci_readl(host, SDHCI_MAX_CURRENT));
+       pr_err(DRIVER_NAME ": Host ctl2: 0x%08x\n",
+              sdhci_readw(host, SDHCI_HOST_CONTROL2));
 
        if (host->flags & SDHCI_USE_ADMA) {
                if (host->flags & SDHCI_USE_64_BIT_DMA)
-                       pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
-                                readl(host->ioaddr + SDHCI_ADMA_ERROR),
-                                readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI),
-                                readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
+                       pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
+                              readl(host->ioaddr + SDHCI_ADMA_ERROR),
+                              readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI),
+                              readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
                else
-                       pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
-                                readl(host->ioaddr + SDHCI_ADMA_ERROR),
-                                readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
+                       pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
+                              readl(host->ioaddr + SDHCI_ADMA_ERROR),
+                              readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
        }
 
-       pr_debug(DRIVER_NAME ": ===========================================\n");
+       pr_err(DRIVER_NAME ": ===========================================\n");
 }
 
 /*****************************************************************************\
@@ -112,12 +109,17 @@ static void sdhci_dumpregs(struct sdhci_host *host)
  *                                                                           *
 \*****************************************************************************/
 
+static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
+{
+       return cmd->data || cmd->flags & MMC_RSP_BUSY;
+}
+
 static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 {
        u32 present;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
-           (host->mmc->caps & MMC_CAP_NONREMOVABLE))
+           !mmc_card_is_removable(host->mmc))
                return;
 
        if (enable) {
@@ -193,7 +195,9 @@ 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_get_cd(host->mmc))
+               struct mmc_host *mmc = host->mmc;
+
+               if (!mmc->ops->get_cd(mmc))
                        return;
        }
 
@@ -210,10 +214,10 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
        }
 }
 
-static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
-
 static void sdhci_init(struct sdhci_host *host, int soft)
 {
+       struct mmc_host *mmc = host->mmc;
+
        if (soft)
                sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
        else
@@ -225,13 +229,17 @@ static void sdhci_init(struct sdhci_host *host, int soft)
                    SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
                    SDHCI_INT_RESPONSE;
 
+       if (host->tuning_mode == SDHCI_TUNING_MODE_2 ||
+           host->tuning_mode == SDHCI_TUNING_MODE_3)
+               host->ier |= SDHCI_INT_RETUNE;
+
        sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
        sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 
        if (soft) {
                /* force clock reconfiguration */
                host->clock = 0;
-               sdhci_set_ios(host->mmc, &host->mmc->ios);
+               mmc->ops->set_ios(mmc, &mmc->ios);
        }
 }
 
@@ -429,8 +437,6 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
 {
        u32 mask;
 
-       BUG_ON(!host->data);
-
        if (host->blocks == 0)
                return;
 
@@ -747,14 +753,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
        u8 ctrl;
        struct mmc_data *data = cmd->data;
 
-       WARN_ON(host->data);
-
-       if (data || (cmd->flags & MMC_RSP_BUSY))
+       if (sdhci_data_line_cmd(cmd))
                sdhci_set_timeout(host, cmd);
 
        if (!data)
                return;
 
+       WARN_ON(host->data);
+
        /* Sanity checks */
        BUG_ON(data->blksz * data->blocks > 524288);
        BUG_ON(data->blksz > host->mmc->max_blk_size);
@@ -879,6 +885,12 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
        sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
 }
 
+static inline bool sdhci_auto_cmd12(struct sdhci_host *host,
+                                   struct mmc_request *mrq)
+{
+       return !mrq->sbc && (host->flags & SDHCI_AUTO_CMD12);
+}
+
 static void sdhci_set_transfer_mode(struct sdhci_host *host,
        struct mmc_command *cmd)
 {
@@ -909,12 +921,12 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
                 * If we are sending CMD23, CMD12 never gets sent
                 * on successful completion (so no Auto-CMD12).
                 */
-               if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) &&
+               if (sdhci_auto_cmd12(host, cmd->mrq) &&
                    (cmd->opcode != SD_IO_RW_EXTENDED))
                        mode |= SDHCI_TRNS_AUTO_CMD12;
-               else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
+               else if (cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
                        mode |= SDHCI_TRNS_AUTO_CMD23;
-                       sdhci_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2);
+                       sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2);
                }
        }
 
@@ -926,14 +938,63 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
        sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
 }
 
-static void sdhci_finish_data(struct sdhci_host *host)
+static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
+{
+       return (!(host->flags & SDHCI_DEVICE_DEAD) &&
+               ((mrq->cmd && mrq->cmd->error) ||
+                (mrq->sbc && mrq->sbc->error) ||
+                (mrq->data && ((mrq->data->error && !mrq->data->stop) ||
+                               (mrq->data->stop && mrq->data->stop->error))) ||
+                (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)));
+}
+
+static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
+{
+       int i;
+
+       for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+               if (host->mrqs_done[i] == mrq) {
+                       WARN_ON(1);
+                       return;
+               }
+       }
+
+       for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+               if (!host->mrqs_done[i]) {
+                       host->mrqs_done[i] = mrq;
+                       break;
+               }
+       }
+
+       WARN_ON(i >= SDHCI_MAX_MRQS);
+
+       tasklet_schedule(&host->finish_tasklet);
+}
+
+static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
 {
-       struct mmc_data *data;
+       if (host->cmd && host->cmd->mrq == mrq)
+               host->cmd = NULL;
+
+       if (host->data_cmd && host->data_cmd->mrq == mrq)
+               host->data_cmd = NULL;
+
+       if (host->data && host->data->mrq == mrq)
+               host->data = NULL;
 
-       BUG_ON(!host->data);
+       if (sdhci_needs_reset(host, mrq))
+               host->pending_reset = true;
+
+       __sdhci_finish_mrq(host, mrq);
+}
+
+static void sdhci_finish_data(struct sdhci_host *host)
+{
+       struct mmc_command *data_cmd = host->data_cmd;
+       struct mmc_data *data = host->data;
 
-       data = host->data;
        host->data = NULL;
+       host->data_cmd = NULL;
 
        if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) ==
            (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA))
@@ -958,20 +1019,41 @@ static void sdhci_finish_data(struct sdhci_host *host)
         */
        if (data->stop &&
            (data->error ||
-            !host->mrq->sbc)) {
+            !data->mrq->sbc)) {
 
                /*
                 * The controller needs a reset of internal state machines
                 * upon error conditions.
                 */
                if (data->error) {
-                       sdhci_do_reset(host, SDHCI_RESET_CMD);
+                       if (!host->cmd || host->cmd == data_cmd)
+                               sdhci_do_reset(host, SDHCI_RESET_CMD);
                        sdhci_do_reset(host, SDHCI_RESET_DATA);
                }
 
+               /* Avoid triggering warning in sdhci_send_command() */
+               host->cmd = NULL;
                sdhci_send_command(host, data->stop);
-       } else
-               tasklet_schedule(&host->finish_tasklet);
+       } else {
+               sdhci_finish_mrq(host, data->mrq);
+       }
+}
+
+static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
+                           unsigned long timeout)
+{
+       if (sdhci_data_line_cmd(mrq->cmd))
+               mod_timer(&host->data_timer, timeout);
+       else
+               mod_timer(&host->timer, timeout);
+}
+
+static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
+{
+       if (sdhci_data_line_cmd(mrq->cmd))
+               del_timer(&host->data_timer);
+       else
+               del_timer(&host->timer);
 }
 
 void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
@@ -989,12 +1071,12 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        timeout = 10;
 
        mask = SDHCI_CMD_INHIBIT;
-       if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
+       if (sdhci_data_line_cmd(cmd))
                mask |= SDHCI_DATA_INHIBIT;
 
        /* We shouldn't wait for data inihibit for stop commands, even
           though they might use busy signaling */
-       if (host->mrq->data && (cmd == host->mrq->data->stop))
+       if (cmd->mrq->data && (cmd == cmd->mrq->data->stop))
                mask &= ~SDHCI_DATA_INHIBIT;
 
        while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
@@ -1003,7 +1085,7 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                               mmc_hostname(host->mmc));
                        sdhci_dumpregs(host);
                        cmd->error = -EIO;
-                       tasklet_schedule(&host->finish_tasklet);
+                       sdhci_finish_mrq(host, cmd->mrq);
                        return;
                }
                timeout--;
@@ -1015,10 +1097,13 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
        else
                timeout += 10 * HZ;
-       mod_timer(&host->timer, timeout);
+       sdhci_mod_timer(host, cmd->mrq, timeout);
 
        host->cmd = cmd;
-       host->busy_handle = 0;
+       if (sdhci_data_line_cmd(cmd)) {
+               WARN_ON(host->data_cmd);
+               host->data_cmd = cmd;
+       }
 
        sdhci_prepare_data(host, cmd);
 
@@ -1030,7 +1115,7 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                pr_err("%s: Unsupported response type!\n",
                        mmc_hostname(host->mmc));
                cmd->error = -EINVAL;
-               tasklet_schedule(&host->finish_tasklet);
+               sdhci_finish_mrq(host, cmd->mrq);
                return;
        }
 
@@ -1059,40 +1144,58 @@ EXPORT_SYMBOL_GPL(sdhci_send_command);
 
 static void sdhci_finish_command(struct sdhci_host *host)
 {
+       struct mmc_command *cmd = host->cmd;
        int i;
 
-       BUG_ON(host->cmd == NULL);
+       host->cmd = NULL;
 
-       if (host->cmd->flags & MMC_RSP_PRESENT) {
-               if (host->cmd->flags & MMC_RSP_136) {
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136) {
                        /* CRC is stripped so we need to do some shifting. */
                        for (i = 0;i < 4;i++) {
-                               host->cmd->resp[i] = sdhci_readl(host,
+                               cmd->resp[i] = sdhci_readl(host,
                                        SDHCI_RESPONSE + (3-i)*4) << 8;
                                if (i != 3)
-                                       host->cmd->resp[i] |=
+                                       cmd->resp[i] |=
                                                sdhci_readb(host,
                                                SDHCI_RESPONSE + (3-i)*4-1);
                        }
                } else {
-                       host->cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE);
+                       cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE);
+               }
+       }
+
+       /*
+        * The host can send and interrupt when the busy state has
+        * ended, allowing us to wait without wasting CPU cycles.
+        * The busy signal uses DAT0 so this is similar to waiting
+        * for data to complete.
+        *
+        * Note: The 1.0 specification is a bit ambiguous about this
+        *       feature so there might be some problems with older
+        *       controllers.
+        */
+       if (cmd->flags & MMC_RSP_BUSY) {
+               if (cmd->data) {
+                       DBG("Cannot wait for busy signal when also doing a data transfer");
+               } else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) &&
+                          cmd == host->data_cmd) {
+                       /* Command complete before busy is ended */
+                       return;
                }
        }
 
        /* Finished CMD23, now send actual command. */
-       if (host->cmd == host->mrq->sbc) {
-               host->cmd = NULL;
-               sdhci_send_command(host, host->mrq->cmd);
+       if (cmd == cmd->mrq->sbc) {
+               sdhci_send_command(host, cmd->mrq->cmd);
        } else {
 
                /* Processed actual command. */
                if (host->data && host->data_early)
                        sdhci_finish_data(host);
 
-               if (!host->cmd->data)
-                       tasklet_schedule(&host->finish_tasklet);
-
-               host->cmd = NULL;
+               if (!cmd->data)
+                       sdhci_finish_mrq(host, cmd->mrq);
        }
 }
 
@@ -1373,26 +1476,22 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        spin_lock_irqsave(&host->lock, flags);
 
-       WARN_ON(host->mrq != NULL);
-
        sdhci_led_activate(host);
 
        /*
         * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
         * requests if Auto-CMD12 is enabled.
         */
-       if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
+       if (sdhci_auto_cmd12(host, mrq)) {
                if (mrq->stop) {
                        mrq->data->stop = NULL;
                        mrq->stop = NULL;
                }
        }
 
-       host->mrq = mrq;
-
        if (!present || host->flags & SDHCI_DEVICE_DEAD) {
-               host->mrq->cmd->error = -ENOMEDIUM;
-               tasklet_schedule(&host->finish_tasklet);
+               mrq->cmd->error = -ENOMEDIUM;
+               sdhci_finish_mrq(host, mrq);
        } else {
                if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
                        sdhci_send_command(host, mrq->sbc);
@@ -1617,7 +1716,7 @@ static int sdhci_get_cd(struct mmc_host *mmc)
                return 0;
 
        /* If nonremovable, assume that the card is always present. */
-       if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+       if (!mmc_card_is_removable(host->mmc))
                return 1;
 
        /*
@@ -1733,13 +1832,14 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 
        switch (ios->signal_voltage) {
        case MMC_SIGNAL_VOLTAGE_330:
+               if (!(host->flags & SDHCI_SIGNALING_330))
+                       return -EINVAL;
                /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
                ctrl &= ~SDHCI_CTRL_VDD_180;
                sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
                if (!IS_ERR(mmc->supply.vqmmc)) {
-                       ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
-                                                   3600000);
+                       ret = mmc_regulator_set_vqmmc(mmc, ios);
                        if (ret) {
                                pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
                                        mmc_hostname(mmc));
@@ -1759,9 +1859,10 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 
                return -EAGAIN;
        case MMC_SIGNAL_VOLTAGE_180:
+               if (!(host->flags & SDHCI_SIGNALING_180))
+                       return -EINVAL;
                if (!IS_ERR(mmc->supply.vqmmc)) {
-                       ret = regulator_set_voltage(mmc->supply.vqmmc,
-                                       1700000, 1950000);
+                       ret = mmc_regulator_set_vqmmc(mmc, ios);
                        if (ret) {
                                pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
                                        mmc_hostname(mmc));
@@ -1790,9 +1891,10 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 
                return -EAGAIN;
        case MMC_SIGNAL_VOLTAGE_120:
+               if (!(host->flags & SDHCI_SIGNALING_120))
+                       return -EINVAL;
                if (!IS_ERR(mmc->supply.vqmmc)) {
-                       ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
-                                                   1300000);
+                       ret = mmc_regulator_set_vqmmc(mmc, ios);
                        if (ret) {
                                pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
                                        mmc_hostname(mmc));
@@ -1811,10 +1913,10 @@ static int sdhci_card_busy(struct mmc_host *mmc)
        struct sdhci_host *host = mmc_priv(mmc);
        u32 present_state;
 
-       /* Check whether DAT[3:0] is 0000 */
+       /* Check whether DAT[0] is 0 */
        present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
 
-       return !(present_state & SDHCI_DATA_LVL_MASK);
+       return !(present_state & SDHCI_DATA_0_LVL_MASK);
 }
 
 static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -1909,7 +2011,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 
        /*
         * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
-        * of loops reaches 40 times or a timeout of 150ms occurs.
+        * of loops reaches 40 times.
         */
        do {
                struct mmc_command cmd = {0};
@@ -1920,13 +2022,13 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
                cmd.retries = 0;
                cmd.data = NULL;
+               cmd.mrq = &mrq;
                cmd.error = 0;
 
                if (tuning_loop_counter-- == 0)
                        break;
 
                mrq.cmd = &cmd;
-               host->mrq = &mrq;
 
                /*
                 * In response to CMD19, the card sends 64 bytes of tuning
@@ -1956,7 +2058,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                sdhci_send_command(host, &cmd);
 
                host->cmd = NULL;
-               host->mrq = NULL;
+               sdhci_del_timer(host, &mrq);
 
                spin_unlock_irqrestore(&host->lock, flags);
                /* Wait for Buffer Read Ready interrupt */
@@ -2086,6 +2188,24 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
                sdhci_pre_dma_transfer(host, mrq->data, COOKIE_PRE_MAPPED);
 }
 
+static inline bool sdhci_has_requests(struct sdhci_host *host)
+{
+       return host->cmd || host->data_cmd;
+}
+
+static void sdhci_error_out_mrqs(struct sdhci_host *host, int err)
+{
+       if (host->data_cmd) {
+               host->data_cmd->error = err;
+               sdhci_finish_mrq(host, host->data_cmd->mrq);
+       }
+
+       if (host->cmd) {
+               host->cmd->error = err;
+               sdhci_finish_mrq(host, host->cmd->mrq);
+       }
+}
+
 static void sdhci_card_event(struct mmc_host *mmc)
 {
        struct sdhci_host *host = mmc_priv(mmc);
@@ -2096,12 +2216,12 @@ static void sdhci_card_event(struct mmc_host *mmc)
        if (host->ops->card_event)
                host->ops->card_event(host);
 
-       present = sdhci_get_cd(host->mmc);
+       present = mmc->ops->get_cd(mmc);
 
        spin_lock_irqsave(&host->lock, flags);
 
-       /* Check host->mrq first in case we are runtime suspended */
-       if (host->mrq && !present) {
+       /* Check sdhci_has_requests() first in case we are runtime suspended */
+       if (sdhci_has_requests(host) && !present) {
                pr_err("%s: Card removed during transfer!\n",
                        mmc_hostname(host->mmc));
                pr_err("%s: Resetting controller.\n",
@@ -2110,8 +2230,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
                sdhci_do_reset(host, SDHCI_RESET_CMD);
                sdhci_do_reset(host, SDHCI_RESET_DATA);
 
-               host->mrq->cmd->error = -ENOMEDIUM;
-               tasklet_schedule(&host->finish_tasklet);
+               sdhci_error_out_mrqs(host, -ENOMEDIUM);
        }
 
        spin_unlock_irqrestore(&host->lock, flags);
@@ -2140,28 +2259,28 @@ static const struct mmc_host_ops sdhci_ops = {
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_tasklet_finish(unsigned long param)
+static bool sdhci_request_done(struct sdhci_host *host)
 {
-       struct sdhci_host *host;
        unsigned long flags;
        struct mmc_request *mrq;
-
-       host = (struct sdhci_host*)param;
+       int i;
 
        spin_lock_irqsave(&host->lock, flags);
 
-        /*
-         * If this tasklet gets rescheduled while running, it will
-         * be run again afterwards but without any active request.
-         */
-       if (!host->mrq) {
-               spin_unlock_irqrestore(&host->lock, flags);
-               return;
+       for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+               mrq = host->mrqs_done[i];
+               if (mrq) {
+                       host->mrqs_done[i] = NULL;
+                       break;
+               }
        }
 
-       del_timer(&host->timer);
+       if (!mrq) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               return true;
+       }
 
-       mrq = host->mrq;
+       sdhci_del_timer(host, mrq);
 
        /*
         * Always unmap the data buffers if they were mapped by
@@ -2183,13 +2302,7 @@ static void sdhci_tasklet_finish(unsigned long param)
         * The controller needs a reset of internal state machines
         * upon error conditions.
         */
-       if (!(host->flags & SDHCI_DEVICE_DEAD) &&
-           ((mrq->cmd && mrq->cmd->error) ||
-            (mrq->sbc && mrq->sbc->error) ||
-            (mrq->data && ((mrq->data->error && !mrq->data->stop) ||
-                           (mrq->data->stop && mrq->data->stop->error))) ||
-            (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
-
+       if (sdhci_needs_reset(host, mrq)) {
                /* Some controllers need this kick or reset won't work here */
                if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
                        /* This is to force an update */
@@ -2197,20 +2310,31 @@ static void sdhci_tasklet_finish(unsigned long param)
 
                /* Spec says we should do both at the same time, but Ricoh
                   controllers do not like that. */
-               sdhci_do_reset(host, SDHCI_RESET_CMD);
-               sdhci_do_reset(host, SDHCI_RESET_DATA);
-       }
+               if (!host->cmd)
+                       sdhci_do_reset(host, SDHCI_RESET_CMD);
+               if (!host->data_cmd)
+                       sdhci_do_reset(host, SDHCI_RESET_DATA);
 
-       host->mrq = NULL;
-       host->cmd = NULL;
-       host->data = NULL;
+               host->pending_reset = false;
+       }
 
-       sdhci_led_deactivate(host);
+       if (!sdhci_has_requests(host))
+               sdhci_led_deactivate(host);
 
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 
        mmc_request_done(host->mmc, mrq);
+
+       return false;
+}
+
+static void sdhci_tasklet_finish(unsigned long param)
+{
+       struct sdhci_host *host = (struct sdhci_host *)param;
+
+       while (!sdhci_request_done(host))
+               ;
 }
 
 static void sdhci_timeout_timer(unsigned long data)
@@ -2222,7 +2346,30 @@ static void sdhci_timeout_timer(unsigned long data)
 
        spin_lock_irqsave(&host->lock, flags);
 
-       if (host->mrq) {
+       if (host->cmd && !sdhci_data_line_cmd(host->cmd)) {
+               pr_err("%s: Timeout waiting for hardware cmd interrupt.\n",
+                      mmc_hostname(host->mmc));
+               sdhci_dumpregs(host);
+
+               host->cmd->error = -ETIMEDOUT;
+               sdhci_finish_mrq(host, host->cmd->mrq);
+       }
+
+       mmiowb();
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void sdhci_timeout_data_timer(unsigned long data)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+
+       host = (struct sdhci_host *)data;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (host->data || host->data_cmd ||
+           (host->cmd && sdhci_data_line_cmd(host->cmd))) {
                pr_err("%s: Timeout waiting for hardware interrupt.\n",
                       mmc_hostname(host->mmc));
                sdhci_dumpregs(host);
@@ -2230,13 +2377,12 @@ static void sdhci_timeout_timer(unsigned long data)
                if (host->data) {
                        host->data->error = -ETIMEDOUT;
                        sdhci_finish_data(host);
+               } else if (host->data_cmd) {
+                       host->data_cmd->error = -ETIMEDOUT;
+                       sdhci_finish_mrq(host, host->data_cmd->mrq);
                } else {
-                       if (host->cmd)
-                               host->cmd->error = -ETIMEDOUT;
-                       else
-                               host->mrq->cmd->error = -ETIMEDOUT;
-
-                       tasklet_schedule(&host->finish_tasklet);
+                       host->cmd->error = -ETIMEDOUT;
+                       sdhci_finish_mrq(host, host->cmd->mrq);
                }
        }
 
@@ -2252,9 +2398,14 @@ static void sdhci_timeout_timer(unsigned long data)
 
 static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
 {
-       BUG_ON(intmask == 0);
-
        if (!host->cmd) {
+               /*
+                * SDHCI recovers from errors by resetting the cmd and data
+                * circuits.  Until that is done, there very well might be more
+                * interrupts, so ignore them in that case.
+                */
+               if (host->pending_reset)
+                       return;
                pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n",
                       mmc_hostname(host->mmc), (unsigned)intmask);
                sdhci_dumpregs(host);
@@ -2285,37 +2436,14 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
                        return;
                }
 
-               tasklet_schedule(&host->finish_tasklet);
+               sdhci_finish_mrq(host, host->cmd->mrq);
                return;
        }
 
-       /*
-        * The host can send and interrupt when the busy state has
-        * ended, allowing us to wait without wasting CPU cycles.
-        * Unfortunately this is overloaded on the "data complete"
-        * interrupt, so we need to take some care when handling
-        * it.
-        *
-        * Note: The 1.0 specification is a bit ambiguous about this
-        *       feature so there might be some problems with older
-        *       controllers.
-        */
-       if (host->cmd->flags & MMC_RSP_BUSY) {
-               if (host->cmd->data)
-                       DBG("Cannot wait for busy signal when also doing a data transfer");
-               else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ)
-                               && !host->busy_handle) {
-                       /* Mark that command complete before busy is ended */
-                       host->busy_handle = 1;
-                       return;
-               }
-
-               /* The controller does not support the end-of-busy IRQ,
-                * fall through and take the SDHCI_INT_RESPONSE */
-       } else if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) &&
-                  host->cmd->opcode == MMC_STOP_TRANSMISSION && !host->data) {
+       if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) &&
+           !(host->cmd->flags & MMC_RSP_BUSY) && !host->data &&
+           host->cmd->opcode == MMC_STOP_TRANSMISSION)
                *mask &= ~SDHCI_INT_DATA_END;
-       }
 
        if (intmask & SDHCI_INT_RESPONSE)
                sdhci_finish_command(host);
@@ -2357,7 +2485,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host) { }
 static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 {
        u32 command;
-       BUG_ON(intmask == 0);
 
        /* CMD19 generates _only_ Buffer Read Ready interrupt */
        if (intmask & SDHCI_INT_DATA_AVAIL) {
@@ -2371,15 +2498,20 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
        }
 
        if (!host->data) {
+               struct mmc_command *data_cmd = host->data_cmd;
+
+               if (data_cmd)
+                       host->data_cmd = NULL;
+
                /*
                 * The "data complete" interrupt is also used to
                 * indicate that a busy state has ended. See comment
                 * above in sdhci_cmd_irq().
                 */
-               if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+               if (data_cmd && (data_cmd->flags & MMC_RSP_BUSY)) {
                        if (intmask & SDHCI_INT_DATA_TIMEOUT) {
-                               host->cmd->error = -ETIMEDOUT;
-                               tasklet_schedule(&host->finish_tasklet);
+                               data_cmd->error = -ETIMEDOUT;
+                               sdhci_finish_mrq(host, data_cmd->mrq);
                                return;
                        }
                        if (intmask & SDHCI_INT_DATA_END) {
@@ -2388,14 +2520,22 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                                 * before the command completed, so make
                                 * sure we do things in the proper order.
                                 */
-                               if (host->busy_handle)
-                                       sdhci_finish_command(host);
-                               else
-                                       host->busy_handle = 1;
+                               if (host->cmd == data_cmd)
+                                       return;
+
+                               sdhci_finish_mrq(host, data_cmd->mrq);
                                return;
                        }
                }
 
+               /*
+                * SDHCI recovers from errors by resetting the cmd and data
+                * circuits. Until that is done, there very well might be more
+                * interrupts, so ignore them in that case.
+                */
+               if (host->pending_reset)
+                       return;
+
                pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
                       mmc_hostname(host->mmc), (unsigned)intmask);
                sdhci_dumpregs(host);
@@ -2453,7 +2593,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                }
 
                if (intmask & SDHCI_INT_DATA_END) {
-                       if (host->cmd) {
+                       if (host->cmd == host->data_cmd) {
                                /*
                                 * Data managed to finish before the
                                 * command completed. Make sure we do
@@ -2537,6 +2677,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
                        pr_err("%s: Card is consuming too much power!\n",
                                mmc_hostname(host->mmc));
 
+               if (intmask & SDHCI_INT_RETUNE)
+                       mmc_retune_needed(host->mmc);
+
                if (intmask & SDHCI_INT_CARD_INT) {
                        sdhci_enable_sdio_irq_nolock(host, false);
                        host->thread_isr |= SDHCI_INT_CARD_INT;
@@ -2546,7 +2689,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
                intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
                             SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
                             SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
-                            SDHCI_INT_CARD_INT);
+                            SDHCI_INT_RETUNE | SDHCI_INT_CARD_INT);
 
                if (intmask) {
                        unexpected |= intmask;
@@ -2582,8 +2725,10 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
        spin_unlock_irqrestore(&host->lock, flags);
 
        if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
-               sdhci_card_event(host->mmc);
-               mmc_detect_change(host->mmc, msecs_to_jiffies(200));
+               struct mmc_host *mmc = host->mmc;
+
+               mmc->ops->card_event(mmc);
+               mmc_detect_change(mmc, msecs_to_jiffies(200));
        }
 
        if (isr & SDHCI_INT_CARD_INT) {
@@ -2605,18 +2750,31 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
 \*****************************************************************************/
 
 #ifdef CONFIG_PM
+/*
+ * To enable wakeup events, the corresponding events have to be enabled in
+ * the Interrupt Status Enable register too. See 'Table 1-6: Wakeup Signal
+ * Table' in the SD Host Controller Standard Specification.
+ * It is useless to restore SDHCI_INT_ENABLE state in
+ * sdhci_disable_irq_wakeups() since it will be set by
+ * sdhci_enable_card_detection() or sdhci_init().
+ */
 void sdhci_enable_irq_wakeups(struct sdhci_host *host)
 {
        u8 val;
        u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE
                        | SDHCI_WAKE_ON_INT;
+       u32 irq_val = SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
+                     SDHCI_INT_CARD_INT;
 
        val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
        val |= mask ;
        /* Avoid fake wake up */
-       if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+       if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) {
                val &= ~(SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE);
+               irq_val &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
+       }
        sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
+       sdhci_writel(host, irq_val, SDHCI_INT_ENABLE);
 }
 EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups);
 
@@ -2636,7 +2794,8 @@ int sdhci_suspend_host(struct sdhci_host *host)
        sdhci_disable_card_detection(host);
 
        mmc_retune_timer_stop(host->mmc);
-       mmc_retune_needed(host->mmc);
+       if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+               mmc_retune_needed(host->mmc);
 
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
                host->ier = 0;
@@ -2654,6 +2813,7 @@ EXPORT_SYMBOL_GPL(sdhci_suspend_host);
 
 int sdhci_resume_host(struct sdhci_host *host)
 {
+       struct mmc_host *mmc = host->mmc;
        int ret = 0;
 
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
@@ -2667,7 +2827,7 @@ int sdhci_resume_host(struct sdhci_host *host)
                sdhci_init(host, 0);
                host->pwr = 0;
                host->clock = 0;
-               sdhci_set_ios(host->mmc, &host->mmc->ios);
+               mmc->ops->set_ios(mmc, &mmc->ios);
        } else {
                sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
                mmiowb();
@@ -2696,7 +2856,8 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
        unsigned long flags;
 
        mmc_retune_timer_stop(host->mmc);
-       mmc_retune_needed(host->mmc);
+       if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+               mmc_retune_needed(host->mmc);
 
        spin_lock_irqsave(&host->lock, flags);
        host->ier &= SDHCI_INT_CARD_INT;
@@ -2716,6 +2877,7 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host);
 
 int sdhci_runtime_resume_host(struct sdhci_host *host)
 {
+       struct mmc_host *mmc = host->mmc;
        unsigned long flags;
        int host_flags = host->flags;
 
@@ -2729,8 +2891,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
        /* Force clock and power re-program */
        host->pwr = 0;
        host->clock = 0;
-       sdhci_start_signal_voltage_switch(host->mmc, &host->mmc->ios);
-       sdhci_set_ios(host->mmc, &host->mmc->ios);
+       mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
+       mmc->ops->set_ios(mmc, &mmc->ios);
 
        if ((host_flags & SDHCI_PV_ENABLED) &&
                !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
@@ -2781,6 +2943,8 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
        host->mmc_host_ops = sdhci_ops;
        mmc->ops = &host->mmc_host_ops;
 
+       host->flags = SDHCI_SIGNALING_330;
+
        return host;
 }
 
@@ -2816,10 +2980,41 @@ static int sdhci_set_dma_mask(struct sdhci_host *host)
        return ret;
 }
 
-int sdhci_add_host(struct sdhci_host *host)
+void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1)
+{
+       u16 v;
+
+       if (host->read_caps)
+               return;
+
+       host->read_caps = true;
+
+       if (debug_quirks)
+               host->quirks = debug_quirks;
+
+       if (debug_quirks2)
+               host->quirks2 = debug_quirks2;
+
+       sdhci_do_reset(host, SDHCI_RESET_ALL);
+
+       v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION);
+       host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
+
+       if (host->quirks & SDHCI_QUIRK_MISSING_CAPS)
+               return;
+
+       host->caps = caps ? *caps : sdhci_readl(host, SDHCI_CAPABILITIES);
+
+       if (host->version < SDHCI_SPEC_300)
+               return;
+
+       host->caps1 = caps1 ? *caps1 : sdhci_readl(host, SDHCI_CAPABILITIES_1);
+}
+EXPORT_SYMBOL_GPL(__sdhci_read_caps);
+
+int sdhci_setup_host(struct sdhci_host *host)
 {
        struct mmc_host *mmc;
-       u32 caps[2] = {0, 0};
        u32 max_current_caps;
        unsigned int ocr_avail;
        unsigned int override_timeout_clk;
@@ -2832,34 +3027,28 @@ int sdhci_add_host(struct sdhci_host *host)
 
        mmc = host->mmc;
 
-       if (debug_quirks)
-               host->quirks = debug_quirks;
-       if (debug_quirks2)
-               host->quirks2 = debug_quirks2;
+       /*
+        * If there are external regulators, get them. Note this must be done
+        * early before resetting the host and reading the capabilities so that
+        * the host can take the appropriate action if regulators are not
+        * available.
+        */
+       ret = mmc_regulator_get_supply(mmc);
+       if (ret == -EPROBE_DEFER)
+               return ret;
 
-       override_timeout_clk = host->timeout_clk;
+       sdhci_read_caps(host);
 
-       sdhci_do_reset(host, SDHCI_RESET_ALL);
+       override_timeout_clk = host->timeout_clk;
 
-       host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
-       host->version = (host->version & SDHCI_SPEC_VER_MASK)
-                               >> SDHCI_SPEC_VER_SHIFT;
        if (host->version > SDHCI_SPEC_300) {
                pr_err("%s: Unknown controller version (%d). You may experience problems.\n",
                       mmc_hostname(mmc), host->version);
        }
 
-       caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
-               sdhci_readl(host, SDHCI_CAPABILITIES);
-
-       if (host->version >= SDHCI_SPEC_300)
-               caps[1] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ?
-                       host->caps1 :
-                       sdhci_readl(host, SDHCI_CAPABILITIES_1);
-
        if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
                host->flags |= SDHCI_USE_SDMA;
-       else if (!(caps[0] & SDHCI_CAN_DO_SDMA))
+       else if (!(host->caps & SDHCI_CAN_DO_SDMA))
                DBG("Controller doesn't have SDMA capability\n");
        else
                host->flags |= SDHCI_USE_SDMA;
@@ -2871,7 +3060,7 @@ int sdhci_add_host(struct sdhci_host *host)
        }
 
        if ((host->version >= SDHCI_SPEC_200) &&
-               (caps[0] & SDHCI_CAN_DO_ADMA2))
+               (host->caps & SDHCI_CAN_DO_ADMA2))
                host->flags |= SDHCI_USE_ADMA;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
@@ -2887,7 +3076,7 @@ int sdhci_add_host(struct sdhci_host *host)
         * SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to
         * implement.
         */
-       if (caps[0] & SDHCI_CAN_64BIT)
+       if (host->caps & SDHCI_CAN_64BIT)
                host->flags |= SDHCI_USE_64_BIT_DMA;
 
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
@@ -2963,10 +3152,10 @@ int sdhci_add_host(struct sdhci_host *host)
        }
 
        if (host->version >= SDHCI_SPEC_300)
-               host->max_clk = (caps[0] & SDHCI_CLOCK_V3_BASE_MASK)
+               host->max_clk = (host->caps & SDHCI_CLOCK_V3_BASE_MASK)
                        >> SDHCI_CLOCK_BASE_SHIFT;
        else
-               host->max_clk = (caps[0] & SDHCI_CLOCK_BASE_MASK)
+               host->max_clk = (host->caps & SDHCI_CLOCK_BASE_MASK)
                        >> SDHCI_CLOCK_BASE_SHIFT;
 
        host->max_clk *= 1000000;
@@ -2985,7 +3174,7 @@ int sdhci_add_host(struct sdhci_host *host)
         * In case of Host Controller v3.00, find out whether clock
         * multiplier is supported.
         */
-       host->clk_mul = (caps[1] & SDHCI_CLOCK_MUL_MASK) >>
+       host->clk_mul = (host->caps1 & SDHCI_CLOCK_MUL_MASK) >>
                        SDHCI_CLOCK_MUL_SHIFT;
 
        /*
@@ -3017,7 +3206,7 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->f_max = max_clk;
 
        if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
-               host->timeout_clk = (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >>
+               host->timeout_clk = (host->caps & SDHCI_TIMEOUT_CLK_MASK) >>
                                        SDHCI_TIMEOUT_CLK_SHIFT;
                if (host->timeout_clk == 0) {
                        if (host->ops->get_timeout_clock) {
@@ -3031,7 +3220,7 @@ int sdhci_add_host(struct sdhci_host *host)
                        }
                }
 
-               if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
+               if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
                        host->timeout_clk *= 1000;
 
                if (override_timeout_clk)
@@ -3072,27 +3261,22 @@ int sdhci_add_host(struct sdhci_host *host)
        if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23)
                mmc->caps &= ~MMC_CAP_CMD23;
 
-       if (caps[0] & SDHCI_CAN_DO_HISPD)
+       if (host->caps & SDHCI_CAN_DO_HISPD)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
-           !(mmc->caps & MMC_CAP_NONREMOVABLE) &&
+           mmc_card_is_removable(mmc) &&
            mmc_gpio_get_cd(host->mmc) < 0)
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
-       /* If there are external regulators, get them */
-       ret = mmc_regulator_get_supply(mmc);
-       if (ret == -EPROBE_DEFER)
-               goto undma;
-
        /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
        if (!IS_ERR(mmc->supply.vqmmc)) {
                ret = regulator_enable(mmc->supply.vqmmc);
                if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000,
                                                    1950000))
-                       caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
-                                       SDHCI_SUPPORT_SDR50 |
-                                       SDHCI_SUPPORT_DDR50);
+                       host->caps1 &= ~(SDHCI_SUPPORT_SDR104 |
+                                        SDHCI_SUPPORT_SDR50 |
+                                        SDHCI_SUPPORT_DDR50);
                if (ret) {
                        pr_warn("%s: Failed to enable vqmmc regulator: %d\n",
                                mmc_hostname(mmc), ret);
@@ -3100,28 +3284,30 @@ int sdhci_add_host(struct sdhci_host *host)
                }
        }
 
-       if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
-               caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
-                      SDHCI_SUPPORT_DDR50);
+       if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
+               host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
+                                SDHCI_SUPPORT_DDR50);
+       }
 
        /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
-       if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
-                      SDHCI_SUPPORT_DDR50))
+       if (host->caps1 & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
+                          SDHCI_SUPPORT_DDR50))
                mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
 
        /* SDR104 supports also implies SDR50 support */
-       if (caps[1] & SDHCI_SUPPORT_SDR104) {
+       if (host->caps1 & SDHCI_SUPPORT_SDR104) {
                mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
                /* SD3.0: SDR104 is supported so (for eMMC) the caps2
                 * field can be promoted to support HS200.
                 */
                if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200))
                        mmc->caps2 |= MMC_CAP2_HS200;
-       } else if (caps[1] & SDHCI_SUPPORT_SDR50)
+       } else if (host->caps1 & SDHCI_SUPPORT_SDR50) {
                mmc->caps |= MMC_CAP_UHS_SDR50;
+       }
 
        if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 &&
-           (caps[1] & SDHCI_SUPPORT_HS400))
+           (host->caps1 & SDHCI_SUPPORT_HS400))
                mmc->caps2 |= MMC_CAP2_HS400;
 
        if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) &&
@@ -3130,25 +3316,25 @@ int sdhci_add_host(struct sdhci_host *host)
                                             1300000)))
                mmc->caps2 &= ~MMC_CAP2_HSX00_1_2V;
 
-       if ((caps[1] & SDHCI_SUPPORT_DDR50) &&
-               !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
+       if ((host->caps1 & SDHCI_SUPPORT_DDR50) &&
+           !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
                mmc->caps |= MMC_CAP_UHS_DDR50;
 
        /* Does the host need tuning for SDR50? */
-       if (caps[1] & SDHCI_USE_SDR50_TUNING)
+       if (host->caps1 & SDHCI_USE_SDR50_TUNING)
                host->flags |= SDHCI_SDR50_NEEDS_TUNING;
 
        /* Driver Type(s) (A, C, D) supported by the host */
-       if (caps[1] & SDHCI_DRIVER_TYPE_A)
+       if (host->caps1 & SDHCI_DRIVER_TYPE_A)
                mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
-       if (caps[1] & SDHCI_DRIVER_TYPE_C)
+       if (host->caps1 & SDHCI_DRIVER_TYPE_C)
                mmc->caps |= MMC_CAP_DRIVER_TYPE_C;
-       if (caps[1] & SDHCI_DRIVER_TYPE_D)
+       if (host->caps1 & SDHCI_DRIVER_TYPE_D)
                mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
 
        /* Initial value for re-tuning timer count */
-       host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
-                             SDHCI_RETUNING_TIMER_COUNT_SHIFT;
+       host->tuning_count = (host->caps1 & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
+                            SDHCI_RETUNING_TIMER_COUNT_SHIFT;
 
        /*
         * In case Re-tuning Timer is not disabled, the actual value of
@@ -3158,7 +3344,7 @@ int sdhci_add_host(struct sdhci_host *host)
                host->tuning_count = 1 << (host->tuning_count - 1);
 
        /* Re-tuning mode supported by the Host Controller */
-       host->tuning_mode = (caps[1] & SDHCI_RETUNING_MODE_MASK) >>
+       host->tuning_mode = (host->caps1 & SDHCI_RETUNING_MODE_MASK) >>
                             SDHCI_RETUNING_MODE_SHIFT;
 
        ocr_avail = 0;
@@ -3187,7 +3373,7 @@ int sdhci_add_host(struct sdhci_host *host)
                }
        }
 
-       if (caps[0] & SDHCI_CAN_VDD_330) {
+       if (host->caps & SDHCI_CAN_VDD_330) {
                ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
 
                mmc->max_current_330 = ((max_current_caps &
@@ -3195,7 +3381,7 @@ int sdhci_add_host(struct sdhci_host *host)
                                   SDHCI_MAX_CURRENT_330_SHIFT) *
                                   SDHCI_MAX_CURRENT_MULTIPLIER;
        }
-       if (caps[0] & SDHCI_CAN_VDD_300) {
+       if (host->caps & SDHCI_CAN_VDD_300) {
                ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
 
                mmc->max_current_300 = ((max_current_caps &
@@ -3203,7 +3389,7 @@ int sdhci_add_host(struct sdhci_host *host)
                                   SDHCI_MAX_CURRENT_300_SHIFT) *
                                   SDHCI_MAX_CURRENT_MULTIPLIER;
        }
-       if (caps[0] & SDHCI_CAN_VDD_180) {
+       if (host->caps & SDHCI_CAN_VDD_180) {
                ocr_avail |= MMC_VDD_165_195;
 
                mmc->max_current_180 = ((max_current_caps &
@@ -3240,6 +3426,15 @@ int sdhci_add_host(struct sdhci_host *host)
                goto unreg;
        }
 
+       if ((mmc->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+                         MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+                         MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR)) ||
+           (mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V)))
+               host->flags |= SDHCI_SIGNALING_180;
+
+       if (mmc->caps2 & MMC_CAP2_HSX00_1_2V)
+               host->flags |= SDHCI_SIGNALING_120;
+
        spin_lock_init(&host->lock);
 
        /*
@@ -3281,7 +3476,7 @@ int sdhci_add_host(struct sdhci_host *host)
        if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) {
                mmc->max_blk_size = 2;
        } else {
-               mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >>
+               mmc->max_blk_size = (host->caps & SDHCI_MAX_BLOCK_MASK) >>
                                SDHCI_MAX_BLOCK_SHIFT;
                if (mmc->max_blk_size >= 3) {
                        pr_warn("%s: Invalid maximum block size, assuming 512 bytes\n",
@@ -3297,6 +3492,28 @@ int sdhci_add_host(struct sdhci_host *host)
         */
        mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535;
 
+       return 0;
+
+unreg:
+       if (!IS_ERR(mmc->supply.vqmmc))
+               regulator_disable(mmc->supply.vqmmc);
+undma:
+       if (host->align_buffer)
+               dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
+                                 host->adma_table_sz, host->align_buffer,
+                                 host->align_addr);
+       host->adma_table = NULL;
+       host->align_buffer = NULL;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_setup_host);
+
+int __sdhci_add_host(struct sdhci_host *host)
+{
+       struct mmc_host *mmc = host->mmc;
+       int ret;
+
        /*
         * Init tasklets.
         */
@@ -3304,6 +3521,8 @@ int sdhci_add_host(struct sdhci_host *host)
                sdhci_tasklet_finish, (unsigned long)host);
 
        setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
+       setup_timer(&host->data_timer, sdhci_timeout_data_timer,
+                   (unsigned long)host);
 
        init_waitqueue_head(&host->buf_ready_int);
 
@@ -3353,10 +3572,10 @@ unirq:
        free_irq(host->irq, host);
 untasklet:
        tasklet_kill(&host->finish_tasklet);
-unreg:
+
        if (!IS_ERR(mmc->supply.vqmmc))
                regulator_disable(mmc->supply.vqmmc);
-undma:
+
        if (host->align_buffer)
                dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
                                  host->adma_table_sz, host->align_buffer,
@@ -3366,7 +3585,18 @@ undma:
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(__sdhci_add_host);
+
+int sdhci_add_host(struct sdhci_host *host)
+{
+       int ret;
 
+       ret = sdhci_setup_host(host);
+       if (ret)
+               return ret;
+
+       return __sdhci_add_host(host);
+}
 EXPORT_SYMBOL_GPL(sdhci_add_host);
 
 void sdhci_remove_host(struct sdhci_host *host, int dead)
@@ -3379,12 +3609,10 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 
                host->flags |= SDHCI_DEVICE_DEAD;
 
-               if (host->mrq) {
+               if (sdhci_has_requests(host)) {
                        pr_err("%s: Controller removed during "
                                " transfer!\n", mmc_hostname(mmc));
-
-                       host->mrq->cmd->error = -ENOMEDIUM;
-                       tasklet_schedule(&host->finish_tasklet);
+                       sdhci_error_out_mrqs(host, -ENOMEDIUM);
                }
 
                spin_unlock_irqrestore(&host->lock, flags);
@@ -3404,6 +3632,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
        free_irq(host->irq, host);
 
        del_timer_sync(&host->timer);
+       del_timer_sync(&host->data_timer);
 
        tasklet_kill(&host->finish_tasklet);
 
index 609f87ca536b845abf355ac9032cdc3c45c25ce2..0411c9f364619a5949e999fc4b1b9288504bfcfc 100644 (file)
 #define  SDHCI_INT_CARD_INSERT 0x00000040
 #define  SDHCI_INT_CARD_REMOVE 0x00000080
 #define  SDHCI_INT_CARD_INT    0x00000100
+#define  SDHCI_INT_RETUNE      0x00001000
 #define  SDHCI_INT_ERROR       0x00008000
 #define  SDHCI_INT_TIMEOUT     0x00010000
 #define  SDHCI_INT_CRC         0x00020000
 #define  SDHCI_CAN_DO_ADMA1    0x00100000
 #define  SDHCI_CAN_DO_HISPD    0x00200000
 #define  SDHCI_CAN_DO_SDMA     0x00400000
+#define  SDHCI_CAN_DO_SUSPEND  0x00800000
 #define  SDHCI_CAN_VDD_330     0x01000000
 #define  SDHCI_CAN_VDD_300     0x02000000
 #define  SDHCI_CAN_VDD_180     0x04000000
@@ -314,6 +316,9 @@ struct sdhci_adma2_64_desc {
  */
 #define SDHCI_MAX_SEGS         128
 
+/* Allow for a a command request and a data request at the same time */
+#define SDHCI_MAX_MRQS         2
+
 enum sdhci_cookie {
        COOKIE_UNMAPPED,
        COOKIE_PRE_MAPPED,      /* mapped by sdhci_pre_req() */
@@ -447,6 +452,9 @@ struct sdhci_host {
 #define SDHCI_SDIO_IRQ_ENABLED (1<<9)  /* SDIO irq enabled */
 #define SDHCI_USE_64_BIT_DMA   (1<<12) /* Use 64-bit DMA */
 #define SDHCI_HS400_TUNING     (1<<13) /* Tuning for HS400 */
+#define SDHCI_SIGNALING_330    (1<<14) /* Host is capable of 3.3V signaling */
+#define SDHCI_SIGNALING_180    (1<<15) /* Host is capable of 1.8V signaling */
+#define SDHCI_SIGNALING_120    (1<<16) /* Host is capable of 1.2V signaling */
 
        unsigned int version;   /* SDHCI spec. version */
 
@@ -460,12 +468,13 @@ struct sdhci_host {
        bool runtime_suspended; /* Host is runtime suspended */
        bool bus_on;            /* Bus power prevents runtime suspend */
        bool preset_enabled;    /* Preset is enabled */
+       bool pending_reset;     /* Cmd/data reset is pending */
 
-       struct mmc_request *mrq;        /* Current request */
+       struct mmc_request *mrqs_done[SDHCI_MAX_MRQS];  /* Requests done */
        struct mmc_command *cmd;        /* Current command */
+       struct mmc_command *data_cmd;   /* Current data command */
        struct mmc_data *data;  /* Current data request */
        unsigned int data_early:1;      /* Data finished before cmd */
-       unsigned int busy_handle:1;     /* Handling the order of Busy-end */
 
        struct sg_mapping_iter sg_miter;        /* SG state for PIO */
        unsigned int blocks;    /* remaining PIO blocks */
@@ -486,9 +495,11 @@ struct sdhci_host {
        struct tasklet_struct finish_tasklet;   /* Tasklet structures */
 
        struct timer_list timer;        /* Timer for timeouts */
+       struct timer_list data_timer;   /* Timer for data timeouts */
 
-       u32 caps;               /* Alternative CAPABILITY_0 */
-       u32 caps1;              /* Alternative CAPABILITY_1 */
+       u32 caps;               /* CAPABILITY_0 */
+       u32 caps1;              /* CAPABILITY_1 */
+       bool read_caps;         /* Capability flags have been read */
 
        unsigned int            ocr_avail_sdio; /* OCR bit masks */
        unsigned int            ocr_avail_sd;
@@ -508,6 +519,8 @@ struct sdhci_host {
        unsigned int            tuning_count;   /* Timer count for re-tuning */
        unsigned int            tuning_mode;    /* Re-tuning mode supported by host */
 #define SDHCI_TUNING_MODE_1    0
+#define SDHCI_TUNING_MODE_2    1
+#define SDHCI_TUNING_MODE_3    2
 
        unsigned long private[0] ____cacheline_aligned;
 };
@@ -645,11 +658,20 @@ static inline void *sdhci_priv(struct sdhci_host *host)
 }
 
 extern void sdhci_card_detect(struct sdhci_host *host);
+extern void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps,
+                             u32 *caps1);
+extern int sdhci_setup_host(struct sdhci_host *host);
+extern int __sdhci_add_host(struct sdhci_host *host);
 extern int sdhci_add_host(struct sdhci_host *host);
 extern void sdhci_remove_host(struct sdhci_host *host, int dead);
 extern void sdhci_send_command(struct sdhci_host *host,
                                struct mmc_command *cmd);
 
+static inline void sdhci_read_caps(struct sdhci_host *host)
+{
+       __sdhci_read_caps(host, NULL, NULL, NULL);
+}
+
 static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
 {
        return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED);
index 983b8b32ef960057ea0f09ee309de5e7ae1e842c..111b66f5439bc25a33c8ed1d8e925ce39d417bb1 100644 (file)
@@ -222,7 +222,7 @@ static struct platform_driver sdhci_f_sdh30_driver = {
        .driver = {
                .name = "f_sdh30",
                .of_match_table = f_sdh30_dt_ids,
-               .pm     = SDHCI_PLTFM_PMOPS,
+               .pm     = &sdhci_pltfm_pmops,
        },
        .probe  = sdhci_f_sdh30_probe,
        .remove = sdhci_f_sdh30_remove,
index dd64b86639840287479d8c2a6ae50bc51e8e79ac..900778421be69b22c05ff7fe5c8e8dbc6bd6917d 100644 (file)
@@ -574,7 +574,7 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
        if (state1 & STS1_CMDSEQ) {
                sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
                sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
-               for (timeout = 10000000; timeout; timeout--) {
+               for (timeout = 10000; timeout; timeout--) {
                        if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1)
                              & STS1_CMDSEQ))
                                break;
@@ -819,10 +819,12 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
                tmp |= CMD_SET_RTYP_NO;
                break;
        case MMC_RSP_R1:
-       case MMC_RSP_R1B:
        case MMC_RSP_R3:
                tmp |= CMD_SET_RTYP_6B;
                break;
+       case MMC_RSP_R1B:
+               tmp |= CMD_SET_RBSY | CMD_SET_RTYP_6B;
+               break;
        case MMC_RSP_R2:
                tmp |= CMD_SET_RTYP_17B;
                break;
@@ -830,17 +832,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
                dev_err(dev, "Unsupported response type.\n");
                break;
        }
-       switch (opc) {
-       /* RBSY */
-       case MMC_SLEEP_AWAKE:
-       case MMC_SWITCH:
-       case MMC_STOP_TRANSMISSION:
-       case MMC_SET_WRITE_PROT:
-       case MMC_CLR_WRITE_PROT:
-       case MMC_ERASE:
-               tmp |= CMD_SET_RBSY;
-               break;
-       }
+
        /* WDAT / DATW */
        if (data) {
                tmp |= CMD_SET_WDAT;
@@ -925,23 +917,13 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
 {
        struct mmc_command *cmd = mrq->cmd;
        u32 opc = cmd->opcode;
-       u32 mask;
+       u32 mask = 0;
        unsigned long flags;
 
-       switch (opc) {
-       /* response busy check */
-       case MMC_SLEEP_AWAKE:
-       case MMC_SWITCH:
-       case MMC_STOP_TRANSMISSION:
-       case MMC_SET_WRITE_PROT:
-       case MMC_CLR_WRITE_PROT:
-       case MMC_ERASE:
+       if (cmd->flags & MMC_RSP_BUSY)
                mask = MASK_START_CMD | MASK_MRBSYE;
-               break;
-       default:
+       else
                mask = MASK_START_CMD | MASK_MCRSPE;
-               break;
-       }
 
        if (host->ccs_enable)
                mask |= MASK_MCCSTO;
@@ -1009,22 +991,6 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
        host->state = STATE_REQUEST;
        spin_unlock_irqrestore(&host->lock, flags);
 
-       switch (mrq->cmd->opcode) {
-       /* MMCIF does not support SD/SDIO command */
-       case MMC_SLEEP_AWAKE: /* = SD_IO_SEND_OP_COND (5) */
-       case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
-               if ((mrq->cmd->flags & MMC_CMD_MASK) != MMC_CMD_BCR)
-                       break;
-       case MMC_APP_CMD:
-       case SD_IO_RW_DIRECT:
-               host->state = STATE_IDLE;
-               mrq->cmd->error = -ETIMEDOUT;
-               mmc_request_done(mmc, mrq);
-               return;
-       default:
-               break;
-       }
-
        host->mrq = mrq;
 
        sh_mmcif_start_cmd(host, mrq);
@@ -1488,6 +1454,9 @@ static int sh_mmcif_probe(struct platform_device *pdev)
        sh_mmcif_init_ocr(host);
 
        mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY;
+       mmc->caps2 |= MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
+       mmc->max_busy_timeout = 10000;
+
        if (pd && pd->caps)
                mmc->caps |= pd->caps;
        mmc->max_segs = 32;
index f750f9494410b081ce4196eca62590a9896640ea..c3b651bf89cb4ad5e562ce41cbe1fa20c17c481e 100644 (file)
 
 #define EXT_ACC           0xe4
 
+#define SDHI_VER_GEN2_SDR50    0x490c
+/* very old datasheets said 0x490c for SDR104, too. They are wrong! */
+#define SDHI_VER_GEN2_SDR104   0xcb0d
+#define SDHI_VER_GEN3_SD       0xcc10
+#define SDHI_VER_GEN3_SDMMC    0xcd10
+
 #define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data)
 
 struct sh_mobile_sdhi_of_data {
@@ -109,14 +115,14 @@ static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
         *      sh_mobile_sdhi_of_data :: dma_buswidth
         */
        switch (sd_ctrl_read16(host, CTL_VERSION)) {
-       case 0x490C:
+       case SDHI_VER_GEN2_SDR50:
                val = (width == 32) ? 0x0001 : 0x0000;
                break;
-       case 0xCB0D:
+       case SDHI_VER_GEN2_SDR104:
                val = (width == 32) ? 0x0000 : 0x0001;
                break;
-       case 0xCC10: /* Gen3, SD only */
-       case 0xCD10: /* Gen3, SD + MMC */
+       case SDHI_VER_GEN3_SD:
+       case SDHI_VER_GEN3_SDMMC:
                if (width == 64)
                        val = 0x0000;
                else if (width == 32)
index 1aac2ad8edf265d02a676747e81cee0961ef540e..7f63ec05bdf41d153a7445be88798fd037ae8aaf 100644 (file)
@@ -259,7 +259,7 @@ static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
 
 static inline void sd_ctrl_write32_as_16_and_16(struct tmio_mmc_host *host, int addr, u32 val)
 {
-       writew(val, host->ctl + (addr << host->bus_shift));
+       writew(val & 0xffff, host->ctl + (addr << host->bus_shift));
        writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
 }
 
index f44e2ab7aea2bab15ade6e1104e4bc80eeb3d633..92467efc4e2c9e59676b74a3aee2e280bb0c30e3 100644 (file)
@@ -1086,7 +1086,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
 
        _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
                                  mmc->caps & MMC_CAP_NEEDS_POLL ||
-                                 mmc->caps & MMC_CAP_NONREMOVABLE ||
+                                 !mmc_card_is_removable(mmc) ||
                                  mmc->slot.cd_irq >= 0);
 
        if (tmio_mmc_clk_enable(_host) < 0) {
index 6ebcf3e41c467233c7d198cc72a7b93a4f7fe4b1..fd57345ffed28709c1e76105cb4fd7df32debe1c 100644 (file)
@@ -14,6 +14,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
                ((val) << (shift) | (mask) << ((shift) + 16))
 
 /* Register definition */
-#define GRF_EMMCPHY_CON0       0x0
-#define GRF_EMMCPHY_CON1       0x4
-#define GRF_EMMCPHY_CON2       0x8
-#define GRF_EMMCPHY_CON3       0xc
-#define GRF_EMMCPHY_CON4       0x10
-#define GRF_EMMCPHY_CON5       0x14
-#define GRF_EMMCPHY_CON6       0x18
-#define GRF_EMMCPHY_STATUS     0x20
-
-#define PHYCTRL_PDB_MASK       0x1
-#define PHYCTRL_PDB_SHIFT      0x0
-#define PHYCTRL_PDB_PWR_ON     0x1
-#define PHYCTRL_PDB_PWR_OFF    0x0
-#define PHYCTRL_ENDLL_MASK     0x1
-#define PHYCTRL_ENDLL_SHIFT     0x1
-#define PHYCTRL_ENDLL_ENABLE   0x1
-#define PHYCTRL_ENDLL_DISABLE  0x0
-#define PHYCTRL_CALDONE_MASK   0x1
-#define PHYCTRL_CALDONE_SHIFT   0x6
-#define PHYCTRL_CALDONE_DONE   0x1
-#define PHYCTRL_CALDONE_GOING  0x0
-#define PHYCTRL_DLLRDY_MASK    0x1
-#define PHYCTRL_DLLRDY_SHIFT   0x5
-#define PHYCTRL_DLLRDY_DONE    0x1
-#define PHYCTRL_DLLRDY_GOING   0x0
+#define GRF_EMMCPHY_CON0               0x0
+#define GRF_EMMCPHY_CON1               0x4
+#define GRF_EMMCPHY_CON2               0x8
+#define GRF_EMMCPHY_CON3               0xc
+#define GRF_EMMCPHY_CON4               0x10
+#define GRF_EMMCPHY_CON5               0x14
+#define GRF_EMMCPHY_CON6               0x18
+#define GRF_EMMCPHY_STATUS             0x20
+
+#define PHYCTRL_PDB_MASK               0x1
+#define PHYCTRL_PDB_SHIFT              0x0
+#define PHYCTRL_PDB_PWR_ON             0x1
+#define PHYCTRL_PDB_PWR_OFF            0x0
+#define PHYCTRL_ENDLL_MASK             0x1
+#define PHYCTRL_ENDLL_SHIFT            0x1
+#define PHYCTRL_ENDLL_ENABLE           0x1
+#define PHYCTRL_ENDLL_DISABLE          0x0
+#define PHYCTRL_CALDONE_MASK           0x1
+#define PHYCTRL_CALDONE_SHIFT          0x6
+#define PHYCTRL_CALDONE_DONE           0x1
+#define PHYCTRL_CALDONE_GOING          0x0
+#define PHYCTRL_DLLRDY_MASK            0x1
+#define PHYCTRL_DLLRDY_SHIFT           0x5
+#define PHYCTRL_DLLRDY_DONE            0x1
+#define PHYCTRL_DLLRDY_GOING           0x0
+#define PHYCTRL_FREQSEL_200M           0x0
+#define PHYCTRL_FREQSEL_50M            0x1
+#define PHYCTRL_FREQSEL_100M           0x2
+#define PHYCTRL_FREQSEL_150M           0x3
+#define PHYCTRL_FREQSEL_MASK           0x3
+#define PHYCTRL_FREQSEL_SHIFT          0xc
+#define PHYCTRL_DR_MASK                        0x7
+#define PHYCTRL_DR_SHIFT               0x4
+#define PHYCTRL_DR_50OHM               0x0
+#define PHYCTRL_DR_33OHM               0x1
+#define PHYCTRL_DR_66OHM               0x2
+#define PHYCTRL_DR_100OHM              0x3
+#define PHYCTRL_DR_40OHM               0x4
+#define PHYCTRL_OTAPDLYENA             0x1
+#define PHYCTRL_OTAPDLYENA_MASK                0x1
+#define PHYCTRL_OTAPDLYENA_SHIFT       0xb
+#define PHYCTRL_OTAPDLYSEL_MASK                0xf
+#define PHYCTRL_OTAPDLYSEL_SHIFT       0x7
 
 struct rockchip_emmc_phy {
        unsigned int    reg_offset;
        struct regmap   *reg_base;
+       struct clk      *emmcclk;
 };
 
-static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
-                                  bool on_off)
+static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
 {
+       struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
        unsigned int caldone;
        unsigned int dllrdy;
+       unsigned int freqsel = PHYCTRL_FREQSEL_200M;
+       unsigned long rate;
+       unsigned long timeout;
 
        /*
         * Keep phyctrl_pdb and phyctrl_endll low to allow
@@ -87,6 +110,43 @@ static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
        if (on_off == PHYCTRL_PDB_PWR_OFF)
                return 0;
 
+       rate = clk_get_rate(rk_phy->emmcclk);
+
+       if (rate != 0) {
+               unsigned long ideal_rate;
+               unsigned long diff;
+
+               switch (rate) {
+               case 1 ... 74999999:
+                       ideal_rate = 50000000;
+                       freqsel = PHYCTRL_FREQSEL_50M;
+                       break;
+               case 75000000 ... 124999999:
+                       ideal_rate = 100000000;
+                       freqsel = PHYCTRL_FREQSEL_100M;
+                       break;
+               case 125000000 ... 174999999:
+                       ideal_rate = 150000000;
+                       freqsel = PHYCTRL_FREQSEL_150M;
+                       break;
+               default:
+                       ideal_rate = 200000000;
+                       break;
+               };
+
+               diff = (rate > ideal_rate) ?
+                       rate - ideal_rate : ideal_rate - rate;
+
+               /*
+                * In order for tuning delays to be accurate we need to be
+                * pretty spot on for the DLL range, so warn if we're too
+                * far off.  Also warn if we're above the 200 MHz max.  Don't
+                * warn for really slow rates since we won't be tuning then.
+                */
+               if ((rate > 50000000 && diff > 15000000) || (rate > 200000000))
+                       dev_warn(&phy->dev, "Unsupported rate: %lu\n", rate);
+       }
+
        /*
         * According to the user manual, calpad calibration
         * cycle takes more than 2us without the minimal recommended
@@ -113,20 +173,62 @@ static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
                return -ETIMEDOUT;
        }
 
+       /* Set the frequency of the DLL operation */
+       regmap_write(rk_phy->reg_base,
+                    rk_phy->reg_offset + GRF_EMMCPHY_CON0,
+                    HIWORD_UPDATE(freqsel, PHYCTRL_FREQSEL_MASK,
+                                  PHYCTRL_FREQSEL_SHIFT));
+
+       /* Turn on the DLL */
        regmap_write(rk_phy->reg_base,
                     rk_phy->reg_offset + GRF_EMMCPHY_CON6,
                     HIWORD_UPDATE(PHYCTRL_ENDLL_ENABLE,
                                   PHYCTRL_ENDLL_MASK,
                                   PHYCTRL_ENDLL_SHIFT));
+
        /*
-        * After enable analog DLL circuits, we need extra 10.2us
-        * for dll to be ready for work.
+        * We turned on the DLL even though the rate was 0 because we the
+        * clock might be turned on later.  ...but we can't wait for the DLL
+        * to lock when the rate is 0 because it will never lock with no
+        * input clock.
+        *
+        * Technically we should be checking the lock later when the clock
+        * is turned on, but for now we won't.
         */
-       udelay(11);
-       regmap_read(rk_phy->reg_base,
-                   rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
-                   &dllrdy);
-       dllrdy = (dllrdy >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK;
+       if (rate == 0)
+               return 0;
+
+       /*
+        * After enabling analog DLL circuits docs say that we need 10.2 us if
+        * our source clock is at 50 MHz and that lock time scales linearly
+        * with clock speed.  If we are powering on the PHY and the card clock
+        * is super slow (like 100 kHZ) this could take as long as 5.1 ms as
+        * per the math: 10.2 us * (50000000 Hz / 100000 Hz) => 5.1 ms
+        * Hopefully we won't be running at 100 kHz, but we should still make
+        * sure we wait long enough.
+        *
+        * NOTE: There appear to be corner cases where the DLL seems to take
+        * extra long to lock for reasons that aren't understood.  In some
+        * extreme cases we've seen it take up to over 10ms (!).  We'll be
+        * generous and give it 50ms.  We still busy wait here because:
+        * - In most cases it should be super fast.
+        * - This is not called lots during normal operation so it shouldn't
+        *   be a power or performance problem to busy wait.  We expect it
+        *   only at boot / resume.  In both cases, eMMC is probably on the
+        *   critical path so busy waiting a little extra time should be OK.
+        */
+       timeout = jiffies + msecs_to_jiffies(50);
+       do {
+               udelay(1);
+
+               regmap_read(rk_phy->reg_base,
+                       rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
+                       &dllrdy);
+               dllrdy = (dllrdy >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK;
+               if (dllrdy == PHYCTRL_DLLRDY_DONE)
+                       break;
+       } while (!time_after(jiffies, timeout));
+
        if (dllrdy != PHYCTRL_DLLRDY_DONE) {
                pr_err("rockchip_emmc_phy_power: dllrdy timeout.\n");
                return -ETIMEDOUT;
@@ -135,33 +237,82 @@ static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
        return 0;
 }
 
-static int rockchip_emmc_phy_power_off(struct phy *phy)
+static int rockchip_emmc_phy_init(struct phy *phy)
 {
        struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
        int ret = 0;
 
-       /* Power down emmc phy analog blocks */
-       ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_OFF);
-       if (ret)
-               return ret;
+       /*
+        * We purposely get the clock here and not in probe to avoid the
+        * circular dependency problem.  We expect:
+        * - PHY driver to probe
+        * - SDHCI driver to start probe
+        * - SDHCI driver to register it's clock
+        * - SDHCI driver to get the PHY
+        * - SDHCI driver to init the PHY
+        *
+        * The clock is optional, so upon any error we just set to NULL.
+        *
+        * NOTE: we don't do anything special for EPROBE_DEFER here.  Given the
+        * above expected use case, EPROBE_DEFER isn't sensible to expect, so
+        * it's just like any other error.
+        */
+       rk_phy->emmcclk = clk_get(&phy->dev, "emmcclk");
+       if (IS_ERR(rk_phy->emmcclk)) {
+               dev_dbg(&phy->dev, "Error getting emmcclk: %d\n", ret);
+               rk_phy->emmcclk = NULL;
+       }
+
+       return ret;
+}
+
+static int rockchip_emmc_phy_exit(struct phy *phy)
+{
+       struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
+
+       clk_put(rk_phy->emmcclk);
 
        return 0;
 }
 
+static int rockchip_emmc_phy_power_off(struct phy *phy)
+{
+       /* Power down emmc phy analog blocks */
+       return rockchip_emmc_phy_power(phy, PHYCTRL_PDB_PWR_OFF);
+}
+
 static int rockchip_emmc_phy_power_on(struct phy *phy)
 {
        struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
-       int ret = 0;
 
-       /* Power up emmc phy analog blocks */
-       ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_ON);
-       if (ret)
-               return ret;
+       /* Drive impedance: 50 Ohm */
+       regmap_write(rk_phy->reg_base,
+                    rk_phy->reg_offset + GRF_EMMCPHY_CON6,
+                    HIWORD_UPDATE(PHYCTRL_DR_50OHM,
+                                  PHYCTRL_DR_MASK,
+                                  PHYCTRL_DR_SHIFT));
 
-       return 0;
+       /* Output tap delay: enable */
+       regmap_write(rk_phy->reg_base,
+                    rk_phy->reg_offset + GRF_EMMCPHY_CON0,
+                    HIWORD_UPDATE(PHYCTRL_OTAPDLYENA,
+                                  PHYCTRL_OTAPDLYENA_MASK,
+                                  PHYCTRL_OTAPDLYENA_SHIFT));
+
+       /* Output tap delay */
+       regmap_write(rk_phy->reg_base,
+                    rk_phy->reg_offset + GRF_EMMCPHY_CON0,
+                    HIWORD_UPDATE(4,
+                                  PHYCTRL_OTAPDLYSEL_MASK,
+                                  PHYCTRL_OTAPDLYSEL_SHIFT));
+
+       /* Power up emmc phy analog blocks */
+       return rockchip_emmc_phy_power(phy, PHYCTRL_PDB_PWR_ON);
 }
 
 static const struct phy_ops ops = {
+       .init           = rockchip_emmc_phy_init,
+       .exit           = rockchip_emmc_phy_exit,
        .power_on       = rockchip_emmc_phy_power_on,
        .power_off      = rockchip_emmc_phy_power_off,
        .owner          = THIS_MODULE,
index eb0151bac50c1fd796f479d017bc3c3d7017c9e9..d8673ca968ba2d65fb3da39680583ca5152641e4 100644 (file)
@@ -95,6 +95,7 @@ struct mmc_ext_csd {
        u8                      raw_partition_support;  /* 160 */
        u8                      raw_rpmb_size_mult;     /* 168 */
        u8                      raw_erased_mem_count;   /* 181 */
+       u8                      strobe_support;         /* 184 */
        u8                      raw_ext_csd_structure;  /* 194 */
        u8                      raw_card_type;          /* 196 */
        u8                      raw_driver_strength;    /* 197 */
@@ -279,6 +280,7 @@ struct mmc_card {
 #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 */
+#define MMC_QUIRK_BROKEN_HPI   (1<<13)         /* Disable broken HPI support */
 
 
        unsigned int            erase_size;     /* erase size in sectors */
@@ -353,6 +355,9 @@ struct mmc_fixup {
        /* SDIO-specfic fields. You can use SDIO_ANY_ID here of course */
        u16 cis_vendor, cis_device;
 
+       /* for MMC cards */
+       unsigned int ext_csd_rev;
+
        void (*vendor_fixup)(struct mmc_card *card, int data);
        int data;
 };
@@ -361,11 +366,20 @@ struct mmc_fixup {
 #define CID_OEMID_ANY ((unsigned short) -1)
 #define CID_NAME_ANY (NULL)
 
+#define EXT_CSD_REV_ANY (-1u)
+
+#define CID_MANFID_SANDISK      0x2
+#define CID_MANFID_TOSHIBA      0x11
+#define CID_MANFID_MICRON       0x13
+#define CID_MANFID_SAMSUNG      0x15
+#define CID_MANFID_KINGSTON     0x70
+#define CID_MANFID_HYNIX       0x90
+
 #define END_FIXUP { NULL }
 
 #define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end,       \
                   _cis_vendor, _cis_device,                            \
-                  _fixup, _data)                                       \
+                  _fixup, _data, _ext_csd_rev)                         \
        {                                                  \
                .name = (_name),                           \
                .manfid = (_manfid),                       \
@@ -376,23 +390,30 @@ struct mmc_fixup {
                .cis_device = (_cis_device),               \
                .vendor_fixup = (_fixup),                  \
                .data = (_data),                           \
+               .ext_csd_rev = (_ext_csd_rev),             \
         }
 
 #define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end,    \
-                     _fixup, _data)                                    \
+                     _fixup, _data, _ext_csd_rev)                      \
        _FIXUP_EXT(_name, _manfid,                                      \
                   _oemid, _rev_start, _rev_end,                        \
                   SDIO_ANY_ID, SDIO_ANY_ID,                            \
-                  _fixup, _data)                                       \
+                  _fixup, _data, _ext_csd_rev)                         \
 
 #define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \
-       MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data)
+       MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data,  \
+                     EXT_CSD_REV_ANY)
+
+#define MMC_FIXUP_EXT_CSD_REV(_name, _manfid, _oemid, _fixup, _data,   \
+                             _ext_csd_rev)                             \
+       MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data,  \
+                     _ext_csd_rev)
 
 #define SDIO_FIXUP(_vendor, _device, _fixup, _data)                    \
        _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY,                        \
                    CID_OEMID_ANY, 0, -1ull,                            \
                   _vendor, _device,                                    \
-                  _fixup, _data)                                       \
+                  _fixup, _data, EXT_CSD_REV_ANY)                      \
 
 #define cid_rev(hwrev, fwrev, year, month)     \
        (((u64) hwrev) << 40 |                  \
@@ -511,6 +532,11 @@ static inline int mmc_card_broken_irq_polling(const struct mmc_card *c)
        return c->quirks & MMC_QUIRK_BROKEN_IRQ_POLLING;
 }
 
+static inline int mmc_card_broken_hpi(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_BROKEN_HPI;
+}
+
 #define mmc_card_name(c)       ((c)->cid.prod_name)
 #define mmc_card_id(c)         (dev_name(&(c)->dev))
 
index f7ed271a1d54573e45cf8bcd834cc0363784f2ef..83b0edfce471c2a9ab536a5ae616e070ac34fc9e 100644 (file)
@@ -112,7 +112,6 @@ struct dw_mci_dma_slave {
  * @part_buf: Simple buffer for partial fifo reads/writes.
  * @push_data: Pointer to FIFO push function.
  * @pull_data: Pointer to FIFO pull function.
- * @quirks: Set of quirks that apply to specific versions of the IP.
  * @vqmmc_enabled: Status of vqmmc, should be true or false.
  * @irq_flags: The flags to be passed to request_irq.
  * @irq: The irq value to be passed to request_irq.
@@ -218,9 +217,6 @@ struct dw_mci {
        void (*push_data)(struct dw_mci *host, void *buf, int cnt);
        void (*pull_data)(struct dw_mci *host, void *buf, int cnt);
 
-       /* Workaround flags */
-       u32                     quirks;
-
        bool                    vqmmc_enabled;
        unsigned long           irq_flags; /* IRQ flags */
        int                     irq;
@@ -242,17 +238,12 @@ struct dw_mci_dma_ops {
        void (*exit)(struct dw_mci *host);
 };
 
-/* IP Quirks/flags. */
-/* Timer for broken data transfer over scheme */
-#define DW_MCI_QUIRK_BROKEN_DTO                        BIT(0)
-
 struct dma_pdata;
 
 /* Board platform data */
 struct dw_mci_board {
        u32 num_slots;
 
-       u32 quirks; /* Workaround / Quirk flags */
        unsigned int bus_hz; /* Clock speed at the cclk_in pad */
 
        u32 caps;       /* Capabilities */
index 45cde8cd39f2434f5f9ec02c702a91a7f6b971c9..aa4bfbf129e4585ebb89b25fca4b03c928925022 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -77,6 +78,8 @@ struct mmc_ios {
 #define MMC_SET_DRIVER_TYPE_A  1
 #define MMC_SET_DRIVER_TYPE_C  2
 #define MMC_SET_DRIVER_TYPE_D  3
+
+       bool enhanced_strobe;                   /* hs400es selection */
 };
 
 struct mmc_host_ops {
@@ -143,6 +146,9 @@ struct mmc_host_ops {
 
        /* Prepare HS400 target operating frequency depending host driver */
        int     (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
+       /* Prepare enhanced strobe depending host driver */
+       void    (*hs400_enhanced_strobe)(struct mmc_host *host,
+                                        struct mmc_ios *ios);
        int     (*select_drive_strength)(struct mmc_card *card,
                                         unsigned int max_dtr, int host_drv,
                                         int card_drv, int *drv_type);
@@ -302,6 +308,9 @@ struct mmc_host {
 #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
 #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)    /* No physical write protect pin, assume that card is always read-write */
 #define MMC_CAP2_NO_SDIO       (1 << 19)       /* Do not send SDIO commands during initialization */
+#define MMC_CAP2_HS400_ES      (1 << 20)       /* Host supports enhanced strobe */
+#define MMC_CAP2_NO_SD         (1 << 21)       /* Do not send SD commands during initialization */
+#define MMC_CAP2_NO_MMC                (1 << 22)       /* Do not send (e)MMC commands during initialization */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
@@ -513,6 +522,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
        return card->host->ios.timing == MMC_TIMING_MMC_HS400;
 }
 
+static inline bool mmc_card_hs400es(struct mmc_card *card)
+{
+       return card->host->ios.enhanced_strobe;
+}
+
 void mmc_retune_timer_stop(struct mmc_host *host);
 
 static inline void mmc_retune_needed(struct mmc_host *host)
index 15f2c4a0a62cbfa3d7751d91be7ebc3bbf6ec645..c376209c70ef4424e19e342c441670439c8a7d68 100644 (file)
@@ -297,6 +297,7 @@ struct _mmc_csd {
 #define EXT_CSD_PART_CONFIG            179     /* R/W */
 #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
 #define EXT_CSD_BUS_WIDTH              183     /* R/W */
+#define EXT_CSD_STROBE_SUPPORT         184     /* RO */
 #define EXT_CSD_HS_TIMING              185     /* R/W */
 #define EXT_CSD_POWER_CLASS            187     /* R/W */
 #define EXT_CSD_REV                    192     /* RO */
@@ -380,12 +381,14 @@ struct _mmc_csd {
 #define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<7)  /* Card can run at 200MHz DDR, 1.2V */
 #define EXT_CSD_CARD_TYPE_HS400                (EXT_CSD_CARD_TYPE_HS400_1_8V | \
                                         EXT_CSD_CARD_TYPE_HS400_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400ES      (1<<8)  /* Card can run at HS400ES */
 
 #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8    2       /* Card is in 8 bit mode */
 #define EXT_CSD_DDR_BUS_WIDTH_4        5       /* Card is in 4 bit DDR mode */
 #define EXT_CSD_DDR_BUS_WIDTH_8        6       /* Card is in 8 bit DDR mode */
+#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)        /* Enhanced strobe mode */
 
 #define EXT_CSD_TIMING_BC      0       /* Backwards compatility */
 #define EXT_CSD_TIMING_HS      1       /* High speed */
index 95ccab3f454a9511a27acc7cf351eac52a5dbdb5..7daa78a2f34223948b4a6c47c3f2e10f15ca01ad 100644 (file)
@@ -46,5 +46,6 @@ struct esdhc_platform_data {
        bool support_vsel;
        unsigned int delay_line;
        unsigned int tuning_step;       /* The delay cell steps in tuning procedure */
+       unsigned int tuning_start_tap;  /* The start delay cell point in tuning procedure */
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */