Merge tag 'mmc-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 5 Jun 2018 23:11:43 +0000 (16:11 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 5 Jun 2018 23:11:43 +0000 (16:11 -0700)
Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Decrease polling rate for erase/trim/discard
   - Allow non-sleeping GPIOs for card detect
   - Improve mmc block removal path
   - Enable support for mmc_sw_reset() for SDIO cards
   - Add mmc_sw_reset() to allow users to do a soft reset of the card
   - Allow power delay to be tunable via DT
   - Allow card detect debounce delay to be tunable via DT
   - Enable new quirk to limit clock rate for Marvell 8887 chip
   - Don't show eMMC RPMB and BOOT areas in /proc/partitions
   - Add capability to avoid 3.3V signaling for fragile HWs

  MMC host:
   - Improve/fixup support for handle highmem pages
   - Remove depends on HAS_DMA in case of platform dependency
   - mvsdio: Enable support for erase/trim/discard
   - rtsx_usb: Enable support for erase/trim/discard
   - renesas_sdhi: Fix WP logic regressions
   - renesas_sdhi: Add r8a77965 support
   - renesas_sdhi: Add R8A77980 to whitelist
   - meson: Add optional support for device reset
   - meson: Add support for the Meson-AXG platform
   - dw_mmc: Add new driver for BlueField DW variant
   - mediatek: Add support for 64G DRAM DMA
   - sunxi: Deploy runtime PM support
   - jz4740: Add support for JZ4780
   - jz4740: Enable support for DT based platforms
   - sdhci: Various improvement to timeout handling
   - sdhci: Disable support for HS200/HS400/UHS when no 1.8V support
   - sdhci-omap: Add support for controller in k2g SoC
   - sdhci-omap: Add workarounds for a couple of Erratas
   - sdhci-omap: Enable support for generic sdhci DT properties
   - sdhci-cadence: Re-send tune request to deal with errata
   - sdhci-pci: Fix 3.3V voltage switch for some BYT-based Intel controllers
   - sdhci-pci: Avoid 3.3V signaling on some NI 904x
   - sdhci-esdhc-imx: Use watermark levels for PIO access
   - sdhci-msm: Improve card detection handling
   - sdhci-msm: Add support voltage pad switching"

* tag 'mmc-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (104 commits)
  mmc: renesas_sdhi: really fix WP logic regressions
  mmc: mvsdio: Enable MMC_CAP_ERASE
  mmc: mvsdio: Respect card busy time out from mmc core
  mmc: sdhci-msm: Remove NO_CARD_NO_RESET quirk
  mmc: sunxi: Use ifdef rather than __maybe_unused
  mmc: mxmmc: Use ifdef rather than __maybe_unused
  mmc: mxmmc: include linux/highmem.h
  mmc: sunxi: mark PM functions as __maybe_unused
  mmc: Throttle calls to MMC_SEND_STATUS during mmc_do_erase()
  mmc: au1xmmc: handle highmem pages
  mmc: Allow non-sleeping GPIO cd
  mmc: sdhci-*: Don't emit error msg if sdhci_add_host() fails
  mmc: sd: Define name for default speed dtr
  mmc: core: Move calls to ->prepare_hs400_tuning() closer to mmc code
  mmc: sdhci-xenon: use match_string() helper
  mmc: wbsd: handle highmem pages
  mmc: ushc: handle highmem pages
  mmc: mxcmmc: handle highmem pages
  mmc: atmel-mci: use sg_copy_{from,to}_buffer
  mmc: android-goldfish: use sg_copy_{from,to}_buffer
  ...

66 files changed:
Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt
Documentation/devicetree/bindings/mmc/bluefield-dw-mshc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/jz4740.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/sdhci-omap.txt
Documentation/devicetree/bindings/mmc/tmio_mmc.txt
arch/mips/boot/dts/ingenic/ci20.dts
arch/mips/boot/dts/ingenic/jz4780.dtsi
arch/mips/configs/ci20_defconfig
drivers/mmc/core/block.c
drivers/mmc/core/card.h
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/pwrseq_simple.c
drivers/mmc/core/quirks.h
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/core/slot-gpio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/android-goldfish.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/au1xmmc.c
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/dw_mmc-bluefield.c [new file with mode: 0644]
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/meson-gx-mmc.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/renesas_sdhi_core.c
drivers/mmc/host/renesas_sdhi_internal_dmac.c
drivers/mmc/host/renesas_sdhi_sys_dmac.c
drivers/mmc/host/rtsx_usb_sdmmc.c
drivers/mmc/host/sdhci-bcm-kona.c
drivers/mmc/host/sdhci-cadence.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-arasan.c
drivers/mmc/host/sdhci-omap.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci-pci.h
drivers/mmc/host/sdhci-pic32.c
drivers/mmc/host/sdhci-pxav2.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci-st.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci-xenon-phy.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sunxi-mmc.c
drivers/mmc/host/ushc.c
drivers/mmc/host/wbsd.c
drivers/mmc/host/wmt-sdmmc.c
include/dt-bindings/dma/jz4780-dma.h [new file with mode: 0644]
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmc/sdio_ids.h

index 50bf611a4d2c01a3488c538a17334af3d1706093..13e70409e8ac6250676eba2d6e31be6187410168 100644 (file)
@@ -12,6 +12,7 @@ Required properties:
   - "amlogic,meson-gxbb-mmc"
   - "amlogic,meson-gxl-mmc"
   - "amlogic,meson-gxm-mmc"
+  - "amlogic,meson-axg-mmc"
 - clocks     : A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
 - clock-names: Should contain the following:
        "core" - Main peripheral bus clock
@@ -19,6 +20,7 @@ Required properties:
        "clkin1" - Other parent clock of internal mux
   The driver has an internal mux clock which switches between clkin0 and clkin1 depending on the
   clock rate requested by the MMC core.
+- resets     : phandle of the internal reset line
 
 Example:
 
@@ -29,4 +31,5 @@ Example:
                clocks = <&clkc CLKID_SD_EMMC_A>, <&xtal>, <&clkc CLKID_FCLK_DIV2>;
                clock-names = "core", "clkin0", "clkin1";
                pinctrl-0 = <&emmc_pins>;
+               resets = <&reset RESET_SD_EMMC_A>;
        };
diff --git a/Documentation/devicetree/bindings/mmc/bluefield-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/bluefield-dw-mshc.txt
new file mode 100644 (file)
index 0000000..b0f0999
--- /dev/null
@@ -0,0 +1,29 @@
+* Mellanox Bluefield SoC specific extensions to the Synopsys Designware
+  Mobile Storage Host Controller
+
+Read synopsys-dw-mshc.txt for more details
+
+The Synopsys designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core Synopsys dw mshc controller properties described
+by synopsys-dw-mshc.txt and the properties used by the Mellanox Bluefield SoC
+specific extensions to the Synopsys Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be one of the following.
+  - "mellanox,bluefield-dw-mshc": for controllers with Mellanox Bluefield SoC
+    specific extensions.
+
+Example:
+
+       /* Mellanox Bluefield SoC MMC */
+       mmc@6008000 {
+               compatible = "mellanox,bluefield-dw-mshc";
+               reg = <0x6008000 0x400>;
+               interrupts = <32>;
+               fifo-depth = <0x100>;
+               clock-frequency = <24000000>;
+               bus-width = <8>;
+               cap-mmc-highspeed;
+       };
diff --git a/Documentation/devicetree/bindings/mmc/jz4740.txt b/Documentation/devicetree/bindings/mmc/jz4740.txt
new file mode 100644 (file)
index 0000000..7cd8c43
--- /dev/null
@@ -0,0 +1,38 @@
+* Ingenic JZ47xx MMC controllers
+
+This file documents the device tree properties used for the MMC controller in
+Ingenic JZ4740/JZ4780 SoCs. These are in addition to the core MMC properties
+described in mmc.txt.
+
+Required properties:
+- compatible: Should be one of the following:
+  - "ingenic,jz4740-mmc" for the JZ4740
+  - "ingenic,jz4780-mmc" for the JZ4780
+- reg: Should contain the MMC controller registers location and length.
+- interrupts: Should contain the interrupt specifier of the MMC controller.
+- clocks: Clock for the MMC controller.
+
+Optional properties:
+- dmas: List of DMA specifiers with the controller specific format
+        as described in the generic DMA client binding. A tx and rx
+        specifier is required.
+- dma-names: RX and TX  DMA request names.
+        Should be "rx" and "tx", in that order.
+
+For additional details on DMA client bindings see ../dma/dma.txt.
+
+Example:
+
+mmc0: mmc@13450000 {
+       compatible = "ingenic,jz4780-mmc";
+       reg = <0x13450000 0x1000>;
+
+       interrupt-parent = <&intc>;
+       interrupts = <37>;
+
+       clocks = <&cgu JZ4780_CLK_MSC0>;
+       clock-names = "mmc";
+
+       dmas = <&dma JZ4780_DMA_MSC0_RX 0xffffffff>, <&dma JZ4780_DMA_MSC0_TX 0xffffffff>;
+       dma-names = "rx", "tx";
+};
index 467cd7b147ced43de21bbe12c8ad5d414f758b85..f5a0923b34ca1e5dfd11f3c9ba03792a6963b5c7 100644 (file)
@@ -19,6 +19,8 @@ Optional properties:
 - wp-gpios: Specify GPIOs for write protection, see gpio binding
 - cd-inverted: when present, polarity on the CD line is inverted. See the note
   below for the case, when a GPIO is used for the CD line
+- cd-debounce-delay-ms: Set delay time before detecting card after card insert interrupt.
+  It's only valid when cd-gpios is present.
 - wp-inverted: when present, polarity on the WP line is inverted. See the note
   below for the case, when a GPIO is used for the WP line
 - disable-wp: When set no physical WP line is present. This property should
@@ -56,6 +58,10 @@ Optional properties:
 - fixed-emmc-driver-type: for non-removable eMMC, enforce this driver type.
   The value <n> is the driver type as specified in the eMMC specification
   (table 206 in spec version 5.1).
+- post-power-on-delay-ms : It was invented for MMC pwrseq-simple which could
+  be referred to mmc-pwrseq-simple.txt. But now it's reused as a tunable delay
+  waiting for I/O signalling and card power supply to be stable, regardless of
+  whether pwrseq-simple is used. Default to 10ms if no available.
 
 *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 51775a372c0651eca1d063d5af0737cc7eac49bc..393848c2138e86f5cc026f1fd04cc68e85916c79 100644 (file)
@@ -4,7 +4,14 @@ Refer to mmc.txt for standard MMC bindings.
 
 Required properties:
 - compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
+             Should be "ti,k2g-sdhci" for K2G
 - ti,hwmods: Must be "mmc<n>", <n> is controller instance starting 1
+            (Not required for K2G).
+- pinctrl-names: Should be subset of "default", "hs", "sdr12", "sdr25", "sdr50",
+                "ddr50-rev11", "sdr104-rev11", "ddr50", "sdr104",
+                "ddr_1_8v-rev11", "ddr_1_8v" or "ddr_3_3v", "hs200_1_8v-rev11",
+                "hs200_1_8v",
+- pinctrl-<n> : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt
 
 Example:
        mmc1: mmc@4809c000 {
index 2d5287eeed953b93314c91a9560db28177e46867..ee978c95189d729447b18dc7d075cf1a2a71fd3e 100644 (file)
@@ -26,6 +26,8 @@ Required properties:
                "renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
                "renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
                "renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
+               "renesas,sdhi-r8a77965" - SDHI IP on R8A77965 SoC
+               "renesas,sdhi-r8a77980" - SDHI IP on R8A77980 SoC
                "renesas,sdhi-r8a77995" - SDHI IP on R8A77995 SoC
                "renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller
                "renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
index 38078594cf97ed5d7d6c99b8a2a09290aec2aba3..50cff3cbcc6de6386d11b07cdbe5a10b60ef976f 100644 (file)
        clock-frequency = <48000000>;
 };
 
+&mmc0 {
+       status = "okay";
+
+       bus-width = <4>;
+       max-frequency = <50000000>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pins_mmc0>;
+
+       cd-gpios = <&gpf 20 GPIO_ACTIVE_LOW>;
+};
+
+&mmc1 {
+       status = "okay";
+
+       bus-width = <4>;
+       max-frequency = <50000000>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pins_mmc1>;
+};
+
 &uart0 {
        status = "okay";
 
                groups = "nemc-cs6";
                bias-disable;
        };
+
+       pins_mmc0: mmc0 {
+               function = "mmc0";
+               groups = "mmc0-1bit-e", "mmc0-4bit-e";
+               bias-disable;
+       };
+
+       pins_mmc1: mmc1 {
+               function = "mmc1";
+               groups = "mmc1-1bit-d", "mmc1-4bit-d";
+               bias-disable;
+       };
 };
index 9b5794667aee2eeb33e76e3829948f16fd81ea99..b72e53bb7292e941562ac0c1a1eb14b803609499 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <dt-bindings/clock/jz4780-cgu.h>
+#include <dt-bindings/dma/jz4780-dma.h>
 
 / {
        #address-cells = <1>;
                status = "disabled";
        };
 
+       dma: dma@13420000 {
+               compatible = "ingenic,jz4780-dma";
+               reg = <0x13420000 0x10000>;
+               #dma-cells = <2>;
+
+               interrupt-parent = <&intc>;
+               interrupts = <10>;
+
+               clocks = <&cgu JZ4780_CLK_PDMA>;
+       };
+
+       mmc0: mmc@13450000 {
+               compatible = "ingenic,jz4780-mmc";
+               reg = <0x13450000 0x1000>;
+
+               interrupt-parent = <&intc>;
+               interrupts = <37>;
+
+               clocks = <&cgu JZ4780_CLK_MSC0>;
+               clock-names = "mmc";
+
+               cap-sd-highspeed;
+               cap-mmc-highspeed;
+               cap-sdio-irq;
+               dmas = <&dma JZ4780_DMA_MSC0_RX 0xffffffff>,
+                      <&dma JZ4780_DMA_MSC0_TX 0xffffffff>;
+               dma-names = "rx", "tx";
+
+               status = "disabled";
+       };
+
+       mmc1: mmc@13460000 {
+               compatible = "ingenic,jz4780-mmc";
+               reg = <0x13460000 0x1000>;
+
+               interrupt-parent = <&intc>;
+               interrupts = <36>;
+
+               clocks = <&cgu JZ4780_CLK_MSC1>;
+               clock-names = "mmc";
+
+               cap-sd-highspeed;
+               cap-mmc-highspeed;
+               cap-sdio-irq;
+               dmas = <&dma JZ4780_DMA_MSC1_RX 0xffffffff>,
+                      <&dma JZ4780_DMA_MSC1_TX 0xffffffff>;
+               dma-names = "rx", "tx";
+
+               status = "disabled";
+       };
+
        bch: bch@134d0000 {
                compatible = "ingenic,jz4780-bch";
                reg = <0x134d0000 0x10000>;
index b5f4ad8f2c45025e39b26e8fd8285d85f4b2a4cc..be23fd25eeaa5c89f0e22efc22ba85e22e3a93c4 100644 (file)
@@ -104,10 +104,14 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
+CONFIG_MMC_JZ4740=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_JZ4740=y
+CONFIG_DMADEVICES=y
+CONFIG_DMA_JZ4780=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_MEMORY=y
+CONFIG_EXT4_FS=y
 # CONFIG_DNOTIFY is not set
 CONFIG_PROC_KCORE=y
 # CONFIG_PROC_PAGE_MONITOR is not set
index d89e17829527cdb6147a2e8ae1999dac77c3ec9d..a0b9102c4c6e10dca0472328e7f97631863a9208 100644 (file)
@@ -2351,7 +2351,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
        set_disk_ro(md->disk, md->read_only || default_ro);
        md->disk->flags = GENHD_FL_EXT_DEVT;
        if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
-               md->disk->flags |= GENHD_FL_NO_PART_SCAN;
+               md->disk->flags |= GENHD_FL_NO_PART_SCAN
+                                  | GENHD_FL_SUPPRESS_PARTITION_INFO;
 
        /*
         * As discussed on lkml, GENHD_FL_REMOVABLE should:
@@ -2965,9 +2966,11 @@ static void mmc_blk_remove(struct mmc_card *card)
        mmc_blk_remove_debugfs(card, md);
        mmc_blk_remove_parts(card, md);
        pm_runtime_get_sync(&card->dev);
-       mmc_claim_host(card->host);
-       mmc_blk_part_switch(card, md->part_type);
-       mmc_release_host(card->host);
+       if (md->part_curr != md->part_type) {
+               mmc_claim_host(card->host);
+               mmc_blk_part_switch(card, md->part_type);
+               mmc_release_host(card->host);
+       }
        if (card->type != MMC_TYPE_SD_COMBO)
                pm_runtime_disable(&card->dev);
        pm_runtime_put_noidle(&card->dev);
index 9c821eedd1566750ce044507bd986b5cad9a2ec0..1170feb8f96982755e601af401fe31950363a918 100644 (file)
@@ -149,6 +149,12 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
        card->quirks &= ~data;
 }
 
+static inline void __maybe_unused add_limit_rate_quirk(struct mmc_card *card,
+                                                      int data)
+{
+       card->quirk_max_rate = data;
+}
+
 /*
  * Quirk add/remove for MMC products.
  */
index 121ce50b6d5ed76418dcb9a5b44b21d6a3809e17..281826d1fcca7d498b1e3d4641b4ceffbebdb4a0 100644 (file)
@@ -50,9 +50,6 @@
 #include "sd_ops.h"
 #include "sdio_ops.h"
 
-/* If the device is not responding */
-#define MMC_CORE_TIMEOUT_MS    (10 * 60 * 1000) /* 10 minute timeout */
-
 /* The max erase timeout, used when host->max_busy_timeout isn't specified */
 #define MMC_ERASE_TIMEOUT_MS   (60 * 1000) /* 60 s */
 
@@ -1484,6 +1481,17 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
 
 }
 
+void mmc_set_initial_signal_voltage(struct mmc_host *host)
+{
+       /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
+       if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
+               dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
+       else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
+               dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
+       else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
+               dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
+}
+
 int mmc_host_set_uhs_voltage(struct mmc_host *host)
 {
        u32 clock;
@@ -1646,19 +1654,13 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
        /* Set initial state and call mmc_set_ios */
        mmc_set_initial_state(host);
 
-       /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
-       if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
-               dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
-       else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
-               dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
-       else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
-               dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
+       mmc_set_initial_signal_voltage(host);
 
        /*
         * This delay should be sufficient to allow the power supply
         * to reach the minimum voltage.
         */
-       mmc_delay(10);
+       mmc_delay(host->ios.power_delay_ms);
 
        mmc_pwrseq_post_power_on(host);
 
@@ -1671,7 +1673,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
         * This delay must be at least 74 clock sizes, or 1 ms, or the
         * time required to reach a stable voltage.
         */
-       mmc_delay(10);
+       mmc_delay(host->ios.power_delay_ms);
 }
 
 void mmc_power_off(struct mmc_host *host)
@@ -1967,6 +1969,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        unsigned int qty = 0, busy_timeout = 0;
        bool use_r1b_resp = false;
        unsigned long timeout;
+       int loop_udelay=64, udelay_max=32768;
        int err;
 
        mmc_retune_hold(card->host);
@@ -2091,9 +2094,15 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                        err =  -EIO;
                        goto out;
                }
+               if ((cmd.resp[0] & R1_READY_FOR_DATA) &&
+                   R1_CURRENT_STATE(cmd.resp[0]) != R1_STATE_PRG)
+                       break;
+
+               usleep_range(loop_udelay, loop_udelay*2);
+               if (loop_udelay < udelay_max)
+                       loop_udelay *= 2;
+       } while (1);
 
-       } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
-                (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
 out:
        mmc_retune_release(card->host);
        return err;
@@ -2435,22 +2444,46 @@ int mmc_hw_reset(struct mmc_host *host)
                return -EINVAL;
 
        mmc_bus_get(host);
-       if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) {
+       if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) {
                mmc_bus_put(host);
                return -EOPNOTSUPP;
        }
 
-       ret = host->bus_ops->reset(host);
+       ret = host->bus_ops->hw_reset(host);
        mmc_bus_put(host);
 
        if (ret)
-               pr_warn("%s: tried to reset card, got error %d\n",
+               pr_warn("%s: tried to HW reset card, got error %d\n",
                        mmc_hostname(host), ret);
 
        return ret;
 }
 EXPORT_SYMBOL(mmc_hw_reset);
 
+int mmc_sw_reset(struct mmc_host *host)
+{
+       int ret;
+
+       if (!host->card)
+               return -EINVAL;
+
+       mmc_bus_get(host);
+       if (!host->bus_ops || host->bus_dead || !host->bus_ops->sw_reset) {
+               mmc_bus_put(host);
+               return -EOPNOTSUPP;
+       }
+
+       ret = host->bus_ops->sw_reset(host);
+       mmc_bus_put(host);
+
+       if (ret)
+               pr_warn("%s: tried to SW reset card, got error %d\n",
+                       mmc_hostname(host), ret);
+
+       return ret;
+}
+EXPORT_SYMBOL(mmc_sw_reset);
+
 static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
 {
        host->f_init = freq;
index d6303d69071b7641fc20d09920cdaeef587433d4..9d8f09ac0821ad7cd112880a6fc1587fda7c08e5 100644 (file)
@@ -32,7 +32,8 @@ struct mmc_bus_ops {
        int (*power_restore)(struct mmc_host *);
        int (*alive)(struct mmc_host *);
        int (*shutdown)(struct mmc_host *);
-       int (*reset)(struct mmc_host *);
+       int (*hw_reset)(struct mmc_host *);
+       int (*sw_reset)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -51,6 +52,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
 int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
 int mmc_host_set_uhs_voltage(struct mmc_host *host);
 int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
+void mmc_set_initial_signal_voltage(struct mmc_host *host);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
 int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
index 64b03d6eaf184a30c133440299f5820943c8b2bf..abf9e884386c4cc42edee4113bb1a989167dba55 100644 (file)
@@ -143,9 +143,6 @@ int mmc_retune(struct mmc_host *host)
                        goto out;
 
                return_to_hs400 = true;
-
-               if (host->ops->prepare_hs400_tuning)
-                       host->ops->prepare_hs400_tuning(host, &host->ios);
        }
 
        err = mmc_execute_tuning(host->card);
@@ -179,7 +176,7 @@ static void mmc_retune_timer(struct timer_list *t)
 int mmc_of_parse(struct mmc_host *host)
 {
        struct device *dev = host->parent;
-       u32 bus_width, drv_type;
+       u32 bus_width, drv_type, cd_debounce_delay_ms;
        int ret;
        bool cd_cap_invert, cd_gpio_invert = false;
        bool ro_cap_invert, ro_gpio_invert = false;
@@ -230,11 +227,16 @@ int mmc_of_parse(struct mmc_host *host)
        } else {
                cd_cap_invert = device_property_read_bool(dev, "cd-inverted");
 
+               if (device_property_read_u32(dev, "cd-debounce-delay-ms",
+                                            &cd_debounce_delay_ms))
+                       cd_debounce_delay_ms = 200;
+
                if (device_property_read_bool(dev, "broken-cd"))
                        host->caps |= MMC_CAP_NEEDS_POLL;
 
                ret = mmc_gpiod_request_cd(host, "cd", 0, true,
-                                          0, &cd_gpio_invert);
+                                          cd_debounce_delay_ms,
+                                          &cd_gpio_invert);
                if (!ret)
                        dev_info(host->parent, "Got CD GPIO\n");
                else if (ret != -ENOENT && ret != -ENOSYS)
@@ -338,6 +340,9 @@ int mmc_of_parse(struct mmc_host *host)
                host->dsr_req = 0;
        }
 
+       device_property_read_u32(dev, "post-power-on-delay-ms",
+                                &host->ios.power_delay_ms);
+
        return mmc_pwrseq_alloc(host);
 }
 
@@ -403,6 +408,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
        host->max_blk_count = PAGE_SIZE / 512;
 
        host->fixed_drv_type = -EINVAL;
+       host->ios.power_delay_ms = 10;
 
        return host;
 }
index 6f8ebd6caa4ca224d5e0dd9ca849b1ff668fa77d..4466f5de54d44fcabed3d43537b15f41e44af8d6 100644 (file)
@@ -1282,6 +1282,10 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
 
        mmc_set_bus_speed(card);
 
+       /* Prepare tuning for HS400 mode. */
+       if (host->ops->prepare_hs400_tuning)
+               host->ops->prepare_hs400_tuning(host, &host->ios);
+
        return 0;
 
 out_err:
@@ -1830,6 +1834,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
        }
 
+       if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
+           host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+               pr_err("%s: Host failed to negotiate down from 3.3V\n",
+                       mmc_hostname(host));
+               err = -EINVAL;
+               goto free_card;
+       }
+
        if (!oldcard)
                host->card = card;
 
@@ -2117,7 +2129,7 @@ static int mmc_can_reset(struct mmc_card *card)
        return 1;
 }
 
-static int mmc_reset(struct mmc_host *host)
+static int _mmc_hw_reset(struct mmc_host *host)
 {
        struct mmc_card *card = host->card;
 
@@ -2151,7 +2163,7 @@ static const struct mmc_bus_ops mmc_ops = {
        .runtime_resume = mmc_runtime_resume,
        .alive = mmc_alive,
        .shutdown = mmc_shutdown,
-       .reset = mmc_reset,
+       .hw_reset = _mmc_hw_reset,
 };
 
 /*
index 13ef162cf066a63363106e40a513f3317205d10d..a8b9fee4d62a1e2c16a463cc02c0a8802c186a29 100644 (file)
@@ -40,14 +40,18 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
        struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
 
        if (!IS_ERR(reset_gpios)) {
-               int i;
-               int values[reset_gpios->ndescs];
+               int i, *values;
+               int nvalues = reset_gpios->ndescs;
 
-               for (i = 0; i < reset_gpios->ndescs; i++)
+               values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL);
+               if (!values)
+                       return;
+
+               for (i = 0; i < nvalues; i++)
                        values[i] = value;
 
-               gpiod_set_array_value_cansleep(
-                       reset_gpios->ndescs, reset_gpios->desc, values);
+               gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values);
+               kfree(values);
        }
 }
 
index 5153577754f02861ceab4689813441f9ac4ea443..dd2f73af8f2c0a2b1573d8f9461706d73d0e708c 100644 (file)
@@ -132,6 +132,9 @@ static const struct mmc_fixup sdio_fixup_methods[] = {
        SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0,
                   add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING),
 
+       SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887WLAN,
+                  add_limit_rate_quirk, 150000000),
+
        END_FIXUP
 };
 
index baf3d5da4ccbbc344a05ae1438be03b11926ba56..d0d9f90e7cdfb7453adc31f6cb5cd458989e8ceb 100644 (file)
@@ -1058,6 +1058,14 @@ retry:
                        mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
                }
        }
+
+       if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
+           host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+               pr_err("%s: Host failed to negotiate down from 3.3V\n",
+                       mmc_hostname(host));
+               err = -EINVAL;
+               goto free_card;
+       }
 done:
        host->card = card;
        return 0;
@@ -1214,7 +1222,7 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
        return 0;
 }
 
-static int mmc_sd_reset(struct mmc_host *host)
+static int mmc_sd_hw_reset(struct mmc_host *host)
 {
        mmc_power_cycle(host, host->card->ocr);
        return mmc_sd_init_card(host, host->card->ocr, host->card);
@@ -1229,7 +1237,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
        .resume = mmc_sd_resume,
        .alive = mmc_sd_alive,
        .shutdown = mmc_sd_suspend,
-       .reset = mmc_sd_reset,
+       .hw_reset = mmc_sd_hw_reset,
 };
 
 /*
index c599a628a38789b035d4744152c34f1c82ee640f..a86490dbca70705fb4022014201a8ac42b0f04da 100644 (file)
@@ -444,6 +444,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
        unsigned int bus_speed, timing;
        int err;
        unsigned char speed;
+       unsigned int max_rate;
 
        /*
         * If the host doesn't support any of the UHS-I modes, fallback on
@@ -500,9 +501,12 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
        if (err)
                return err;
 
+       max_rate = min_not_zero(card->quirk_max_rate,
+                               card->sw_caps.uhs_max_dtr);
+
        if (bus_speed) {
                mmc_set_timing(card->host, timing);
-               mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
+               mmc_set_clock(card->host, max_rate);
        }
 
        return 0;
@@ -788,6 +792,14 @@ try_again:
                if (err)
                        goto remove;
        }
+
+       if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
+           host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+               pr_err("%s: Host failed to negotiate down from 3.3V\n",
+                       mmc_hostname(host));
+               err = -EINVAL;
+               goto remove;
+       }
 finish:
        if (!oldcard)
                host->card = card;
@@ -801,6 +813,22 @@ err:
        return err;
 }
 
+static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
+{
+       int ret;
+
+       sdio_reset(host);
+       mmc_go_idle(host);
+       mmc_send_if_cond(host, host->card->ocr);
+
+       ret = mmc_send_io_op_cond(host, 0, NULL);
+       if (ret)
+               return ret;
+
+       return mmc_sdio_init_card(host, host->card->ocr, host->card,
+                                 powered_resume);
+}
+
 /*
  * Host is being removed. Free up the current card.
  */
@@ -948,14 +976,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
 
        /* No need to reinitialize powered-resumed nonremovable cards */
        if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
-               sdio_reset(host);
-               mmc_go_idle(host);
-               mmc_send_if_cond(host, host->card->ocr);
-               err = mmc_send_io_op_cond(host, 0, NULL);
-               if (!err)
-                       err = mmc_sdio_init_card(host, host->card->ocr,
-                                                host->card,
-                                                mmc_card_keep_power(host));
+               err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
        } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
                /* We may have switched to 1-bit mode during suspend */
                err = sdio_enable_4bit_bus(host->card);
@@ -978,8 +999,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
 {
        int ret;
 
-       mmc_claim_host(host);
-
        /*
         * Reset the card by performing the same steps that are taken by
         * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
@@ -997,20 +1016,12 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
         *
         */
 
-       sdio_reset(host);
-       mmc_go_idle(host);
-       mmc_send_if_cond(host, host->card->ocr);
-
-       ret = mmc_send_io_op_cond(host, 0, NULL);
-       if (ret)
-               goto out;
+       mmc_claim_host(host);
 
-       ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
-                               mmc_card_keep_power(host));
+       ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
        if (!ret && host->sdio_irqs)
                mmc_signal_sdio_irq(host);
 
-out:
        mmc_release_host(host);
 
        return ret;
@@ -1039,12 +1050,24 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
        return ret;
 }
 
-static int mmc_sdio_reset(struct mmc_host *host)
+static int mmc_sdio_hw_reset(struct mmc_host *host)
 {
        mmc_power_cycle(host, host->card->ocr);
        return mmc_sdio_power_restore(host);
 }
 
+static int mmc_sdio_sw_reset(struct mmc_host *host)
+{
+       mmc_set_clock(host, host->f_init);
+       sdio_reset(host);
+       mmc_go_idle(host);
+
+       mmc_set_initial_state(host);
+       mmc_set_initial_signal_voltage(host);
+
+       return mmc_sdio_reinit_card(host, 0);
+}
+
 static const struct mmc_bus_ops mmc_sdio_ops = {
        .remove = mmc_sdio_remove,
        .detect = mmc_sdio_detect,
@@ -1055,7 +1078,8 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
        .runtime_resume = mmc_sdio_runtime_resume,
        .power_restore = mmc_sdio_power_restore,
        .alive = mmc_sdio_alive,
-       .reset = mmc_sdio_reset,
+       .hw_reset = mmc_sdio_hw_reset,
+       .sw_reset = mmc_sdio_sw_reset,
 };
 
 
index 31f7dbb1566873a4e05ae336c3c602fcf0f53c53..ef05e00393782d16d77f2f1ecf16803f69461217 100644 (file)
@@ -28,15 +28,17 @@ struct mmc_gpio {
        irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id);
        char *ro_label;
        char cd_label[0];
+       u32 cd_debounce_delay_ms;
 };
 
 static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
 {
        /* Schedule a card detection after a debounce timeout */
        struct mmc_host *host = dev_id;
+       struct mmc_gpio *ctx = host->slot.handler_priv;
 
        host->trigger_card_event = true;
-       mmc_detect_change(host, msecs_to_jiffies(200));
+       mmc_detect_change(host, msecs_to_jiffies(ctx->cd_debounce_delay_ms));
 
        return IRQ_HANDLED;
 }
@@ -49,6 +51,7 @@ int mmc_gpio_alloc(struct mmc_host *host)
 
        if (ctx) {
                ctx->ro_label = ctx->cd_label + len;
+               ctx->cd_debounce_delay_ms = 200;
                snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
                snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
                host->slot.handler_priv = ctx;
@@ -76,15 +79,22 @@ EXPORT_SYMBOL(mmc_gpio_get_ro);
 int mmc_gpio_get_cd(struct mmc_host *host)
 {
        struct mmc_gpio *ctx = host->slot.handler_priv;
+       int cansleep;
 
        if (!ctx || !ctx->cd_gpio)
                return -ENOSYS;
 
-       if (ctx->override_cd_active_level)
-               return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^
-                       !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
+       cansleep = gpiod_cansleep(ctx->cd_gpio);
+       if (ctx->override_cd_active_level) {
+               int value = cansleep ?
+                               gpiod_get_raw_value_cansleep(ctx->cd_gpio) :
+                               gpiod_get_raw_value(ctx->cd_gpio);
+               return !value ^ !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
+       }
 
-       return gpiod_get_value_cansleep(ctx->cd_gpio);
+       return cansleep ?
+               gpiod_get_value_cansleep(ctx->cd_gpio) :
+               gpiod_get_value(ctx->cd_gpio);
 }
 EXPORT_SYMBOL(mmc_gpio_get_cd);
 
@@ -261,7 +271,7 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
        if (debounce) {
                ret = gpiod_set_debounce(desc, debounce);
                if (ret < 0)
-                       return ret;
+                       ctx->cd_debounce_delay_ms = debounce;
        }
 
        if (gpio_invert)
index 9589f9c9046f14b18b24614cb524b8574eb08991..0581c199c996546d9f02b8fe5db0f5cfbc9963fc 100644 (file)
@@ -345,11 +345,11 @@ config MMC_SDHCI_IPROC
          If unsure, say N.
 
 config MMC_MESON_GX
-       tristate "Amlogic S905/GX* SD/MMC Host Controller support"
+       tristate "Amlogic S905/GX*/AXG SD/MMC Host Controller support"
        depends on ARCH_MESON && MMC
        help
          This selects support for the Amlogic SD/MMC Host Controller
-         found on the S905/GX* family of SoCs.  This controller is
+         found on the S905/GX*/AXG family of SoCs.  This controller is
          MMC 5.1 compliant and supports SD, eMMC and SDIO interfaces.
 
          If you have a controller with this interface, say Y here.
@@ -358,7 +358,6 @@ config MMC_MESON_MX_SDIO
        tristate "Amlogic Meson6/Meson8/Meson8b SD/MMC Host Controller support"
        depends on ARCH_MESON || COMPILE_TEST
        depends on COMMON_CLK
-       depends on HAS_DMA
        depends on OF
        help
          This selects support for the SD/MMC Host Controller on
@@ -401,7 +400,6 @@ config MMC_OMAP
 
 config MMC_OMAP_HS
        tristate "TI OMAP High Speed Multimedia Card Interface support"
-       depends on HAS_DMA
        depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST
        help
          This selects the TI OMAP High Speed Multimedia card Interface.
@@ -511,7 +509,6 @@ config MMC_DAVINCI
 
 config MMC_GOLDFISH
        tristate "goldfish qemu Multimedia Card Interface support"
-       depends on HAS_DMA
        depends on GOLDFISH || COMPILE_TEST
        help
          This selects the Goldfish Multimedia card Interface emulation
@@ -605,7 +602,7 @@ config MMC_SDHI
 
 config MMC_SDHI_SYS_DMAC
        tristate "DMA for SDHI SD/SDIO controllers using SYS-DMAC"
-       depends on MMC_SDHI && HAS_DMA
+       depends on MMC_SDHI
        default MMC_SDHI if (SUPERH || ARM)
        help
          This provides DMA support for SDHI SD/SDIO controllers
@@ -615,7 +612,7 @@ config MMC_SDHI_SYS_DMAC
 config MMC_SDHI_INTERNAL_DMAC
        tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering"
        depends on ARM64 || COMPILE_TEST
-       depends on MMC_SDHI && HAS_DMA
+       depends on MMC_SDHI
        default MMC_SDHI if ARM64
        help
          This provides DMA support for SDHI SD/SDIO controllers
@@ -669,7 +666,6 @@ config MMC_CAVIUM_THUNDERX
 
 config MMC_DW
        tristate "Synopsys DesignWare Memory Card Interface"
-       depends on HAS_DMA
        depends on ARC || ARM || ARM64 || MIPS || COMPILE_TEST
        help
          This selects support for the Synopsys DesignWare Mobile Storage IP
@@ -690,6 +686,15 @@ config MMC_DW_PLTFM
 
          If unsure, say Y.
 
+config MMC_DW_BLUEFIELD
+       tristate "BlueField specific extensions for Synopsys DW Memory Card Interface"
+       depends on MMC_DW
+       select MMC_DW_PLTFM
+       help
+         This selects support for Mellanox BlueField SoC specific extensions to
+         the Synopsys DesignWare Memory Card Interface driver. Select this
+         option for platforms based on Mellanox BlueField SoC's.
+
 config MMC_DW_EXYNOS
        tristate "Exynos specific extensions for Synopsys DW Memory Card Interface"
        depends on MMC_DW
@@ -748,7 +753,6 @@ config MMC_DW_ZX
 
 config MMC_SH_MMCIF
        tristate "SuperH Internal MMCIF support"
-       depends on HAS_DMA
        depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
        help
          This selects the MMC Host Interface controller (MMCIF) found in various
@@ -756,11 +760,12 @@ config MMC_SH_MMCIF
 
 
 config MMC_JZ4740
-       tristate "JZ4740 SD/Multimedia Card Interface support"
-       depends on MACH_JZ4740
+       tristate "Ingenic JZ47xx SD/Multimedia Card Interface support"
+       depends on MACH_JZ4740 || MACH_JZ4780
        help
-         This selects support for the SD/MMC controller on Ingenic JZ4740
-         SoCs.
+         This selects support for the SD/MMC controller on Ingenic
+         JZ4740, JZ4750, JZ4770 and JZ4780 SoCs.
+
          If you have a board based on such a SoC and with a SD/MMC slot,
          say Y or M here.
 
@@ -868,7 +873,6 @@ config MMC_TOSHIBA_PCI
 config MMC_BCM2835
        tristate "Broadcom BCM2835 SDHOST MMC Controller support"
        depends on ARCH_BCM2835 || COMPILE_TEST
-       depends on HAS_DMA
        help
          This selects the BCM2835 SDHOST MMC controller. If you have
          a BCM2835 platform with SD or MMC devices, say Y or M here.
index 6aead24879b4225d60c8ae1432ee047882becfd7..85dc1322c3de1bc50c8456ea3ec5d664215f07d6 100644 (file)
@@ -49,6 +49,7 @@ thunderx-mmc-objs := cavium.o cavium-thunderx.o
 obj-$(CONFIG_MMC_CAVIUM_THUNDERX) += thunderx-mmc.o
 obj-$(CONFIG_MMC_DW)           += dw_mmc.o
 obj-$(CONFIG_MMC_DW_PLTFM)     += dw_mmc-pltfm.o
+obj-$(CONFIG_MMC_DW_BLUEFIELD) += dw_mmc-bluefield.o
 obj-$(CONFIG_MMC_DW_EXYNOS)    += dw_mmc-exynos.o
 obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_mmc-hi3798cv200.o
 obj-$(CONFIG_MMC_DW_K3)                += dw_mmc-k3.o
index 63d27589cd89d758550c40fb68035c77588e24f0..294de177632c6e25a2024d42f8fbdd926043a80f 100644 (file)
@@ -217,8 +217,8 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
                         * We don't really have DMA, so we need
                         * to copy from our platform driver buffer
                         */
-                       uint8_t *dest = (uint8_t *)sg_virt(data->sg);
-                       memcpy(dest, host->virt_base, data->sg->length);
+                       sg_copy_to_buffer(data->sg, 1, host->virt_base,
+                                       data->sg->length);
                }
                host->data->bytes_xfered += data->sg->length;
                dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
@@ -393,8 +393,8 @@ static void goldfish_mmc_prepare_data(struct goldfish_mmc_host *host,
                 * We don't really have DMA, so we need to copy to our
                 * platform driver buffer
                 */
-               const uint8_t *src = (uint8_t *)sg_virt(data->sg);
-               memcpy(host->virt_base, src, data->sg->length);
+               sg_copy_from_buffer(data->sg, 1, host->virt_base,
+                               data->sg->length);
        }
 }
 
index e55f3932d580b471681514b2ce23db91d90dc5de..5aa2c9404e926db1af2e17452a64cf5a08e4156b 100644 (file)
@@ -1967,7 +1967,6 @@ static void atmci_tasklet_func(unsigned long priv)
 static void atmci_read_data_pio(struct atmel_mci *host)
 {
        struct scatterlist      *sg = host->sg;
-       void                    *buf = sg_virt(sg);
        unsigned int            offset = host->pio_offset;
        struct mmc_data         *data = host->data;
        u32                     value;
@@ -1977,7 +1976,7 @@ static void atmci_read_data_pio(struct atmel_mci *host)
        do {
                value = atmci_readl(host, ATMCI_RDR);
                if (likely(offset + 4 <= sg->length)) {
-                       put_unaligned(value, (u32 *)(buf + offset));
+                       sg_pcopy_to_buffer(sg, 1, &value, sizeof(u32), offset);
 
                        offset += 4;
                        nbytes += 4;
@@ -1990,11 +1989,11 @@ static void atmci_read_data_pio(struct atmel_mci *host)
                                        goto done;
 
                                offset = 0;
-                               buf = sg_virt(sg);
                        }
                } else {
                        unsigned int remaining = sg->length - offset;
-                       memcpy(buf + offset, &value, remaining);
+
+                       sg_pcopy_to_buffer(sg, 1, &value, remaining, offset);
                        nbytes += remaining;
 
                        flush_dcache_page(sg_page(sg));
@@ -2004,8 +2003,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
                                goto done;
 
                        offset = 4 - remaining;
-                       buf = sg_virt(sg);
-                       memcpy(buf, (u8 *)&value + remaining, offset);
+                       sg_pcopy_to_buffer(sg, 1, (u8 *)&value + remaining,
+                                       offset, 0);
                        nbytes += offset;
                }
 
@@ -2035,7 +2034,6 @@ done:
 static void atmci_write_data_pio(struct atmel_mci *host)
 {
        struct scatterlist      *sg = host->sg;
-       void                    *buf = sg_virt(sg);
        unsigned int            offset = host->pio_offset;
        struct mmc_data         *data = host->data;
        u32                     value;
@@ -2044,7 +2042,7 @@ static void atmci_write_data_pio(struct atmel_mci *host)
 
        do {
                if (likely(offset + 4 <= sg->length)) {
-                       value = get_unaligned((u32 *)(buf + offset));
+                       sg_pcopy_from_buffer(sg, 1, &value, sizeof(u32), offset);
                        atmci_writel(host, ATMCI_TDR, value);
 
                        offset += 4;
@@ -2056,13 +2054,12 @@ static void atmci_write_data_pio(struct atmel_mci *host)
                                        goto done;
 
                                offset = 0;
-                               buf = sg_virt(sg);
                        }
                } else {
                        unsigned int remaining = sg->length - offset;
 
                        value = 0;
-                       memcpy(&value, buf + offset, remaining);
+                       sg_pcopy_from_buffer(sg, 1, &value, remaining, offset);
                        nbytes += remaining;
 
                        host->sg = sg = sg_next(sg);
@@ -2073,8 +2070,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
                        }
 
                        offset = 4 - remaining;
-                       buf = sg_virt(sg);
-                       memcpy((u8 *)&value + remaining, buf, offset);
+                       sg_pcopy_from_buffer(sg, 1, (u8 *)&value + remaining,
+                                       offset, 0);
                        atmci_writel(host, ATMCI_TDR, value);
                        nbytes += offset;
                }
index ed77fbfa477404c477407f60567d2b19197e0805..9b4be67330dd2fa5cefb0cf139b77f989c2f0383 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
+#include <linux/highmem.h>
 #include <linux/leds.h>
 #include <linux/mmc/host.h>
 #include <linux/slab.h>
@@ -405,7 +406,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
 
        /* This is the pointer to the data buffer */
        sg = &data->sg[host->pio.index];
-       sg_ptr = sg_virt(sg) + host->pio.offset;
+       sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset;
 
        /* This is the space left inside the buffer */
        sg_len = data->sg[host->pio.index].length - host->pio.offset;
@@ -421,11 +422,12 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
                if (!(status & SD_STATUS_TH))
                        break;
 
-               val = *sg_ptr++;
+               val = sg_ptr[count];
 
                __raw_writel((unsigned long)val, HOST_TXPORT(host));
                wmb(); /* drain writebuffer */
        }
+       kunmap_atomic(sg_ptr);
 
        host->pio.len -= count;
        host->pio.offset += count;
@@ -462,7 +464,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
 
        if (host->pio.index < host->dma.len) {
                sg = &data->sg[host->pio.index];
-               sg_ptr = sg_virt(sg) + host->pio.offset;
+               sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset;
 
                /* This is the space left inside the buffer */
                sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
@@ -501,8 +503,10 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
                val = __raw_readl(HOST_RXPORT(host));
 
                if (sg_ptr)
-                       *sg_ptr++ = (unsigned char)(val & 0xFF);
+                       sg_ptr[count] = (unsigned char)(val & 0xFF);
        }
+       if (sg_ptr)
+               kunmap_atomic(sg_ptr);
 
        host->pio.len -= count;
        host->pio.offset += count;
index 8e363174f9d651510822d6cc80b22f704e8576a5..9e68c3645e2270272f3bed4a5035e0dd8cdd2247 100644 (file)
@@ -1377,8 +1377,7 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int davinci_mmcsd_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+       struct mmc_davinci_host *host = dev_get_drvdata(dev);
 
        writel(0, host->base + DAVINCI_MMCIM);
        mmc_davinci_reset_ctrl(host, 1);
@@ -1389,8 +1388,7 @@ static int davinci_mmcsd_suspend(struct device *dev)
 
 static int davinci_mmcsd_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+       struct mmc_davinci_host *host = dev_get_drvdata(dev);
 
        clk_enable(host->clk);
        mmc_davinci_reset_ctrl(host, 0);
diff --git a/drivers/mmc/host/dw_mmc-bluefield.c b/drivers/mmc/host/dw_mmc-bluefield.c
new file mode 100644 (file)
index 0000000..54c3fbb
--- /dev/null
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Mellanox Technologies.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define UHS_REG_EXT_SAMPLE_MASK                GENMASK(22, 16)
+#define UHS_REG_EXT_DRIVE_MASK         GENMASK(29, 23)
+#define BLUEFIELD_UHS_REG_EXT_SAMPLE   2
+#define BLUEFIELD_UHS_REG_EXT_DRIVE    4
+
+static void dw_mci_bluefield_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+       u32 reg;
+
+       /* Update the Drive and Sample fields in register UHS_REG_EXT. */
+       reg = mci_readl(host, UHS_REG_EXT);
+       reg &= ~UHS_REG_EXT_SAMPLE_MASK;
+       reg |= FIELD_PREP(UHS_REG_EXT_SAMPLE_MASK,
+                         BLUEFIELD_UHS_REG_EXT_SAMPLE);
+       reg &= ~UHS_REG_EXT_DRIVE_MASK;
+       reg |= FIELD_PREP(UHS_REG_EXT_DRIVE_MASK, BLUEFIELD_UHS_REG_EXT_DRIVE);
+       mci_writel(host, UHS_REG_EXT, reg);
+}
+
+static const struct dw_mci_drv_data bluefield_drv_data = {
+       .set_ios                = dw_mci_bluefield_set_ios
+};
+
+static const struct of_device_id dw_mci_bluefield_match[] = {
+       { .compatible = "mellanox,bluefield-dw-mshc",
+         .data = &bluefield_drv_data },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_bluefield_match);
+
+static int dw_mci_bluefield_probe(struct platform_device *pdev)
+{
+       const struct dw_mci_drv_data *drv_data = NULL;
+       const struct of_device_id *match;
+
+       if (pdev->dev.of_node) {
+               match = of_match_node(dw_mci_bluefield_match,
+                                     pdev->dev.of_node);
+               drv_data = match->data;
+       }
+
+       return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+static struct platform_driver dw_mci_bluefield_pltfm_driver = {
+       .probe          = dw_mci_bluefield_probe,
+       .remove         = dw_mci_pltfm_remove,
+       .driver         = {
+               .name           = "dwmmc_bluefield",
+               .of_match_table = dw_mci_bluefield_match,
+               .pm             = &dw_mci_pltfm_pmops,
+       },
+};
+
+module_platform_driver(dw_mci_bluefield_pltfm_driver);
+
+MODULE_DESCRIPTION("BlueField DW Multimedia Card driver");
+MODULE_AUTHOR("Mellanox Technologies");
+MODULE_LICENSE("GPL v2");
index 40d7de2eea1216c95a7f4fba9b8a7d05b7b1d6e4..8c86a800a8fd6a47cefc54af631dcd0fd330ea0f 100644 (file)
@@ -44,9 +44,8 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
         * bus_hz = cclkin / RK3288_CLKGEN_DIV
         * ios->clock = (div == 0) ? bus_hz : (bus_hz / (2 * div))
         *
-        * Note: div can only be 0 or 1
-        *       if DDR50 8bit mode(only emmc work in 8bit mode),
-        *       div must be set 1
+        * Note: div can only be 0 or 1, but div must be set to 1 for eMMC
+        * DDR52 8-bit mode.
         */
        if (ios->bus_width == MMC_BUS_WIDTH_8 &&
            ios->timing == MMC_TIMING_MMC_DDR52)
index 29a1afa81f664a267a9f0a3865314fffacb3f95d..623f4d27fa0161b1a938521c266176f544f2ff22 100644 (file)
@@ -1230,6 +1230,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
        if (host->state == STATE_WAITING_CMD11_DONE)
                sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
 
+       slot->mmc->actual_clock = 0;
+
        if (!clock) {
                mci_writel(host, CLKENA, 0);
                mci_send_cmd(slot, sdmmc_cmd_bits, 0);
@@ -1288,6 +1290,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
 
                /* keep the last clock value that was requested from core */
                slot->__clk_old = clock;
+               slot->mmc->actual_clock = div ? ((host->bus_hz / div) >> 1) :
+                                         host->bus_hz;
        }
 
        host->current_speed = clock;
index a0168e9e4fce74cdb8ed6fb2e30477e809999f35..993386c9ea500f2006c73b66c84876084f502c6f 100644 (file)
@@ -1,5 +1,7 @@
 /*
  *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  Copyright (C) 2013, Imagination Technologies
+ *
  *  JZ4740 SD/MMC controller driver
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *
  */
 
-#include <linux/mmc/host.h>
-#include <linux/mmc/slot-gpio.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
-#include <linux/interrupt.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
-#include <linux/delay.h>
 #include <linux/scatterlist.h>
-#include <linux/clk.h>
 
-#include <linux/bitops.h>
-#include <linux/gpio.h>
 #include <asm/cacheflush.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
 
 #include <asm/mach-jz4740/dma.h>
 #include <asm/mach-jz4740/jz4740_mmc.h>
@@ -51,6 +54,7 @@
 #define JZ_REG_MMC_RESP_FIFO   0x34
 #define JZ_REG_MMC_RXFIFO      0x38
 #define JZ_REG_MMC_TXFIFO      0x3C
+#define JZ_REG_MMC_DMAC                0x44
 
 #define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7)
 #define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6)
 #define JZ_MMC_IRQ_PRG_DONE BIT(1)
 #define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0)
 
+#define JZ_MMC_DMAC_DMA_SEL BIT(1)
+#define JZ_MMC_DMAC_DMA_EN BIT(0)
 
 #define JZ_MMC_CLK_RATE 24000000
 
+enum jz4740_mmc_version {
+       JZ_MMC_JZ4740,
+       JZ_MMC_JZ4750,
+       JZ_MMC_JZ4780,
+};
+
 enum jz4740_mmc_state {
        JZ4740_MMC_STATE_READ_RESPONSE,
        JZ4740_MMC_STATE_TRANSFER_DATA,
@@ -125,6 +137,8 @@ struct jz4740_mmc_host {
        struct jz4740_mmc_platform_data *pdata;
        struct clk *clk;
 
+       enum jz4740_mmc_version version;
+
        int irq;
        int card_detect_irq;
 
@@ -137,7 +151,7 @@ struct jz4740_mmc_host {
 
        uint32_t cmdat;
 
-       uint16_t irq_mask;
+       uint32_t irq_mask;
 
        spinlock_t lock;
 
@@ -159,6 +173,32 @@ struct jz4740_mmc_host {
 #define JZ4740_MMC_FIFO_HALF_SIZE 8
 };
 
+static void jz4740_mmc_write_irq_mask(struct jz4740_mmc_host *host,
+                                     uint32_t val)
+{
+       if (host->version >= JZ_MMC_JZ4750)
+               return writel(val, host->base + JZ_REG_MMC_IMASK);
+       else
+               return writew(val, host->base + JZ_REG_MMC_IMASK);
+}
+
+static void jz4740_mmc_write_irq_reg(struct jz4740_mmc_host *host,
+                                    uint32_t val)
+{
+       if (host->version >= JZ_MMC_JZ4780)
+               return writel(val, host->base + JZ_REG_MMC_IREG);
+       else
+               return writew(val, host->base + JZ_REG_MMC_IREG);
+}
+
+static uint32_t jz4740_mmc_read_irq_reg(struct jz4740_mmc_host *host)
+{
+       if (host->version >= JZ_MMC_JZ4780)
+               return readl(host->base + JZ_REG_MMC_IREG);
+       else
+               return readw(host->base + JZ_REG_MMC_IREG);
+}
+
 /*----------------------------------------------------------------------------*/
 /* DMA infrastructure */
 
@@ -173,31 +213,23 @@ static void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host)
 
 static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
 {
-       dma_cap_mask_t mask;
-
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       host->dma_tx = dma_request_channel(mask, NULL, host);
-       if (!host->dma_tx) {
+       host->dma_tx = dma_request_chan(mmc_dev(host->mmc), "tx");
+       if (IS_ERR(host->dma_tx)) {
                dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n");
-               return -ENODEV;
+               return PTR_ERR(host->dma_tx);
        }
 
-       host->dma_rx = dma_request_channel(mask, NULL, host);
-       if (!host->dma_rx) {
+       host->dma_rx = dma_request_chan(mmc_dev(host->mmc), "rx");
+       if (IS_ERR(host->dma_rx)) {
                dev_err(mmc_dev(host->mmc), "Failed to get dma_rx channel\n");
-               goto free_master_write;
+               dma_release_channel(host->dma_tx);
+               return PTR_ERR(host->dma_rx);
        }
 
        /* Initialize DMA pre request cookie */
        host->next_data.cookie = 1;
 
        return 0;
-
-free_master_write:
-       dma_release_channel(host->dma_tx);
-       return -ENODEV;
 }
 
 static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host,
@@ -363,7 +395,7 @@ static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host,
        else
                host->irq_mask |= irq;
 
-       writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK);
+       jz4740_mmc_write_irq_mask(host, host->irq_mask);
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -415,10 +447,10 @@ static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host,
        unsigned int irq)
 {
        unsigned int timeout = 0x800;
-       uint16_t status;
+       uint32_t status;
 
        do {
-               status = readw(host->base + JZ_REG_MMC_IREG);
+               status = jz4740_mmc_read_irq_reg(host);
        } while (!(status & irq) && --timeout);
 
        if (timeout == 0) {
@@ -518,7 +550,7 @@ static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host,
        void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO;
        uint32_t *buf;
        uint32_t d;
-       uint16_t status;
+       uint32_t status;
        size_t i, j;
        unsigned int timeout;
 
@@ -654,8 +686,25 @@ static void jz4740_mmc_send_command(struct jz4740_mmc_host *host,
                cmdat |= JZ_MMC_CMDAT_DATA_EN;
                if (cmd->data->flags & MMC_DATA_WRITE)
                        cmdat |= JZ_MMC_CMDAT_WRITE;
-               if (host->use_dma)
-                       cmdat |= JZ_MMC_CMDAT_DMA_EN;
+               if (host->use_dma) {
+                       /*
+                        * The 4780's MMC controller has integrated DMA ability
+                        * in addition to being able to use the external DMA
+                        * controller. It moves DMA control bits to a separate
+                        * register. The DMA_SEL bit chooses the external
+                        * controller over the integrated one. Earlier SoCs
+                        * can only use the external controller, and have a
+                        * single DMA enable bit in CMDAT.
+                        */
+                       if (host->version >= JZ_MMC_JZ4780) {
+                               writel(JZ_MMC_DMAC_DMA_EN | JZ_MMC_DMAC_DMA_SEL,
+                                      host->base + JZ_REG_MMC_DMAC);
+                       } else {
+                               cmdat |= JZ_MMC_CMDAT_DMA_EN;
+                       }
+               } else if (host->version >= JZ_MMC_JZ4780) {
+                       writel(0, host->base + JZ_REG_MMC_DMAC);
+               }
 
                writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN);
                writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB);
@@ -736,7 +785,7 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
                        host->state = JZ4740_MMC_STATE_SEND_STOP;
                        break;
                }
-               writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG);
+               jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_DATA_TRAN_DONE);
 
        case JZ4740_MMC_STATE_SEND_STOP:
                if (!req->stop)
@@ -766,9 +815,10 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
 {
        struct jz4740_mmc_host *host = devid;
        struct mmc_command *cmd = host->cmd;
-       uint16_t irq_reg, status, tmp;
+       uint32_t irq_reg, status, tmp;
 
-       irq_reg = readw(host->base + JZ_REG_MMC_IREG);
+       status = readl(host->base + JZ_REG_MMC_STATUS);
+       irq_reg = jz4740_mmc_read_irq_reg(host);
 
        tmp = irq_reg;
        irq_reg &= ~host->irq_mask;
@@ -777,10 +827,10 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
                JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE);
 
        if (tmp != irq_reg)
-               writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG);
+               jz4740_mmc_write_irq_reg(host, tmp & ~irq_reg);
 
        if (irq_reg & JZ_MMC_IRQ_SDIO) {
-               writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG);
+               jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_SDIO);
                mmc_signal_sdio_irq(host->mmc);
                irq_reg &= ~JZ_MMC_IRQ_SDIO;
        }
@@ -789,8 +839,6 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
                if (test_and_clear_bit(0, &host->waiting)) {
                        del_timer(&host->timeout_timer);
 
-                       status = readl(host->base + JZ_REG_MMC_STATUS);
-
                        if (status & JZ_MMC_STATUS_TIMEOUT_RES) {
                                        cmd->error = -ETIMEDOUT;
                        } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) {
@@ -803,7 +851,7 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
                        }
 
                        jz4740_mmc_set_irq_enabled(host, irq_reg, false);
-                       writew(irq_reg, host->base + JZ_REG_MMC_IREG);
+                       jz4740_mmc_write_irq_reg(host, irq_reg);
 
                        return IRQ_WAKE_THREAD;
                }
@@ -818,7 +866,7 @@ static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate)
        int real_rate;
 
        jz4740_mmc_clock_disable(host);
-       clk_set_rate(host->clk, JZ_MMC_CLK_RATE);
+       clk_set_rate(host->clk, host->mmc->f_max);
 
        real_rate = clk_get_rate(host->clk);
 
@@ -837,9 +885,7 @@ static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
 
        host->req = req;
 
-       writew(0xffff, host->base + JZ_REG_MMC_IREG);
-
-       writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG);
+       jz4740_mmc_write_irq_reg(host, ~0);
        jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true);
 
        host->state = JZ4740_MMC_STATE_READ_RESPONSE;
@@ -857,7 +903,7 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        switch (ios->power_mode) {
        case MMC_POWER_UP:
                jz4740_mmc_reset(host);
-               if (gpio_is_valid(host->pdata->gpio_power))
+               if (host->pdata && gpio_is_valid(host->pdata->gpio_power))
                        gpio_set_value(host->pdata->gpio_power,
                                        !host->pdata->power_active_low);
                host->cmdat |= JZ_MMC_CMDAT_INIT;
@@ -866,7 +912,7 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        case MMC_POWER_ON:
                break;
        default:
-               if (gpio_is_valid(host->pdata->gpio_power))
+               if (host->pdata && gpio_is_valid(host->pdata->gpio_power))
                        gpio_set_value(host->pdata->gpio_power,
                                        host->pdata->power_active_low);
                clk_disable_unprepare(host->clk);
@@ -926,7 +972,7 @@ static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
 static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
        struct platform_device *pdev)
 {
-       struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+       struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int ret = 0;
 
        if (!pdata)
@@ -955,7 +1001,7 @@ static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
 
 static void jz4740_mmc_free_gpios(struct platform_device *pdev)
 {
-       struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+       struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
        if (!pdata)
                return;
@@ -964,14 +1010,22 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
                gpio_free(pdata->gpio_power);
 }
 
+static const struct of_device_id jz4740_mmc_of_match[] = {
+       { .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 },
+       { .compatible = "ingenic,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 },
+       {},
+};
+MODULE_DEVICE_TABLE(of, jz4740_mmc_of_match);
+
 static int jz4740_mmc_probe(struct platform_device* pdev)
 {
        int ret;
        struct mmc_host *mmc;
        struct jz4740_mmc_host *host;
+       const struct of_device_id *match;
        struct jz4740_mmc_platform_data *pdata;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
 
        mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev);
        if (!mmc) {
@@ -982,6 +1036,27 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
        host = mmc_priv(mmc);
        host->pdata = pdata;
 
+       match = of_match_device(jz4740_mmc_of_match, &pdev->dev);
+       if (match) {
+               host->version = (enum jz4740_mmc_version)match->data;
+               ret = mmc_of_parse(mmc);
+               if (ret) {
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(&pdev->dev,
+                                       "could not parse of data: %d\n", ret);
+                       goto err_free_host;
+               }
+       } else {
+               /* JZ4740 should be the only one using legacy probe */
+               host->version = JZ_MMC_JZ4740;
+               mmc->caps |= MMC_CAP_SDIO_IRQ;
+               if (!(pdata && pdata->data_1bit))
+                       mmc->caps |= MMC_CAP_4_BIT_DATA;
+               ret = jz4740_mmc_request_gpios(mmc, pdev);
+               if (ret)
+                       goto err_free_host;
+       }
+
        host->irq = platform_get_irq(pdev, 0);
        if (host->irq < 0) {
                ret = host->irq;
@@ -1004,16 +1079,11 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
                goto err_free_host;
        }
 
-       ret = jz4740_mmc_request_gpios(mmc, pdev);
-       if (ret)
-               goto err_release_dma;
-
        mmc->ops = &jz4740_mmc_ops;
-       mmc->f_min = JZ_MMC_CLK_RATE / 128;
-       mmc->f_max = JZ_MMC_CLK_RATE;
+       if (!mmc->f_max)
+               mmc->f_max = JZ_MMC_CLK_RATE;
+       mmc->f_min = mmc->f_max / 128;
        mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA;
-       mmc->caps |= MMC_CAP_SDIO_IRQ;
 
        mmc->max_blk_size = (1 << 10) - 1;
        mmc->max_blk_count = (1 << 15) - 1;
@@ -1025,7 +1095,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
        host->mmc = mmc;
        host->pdev = pdev;
        spin_lock_init(&host->lock);
-       host->irq_mask = 0xffff;
+       host->irq_mask = ~0;
+
+       jz4740_mmc_reset(host);
 
        ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0,
                        dev_name(&pdev->dev), host);
@@ -1034,20 +1106,20 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
                goto err_free_gpios;
        }
 
-       jz4740_mmc_reset(host);
        jz4740_mmc_clock_disable(host);
        timer_setup(&host->timeout_timer, jz4740_mmc_timeout, 0);
 
-       host->use_dma = true;
-       if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0)
-               host->use_dma = false;
+       ret = jz4740_mmc_acquire_dma_channels(host);
+       if (ret == -EPROBE_DEFER)
+               goto err_free_irq;
+       host->use_dma = !ret;
 
        platform_set_drvdata(pdev, host);
        ret = mmc_add_host(mmc);
 
        if (ret) {
                dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret);
-               goto err_free_irq;
+               goto err_release_dma;
        }
        dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n");
 
@@ -1057,13 +1129,13 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 
        return 0;
 
+err_release_dma:
+       if (host->use_dma)
+               jz4740_mmc_release_dma_channels(host);
 err_free_irq:
        free_irq(host->irq, host);
 err_free_gpios:
        jz4740_mmc_free_gpios(pdev);
-err_release_dma:
-       if (host->use_dma)
-               jz4740_mmc_release_dma_channels(host);
 err_free_host:
        mmc_free_host(mmc);
 
@@ -1116,6 +1188,7 @@ static struct platform_driver jz4740_mmc_driver = {
        .remove = jz4740_mmc_remove,
        .driver = {
                .name = "jz4740-mmc",
+               .of_match_table = of_match_ptr(jz4740_mmc_of_match),
                .pm = JZ4740_MMC_PM_OPS,
        },
 };
index 4f972b879fe6f36ef0018d82a1b71f57c2de3cce..c201c378537e4f1a8a601e8d857481a7e6af9f0c 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/regulator/consumer.h>
+#include <linux/reset.h>
 #include <linux/interrupt.h>
 #include <linux/bitfield.h>
 #include <linux/pinctrl/consumer.h>
 #define   CLK_CORE_PHASE_MASK GENMASK(9, 8)
 #define   CLK_TX_PHASE_MASK GENMASK(11, 10)
 #define   CLK_RX_PHASE_MASK GENMASK(13, 12)
-#define   CLK_TX_DELAY_MASK GENMASK(19, 16)
-#define   CLK_RX_DELAY_MASK GENMASK(23, 20)
+#define   CLK_V2_TX_DELAY_MASK GENMASK(19, 16)
+#define   CLK_V2_RX_DELAY_MASK GENMASK(23, 20)
+#define   CLK_V2_ALWAYS_ON BIT(24)
+
+#define   CLK_V3_TX_DELAY_MASK GENMASK(21, 16)
+#define   CLK_V3_RX_DELAY_MASK GENMASK(27, 22)
+#define   CLK_V3_ALWAYS_ON BIT(28)
+
 #define   CLK_DELAY_STEP_PS 200
 #define   CLK_PHASE_STEP 30
 #define   CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP)
-#define   CLK_ALWAYS_ON BIT(24)
+
+#define   CLK_TX_DELAY_MASK(h)         (h->data->tx_delay_mask)
+#define   CLK_RX_DELAY_MASK(h)         (h->data->rx_delay_mask)
+#define   CLK_ALWAYS_ON(h)             (h->data->always_on)
 
 #define SD_EMMC_DELAY 0x4
 #define SD_EMMC_ADJUST 0x8
+
+#define SD_EMMC_DELAY1 0x4
+#define SD_EMMC_DELAY2 0x8
+#define SD_EMMC_V3_ADJUST 0xc
+
 #define SD_EMMC_CALOUT 0x10
 #define SD_EMMC_START 0x40
 #define   START_DESC_INIT BIT(0)
 
 #define MUX_CLK_NUM_PARENTS 2
 
+struct meson_mmc_data {
+       unsigned int tx_delay_mask;
+       unsigned int rx_delay_mask;
+       unsigned int always_on;
+};
+
 struct sd_emmc_desc {
        u32 cmd_cfg;
        u32 cmd_arg;
@@ -131,6 +152,7 @@ struct sd_emmc_desc {
 
 struct meson_host {
        struct  device          *dev;
+       struct  meson_mmc_data *data;
        struct  mmc_host        *mmc;
        struct  mmc_command     *cmd;
 
@@ -474,7 +496,7 @@ static int meson_mmc_clk_init(struct meson_host *host)
 
        /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */
        clk_reg = 0;
-       clk_reg |= CLK_ALWAYS_ON;
+       clk_reg |= CLK_ALWAYS_ON(host);
        clk_reg |= CLK_DIV_MASK;
        writel(clk_reg, host->regs + SD_EMMC_CLOCK);
 
@@ -574,7 +596,7 @@ static int meson_mmc_clk_init(struct meson_host *host)
 
        tx->reg = host->regs + SD_EMMC_CLOCK;
        tx->phase_mask = CLK_TX_PHASE_MASK;
-       tx->delay_mask = CLK_TX_DELAY_MASK;
+       tx->delay_mask = CLK_TX_DELAY_MASK(host);
        tx->delay_step_ps = CLK_DELAY_STEP_PS;
        tx->hw.init = &init;
 
@@ -597,7 +619,7 @@ static int meson_mmc_clk_init(struct meson_host *host)
 
        rx->reg = host->regs + SD_EMMC_CLOCK;
        rx->phase_mask = CLK_RX_PHASE_MASK;
-       rx->delay_mask = CLK_RX_DELAY_MASK;
+       rx->delay_mask = CLK_RX_DELAY_MASK(host);
        rx->delay_step_ps = CLK_DELAY_STEP_PS;
        rx->hw.init = &init;
 
@@ -1184,6 +1206,21 @@ static int meson_mmc_probe(struct platform_device *pdev)
                goto free_host;
        }
 
+       host->data = (struct meson_mmc_data *)
+               of_device_get_match_data(&pdev->dev);
+       if (!host->data) {
+               ret = -EINVAL;
+               goto free_host;
+       }
+
+       ret = device_reset_optional(&pdev->dev);
+       if (ret) {
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "device reset failed: %d\n", ret);
+
+               return ret;
+       }
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        host->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(host->regs)) {
@@ -1315,11 +1352,24 @@ static int meson_mmc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct meson_mmc_data meson_gx_data = {
+       .tx_delay_mask  = CLK_V2_TX_DELAY_MASK,
+       .rx_delay_mask  = CLK_V2_RX_DELAY_MASK,
+       .always_on      = CLK_V2_ALWAYS_ON,
+};
+
+static const struct meson_mmc_data meson_axg_data = {
+       .tx_delay_mask  = CLK_V3_TX_DELAY_MASK,
+       .rx_delay_mask  = CLK_V3_RX_DELAY_MASK,
+       .always_on      = CLK_V3_ALWAYS_ON,
+};
+
 static const struct of_device_id meson_mmc_of_match[] = {
-       { .compatible = "amlogic,meson-gx-mmc", },
-       { .compatible = "amlogic,meson-gxbb-mmc", },
-       { .compatible = "amlogic,meson-gxl-mmc", },
-       { .compatible = "amlogic,meson-gxm-mmc", },
+       { .compatible = "amlogic,meson-gx-mmc",         .data = &meson_gx_data },
+       { .compatible = "amlogic,meson-gxbb-mmc",       .data = &meson_gx_data },
+       { .compatible = "amlogic,meson-gxl-mmc",        .data = &meson_gx_data },
+       { .compatible = "amlogic,meson-gxm-mmc",        .data = &meson_gx_data },
+       { .compatible = "amlogic,meson-axg-mmc",        .data = &meson_axg_data },
        {}
 };
 MODULE_DEVICE_TABLE(of, meson_mmc_of_match);
@@ -1335,6 +1385,6 @@ static struct platform_driver meson_mmc_driver = {
 
 module_platform_driver(meson_mmc_driver);
 
-MODULE_DESCRIPTION("Amlogic S905*/GX* SD/eMMC driver");
+MODULE_DESCRIPTION("Amlogic S905*/GX*/AXG SD/eMMC driver");
 MODULE_AUTHOR("Kevin Hilman <khilman@baylibre.com>");
 MODULE_LICENSE("GPL v2");
index 70b0df8b9c7865a5dbb4d466d9c856215bbc6984..f1849775e47e2726ef2addb357016418a246469b 100644 (file)
@@ -1253,15 +1253,12 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
        struct sg_mapping_iter *sg_miter = &host->sg_miter;
        struct variant_data *variant = host->variant;
        void __iomem *base = host->base;
-       unsigned long flags;
        u32 status;
 
        status = readl(base + MMCISTATUS);
 
        dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
 
-       local_irq_save(flags);
-
        do {
                unsigned int remain, len;
                char *buffer;
@@ -1301,8 +1298,6 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
 
        sg_miter_stop(sg_miter);
 
-       local_irq_restore(flags);
-
        /*
         * If we have less than the fifo 'half-full' threshold to transfer,
         * trigger a PIO interrupt as soon as any data is available.
index cb274e82229336b589ff3dbc615aba7aef40a1d7..04841386b65da4b474e8b30afe9872a727eac902 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/ioport.h>
 #include <linux/irq.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/of_gpio.h>
 #include <linux/pinctrl/consumer.h>
@@ -70,6 +71,7 @@
 #define SDC_ADV_CFG0     0x64
 #define EMMC_IOCON       0x7c
 #define SDC_ACMD_RESP    0x80
+#define DMA_SA_H4BIT     0x8c
 #define MSDC_DMA_SA      0x90
 #define MSDC_DMA_CTRL    0x98
 #define MSDC_DMA_CFG     0x9c
 /* SDC_ADV_CFG0 mask */
 #define SDC_RX_ENHANCE_EN      (0x1 << 20)     /* RW */
 
+/* DMA_SA_H4BIT mask */
+#define DMA_ADDR_HIGH_4BIT      (0xf << 0)      /* RW */
+
 /* MSDC_DMA_CTRL mask */
 #define MSDC_DMA_CTRL_START     (0x1 << 0)     /* W */
 #define MSDC_DMA_CTRL_STOP      (0x1 << 1)     /* W */
 
 #define MSDC_PATCH_BIT2_CFGRESP   (0x1 << 15)   /* RW */
 #define MSDC_PATCH_BIT2_CFGCRCSTS (0x1 << 28)   /* RW */
+#define MSDC_PB2_SUPPORT_64G      (0x1 << 1)    /* RW */
 #define MSDC_PB2_RESPWAIT         (0x3 << 2)    /* RW */
 #define MSDC_PB2_RESPSTSENSEL     (0x7 << 16)   /* RW */
 #define MSDC_PB2_CRCSTSENSEL      (0x7 << 29)   /* RW */
@@ -280,6 +286,8 @@ struct mt_gpdma_desc {
 #define GPDMA_DESC_BDP         (0x1 << 1)
 #define GPDMA_DESC_CHECKSUM    (0xff << 8) /* bit8 ~ bit15 */
 #define GPDMA_DESC_INT         (0x1 << 16)
+#define GPDMA_DESC_NEXT_H4     (0xf << 24)
+#define GPDMA_DESC_PTR_H4      (0xf << 28)
        u32 next;
        u32 ptr;
        u32 gpd_data_len;
@@ -296,6 +304,8 @@ struct mt_bdma_desc {
 #define BDMA_DESC_CHECKSUM     (0xff << 8) /* bit8 ~ bit15 */
 #define BDMA_DESC_BLKPAD       (0x1 << 17)
 #define BDMA_DESC_DWPAD                (0x1 << 18)
+#define BDMA_DESC_NEXT_H4      (0xf << 24)
+#define BDMA_DESC_PTR_H4       (0xf << 28)
        u32 next;
        u32 ptr;
        u32 bd_data_len;
@@ -334,6 +344,7 @@ struct mtk_mmc_compatible {
        bool busy_check;
        bool stop_clk_fix;
        bool enhance_rx;
+       bool support_64g;
 };
 
 struct msdc_tune_para {
@@ -403,6 +414,7 @@ static const struct mtk_mmc_compatible mt8135_compat = {
        .busy_check = false,
        .stop_clk_fix = false,
        .enhance_rx = false,
+       .support_64g = false,
 };
 
 static const struct mtk_mmc_compatible mt8173_compat = {
@@ -414,6 +426,7 @@ static const struct mtk_mmc_compatible mt8173_compat = {
        .busy_check = false,
        .stop_clk_fix = false,
        .enhance_rx = false,
+       .support_64g = false,
 };
 
 static const struct mtk_mmc_compatible mt2701_compat = {
@@ -425,6 +438,7 @@ static const struct mtk_mmc_compatible mt2701_compat = {
        .busy_check = false,
        .stop_clk_fix = false,
        .enhance_rx = false,
+       .support_64g = false,
 };
 
 static const struct mtk_mmc_compatible mt2712_compat = {
@@ -436,6 +450,7 @@ static const struct mtk_mmc_compatible mt2712_compat = {
        .busy_check = true,
        .stop_clk_fix = true,
        .enhance_rx = true,
+       .support_64g = true,
 };
 
 static const struct mtk_mmc_compatible mt7622_compat = {
@@ -447,6 +462,7 @@ static const struct mtk_mmc_compatible mt7622_compat = {
        .busy_check = true,
        .stop_clk_fix = true,
        .enhance_rx = true,
+       .support_64g = false,
 };
 
 static const struct of_device_id msdc_of_ids[] = {
@@ -556,7 +572,12 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
                /* init bd */
                bd[j].bd_info &= ~BDMA_DESC_BLKPAD;
                bd[j].bd_info &= ~BDMA_DESC_DWPAD;
-               bd[j].ptr = (u32)dma_address;
+               bd[j].ptr = lower_32_bits(dma_address);
+               if (host->dev_comp->support_64g) {
+                       bd[j].bd_info &= ~BDMA_DESC_PTR_H4;
+                       bd[j].bd_info |= (upper_32_bits(dma_address) & 0xf)
+                                        << 28;
+               }
                bd[j].bd_data_len &= ~BDMA_DESC_BUFLEN;
                bd[j].bd_data_len |= (dma_len & BDMA_DESC_BUFLEN);
 
@@ -575,7 +596,10 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
        dma_ctrl &= ~(MSDC_DMA_CTRL_BRUSTSZ | MSDC_DMA_CTRL_MODE);
        dma_ctrl |= (MSDC_BURST_64B << 12 | 1 << 8);
        writel_relaxed(dma_ctrl, host->base + MSDC_DMA_CTRL);
-       writel((u32)dma->gpd_addr, host->base + MSDC_DMA_SA);
+       if (host->dev_comp->support_64g)
+               sdr_set_field(host->base + DMA_SA_H4BIT, DMA_ADDR_HIGH_4BIT,
+                             upper_32_bits(dma->gpd_addr) & 0xf);
+       writel(lower_32_bits(dma->gpd_addr), host->base + MSDC_DMA_SA);
 }
 
 static void msdc_prepare_data(struct msdc_host *host, struct mmc_request *mrq)
@@ -1366,6 +1390,9 @@ static void msdc_init_hw(struct msdc_host *host)
                             MSDC_PATCH_BIT2_CFGCRCSTS);
        }
 
+       if (host->dev_comp->support_64g)
+               sdr_set_bits(host->base + MSDC_PATCH_BIT2,
+                            MSDC_PB2_SUPPORT_64G);
        if (host->dev_comp->data_tune) {
                sdr_set_bits(host->base + tune_reg,
                             MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL);
@@ -1407,19 +1434,32 @@ static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma)
 {
        struct mt_gpdma_desc *gpd = dma->gpd;
        struct mt_bdma_desc *bd = dma->bd;
+       dma_addr_t dma_addr;
        int i;
 
        memset(gpd, 0, sizeof(struct mt_gpdma_desc) * 2);
 
+       dma_addr = dma->gpd_addr + sizeof(struct mt_gpdma_desc);
        gpd->gpd_info = GPDMA_DESC_BDP; /* hwo, cs, bd pointer */
-       gpd->ptr = (u32)dma->bd_addr; /* physical address */
        /* gpd->next is must set for desc DMA
         * That's why must alloc 2 gpd structure.
         */
-       gpd->next = (u32)dma->gpd_addr + sizeof(struct mt_gpdma_desc);
+       gpd->next = lower_32_bits(dma_addr);
+       if (host->dev_comp->support_64g)
+               gpd->gpd_info |= (upper_32_bits(dma_addr) & 0xf) << 24;
+
+       dma_addr = dma->bd_addr;
+       gpd->ptr = lower_32_bits(dma->bd_addr); /* physical address */
+       if (host->dev_comp->support_64g)
+               gpd->gpd_info |= (upper_32_bits(dma_addr) & 0xf) << 28;
+
        memset(bd, 0, sizeof(struct mt_bdma_desc) * MAX_BD_NUM);
-       for (i = 0; i < (MAX_BD_NUM - 1); i++)
-               bd[i].next = (u32)dma->bd_addr + sizeof(*bd) * (i + 1);
+       for (i = 0; i < (MAX_BD_NUM - 1); i++) {
+               dma_addr = dma->bd_addr + sizeof(*bd) * (i + 1);
+               bd[i].next = lower_32_bits(dma_addr);
+               if (host->dev_comp->support_64g)
+                       bd[i].bd_info |= (upper_32_bits(dma_addr) & 0xf) << 24;
+       }
 }
 
 static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -1820,7 +1860,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
        struct mmc_host *mmc;
        struct msdc_host *host;
        struct resource *res;
-       const struct of_device_id *of_id;
        int ret;
 
        if (!pdev->dev.of_node) {
@@ -1828,9 +1867,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       of_id = of_match_node(msdc_of_ids, pdev->dev.of_node);
-       if (!of_id)
-               return -EINVAL;
        /* Allocate MMC host for this device */
        mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev);
        if (!mmc)
@@ -1899,7 +1935,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
        msdc_of_property_parse(pdev, host);
 
        host->dev = &pdev->dev;
-       host->dev_comp = of_id->data;
+       host->dev_comp = of_device_get_match_data(&pdev->dev);
        host->mmc = mmc;
        host->src_clk_freq = clk_get_rate(host->src_clk);
        /* Set host parameters to mmc */
@@ -1916,7 +1952,10 @@ static int msdc_drv_probe(struct platform_device *pdev)
        mmc->max_blk_size = 2048;
        mmc->max_req_size = 512 * 1024;
        mmc->max_blk_count = mmc->max_req_size / 512;
-       host->dma_mask = DMA_BIT_MASK(32);
+       if (host->dev_comp->support_64g)
+               host->dma_mask = DMA_BIT_MASK(36);
+       else
+               host->dma_mask = DMA_BIT_MASK(32);
        mmc_dev(mmc)->dma_mask = &host->dma_mask;
 
        host->timeout_clks = 3 * 1048576;
index 210247b3d11ad50d0998216f8ddce6fb0541de2f..e22bbff89c8d24c62d075327de4b65935a345162 100644 (file)
@@ -143,6 +143,7 @@ static void mvsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
        struct mmc_command *cmd = mrq->cmd;
        u32 cmdreg = 0, xfer = 0, intr = 0;
        unsigned long flags;
+       unsigned int timeout;
 
        BUG_ON(host->mrq != NULL);
        host->mrq = mrq;
@@ -234,7 +235,8 @@ static void mvsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
        mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
        mvsd_write(MVSD_ERR_INTR_EN, 0xffff);
 
-       mod_timer(&host->timer, jiffies + 5 * HZ);
+       timeout = cmd->busy_timeout ? cmd->busy_timeout : 5000;
+       mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout));
 
        spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -755,6 +757,8 @@ static int mvsd_probe(struct platform_device *pdev)
        if (maxfreq)
                mmc->f_max = maxfreq;
 
+       mmc->caps |= MMC_CAP_ERASE;
+
        spin_lock_init(&host->lock);
 
        host->base = devm_ioremap_resource(&pdev->dev, r);
index 5ff8ef7223cc484814b5221b1758fd839def27c5..75f781c11e897ff8e47ed92fb7995ba33f706cd0 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
+#include <linux/highmem.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/blkdev.h>
@@ -291,8 +292,10 @@ static void mxcmci_swap_buffers(struct mmc_data *data)
        struct scatterlist *sg;
        int i;
 
-       for_each_sg(data->sg, sg, data->sg_len, i)
-               buffer_swap32(sg_virt(sg), sg->length);
+       for_each_sg(data->sg, sg, data->sg_len, i) {
+               void *buf = kmap_atomic(sg_page(sg) + sg->offset;
+               buffer_swap32(buf, sg->length);
+               kunmap_atomic(buf);
 }
 #else
 static inline void mxcmci_swap_buffers(struct mmc_data *data) {}
@@ -609,6 +612,7 @@ static int mxcmci_transfer_data(struct mxcmci_host *host)
 {
        struct mmc_data *data = host->req->data;
        struct scatterlist *sg;
+       void *buf;
        int stat, i;
 
        host->data = data;
@@ -616,14 +620,18 @@ static int mxcmci_transfer_data(struct mxcmci_host *host)
 
        if (data->flags & MMC_DATA_READ) {
                for_each_sg(data->sg, sg, data->sg_len, i) {
-                       stat = mxcmci_pull(host, sg_virt(sg), sg->length);
+                       buf = kmap_atomic(sg_page(sg) + sg->offset);
+                       stat = mxcmci_pull(host, buf, sg->length);
+                       kunmap(buf);
                        if (stat)
                                return stat;
                        host->datasize += sg->length;
                }
        } else {
                for_each_sg(data->sg, sg, data->sg_len, i) {
-                       stat = mxcmci_push(host, sg_virt(sg), sg->length);
+                       buf = kmap_atomic(sg_page(sg) + sg->offset);
+                       stat = mxcmci_push(host, buf, sg->length);
+                       kunmap(buf);
                        if (stat)
                                return stat;
                        host->datasize += sg->length;
@@ -1206,7 +1214,8 @@ static int mxcmci_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __maybe_unused mxcmci_suspend(struct device *dev)
+#ifdef CONFIG_PM_SLEEP
+static int mxcmci_suspend(struct device *dev)
 {
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct mxcmci_host *host = mmc_priv(mmc);
@@ -1216,7 +1225,7 @@ static int __maybe_unused mxcmci_suspend(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused mxcmci_resume(struct device *dev)
+static int mxcmci_resume(struct device *dev)
 {
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct mxcmci_host *host = mmc_priv(mmc);
@@ -1232,6 +1241,7 @@ static int __maybe_unused mxcmci_resume(struct device *dev)
 
        return ret;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
 
index 51e01f03fb995f06619cb194b5319725f81ed9ec..45c015da2e757c9099aa3b4d0378ffe960ea7dcb 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/mfd/tmio.h>
 #include <linux/sh_dma.h>
 #include <linux/delay.h>
@@ -534,6 +535,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
        host->multi_io_quirk    = renesas_sdhi_multi_io_quirk;
        host->dma_ops           = dma_ops;
 
+       /* For some SoC, we disable internal WP. GPIO may override this */
+       if (mmc_can_gpio_ro(host->mmc))
+               mmc_data->capabilities2 &= ~MMC_CAP2_NO_WRITE_PROTECT;
+
        /* SDR speeds are only available on Gen2+ */
        if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) {
                /* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */
index 6af946d16d241f685814fa8933f32fd672c40c22..f7f9773d161f1e5e2f58ae1f9a32c800ac5f3474 100644 (file)
@@ -87,11 +87,12 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
                          TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
        .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
                          MMC_CAP_CMD23,
+       .capabilities2  = MMC_CAP2_NO_WRITE_PROTECT,
        .bus_shift      = 2,
        .scc_offset     = 0x1000,
        .taps           = rcar_gen3_scc_taps,
        .taps_num       = ARRAY_SIZE(rcar_gen3_scc_taps),
-       /* Gen3 SDHI DMAC can handle 0xffffffff blk count, but seg = 1 */
+       /* DMAC can handle 0xffffffff blk count but only 1 segment */
        .max_blk_count  = 0xffffffff,
        .max_segs       = 1,
 };
@@ -157,38 +158,34 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
 {
        struct scatterlist *sg = host->sg_ptr;
        u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE;
-       enum dma_data_direction dir;
-       int ret;
 
-       /* This DMAC cannot handle if sg_len is not 1 */
-       WARN_ON(host->sg_len > 1);
+       if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len,
+                       mmc_get_dma_dir(data)))
+               goto force_pio;
 
        /* This DMAC cannot handle if buffer is not 8-bytes alignment */
-       if (!IS_ALIGNED(sg->offset, 8))
+       if (!IS_ALIGNED(sg_dma_address(sg), 8)) {
+               dma_unmap_sg(&host->pdev->dev, sg, host->sg_len,
+                            mmc_get_dma_dir(data));
                goto force_pio;
+       }
 
        if (data->flags & MMC_DATA_READ) {
                dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
-               dir = DMA_FROM_DEVICE;
                if (test_bit(SDHI_INTERNAL_DMAC_ONE_RX_ONLY, &global_flags) &&
                    test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags))
                        goto force_pio;
        } else {
                dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
-               dir = DMA_TO_DEVICE;
        }
 
-       ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, dir);
-       if (ret == 0)
-               goto force_pio;
-
        renesas_sdhi_internal_dmac_enable_dma(host, true);
 
        /* set dma parameters */
        renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
                                            dtran_mode);
        renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
-                                           sg->dma_address);
+                                           sg_dma_address(sg));
 
        return;
 
@@ -272,12 +269,17 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
  * implementation as others may use a different implementation.
  */
 static const struct soc_device_attribute gen3_soc_whitelist[] = {
+       /* specific ones */
        { .soc_id = "r8a7795", .revision = "ES1.*",
          .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
-       { .soc_id = "r8a7795", .revision = "ES2.0" },
        { .soc_id = "r8a7796", .revision = "ES1.0",
          .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
-       { .soc_id = "r8a77995", .revision = "ES1.0" },
+       /* generic ones */
+       { .soc_id = "r8a7795" },
+       { .soc_id = "r8a7796" },
+       { .soc_id = "r8a77965" },
+       { .soc_id = "r8a77980" },
+       { .soc_id = "r8a77995" },
        { /* sentinel */ }
 };
 
index 848e50c1638aa6088f00dce9dd832fce1fd3e4d5..4bb46c489d71f8484de857bcc4f014001271451a 100644 (file)
@@ -42,6 +42,7 @@ static const struct renesas_sdhi_of_data of_rz_compatible = {
 static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = {
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL,
        .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+       .capabilities2  = MMC_CAP2_NO_WRITE_PROTECT,
 };
 
 /* Definitions for sampling clocks */
@@ -61,6 +62,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {
                          TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
        .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
                          MMC_CAP_CMD23,
+       .capabilities2  = MMC_CAP2_NO_WRITE_PROTECT,
        .dma_buswidth   = DMA_SLAVE_BUSWIDTH_4_BYTES,
        .dma_rx_offset  = 0x2000,
        .scc_offset     = 0x0300,
@@ -81,6 +83,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
                          TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
        .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
                          MMC_CAP_CMD23,
+       .capabilities2  = MMC_CAP2_NO_WRITE_PROTECT,
        .bus_shift      = 2,
        .scc_offset     = 0x1000,
        .taps           = rcar_gen3_scc_taps,
index 78422079ecfa425689bbdcf3882dfbe11afc694a..9a3ff22dd0fe29353ffa20a94695670b15c81737 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sd.h>
-#include <linux/mmc/sdio.h>
 #include <linux/mmc/card.h>
 #include <linux/scatterlist.h>
 #include <linux/pm_runtime.h>
@@ -343,7 +342,7 @@ static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host,
        }
 
        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_usb_write_register(ucr, SD_BUS_STAT,
@@ -839,17 +838,6 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
                goto finish_detect_card;
        }
 
-       /*
-        * Reject SDIO CMDs to speed up card identification
-        * since unsupported
-        */
-       if (cmd->opcode == SD_IO_SEND_OP_COND ||
-           cmd->opcode == SD_IO_RW_DIRECT ||
-           cmd->opcode == SD_IO_RW_EXTENDED) {
-               cmd->error = -EINVAL;
-               goto finish;
-       }
-
        mutex_lock(&ucr->dev_mutex);
 
        mutex_lock(&host->host_mutex);
@@ -1332,8 +1320,9 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
        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_SDR50 |
-               MMC_CAP_NEEDS_POLL;
-       mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE;
+               MMC_CAP_NEEDS_POLL | MMC_CAP_ERASE;
+       mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE |
+               MMC_CAP2_NO_SDIO;
 
        mmc->max_current_330 = 400;
        mmc->max_current_180 = 800;
index 11ca95c60bcf5738e98ec9f16cd6dd79b5b1c042..bdbd4897c0f7322a5e1dcb287b6ce36921b789f0 100644 (file)
@@ -284,10 +284,8 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
        sdhci_bcm_kona_sd_init(host);
 
        ret = sdhci_add_host(host);
-       if (ret) {
-               dev_err(dev, "Failed sdhci_add_host\n");
+       if (ret)
                goto err_reset;
-       }
 
        /* if device is eMMC, emulate card insert right here */
        if (!mmc_card_is_removable(host->mmc)) {
index 0f589e26ee6399d6087a776b174df7c3a6bc522b..7a343b87b5e581814235bdf4bbe0cd660732d27e 100644 (file)
@@ -253,6 +253,7 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
        struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
        void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
        u32 tmp;
+       int i, ret;
 
        if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
                return -EINVAL;
@@ -260,11 +261,24 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
        tmp = readl(reg);
        tmp &= ~SDHCI_CDNS_HRS06_TUNE;
        tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
-       tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
-       writel(tmp, reg);
 
-       return readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS06_TUNE_UP),
-                                 0, 1);
+       /*
+        * Workaround for IP errata:
+        * The IP6116 SD/eMMC PHY design has a timing issue on receive data
+        * path. Send tune request twice.
+        */
+       for (i = 0; i < 2; i++) {
+               tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
+               writel(tmp, reg);
+
+               ret = readl_poll_timeout(reg, tmp,
+                                        !(tmp & SDHCI_CDNS_HRS06_TUNE_UP),
+                                        0, 1);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)
index cd2b5f643a1505c81b1d60109ddfb6a994549951..d6aef70d34fac0554d223bed4121e173dea1281d 100644 (file)
 #define  ESDHC_VENDOR_SPEC_FRC_SDCLK_ON        (1 << 8)
 #define ESDHC_WTMK_LVL                 0x44
 #define  ESDHC_WTMK_DEFAULT_VAL                0x10401040
+#define  ESDHC_WTMK_LVL_RD_WML_MASK    0x000000FF
+#define  ESDHC_WTMK_LVL_RD_WML_SHIFT   0
+#define  ESDHC_WTMK_LVL_WR_WML_MASK    0x00FF0000
+#define  ESDHC_WTMK_LVL_WR_WML_SHIFT   16
+#define  ESDHC_WTMK_LVL_WML_VAL_DEF    64
+#define  ESDHC_WTMK_LVL_WML_VAL_MAX    128
 #define ESDHC_MIX_CTRL                 0x48
 #define  ESDHC_MIX_CTRL_DDREN          (1 << 3)
 #define  ESDHC_MIX_CTRL_AC23EN         (1 << 7)
@@ -516,6 +522,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                }
 
                if (esdhc_is_usdhc(imx_data)) {
+                       u32 wml;
                        u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
                        /* Swap AC23 bit */
                        if (val & SDHCI_TRNS_AUTO_CMD23) {
@@ -524,6 +531,21 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                        }
                        m = val | (m & ~ESDHC_MIX_CTRL_SDHCI_MASK);
                        writel(m, host->ioaddr + ESDHC_MIX_CTRL);
+
+                       /* Set watermark levels for PIO access to maximum value
+                        * (128 words) to accommodate full 512 bytes buffer.
+                        * For DMA access restore the levels to default value.
+                        */
+                       m = readl(host->ioaddr + ESDHC_WTMK_LVL);
+                       if (val & SDHCI_TRNS_DMA)
+                               wml = ESDHC_WTMK_LVL_WML_VAL_DEF;
+                       else
+                               wml = ESDHC_WTMK_LVL_WML_VAL_MAX;
+                       m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK |
+                              ESDHC_WTMK_LVL_WR_WML_MASK);
+                       m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) |
+                            (wml << ESDHC_WTMK_LVL_WR_WML_SHIFT);
+                       writel(m, host->ioaddr + ESDHC_WTMK_LVL);
                } else {
                        /*
                         * Postpone this write, we must do it together with a
index c283291db705238dab53ee0104808a198aa4288e..646bf377ba77bbe8f4c93ee7082712453c4ecbb6 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/iopoll.h>
+#include <linux/regulator/consumer.h>
 
 #include "sdhci-pltfm.h"
 
 #define CORE_HC_MCLK_SEL_DFLT  (2 << 8)
 #define CORE_HC_MCLK_SEL_HS400 (3 << 8)
 #define CORE_HC_MCLK_SEL_MASK  (3 << 8)
+#define CORE_IO_PAD_PWR_SWITCH_EN      (1 << 15)
+#define CORE_IO_PAD_PWR_SWITCH  (1 << 16)
 #define CORE_HC_SELECT_IN_EN   BIT(18)
 #define CORE_HC_SELECT_IN_HS400        (6 << 19)
 #define CORE_HC_SELECT_IN_MASK (7 << 19)
 
+#define CORE_3_0V_SUPPORT      (1 << 25)
+#define CORE_1_8V_SUPPORT      (1 << 26)
+#define CORE_VOLT_SUPPORT      (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT)
+
 #define CORE_CSR_CDC_CTLR_CFG0         0x130
 #define CORE_SW_TRIG_FULL_CALIB                BIT(16)
 #define CORE_HW_AUTOCAL_ENA            BIT(17)
@@ -148,6 +155,7 @@ struct sdhci_msm_host {
        u32 curr_io_level;
        wait_queue_head_t pwr_irq_wait;
        bool pwr_irq_flag;
+       u32 caps_0;
 };
 
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -1103,8 +1111,8 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
        u32 irq_status, irq_ack = 0;
        int retry = 10;
-       int pwr_state = 0, io_level = 0;
-
+       u32 pwr_state = 0, io_level = 0;
+       u32 config;
 
        irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
        irq_status &= INT_MASK;
@@ -1161,6 +1169,38 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
         */
        writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
 
+       /*
+        * If we don't have info regarding the voltage levels supported by
+        * regulators, don't change the IO PAD PWR SWITCH.
+        */
+       if (msm_host->caps_0 & CORE_VOLT_SUPPORT) {
+               u32 new_config;
+               /*
+                * We should unset IO PAD PWR switch only if the register write
+                * can set IO lines high and the regulator also switches to 3 V.
+                * Else, we should keep the IO PAD PWR switch set.
+                * This is applicable to certain targets where eMMC vccq supply
+                * is only 1.8V. In such targets, even during REQ_IO_HIGH, the
+                * IO PAD PWR switch must be kept set to reflect actual
+                * regulator voltage. This way, during initialization of
+                * controllers with only 1.8V, we will set the IO PAD bit
+                * without waiting for a REQ_IO_LOW.
+                */
+               config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
+               new_config = config;
+
+               if ((io_level & REQ_IO_HIGH) &&
+                               (msm_host->caps_0 & CORE_3_0V_SUPPORT))
+                       new_config &= ~CORE_IO_PAD_PWR_SWITCH;
+               else if ((io_level & REQ_IO_LOW) ||
+                               (msm_host->caps_0 & CORE_1_8V_SUPPORT))
+                       new_config |= CORE_IO_PAD_PWR_SWITCH;
+
+               if (config ^ new_config)
+                       writel_relaxed(new_config,
+                                       host->ioaddr + CORE_VENDOR_SPEC);
+       }
+
        if (pwr_state)
                msm_host->curr_pwr_state = pwr_state;
        if (io_level)
@@ -1313,6 +1353,45 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg)
                sdhci_msm_check_power_status(host, req_type);
 }
 
+static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host)
+{
+       struct mmc_host *mmc = msm_host->mmc;
+       struct regulator *supply = mmc->supply.vqmmc;
+       u32 caps = 0, config;
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (!IS_ERR(mmc->supply.vqmmc)) {
+               if (regulator_is_supported_voltage(supply, 1700000, 1950000))
+                       caps |= CORE_1_8V_SUPPORT;
+               if (regulator_is_supported_voltage(supply, 2700000, 3600000))
+                       caps |= CORE_3_0V_SUPPORT;
+
+               if (!caps)
+                       pr_warn("%s: 1.8/3V not supported for vqmmc\n",
+                                       mmc_hostname(mmc));
+       }
+
+       if (caps) {
+               /*
+                * Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH
+                * bit can be used as required later on.
+                */
+               u32 io_level = msm_host->curr_io_level;
+
+               config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
+               config |= CORE_IO_PAD_PWR_SWITCH_EN;
+
+               if ((io_level & REQ_IO_HIGH) && (caps & CORE_3_0V_SUPPORT))
+                       config &= ~CORE_IO_PAD_PWR_SWITCH;
+               else if ((io_level & REQ_IO_LOW) || (caps & CORE_1_8V_SUPPORT))
+                       config |= CORE_IO_PAD_PWR_SWITCH;
+
+               writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
+       }
+       msm_host->caps_0 |= caps;
+       pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
+}
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
        { .compatible = "qcom,sdhci-msm-v4" },
        {},
@@ -1333,7 +1412,6 @@ static const struct sdhci_ops sdhci_msm_ops = {
 
 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 |
                  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
        .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
@@ -1530,6 +1608,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        ret = sdhci_add_host(host);
        if (ret)
                goto pm_runtime_disable;
+       sdhci_msm_set_regulator_caps(msm_host);
 
        pm_runtime_mark_last_busy(&pdev->dev);
        pm_runtime_put_autosuspend(&pdev->dev);
index c33a5f7393bd189b99e805dfc3a10f15fdd1e7bd..e3332a522a5d9c0bd0fc0f41bbd17cef99ea503b 100644 (file)
@@ -290,7 +290,8 @@ static const struct sdhci_pltfm_data sdhci_arasan_pdata = {
        .ops = &sdhci_arasan_ops,
        .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
        .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
-                       SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
+                       SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
+                       SDHCI_QUIRK2_STOP_WITH_TC,
 };
 
 static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
@@ -359,8 +360,7 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = {
  */
 static int sdhci_arasan_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
        int ret;
@@ -403,8 +403,7 @@ static int sdhci_arasan_suspend(struct device *dev)
  */
 static int sdhci_arasan_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
        int ret;
index 1456abd5eeb9563aa6a5cec10d066a019a02201f..f3a7c8ece4bef74c0cd29ea28361157d44ed418e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/sys_soc.h>
 
 #include "sdhci-pltfm.h"
 
@@ -35,6 +36,7 @@
 #define CON_DDR                        BIT(19)
 #define CON_CLKEXTFREE         BIT(16)
 #define CON_PADEN              BIT(15)
+#define CON_CTPL               BIT(11)
 #define CON_INIT               BIT(1)
 #define CON_OD                 BIT(0)
 
@@ -100,6 +102,7 @@ struct sdhci_omap_data {
 };
 
 struct sdhci_omap_host {
+       char                    *version;
        void __iomem            *base;
        struct device           *dev;
        struct  regulator       *pbias;
@@ -224,6 +227,23 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host,
        }
 }
 
+static void sdhci_omap_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+       u32 reg;
+
+       reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+       if (enable)
+               reg |= (CON_CTPL | CON_CLKEXTFREE);
+       else
+               reg &= ~(CON_CTPL | CON_CLKEXTFREE);
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
+
+       sdhci_enable_sdio_irq(mmc, enable);
+}
+
 static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host,
                                      int count)
 {
@@ -713,10 +733,15 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = {
                  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
        .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN |
                   SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
-                  SDHCI_QUIRK2_RSP_136_HAS_CRC,
+                  SDHCI_QUIRK2_RSP_136_HAS_CRC |
+                  SDHCI_QUIRK2_DISABLE_HW_TIMEOUT,
        .ops = &sdhci_omap_ops,
 };
 
+static const struct sdhci_omap_data k2g_data = {
+       .offset = 0x200,
+};
+
 static const struct sdhci_omap_data dra7_data = {
        .offset = 0x200,
        .flags  = SDHCI_OMAP_REQUIRE_IODELAY,
@@ -724,6 +749,7 @@ static const struct sdhci_omap_data dra7_data = {
 
 static const struct of_device_id omap_sdhci_match[] = {
        { .compatible = "ti,dra7-sdhci", .data = &dra7_data },
+       { .compatible = "ti,k2g-sdhci", .data = &k2g_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, omap_sdhci_match);
@@ -733,12 +759,21 @@ static struct pinctrl_state
                                  u32 *caps, u32 capmask)
 {
        struct device *dev = omap_host->dev;
+       char *version = omap_host->version;
        struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV);
+       char str[20];
 
        if (!(*caps & capmask))
                goto ret;
 
-       pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode);
+       if (version) {
+               snprintf(str, 20, "%s-%s", mode, version);
+               pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, str);
+       }
+
+       if (IS_ERR(pinctrl_state))
+               pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode);
+
        if (IS_ERR(pinctrl_state)) {
                dev_err(dev, "no pinctrl state for %s mode", mode);
                *caps &= ~capmask;
@@ -807,8 +842,15 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host
 
        state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_1_8v", caps,
                                                 MMC_CAP_1_8V_DDR);
-       if (!IS_ERR(state))
+       if (!IS_ERR(state)) {
                pinctrl_state[MMC_TIMING_MMC_DDR52] = state;
+       } else {
+               state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_3_3v",
+                                                        caps,
+                                                        MMC_CAP_3_3V_DDR);
+               if (!IS_ERR(state))
+                       pinctrl_state[MMC_TIMING_MMC_DDR52] = state;
+       }
 
        state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps,
                                                 MMC_CAP_SD_HIGHSPEED);
@@ -830,6 +872,16 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host
        return 0;
 }
 
+static const struct soc_device_attribute sdhci_omap_soc_devices[] = {
+       {
+               .machine = "DRA7[45]*",
+               .revision = "ES1.[01]",
+       },
+       {
+               /* sentinel */
+       }
+};
+
 static int sdhci_omap_probe(struct platform_device *pdev)
 {
        int ret;
@@ -841,6 +893,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
        struct mmc_host *mmc;
        const struct of_device_id *match;
        struct sdhci_omap_data *data;
+       const struct soc_device_attribute *soc;
 
        match = of_match_device(omap_sdhci_match, dev);
        if (!match)
@@ -871,10 +924,22 @@ static int sdhci_omap_probe(struct platform_device *pdev)
        host->ioaddr += offset;
 
        mmc = host->mmc;
+       sdhci_get_of_property(pdev);
        ret = mmc_of_parse(mmc);
        if (ret)
                goto err_pltfm_free;
 
+       soc = soc_device_match(sdhci_omap_soc_devices);
+       if (soc) {
+               omap_host->version = "rev11";
+               if (!strcmp(dev_name(dev), "4809c000.mmc"))
+                       mmc->f_max = 96000000;
+               if (!strcmp(dev_name(dev), "480b4000.mmc"))
+                       mmc->f_max = 48000000;
+               if (!strcmp(dev_name(dev), "480ad000.mmc"))
+                       mmc->f_max = 48000000;
+       }
+
        pltfm_host->clk = devm_clk_get(dev, "fck");
        if (IS_ERR(pltfm_host->clk)) {
                ret = PTR_ERR(pltfm_host->clk);
@@ -916,26 +981,31 @@ static int sdhci_omap_probe(struct platform_device *pdev)
                goto err_put_sync;
        }
 
-       ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host);
-       if (ret)
-               goto err_put_sync;
-
        host->mmc_host_ops.get_ro = mmc_gpio_get_ro;
        host->mmc_host_ops.start_signal_voltage_switch =
                                        sdhci_omap_start_signal_voltage_switch;
        host->mmc_host_ops.set_ios = sdhci_omap_set_ios;
        host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
        host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
+       host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq;
 
-       sdhci_read_caps(host);
-       host->caps |= SDHCI_CAN_DO_ADMA2;
-
-       ret = sdhci_add_host(host);
+       ret = sdhci_setup_host(host);
        if (ret)
                goto err_put_sync;
 
+       ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host);
+       if (ret)
+               goto err_cleanup_host;
+
+       ret = __sdhci_add_host(host);
+       if (ret)
+               goto err_cleanup_host;
+
        return 0;
 
+err_cleanup_host:
+       sdhci_cleanup_host(host);
+
 err_put_sync:
        pm_runtime_put_sync(dev);
 
index 78c25ad35fd27f019b24f2f4045f214b0e8b5ed5..77dd3521daae4aee806190db9f7970b44b87daa7 100644 (file)
@@ -453,6 +453,7 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
 enum {
        INTEL_DSM_FNS           =  0,
        INTEL_DSM_V18_SWITCH    =  3,
+       INTEL_DSM_V33_SWITCH    =  4,
        INTEL_DSM_DRV_STRENGTH  =  9,
        INTEL_DSM_D3_RETUNE     = 10,
 };
@@ -620,17 +621,37 @@ static void intel_hs400_enhanced_strobe(struct mmc_host *mmc,
        sdhci_writel(host, val, INTEL_HS400_ES_REG);
 }
 
-static void sdhci_intel_voltage_switch(struct sdhci_host *host)
+static int intel_start_signal_voltage_switch(struct mmc_host *mmc,
+                                            struct mmc_ios *ios)
 {
+       struct device *dev = mmc_dev(mmc);
+       struct sdhci_host *host = mmc_priv(mmc);
        struct sdhci_pci_slot *slot = sdhci_priv(host);
        struct intel_host *intel_host = sdhci_pci_priv(slot);
-       struct device *dev = &slot->chip->pdev->dev;
+       unsigned int fn;
        u32 result = 0;
        int err;
 
-       err = intel_dsm(intel_host, dev, INTEL_DSM_V18_SWITCH, &result);
-       pr_debug("%s: %s DSM error %d result %u\n",
-                mmc_hostname(host->mmc), __func__, err, result);
+       err = sdhci_start_signal_voltage_switch(mmc, ios);
+       if (err)
+               return err;
+
+       switch (ios->signal_voltage) {
+       case MMC_SIGNAL_VOLTAGE_330:
+               fn = INTEL_DSM_V33_SWITCH;
+               break;
+       case MMC_SIGNAL_VOLTAGE_180:
+               fn = INTEL_DSM_V18_SWITCH;
+               break;
+       default:
+               return 0;
+       }
+
+       err = intel_dsm(intel_host, dev, fn, &result);
+       pr_debug("%s: %s DSM fn %u error %d result %u\n",
+                mmc_hostname(mmc), __func__, fn, err, result);
+
+       return 0;
 }
 
 static const struct sdhci_ops sdhci_intel_byt_ops = {
@@ -641,7 +662,6 @@ static const struct sdhci_ops sdhci_intel_byt_ops = {
        .reset                  = sdhci_reset,
        .set_uhs_signaling      = sdhci_set_uhs_signaling,
        .hw_reset               = sdhci_pci_hw_reset,
-       .voltage_switch         = sdhci_intel_voltage_switch,
 };
 
 static const struct sdhci_ops sdhci_intel_glk_ops = {
@@ -652,7 +672,6 @@ static const struct sdhci_ops sdhci_intel_glk_ops = {
        .reset                  = sdhci_reset,
        .set_uhs_signaling      = sdhci_set_uhs_signaling,
        .hw_reset               = sdhci_pci_hw_reset,
-       .voltage_switch         = sdhci_intel_voltage_switch,
        .irq                    = sdhci_cqhci_irq,
 };
 
@@ -691,6 +710,7 @@ static void byt_probe_slot(struct sdhci_pci_slot *slot)
        byt_read_dsm(slot);
 
        ops->execute_tuning = intel_execute_tuning;
+       ops->start_signal_voltage_switch = intel_start_signal_voltage_switch;
 }
 
 static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
@@ -832,6 +852,10 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
            slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_SD)
                slot->host->mmc_host_ops.get_cd = bxt_get_cd;
 
+       if (slot->chip->pdev->subsystem_vendor == PCI_VENDOR_ID_NI &&
+           slot->chip->pdev->subsystem_device == PCI_SUBDEVICE_ID_NI_78E3)
+               slot->host->mmc->caps2 |= MMC_CAP2_AVOID_3_3V;
+
        return 0;
 }
 
index 5cbcdc448f98fdcb53533f64fe4c176fd2796d70..db9cb54ef700c693e456d8c7a66b9178beaf051b 100644 (file)
@@ -54,6 +54,7 @@
 #define PCI_DEVICE_ID_REALTEK_5250     0x5250
 
 #define PCI_SUBDEVICE_ID_NI_7884       0x7884
+#define PCI_SUBDEVICE_ID_NI_78E3       0x78e3
 
 #define PCI_VENDOR_ID_ARASAN           0x16e6
 #define PCI_DEVICE_ID_ARASAN_PHY_EMMC  0x0670
index a6caa49ca25acb67e62ce7d23c435b70c9624349..a11e6397d4ff815d758c809b76000bdcd4f3421f 100644 (file)
@@ -200,10 +200,8 @@ static int pic32_sdhci_probe(struct platform_device *pdev)
        }
 
        ret = sdhci_add_host(host);
-       if (ret) {
-               dev_err(&pdev->dev, "error adding host\n");
+       if (ret)
                goto err_base_clk;
-       }
 
        dev_info(&pdev->dev, "Successfully added sdhci host\n");
        return 0;
index 8986f9d9cf98bc3961f5210db7d88f84722a5c2d..2c3827f54927e5658fc8e12cc70c4ede0e47c3c2 100644 (file)
@@ -221,10 +221,8 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
        host->ops = &pxav2_sdhci_ops;
 
        ret = sdhci_add_host(host);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add host\n");
+       if (ret)
                goto disable_clk;
-       }
 
        return 0;
 
index a34434166ca7bcf54d2a426b50bdd765de39c76b..b8e96f39242890982f0815b2731c336dd58cda50 100644 (file)
@@ -472,10 +472,8 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
        pm_suspend_ignore_children(&pdev->dev, 1);
 
        ret = sdhci_add_host(host);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add host\n");
+       if (ret)
                goto err_add_host;
-       }
 
        if (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ)
                device_init_wakeup(&pdev->dev, 1);
index cda83ccb2702139856a059f9ceef84b650df3a38..9ef89d00970e1abf2c0cf27cfe0aa9e23bd0bdf6 100644 (file)
@@ -655,10 +655,8 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
                goto err_req_regs;
 
        ret = sdhci_add_host(host);
-       if (ret) {
-               dev_err(dev, "sdhci_add_host() failed\n");
+       if (ret)
                goto err_req_regs;
-       }
 
 #ifdef CONFIG_PM
        if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
index 14511526a3a8f2cbe8379f00fca6a227582c4dda..9247d51f2eed232f08aaf4875a0aacb7034a66d0 100644 (file)
@@ -126,10 +126,8 @@ static int sdhci_probe(struct platform_device *pdev)
        }
 
        ret = sdhci_add_host(host);
-       if (ret) {
-               dev_dbg(&pdev->dev, "error adding host\n");
+       if (ret)
                goto disable_clk;
-       }
 
        platform_set_drvdata(pdev, host);
 
index c32daed0d418006c11310c086ca289613022d0be..8f95647195d933348c434dfe03b6e53c902ed44b 100644 (file)
@@ -422,10 +422,8 @@ static int sdhci_st_probe(struct platform_device *pdev)
        st_mmcss_cconfig(np, host);
 
        ret = sdhci_add_host(host);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed sdhci_add_host\n");
+       if (ret)
                goto err_out;
-       }
 
        host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
 
index b877c13184c2dd2e519e4f7ff2f573d96a9f9c0e..970d38f6893998203dc76050c58a7354bf149cc5 100644 (file)
@@ -231,7 +231,7 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
        if (timing == MMC_TIMING_UHS_DDR50)
                tegra_host->ddr_signaling = true;
 
-       return sdhci_set_uhs_signaling(host, timing);
+       sdhci_set_uhs_signaling(host, timing);
 }
 
 static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)
index ec87943352418056ad40b09bba05c0f3569ecbf6..a35804b203a752e0acded7ca10e8144a2ebd68fd 100644 (file)
@@ -814,15 +814,10 @@ static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
-       int i, ret;
+       int ret;
 
-       for (i = 0; i < NR_PHY_TYPES; i++) {
-               if (!strcmp(phy_name, phy_types[i])) {
-                       priv->phy_type = i;
-                       break;
-               }
-       }
-       if (i == NR_PHY_TYPES) {
+       priv->phy_type = match_string(phy_types, NR_PHY_TYPES, phy_name);
+       if (priv->phy_type < 0) {
                dev_err(mmc_dev(host->mmc),
                        "Unable to determine PHY name %s. Use default eMMC 5.1 PHY\n",
                        phy_name);
index 2ededa7f43dffc37fb4fa27aeb8cde884fd6c14e..1c828e0e9905ce37d66d03a08b7673c3391d006d 100644 (file)
@@ -709,29 +709,16 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
                return sg_dma_address(host->data->sg);
 }
 
-static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+static unsigned int sdhci_target_timeout(struct sdhci_host *host,
+                                        struct mmc_command *cmd,
+                                        struct mmc_data *data)
 {
-       u8 count;
-       struct mmc_data *data = cmd->data;
-       unsigned target_timeout, current_timeout;
-
-       /*
-        * If the host controller provides us with an incorrect timeout
-        * value, just skip the check and use 0xE.  The hardware may take
-        * longer to time out, but that's much better than having a too-short
-        * timeout value.
-        */
-       if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
-               return 0xE;
-
-       /* Unspecified timeout, assume max */
-       if (!data && !cmd->busy_timeout)
-               return 0xE;
+       unsigned int target_timeout;
 
        /* timeout in us */
-       if (!data)
+       if (!data) {
                target_timeout = cmd->busy_timeout * 1000;
-       else {
+       else {
                target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
                if (host->clock && data->timeout_clks) {
                        unsigned long long val;
@@ -748,6 +735,67 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
                }
        }
 
+       return target_timeout;
+}
+
+static void sdhci_calc_sw_timeout(struct sdhci_host *host,
+                                 struct mmc_command *cmd)
+{
+       struct mmc_data *data = cmd->data;
+       struct mmc_host *mmc = host->mmc;
+       struct mmc_ios *ios = &mmc->ios;
+       unsigned char bus_width = 1 << ios->bus_width;
+       unsigned int blksz;
+       unsigned int freq;
+       u64 target_timeout;
+       u64 transfer_time;
+
+       target_timeout = sdhci_target_timeout(host, cmd, data);
+       target_timeout *= NSEC_PER_USEC;
+
+       if (data) {
+               blksz = data->blksz;
+               freq = host->mmc->actual_clock ? : host->clock;
+               transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
+               do_div(transfer_time, freq);
+               /* multiply by '2' to account for any unknowns */
+               transfer_time = transfer_time * 2;
+               /* calculate timeout for the entire data */
+               host->data_timeout = data->blocks * target_timeout +
+                                    transfer_time;
+       } else {
+               host->data_timeout = target_timeout;
+       }
+
+       if (host->data_timeout)
+               host->data_timeout += MMC_CMD_TRANSFER_TIME;
+}
+
+static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
+                            bool *too_big)
+{
+       u8 count;
+       struct mmc_data *data = cmd->data;
+       unsigned target_timeout, current_timeout;
+
+       *too_big = true;
+
+       /*
+        * If the host controller provides us with an incorrect timeout
+        * value, just skip the check and use 0xE.  The hardware may take
+        * longer to time out, but that's much better than having a too-short
+        * timeout value.
+        */
+       if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
+               return 0xE;
+
+       /* Unspecified timeout, assume max */
+       if (!data && !cmd->busy_timeout)
+               return 0xE;
+
+       /* timeout in us */
+       target_timeout = sdhci_target_timeout(host, cmd, data);
+
        /*
         * Figure out needed cycles.
         * We do this in steps in order to fit inside a 32 bit int.
@@ -768,9 +816,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
        }
 
        if (count >= 0xF) {
-               DBG("Too large timeout 0x%x requested for CMD%d!\n",
-                   count, cmd->opcode);
+               if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT))
+                       DBG("Too large timeout 0x%x requested for CMD%d!\n",
+                           count, cmd->opcode);
                count = 0xE;
+       } else {
+               *too_big = false;
        }
 
        return count;
@@ -790,6 +841,16 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
        sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
+static void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
+{
+       if (enable)
+               host->ier |= SDHCI_INT_DATA_TIMEOUT;
+       else
+               host->ier &= ~SDHCI_INT_DATA_TIMEOUT;
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
 static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
        u8 count;
@@ -797,7 +858,18 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
        if (host->ops->set_timeout) {
                host->ops->set_timeout(host, cmd);
        } else {
-               count = sdhci_calc_timeout(host, cmd);
+               bool too_big = false;
+
+               count = sdhci_calc_timeout(host, cmd, &too_big);
+
+               if (too_big &&
+                   host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
+                       sdhci_calc_sw_timeout(host, cmd);
+                       sdhci_set_data_timeout_irq(host, false);
+               } else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
+                       sdhci_set_data_timeout_irq(host, true);
+               }
+
                sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
        }
 }
@@ -807,6 +879,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
        u8 ctrl;
        struct mmc_data *data = cmd->data;
 
+       host->data_timeout = 0;
+
        if (sdhci_data_line_cmd(cmd))
                sdhci_set_timeout(host, cmd);
 
@@ -1160,13 +1234,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                mdelay(1);
        }
 
-       timeout = jiffies;
-       if (!cmd->data && cmd->busy_timeout > 9000)
-               timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
-       else
-               timeout += 10 * HZ;
-       sdhci_mod_timer(host, cmd->mrq, timeout);
-
        host->cmd = cmd;
        if (sdhci_data_line_cmd(cmd)) {
                WARN_ON(host->data_cmd);
@@ -1206,6 +1273,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
            cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
                flags |= SDHCI_CMD_DATA;
 
+       timeout = jiffies;
+       if (host->data_timeout)
+               timeout += nsecs_to_jiffies(host->data_timeout);
+       else if (!cmd->data && cmd->busy_timeout > 9000)
+               timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
+       else
+               timeout += 10 * HZ;
+       sdhci_mod_timer(host, cmd->mrq, timeout);
+
        sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
 }
 EXPORT_SYMBOL_GPL(sdhci_send_command);
@@ -3616,6 +3692,10 @@ int sdhci_setup_host(struct sdhci_host *host)
                mmc->max_busy_timeout /= host->timeout_clk;
        }
 
+       if (host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT &&
+           !host->ops->get_max_timeout_count)
+               mmc->max_busy_timeout = 0;
+
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
        mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
 
@@ -3672,6 +3752,16 @@ int sdhci_setup_host(struct sdhci_host *host)
        if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
                host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
                                 SDHCI_SUPPORT_DDR50);
+               /*
+                * The SDHCI controller in a SoC might support HS200/HS400
+                * (indicated using mmc-hs200-1_8v/mmc-hs400-1_8v dt property),
+                * but if the board is modeled such that the IO lines are not
+                * connected to 1.8v then HS200/HS400 cannot be supported.
+                * Disable HS200/HS400 if the board does not have 1.8v connected
+                * to the IO lines. (Applicable for other modes in 1.8v)
+                */
+               mmc->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES);
+               mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS);
        }
 
        /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
index c95b0a4a759467898985a5058eed9e5ec0dd63bd..23966f887da6d8d49f5fd9260dee1ba027564427 100644 (file)
@@ -332,6 +332,14 @@ struct sdhci_adma2_64_desc {
 /* Allow for a a command request and a data request at the same time */
 #define SDHCI_MAX_MRQS         2
 
+/*
+ * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms.
+ * However since the start time of the command, the time between
+ * command and response, and the time between response and start of data is
+ * not known, set the command transfer time to 10ms.
+ */
+#define MMC_CMD_TRANSFER_TIME  (10 * NSEC_PER_MSEC) /* max 10 ms */
+
 enum sdhci_cookie {
        COOKIE_UNMAPPED,
        COOKIE_PRE_MAPPED,      /* mapped by sdhci_pre_req() */
@@ -437,6 +445,11 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN             (1<<15)
 /* Controller has CRC in 136 bit Command Response */
 #define SDHCI_QUIRK2_RSP_136_HAS_CRC                   (1<<16)
+/*
+ * Disable HW timeout if the requested timeout is more than the maximum
+ * obtainable timeout.
+ */
+#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT                        (1<<17)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
@@ -550,6 +563,8 @@ struct sdhci_host {
        /* Host SDMA buffer boundary. */
        u32                     sdma_boundary;
 
+       u64                     data_timeout;
+
        unsigned long private[0] ____cacheline_aligned;
 };
 
index 20cfb20418f3ef52d8c5858c3c051662898fd448..e7472590f2ed6416b800ef85c2efeae574cc6718 100644 (file)
  * the License, or (at your option) any later version.
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-
 #include <linux/clk.h>
 #include <linux/clk/sunxi-ng.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/scatterlist.h>
+#include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/reset.h>
-#include <linux/regulator/consumer.h>
-
-#include <linux/of_address.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
-
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/core.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/sd.h>
 #include <linux/mmc/sdio.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/core.h>
-#include <linux/mmc/card.h>
 #include <linux/mmc/slot-gpio.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
 
 /* register offset definitions */
 #define SDXC_REG_GCTRL (0x00) /* SMC Global Control Register */
@@ -322,10 +320,9 @@ static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host)
        return 0;
 }
 
-static int sunxi_mmc_init_host(struct mmc_host *mmc)
+static int sunxi_mmc_init_host(struct sunxi_mmc_host *host)
 {
        u32 rval;
-       struct sunxi_mmc_host *host = mmc_priv(mmc);
 
        if (sunxi_mmc_reset_host(host))
                return -EIO;
@@ -859,17 +856,48 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
        return 0;
 }
 
-static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+static void sunxi_mmc_set_bus_width(struct sunxi_mmc_host *host,
+                                  unsigned char width)
+{
+       switch (width) {
+       case MMC_BUS_WIDTH_1:
+               mmc_writel(host, REG_WIDTH, SDXC_WIDTH1);
+               break;
+       case MMC_BUS_WIDTH_4:
+               mmc_writel(host, REG_WIDTH, SDXC_WIDTH4);
+               break;
+       case MMC_BUS_WIDTH_8:
+               mmc_writel(host, REG_WIDTH, SDXC_WIDTH8);
+               break;
+       }
+}
+
+static void sunxi_mmc_set_clk(struct sunxi_mmc_host *host, struct mmc_ios *ios)
 {
-       struct sunxi_mmc_host *host = mmc_priv(mmc);
        u32 rval;
 
-       /* Set the power state */
-       switch (ios->power_mode) {
-       case MMC_POWER_ON:
-               break;
+       /* set ddr mode */
+       rval = mmc_readl(host, REG_GCTRL);
+       if (ios->timing == MMC_TIMING_UHS_DDR50 ||
+           ios->timing == MMC_TIMING_MMC_DDR52)
+               rval |= SDXC_DDR_MODE;
+       else
+               rval &= ~SDXC_DDR_MODE;
+       mmc_writel(host, REG_GCTRL, rval);
+
+       host->ferror = sunxi_mmc_clk_set_rate(host, ios);
+       /* Android code had a usleep_range(50000, 55000); here */
+}
 
+static void sunxi_mmc_card_power(struct sunxi_mmc_host *host,
+                                struct mmc_ios *ios)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       switch (ios->power_mode) {
        case MMC_POWER_UP:
+               dev_dbg(mmc_dev(mmc), "Powering card up\n");
+
                if (!IS_ERR(mmc->supply.vmmc)) {
                        host->ferror = mmc_regulator_set_ocr(mmc,
                                                             mmc->supply.vmmc,
@@ -887,53 +915,33 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        }
                        host->vqmmc_enabled = true;
                }
-
-               host->ferror = sunxi_mmc_init_host(mmc);
-               if (host->ferror)
-                       return;
-
-               dev_dbg(mmc_dev(mmc), "power on!\n");
                break;
 
        case MMC_POWER_OFF:
-               dev_dbg(mmc_dev(mmc), "power off!\n");
-               sunxi_mmc_reset_host(host);
+               dev_dbg(mmc_dev(mmc), "Powering card off\n");
+
                if (!IS_ERR(mmc->supply.vmmc))
                        mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
 
                if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled)
                        regulator_disable(mmc->supply.vqmmc);
+
                host->vqmmc_enabled = false;
                break;
-       }
 
-       /* set bus width */
-       switch (ios->bus_width) {
-       case MMC_BUS_WIDTH_1:
-               mmc_writel(host, REG_WIDTH, SDXC_WIDTH1);
-               break;
-       case MMC_BUS_WIDTH_4:
-               mmc_writel(host, REG_WIDTH, SDXC_WIDTH4);
-               break;
-       case MMC_BUS_WIDTH_8:
-               mmc_writel(host, REG_WIDTH, SDXC_WIDTH8);
+       default:
+               dev_dbg(mmc_dev(mmc), "Ignoring unknown card power state\n");
                break;
        }
+}
 
-       /* set ddr mode */
-       rval = mmc_readl(host, REG_GCTRL);
-       if (ios->timing == MMC_TIMING_UHS_DDR50 ||
-           ios->timing == MMC_TIMING_MMC_DDR52)
-               rval |= SDXC_DDR_MODE;
-       else
-               rval &= ~SDXC_DDR_MODE;
-       mmc_writel(host, REG_GCTRL, rval);
+static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct sunxi_mmc_host *host = mmc_priv(mmc);
 
-       /* set up clock */
-       if (ios->power_mode) {
-               host->ferror = sunxi_mmc_clk_set_rate(host, ios);
-               /* Android code had a usleep_range(50000, 55000); here */
-       }
+       sunxi_mmc_card_power(host, ios);
+       sunxi_mmc_set_bus_width(host, ios->bus_width);
+       sunxi_mmc_set_clk(host, ios);
 }
 
 static int sunxi_mmc_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -955,6 +963,9 @@ static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
        unsigned long flags;
        u32 imask;
 
+       if (enable)
+               pm_runtime_get_noresume(host->dev);
+
        spin_lock_irqsave(&host->lock, flags);
 
        imask = mmc_readl(host, REG_IMASK);
@@ -967,6 +978,9 @@ static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
        }
        mmc_writel(host, REG_IMASK, imask);
        spin_unlock_irqrestore(&host->lock, flags);
+
+       if (!enable)
+               pm_runtime_put_noidle(host->mmc->parent);
 }
 
 static void sunxi_mmc_hw_reset(struct mmc_host *mmc)
@@ -1380,6 +1394,15 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
        if (ret)
                goto error_free_dma;
 
+       ret = sunxi_mmc_init_host(host);
+       if (ret)
+               goto error_free_dma;
+
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
        ret = mmc_add_host(mmc);
        if (ret)
                goto error_free_dma;
@@ -1400,6 +1423,7 @@ static int sunxi_mmc_remove(struct platform_device *pdev)
        struct sunxi_mmc_host *host = mmc_priv(mmc);
 
        mmc_remove_host(mmc);
+       pm_runtime_force_suspend(&pdev->dev);
        disable_irq(host->irq);
        sunxi_mmc_disable(host);
        dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
@@ -1408,10 +1432,47 @@ static int sunxi_mmc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int sunxi_mmc_runtime_resume(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct sunxi_mmc_host *host = mmc_priv(mmc);
+       int ret;
+
+       ret = sunxi_mmc_enable(host);
+       if (ret)
+               return ret;
+
+       sunxi_mmc_init_host(host);
+       sunxi_mmc_set_bus_width(host, mmc->ios.bus_width);
+       sunxi_mmc_set_clk(host, &mmc->ios);
+
+       return 0;
+}
+
+static int sunxi_mmc_runtime_suspend(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct sunxi_mmc_host *host = mmc_priv(mmc);
+
+       sunxi_mmc_reset_host(host);
+       sunxi_mmc_disable(host);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops sunxi_mmc_pm_ops = {
+       SET_RUNTIME_PM_OPS(sunxi_mmc_runtime_suspend,
+                          sunxi_mmc_runtime_resume,
+                          NULL)
+};
+
 static struct platform_driver sunxi_mmc_driver = {
        .driver = {
                .name   = "sunxi-mmc",
                .of_match_table = of_match_ptr(sunxi_mmc_of_match),
+               .pm = &sunxi_mmc_pm_ops,
        },
        .probe          = sunxi_mmc_probe,
        .remove         = sunxi_mmc_remove,
index 81dac17064d75c1df707cc9383a18e0fc8ef30ed..b2b379b10dfabf9bb4f3d7171751671ce11d0ff7 100644 (file)
@@ -300,8 +300,10 @@ static void ushc_request(struct mmc_host *mmc, struct mmc_request *req)
                        pipe = usb_sndbulkpipe(ushc->usb_dev, 2);
 
                usb_fill_bulk_urb(ushc->data_urb, ushc->usb_dev, pipe,
-                                 sg_virt(data->sg), data->sg->length,
+                                 NULL, data->sg->length,
                                  data_callback, ushc);
+               ushc->data_urb->num_sgs = 1;
+               ushc->data_urb->sg = data->sg;
                ret = usb_submit_urb(ushc->data_urb, GFP_ATOMIC);
                if (ret < 0)
                        goto out;
index f4233576153bf40f0543435d248ea2c6fbe537fe..1e54bbf13d75bb68bc8383655842353a74e8803b 100644 (file)
@@ -268,43 +268,29 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
        return host->num_sg;
 }
 
-static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
+static inline char *wbsd_map_sg(struct wbsd_host *host)
 {
-       return sg_virt(host->cur_sg);
+       return kmap_atomic(sg_page(host->cur_sg)) + host->cur_sg->offset;
 }
 
 static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
 {
-       unsigned int len, i;
-       struct scatterlist *sg;
-       char *dmabuf = host->dma_buffer;
-       char *sgbuf;
-
-       sg = data->sg;
-       len = data->sg_len;
-
-       for (i = 0; i < len; i++) {
-               sgbuf = sg_virt(&sg[i]);
-               memcpy(dmabuf, sgbuf, sg[i].length);
-               dmabuf += sg[i].length;
-       }
+       size_t len = 0;
+       int i;
+
+       for (i = 0; i < data->sg_len; i++)
+               len += data->sg[i].length;
+       sg_copy_to_buffer(data->sg, data->sg_len, host->dma_buffer, len);
 }
 
 static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
 {
-       unsigned int len, i;
-       struct scatterlist *sg;
-       char *dmabuf = host->dma_buffer;
-       char *sgbuf;
-
-       sg = data->sg;
-       len = data->sg_len;
-
-       for (i = 0; i < len; i++) {
-               sgbuf = sg_virt(&sg[i]);
-               memcpy(sgbuf, dmabuf, sg[i].length);
-               dmabuf += sg[i].length;
-       }
+       size_t len = 0;
+       int i;
+
+       for (i = 0; i < data->sg_len; i++)
+               len += data->sg[i].length;
+       sg_copy_from_buffer(data->sg, data->sg_len, host->dma_buffer, len);
 }
 
 /*
@@ -418,7 +404,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
 {
        struct mmc_data *data = host->mrq->cmd->data;
        char *buffer;
-       int i, fsr, fifo;
+       int i, idx, fsr, fifo;
 
        /*
         * Handle excessive data.
@@ -426,7 +412,8 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
        if (host->num_sg == 0)
                return;
 
-       buffer = wbsd_sg_to_buffer(host) + host->offset;
+       buffer = wbsd_map_sg(host) + host->offset;
+       idx = 0;
 
        /*
         * Drain the fifo. This has a tendency to loop longer
@@ -445,8 +432,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
                        fifo = 1;
 
                for (i = 0; i < fifo; i++) {
-                       *buffer = inb(host->base + WBSD_DFR);
-                       buffer++;
+                       buffer[idx++] = inb(host->base + WBSD_DFR);
                        host->offset++;
                        host->remain--;
 
@@ -456,16 +442,19 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
                         * End of scatter list entry?
                         */
                        if (host->remain == 0) {
+                               kunmap_atomic(buffer);
                                /*
                                 * Get next entry. Check if last.
                                 */
                                if (!wbsd_next_sg(host))
                                        return;
 
-                               buffer = wbsd_sg_to_buffer(host);
+                               buffer = wbsd_map_sg(host);
+                               idx = 0;
                        }
                }
        }
+       kunmap_atomic(buffer);
 
        /*
         * This is a very dirty hack to solve a
@@ -480,7 +469,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
 {
        struct mmc_data *data = host->mrq->cmd->data;
        char *buffer;
-       int i, fsr, fifo;
+       int i, idx, fsr, fifo;
 
        /*
         * Check that we aren't being called after the
@@ -489,7 +478,8 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
        if (host->num_sg == 0)
                return;
 
-       buffer = wbsd_sg_to_buffer(host) + host->offset;
+       buffer = wbsd_map_sg(host) + host->offset;
+       idx = 0;
 
        /*
         * Fill the fifo. This has a tendency to loop longer
@@ -508,8 +498,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
                        fifo = 15;
 
                for (i = 16; i > fifo; i--) {
-                       outb(*buffer, host->base + WBSD_DFR);
-                       buffer++;
+                       outb(buffer[idx], host->base + WBSD_DFR);
                        host->offset++;
                        host->remain--;
 
@@ -519,16 +508,19 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
                         * End of scatter list entry?
                         */
                        if (host->remain == 0) {
+                               kunmap_atomic(buffer);
                                /*
                                 * Get next entry. Check if last.
                                 */
                                if (!wbsd_next_sg(host))
                                        return;
 
-                               buffer = wbsd_sg_to_buffer(host);
+                               buffer = wbsd_map_sg(host);
+                               idx = 0;
                        }
                }
        }
+       kunmap_atomic(buffer);
 
        /*
         * The controller stops sending interrupts for
index fd30ac7da5e5f65636779c04587840a8f0ce8a66..3ba42f50801435356973eabcbf1bb07108f9ffce 100644 (file)
@@ -928,8 +928,7 @@ static int wmt_mci_remove(struct platform_device *pdev)
 static int wmt_mci_suspend(struct device *dev)
 {
        u32 reg_tmp;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
+       struct mmc_host *mmc = dev_get_drvdata(dev);
        struct wmt_mci_priv *priv;
 
        if (!mmc)
@@ -953,8 +952,7 @@ static int wmt_mci_suspend(struct device *dev)
 static int wmt_mci_resume(struct device *dev)
 {
        u32 reg_tmp;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
+       struct mmc_host *mmc = dev_get_drvdata(dev);
        struct wmt_mci_priv *priv;
 
        if (mmc) {
diff --git a/include/dt-bindings/dma/jz4780-dma.h b/include/dt-bindings/dma/jz4780-dma.h
new file mode 100644 (file)
index 0000000..df017fd
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef __DT_BINDINGS_DMA_JZ4780_DMA_H__
+#define __DT_BINDINGS_DMA_JZ4780_DMA_H__
+
+/*
+ * Request type numbers for the JZ4780 DMA controller (written to the DRTn
+ * register for the channel).
+ */
+#define JZ4780_DMA_I2S1_TX     0x4
+#define JZ4780_DMA_I2S1_RX     0x5
+#define JZ4780_DMA_I2S0_TX     0x6
+#define JZ4780_DMA_I2S0_RX     0x7
+#define JZ4780_DMA_AUTO                0x8
+#define JZ4780_DMA_SADC_RX     0x9
+#define JZ4780_DMA_UART4_TX    0xc
+#define JZ4780_DMA_UART4_RX    0xd
+#define JZ4780_DMA_UART3_TX    0xe
+#define JZ4780_DMA_UART3_RX    0xf
+#define JZ4780_DMA_UART2_TX    0x10
+#define JZ4780_DMA_UART2_RX    0x11
+#define JZ4780_DMA_UART1_TX    0x12
+#define JZ4780_DMA_UART1_RX    0x13
+#define JZ4780_DMA_UART0_TX    0x14
+#define JZ4780_DMA_UART0_RX    0x15
+#define JZ4780_DMA_SSI0_TX     0x16
+#define JZ4780_DMA_SSI0_RX     0x17
+#define JZ4780_DMA_SSI1_TX     0x18
+#define JZ4780_DMA_SSI1_RX     0x19
+#define JZ4780_DMA_MSC0_TX     0x1a
+#define JZ4780_DMA_MSC0_RX     0x1b
+#define JZ4780_DMA_MSC1_TX     0x1c
+#define JZ4780_DMA_MSC1_RX     0x1d
+#define JZ4780_DMA_MSC2_TX     0x1e
+#define JZ4780_DMA_MSC2_RX     0x1f
+#define JZ4780_DMA_PCM0_TX     0x20
+#define JZ4780_DMA_PCM0_RX     0x21
+#define JZ4780_DMA_SMB0_TX     0x24
+#define JZ4780_DMA_SMB0_RX     0x25
+#define JZ4780_DMA_SMB1_TX     0x26
+#define JZ4780_DMA_SMB1_RX     0x27
+#define JZ4780_DMA_SMB2_TX     0x28
+#define JZ4780_DMA_SMB2_RX     0x29
+#define JZ4780_DMA_SMB3_TX     0x2a
+#define JZ4780_DMA_SMB3_RX     0x2b
+#define JZ4780_DMA_SMB4_TX     0x2c
+#define JZ4780_DMA_SMB4_RX     0x2d
+#define JZ4780_DMA_DES_TX      0x2e
+#define JZ4780_DMA_DES_RX      0x2f
+
+#endif /* __DT_BINDINGS_DMA_JZ4780_DMA_H__ */
index 279b39008a33bb68745d9ea55ea5dd7ed522fd1c..de7377815b6b4c9828beccd1c6a37932c8a29d0d 100644 (file)
@@ -156,6 +156,7 @@ struct sd_switch_caps {
 #define UHS_DDR50_MAX_DTR      50000000
 #define UHS_SDR25_MAX_DTR      UHS_DDR50_MAX_DTR
 #define UHS_SDR12_MAX_DTR      25000000
+#define DEFAULT_SPEED_MAX_DTR  UHS_SDR12_MAX_DTR
        unsigned int            sd3_bus_mode;
 #define UHS_SDR12_BUS_SPEED    0
 #define HIGH_SPEED_BUS_SPEED   1
@@ -252,6 +253,7 @@ struct mmc_card {
 #define MMC_TYPE_SD_COMBO      3               /* SD combo (IO+mem) card */
        unsigned int            state;          /* (our) card state */
        unsigned int            quirks;         /* card quirks */
+       unsigned int            quirk_max_rate; /* max rate set by quirks */
 #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
                                                /* for byte mode */
index 927519385482e4ab919a9e0dffd5181de450f5a4..134a6483347a1e565d91c812c1e1212e989463bb 100644 (file)
@@ -177,6 +177,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd,
                int retries);
 
 int mmc_hw_reset(struct mmc_host *host);
+int mmc_sw_reset(struct mmc_host *host);
 void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card);
 
 #endif /* LINUX_MMC_CORE_H */
index 85146235231edf4f0d8c747f69a89a3bb2bf3d8a..64300a48dcce8a1b169bd1b63319ad54b86ec9dd 100644 (file)
@@ -22,6 +22,7 @@
 struct mmc_ios {
        unsigned int    clock;                  /* clock rate */
        unsigned short  vdd;
+       unsigned int    power_delay_ms;         /* waiting for stable power */
 
 /* vdd stores the bit number of the selected voltage range from below. */
 
@@ -320,6 +321,9 @@ struct mmc_host {
 #define MMC_CAP_UHS_SDR50      (1 << 18)       /* Host supports UHS SDR50 mode */
 #define MMC_CAP_UHS_SDR104     (1 << 19)       /* Host supports UHS SDR104 mode */
 #define MMC_CAP_UHS_DDR50      (1 << 20)       /* Host supports UHS DDR50 mode */
+#define MMC_CAP_UHS            (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | \
+                                MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | \
+                                MMC_CAP_UHS_DDR50)
 /* (1 << 21) is free for reuse */
 #define MMC_CAP_DRIVER_TYPE_A  (1 << 23)       /* Host supports Driver Type A */
 #define MMC_CAP_DRIVER_TYPE_C  (1 << 24)       /* Host supports Driver Type C */
@@ -345,6 +349,7 @@ struct mmc_host {
 #define MMC_CAP2_HS400_1_2V    (1 << 16)       /* Can support HS400 1.2V */
 #define MMC_CAP2_HS400         (MMC_CAP2_HS400_1_8V | \
                                 MMC_CAP2_HS400_1_2V)
+#define MMC_CAP2_HSX00_1_8V    (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V)
 #define MMC_CAP2_HSX00_1_2V    (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
 #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 */
@@ -354,6 +359,7 @@ struct mmc_host {
 #define MMC_CAP2_NO_MMC                (1 << 22)       /* Do not send (e)MMC commands during initialization */
 #define MMC_CAP2_CQE           (1 << 23)       /* Has eMMC command queue engine */
 #define MMC_CAP2_CQE_DCMD      (1 << 24)       /* CQE can issue a direct command */
+#define MMC_CAP2_AVOID_3_3V    (1 << 25)       /* Host must negotiate down from 3.3V */
 
        int                     fixed_drv_type; /* fixed driver type for non-removable media */
 
index cdd66a5fbd5e00905ff5e6c2623e6efaf12bf225..2836a96e014ac36469eebdd37c7626d424186136 100644 (file)
@@ -55,6 +55,7 @@
 #define SDIO_DEVICE_ID_MARVELL_8688WLAN                0x9104
 #define SDIO_DEVICE_ID_MARVELL_8688BT          0x9105
 #define SDIO_DEVICE_ID_MARVELL_8797_F0         0x9128
+#define SDIO_DEVICE_ID_MARVELL_8887WLAN        0x9134
 
 #define SDIO_VENDOR_ID_SIANO                   0x039a
 #define SDIO_DEVICE_ID_SIANO_NOVA_B0           0x0201