summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-08-18 15:54:05 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-18 15:54:05 -0700
commitbbd60bffaf780464298cb7a39852f7f1065f1726 (patch)
tree1338cf7dd93214382127a53b88969e870fbb837a /drivers
parent307797159ac25fe5a2048bf5c6a5718298edca57 (diff)
parent7f38abf220e2c800a2c451372e9f07ed5fd0ea49 (diff)
downloadlinux-bbd60bffaf780464298cb7a39852f7f1065f1726.tar.gz
linux-bbd60bffaf780464298cb7a39852f7f1065f1726.tar.bz2
linux-bbd60bffaf780464298cb7a39852f7f1065f1726.zip
Merge tag 'mmc-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson: "Updates for MMC for v4.19. MMC core: - Add some fine-grained hooks to further support HS400 tuning - Improve error path for bus width setting for HS400es - Use a common method when checking R1 status MMC host: - renesas_sdhi: Add r8a77990 support - renesas_sdhi: Add eMMC HS400 mode support - tmio/renesas_sdhi: Improve tuning/clock management - tmio: Add eMMC HS400 mode support - sunxi: Add support for 3.3V eMMC DDR mode - mmci: Initial support to manage variant specific callbacks - sdhci: Don't try 3.3V I/O voltage if not supported - sdhci-pci-dwc-mshc: Add driver to support Synopsys dwc mshc SDHCI PCI - sdhci-of-dwcmshc: Add driver to support Synopsys DWC MSHC SDHCI - sdhci-msm: Add support for new version sdcc V5 - sdhci-pci-o2micro: Add support for O2 eMMC HS200 mode - sdhci-pci-o2micro: Add support for O2 hardware tuning - sdhci-pci-o2micro: Add MSI interrupt support for O2 SD host - sdhci-pci: Add support for Intel ICP - sdhci-tegra: Prevent ACMD23 and HS200 mode on Tegra 3 - sdhci-tegra: Fix eMMC DDR52 mode - sdhci-tegra: Improve clock management - dw_mmc-rockchip: Document compatible string for px30 - sdhci-esdhc-imx: Add support for 3.3V eMMC DDR mode - sdhci-of-esdhc: Set proper DMA mask for ls104x chips - sdhci-of-esdhc: Improve clock management - sdhci-of-arasan: Add a quirk to manage unstable clocks - dw_mmc-exynos: Address potential external abort during system resume - pxamci: Add support for common MMC DT bindings - pxamci: Several cleanups and improvements - pxamci: Merge immutable branch for pxa to switch to DMA slave maps" * tag 'mmc-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (56 commits) mmc: core: improve reasonableness of bus width setting for HS400es mmc: tmio: remove unneeded variable in tmio_mmc_start_command() mmc: renesas_sdhi: Fix sampling clock position selecting mmc: tmio: Fix tuning flow mmc: sunxi: remove output of virtual base address dt-bindings: mmc: rockchip-dw-mshc: add description for px30 mmc: renesas_sdhi: Add r8a77990 support mmc: sunxi: allow 3.3V DDR when DDR is available mmc: mmci: Add and implement a ->dma_setup() callback for qcom dml mmc: mmci: Initial support to manage variant specific callbacks mmc: tegra: Force correct divider calculation on DDR50/52 mmc: sdhci: Add MSI interrupt support for O2 SD host mmc: sdhci: Add support for O2 hardware tuning mmc: sdhci: Export sdhci tuning function symbol mmc: sdhci: Change O2 Host HS200 mode clock frequency to 200MHz mmc: sdhci: Add support for O2 eMMC HS200 mode mmc: tegra: Add and use tegra_sdhci_get_max_clock() mmc: sdhci-esdhc-imx: fix indent mmc: sdhci-esdhc-imx: disable clocks before changing frequency mmc: tegra: prevent ACMD23 on Tegra 3 ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/core/core.c48
-rw-r--r--drivers/mmc/core/core.h2
-rw-r--r--drivers/mmc/core/mmc.c16
-rw-r--r--drivers/mmc/core/mmc_ops.c2
-rw-r--r--drivers/mmc/core/sdio.c1
-rw-r--r--drivers/mmc/host/Kconfig11
-rw-r--r--drivers/mmc/host/Makefile4
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c33
-rw-r--r--drivers/mmc/host/mmci.c82
-rw-r--r--drivers/mmc/host/mmci.h81
-rw-r--r--drivers/mmc/host/mmci_qcom_dml.c18
-rw-r--r--drivers/mmc/host/mmci_qcom_dml.h5
-rw-r--r--drivers/mmc/host/pxamci.c211
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c139
-rw-r--r--drivers/mmc/host/renesas_sdhi_internal_dmac.c20
-rw-r--r--drivers/mmc/host/renesas_sdhi_sys_dmac.c17
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c29
-rw-r--r--drivers/mmc/host/sdhci-msm.c510
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c16
-rw-r--r--drivers/mmc/host/sdhci-of-dwcmshc.c116
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c91
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c3
-rw-r--r--drivers/mmc/host/sdhci-pci-dwc-mshc.c84
-rw-r--r--drivers/mmc/host/sdhci-pci-o2micro.c129
-rw-r--r--drivers/mmc/host/sdhci-pci.h5
-rw-r--r--drivers/mmc/host/sdhci-tegra.c37
-rw-r--r--drivers/mmc/host/sdhci-xenon-phy.c1
-rw-r--r--drivers/mmc/host/sdhci.c25
-rw-r--r--drivers/mmc/host/sdhci.h5
-rw-r--r--drivers/mmc/host/sunxi-mmc.c7
-rw-r--r--drivers/mmc/host/tmio_mmc.h6
-rw-r--r--drivers/mmc/host/tmio_mmc_core.c52
32 files changed, 1322 insertions, 484 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 281826d1fcca..50a5c340307b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2078,7 +2078,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
/* Do not retry else we can't see errors */
err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err || (cmd.resp[0] & 0xFDF92000)) {
+ if (err || R1_STATUS(cmd.resp[0])) {
pr_err("error %d requesting status %#x\n",
err, cmd.resp[0]);
err = -EIO;
@@ -2716,52 +2716,6 @@ void mmc_stop_host(struct mmc_host *host)
mmc_release_host(host);
}
-int mmc_power_save_host(struct mmc_host *host)
-{
- int ret = 0;
-
- pr_debug("%s: %s: powering down\n", mmc_hostname(host), __func__);
-
- mmc_bus_get(host);
-
- if (!host->bus_ops || host->bus_dead) {
- mmc_bus_put(host);
- return -EINVAL;
- }
-
- if (host->bus_ops->power_save)
- ret = host->bus_ops->power_save(host);
-
- mmc_bus_put(host);
-
- mmc_power_off(host);
-
- return ret;
-}
-EXPORT_SYMBOL(mmc_power_save_host);
-
-int mmc_power_restore_host(struct mmc_host *host)
-{
- int ret;
-
- pr_debug("%s: %s: powering up\n", mmc_hostname(host), __func__);
-
- mmc_bus_get(host);
-
- if (!host->bus_ops || host->bus_dead) {
- mmc_bus_put(host);
- return -EINVAL;
- }
-
- mmc_power_up(host, host->card->ocr);
- ret = host->bus_ops->power_restore(host);
-
- mmc_bus_put(host);
-
- return ret;
-}
-EXPORT_SYMBOL(mmc_power_restore_host);
-
#ifdef CONFIG_PM_SLEEP
/* Do the card removal on suspend if card is assumed removeable
* Do that in pm notifier while userspace isn't yet frozen, so we will be able
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 9d8f09ac0821..087ba68b2920 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -28,8 +28,6 @@ struct mmc_bus_ops {
int (*resume)(struct mmc_host *);
int (*runtime_suspend)(struct mmc_host *);
int (*runtime_resume)(struct mmc_host *);
- int (*power_save)(struct mmc_host *);
- int (*power_restore)(struct mmc_host *);
int (*alive)(struct mmc_host *);
int (*shutdown)(struct mmc_host *);
int (*hw_reset)(struct mmc_host *);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 4466f5de54d4..bc1bd2c25613 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1169,6 +1169,10 @@ static int mmc_select_hs400(struct mmc_card *card)
/* Set host controller to HS timing */
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+ /* Prepare host to downgrade to HS timing */
+ if (host->ops->hs400_downgrade)
+ host->ops->hs400_downgrade(host);
+
/* Reduce frequency to HS frequency */
max_dtr = card->ext_csd.hs_max_dtr;
mmc_set_clock(host, max_dtr);
@@ -1209,6 +1213,9 @@ static int mmc_select_hs400(struct mmc_card *card)
if (err)
goto out_err;
+ if (host->ops->hs400_complete)
+ host->ops->hs400_complete(host);
+
return 0;
out_err:
@@ -1256,6 +1263,9 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
mmc_set_timing(host, MMC_TIMING_MMC_HS);
+ if (host->ops->hs400_downgrade)
+ host->ops->hs400_downgrade(host);
+
err = mmc_switch_status(card);
if (err)
goto out_err;
@@ -1338,8 +1348,12 @@ static int mmc_select_hs400es(struct mmc_card *card)
goto out_err;
err = mmc_select_bus_width(card);
- if (err < 0)
+ if (err != MMC_BUS_WIDTH_8) {
+ pr_err("%s: switch to 8bit bus width failed, err:%d\n",
+ mmc_hostname(host), err);
+ err = err < 0 ? err : -ENOTSUPP;
goto out_err;
+ }
/* Switch card to HS mode */
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 42d6aa89a48a..873b2aa0c155 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -417,7 +417,7 @@ static int mmc_switch_status_error(struct mmc_host *host, u32 status)
if (status & R1_SPI_ILLEGAL_COMMAND)
return -EBADMSG;
} else {
- if (status & 0xFDFFA000)
+ if (R1_STATUS(status))
pr_warn("%s: unexpected status %#x after switch\n",
mmc_hostname(host), status);
if (status & R1_SWITCH_ERROR)
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index a86490dbca70..d8e17ea6126d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -1076,7 +1076,6 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
.resume = mmc_sdio_resume,
.runtime_suspend = mmc_sdio_runtime_suspend,
.runtime_resume = mmc_sdio_runtime_resume,
- .power_restore = mmc_sdio_power_restore,
.alive = mmc_sdio_alive,
.hw_reset = mmc_sdio_hw_reset,
.sw_reset = mmc_sdio_sw_reset,
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 0581c199c996..694d0828215d 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -176,6 +176,17 @@ config MMC_SDHCI_OF_HLWD
If unsure, say N.
+config MMC_SDHCI_OF_DWCMSHC
+ tristate "SDHCI OF support for the Synopsys DWC MSHC"
+ depends on MMC_SDHCI_PLTFM
+ depends on OF
+ depends on COMMON_CLK
+ help
+ This selects Synopsys DesignWare Cores Mobile Storage Controller
+ support.
+ If you have a controller with this interface, say Y or M here.
+ If unsure, say N.
+
config MMC_SDHCI_CADENCE
tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
depends on MMC_SDHCI_PLTFM
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 85dc1322c3de..ce8398e6f2c0 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -11,7 +11,8 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
-sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o
+sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
+ sdhci-pci-dwc-mshc.o
obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
@@ -82,6 +83,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o
obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
+obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index a84aa3f1ae85..ab47b018716a 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -175,6 +175,20 @@ static int dw_mci_exynos_runtime_resume(struct device *dev)
return ret;
}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * dw_mci_exynos_suspend_noirq - Exynos-specific suspend code
+ *
+ * This ensures that device will be in runtime active state in
+ * dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume()
+ */
+static int dw_mci_exynos_suspend_noirq(struct device *dev)
+{
+ pm_runtime_get_noresume(dev);
+ return pm_runtime_force_suspend(dev);
+}
/**
* dw_mci_exynos_resume_noirq - Exynos-specific resume code
@@ -186,12 +200,16 @@ static int dw_mci_exynos_runtime_resume(struct device *dev)
*
* We run this code on all exynos variants because it doesn't hurt.
*/
-
static int dw_mci_exynos_resume_noirq(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
struct dw_mci_exynos_priv_data *priv = host->priv;
u32 clksel;
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
@@ -207,11 +225,11 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
mci_writel(host, CLKSEL, clksel);
}
+ pm_runtime_put(dev);
+
return 0;
}
-#else
-#define dw_mci_exynos_resume_noirq NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
{
@@ -553,14 +571,11 @@ static int dw_mci_exynos_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops dw_mci_exynos_pmops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq,
+ dw_mci_exynos_resume_noirq)
SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
dw_mci_exynos_runtime_resume,
NULL)
- .resume_noirq = dw_mci_exynos_resume_noirq,
- .thaw_noirq = dw_mci_exynos_resume_noirq,
- .restore_noirq = dw_mci_exynos_resume_noirq,
};
static struct platform_driver dw_mci_exynos_pltfm_driver = {
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index f1849775e47e..1841d250e9e2 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -48,78 +48,6 @@
static unsigned int fmax = 515633;
-/**
- * struct variant_data - MMCI variant-specific quirks
- * @clkreg: default value for MCICLOCK register
- * @clkreg_enable: enable value for MMCICLOCK register
- * @clkreg_8bit_bus_enable: enable value for 8 bit bus
- * @clkreg_neg_edge_enable: enable value for inverted data/cmd output
- * @datalength_bits: number of bits in the MMCIDATALENGTH register
- * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
- * is asserted (likewise for RX)
- * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
- * is asserted (likewise for RX)
- * @data_cmd_enable: enable value for data commands.
- * @st_sdio: enable ST specific SDIO logic
- * @st_clkdiv: true if using a ST-specific clock divider algorithm
- * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
- * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
- * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
- * register
- * @datactrl_mask_sdio: SDIO enable mask in datactrl register
- * @pwrreg_powerup: power up value for MMCIPOWER register
- * @f_max: maximum clk frequency supported by the controller.
- * @signal_direction: input/out direction of bus signals can be indicated
- * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
- * @busy_detect: true if the variant supports busy detection on DAT0.
- * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
- * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
- * indicating that the card is busy
- * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
- * getting busy end detection interrupts
- * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
- * @explicit_mclk_control: enable explicit mclk control in driver.
- * @qcom_fifo: enables qcom specific fifo pio read logic.
- * @qcom_dml: enables qcom specific dma glue for dma transfers.
- * @reversed_irq_handling: handle data irq before cmd irq.
- * @mmcimask1: true if variant have a MMCIMASK1 register.
- * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
- * register.
- * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
- */
-struct variant_data {
- unsigned int clkreg;
- unsigned int clkreg_enable;
- unsigned int clkreg_8bit_bus_enable;
- unsigned int clkreg_neg_edge_enable;
- unsigned int datalength_bits;
- unsigned int fifosize;
- unsigned int fifohalfsize;
- unsigned int data_cmd_enable;
- unsigned int datactrl_mask_ddrmode;
- unsigned int datactrl_mask_sdio;
- bool st_sdio;
- bool st_clkdiv;
- bool blksz_datactrl16;
- bool blksz_datactrl4;
- u32 pwrreg_powerup;
- u32 f_max;
- bool signal_direction;
- bool pwrreg_clkgate;
- bool busy_detect;
- u32 busy_dpsm_flag;
- u32 busy_detect_flag;
- u32 busy_detect_mask;
- bool pwrreg_nopower;
- bool explicit_mclk_control;
- bool qcom_fifo;
- bool qcom_dml;
- bool reversed_irq_handling;
- bool mmcimask1;
- u32 start_err;
- u32 opendrain;
-};
-
static struct variant_data variant_arm = {
.fifosize = 16 * 4,
.fifohalfsize = 8 * 4,
@@ -280,6 +208,7 @@ static struct variant_data variant_qcom = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .init = qcom_variant_init,
};
/* Busy detection for the ST Micro variant */
@@ -489,7 +418,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
static void mmci_dma_setup(struct mmci_host *host)
{
const char *rxname, *txname;
- struct variant_data *variant = host->variant;
host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
@@ -537,9 +465,8 @@ static void mmci_dma_setup(struct mmci_host *host)
host->mmc->max_seg_size = max_seg_size;
}
- if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel)
- if (dml_hw_init(host, host->mmc->parent->of_node))
- variant->qcom_dml = false;
+ if (host->ops && host->ops->dma_setup)
+ host->ops->dma_setup(host);
}
/*
@@ -1706,6 +1633,9 @@ static int mmci_probe(struct amba_device *dev,
goto clk_disable;
}
+ if (variant->init)
+ variant->init(host);
+
/*
* The ARM and ST versions of the block have slightly different
* clock divider equations which means that the minimum divider
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index f91cdf7f6dae..517591d219e9 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -195,8 +195,86 @@
#define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"
struct clk;
-struct variant_data;
struct dma_chan;
+struct mmci_host;
+
+/**
+ * struct variant_data - MMCI variant-specific quirks
+ * @clkreg: default value for MCICLOCK register
+ * @clkreg_enable: enable value for MMCICLOCK register
+ * @clkreg_8bit_bus_enable: enable value for 8 bit bus
+ * @clkreg_neg_edge_enable: enable value for inverted data/cmd output
+ * @datalength_bits: number of bits in the MMCIDATALENGTH register
+ * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
+ * is asserted (likewise for RX)
+ * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
+ * is asserted (likewise for RX)
+ * @data_cmd_enable: enable value for data commands.
+ * @st_sdio: enable ST specific SDIO logic
+ * @st_clkdiv: true if using a ST-specific clock divider algorithm
+ * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
+ * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
+ * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
+ * register
+ * @datactrl_mask_sdio: SDIO enable mask in datactrl register
+ * @pwrreg_powerup: power up value for MMCIPOWER register
+ * @f_max: maximum clk frequency supported by the controller.
+ * @signal_direction: input/out direction of bus signals can be indicated
+ * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
+ * @busy_detect: true if the variant supports busy detection on DAT0.
+ * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
+ * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
+ * indicating that the card is busy
+ * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
+ * getting busy end detection interrupts
+ * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
+ * @explicit_mclk_control: enable explicit mclk control in driver.
+ * @qcom_fifo: enables qcom specific fifo pio read logic.
+ * @qcom_dml: enables qcom specific dma glue for dma transfers.
+ * @reversed_irq_handling: handle data irq before cmd irq.
+ * @mmcimask1: true if variant have a MMCIMASK1 register.
+ * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
+ * register.
+ * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
+ */
+struct variant_data {
+ unsigned int clkreg;
+ unsigned int clkreg_enable;
+ unsigned int clkreg_8bit_bus_enable;
+ unsigned int clkreg_neg_edge_enable;
+ unsigned int datalength_bits;
+ unsigned int fifosize;
+ unsigned int fifohalfsize;
+ unsigned int data_cmd_enable;
+ unsigned int datactrl_mask_ddrmode;
+ unsigned int datactrl_mask_sdio;
+ bool st_sdio;
+ bool st_clkdiv;
+ bool blksz_datactrl16;
+ bool blksz_datactrl4;
+ u32 pwrreg_powerup;
+ u32 f_max;
+ bool signal_direction;
+ bool pwrreg_clkgate;
+ bool busy_detect;
+ u32 busy_dpsm_flag;
+ u32 busy_detect_flag;
+ u32 busy_detect_mask;
+ bool pwrreg_nopower;
+ bool explicit_mclk_control;
+ bool qcom_fifo;
+ bool qcom_dml;
+ bool reversed_irq_handling;
+ bool mmcimask1;
+ u32 start_err;
+ u32 opendrain;
+ void (*init)(struct mmci_host *host);
+};
+
+/* mmci variant callbacks */
+struct mmci_host_ops {
+ void (*dma_setup)(struct mmci_host *host);
+};
struct mmci_host_next {
struct dma_async_tx_descriptor *dma_desc;
@@ -228,6 +306,7 @@ struct mmci_host {
u32 mask1_reg;
bool vqmmc_enabled;
struct mmci_platform_data *plat;
+ struct mmci_host_ops *ops;
struct variant_data *variant;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c
index 00750c9d3514..be3fab5db83f 100644
--- a/drivers/mmc/host/mmci_qcom_dml.c
+++ b/drivers/mmc/host/mmci_qcom_dml.c
@@ -119,17 +119,20 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name)
}
/* Initialize the dml hardware connected to SD Card controller */
-int dml_hw_init(struct mmci_host *host, struct device_node *np)
+static void qcom_dma_setup(struct mmci_host *host)
{
u32 config;
void __iomem *base;
int consumer_id, producer_id;
+ struct device_node *np = host->mmc->parent->of_node;
consumer_id = of_get_dml_pipe_index(np, "tx");
producer_id = of_get_dml_pipe_index(np, "rx");
- if (producer_id < 0 || consumer_id < 0)
- return -ENODEV;
+ if (producer_id < 0 || consumer_id < 0) {
+ host->variant->qcom_dml = false;
+ return;
+ }
base = host->base + DML_OFFSET;
@@ -172,6 +175,13 @@ int dml_hw_init(struct mmci_host *host, struct device_node *np)
/* Make sure dml initialization is finished */
mb();
+}
- return 0;
+static struct mmci_host_ops qcom_variant_ops = {
+ .dma_setup = qcom_dma_setup,
+};
+
+void qcom_variant_init(struct mmci_host *host)
+{
+ host->ops = &qcom_variant_ops;
}
diff --git a/drivers/mmc/host/mmci_qcom_dml.h b/drivers/mmc/host/mmci_qcom_dml.h
index 6e405d09d534..fa16f6f4d4ad 100644
--- a/drivers/mmc/host/mmci_qcom_dml.h
+++ b/drivers/mmc/host/mmci_qcom_dml.h
@@ -16,12 +16,11 @@
#define __MMC_QCOM_DML_H__
#ifdef CONFIG_MMC_QCOM_DML
-int dml_hw_init(struct mmci_host *host, struct device_node *np);
+void qcom_variant_init(struct mmci_host *host);
void dml_start_xfer(struct mmci_host *host, struct mmc_data *data);
#else
-static inline int dml_hw_init(struct mmci_host *host, struct device_node *np)
+static inline void qcom_variant_init(struct mmci_host *host)
{
- return -ENOSYS;
}
static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
{
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 6c94474e36f4..f7ffbf1676b1 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -58,11 +58,11 @@ struct pxamci_host {
void __iomem *base;
struct clk *clk;
unsigned long clkrate;
- int irq;
unsigned int clkrt;
unsigned int cmdat;
unsigned int imask;
unsigned int power_mode;
+ unsigned long detect_delay_ms;
struct pxamci_platform_data *pdata;
struct mmc_request *mrq;
@@ -72,64 +72,48 @@ struct pxamci_host {
struct dma_chan *dma_chan_rx;
struct dma_chan *dma_chan_tx;
dma_cookie_t dma_cookie;
- dma_addr_t sg_dma;
unsigned int dma_len;
-
unsigned int dma_dir;
- unsigned int dma_drcmrrx;
- unsigned int dma_drcmrtx;
-
- struct regulator *vcc;
};
-static inline void pxamci_init_ocr(struct pxamci_host *host)
+static int pxamci_init_ocr(struct pxamci_host *host)
{
-#ifdef CONFIG_REGULATOR
- host->vcc = devm_regulator_get_optional(mmc_dev(host->mmc), "vmmc");
-
- if (IS_ERR(host->vcc))
- host->vcc = NULL;
- else {
- host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
- if (host->pdata && host->pdata->ocr_mask)
- dev_warn(mmc_dev(host->mmc),
- "ocr_mask/setpower will not be used\n");
- }
-#endif
- if (host->vcc == NULL) {
+ struct mmc_host *mmc = host->mmc;
+ int ret;
+
+ ret = mmc_regulator_get_supply(mmc);
+ if (ret < 0)
+ return ret;
+
+ if (IS_ERR(mmc->supply.vmmc)) {
/* fall-back to platform data */
- host->mmc->ocr_avail = host->pdata ?
+ mmc->ocr_avail = host->pdata ?
host->pdata->ocr_mask :
MMC_VDD_32_33 | MMC_VDD_33_34;
}
+
+ return 0;
}
static inline int pxamci_set_power(struct pxamci_host *host,
unsigned char power_mode,
unsigned int vdd)
{
+ struct mmc_host *mmc = host->mmc;
+ struct regulator *supply = mmc->supply.vmmc;
int on;
- if (host->vcc) {
- int ret;
+ if (!IS_ERR(supply))
+ return mmc_regulator_set_ocr(mmc, supply, vdd);
- if (power_mode == MMC_POWER_UP) {
- ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
- if (ret)
- return ret;
- } else if (power_mode == MMC_POWER_OFF) {
- ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
- if (ret)
- return ret;
- }
- }
- if (!host->vcc && host->pdata &&
+ if (host->pdata &&
gpio_is_valid(host->pdata->gpio_power)) {
on = ((1 << vdd) & host->pdata->ocr_mask);
gpio_set_value(host->pdata->gpio_power,
!!on ^ host->pdata->gpio_power_invert);
}
- if (!host->vcc && host->pdata && host->pdata->setpower)
+
+ if (host->pdata && host->pdata->setpower)
return host->pdata->setpower(mmc_dev(host->mmc), vdd);
return 0;
@@ -584,7 +568,7 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid)
{
struct pxamci_host *host = mmc_priv(devid);
- mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms));
+ mmc_detect_change(devid, msecs_to_jiffies(host->detect_delay_ms));
return IRQ_HANDLED;
}
@@ -596,37 +580,30 @@ static const struct of_device_id pxa_mmc_dt_ids[] = {
MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids);
-static int pxamci_of_init(struct platform_device *pdev)
+static int pxamci_of_init(struct platform_device *pdev,
+ struct mmc_host *mmc)
{
- struct device_node *np = pdev->dev.of_node;
- struct pxamci_platform_data *pdata;
- u32 tmp;
-
- if (!np)
- return 0;
-
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
+ struct device_node *np = pdev->dev.of_node;
+ struct pxamci_host *host = mmc_priv(mmc);
+ u32 tmp;
+ int ret;
- pdata->gpio_card_detect =
- of_get_named_gpio(np, "cd-gpios", 0);
- pdata->gpio_card_ro =
- of_get_named_gpio(np, "wp-gpios", 0);
+ if (!np)
+ return 0;
/* pxa-mmc specific */
- pdata->gpio_power =
- of_get_named_gpio(np,