diff options
Diffstat (limited to 'drivers/mmc')
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: |