summaryrefslogtreecommitdiff
path: root/drivers/mmc/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r--drivers/mmc/host/Kconfig21
-rw-r--r--drivers/mmc/host/Makefile2
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c4
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c2
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c162
-rw-r--r--drivers/mmc/host/dw_mmc.c290
-rw-r--r--drivers/mmc/host/dw_mmc.h13
-rw-r--r--drivers/mmc/host/mmc_spi.c1
-rw-r--r--drivers/mmc/host/moxart-mmc.c1
-rw-r--r--drivers/mmc/host/mtk-sd.c306
-rw-r--r--drivers/mmc/host/omap.c1
-rw-r--r--drivers/mmc/host/sdhci-acpi.c11
-rw-r--r--drivers/mmc/host/sdhci-bcm-kona.c2
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c6
-rw-r--r--drivers/mmc/host/sdhci-esdhc.h2
-rw-r--r--drivers/mmc/host/sdhci-msm.c2
-rw-r--r--drivers/mmc/host/sdhci-of-at91.c1
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c463
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c (renamed from drivers/mmc/host/sdhci-pci.c)62
-rw-r--r--drivers/mmc/host/sdhci-pci-o2micro.c6
-rw-r--r--drivers/mmc/host/sdhci-pci-o2micro.h2
-rw-r--r--drivers/mmc/host/sdhci-pci.h7
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c6
-rw-r--r--drivers/mmc/host/sdhci-sirf.c5
-rw-r--r--drivers/mmc/host/sdhci.c29
-rw-r--r--drivers/mmc/host/sunxi-mmc.c8
-rw-r--r--drivers/mmc/host/vub300.c6
-rw-r--r--drivers/mmc/host/wbsd.c2
28 files changed, 1150 insertions, 273 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 8a1e3498261e..af71de5fda3b 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -67,7 +67,7 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
has the effect of scrambling the addresses and formats of data
accessed in sizes other than the datum size.
- This is the case for the Freescale eSDHC and Nintendo Wii SDHCI.
+ This is the case for the Nintendo Wii SDHCI.
config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus"
@@ -140,8 +140,8 @@ config MMC_SDHCI_OF_AT91
config MMC_SDHCI_OF_ESDHC
tristate "SDHCI OF support for the Freescale eSDHC controller"
depends on MMC_SDHCI_PLTFM
- depends on PPC
- select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+ depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE
+ select MMC_SDHCI_IO_ACCESSORS
help
This selects the Freescale eSDHC controller support.
@@ -366,7 +366,7 @@ config MMC_OMAP
config MMC_OMAP_HS
tristate "TI OMAP High Speed Multimedia Card Interface support"
depends on HAS_DMA
- depends on ARCH_OMAP2PLUS || COMPILE_TEST
+ depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST
help
This selects the TI OMAP High Speed Multimedia card Interface.
If you have an omap2plus board with a Multimedia Card slot,
@@ -473,7 +473,7 @@ config MMC_DAVINCI
config MMC_GOLDFISH
tristate "goldfish qemu Multimedia Card Interface support"
- depends on GOLDFISH
+ depends on GOLDFISH || COMPILE_TEST
help
This selects the Goldfish Multimedia card Interface emulation
found on the Goldfish Android virtual device emulation.
@@ -615,15 +615,7 @@ config MMC_DW
help
This selects support for the Synopsys DesignWare Mobile Storage IP
block, this provides host support for SD and MMC interfaces, in both
- PIO and external DMA modes.
-
-config MMC_DW_IDMAC
- bool "Internal DMAC interface"
- depends on MMC_DW
- help
- This selects support for the internal DMAC block within the Synopsys
- Designware Mobile Storage IP block. This disables the external DMA
- interface.
+ PIO, internal DMA mode and external DMA mode.
config MMC_DW_PLTFM
tristate "Synopsys Designware MCI Support as platform device"
@@ -652,7 +644,6 @@ config MMC_DW_K3
tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
depends on MMC_DW
select MMC_DW_PLTFM
- select MMC_DW_IDMAC
help
This selects support for Hisilicon K3 SoC specific extensions to the
Synopsys DesignWare Memory Card Interface driver. Select this option
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 4f3452afa6ca..3595f83e89dd 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -9,8 +9,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
obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
-obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-o2micro.o
obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 1e75309898b7..3a7e835a0033 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -446,7 +446,7 @@ out:
return loc;
}
-static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
+static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
{
struct dw_mci *host = slot->host;
struct dw_mci_exynos_priv_data *priv = host->priv;
@@ -461,7 +461,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
mci_writel(host, TMOUT, ~0);
smpl = dw_mci_exynos_move_next_clksmpl(host);
- if (!mmc_send_tuning(mmc))
+ if (!mmc_send_tuning(mmc, opcode, NULL))
candiates |= (1 << smpl);
} while (start_smpl != smpl);
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index ec6dbcdec693..7e1d13b68b06 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -59,6 +59,8 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
host->pdata = pdev->dev.platform_data;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ /* Get registers' physical base address */
+ host->phy_regs = (void *)(regs->start);
host->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(host->regs))
return PTR_ERR(host->regs);
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index bc76aa22473e..9becebeeccd1 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -13,12 +13,19 @@
#include <linux/mmc/host.h>
#include <linux/mmc/dw_mmc.h>
#include <linux/of_address.h>
+#include <linux/slab.h>
#include "dw_mmc.h"
#include "dw_mmc-pltfm.h"
#define RK3288_CLKGEN_DIV 2
+struct dw_mci_rockchip_priv_data {
+ struct clk *drv_clk;
+ struct clk *sample_clk;
+ int default_sample_phase;
+};
+
static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
{
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
@@ -33,6 +40,7 @@ static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{
+ struct dw_mci_rockchip_priv_data *priv = host->priv;
int ret;
unsigned int cclkin;
u32 bus_hz;
@@ -66,6 +74,158 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
/* force dw_mci_setup_bus() */
host->current_speed = 0;
}
+
+ /* Make sure we use phases which we can enumerate with */
+ if (!IS_ERR(priv->sample_clk))
+ clk_set_phase(priv->sample_clk, priv->default_sample_phase);
+}
+
+#define NUM_PHASES 360
+#define TUNING_ITERATION_TO_PHASE(i) (DIV_ROUND_UP((i) * 360, NUM_PHASES))
+
+static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
+{
+ struct dw_mci *host = slot->host;
+ struct dw_mci_rockchip_priv_data *priv = host->priv;
+ struct mmc_host *mmc = slot->mmc;
+ int ret = 0;
+ int i;
+ bool v, prev_v = 0, first_v;
+ struct range_t {
+ int start;
+ int end; /* inclusive */
+ };
+ struct range_t *ranges;
+ unsigned int range_count = 0;
+ int longest_range_len = -1;
+ int longest_range = -1;
+ int middle_phase;
+
+ if (IS_ERR(priv->sample_clk)) {
+ dev_err(host->dev, "Tuning clock (sample_clk) not defined.\n");
+ return -EIO;
+ }
+
+ ranges = kmalloc_array(NUM_PHASES / 2 + 1, sizeof(*ranges), GFP_KERNEL);
+ if (!ranges)
+ return -ENOMEM;
+
+ /* Try each phase and extract good ranges */
+ for (i = 0; i < NUM_PHASES; ) {
+ clk_set_phase(priv->sample_clk, TUNING_ITERATION_TO_PHASE(i));
+
+ v = !mmc_send_tuning(mmc, opcode, NULL);
+
+ if (i == 0)
+ first_v = v;
+
+ if ((!prev_v) && v) {
+ range_count++;
+ ranges[range_count-1].start = i;
+ }
+ if (v) {
+ ranges[range_count-1].end = i;
+ i++;
+ } else if (i == NUM_PHASES - 1) {
+ /* No extra skipping rules if we're at the end */
+ i++;
+ } else {
+ /*
+ * No need to check too close to an invalid
+ * one since testing bad phases is slow. Skip
+ * 20 degrees.
+ */
+ i += DIV_ROUND_UP(20 * NUM_PHASES, 360);
+
+ /* Always test the last one */
+ if (i >= NUM_PHASES)
+ i = NUM_PHASES - 1;
+ }
+
+ prev_v = v;
+ }
+
+ if (range_count == 0) {
+ dev_warn(host->dev, "All phases bad!");
+ ret = -EIO;
+ goto free;
+ }
+
+ /* wrap around case, merge the end points */
+ if ((range_count > 1) && first_v && v) {
+ ranges[0].start = ranges[range_count-1].start;
+ range_count--;
+ }
+
+ if (ranges[0].start == 0 && ranges[0].end == NUM_PHASES - 1) {
+ clk_set_phase(priv->sample_clk, priv->default_sample_phase);
+ dev_info(host->dev, "All phases work, using default phase %d.",
+ priv->default_sample_phase);
+ goto free;
+ }
+
+ /* Find the longest range */
+ for (i = 0; i < range_count; i++) {
+ int len = (ranges[i].end - ranges[i].start + 1);
+
+ if (len < 0)
+ len += NUM_PHASES;
+
+ if (longest_range_len < len) {
+ longest_range_len = len;
+ longest_range = i;
+ }
+
+ dev_dbg(host->dev, "Good phase range %d-%d (%d len)\n",
+ TUNING_ITERATION_TO_PHASE(ranges[i].start),
+ TUNING_ITERATION_TO_PHASE(ranges[i].end),
+ len
+ );
+ }
+
+ dev_dbg(host->dev, "Best phase range %d-%d (%d len)\n",
+ TUNING_ITERATION_TO_PHASE(ranges[longest_range].start),
+ TUNING_ITERATION_TO_PHASE(ranges[longest_range].end),
+ longest_range_len
+ );
+
+ middle_phase = ranges[longest_range].start + longest_range_len / 2;
+ middle_phase %= NUM_PHASES;
+ dev_info(host->dev, "Successfully tuned phase to %d\n",
+ TUNING_ITERATION_TO_PHASE(middle_phase));
+
+ clk_set_phase(priv->sample_clk,
+ TUNING_ITERATION_TO_PHASE(middle_phase));
+
+free:
+ kfree(ranges);
+ return ret;
+}
+
+static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
+{
+ struct device_node *np = host->dev->of_node;
+ struct dw_mci_rockchip_priv_data *priv;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (of_property_read_u32(np, "rockchip,default-sample-phase",
+ &priv->default_sample_phase))
+ priv->default_sample_phase = 0;
+
+ 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");
+
+ 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");
+
+ host->priv = priv;
+
+ return 0;
}
static int dw_mci_rockchip_init(struct dw_mci *host)
@@ -95,6 +255,8 @@ static const struct dw_mci_drv_data rk3288_drv_data = {
.caps = dw_mci_rk3288_dwmmc_caps,
.prepare_command = dw_mci_rockchip_prepare_command,
.set_ios = dw_mci_rk3288_set_ios,
+ .execute_tuning = dw_mci_rk3288_execute_tuning,
+ .parse_dt = dw_mci_rk3288_parse_dt,
.setup_clock = dw_mci_rk3288_setup_clock,
.init = dw_mci_rockchip_init,
};
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index fcbf5524fd31..7a6cedbe48a8 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -56,7 +56,6 @@
#define DW_MCI_FREQ_MAX 200000000 /* unit: HZ */
#define DW_MCI_FREQ_MIN 400000 /* unit: HZ */
-#ifdef CONFIG_MMC_DW_IDMAC
#define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
@@ -102,7 +101,6 @@ struct idmac_desc {
/* Each descriptor can transfer up to 4KB of data in chained mode */
#define DW_MCI_DESC_DATA_LENGTH 0x1000
-#endif /* CONFIG_MMC_DW_IDMAC */
static bool dw_mci_reset(struct dw_mci *host);
static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
@@ -407,7 +405,6 @@ static int dw_mci_get_dma_dir(struct mmc_data *data)
return DMA_FROM_DEVICE;
}
-#ifdef CONFIG_MMC_DW_IDMAC
static void dw_mci_dma_cleanup(struct dw_mci *host)
{
struct mmc_data *data = host->data;
@@ -445,12 +442,21 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host)
mci_writel(host, BMOD, temp);
}
-static void dw_mci_idmac_complete_dma(struct dw_mci *host)
+static void dw_mci_dmac_complete_dma(void *arg)
{
+ struct dw_mci *host = arg;
struct mmc_data *data = host->data;
dev_vdbg(host->dev, "DMA complete\n");
+ if ((host->use_dma == TRANS_MODE_EDMAC) &&
+ data && (data->flags & MMC_DATA_READ))
+ /* Invalidate cache after read */
+ dma_sync_sg_for_cpu(mmc_dev(host->cur_slot->mmc),
+ data->sg,
+ data->sg_len,
+ DMA_FROM_DEVICE);
+
host->dma_ops->cleanup(host);
/*
@@ -564,7 +570,7 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
wmb(); /* drain writebuffer */
}
-static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
+static int dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
{
u32 temp;
@@ -589,6 +595,8 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
/* Start it running */
mci_writel(host, PLDMND, 1);
+
+ return 0;
}
static int dw_mci_idmac_init(struct dw_mci *host)
@@ -669,10 +677,110 @@ static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
.init = dw_mci_idmac_init,
.start = dw_mci_idmac_start_dma,
.stop = dw_mci_idmac_stop_dma,
- .complete = dw_mci_idmac_complete_dma,
+ .complete = dw_mci_dmac_complete_dma,
+ .cleanup = dw_mci_dma_cleanup,
+};
+
+static void dw_mci_edmac_stop_dma(struct dw_mci *host)
+{
+ dmaengine_terminate_all(host->dms->ch);
+}
+
+static int dw_mci_edmac_start_dma(struct dw_mci *host,
+ unsigned int sg_len)
+{
+ struct dma_slave_config cfg;
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct scatterlist *sgl = host->data->sg;
+ const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
+ u32 sg_elems = host->data->sg_len;
+ u32 fifoth_val;
+ u32 fifo_offset = host->fifo_reg - host->regs;
+ int ret = 0;
+
+ /* Set external dma config: burst size, burst width */
+ cfg.dst_addr = (dma_addr_t)(host->phy_regs + fifo_offset);
+ cfg.src_addr = cfg.dst_addr;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+ /* Match burst msize with external dma config */
+ fifoth_val = mci_readl(host, FIFOTH);
+ cfg.dst_maxburst = mszs[(fifoth_val >> 28) & 0x7];
+ cfg.src_maxburst = cfg.dst_maxburst;
+
+ if (host->data->flags & MMC_DATA_WRITE)
+ cfg.direction = DMA_MEM_TO_DEV;
+ else
+ cfg.direction = DMA_DEV_TO_MEM;
+
+ ret = dmaengine_slave_config(host->dms->ch, &cfg);
+ if (ret) {
+ dev_err(host->dev, "Failed to config edmac.\n");
+ return -EBUSY;
+ }
+
+ desc = dmaengine_prep_slave_sg(host->dms->ch, sgl,
+ sg_len, cfg.direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(host->dev, "Can't prepare slave sg.\n");
+ return -EBUSY;
+ }
+
+ /* Set dw_mci_dmac_complete_dma as callback */
+ desc->callback = dw_mci_dmac_complete_dma;
+ desc->callback_param = (void *)host;
+ dmaengine_submit(desc);
+
+ /* Flush cache before write */
+ if (host->data->flags & MMC_DATA_WRITE)
+ dma_sync_sg_for_device(mmc_dev(host->cur_slot->mmc), sgl,
+ sg_elems, DMA_TO_DEVICE);
+
+ dma_async_issue_pending(host->dms->ch);
+
+ return 0;
+}
+
+static int dw_mci_edmac_init(struct dw_mci *host)
+{
+ /* Request external dma channel */
+ host->dms = kzalloc(sizeof(struct dw_mci_dma_slave), GFP_KERNEL);
+ if (!host->dms)
+ return -ENOMEM;
+
+ host->dms->ch = dma_request_slave_channel(host->dev, "rx-tx");
+ if (!host->dms->ch) {
+ dev_err(host->dev, "Failed to get external DMA channel.\n");
+ kfree(host->dms);
+ host->dms = NULL;
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void dw_mci_edmac_exit(struct dw_mci *host)
+{
+ if (host->dms) {
+ if (host->dms->ch) {
+ dma_release_channel(host->dms->ch);
+ host->dms->ch = NULL;
+ }
+ kfree(host->dms);
+ host->dms = NULL;
+ }
+}
+
+static const struct dw_mci_dma_ops dw_mci_edmac_ops = {
+ .init = dw_mci_edmac_init,
+ .exit = dw_mci_edmac_exit,
+ .start = dw_mci_edmac_start_dma,
+ .stop = dw_mci_edmac_stop_dma,
+ .complete = dw_mci_dmac_complete_dma,
.cleanup = dw_mci_dma_cleanup,
};
-#endif /* CONFIG_MMC_DW_IDMAC */
static int dw_mci_pre_dma_transfer(struct dw_mci *host,
struct mmc_data *data,
@@ -752,7 +860,6 @@ static void dw_mci_post_req(struct mmc_host *mmc,
static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
{
-#ifdef CONFIG_MMC_DW_IDMAC
unsigned int blksz = data->blksz;
const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
u32 fifo_width = 1 << host->data_shift;
@@ -760,6 +867,10 @@ static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
int idx = ARRAY_SIZE(mszs) - 1;
+ /* pio should ship this scenario */
+ if (!host->use_dma)
+ return;
+
tx_wmark = (host->fifo_depth) / 2;
tx_wmark_invers = host->fifo_depth - tx_wmark;
@@ -788,7 +899,6 @@ static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
done:
fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark);
mci_writel(host, FIFOTH, fifoth_val);
-#endif
}
static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
@@ -850,10 +960,12 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
host->using_dma = 1;
- dev_vdbg(host->dev,
- "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
- (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
- sg_len);
+ if (host->use_dma == TRANS_MODE_IDMAC)
+ dev_vdbg(host->dev,
+ "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
+ (unsigned long)host->sg_cpu,
+ (unsigned long)host->sg_dma,
+ sg_len);
/*
* Decide the MSIZE and RX/TX Watermark.
@@ -875,7 +987,11 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
mci_writel(host, INTMASK, temp);
spin_unlock_irqrestore(&host->irq_lock, irqflags);
- host->dma_ops->start(host, sg_len);
+ if (host->dma_ops->start(host, sg_len)) {
+ /* We can't do DMA */
+ dev_err(host->dev, "%s: failed to start DMA.\n", __func__);
+ return -ENODEV;
+ }
return 0;
}
@@ -1177,6 +1293,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* DDR mode set */
if (ios->timing == MMC_TIMING_MMC_DDR52 ||
+ ios->timing == MMC_TIMING_UHS_DDR50 ||
ios->timing == MMC_TIMING_MMC_HS400)
regs |= ((0x1 << slot->id) << 16);
else
@@ -1279,7 +1396,6 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
const struct dw_mci_drv_data *drv_data = host->drv_data;
u32 uhs;
u32 v18 = SDMMC_UHS_18V << slot->id;
- int min_uv, max_uv;
int ret;
if (drv_data && drv_data->switch_voltage)
@@ -1291,22 +1407,18 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
* does no harm but you need to set the regulator directly. Try both.
*/
uhs = mci_readl(host, UHS_REG);
- if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
- min_uv = 2700000;
- max_uv = 3600000;
+ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
uhs &= ~v18;
- } else {
- min_uv = 1700000;
- max_uv = 1950000;
+ else
uhs |= v18;
- }
+
if (!IS_ERR(mmc->supply.vqmmc)) {
- ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv);
+ ret = mmc_regulator_set_vqmmc(mmc, ios);
if (ret) {
dev_dbg(&mmc->class_dev,
- "Regulator set error %d: %d - %d\n",
- ret, min_uv, max_uv);
+ "Regulator set error %d - %s V\n",
+ ret, uhs & v18 ? "1.8" : "3.3");
return ret;
}
}
@@ -1427,7 +1539,7 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
int err = -EINVAL;
if (drv_data && drv_data->execute_tuning)
- err = drv_data->execute_tuning(slot);
+ err = drv_data->execute_tuning(slot, opcode);
return err;
}
@@ -2343,15 +2455,17 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
-#ifdef CONFIG_MMC_DW_IDMAC
- /* Handle DMA interrupts */
+ if (host->use_dma != TRANS_MODE_IDMAC)
+ return IRQ_HANDLED;
+
+ /* Handle IDMA interrupts */
if (host->dma_64bit_address == 1) {
pending = mci_readl(host, IDSTS64);
if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |
SDMMC_IDMAC_INT_RI);
mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI);
- host->dma_ops->complete(host);
+ host->dma_ops->complete((void *)host);
}
} else {
pending = mci_readl(host, IDSTS);
@@ -2359,10 +2473,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |
SDMMC_IDMAC_INT_RI);
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
- host->dma_ops->complete(host);
+ host->dma_ops->complete((void *)host);
}
}
-#endif
return IRQ_HANDLED;
}
@@ -2471,13 +2584,21 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
goto err_host_allocated;
/* Useful defaults if platform data is unset. */
- if (host->use_dma) {
+ if (host->use_dma == TRANS_MODE_IDMAC) {
mmc->max_segs = host->ring_size;
mmc->max_blk_size = 65536;
mmc->max_seg_size = 0x1000;
mmc->max_req_size = mmc->max_seg_size * host->ring_size;
mmc->max_blk_count = mmc->max_req_size / 512;
+ } else if (host->use_dma == TRANS_MODE_EDMAC) {
+ mmc->max_segs = 64;
+ mmc->max_blk_size = 65536;
+ mmc->max_blk_count = 65535;
+ mmc->max_req_size =
+ mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
} else {
+ /* TRANS_MODE_PIO */
mmc->max_segs = 64;
mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
mmc->max_blk_count = 512;
@@ -2517,38 +2638,74 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
static void dw_mci_init_dma(struct dw_mci *host)
{
int addr_config;
- /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */
- addr_config = (mci_readl(host, HCON) >> 27) & 0x01;
-
- if (addr_config == 1) {
- /* host supports IDMAC in 64-bit address mode */
- host->dma_64bit_address = 1;
- dev_info(host->dev, "IDMAC supports 64-bit address mode.\n");
- if (!dma_set_mask(host->dev, DMA_BIT_MASK(64)))
- dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64));
- } else {
- /* host supports IDMAC in 32-bit address mode */
- host->dma_64bit_address = 0;
- dev_info(host->dev, "IDMAC supports 32-bit address mode.\n");
- }
+ struct device *dev = host->dev;
+ struct device_node *np = dev->of_node;
- /* Alloc memory for sg translation */
- host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
- &host->sg_dma, GFP_KERNEL);
- if (!host->sg_cpu) {
- dev_err(host->dev, "%s: could not alloc DMA memory\n",
- __func__);
+ /*
+ * Check tansfer mode from HCON[17:16]
+ * Clear the ambiguous description of dw_mmc databook:
+ * 2b'00: No DMA Interface -> Actually means using Internal DMA block
+ * 2b'01: DesignWare DMA Interface -> Synopsys DW-DMA block
+ * 2b'10: Generic DMA Interface -> non-Synopsys generic DMA block
+ * 2b'11: Non DW DMA Interface -> pio only
+ * Compared to DesignWare DMA Interface, Generic DMA Interface has a
+ * simpler request/acknowledge handshake mechanism and both of them
+ * are regarded as external dma master for dw_mmc.
+ */
+ host->use_dma = SDMMC_GET_TRANS_MODE(mci_readl(host, HCON));
+ if (host->use_dma == DMA_INTERFACE_IDMA) {
+ host->use_dma = TRANS_MODE_IDMAC;
+ } else if (host->use_dma == DMA_INTERFACE_DWDMA ||
+ host->use_dma == DMA_INTERFACE_GDMA) {
+ host->use_dma = TRANS_MODE_EDMAC;
+ } else {
goto no_dma;
}
/* Determine which DMA interface to use */
-#ifdef CONFIG_MMC_DW_IDMAC
- host->dma_ops = &dw_mci_idmac_ops;
- dev_info(host->dev, "Using internal DMA controller.\n");
-#endif
+ if (host->use_dma == TRANS_MODE_IDMAC) {
+ /*
+ * Check ADDR_CONFIG bit in HCON to find
+ * IDMAC address bus width
+ */
+ addr_config = SDMMC_GET_ADDR_CONFIG(mci_readl(host, HCON));
+
+ if (addr_config == 1) {
+ /* host supports IDMAC in 64-bit address mode */
+ host->dma_64bit_address = 1;
+ dev_info(host->dev,
+ "IDMAC supports 64-bit address mode.\n");
+ if (!dma_set_mask(host->dev, DMA_BIT_MASK(64)))
+ dma_set_coherent_mask(host->dev,
+ DMA_BIT_MASK(64));
+ } else {
+ /* host supports IDMAC in 32-bit address mode */
+ host->dma_64bit_address = 0;
+ dev_info(host->dev,
+ "IDMAC supports 32-bit address mode.\n");
+ }
- if (!host->dma_ops)
- goto no_dma;
+ /* Alloc memory for sg translation */
+ host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
+ &host->sg_dma, GFP_KERNEL);
+ if (!host->sg_cpu) {
+ dev_err(host->dev,
+ "%s: could not alloc DMA memory\n",
+ __func__);
+ goto no_dma;
+ }
+
+ host->dma_ops = &dw_mci_idmac_ops;
+ dev_info(host->dev, "Using internal DMA controller.\n");
+ } else {
+ /* TRANS_MODE_EDMAC: check dma bindings again */
+ if ((of_property_count_strings(np, "dma-names") < 0) ||
+ (!of_find_property(np, "dmas", NULL))) {
+ goto no_dma;
+ }
+ host->dma_ops = &dw_mci_edmac_ops;
+ dev_info(host->dev, "Using external DMA controller.\n");
+ }
if (host->dma_ops->init && host->dma_ops->start &&
host->dma_ops->stop && host->dma_ops->cleanup) {
@@ -2562,12 +2719,11 @@ static void dw_mci_init_dma(struct dw_mci *host)
goto no_dma;
}
- host->use_dma = 1;
return;
no_dma:
dev_info(host->dev, "Using PIO mode.\n");
- host->use_dma = 0;
+ host->use_dma = TRANS_MODE_PIO;
}
static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
@@ -2650,10 +2806,9 @@ static bool dw_mci_reset(struct dw_mci *host)
}
}
-#if IS_ENABLED(CONFIG_MMC_DW_IDMAC)
- /* It is also recommended that we reset and reprogram idmac */
- dw_mci_idmac_reset(host);
-#endif
+ if (host->use_dma == TRANS_MODE_IDMAC)
+ /* It is also recommended that we reset and reprogram idmac */
+ dw_mci_idmac_reset(host);
ret = true;
@@ -2890,7 +3045,7 @@ int dw_mci_probe(struct dw_mci *host)
* Get the host data width - this assumes that HCON has been set with
* the correct values.
*/
- i = (mci_readl(host, HCON) >> 7) & 0x7;
+ i = SDMMC_GET_HDATA_WIDTH(mci_readl(host, HCON));
if (!i) {
host->push_data = dw_mci_push_data16;
host->pull_data = dw_mci_pull_data16;
@@ -2972,7 +3127,7 @@ int dw_mci_probe(struct dw_mci *host)
if (host->pdata->num_slots)
host->num_slots = host->pdata->num_slots;
else
- host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
+ host->num_slots = SDMMC_GET_SLOT_NUM(mci_readl(host, HCON));
/*
* Enable interrupts for command done, data over, data empty,
@@ -3067,6 +3222,9 @@ EXPORT_SYMBOL(dw_mci_remove);
*/
int dw_mci_suspend(struct dw_mci *host)
{
+ if (host->use_dma && host->dma_ops->exit)
+ host->dma_ops->exit(host);
+
return 0;
}
EXPORT_SYMBOL(dw_mci_suspend);
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 8ce4674730a6..f695b58f0613 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -148,6 +148,15 @@
#define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \
((r) & 0xFFF) << 16 | \
((t) & 0xFFF))
+/* HCON register defines */
+#define DMA_INTERFACE_IDMA (0x0)
+#define DMA_INTERFACE_DWDMA (0x1)
+#define DMA_INTERFACE_GDMA (0x2)
+#define DMA_INTERFACE_NODMA (0x3)
+#define SDMMC_GET_TRANS_MODE(x) (((x)>>16) & 0x3)
+#define SDMMC_GET_SLOT_NUM(x) ((((x)>>1) & 0x1F) + 1)
+#define SDMMC_GET_HDATA_WIDTH(x) (((x)>>7) & 0x7)
+#define SDMMC_GET_ADDR_CONFIG(x) (((x)>>27) & 0x1)
/* Internal DMAC interrupt defines */
#define SDMMC_IDMAC_INT_AI BIT(9)
#define SDMMC_IDMAC_INT_NI BIT(8)
@@ -163,7 +172,7 @@
/* Version ID register define */
#define SDMMC_GET_VERID(x) ((x) & 0xFFFF)
/* Card read threshold */
-#define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x))
+#define SDMMC_SET_RD_THLD(v, x) (((v) & 0xFFF) << 16 | (x))
#define SDMMC_UHS_18V BIT(0)
/* All ctrl reset bits */
#define SDMMC_CTRL_ALL_RESET_FLAGS \
@@ -281,7 +290,7 @@ struct dw_mci_drv_data {
void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host);
- int (*execute_tuning)(struct dw_mci_slot *slot);
+ int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode);
int (*prepare_hs400_tuning)(struct dw_mci *host,
struct mmc_ios *ios);
int (*switch_voltage)(struct mmc_host *mmc,
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 8c79831b20fb..1c1b45ef3faf 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -1511,6 +1511,7 @@ static const struct of_device_id mmc_spi_of_match_table[] = {
{ .compatible = "mmc-spi-slot", },
{},
};
+MODULE_DEVICE_TABLE(of, mmc_spi_of_match_table);
static struct spi_driver mmc_spi_driver = {
.driver = {
diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c
index 006f1862444b..79905ce895ad 100644
--- a/drivers/mmc/host/moxart-mmc.c
+++ b/drivers/mmc/host/moxart-mmc.c
@@ -711,6 +711,7 @@ static const struct of_device_id moxart_mmc_match[] = {
{ .compatible = "faraday,ftsdc010" },
{ }
};
+MODULE_DEVICE_TABLE(of, moxart_mmc_match);
static struct platform_driver moxart_mmc_driver = {
.probe = moxart_probe,
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 7153500dd007..39568cc29a2a 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -26,6 +26,7 @@
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/mmc/card.h>
@@ -64,6 +65,7 @@
#define SDC_RESP2 0x48
#define SDC_RESP3 0x4c
#define SDC_BLK_NUM 0x50
+#define EMMC_IOCON 0x7c
#define SDC_ACMD_RESP 0x80
#define MSDC_DMA_SA 0x90
#define MSDC_DMA_CTRL 0x98
@@ -71,6 +73,8 @@
#define MSDC_PATCH_BIT 0xb0
#define MSDC_PATCH_BIT1 0xb4
#define MSDC_PAD_TUNE 0xec
+#define PAD_DS_TUNE 0x188
+#define EMMC50_CFG0 0x208
/*--------------------------------------------------------------------------*/
/* Register Mask */
@@ -87,6 +91,7 @@
#define MSDC_CFG_CKSTB (0x1 << 7) /* R */
#define MSDC_CFG_CKDIV (0xff << 8) /* RW */
#define MSDC_CFG_CKMOD (0x3 << 16) /* RW */
+#define MSDC_CFG_HS400_CK_MODE (0x1 << 18) /* RW */
/* MSDC_IOCON mask */
#define MSDC_IOCON_SDR104CKS (0x1 << 0) /* RW */
@@ -204,6 +209,17 @@
#define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */
#define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */
+#define MSDC_PAD_TUNE_DATRRDLY (0x1f << 8) /* RW */
+#define MSDC_PAD_TUNE_CMDRDLY (0x1f << 16) /* RW */
+
+#define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */
+#define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */
+#define PAD_DS_TUNE_DLY3 (0x1f << 12) /* RW */
+
+#define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0) /* RW */
+#define EMMC50_CFG_CRCSTS_EDGE (0x1 << 3) /* RW */
+#define EMMC50_CFG_CFCSTS_SEL (0x1 << 4) /* RW */
+
#define REQ_CMD_EIO (0x1 << 0)
#define REQ_CMD_TMO (0x1 << 1)
#define REQ_DAT_ERR (0x1 << 2)
@@ -219,6 +235,7 @@
#define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */
#define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */
+#define PAD_DELAY_MAX 32 /* PAD delay cells */
/*--------------------------------------------------------------------------*/
/* Descriptor Structure */
/*--------------------------------------------------------------------------*/
@@ -265,6 +282,14 @@ struct msdc_save_para {
u32 pad_tune;
u32 patch_bit0;
u32 patch_bit1;
+ u32 pad_ds_tune;
+ u32 emmc50_cfg0;
+};
+
+struct msdc_delay_phase {
+ u8 maxlen;
+ u8 start;
+ u8 final_phase;
};
struct msdc_host {
@@ -297,8 +322,9 @@ struct msdc_host {
u32 mclk; /* mmc subsystem clock frequency */
u32 src_clk_freq; /* source clock frequency */
u32 sclk; /* SD/MS bus clock frequency */
- bool ddr;
+ unsigned char timing;
bool vqmmc_enabled;
+ u32 hs400_ds_delay;
struct msdc_save_para save_para; /* used when gate HCLK */
};
@@ -353,7 +379,10 @@ static void msdc_reset_hw(struct msdc_host *host)
static void msdc_cmd_next(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd);
-static u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO |
+static const u32 cmd_ints_mask = MSDC_INTEN_CMDRDY | MSDC_INTEN_RSPCRCERR |
+ MSDC_INTEN_CMDTMO | MSDC_INTEN_ACMDRDY |
+ MSDC_INTEN_ACMDCRCERR | MSDC_INTEN_ACMDTMO;
+static const u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO |
MSDC_INTEN_DATCRCERR | MSDC_INTEN_DMA_BDCSERR |
MSDC_INTEN_DMA_GPDCSERR | MSDC_INTEN_DMA_PROTECT;
@@ -485,7 +514,7 @@ static void msdc_ungate_clock(struct msdc_host *host)
cpu_relax();
}
-static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
+static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
{
u32 mode;
u32 flags;
@@ -501,8 +530,15 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
flags = readl(host->base + MSDC_INTEN);
sdr_clr_bits(host->base + MSDC_INTEN, flags);
- if (ddr) { /* may need to modify later */
- mode = 0x2; /* ddr mode and use divisor */
+ sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_HS400_CK_MODE);
+ if (timing == MMC_TIMING_UHS_DDR50 ||
+ timing == MMC_TIMING_MMC_DDR52 ||
+ timing == MMC_TIMING_MMC_HS400) {
+ if (timing == MMC_TIMING_MMC_HS400)
+ mode = 0x3;
+ else
+ mode = 0x2; /* ddr mode and use divisor */
+
if (hz >= (host->src_clk_freq >> 2)) {
div = 0; /* mean div = 1/4 */
sclk = host->src_clk_freq >> 2; /* sclk = clk / 4 */
@@ -511,6 +547,14 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
sclk = (host->src_clk_freq >> 2) / div;
div = (div >> 1);
}
+
+ if (timing == MMC_TIMING_MMC_HS400 &&
+ hz >= (host->src_clk_freq >> 1)) {
+ sdr_set_bits(host->base + MSDC_CFG,
+ MSDC_CFG_HS400_CK_MODE);
+ sclk = host->src_clk_freq >> 1;
+ div = 0; /* div is ignore when bit18 is set */
+ }
} else if (hz >= host->src_clk_freq) {
mode = 0x1; /* no divisor */
div = 0;
@@ -532,12 +576,12 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
cpu_relax();
host->sclk = sclk;
host->mclk = hz;
- host->ddr = ddr;
+ host->timing = timing;
/* need because clk changed. */
msdc_set_timeout(host, host->timeout_ns, host->timeout_clks);
sdr_set_bits(host->base + MSDC_INTEN, flags);
- dev_dbg(host->dev, "sclk: %d, ddr: %d\n", host->sclk, ddr);
+ dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->sclk, timing);
}
static inline u32 msdc_cmd_find_resp(struct msdc_host *host,
@@ -725,11 +769,7 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
if (done)
return true;
- sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY |
- MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO |
- MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR |
- MSDC_INTEN_ACMDTMO);
- writel(cmd->arg, host->base + SDC_ARG);
+ sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
@@ -819,10 +859,7 @@ static void msdc_start_command(struct msdc_host *host,
rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
- sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY |
- MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO |
- MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR |
- MSDC_INTEN_ACMDTMO);
+ sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
writel(cmd->arg, host->base + SDC_ARG);
writel(rawcmd, host->base + SDC_CMD);
}
@@ -896,7 +933,7 @@ static void msdc_data_xfer_next(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_data *data)
{
if (mmc_op_multi(mrq->cmd->opcode) && mrq->stop && !mrq->stop->error &&
- (!data->bytes_xfered || !mrq->sbc))
+ !mrq->sbc)
msdc_start_command(host, mrq, mrq->stop);
else
msdc_request_done(host, mrq);
@@ -942,6 +979,8 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
if (events & MSDC_INT_DATTMO)
data->error = -ETIMEDOUT;
+ else if (events & MSDC_INT_DATCRCERR)
+ data->error = -EILSEQ;
dev_err(host->dev, "%s: cmd=%d; blocks=%d",
__func__, mrq->cmd->opcode, data->blocks);
@@ -1113,10 +1152,12 @@ static void msdc_init_hw(struct msdc_host *host)
writel(0, host->base + MSDC_PAD_TUNE);
writel(0, host->base + MSDC_IOCON);
- sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 1);
- writel(0x403c004f, host->base + MSDC_PATCH_BIT);
+ sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
+ writel(0x403c0046, host->base + MSDC_PATCH_BIT);
sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL, 1);
writel(0xffff0089, host->base + MSDC_PATCH_BIT1);
+ sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL);
+
/* Configure to enable SDIO mode.
* it's must otherwise sdio cmd5 failed
*/
@@ -1148,11 +1189,14 @@ static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma)
struct mt_bdma_desc *bd = dma->bd;
int i;
- memset(gpd, 0, sizeof(struct mt_gpdma_desc));
+ memset(gpd, 0, sizeof(struct mt_gpdma_desc) * 2);
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);
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);
@@ -1162,20 +1206,16 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct msdc_host *host = mmc_priv(mmc);
int ret;
- u32 ddr = 0;
pm_runtime_get_sync(host->dev);
- if (ios->timing == MMC_TIMING_UHS_DDR50 ||
- ios->timing == MMC_TIMING_MMC_DDR52)
- ddr = 1;
-
msdc_set_buswidth(host, ios->bus_width);
/* Suspend/Resume will do power off/on */
switch (ios->power_mode) {
case MMC_POWER_UP:
if (!IS_ERR(mmc->supply.vmmc)) {
+ msdc_init_hw(host);
ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
ios->vdd);
if (ret) {
@@ -1206,14 +1246,207 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
break;
}
- if (host->mclk != ios->clock || host->ddr != ddr)
- msdc_set_mclk(host, ddr, ios->clock);
+ if (host->mclk != ios->clock || host->timing != ios->timing)
+ msdc_set_mclk(host, ios->timing, ios->clock);
end:
pm_runtime_mark_last_busy(host->dev);
pm_runtime_put_autosuspend(host->dev);
}
+static u32 test_delay_bit(u32 delay, u32 bit)
+{
+ bit %= PAD_DELAY_MAX;
+ return delay & (1 << bit);
+}
+
+static int get_delay_len(u32 delay, u32 start_bit)
+{
+ int i;
+
+ for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) {
+ if (test_delay_bit(delay, start_bit + i) == 0)
+ return i;
+ }
+ return PAD_DELAY_MAX - start_bit;
+}
+
+static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
+{
+ int start = 0, len = 0;
+ int start_final = 0, len_final = 0;
+ u8 final_phase = 0xff;
+ struct msdc_delay_phase delay_phase;
+
+ if (delay == 0) {
+ dev_err(host->dev, "phase error: [map:%x]\n", delay);
+ delay_phase.final_phase = final_phase;
+ return delay_phase;
+ }
+
+ while (start < PAD_DELAY_MAX) {
+ len = get_delay_len(delay, start);
+ if (len_final < len) {
+ start_final = start;
+ len_final = len;
+ }
+ start += len ? len : 1;
+ if (len >= 8 && start_final < 4)
+ break;
+ }
+
+ /* The rule is that to find the smallest delay cell */
+ if (start_final == 0)
+ final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX;
+ else
+ final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX;
+ dev_info(host->dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n",
+ delay, len_final, final_phase);
+
+ delay_phase.maxlen = len_final;
+ delay_phase.start = start_final;
+ delay_phase.final_phase = final_phase;
+ return delay_phase;
+}
+
+static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ u32 rise_delay = 0, fall_delay = 0;
+ struct msdc_delay_phase final_rise_delay, final_fall_delay;
+ u8 final_delay, final_maxlen;
+ int cmd_err;
+ int i;
+
+ sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+ for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+ sdr_set_field(host->base + MSDC_PAD_TUNE,
+ MSDC_PAD_TUNE_CMDRDLY, i);
+ mmc_send_tuning(mmc, opcode, &cmd_err);
+ if (!cmd_err)
+ rise_delay |= (1 << i);
+ }
+
+ sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+ for (i = 0; i < PAD_DELAY_MAX; i++) {
+ sdr_set_field(host->base + MSDC_PAD_TUNE,
+ MSDC_PAD_TUNE_CMDRDLY, i);
+ mmc_send_tuning(mmc, opcode, &cmd_err);
+ if (!cmd_err)
+ fall_delay |= (1 << i);
+ }
+
+ final_rise_delay = get_best_delay(host, rise_delay);
+ final_fall_delay = get_best_delay(host, fall_delay);
+
+ final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
+ if (final_maxlen == final_rise_delay.maxlen) {
+ sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+ sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+ final_rise_delay.final_phase);
+ final_delay = final_rise_delay.final_phase;
+ } else {
+ sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+ sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+ final_fall_delay.final_phase);
+ final_delay = final_fall_delay.final_phase;
+ }
+
+ return final_delay == 0xff ? -EIO : 0;
+}
+
+static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ u32 rise_delay = 0, fall_delay = 0;
+ struct msdc_delay_phase final_rise_delay, final_fall_delay;
+ u8 final_delay, final_maxlen;
+ int i, ret;
+
+ sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+ sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+ for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+ sdr_set_field(host->base + MSDC_PAD_TUNE,
+ MSDC_PAD_TUNE_DATRRDLY, i);
+ ret = mmc_send_tuning(mmc, opcode, NULL);
+ if (!ret)
+ rise_delay |= (1 << i);
+ }
+
+ sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+ sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+ for (i = 0; i < PAD_DELAY_MAX; i++) {
+ sdr_set_field(host->base + MSDC_PAD_TUNE,
+ MSDC_PAD_TUNE_DATRRDLY, i);
+ ret = mmc_send_tuning(mmc, opcode, NULL);
+ if (!ret)
+ fall_delay |= (1 << i);
+ }
+
+ final_rise_delay = get_best_delay(host, rise_delay);
+ final_fall_delay = get_best_delay(host, fall_delay);
+
+ final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
+ /* Rising edge is more stable, prefer to use it */
+ if (final_rise_delay.maxlen >= 10)
+ final_maxlen = final_rise_delay.maxlen;
+ if (final_maxlen == final_rise_delay.maxlen) {
+ sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+ sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+ sdr_set_field(host->base + MSDC_PAD_TUNE,
+ MSDC_PAD_TUNE_DATRRDLY,
+ final_rise_delay.final_phase);
+ final_delay = final_rise_delay.final_phase;
+ } else {
+ sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+ sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+ sdr_set_field(host->base + MSDC_PAD_TUNE,
+ MSDC_PAD_TUNE_DATRRDLY,
+ final_fall_delay.final_phase);
+ final_delay = final_fall_delay.final_phase;
+ }
+
+ return final_delay == 0xff ? -EIO : 0;
+}
+
+static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ int ret;
+
+ pm_runtime_get_sync(host->dev);
+ ret = msdc_tune_response(mmc, opcode);
+ if (ret == -EIO) {
+ dev_err(host->dev, "Tune response fail!\n");
+ goto out;
+ }
+ ret = msdc_tune_data(mmc, opcode);
+ if (ret == -EIO)
+ dev_err(host->dev, "Tune data fail!\n");
+
+out:
+ pm_runtime_mark_last_busy(host->dev);
+ pm_runtime_put_autosuspend(host->dev);
+ return ret;
+}
+
+static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+
+ writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE);
+ return 0;
+}
+
+static void msdc_hw_reset(struct mmc_host *mmc)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+
+ sdr_set_bits(host->base + EMMC_IOCON, 1);
+ udelay(10); /* 10us is enough */
+ sdr_clr_bits(host->base + EMMC_IOCON, 1);
+}
+
static struct mmc_host_ops mt_msdc_ops = {
.post_req = msdc_post_req,
.pre_req = msdc_pre_req,
@@ -1221,6 +1454,9 @@ static struct mmc_host_ops mt_msdc_ops = {
.set_ios = msdc_ops_set_ios,
.start_signal_voltage_switch = msdc_ops_switch_volt,
.card_busy = msdc_card_busy,
+ .execute_tuning = msdc_execute_tuning,
+ .prepare_hs400_tuning = msdc_prepare_hs400_tuning,
+ .hw_reset = msdc_hw_reset,
};
static int msdc_drv_probe(struct platform_device *pdev)
@@ -1294,6 +1530,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
goto host_free;
}
+ if (!of_property_read_u32(pdev->dev.of_node, "hs400-ds-delay",
+ &host->hs400_ds_delay))
+ dev_dbg(&pdev->dev, "hs400-ds-delay: %x\n",
+ host->hs400_ds_delay);
+
host->dev = &pdev->dev;
host->mmc = mmc;
host->src_clk_freq = clk_get_rate(host->src_clk);
@@ -1302,6 +1543,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
mmc->f_min = host->src_clk_freq / (4 * 255);
mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
+ mmc->caps |= MMC_CAP_RUNTIME_RESUME;
/* MMC core transfer sizes tunable parameters */
mmc->max_segs = MAX_BD_NUM;
mmc->max_seg_size = BDMA_DESC_BUFLEN;
@@ -1313,7 +1555,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
host->timeout_clks = 3 * 1048576;
host->dma.gpd = dma_alloc_coherent(&pdev->dev,
- sizeof(struct mt_gpdma_desc),
+ 2 * sizeof(struct mt_gpdma_desc),
&host->dma.gpd_addr, GFP_KERNEL);
host->dma.bd = dma_alloc_coherent(&pdev->dev,
MAX_BD_NUM * sizeof(struct mt_bdma_desc),
@@ -1354,7 +1596,7 @@ release:
release_mem:
if (host->dma.gpd)
dma_free_coherent(&pdev->dev,
- sizeof(struct mt_gpdma_desc),
+ 2 * sizeof(struct mt_gpdma_desc),
host->dma.gpd, host->dma.gpd_addr);
if (host->dma.bd)
dma_free_coherent(&pdev->dev,
@@ -1403,6 +1645,8 @@ static void msdc_save_reg(struct msdc_host *host)
host->save_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT);
host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1);
+ host->save_para.pad_ds_tune = readl(host->base + PAD_DS_TUNE);
+ host->save_para.emmc50_cfg0 = readl(host->base + EMMC50_CFG0);
}
static void msdc_restore_reg(struct msdc_host *host)
@@ -1413,6 +1657,8 @@ static void msdc_restore_reg(struct msdc_host *host)
writel(host->save_para.pad_tune, host->base + MSDC_PAD_TUNE);
writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT);
writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1);
+ writel(host->save_para.pad_ds_tune, host->base + PAD_DS_TUNE);
+ writel(host->save_para.emmc50_cfg0, host->base + EMMC50_CFG0);
}
static int msdc_runtime_suspend(struct device *dev)
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index b763b11ed9e1..b9958a123594 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -1490,6 +1490,7 @@ static const struct of_device_id mmc_omap_match[] = {
{ .compatible = "ti,omap2420-mmc", },
{ },
};
+MODULE_DEVICE_TABLE(of, mmc_omap_match);
#endif
static struct platform_driver mmc_omap_driver = {
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 22d929fa3371..f6047fc94062 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -207,7 +207,9 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
.caps2 = MMC_CAP2_HC_ERASE_SZ,
.flags = SDHCI_ACPI_RUNTIME_PM,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
- .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+ SDHCI_QUIRK2_STOP_WITH_TC |
+ SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
.probe_slot = sdhci_acpi_emmc_probe_slot,
};
@@ -239,6 +241,9 @@ struct sdhci_acpi_uid_slot {
};
static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
+ { "80865ACA", NULL, &sdhci_acpi_slot_int_sd },
+ { "80865ACC", NULL, &sdhci_acpi_slot_int_emmc },
+ { "80865AD0", NULL, &sdhci_acpi_slot_int_sdio },
{ "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
{ "80860F14" , "3" , &sdhci_acpi_slot_int_sd },
{ "80860F16" , NULL, &sdhci_acpi_slot_int_sd },
@@ -247,11 +252,15 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
{ "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio },
{ "INT3436" , NULL, &sdhci_acpi_slot_int_sdio },
{ "INT344D" , NULL, &sdhci_acpi_slot_int_sdio },
+ { "PNP0FFF" , "3" , &sdhci_acpi_slot_int_sd },
{ "PNP0D40" },
{ },
};
static const struct acpi_device_id sdhci_acpi_ids[] = {
+ { "80865ACA" },
+ { "80865ACC" },
+ { "80865AD0" },
{ "80860F14" },
{ "80860F16" },
{ "INT33BB" },
diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
index 2bd90fb35c75..00a8a40a3729 100644
--- a/drivers/mmc/host/sdhci-bcm-kona.c
+++ b/drivers/mmc/host/sdhci-bcm-kona.c
@@ -273,7 +273,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
dev_dbg(dev, "is_8bit=%c\n",
- (host->mmc->caps | MMC_CAP_8_BIT_DATA) ? 'Y' : 'N');
+ (host->mmc->caps & MMC_CAP_8_BIT_DATA) ? 'Y' : 'N');
ret = sdhci_bcm_kona_sd_reset(host);
if (ret)
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 886d230f41d0..1f1582f6cccb 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -759,7 +759,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
min = ESDHC_TUNE_CTRL_MIN;
while (min < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, min);
- if (!mmc_send_tuning(host->mmc))
+ if (!mmc_send_tuning(host->mmc, opcode, NULL))
break;
min += ESDHC_TUNE_CTRL_STEP;
}
@@ -768,7 +768,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
max = min + ESDHC_TUNE_CTRL_STEP;
while (max < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, max);
- if (mmc_send_tuning(host->mmc)) {
+ if (mmc_send_tuning(host->mmc, opcode, NULL)) {
max -= ESDHC_TUNE_CTRL_STEP;
break;
}
@@ -778,7 +778,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
/* use average delay to get the best timing */
avg = (min + max) / 2;
esdhc_prepare_tuning(host, avg);
- ret = mmc_send_tuning(host->mmc);
+ ret = mmc_send_tuning(host->mmc, opcode, NULL);
esdhc_post_tuning(host);
dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index 163ac9974d91..de132e281753 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -24,6 +24,8 @@
SDHCI_QUIRK_PIO_NEEDS_DELAY | \
SDHCI_QUIRK_NO_HISPD_BIT)
+#define ESDHC_PROCTL 0x28
+
#define ESDHC_SYSTEM_CONTROL 0x2c
#define ESDHC_CLOCK_MASK 0x0000fff0
#define ESDHC_PREDIV_SHIFT 8
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4bcee033feda..4695bee203ea 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -373,7 +373,7 @@ retry:
if (rc)
return rc;
- rc = mmc_send_tuning(mmc);
+ rc = mmc_send_tuning(mmc, opcode, NULL);
if (!rc) {
/* Tuning is successful at this tuning point */
tuned_phases[tuned_phase_cnt++] = phase;
diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
index a0f05de5409f..06d0b50dfe71 100644
--- a/drivers/mmc/host/sdhci-of-at91.c
+++ b/drivers/mmc/host/sdhci-of-at91.c
@@ -111,7 +111,6 @@ static int sdhci_at91_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "failed to set gck");
goto hclock_disable_unprepare;
- return -EINVAL;
}
/*
* We need to check if we have the requested rate for gck because in
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 653f335bef15..90e94a028a49 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -24,122 +24,324 @@
#define VENDOR_V_22 0x12
#define VENDOR_V_23 0x13
-static u32 esdhc_readl(struct sdhci_host *host, int reg)
+
+struct sdhci_esdhc {
+ u8 vendor_ver;
+ u8 spec_ver;
+};
+
+/**
+ * esdhc_read*_fixup - Fixup the value read from incompatible eSDHC register
+ * to make it compatible with SD spec.
+ *
+ * @host: pointer to sdhci_host
+ * @spec_reg: SD spec register address
+ * @value: 32bit eSDHC register value on spec_reg address
+ *
+ * In SD spec, there are 8/16/32/64 bits registers, while all of eSDHC
+ * registers are 32 bits. There are differences in register size, register
+ * address, register function, bit position and function between eSDHC spec
+ * and SD spec.
+ *
+ * Return a fixed up register value
+ */
+static u32 esdhc_readl_fixup(struct sdhci_host *host,
+ int spec_reg, u32 value)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = pltfm_host->priv;
u32 ret;
- ret = in_be32(host->ioaddr + reg);
/*
* The bit of ADMA flag in eSDHC is not compatible with standard
* SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is
* supported by eSDHC.
* And for many FSL eSDHC controller, the reset value of field
- * SDHCI_CAN_DO_ADMA1 is one, but some of them can't support ADMA,
+ * SDHCI_CAN_DO_ADMA1 is 1, but some of them can't support ADMA,
* only these vendor version is greater than 2.2/0x12 support ADMA.
- * For FSL eSDHC, must aligned 4-byte, so use 0xFC to read the
- * the verdor version number, oxFE is SDHCI_HOST_VERSION.
*/
- if ((reg == SDHCI_CAPABILITIES) && (ret & SDHCI_CAN_DO_ADMA1)) {
- u32 tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
- tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
- if (tmp > VENDOR_V_22)
- ret |= SDHCI_CAN_DO_ADMA2;
+ if ((spec_reg == SDHCI_CAPABILITIES) && (value & SDHCI_CAN_DO_ADMA1)) {
+ if (esdhc->vendor_ver > VENDOR_V_22) {
+ ret = value | SDHCI_CAN_DO_ADMA2;
+ return ret;
+ }
}
-
+ ret = value;
return ret;
}
-static u16 esdhc_readw(struct sdhci_host *host, int reg)
+static u16 esdhc_readw_fixup(struct sdhci_host *host,
+ int spec_reg, u32 value)
{
u16 ret;
- int base = reg & ~0x3;
- int shift = (reg & 0x2) * 8;
+ int shift = (spec_reg & 0x2) * 8;
- if (unlikely(reg == SDHCI_HOST_VERSION))
- ret = in_be32(host->ioaddr + base) & 0xffff;
+ if (spec_reg == SDHCI_HOST_VERSION)
+ ret = value & 0xffff;
else
- ret = (in_be32(host->ioaddr + base) >> shift) & 0xffff;
+ ret = (value >> shift) & 0xffff;
return ret;
}
-static u8 esdhc_readb(struct sdhci_host *host, int reg)
+static u8 esdhc_readb_fixup(struct sdhci_host *host,
+ int spec_reg, u32 value)
{
- int base = reg & ~0x3;
- int shift = (reg & 0x3) * 8;
- u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff;
+ u8 ret;
+ u8 dma_bits;
+ int shift = (spec_reg & 0x3) * 8;
+
+ ret = (value >> shift) & 0xff;
/*
* "DMA select" locates at offset 0x28 in SD specification, but on
* P5020 or P3041, it locates at 0x29.
*/
- if (reg == SDHCI_HOST_CONTROL) {
- u32 dma_bits;
-
- dma_bits = in_be32(host->ioaddr + reg);
+ if (spec_reg == SDHCI_HOST_CONTROL) {
/* DMA select is 22,23 bits in Protocol Control Register */
- dma_bits = (dma_bits >> 5) & SDHCI_CTRL_DMA_MASK;
-
+ dma_bits = (value >> 5) & SDHCI_CTRL_DMA_MASK;
/* fixup the result */
ret &= ~SDHCI_CTRL_DMA_MASK;
ret |= dma_bits;
}
-
return ret;
}
-static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
+/**
+ * esdhc_write*_fixup - Fixup the SD spec register value so that it could be
+ * written into eSDHC register.
+ *
+ * @host: pointer to sdhci_host
+ * @spec_reg: SD spec register address
+ * @value: 8/16/32bit SD spec register value that would be written
+ * @old_value: 32bit eSDHC register value on spec_reg address
+ *
+ * In SD spec, there are 8/16/32/64 bits registers, while all of eSDHC
+ * registers are 32 bits. There are differences in register size, register
+ * address, register function, bit position and function between eSDHC spec
+ * and SD spec.
+ *
+ * Return a fixed up register value
+ */
+static u32 esdhc_writel_fixup(struct sdhci_host *host,
+ int spec_reg, u32 value, u32 old_value)
{
+ u32 ret;
+
/*
- * Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
- * when SYSCTL[RSTD]) is set for some special operations.
- * No any impact other operation.
+ * Enabling IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
+ * when SYSCTL[RSTD] is set for some special operations.
+ * No any impact on other operation.
*/
- if (reg == SDHCI_INT_ENABLE)
- val |= SDHCI_INT_BLK_GAP;
- sdhci_be32bs_writel(host, val, reg);
+ if (spec_reg == SDHCI_INT_ENABLE)
+ ret = value | SDHCI_INT_BLK_GAP;
+ else
+ ret = value;
+
+ return ret;
}
-static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
+static u32 esdhc_writew_fixup(struct sdhci_host *host,
+ int spec_reg, u16 value, u32 old_value)
{
- if (reg == SDHCI_BLOCK_SIZE) {
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ int shift = (spec_reg & 0x2) * 8;
+ u32 ret;
+
+ switch (spec_reg) {
+ case SDHCI_TRANSFER_MODE:
+ /*
+ * Postpone this write, we must do it together with a
+ * command write that is down below. Return old value.
+ */
+ pltfm_host->xfer_mode_shadow = value;
+ return old_value;
+ case SDHCI_COMMAND:
+ ret = (value << 16) | pltfm_host->xfer_mode_shadow;
+ return ret;
+ }
+
+ ret = old_value & (~(0xffff << shift));
+ ret |= (value << shift);
+
+ if (spec_reg == SDHCI_BLOCK_SIZE) {
/*
* Two last DMA bits are reserved, and first one is used for
* non-standard blksz of 4096 bytes that we don't support
* yet. So clear the DMA boundary bits.
*/
- val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+ ret &= (~SDHCI_MAKE_BLKSZ(0x7, 0));
}
- sdhci_be32bs_writew(host, val, reg);
+ return ret;
}
-static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
+static u32 esdhc_writeb_fixup(struct sdhci_host *host,
+ int spec_reg, u8 value, u32 old_value)
{
+ u32 ret;
+ u32 dma_bits;
+ u8 tmp;
+ int shift = (spec_reg & 0x3) * 8;
+
+ /*
+ * eSDHC doesn't have a standard power control register, so we do
+ * nothing here to avoid incorrect operation.
+ */
+ if (spec_reg == SDHCI_POWER_CONTROL)
+ return old_value;
/*
* "DMA select" location is offset 0x28 in SD specification, but on
* P5020 or P3041, it's located at 0x29.
*/
- if (reg == SDHCI_HOST_CONTROL) {
- u32 dma_bits;
-
+ if (spec_reg == SDHCI_HOST_CONTROL) {
/*
* If host control register is not standard, exit
* this function
*/
if (host->quirks2 & SDHCI_QUIRK2_BROKEN_HOST_CONTROL)
- return;
+ return old_value;
/* DMA select is 22,23 bits in Protocol Control Register */
- dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5;
- clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5,
- dma_bits);
- val &= ~SDHCI_CTRL_DMA_MASK;
- val |= in_be32(host->ioaddr + reg) & SDHCI_CTRL_DMA_MASK;
+ dma_bits = (value & SDHCI_CTRL_DMA_MASK) << 5;
+ ret = (old_value & (~(SDHCI_CTRL_DMA_MASK << 5))) | dma_bits;
+ tmp = (value & (~SDHCI_CTRL_DMA_MASK)) |
+ (old_value & SDHCI_CTRL_DMA_MASK);
+ ret = (ret & (~0xff)) | tmp;
+
+ /* Prevent SDHCI core from writing reserved bits (e.g. HISPD) */
+ ret &= ~ESDHC_HOST_CONTROL_RES;
+ return ret;
}
- /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
- if (reg == SDHCI_HOST_CONTROL)
- val &= ~ESDHC_HOST_CONTROL_RES;
- sdhci_be32bs_writeb(host, val, reg);
+ ret = (old_value & (~(0xff << shift))) | (value << shift);
+ return ret;
+}
+
+static u32 esdhc_be_readl(struct sdhci_host *host, int reg)
+{
+ u32 ret;
+ u32 value;
+
+ value = ioread32be(host->ioaddr + reg);
+ ret = esdhc_readl_fixup(host, reg, value);
+
+ return ret;
+}
+
+static u32 esdhc_le_readl(struct sdhci_host *host, int reg)
+{
+ u32 ret;
+ u32 value;
+
+ value = ioread32(host->ioaddr + reg);
+ ret = esdhc_readl_fixup(host, reg, value);
+
+ return ret;
+}
+
+static u16 esdhc_be_readw(struct sdhci_host *host, int reg)
+{
+ u16 ret;
+ u32 value;
+ int base = reg & ~0x3;
+
+ value = ioread32be(host->ioaddr + base);
+ ret = esdhc_readw_fixup(host, reg, value);
+ return ret;
+}
+
+static u16 esdhc_le_readw(struct sdhci_host *host, int reg)
+{
+ u16 ret;
+ u32 value;
+ int base = reg & ~0x3;
+
+ value = ioread32(host->ioaddr + base);
+ ret = esdhc_readw_fixup(host, reg, value);
+ return ret;
+}
+
+static u8 esdhc_be_readb(struct sdhci_host *host, int reg)
+{
+ u8 ret;
+ u32 value;
+ int base = reg & ~0x3;
+
+ value = ioread32be(host->ioaddr + base);
+ ret = esdhc_readb_fixup(host, reg, value);
+ return ret;
+}
+
+static u8 esdhc_le_readb(struct sdhci_host *host, int reg)
+{
+ u8 ret;
+ u32 value;
+ int base = reg & ~0x3;
+
+ value = ioread32(host->ioaddr + base);
+ ret = esdhc_readb_fixup(host, reg, value);
+ return ret;
+}
+
+static void esdhc_be_writel(struct sdhci_host *host, u32 val, int reg)
+{
+ u32 value;
+
+ value = esdhc_writel_fixup(host, reg, val, 0);
+ iowrite32be(value, host->ioaddr + reg);
+}
+
+static void esdhc_le_writel(struct sdhci_host *host, u32 val, int reg)
+{
+ u32 value;
+
+ value = esdhc_writel_fixup(host, reg, val, 0);
+ iowrite32(value, host->ioaddr + reg);
+}
+
+static void esdhc_be_writew(struct sdhci_host *host, u16 val, int reg)
+{
+ int base = reg & ~0x3;
+ u32 value;
+ u32 ret;
+
+ value = ioread32be(host->ioaddr + base);
+ ret = esdhc_writew_fixup(host, reg, val, value);
+ if (reg != SDHCI_TRANSFER_MODE)
+ iowrite32be(ret, host->ioaddr + base);
+}
+
+static void esdhc_le_writew(struct sdhci_host *host, u16 val, int reg)
+{
+ int base = reg & ~0x3;
+ u32 value;
+ u32 ret;
+
+ value = ioread32(host->ioaddr + base);
+ ret = esdhc_writew_fixup(host, reg, val, value);
+ if (reg != SDHCI_TRANSFER_MODE)
+ iowrite32(ret, host->ioaddr + base);
+}
+
+static void esdhc_be_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+ int base = reg & ~0x3;
+ u32 value;
+ u32 ret;
+
+ value = ioread32be(host->ioaddr + base);
+ ret = esdhc_writeb_fixup(host, reg, val, value);
+ iowrite32be(ret, host->ioaddr + base);
+}
+
+static void esdhc_le_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+ int base = reg & ~0x3;
+ u32 value;
+ u32 ret;
+
+ value = ioread32(host->ioaddr + base);
+ ret = esdhc_writeb_fixup(host, reg, val, value);
+ iowrite32(ret, host->ioaddr + base);
}
/*
@@ -149,19 +351,17 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
* For Continue, apply soft reset for data(SYSCTL[RSTD]);
* and re-issue the entire read transaction from beginning.
*/
-static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
+static void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask)
{
- u32 tmp;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = pltfm_host->priv;
bool applicable;
dma_addr_t dmastart;
dma_addr_t dmanow;
- tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
- tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
-
applicable = (intmask & SDHCI_INT_DATA_END) &&
- (intmask & SDHCI_INT_BLK_GAP) &&
- (tmp == VENDOR_V_23);
+ (intmask & SDHCI_INT_BLK_GAP) &&
+ (esdhc->vendor_ver == VENDOR_V_23);
if (!applicable)
return;
@@ -179,7 +379,11 @@ static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
static int esdhc_of_enable_dma(struct sdhci_host *host)
{
- setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
+ u32 value;
+
+ value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+ value |= ESDHC_DMA_SNOOP;
+ sdhci_writel(host, value, ESDHC_DMA_SYSCTL);
return 0;
}
@@ -199,6 +403,8 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = pltfm_host->priv;
int pre_div = 1;
int div = 1;
u32 temp;
@@ -209,9 +415,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
return;
/* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
- temp = esdhc_readw(host, SDHCI_HOST_VERSION);
- temp = (temp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
- if (temp < VENDOR_V_23)
+ if (esdhc->vendor_ver < VENDOR_V_23)
pre_div = 2;
/* Workaround to reduce the clock frequency for p1010 esdhc */
@@ -247,39 +451,26 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
mdelay(1);
}
-static void esdhc_of_platform_init(struct sdhci_host *host)
-{
- u32 vvn;
-
- vvn = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
- vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
- if (vvn == VENDOR_V_22)
- host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
-
- if (vvn > VENDOR_V_22)
- host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
-}
-
static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
{
u32 ctrl;
+ ctrl = sdhci_readl(host, ESDHC_PROCTL);
+ ctrl &= (~ESDHC_CTRL_BUSWIDTH_MASK);
switch (width) {
case MMC_BUS_WIDTH_8:
- ctrl = ESDHC_CTRL_8BITBUS;
+ ctrl |= ESDHC_CTRL_8BITBUS;
break;
case MMC_BUS_WIDTH_4:
- ctrl = ESDHC_CTRL_4BITBUS;
+ ctrl |= ESDHC_CTRL_4BITBUS;
break;
default:
- ctrl = 0;
break;
}
- clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL,
- ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
+ sdhci_writel(host, ctrl, ESDHC_PROCTL);
}
static void esdhc_reset(struct sdhci_host *host, u8 mask)
@@ -290,32 +481,13 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
-static const struct sdhci_ops sdhci_esdhc_ops = {
- .read_l = esdhc_readl,
- .read_w = esdhc_readw,
- .read_b = esdhc_readb,
- .write_l = esdhc_writel,
- .write_w = esdhc_writew,
- .write_b = esdhc_writeb,
- .set_clock = esdhc_of_set_clock,
- .enable_dma = esdhc_of_enable_dma,
- .get_max_clock = esdhc_of_get_max_clock,
- .get_min_clock = esdhc_of_get_min_clock,
- .platform_init = esdhc_of_platform_init,
- .adma_workaround = esdhci_of_adma_workaround,
- .set_bus_width = esdhc_pltfm_set_bus_width,
- .reset = esdhc_reset,
- .set_uhs_signaling = sdhci_set_uhs_signaling,
-};
-
#ifdef CONFIG_PM
-
static u32 esdhc_proctl;
static int esdhc_of_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
- esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
+ esdhc_proctl = sdhci_readl(host, SDHCI_HOST_CONTROL);
return sdhci_suspend_host(host);
}
@@ -328,9 +500,8 @@ static int esdhc_of_resume(struct device *dev)
if (ret == 0) {
/* Isn't this already done by sdhci_resume_host() ? --rmk */
esdhc_of_enable_dma(host);
- sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
+ sdhci_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
}
-
return ret;
}
@@ -343,37 +514,103 @@ static const struct dev_pm_ops esdhc_pmops = {
#define ESDHC_PMOPS NULL
#endif
-static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
- /*
- * card detection could be handled via GPIO
- * eSDHC cannot support End Attribute in NOP ADMA descriptor
- */
+static const struct sdhci_ops sdhci_esdhc_be_ops = {
+ .read_l = esdhc_be_readl,
+ .read_w = esdhc_be_readw,
+ .read_b = esdhc_be_readb,
+ .write_l = esdhc_be_writel,
+ .write_w = esdhc_be_writew,
+ .write_b = esdhc_be_writeb,
+ .set_clock = esdhc_of_set_clock,
+ .enable_dma = esdhc_of_enable_dma,
+ .get_max_clock = esdhc_of_get_max_clock,
+ .get_min_clock = esdhc_of_get_min_clock,
+ .adma_workaround = esdhc_of_adma_workaround,
+ .set_bus_width = esdhc_pltfm_set_bus_width,
+ .reset = esdhc_reset,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static const struct sdhci_ops sdhci_esdhc_le_ops = {
+ .read_l = esdhc_le_readl,
+ .read_w = esdhc_le_readw,
+ .read_b = esdhc_le_readb,
+ .write_l = esdhc_le_writel,
+ .write_w = esdhc_le_writew,
+ .write_b = esdhc_le_writeb,
+ .set_clock = esdhc_of_set_clock,
+ .enable_dma = esdhc_of_enable_dma,
+ .get_max_clock = esdhc_of_get_max_clock,
+ .get_min_clock = esdhc_of_get_min_clock,
+ .adma_workaround = esdhc_of_adma_workaround,
+ .set_bus_width = esdhc_pltfm_set_bus_width,
+ .reset = esdhc_reset,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = {
.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
| SDHCI_QUIRK_NO_CARD_NO_RESET
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
- .ops = &sdhci_esdhc_ops,
+ .ops = &sdhci_esdhc_be_ops,
};
+static const struct sdhci_pltfm_data sdhci_esdhc_le_pdata = {
+ .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
+ | SDHCI_QUIRK_NO_CARD_NO_RESET
+ | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+ .ops = &sdhci_esdhc_le_ops,
+};
+
+static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host;
+ struct sdhci_esdhc *esdhc;
+ u16 host_ver;
+
+ pltfm_host = sdhci_priv(host);
+ esdhc = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_esdhc),
+ GFP_KERNEL);
+
+ host_ver = sdhci_readw(host, SDHCI_HOST_VERSION);
+ esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >>
+ SDHCI_VENDOR_VER_SHIFT;
+ esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK;
+
+ pltfm_host->priv = esdhc;
+}
+
static int sdhci_esdhc_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct device_node *np;
int ret;
- host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0);
+ np = pdev->dev.of_node;
+
+ if (of_get_property(np, "little-endian", NULL))
+ host = sdhci_pltfm_init(pdev, &sdhci_esdhc_le_pdata, 0);
+ else
+ host = sdhci_pltfm_init(pdev, &sdhci_esdhc_be_pdata, 0);
+
if (IS_ERR(host))
return PTR_ERR(host);
+ esdhc_init(pdev, host);
+
sdhci_get_of_property(pdev);
- np = pdev->dev.of_node;
if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
of_device_is_compatible(np, "fsl,p5020-esdhc") ||
of_device_is_compatible(np, "fsl,p4080-esdhc") ||
of_device_is_compatible(np, "fsl,p1020-esdhc") ||
- of_device_is_compatible(np, "fsl,t1040-esdhc"))
+ of_device_is_compatible(np, "fsl,t1040-esdhc") ||
+ of_device_is_compatible(np, "fsl,ls1021a-esdhc"))
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+ if (of_device_is_compatible(np, "fsl,ls1021a-esdhc"))
+ host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+
if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
/*
* Freescale messed up with P2020 as it has a non-standard
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci-core.c
index b3b0a3e4fca1..cf7ad458b4f4 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -444,11 +444,7 @@ static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
else
scratch &= ~0x47;
- ret = pci_write_config_byte(chip->pdev, 0xAE, scratch);
- if (ret)
- return ret;
-
- return 0;
+ return pci_write_config_byte(chip->pdev, 0xAE, scratch);
}
static int jmicron_probe(struct sdhci_pci_chip *chip)
@@ -1113,6 +1109,62 @@ static const struct pci_device_id pci_ids[] = {
},
{
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_DNV_EMMC,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_BXT_EMMC,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_BXT_SDIO,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_BXT_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_APL_EMMC,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_APL_SDIO,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_APL_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
+ },
+
+ {
.vendor = PCI_VENDOR_ID_O2,
.device = PCI_DEVICE_ID_O2_8120,
.subvendor = PCI_ANY_ID,
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c
index e2ec108dba0e..d48f03104b5b 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -60,7 +60,7 @@ static void o2_pci_led_enable(struct sdhci_pci_chip *chip)
}
-void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
+static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
{
u32 scratch_32;
int ret;
@@ -145,7 +145,6 @@ void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
scratch_32 |= 0x00080000;
pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL4, scratch_32);
}
-EXPORT_SYMBOL_GPL(sdhci_pci_o2_fujin2_pci_init);
int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
{
@@ -179,7 +178,6 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
return 0;
}
-EXPORT_SYMBOL_GPL(sdhci_pci_o2_probe_slot);
int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
{
@@ -385,11 +383,9 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
return 0;
}
-EXPORT_SYMBOL_GPL(sdhci_pci_o2_probe);
int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip)
{
sdhci_pci_o2_probe(chip);
return 0;
}
-EXPORT_SYMBOL_GPL(sdhci_pci_o2_resume);
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.h b/drivers/mmc/host/sdhci-pci-o2micro.h
index f7ffc908d9a0..770f53857211 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.h
+++ b/drivers/mmc/host/sdhci-pci-o2micro.h
@@ -64,8 +64,6 @@
#define O2_SD_VENDOR_SETTING 0x110
#define O2_SD_VENDOR_SETTING2 0x1C8
-extern void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip);
-
extern int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot);
extern int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip);
diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
index 541f1cad5247..d1a0b4db60db 100644
--- a/drivers/mmc/host/sdhci-pci.h
+++ b/drivers/mmc/host/sdhci-pci.h
@@ -24,6 +24,13 @@
#define PCI_DEVICE_ID_INTEL_SPT_EMMC 0x9d2b
#define PCI_DEVICE_ID_INTEL_SPT_SDIO 0x9d2c
#define PCI_DEVICE_ID_INTEL_SPT_SD 0x9d2d
+#define PCI_DEVICE_ID_INTEL_DNV_EMMC 0x19db
+#define PCI_DEVICE_ID_INTEL_BXT_SD 0x0aca
+#define PCI_DEVICE_ID_INTEL_BXT_EMMC 0x0acc
+#define PCI_DEVICE_ID_INTEL_BXT_SDIO 0x0ad0
+#define PCI_DEVICE_ID_INTEL_APL_SD 0x5aca
+#define PCI_DEVICE_ID_INTEL_APL_EMMC 0x5acc
+#define PCI_DEVICE_ID_INTEL_APL_SDIO 0x5ad0
/*
* PCI registers
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index a207f5aaf62f..87fb5ea8ebe7 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -71,9 +71,7 @@ void sdhci_get_of_property(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- const __be32 *clk;
u32 bus_width;
- int size;
if (of_get_property(np, "sdhci,auto-cmd12", NULL))
host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
@@ -101,9 +99,7 @@ void sdhci_get_of_property(struct platform_device *pdev)
of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
- clk = of_get_property(np, "clock-frequency", &size);
- if (clk && size == sizeof(*clk) && *clk)
- pltfm_host->clock = be32_to_cpup(clk);
+ of_property_read_u32(np, "clock-frequency", &pltfm_host->clock);
if (of_find_property(np, "keep-power-in-suspend", NULL))
host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
index 884294576356..34866f668dd7 100644
--- a/drivers/mmc/host/sdhci-sirf.c
+++ b/drivers/mmc/host/sdhci-sirf.c
@@ -50,7 +50,8 @@ static u32 sdhci_sirf_readl_le(struct sdhci_host *host, int reg)
if (unlikely((reg == SDHCI_CAPABILITIES_1) &&
(host->mmc->caps & MMC_CAP_UHS_SDR50))) {
/* fake CAP_1 register */
- val = SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING;
+ val = SDHCI_SUPPORT_DDR50 |
+ SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING;
}
if (unlikely(reg == SDHCI_SLOT_INT_STATUS)) {
@@ -97,7 +98,7 @@ retry:
clock_setting | phase,
SDHCI_CLK_DELAY_SETTING);
- if (!mmc_send_tuning(mmc)) {
+ if (!mmc_send_tuning(mmc, opcode, NULL)) {
/* Tuning is successful at this tuning point */
tuned_phase_cnt++;
dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index fbc7efdddcb5..b48565ed5616 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1895,9 +1895,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
tuning_count = host->tuning_count;
/*
- * The Host Controller needs tuning only in case of SDR104 mode
- * and for SDR50 mode when Use Tuning for SDR50 is set in the
- * Capabilities register.
+ * The Host Controller needs tuning in case of SDR104 and DDR50
+ * mode, and for SDR50 mode when Use Tuning for SDR50 is set in
+ * the Capabilities register.
* If the Host Controller supports the HS200 mode then the
* tuning function has to be executed.
*/
@@ -1917,6 +1917,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
break;
case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_UHS_DDR50:
break;
case MMC_TIMING_UHS_SDR50:
@@ -2716,17 +2717,6 @@ int sdhci_resume_host(struct sdhci_host *host)
host->ops->enable_dma(host);
}
- if (!device_may_wakeup(mmc_dev(host->mmc))) {
- ret = request_threaded_irq(host->irq, sdhci_irq,
- sdhci_thread_irq, IRQF_SHARED,
- mmc_hostname(host->mmc), host);
- if (ret)
- return ret;
- } else {
- sdhci_disable_irq_wakeups(host);
- disable_irq_wake(host->irq);
- }
-
if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) &&
(host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) {
/* Card keeps power but host controller does not */
@@ -2739,6 +2729,17 @@ int sdhci_resume_host(struct sdhci_host *host)
mmiowb();
}
+ if (!device_may_wakeup(mmc_dev(host->mmc))) {
+ ret = request_threaded_irq(host->irq, sdhci_irq,
+ sdhci_thread_irq, IRQF_SHARED,
+ mmc_hostname(host->mmc), host);
+ if (ret)
+ return ret;
+ } else {
+ sdhci_disable_irq_wakeups(host);
+ disable_irq_wake(host->irq);
+ }
+
sdhci_enable_card_detection(host);
return ret;
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index b981b8552e43..83de82bceafc 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -873,6 +873,13 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
spin_unlock_irqrestore(&host->lock, iflags);
}
+static int sunxi_mmc_card_busy(struct mmc_host *mmc)
+{
+ struct sunxi_mmc_host *host = mmc_priv(mmc);
+
+ return !!(mmc_readl(host, REG_STAS) & SDXC_CARD_DATA_BUSY);
+}
+
static const struct of_device_id sunxi_mmc_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-mmc", },
{ .compatible = "allwinner,sun5i-a13-mmc", },
@@ -888,6 +895,7 @@ static struct mmc_host_ops sunxi_mmc_ops = {
.get_cd = mmc_gpio_get_cd,
.enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
.hw_reset = sunxi_mmc_hw_reset,
+ .card_busy = sunxi_mmc_card_busy,
};
static const struct sunxi_mmc_clk_delay sunxi_mmc_clk_delays[] = {
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index fbabbb82b354..1e819f98b94f 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -563,7 +563,7 @@ static void add_offloaded_reg(struct vub300_mmc_host *vub300,
i += 1;
continue;
}
- };
+ }
__add_offloaded_reg_to_fifo(vub300, register_access, func);
}
@@ -1372,7 +1372,7 @@ static void download_offload_pseudocode(struct vub300_mmc_host *vub300)
l += snprintf(vub300->vub_name + l,
sizeof(vub300->vub_name) - l, "_%04X%04X",
sf->vendor, sf->device);
- };
+ }
snprintf(vub300->vub_name + l, sizeof(vub300->vub_name) - l, ".bin");
dev_info(&vub300->udev->dev, "requesting offload firmware %s\n",
vub300->vub_name);
@@ -1893,7 +1893,7 @@ static int satisfy_request_from_offloaded_data(struct vub300_mmc_host *vub300,
i += 1;
continue;
}
- };
+ }
if (vub300->total_offload_count == 0)
return 0;
else if (vub300->fn[func].offload_count == 0)
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c
index ca183ea767b3..c3fd16d997ca 100644
--- a/drivers/mmc/host/wbsd.c
+++ b/drivers/mmc/host/wbsd.c
@@ -809,7 +809,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
cmd->error = -EINVAL;
goto done;
- };
+ }
}
/*