summaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 12:17:25 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 12:17:25 -0700
commitdc73d6a8d42d208c027b4bcca59a77d045895977 (patch)
tree1c6e135caa45d2e085ec0e5b106459a73359905c /drivers/mmc
parentdabe51840e2790aa7e66c53990d15c663b0d628a (diff)
parent4472f0fc248e3f0573301f725eff9dc9cde5cb62 (diff)
Merge tag 'mmc-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson: "MMC core: - Export host capabilities through debugfs - Export card RCA register via sysfs - Improve card initializing sequence while enabling 4-bit bus - Export a function to enable/disable wakeup for card detect IRQ MMC host: - dw_mmc: Add support for new hi3798cv200 variant - dw_mmc: Remove support for some deprecated DT properties - mediatek: Add support for new variant used on MT7622 SoC - sdhci: Improve wakeup support for SDIO IRQs - sdhci: Improve wakeup support for card detect IRQs - sdhci-omap: Add tuning support - sdhci_omap: Add UHS-I mode support - sunxi: Prepare for runtime PM support via a few re-factorings - tmio: deprecate "toshiba,mmc-wrprotect-disable" DT property - tmio/renesas_sdhi: Consolidate code supporting write protect - tmio: Improve DMA vs PIO handling - tmio: Add support for IP-builtin card detection logic" * tag 'mmc-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (55 commits) mmc: renesas_sdhi: replace EXT_ACC with HOST_MODE mmc: update sdio_claim_irq documentation mmc: Export host capabilities to debugfs. mmc: core: Disable HPI for certain Micron (Numonyx) eMMC cards mmc: block: fix updating ext_csd caches on ioctl call mmc: sunxi: Set our device drvdata earlier mmc: sunxi: Move the reset deassertion before enabling the clocks mmc: sunxi: Move resources management to separate functions mmc: dw_mmc: add support for hi3798cv200 specific extensions of dw-mshc dt-bindings: mmc: add bindings for hi3798cv200-dw-mshc mmc: core: Export card RCA register via sysfs mmc: renesas_sdhi: fix WP detection mmc: core: Use memdup_user() rather than duplicating its implementation mmc: dw_mmc-rockchip: correct property names in debug mmc: sd: Remove redundant err assignment from mmc_read_switch mmc: sdio: Check the return value of sdio_enable_4bit_bus mmc: core: Don't try UHS-I mode if 4-bit mode isn't supported arm64: dts: hi3660: remove 'num-slots' property for dwmmc ARM: dts: lpc18xx: remove 'num-slots' property for dwmmc arm64: dts: stratix10: remove 'num-slots' property for dwmmc ...
Diffstat (limited to 'drivers/mmc')
-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
28 files changed, 842 insertions, 257 deletions
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/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -282,11 +282,11 @@ static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
priv->drv_clk = devm_clk_get(host->dev, "ciu-drive");
if (IS_ERR(priv->drv_clk))
- dev_dbg(host->dev, "ciu_drv not available\n");
+ dev_dbg(host->dev, "ciu-drive not available\n");
priv->sample_clk = devm_clk_get(host->dev, "ciu-sample");
if (IS_ERR(priv->sample_clk))
- dev_dbg(host->dev, "ciu_sample not available\n");
+ dev_dbg(host->dev, "ciu-sample not available\n");
host->priv = priv;
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 06d47414d0c1..29a1afa81f66 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -147,19 +147,7 @@ static int dw_mci_req_show(struct seq_file *s, void *v)
return 0;
}
-
-static int dw_mci_req_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dw_mci_req_show, inode->i_private);
-}
-
-static const struct file_operations dw_mci_req_fops = {
- .owner = THIS_MODULE,
- .open = dw_mci_req_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(dw_mci_req);
static int dw_mci_regs_show(struct seq_file *s, void *v)
{
@@ -178,19 +166,7 @@ static int dw_mci_regs_show(struct seq_file *s, void *v)
return 0;
}
-
-static int dw_mci_regs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dw_mci_regs_show, inode->i_private);
-}
-
-static const struct file_operations dw_mci_regs_fops = {
- .owner = THIS_MODULE,
- .open = dw_mci_regs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(dw_mci_regs);
static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
{
@@ -2030,7 +2006,6 @@ static void dw_mci_tasklet_func(unsigned long priv)
set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
err = dw_mci_command_complete(host, cmd);
if (cmd == mrq->sbc && !err) {
- prev_state = state = STATE_SENDING_CMD;
__dw_mci_start_request(host, host->slot,
mrq->cmd);
goto unlock;
@@ -2826,6 +2801,10 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot)
if (host->pdata->caps2)
mmc->caps2 = host->pdata->caps2;
+ mmc->f_min = DW_MCI_FREQ_MIN;
+ if (!mmc->f_max)
+ mmc->f_max = DW_MCI_FREQ_MAX;
+
/* Process SDIO IRQs through the sdio_irq_work. */
if (mmc->caps & MMC_CAP_SDIO_IRQ)
mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
@@ -2838,7 +2817,6 @@ static int dw_mci_init_slot(struct dw_mci *host)
struct mmc_host *mmc;
struct dw_mci_slot *slot;
int ret;
- u32 freq[2];
mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
if (!mmc)
@@ -2852,16 +2830,6 @@ static int dw_mci_init_slot(struct dw_mci *host)
host->slot = slot;
mmc->ops = &dw_mci_ops;
- if (device_property_read_u32_array(host->dev, "clock-freq-min-max",
- freq, 2)) {
- mmc->f_min = DW_MCI_FREQ_MIN;
- mmc->f_max = DW_MCI_FREQ_MAX;
- } else {
- dev_info(host->dev,
- "'clock-freq-min-max' property was deprecated.\n");
- mmc->f_min = freq[0];
- mmc->f_max = freq[1];
- }
/*if there are external regulators, get them*/
ret = mmc_regulator_get_supply(mmc);
@@ -3160,10 +3128,6 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
return ERR_PTR(-EPROBE_DEFER);
}
- /* find out number of slots supported */
- if (!device_property_read_u32(dev, "num-slots", &pdata->num_slots))
- dev_info(dev, "'num-slots' was deprecated.\n");
-
if (device_property_read_u32(dev, "fifo-depth", &pdata->fifo_depth))
dev_info(dev,
"fifo-depth property not found, using value of FIFOTH register as default\n");
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 1424bd490dd1..46e9f8ec5398 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -65,8 +65,7 @@ struct dw_mci_dma_slave {
* @fifo_reg: Pointer to MMIO registers for data FIFO
* @sg: Scatterlist entry currently being processed by PIO code, if any.
* @sg_miter: PIO mapping scatterlist iterator.
- * @cur_slot: The slot which is currently using the controller.
- * @mrq: The request currently being processed on @cur_slot,
+ * @mrq: The request currently being processed on @slot,
* or NULL if the controller is idle.
* @cmd: The command currently being sent to the card, or NULL.
* @data: The data currently being transferred, or NULL if no data
@@ -102,7 +101,6 @@ struct dw_mci_dma_slave {
* @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
* rate and timeout calculations.
* @current_speed: Configured rate of the controller.
- * @num_slots: Number of slots available.
* @fifoth_val: The value of FIFOTH register.
* @verid: Denote Version ID.
* @dev: Device associated with the MMC controller.
@@ -134,17 +132,17 @@ struct dw_mci_dma_slave {
* =======
*
* @lock is a softirq-safe spinlock protecting @queue as well as
+ * @slot, @mrq and @state. These must always be updated
* at the same time while holding @lock.
+ * The @mrq field of struct dw_mci_slot is also protected by @lock,
+ * and must always be written at the same time as the slot is added to
+ * @queue.
*
* @irq_lock is an irq-safe spinlock protecting the INTMASK register
* to allow the interrupt handler to modify it directly. Held for only long
* enough to read-modify-write INTMASK and no other locks are grabbed when
* holding this one.
*
- * The @mrq field of struct dw_mci_slot is also protected by @lock,
- * and must always be written at the same time as the slot is added to
- * @queue.
- *
* @pending_events and @completed_events are accessed using atomic bit
* operations, so they don't need any locking.
*
@@ -253,8 +251,6 @@ struct dma_pdata;
/* Board platform data */
struct dw_mci_board {
- u32 num_slots;
-
unsigned int bus_hz; /* Clock speed at the cclk_in pad */
u32 caps; /* Capabilities */
@@ -318,11 +314,12 @@ struct dw_mci_board {
#define SDMMC_BUFADDR 0x098
#define SDMMC_CDTHRCTL 0x100
#define SDMMC_UHS_REG_EXT 0x108
+#define SDMMC_DDR_REG 0x10c
#define SDMMC_ENABLE_SHIFT 0x110
#define SDMMC_DATA(x) (x)
/*
-* Registers to support idmac 64-bit address mode
-*/
+ * Registers to support idmac 64-bit address mode
+ */
#define SDMMC_DBADDRL 0x088
#define SDMMC_DBADDRU 0x08c
#define SDMMC_IDSTS64 0x090
@@ -443,13 +440,19 @@ struct dw_mci_board {
#define SDMMC_CARD_WR_THR_EN BIT(2)
#define SDMMC_CARD_RD_THR_EN BIT(0)
/* UHS-1 register defines */
+#define SDMMC_UHS_DDR BIT(16)
#define SDMMC_UHS_18V BIT(0)
+/* DDR register defines */
+#define SDMMC_DDR_HS400 BIT(31)
+/* Enable shift register defines */
+#define SDMMC_ENABLE_PHASE BIT(0)
/* All ctrl reset bits */
#define SDMMC_CTRL_ALL_RESET_FLAGS \
(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)
/* FIFO register access macros. These should not change the data endian-ness
- * as they are written to memory to be dealt with by the upper layers */
+ * as they are written to memory to be dealt with by the upper layers
+ */
#define mci_fifo_readw(__reg) __raw_readw(__reg)
#define mci_fifo_readl(__reg) __raw_readl(__reg)
#define mci_fifo_readq(__reg) __raw_readq(__reg)
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 6457a7d8880f..cb274e822293 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -438,11 +438,23 @@ static const struct mtk_mmc_compatible mt2712_compat = {
.enhance_rx = true,
};
+static const struct mtk_mmc_compatible mt7622_compat = {
+ .clk_div_bits = 12,
+ .hs400_tune = false,
+ .pad_tune_reg = MSDC_PAD_TUNE0,
+ .async_fifo = true,
+ .data_tune = true,
+ .busy_check = true,
+ .stop_clk_fix = true,
+ .enhance_rx = true,
+};
+
static const struct of_device_id msdc_of_ids[] = {
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
{ .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat},
{ .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat},
+ { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
{}
};
MODULE_DEVICE_TABLE(of, msdc_of_ids);
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 80943fa07db6..51e01f03fb99 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -38,7 +38,7 @@
#include "renesas_sdhi.h"
#include "tmio_mmc.h"
-#define EXT_ACC 0xe4
+#define HOST_MODE 0xe4
#define SDHI_VER_GEN2_SDR50 0x490c
#define SDHI_VER_RZ_A1 0x820b
@@ -76,7 +76,7 @@ static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
return;
}
- sd_ctrl_write16(host, EXT_ACC, val);
+ sd_ctrl_write16(host, HOST_MODE, val);
}
static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
@@ -417,7 +417,7 @@ static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
case CTL_SD_MEM_CARD_OPT:
case CTL_TRANSACTION_CTL:
case CTL_DMA_ENABLE:
- case EXT_ACC:
+ case HOST_MODE:
if (host->pdata->flags & TMIO_MMC_HAVE_CBSY)
bit = TMIO_STAT_CMD_BUSY;
/* fallthrough */
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index 7c03cfead6f9..8e0acd197c43 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/