summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt40
-rw-r--r--Documentation/devicetree/bindings/mmc/mtk-sd.txt1
-rw-r--r--Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt9
-rw-r--r--Documentation/devicetree/bindings/mmc/tmio_mmc.txt1
-rw-r--r--arch/arm/boot/dts/lpc18xx.dtsi1
-rw-r--r--arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts1
-rw-r--r--arch/arm/boot/dts/socfpga_arria5.dtsi1
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5.dtsi1
-rw-r--r--arch/arm/boot/dts/socfpga_vt.dts1
-rw-r--r--arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts1
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi3660.dtsi2
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c2
-rw-r--r--drivers/mmc/core/block.c15
-rw-r--r--drivers/mmc/core/core.c5
-rw-r--r--drivers/mmc/core/debugfs.c19
-rw-r--r--drivers/mmc/core/host.h3
-rw-r--r--drivers/mmc/core/mmc.c2
-rw-r--r--drivers/mmc/core/sd.c20
-rw-r--r--drivers/mmc/core/sdio.c9
-rw-r--r--drivers/mmc/core/sdio_irq.c4
-rw-r--r--drivers/mmc/core/slot-gpio.c23
-rw-r--r--drivers/mmc/host/Kconfig9
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/dw_mmc-hi3798cv200.c202
-rw-r--r--drivers/mmc/host/dw_mmc-pci.c1
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c4
-rw-r--r--drivers/mmc/host/dw_mmc.c48
-rw-r--r--drivers/mmc/host/dw_mmc.h27
-rw-r--r--drivers/mmc/host/mtk-sd.c12
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c6
-rw-r--r--drivers/mmc/host/renesas_sdhi_internal_dmac.c11
-rw-r--r--drivers/mmc/host/renesas_sdhi_sys_dmac.c17
-rw-r--r--drivers/mmc/host/sdhci-iproc.c1
-rw-r--r--drivers/mmc/host/sdhci-omap.c378
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c43
-rw-r--r--drivers/mmc/host/sdhci.c19
-rw-r--r--drivers/mmc/host/sh_mmcif.c8
-rw-r--r--drivers/mmc/host/sunxi-mmc.c144
-rw-r--r--drivers/mmc/host/tmio_mmc_core.c66
-rw-r--r--drivers/mmc/host/ushc.c2
-rw-r--r--include/linux/mfd/tmio.h1
-rw-r--r--include/linux/mmc/slot-gpio.h1
42 files changed, 885 insertions, 277 deletions
diff --git a/Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt
new file mode 100644
index 000000000000..a0693b7145f2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt
@@ -0,0 +1,40 @@
+* Hisilicon Hi3798CV200 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 Hisilicon Hi3798CV200
+specific extensions to the Synopsys Designware Mobile Storage Host Controller.
+
+Required Properties:
+- compatible: Should contain "hisilicon,hi3798cv200-dw-mshc".
+- clocks: A list of phandle + clock-specifier pairs for the clocks listed
+ in clock-names.
+- clock-names: Should contain the following:
+ "ciu" - The ciu clock described in synopsys-dw-mshc.txt.
+ "biu" - The biu clock described in synopsys-dw-mshc.txt.
+ "ciu-sample" - Hi3798CV200 extended phase clock for ciu sampling.
+ "ciu-drive" - Hi3798CV200 extended phase clock for ciu driving.
+
+Example:
+
+ emmc: mmc@9830000 {
+ compatible = "hisilicon,hi3798cv200-dw-mshc";
+ reg = <0x9830000 0x10000>;
+ interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&crg HISTB_MMC_CIU_CLK>,
+ <&crg HISTB_MMC_BIU_CLK>,
+ <&crg HISTB_MMC_SAMPLE_CLK>,
+ <&crg HISTB_MMC_DRV_CLK>;
+ clock-names = "ciu", "biu", "ciu-sample", "ciu-drive";
+ fifo-depth = <256>;
+ clock-frequency = <200000000>;
+ cap-mmc-highspeed;
+ mmc-ddr-1_8v;
+ mmc-hs200-1_8v;
+ non-removable;
+ bus-width = <8>;
+ };
diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.txt b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
index 9b8017670870..f33467a54a05 100644
--- a/Documentation/devicetree/bindings/mmc/mtk-sd.txt
+++ b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
@@ -12,6 +12,7 @@ Required properties:
"mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
"mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
"mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
+ "mediatek,mt7622-mmc": for MT7622 SoC
"mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC
- reg: physical base address of the controller and length
diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
index ef3e5f14067a..7e5e427a22ce 100644
--- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
@@ -59,15 +59,6 @@ Optional properties:
is specified and the ciu clock is specified then we'll try to set the ciu
clock to this at probe time.
-* clock-freq-min-max (DEPRECATED): Minimum and Maximum clock frequency for card output
- clock(cclk_out). If it's not specified, max is 200MHZ and min is 400KHz by default.
- (Use the "max-frequency" instead of "clock-freq-min-max".)
-
-* num-slots (DEPRECATED): specifies the number of slots supported by the controller.
- The number of physical slots actually used could be equal or less than the
- value specified by num-slots. If this property is not specified, the value
- of num-slot property is assumed to be 1.
-
* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
specified, the default value of the fifo size is determined from the
controller registers.
diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
index d8685cb83325..2d5287eeed95 100644
--- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
@@ -50,7 +50,6 @@ Required properties:
2: R7S72100
Optional properties:
-- toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
- pinctrl-names: should be "default", "state_uhs"
- pinctrl-0: should contain default/high speed pin ctrl
- pinctrl-1: should contain uhs mode pin ctrl
diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi
index 7cae9c5e27db..10b8249b8ab6 100644
--- a/arch/arm/boot/dts/lpc18xx.dtsi
+++ b/arch/arm/boot/dts/lpc18xx.dtsi
@@ -115,7 +115,6 @@
compatible = "snps,dw-mshc";
reg = <0x40004000 0x1000>;
interrupts = <6>;
- num-slots = <1>;
clocks = <&ccu2 CLK_SDIO>, <&ccu1 CLK_CPU_SDIO>;
clock-names = "ciu", "biu";
resets = <&rgu 20>;
diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts
index 040a164ba148..5822fd2085db 100644
--- a/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts
+++ b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts
@@ -20,7 +20,6 @@
&mmc {
status = "okay";
- num-slots = <1>;
cap-sd-highspeed;
broken-cd;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/socfpga_arria5.dtsi b/arch/arm/boot/dts/socfpga_arria5.dtsi
index 8c037297296c..e59461f5416e 100644
--- a/arch/arm/boot/dts/socfpga_arria5.dtsi
+++ b/arch/arm/boot/dts/socfpga_arria5.dtsi
@@ -30,7 +30,6 @@
};
mmc0: dwmmc0@ff704000 {
- num-slots = <1>;
broken-cd;
bus-width = <4>;
cap-mmc-highspeed;
diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dtsi b/arch/arm/boot/dts/socfpga_cyclone5.dtsi
index a05e3df23103..68ced67f8bfb 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5.dtsi
+++ b/arch/arm/boot/dts/socfpga_cyclone5.dtsi
@@ -31,7 +31,6 @@
};
mmc0: dwmmc0@ff704000 {
- num-slots = <1>;
broken-cd;
bus-width = <4>;
cap-mmc-highspeed;
diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts
index dfe2193cd4d5..547c38632c68 100644
--- a/arch/arm/boot/dts/socfpga_vt.dts
+++ b/arch/arm/boot/dts/socfpga_vt.dts
@@ -42,7 +42,6 @@
};
dwmmc0@ff704000 {
- num-slots = <1>;
broken-cd;
bus-width = <4>;
cap-mmc-highspeed;
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
index 000756429b77..51ce5832ee1d 100644
--- a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
+++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
@@ -88,7 +88,6 @@
&mmc {
status = "okay";
- num-slots = <1>;
cap-sd-highspeed;
broken-cd;
bus-width = <4>;
diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
index 63d4f9dca77f..a7ecd9074ea2 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
@@ -922,7 +922,6 @@
#size-cells = <0>;
cd-inverted;
compatible = "hisilicon,hi3660-dw-mshc";
- num-slots = <1>;
bus-width = <0x4>;
disable-wp;
cap-sd-highspeed;
@@ -960,7 +959,6 @@
compatible = "hisilicon,hi3660-dw-mshc";
reg = <0x0 0xff3ff000 0x0 0x1000>;
interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
- num-slots = <1>;
clocks = <&crg_ctrl HI3660_CLK_GATE_SDIO0>,
<&crg_ctrl HI3660_HCLK_GATE_SDIO0>;
clock-names = "ciu", "biu";
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index 5deb2d82f19f..6af7777332fc 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -375,8 +375,8 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = {
static struct tmio_mmc_data sh7724_sdhi0_data = {
.chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX,
.chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX,
- .flags = TMIO_MMC_WRPROTECT_DISABLE,
.capabilities = MMC_CAP_SDIO_IRQ,
+ .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
};
static struct platform_device kfr2r09_sh_sdhi0_device = {
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 2cfb963d9f37..a2b9c2500c4c 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -376,22 +376,15 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
return idata;
}
- idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL);
- if (!idata->buf) {
- err = -ENOMEM;
+ idata->buf = memdup_user((void __user *)(unsigned long)
+ idata->ic.data_ptr, idata->buf_bytes);
+ if (IS_ERR(idata->buf)) {
+ err = PTR_ERR(idata->buf);
goto idata_err;
}
- if (copy_from_user(idata->buf, (void __user *)(unsigned long)
- idata->ic.data_ptr, idata->buf_bytes)) {
- err = -EFAULT;
- goto copy_err;
- }
-
return idata;
-copy_err:
- kfree(idata->buf);
idata_err:
kfree(idata);
out:
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c0ba6d8823b7..121ce50b6d5e 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2369,7 +2369,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
return card->pref_erase;
max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
- if (mmc_can_trim(card)) {
+ if (max_discard && mmc_can_trim(card)) {
max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG);
if (max_trim < max_discard)
max_discard = max_trim;
@@ -2655,8 +2655,7 @@ void mmc_start_host(struct mmc_host *host)
void mmc_stop_host(struct mmc_host *host)
{
if (host->slot.cd_irq >= 0) {
- if (host->slot.cd_wake_enabled)
- disable_irq_wake(host->slot.cd_irq);
+ mmc_gpio_set_cd_wake(host, false);
disable_irq(host->slot.cd_irq);
}
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 0f4a7d7b2626..d2275c5a2311 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -196,18 +196,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
return 0;
}
-
-static int mmc_ios_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mmc_ios_show, inode->i_private);
-}
-
-static const struct file_operations mmc_ios_fops = {
- .open = mmc_ios_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mmc_ios);
static int mmc_clock_opt_get(void *data, u64 *val)
{
@@ -254,6 +243,12 @@ void mmc_add_host_debugfs(struct mmc_host *host)
if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
goto err_node;
+ if (!debugfs_create_x32("caps", S_IRUSR, root, &host->caps))
+ goto err_node;
+
+ if (!debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2))
+ goto err_node;
+
if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
&mmc_clock_fops))
goto err_node;
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 06ec19b5bf9f..4805438c02ff 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -56,7 +56,8 @@ static inline int mmc_host_uhs(struct mmc_host *host)
return host->caps &
(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50);
+ MMC_CAP_UHS_DDR50) &&
+ host->caps & MMC_CAP_4_BIT_DATA;
}
static inline bool mmc_card_hs200(struct mmc_card *card)
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 208a762b87ef..6f8ebd6caa4c 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -792,6 +792,7 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
+MMC_DEV_ATTR(rca, "0x%04x\n", card->rca);
MMC_DEV_ATTR(cmdq_en, "%d\n", card->ext_csd.cmdq_en);
static ssize_t mmc_fwrev_show(struct device *dev,
@@ -848,6 +849,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_raw_rpmb_size_mult.attr,
&dev_attr_rel_sectors.attr,
&dev_attr_ocr.attr,
+ &dev_attr_rca.attr,
&dev_attr_dsr.attr,
&dev_attr_cmdq_en.attr,
NULL,
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 62b84dd8f9fe..baf3d5da4ccb 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -291,8 +291,6 @@ static int mmc_read_switch(struct mmc_card *card)
return 0;
}
- err = -EIO;
-
status = kmalloc(64, GFP_KERNEL);
if (!status)
return -ENOMEM;
@@ -582,9 +580,6 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
int err;
u8 *status;
- if (!card->scr.sda_spec3)
- return 0;
-
if (!(card->csd.cmdclass & CCC_SWITCH))
return 0;
@@ -593,14 +588,11 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
return -ENOMEM;
/* Set 4-bit bus width */
- if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
- err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err)
- goto out;
+ err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+ if (err)
+ goto out;
- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
- }
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
/*
* Select the bus speed mode depending on host
@@ -676,6 +668,7 @@ MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
+MMC_DEV_ATTR(rca, "0x%04x\n", card->rca);
static ssize_t mmc_dsr_show(struct device *dev,
@@ -709,6 +702,7 @@ static struct attribute *sd_std_attrs[] = {
&dev_attr_oemid.attr,
&dev_attr_serial.attr,
&dev_attr_ocr.attr,
+ &dev_attr_rca.attr,
&dev_attr_dsr.attr,
NULL,
};
@@ -1033,7 +1027,7 @@ retry:
}
/* Initialization sequence for UHS-I cards */
- if (rocr & SD_ROCR_S18A) {
+ if (rocr & SD_ROCR_S18A && mmc_host_uhs(host)) {
err = mmc_sd_init_uhs_card(card);
if (err)
goto free_card;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index cc43687ca241..c599a628a387 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -518,11 +518,10 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
if (!card->scr.sda_spec3)
return 0;
- /*
- * Switch to wider bus (if supported).
- */
- if (card->host->caps & MMC_CAP_4_BIT_DATA)
- err = sdio_enable_4bit_bus(card);
+ /* Switch to wider bus */
+ err = sdio_enable_4bit_bus(card);
+ if (err)
+ goto out;
/* Set the driver strength for the card */
sdio_select_driver_type(card);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 7a2eaf8410a3..7ca7b99413f0 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -277,8 +277,8 @@ static void sdio_single_irq_set(struct mmc_card *card)
*
* Claim and activate the IRQ for the given SDIO function. The provided
* handler will be called when that IRQ is asserted. The host is always
- * claimed already when the handler is called so the handler must not
- * call sdio_claim_host() nor sdio_release_host().
+ * claimed already when the handler is called so the handler should not
+ * call sdio_claim_host() or sdio_release_host().
*/
int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
{
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 3698b0576009..31f7dbb15668 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -149,11 +149,30 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host)
if (irq < 0)
host->caps |= MMC_CAP_NEEDS_POLL;
- else if ((host->caps & MMC_CAP_CD_WAKE) && !enable_irq_wake(irq))
- host->slot.cd_wake_enabled = true;
}
EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
+int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on)
+{
+ int ret = 0;
+
+ if (!(host->caps & MMC_CAP_CD_WAKE) ||
+ host->slot.cd_irq < 0 ||
+ on == host->slot.cd_wake_enabled)
+ return 0;
+
+ if (on) {
+ ret = enable_irq_wake(host->slot.cd_irq);
+ host->slot.cd_wake_enabled = !ret;
+ } else {
+ disable_irq_wake(host->slot.cd_irq);
+ host->slot.cd_wake_enabled = false;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(mmc_gpio_set_cd_wake);
+
/* Register an alternate interrupt service routine for
* the card-detect GPIO.
*/
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index b4fd5d48dd35..9589f9c9046f 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -699,6 +699,15 @@ config MMC_DW_EXYNOS
Synopsys DesignWare Memory Card Interface driver. Select this option
for platforms based on Exynos4 and Exynos5 SoC's.
+config MMC_DW_HI3798CV200
+ tristate "Hi3798CV200 specific extensions for Synopsys DW Memory Card Interface"
+ depends on MMC_DW
+ select MMC_DW_PLTFM
+ help
+ This selects support for HiSilicon Hi3798CV200 SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on HiSilicon Hi3798CV200 SoC.
+
config MMC_DW_K3
tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
depends on MMC_DW
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index f563cc0b7f93..6aead24879b4 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -50,6 +50,7 @@ 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_EXYNOS) += dw_mmc-exynos.o
+obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_mmc-hi3798cv200.o
obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o
diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c
new file mode 100644
index 000000000000..f9b333ff259e
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 HiSilicon Technologies Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define ALL_INT_CLR 0x1ffff
+
+struct hi3798cv200_priv {
+ struct clk *sample_clk;
+ struct clk *drive_clk;
+};
+
+static void dw_mci_hi3798cv200_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+ struct hi3798cv200_priv *priv = host->priv;
+ u32 val;
+
+ val = mci_readl(host, UHS_REG);
+ if (ios->timing == MMC_TIMING_MMC_DDR52 ||
+ ios->timing == MMC_TIMING_UHS_DDR50)
+ val |= SDMMC_UHS_DDR;
+ else
+ val &= ~SDMMC_UHS_DDR;
+ mci_writel(host, UHS_REG, val);
+
+ val = mci_readl(host, ENABLE_SHIFT);
+ if (ios->timing == MMC_TIMING_MMC_DDR52)
+ val |= SDMMC_ENABLE_PHASE;
+ else
+ val &= ~SDMMC_ENABLE_PHASE;
+ mci_writel(host, ENABLE_SHIFT, val);
+
+ val = mci_readl(host, DDR_REG);
+ if (ios->timing == MMC_TIMING_MMC_HS400)
+ val |= SDMMC_DDR_HS400;
+ else
+ val &= ~SDMMC_DDR_HS400;
+ mci_writel(host, DDR_REG, val);
+
+ if (ios->timing == MMC_TIMING_MMC_HS ||
+ ios->timing == MMC_TIMING_LEGACY)
+ clk_set_phase(priv->drive_clk, 180);
+ else if (ios->timing == MMC_TIMING_MMC_HS200)
+ clk_set_phase(priv->drive_clk, 135);
+}
+
+static int dw_mci_hi3798cv200_execute_tuning(struct dw_mci_slot *slot,
+ u32 opcode)
+{
+ int degrees[] = { 0, 45, 90, 135, 180, 225, 270, 315 };
+ struct dw_mci *host = slot->host;
+ struct hi3798cv200_priv *priv = host->priv;
+ int raise_point = -1, fall_point = -1;
+ int err, prev_err = -1;
+ int found = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(degrees); i++) {
+ clk_set_phase(priv->sample_clk, degrees[i]);
+ mci_writel(host, RINTSTS, ALL_INT_CLR);
+
+ err = mmc_send_tuning(slot->mmc, opcode, NULL);
+ if (!err)
+ found = 1;
+
+ if (i > 0) {
+ if (err && !prev_err)
+ fall_point = i - 1;
+ if (!err && prev_err)
+ raise_point = i;
+ }
+
+ if (raise_point != -1 && fall_point != -1)
+ goto tuning_out;
+
+ prev_err = err;
+ err = 0;
+ }
+
+tuning_out:
+ if (found) {
+ if (raise_point == -1)
+ raise_point = 0;
+ if (fall_point == -1)
+ fall_point = ARRAY_SIZE(degrees) - 1;
+ if (fall_point < raise_point) {
+ if ((raise_point + fall_point) >
+ (ARRAY_SIZE(degrees) - 1))
+ i = fall_point / 2;
+ else
+ i = (raise_point + ARRAY_SIZE(degrees) - 1) / 2;
+ } else {
+ i = (raise_point + fall_point) / 2;
+ }
+
+ clk_set_phase(priv->sample_clk, degrees[i]);
+ dev_dbg(host->dev, "Tuning clk_sample[%d, %d], set[%d]\n",
+ raise_point, fall_point, degrees[i]);
+ } else {
+ dev_err(host->dev, "No valid clk_sample shift! use default\n");
+ err = -EINVAL;
+ }
+
+ mci_writel(host, RINTSTS, ALL_INT_CLR);
+ return err;
+}
+
+static int dw_mci_hi3798cv200_init(struct dw_mci *host)
+{
+ struct hi3798cv200_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->sample_clk = devm_clk_get(host->dev, "ciu-sample");
+ if (IS_ERR(priv->sample_clk)) {
+ dev_err(host->dev, "failed to get ciu-sample clock\n");
+ return PTR_ERR(priv->sample_clk);
+ }
+
+ priv->drive_clk = devm_clk_get(host->dev, "ciu-drive");
+ if (IS_ERR(priv->drive_clk)) {
+ dev_err(host->dev, "failed to get ciu-drive clock\n");
+ return PTR_ERR(priv->drive_clk);
+ }
+
+ ret = clk_prepare_enable(priv->sample_clk);
+ if (ret) {
+ dev_err(host->dev, "failed to enable ciu-sample clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(priv->drive_clk);
+ if (ret) {
+ dev_err(host->dev, "failed to enable ciu-drive clock\n");
+ goto disable_sample_clk;
+ }
+
+ host->priv = priv;
+ return 0;
+
+disable_sample_clk:
+ clk_disable_unprepare(priv->sample_clk);
+ return ret;
+}
+
+static const struct dw_mci_drv_data hi3798cv200_data = {
+ .init = dw_mci_hi3798cv200_init,
+ .set_ios = dw_mci_hi3798cv200_set_ios,
+ .execute_tuning = dw_mci_hi3798cv200_execute_tuning,
+};
+
+static int dw_mci_hi3798cv200_probe(struct platform_device *pdev)
+{
+ return dw_mci_pltfm_register(pdev, &hi3798cv200_data);
+}
+
+static int dw_mci_hi3798cv200_remove(struct platform_device *pdev)
+{
+ struct dw_mci *host = platform_get_drvdata(pdev);
+ struct hi3798cv200_priv *priv = host->priv;
+
+ clk_disable_unprepare(priv->drive_clk);
+ clk_disable_unprepare(priv->sample_clk);
+
+ return dw_mci_pltfm_remove(pdev);
+}
+
+static const struct of_device_id dw_mci_hi3798cv200_match[] = {
+ { .compatible = "hisilicon,hi3798cv200-dw-mshc", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, dw_mci_hi3798cv200_match);
+static struct platform_driver dw_mci_hi3798cv200_driver = {
+ .probe = dw_mci_hi3798cv200_probe,
+ .remove = dw_mci_hi3798cv200_remove,
+ .driver = {
+ .name = "dwmmc_hi3798cv200",
+ .of_match_table = dw_mci_hi3798cv200_match,
+ },
+};
+module_platform_driver(dw_mci_hi3798cv200_driver);
+
+MODULE_DESCRIPTION("HiSilicon Hi3798CV200 Specific DW-MSHC Driver Extension");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dwmmc_hi3798cv200");
diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
index ab8713297edb..3ad07d7b2c97 100644
--- a/drivers/mmc/host/dw_mmc-pci.c
+++ b/drivers/mmc/host/dw_mmc-pci.c
@@ -29,7 +29,6 @@
MMC_CAP_SDIO_IRQ)
static struct dw_mci_board pci_board_data = {
- .num_slots = 1,
.caps = DW_MCI_CAPABILITIES,
.bus_hz = 33 * 1000 * 1000,
.detect_delay_ms = 200,
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 339295212935..40d7de2eea12 100644
--- a/