summaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/block.c34
-rw-r--r--drivers/mmc/core/card.h1
-rw-r--r--drivers/mmc/core/core.c5
-rw-r--r--drivers/mmc/core/debugfs.c19
-rw-r--r--drivers/mmc/core/host.h3
-rw-r--r--drivers/mmc/core/mmc.c2
-rw-r--r--drivers/mmc/core/mmc_ops.c4
-rw-r--r--drivers/mmc/core/quirks.h6
-rw-r--r--drivers/mmc/core/sd.c20
-rw-r--r--drivers/mmc/core/sdio.c9
-rw-r--r--drivers/mmc/core/sdio_irq.c4
-rw-r--r--drivers/mmc/core/slot-gpio.c23
-rw-r--r--drivers/mmc/host/Kconfig28
-rw-r--r--drivers/mmc/host/Makefile2
-rw-r--r--drivers/mmc/host/bfin_sdh.c679
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c9
-rw-r--r--drivers/mmc/host/dw_mmc-hi3798cv200.c202
-rw-r--r--drivers/mmc/host/dw_mmc-k3.c4
-rw-r--r--drivers/mmc/host/dw_mmc-pci.c1
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c5
-rw-r--r--drivers/mmc/host/dw_mmc-zx.c1
-rw-r--r--drivers/mmc/host/dw_mmc.c145
-rw-r--r--drivers/mmc/host/dw_mmc.h29
-rw-r--r--drivers/mmc/host/mtk-sd.c12
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c6
-rw-r--r--drivers/mmc/host/renesas_sdhi_internal_dmac.c11
-rw-r--r--drivers/mmc/host/renesas_sdhi_sys_dmac.c17
-rw-r--r--drivers/mmc/host/sdhci-acpi.c2
-rw-r--r--drivers/mmc/host/sdhci-iproc.c1
-rw-r--r--drivers/mmc/host/sdhci-omap.c378
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c78
-rw-r--r--drivers/mmc/host/sdhci.c19
-rw-r--r--drivers/mmc/host/sh_mmcif.c8
-rw-r--r--drivers/mmc/host/sunxi-mmc.c144
-rw-r--r--drivers/mmc/host/tmio_mmc_core.c66
-rw-r--r--drivers/mmc/host/ushc.c2
36 files changed, 979 insertions, 1000 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index c895bb0d5569..02485e310c81 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -72,6 +72,7 @@ MODULE_ALIAS("mmc:block");
#define MMC_BLK_TIMEOUT_MS (10 * 1000)
#define MMC_SANITIZE_REQ_TIMEOUT 240000
#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
+#define MMC_EXTRACT_VALUE_FROM_ARG(x) ((x & 0x0000FF00) >> 8)
#define mmc_req_rel_wr(req) ((req->cmd_flags & REQ_FUA) && \
(rq_data_dir(req) == WRITE))
@@ -375,22 +376,15 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
return idata;
}
- idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL);
- if (!idata->buf) {
- err = -ENOMEM;
+ idata->buf = memdup_user((void __user *)(unsigned long)
+ idata->ic.data_ptr, idata->buf_bytes);
+ if (IS_ERR(idata->buf)) {
+ err = PTR_ERR(idata->buf);
goto idata_err;
}
- if (copy_from_user(idata->buf, (void __user *)(unsigned long)
- idata->ic.data_ptr, idata->buf_bytes)) {
- err = -EFAULT;
- goto copy_err;
- }
-
return idata;
-copy_err:
- kfree(idata->buf);
idata_err:
kfree(idata);
out:
@@ -587,6 +581,24 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
}
/*
+ * Make sure the cache of the PARTITION_CONFIG register and
+ * PARTITION_ACCESS bits is updated in case the ioctl ext_csd write
+ * changed it successfully.
+ */
+ if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_PART_CONFIG) &&
+ (cmd.opcode == MMC_SWITCH)) {
+ struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
+ u8 value = MMC_EXTRACT_VALUE_FROM_ARG(cmd.arg);
+
+ /*
+ * Update cache so the next mmc_blk_part_switch call operates
+ * on up-to-date data.
+ */
+ card->ext_csd.part_config = value;
+ main_md->part_curr = value & EXT_CSD_PART_CONFIG_ACC_MASK;
+ }
+
+ /*
* According to the SD specs, some commands require a delay after
* issuing the command.
*/
diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
index 79a5b985ccf5..9c821eedd156 100644
--- a/drivers/mmc/core/card.h
+++ b/drivers/mmc/core/card.h
@@ -82,6 +82,7 @@ struct mmc_fixup {
#define CID_MANFID_APACER 0x27
#define CID_MANFID_KINGSTON 0x70
#define CID_MANFID_HYNIX 0x90
+#define CID_MANFID_NUMONYX 0xFE
#define END_FIXUP { NULL }
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c0ba6d8823b7..121ce50b6d5e 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2369,7 +2369,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
return card->pref_erase;
max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
- if (mmc_can_trim(card)) {
+ if (max_discard && mmc_can_trim(card)) {
max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG);
if (max_trim < max_discard)
max_discard = max_trim;
@@ -2655,8 +2655,7 @@ void mmc_start_host(struct mmc_host *host)
void mmc_stop_host(struct mmc_host *host)
{
if (host->slot.cd_irq >= 0) {
- if (host->slot.cd_wake_enabled)
- disable_irq_wake(host->slot.cd_irq);
+ mmc_gpio_set_cd_wake(host, false);
disable_irq(host->slot.cd_irq);
}
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 0f4a7d7b2626..d2275c5a2311 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -196,18 +196,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
return 0;
}
-
-static int mmc_ios_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mmc_ios_show, inode->i_private);
-}
-
-static const struct file_operations mmc_ios_fops = {
- .open = mmc_ios_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mmc_ios);
static int mmc_clock_opt_get(void *data, u64 *val)
{
@@ -254,6 +243,12 @@ void mmc_add_host_debugfs(struct mmc_host *host)
if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
goto err_node;
+ if (!debugfs_create_x32("caps", S_IRUSR, root, &host->caps))
+ goto err_node;
+
+ if (!debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2))
+ goto err_node;
+
if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
&mmc_clock_fops))
goto err_node;
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 06ec19b5bf9f..4805438c02ff 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -56,7 +56,8 @@ static inline int mmc_host_uhs(struct mmc_host *host)
return host->caps &
(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50);
+ MMC_CAP_UHS_DDR50) &&
+ host->caps & MMC_CAP_4_BIT_DATA;
}
static inline bool mmc_card_hs200(struct mmc_card *card)
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 208a762b87ef..6f8ebd6caa4c 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -792,6 +792,7 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
+MMC_DEV_ATTR(rca, "0x%04x\n", card->rca);
MMC_DEV_ATTR(cmdq_en, "%d\n", card->ext_csd.cmdq_en);
static ssize_t mmc_fwrev_show(struct device *dev,
@@ -848,6 +849,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_raw_rpmb_size_mult.attr,
&dev_attr_rel_sectors.attr,
&dev_attr_ocr.attr,
+ &dev_attr_rca.attr,
&dev_attr_dsr.attr,
&dev_attr_cmdq_en.attr,
NULL,
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 908e4db03535..42d6aa89a48a 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -848,7 +848,6 @@ int mmc_interrupt_hpi(struct mmc_card *card)
return 1;
}
- mmc_claim_host(card->host);
err = mmc_send_status(card, &status);
if (err) {
pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
@@ -890,7 +889,6 @@ int mmc_interrupt_hpi(struct mmc_card *card)
} while (!err);
out:
- mmc_release_host(card->host);
return err;
}
@@ -932,9 +930,7 @@ static int mmc_read_bkops_status(struct mmc_card *card)
int err;
u8 *ext_csd;
- mmc_claim_host(card->host);
err = mmc_get_ext_csd(card, &ext_csd);
- mmc_release_host(card->host);
if (err)
return err;
diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
index 75d317623852..5153577754f0 100644
--- a/drivers/mmc/core/quirks.h
+++ b/drivers/mmc/core/quirks.h
@@ -109,6 +109,12 @@ static const struct mmc_fixup mmc_ext_csd_fixups[] = {
*/
MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
+ /*
+ * Certain Micron (Numonyx) eMMC 4.5 cards might get broken when HPI
+ * feature is used so disable the HPI feature for such buggy cards.
+ */
+ MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_NUMONYX,
+ 0x014e, add_quirk, MMC_QUIRK_BROKEN_HPI, 6),
END_FIXUP
};
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 62b84dd8f9fe..baf3d5da4ccb 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -291,8 +291,6 @@ static int mmc_read_switch(struct mmc_card *card)
return 0;
}
- err = -EIO;
-
status = kmalloc(64, GFP_KERNEL);
if (!status)
return -ENOMEM;
@@ -582,9 +580,6 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
int err;
u8 *status;
- if (!card->scr.sda_spec3)
- return 0;
-
if (!(card->csd.cmdclass & CCC_SWITCH))
return 0;
@@ -593,14 +588,11 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
return -ENOMEM;
/* Set 4-bit bus width */
- if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
- err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err)
- goto out;
+ err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+ if (err)
+ goto out;
- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
- }
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
/*
* Select the bus speed mode depending on host
@@ -676,6 +668,7 @@ MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
+MMC_DEV_ATTR(rca, "0x%04x\n", card->rca);
static ssize_t mmc_dsr_show(struct device *dev,
@@ -709,6 +702,7 @@ static struct attribute *sd_std_attrs[] = {
&dev_attr_oemid.attr,
&dev_attr_serial.attr,
&dev_attr_ocr.attr,
+ &dev_attr_rca.attr,
&dev_attr_dsr.attr,
NULL,
};
@@ -1033,7 +1027,7 @@ retry:
}
/* Initialization sequence for UHS-I cards */
- if (rocr & SD_ROCR_S18A) {
+ if (rocr & SD_ROCR_S18A && mmc_host_uhs(host)) {
err = mmc_sd_init_uhs_card(card);
if (err)
goto free_card;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index cc43687ca241..c599a628a387 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -518,11 +518,10 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
if (!card->scr.sda_spec3)
return 0;
- /*
- * Switch to wider bus (if supported).
- */
- if (card->host->caps & MMC_CAP_4_BIT_DATA)
- err = sdio_enable_4bit_bus(card);
+ /* Switch to wider bus */
+ err = sdio_enable_4bit_bus(card);
+ if (err)
+ goto out;
/* Set the driver strength for the card */
sdio_select_driver_type(card);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 7a2eaf8410a3..7ca7b99413f0 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -277,8 +277,8 @@ static void sdio_single_irq_set(struct mmc_card *card)
*
* Claim and activate the IRQ for the given SDIO function. The provided
* handler will be called when that IRQ is asserted. The host is always
- * claimed already when the handler is called so the handler must not
- * call sdio_claim_host() nor sdio_release_host().
+ * claimed already when the handler is called so the handler should not
+ * call sdio_claim_host() or sdio_release_host().
*/
int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
{
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 3698b0576009..31f7dbb15668 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -149,11 +149,30 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host)
if (irq < 0)
host->caps |= MMC_CAP_NEEDS_POLL;
- else if ((host->caps & MMC_CAP_CD_WAKE) && !enable_irq_wake(irq))
- host->slot.cd_wake_enabled = true;
}
EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
+int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on)
+{
+ int ret = 0;
+
+ if (!(host->caps & MMC_CAP_CD_WAKE) ||
+ host->slot.cd_irq < 0 ||
+ on == host->slot.cd_wake_enabled)
+ return 0;
+
+ if (on) {
+ ret = enable_irq_wake(host->slot.cd_irq);
+ host->slot.cd_wake_enabled = !ret;
+ } else {
+ disable_irq_wake(host->slot.cd_irq);
+ host->slot.cd_wake_enabled = false;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(mmc_gpio_set_cd_wake);
+
/* Register an alternate interrupt service routine for
* the card-detect GPIO.
*/
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 620c2d90a646..9589f9c9046f 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -646,25 +646,6 @@ config MMC_VIA_SDMMC
If unsure, say N.
-config SDH_BFIN
- tristate "Blackfin Secure Digital Host support"
- depends on (BF54x && !BF544) || (BF51x && !BF512)
- help
- If you say yes here you will get support for the Blackfin on-chip
- Secure Digital Host interface. This includes support for MMC and
- SD cards.
-
- To compile this driver as a module, choose M here: the
- module will be called bfin_sdh.
-
- If unsure, say N.
-
-config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
- bool "Blackfin EZkit Missing SDH_CMD Pull Up Resistor Workaround"
- depends on SDH_BFIN
- help
- If you say yes here SD-Cards may work on the EZkit.
-
config MMC_CAVIUM_OCTEON
tristate "Cavium OCTEON SD/MMC Card Interface support"
depends on CAVIUM_OCTEON_SOC
@@ -718,6 +699,15 @@ config MMC_DW_EXYNOS
Synopsys DesignWare Memory Card Interface driver. Select this option
for platforms based on Exynos4 and Exynos5 SoC's.
+config MMC_DW_HI3798CV200
+ tristate "Hi3798CV200 specific extensions for Synopsys DW Memory Card Interface"
+ depends on MMC_DW
+ select MMC_DW_PLTFM
+ help
+ This selects support for HiSilicon Hi3798CV200 SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on HiSilicon Hi3798CV200 SoC.
+
config MMC_DW_K3
tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
depends on MMC_DW
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 84cd1388abc3..6aead24879b4 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -43,7 +43,6 @@ obj-$(CONFIG_MMC_SDHI_SYS_DMAC) += renesas_sdhi_sys_dmac.o
obj-$(CONFIG_MMC_SDHI_INTERNAL_DMAC) += renesas_sdhi_internal_dmac.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
-obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
octeon-mmc-objs := cavium.o cavium-octeon.o
obj-$(CONFIG_MMC_CAVIUM_OCTEON) += octeon-mmc.o
thunderx-mmc-objs := cavium.o cavium-thunderx.o
@@ -51,6 +50,7 @@ obj-$(CONFIG_MMC_CAVIUM_THUNDERX) += thunderx-mmc.o
obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
+obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_mmc-hi3798cv200.o
obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o
diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c
deleted file mode 100644
index 526231e38583..000000000000
--- a/drivers/mmc/host/bfin_sdh.c
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * bfin_sdh.c - Analog Devices Blackfin SDH Controller
- *
- * Copyright (C) 2007-2009 Analog Device Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#define DRIVER_NAME "bfin-sdh"
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/mmc/host.h>
-#include <linux/proc_fs.h>
-#include <linux/gfp.h>
-
-#include <asm/cacheflush.h>
-#include <asm/dma.h>
-#include <asm/portmux.h>
-#include <asm/bfin_sdh.h>
-
-#if defined(CONFIG_BF51x) || defined(__ADSPBF60x__)
-#define bfin_read_SDH_CLK_CTL bfin_read_RSI_CLK_CTL
-#define bfin_write_SDH_CLK_CTL bfin_write_RSI_CLK_CTL
-#define bfin_write_SDH_ARGUMENT bfin_write_RSI_ARGUMENT
-#define bfin_write_SDH_COMMAND bfin_write_RSI_COMMAND
-#define bfin_write_SDH_DATA_TIMER bfin_write_RSI_DATA_TIMER
-#define bfin_read_SDH_RESPONSE0 bfin_read_RSI_RESPONSE0
-#define bfin_read_SDH_RESPONSE1 bfin_read_RSI_RESPONSE1
-#define bfin_read_SDH_RESPONSE2 bfin_read_RSI_RESPONSE2
-#define bfin_read_SDH_RESPONSE3 bfin_read_RSI_RESPONSE3
-#define bfin_write_SDH_DATA_LGTH bfin_write_RSI_DATA_LGTH
-#define bfin_read_SDH_DATA_CTL bfin_read_RSI_DATA_CTL
-#define bfin_write_SDH_DATA_CTL bfin_write_RSI_DATA_CTL
-#define bfin_read_SDH_DATA_CNT bfin_read_RSI_DATA_CNT
-#define bfin_write_SDH_STATUS_CLR bfin_write_RSI_STATUS_CLR
-#define bfin_read_SDH_E_STATUS bfin_read_RSI_E_STATUS
-#define bfin_write_SDH_E_STATUS bfin_write_RSI_E_STATUS
-#define bfin_read_SDH_STATUS bfin_read_RSI_STATUS
-#define bfin_write_SDH_MASK0 bfin_write_RSI_MASK0
-#define bfin_write_SDH_E_MASK bfin_write_RSI_E_MASK
-#define bfin_read_SDH_CFG bfin_read_RSI_CFG
-#define bfin_write_SDH_CFG bfin_write_RSI_CFG
-# if defined(__ADSPBF60x__)
-# define bfin_read_SDH_BLK_SIZE bfin_read_RSI_BLKSZ
-# define bfin_write_SDH_BLK_SIZE bfin_write_RSI_BLKSZ
-# else
-# define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CTL
-# define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CTL
-# endif
-#endif
-
-struct sdh_host {
- struct mmc_host *mmc;
- spinlock_t lock;
- struct resource *res;
- void __iomem *base;
- int irq;
- int stat_irq;
- int dma_ch;
- int dma_dir;
- struct dma_desc_array *sg_cpu;
- dma_addr_t sg_dma;
- int dma_len;
-
- unsigned long sclk;
- unsigned int imask;
- unsigned int power_mode;
- unsigned int clk_div;
-
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
-};
-
-static struct bfin_sd_host *get_sdh_data(struct platform_device *pdev)
-{
- return pdev->dev.platform_data;
-}
-
-static void sdh_stop_clock(struct sdh_host *host)
-{
- bfin_write_SDH_CLK_CTL(bfin_read_SDH_CLK_CTL() & ~CLK_E);
- SSYNC();
-}
-
-static void sdh_enable_stat_irq(struct sdh_host *host, unsigned int mask)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->imask |= mask;
- bfin_write_SDH_MASK0(mask);
- SSYNC();
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sdh_disable_stat_irq(struct sdh_host *host, unsigned int mask)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->imask &= ~mask;
- bfin_write_SDH_MASK0(host->imask);
- SSYNC();
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
-{
- unsigned int length;
- unsigned int data_ctl;
- unsigned int dma_cfg;
- unsigned int cycle_ns, timeout;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter flags: 0x%x\n", __func__, data->flags);
- host->data = data;
- data_ctl = 0;
- dma_cfg = 0;
-
- length = data->blksz * data->blocks;
- bfin_write_SDH_DATA_LGTH(length);
-
- if (data->flags & MMC_DATA_READ)
- data_ctl |= DTX_DIR;
- /* Only supports power-of-2 block size */
- if (data->blksz & (data->blksz - 1))
- return -EINVAL;
-#ifndef RSI_BLKSZ
- data_ctl |= ((ffs(data->blksz) - 1) << 4);
-#else
- bfin_write_SDH_BLK_SIZE(data->blksz);
-#endif
-
- bfin_write_SDH_DATA_CTL(data_ctl);
- /* the time of a host clock period in ns */
- cycle_ns = 1000000000 / (host->sclk / (2 * (host->clk_div + 1)));
- timeout = data->timeout_ns / cycle_ns;
- timeout += data->timeout_clks;
- bfin_write_SDH_DATA_TIMER(timeout);
- SSYNC();
-
- if (data->flags & MMC_DATA_READ) {
- host->dma_dir = DMA_FROM_DEVICE;
- dma_cfg |= WNR;
- } else
- host->dma_dir = DMA_TO_DEVICE;
-
- sdh_enable_stat_irq(host, (DAT_CRC_FAIL | DAT_TIME_OUT | DAT_END));
- host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma_dir);
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
- dma_cfg |= DMAFLOW_ARRAY | RESTART | WDSIZE_32 | DMAEN;
-# ifdef RSI_BLKSZ
- dma_cfg |= PSIZE_32 | NDSIZE_3;
-# else
- dma_cfg |= NDSIZE_5;
-# endif
- {
- struct scatterlist *sg;
- int i;
- for_each_sg(data->sg, sg, host->dma_len, i) {
- host->sg_cpu[i].start_addr = sg_dma_address(sg);
- host->sg_cpu[i].cfg = dma_cfg;
- host->sg_cpu[i].x_count = sg_dma_len(sg) / 4;
- host->sg_cpu[i].x_modify = 4;
- dev_dbg(mmc_dev(host->mmc), "%d: start_addr:0x%lx, "
- "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
- i, host->sg_cpu[i].start_addr,
- host->sg_cpu[i].cfg, host->sg_cpu[i].x_count,
- host->sg_cpu[i].x_modify);
- }
- }
- flush_dcache_range((unsigned int)host->sg_cpu,
- (unsigned int)host->sg_cpu +
- host->dma_len * sizeof(struct dma_desc_array));
- /* Set the last descriptor to stop mode */
- host->sg_cpu[host->dma_len - 1].cfg &= ~(DMAFLOW | NDSIZE);
- host->sg_cpu[host->dma_len - 1].cfg |= DI_EN;
-
- set_dma_curr_desc_addr(host->dma_ch, (unsigned long *)host->sg_dma);
- set_dma_x_count(host->dma_ch, 0);
- set_dma_x_modify(host->dma_ch, 0);
- SSYNC();
- set_dma_config(host->dma_ch, dma_cfg);
-#elif defined(CONFIG_BF51x)
- /* RSI DMA doesn't work in array mode */
- dma_cfg |= WDSIZE_32 | DMAEN;
- set_dma_start_addr(host->dma_ch, sg_dma_address(&data->sg[0]));
- set_dma_x_count(host->dma_ch, length / 4);
- set_dma_x_modify(host->dma_ch, 4);
- SSYNC();
- set_dma_config(host->dma_ch, dma_cfg);
-#endif
- bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E);
-
- SSYNC();
-
- dev_dbg(mmc_dev(host->mmc), "%s exit\n", __func__);
- return 0;
-}
-
-static void sdh_start_cmd(struct sdh_host *host, struct mmc_command *cmd)
-{
- unsigned int sdh_cmd;
- unsigned int stat_mask;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter cmd: 0x%p\n", __func__, cmd);
- WARN_ON(host->cmd != NULL);
- host->cmd = cmd;
-
- sdh_cmd = 0;
- stat_mask = 0;
-
- sdh_cmd |= cmd->opcode;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- sdh_cmd |= CMD_RSP;
- stat_mask |= CMD_RESP_END;
- } else {
- stat_mask |= CMD_SENT;
- }
-
- if (cmd->flags & MMC_RSP_136)
- sdh_cmd |= CMD_L_RSP;
-
- stat_mask |= CMD_CRC_FAIL | CMD_TIME_OUT;
-
- sdh_enable_stat_irq(host, stat_mask);
-
- bfin_write_SDH_ARGUMENT(cmd->arg);
- bfin_write_SDH_COMMAND(sdh_cmd | CMD_E);
- bfin_write_SDH_CLK_CTL(bfin_read_SDH_CLK_CTL() | CLK_E);
- SSYNC();
-}
-
-static void sdh_finish_request(struct sdh_host *host, struct mmc_request *mrq)
-{
- dev_dbg(mmc_dev(host->mmc), "%s enter\n", __func__);
- host->mrq = NULL;
- host->cmd = NULL;
- host->data = NULL;
- mmc_request_done(host->mmc, mrq);
-}
-
-static int sdh_cmd_done(struct sdh_host *host, unsigned int stat)
-{
- struct mmc_command *cmd = host->cmd;
- int ret = 0;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter cmd: %p\n", __func__, cmd);
- if (!cmd)
- return 0;
-
- host->cmd = NULL;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- cmd->resp[0] = bfin_read_SDH_RESPONSE0();
- if (cmd->flags & MMC_RSP_136) {
- cmd->resp[1] = bfin_read_SDH_RESPONSE1();
- cmd->resp[2] = bfin_read_SDH_RESPONSE2();
- cmd->resp[3] = bfin_read_SDH_RESPONSE3();
- }
- }
- if (stat & CMD_TIME_OUT)
- cmd->error = -ETIMEDOUT;
- else if (stat & CMD_CRC_FAIL && cmd->flags & MMC_RSP_CRC)
- cmd->error = -EILSEQ;
-
- sdh_disable_stat_irq(host, (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | CMD_CRC_FAIL));
-
- if (host->data && !cmd->error) {
- if (host->data->flags & MMC_DATA_WRITE) {
- ret = sdh_setup_data(host, host->data);
- if (ret)
- return 0;
- }
-
- sdh_enable_stat_irq(host, DAT_END | RX_OVERRUN | TX_UNDERRUN | DAT_TIME_OUT);
- } else
- sdh_finish_request(host, host->mrq);
-
- return 1;
-}
-
-static int sdh_data_done(struct sdh_host *host, unsigned int stat)
-{
- struct mmc_data *data = host->data;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter stat: 0x%x\n", __func__, stat);
- if (!data)
- return 0;
-
- disable_dma(host->dma_ch);
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- host->dma_dir);
-
- if (stat & DAT_TIME_OUT)
- data->error = -ETIMEDOUT;
- else if (stat & DAT_CRC_FAIL)
- data->error = -EILSEQ;
- else if (stat & (RX_OVERRUN | TX_UNDERRUN))
- data->error = -EIO;
-
- if (!data->error)
- data->bytes_xfered = data->blocks * data->blksz;
- else
- data->bytes_xfered = 0;
-
- bfin_write_SDH_STATUS_CLR(DAT_END_STAT | DAT_TIMEOUT_STAT | \
- DAT_CRC_FAIL_STAT | DAT_BLK_END_STAT | RX_OVERRUN | TX_UNDERRUN);
- bfin_write_SDH_DATA_CTL(0);
- SSYNC();
-
- host->data = NULL;
- if (host->mrq->stop) {
- sdh_stop_clock(host);
- sdh_start_cmd(host, host->mrq->stop);
- } else {
- sdh_finish_request(host, host->mrq);
- }
-
- return 1;
-}
-
-static void sdh_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct sdh_host *host = mmc_priv(mmc);
- int ret = 0;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter, mrp:%p, cmd:%p\n", __func__, mrq, mrq->cmd);
- WARN_ON(host->mrq != NULL);
-
- spin_lock(&host->lock);
- host->mrq = mrq;
- host->data = mrq->data;
-
- if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
- ret = sdh_setup_data(host, mrq->data);
- if (ret)
- goto data_err;
- }
-
- sdh_start_cmd(host, mrq->cmd);
-data_err: