diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-25 08:23:32 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-25 08:23:32 -0700 |
commit | 92bf3d09410531a06e06504957271e3978f937e2 (patch) | |
tree | e638413049deb010103bc65e2650d1315dbaa748 /drivers/mmc | |
parent | 603d6637aeb9a14cd0087d7c24c3777bfa51fcbf (diff) | |
parent | 0caaa9539adcff38ce12e99f0ab25645e7eb3eea (diff) |
Merge tag 'mmc-merge-for-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC changes from Chris Ball
- at91-mci: This driver will be replaced by atmel-mci in 3.7.
- atmel-mci: Add support for old at91-mci hardware.
- dw_mmc: Allow multiple controllers; this previously caused
corruption.
- imxmmc: Remove this driver, replaced by mxcmmc.
- mmci: Add device tree support.
- omap: Allow multiple controllers.
- omap_hsmmc: Auto CMD12, DDR support.
- tegra: Support SD 3.0 spec.
Fix up the usual trivial conflicts in feature-removal-schedule.txt
* tag 'mmc-merge-for-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (38 commits)
mmc: at91-mci: this driver is now deprecated
mmc: omap_hsmmc: pass IRQF_ONESHOT to request_threaded_irq
mmc: block: Allow disabling 512B sector size emulation
mmc: atmel-mci: add debug logs
mmc: atmel-mci: add support for version lower than v2xx
mmc: atmel-mci: change the state machine for compatibility with old IP
mmc: atmel-mci: the r/w proof capability lack was not well managed
mmc: dw_mmc: Fixed sdio interrupt mask bit setting bug
mmc: omap: convert to module_platform_driver
mmc: omap: make it behave well as a module
mmc: omap: convert to per instance workqueue
mmc: core: Remove dead code
mmc: card: Avoid null pointer dereference
mmc: core: Prevent eMMC VCC supply to be cut from late init
mmc: dw_mmc: make multiple instances of dw_mci_card_workqueue
mmc: queue: remove redundant memsets
mmc: queue: rename mmc_request function
mmc: core: skip card initialization if power class selection fails
mmc: core: fix the signaling 1.8V for HS200
mmc: core: fix the decision of HS200/DDR card-type
...
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/card/block.c | 22 | ||||
-rw-r--r-- | drivers/mmc/card/queue.c | 6 | ||||
-rw-r--r-- | drivers/mmc/core/bus.c | 2 | ||||
-rw-r--r-- | drivers/mmc/core/cd-gpio.c | 3 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 18 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 119 | ||||
-rw-r--r-- | drivers/mmc/core/sdio.c | 2 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_irq.c | 11 | ||||
-rw-r--r-- | drivers/mmc/host/Kconfig | 17 | ||||
-rw-r--r-- | drivers/mmc/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 469 | ||||
-rw-r--r-- | drivers/mmc/host/davinci_mmc.c | 1 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc.c | 18 | ||||
-rw-r--r-- | drivers/mmc/host/imxmmc.c | 1169 | ||||
-rw-r--r-- | drivers/mmc/host/imxmmc.h | 64 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.c | 65 | ||||
-rw-r--r-- | drivers/mmc/host/omap.c | 48 | ||||
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 84 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-spear.c | 82 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 26 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 4 |
21 files changed, 630 insertions, 1601 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index dabec556ebb..dd2d374dcc7 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -384,7 +384,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, md = mmc_blk_get(bdev->bd_disk); if (!md) { err = -EINVAL; - goto cmd_done; + goto cmd_err; } card = md->queue.card; @@ -483,6 +483,7 @@ cmd_rel_host: cmd_done: mmc_blk_put(md); +cmd_err: kfree(idata->buf); kfree(idata); return err; @@ -1283,7 +1284,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) int ret = 1, disable_multi = 0, retry = 0, type; enum mmc_blk_status status; struct mmc_queue_req *mq_rq; - struct request *req; + struct request *req = rqc; struct mmc_async_req *areq; if (!rqc && !mq->mqrq_prev->req) @@ -1291,6 +1292,16 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) do { if (rqc) { + /* + * When 4KB native sector is enabled, only 8 blocks + * multiple read or write is allowed + */ + if ((brq->data.blocks & 0x07) && + (card->ext_csd.data_sector_size == 4096)) { + pr_err("%s: Transfer size is not 4KB sector size aligned\n", + req->rq_disk->disk_name); + goto cmd_abort; + } mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); areq = &mq->mqrq_cur->mmc_active; } else @@ -1538,7 +1549,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, snprintf(md->disk->disk_name, sizeof(md->disk->disk_name), "mmcblk%d%s", md->name_idx, subname ? subname : ""); - blk_queue_logical_block_size(md->queue.queue, 512); + if (mmc_card_mmc(card)) + blk_queue_logical_block_size(md->queue.queue, + card->ext_csd.data_sector_size); + else + blk_queue_logical_block_size(md->queue.queue, 512); + set_capacity(md->disk, size); if (mmc_host_cmd23(card->host)) { diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 996f8e36e23..e360a979857 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -96,7 +96,7 @@ static int mmc_queue_thread(void *d) * on any queue on this host, and attempt to issue it. This may * not be the queue we were asked to process. */ -static void mmc_request(struct request_queue *q) +static void mmc_request_fn(struct request_queue *q) { struct mmc_queue *mq = q->queuedata; struct request *req; @@ -171,12 +171,10 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, limit = *mmc_dev(host)->dma_mask; mq->card = card; - mq->queue = blk_init_queue(mmc_request, lock); + mq->queue = blk_init_queue(mmc_request_fn, lock); if (!mq->queue) return -ENOMEM; - memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur)); - memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev)); mq->mqrq_cur = mqrq_cur; mq->mqrq_prev = mqrq_prev; mq->queue->queuedata = mq; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index c60cee92a2b..9b68933f27e 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -122,6 +122,7 @@ static int mmc_bus_remove(struct device *dev) return 0; } +#ifdef CONFIG_PM_SLEEP static int mmc_bus_suspend(struct device *dev) { struct mmc_driver *drv = to_mmc_driver(dev->driver); @@ -143,6 +144,7 @@ static int mmc_bus_resume(struct device *dev) ret = drv->resume(card); return ret; } +#endif #ifdef CONFIG_PM_RUNTIME diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c index 2c14be73254..f13e38decea 100644 --- a/drivers/mmc/core/cd-gpio.c +++ b/drivers/mmc/core/cd-gpio.c @@ -73,6 +73,9 @@ void mmc_cd_gpio_free(struct mmc_host *host) { struct mmc_cd_gpio *cd = host->hotplug.handler_priv; + if (!cd) + return; + free_irq(host->hotplug.irq, host); gpio_free(cd->gpio); kfree(cd); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index ba821fe70bc..0b6141d29db 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -42,6 +42,7 @@ #include "sdio_ops.h" static struct workqueue_struct *workqueue; +static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; /* * Enabling software CRCs on the data blocks can be a significant (30%) @@ -1157,6 +1158,9 @@ static void mmc_power_up(struct mmc_host *host) { int bit; + if (host->ios.power_mode == MMC_POWER_ON) + return; + mmc_host_clk_hold(host); /* If ocr is set, we use it */ @@ -1199,6 +1203,10 @@ static void mmc_power_up(struct mmc_host *host) void mmc_power_off(struct mmc_host *host) { int err = 0; + + if (host->ios.power_mode == MMC_POWER_OFF) + return; + mmc_host_clk_hold(host); host->ios.clock = 0; @@ -2005,7 +2013,6 @@ EXPORT_SYMBOL(mmc_detect_card_removed); void mmc_rescan(struct work_struct *work) { - static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; struct mmc_host *host = container_of(work, struct mmc_host, detect.work); int i; @@ -2044,8 +2051,12 @@ void mmc_rescan(struct work_struct *work) */ mmc_bus_put(host); - if (host->ops->get_cd && host->ops->get_cd(host) == 0) + if (host->ops->get_cd && host->ops->get_cd(host) == 0) { + mmc_claim_host(host); + mmc_power_off(host); + mmc_release_host(host); goto out; + } mmc_claim_host(host); for (i = 0; i < ARRAY_SIZE(freqs); i++) { @@ -2063,7 +2074,8 @@ void mmc_rescan(struct work_struct *work) void mmc_start_host(struct mmc_host *host) { - mmc_power_off(host); + host->f_init = max(freqs[0], host->f_min); + mmc_power_up(host); mmc_detect_change(host, 0); } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 54df5adc041..2d4a4b74675 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -235,6 +235,36 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) return err; } +static void mmc_select_card_type(struct mmc_card *card) +{ + struct mmc_host *host = card->host; + u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK; + unsigned int caps = host->caps, caps2 = host->caps2; + unsigned int hs_max_dtr = 0; + + if (card_type & EXT_CSD_CARD_TYPE_26) + hs_max_dtr = MMC_HIGH_26_MAX_DTR; + + if (caps & MMC_CAP_MMC_HIGHSPEED && + card_type & EXT_CSD_CARD_TYPE_52) + hs_max_dtr = MMC_HIGH_52_MAX_DTR; + + if ((caps & MMC_CAP_1_8V_DDR && + card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) || + (caps & MMC_CAP_1_2V_DDR && + card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)) + hs_max_dtr = MMC_HIGH_DDR_MAX_DTR; + + if ((caps2 & MMC_CAP2_HS200_1_8V_SDR && + card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) || + (caps2 & MMC_CAP2_HS200_1_2V_SDR && + card_type & EXT_CSD_CARD_TYPE_SDR_1_2V)) + hs_max_dtr = MMC_HS200_MAX_DTR; + + card->ext_csd.hs_max_dtr = hs_max_dtr; + card->ext_csd.card_type = card_type; +} + /* * Decode extended CSD. */ @@ -284,56 +314,9 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512) mmc_card_set_blockaddr(card); } + card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; - switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { - case EXT_CSD_CARD_TYPE_SDR_ALL: - case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V: - case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V: - case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52: - card->ext_csd.hs_max_dtr = 200000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200; - break; - case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL: - case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V: - case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V: - case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52: - card->ext_csd.hs_max_dtr = 200000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V; - break; - case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL: - case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V: - case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V: - case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52: - card->ext_csd.hs_max_dtr = 200000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V; - break; - case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 | - EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 52000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52; - break; - case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 | - EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 52000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V; - break; - case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 | - EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 52000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V; - break; - case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 52000000; - break; - case EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 26000000; - break; - default: - /* MMC v4 spec says this cannot happen */ - pr_warning("%s: card is mmc v4 but doesn't " - "support any high-speed modes.\n", - mmc_hostname(card->host)); - } + mmc_select_card_type(card); card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.raw_erase_timeout_mult = @@ -533,6 +516,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } else { card->ext_csd.data_tag_unit_size = 0; } + } else { + card->ext_csd.data_sector_size = 512; } out: @@ -556,14 +541,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) err = mmc_get_ext_csd(card, &bw_ext_csd); if (err || bw_ext_csd == NULL) { - if (bus_width != MMC_BUS_WIDTH_1) - err = -EINVAL; + err = -EINVAL; goto out; } - if (bus_width == MMC_BUS_WIDTH_1) - goto out; - /* only compare read only fields */ err = !((card->ext_csd.raw_partition_support == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && @@ -736,6 +717,10 @@ static int mmc_select_powerclass(struct mmc_card *card, card->ext_csd.generic_cmd6_time); } + if (err) + pr_err("%s: power class selection for ext_csd_bus_width %d" + " failed\n", mmc_hostname(card->host), bus_width); + return err; } @@ -745,7 +730,7 @@ static int mmc_select_powerclass(struct mmc_card *card, */ static int mmc_select_hs200(struct mmc_card *card) { - int idx, err = 0; + int idx, err = -EINVAL; struct mmc_host *host; static unsigned ext_csd_bits[] = { EXT_CSD_BUS_WIDTH_4, @@ -761,10 +746,12 @@ static int mmc_select_hs200(struct mmc_card *card) host = card->host; if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V && - host->caps2 & MMC_CAP2_HS200_1_2V_SDR) - if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0)) - err = mmc_set_signal_voltage(host, - MMC_SIGNAL_VOLTAGE_180, 0); + host->caps2 & MMC_CAP2_HS200_1_2V_SDR) + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0); + + if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V && + host->caps2 & MMC_CAP2_HS200_1_8V_SDR) + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, 0); /* If fails try again during next card power cycle */ if (err) @@ -1117,9 +1104,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4; err = mmc_select_powerclass(card, ext_csd_bits, ext_csd); if (err) - pr_warning("%s: power class selection to bus width %d" - " failed\n", mmc_hostname(card->host), - 1 << bus_width); + goto err; } /* @@ -1151,10 +1136,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, err = mmc_select_powerclass(card, ext_csd_bits[idx][0], ext_csd); if (err) - pr_warning("%s: power class selection to " - "bus width %d failed\n", - mmc_hostname(card->host), - 1 << bus_width); + goto err; err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, @@ -1182,10 +1164,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, err = mmc_select_powerclass(card, ext_csd_bits[idx][1], ext_csd); if (err) - pr_warning("%s: power class selection to " - "bus width %d ddr %d failed\n", - mmc_hostname(card->host), - 1 << bus_width, ddr); + goto err; err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2c7c83f832d..13d0e95380a 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -947,7 +947,7 @@ static int mmc_sdio_resume(struct mmc_host *host) } if (!err && host->sdio_irqs) - mmc_signal_sdio_irq(host); + wake_up_process(host->sdio_irq_thread); mmc_release_host(host); /* diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index f573e7f9f74..3d8ceb4084d 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -28,18 +28,20 @@ #include "sdio_ops.h" -static int process_sdio_pending_irqs(struct mmc_card *card) +static int process_sdio_pending_irqs(struct mmc_host *host) { + struct mmc_card *card = host->card; int i, ret, count; unsigned char pending; struct sdio_func *func; /* * Optimization, if there is only 1 function interrupt registered - * call irq handler directly + * and we know an IRQ was signaled then call irq handler directly. + * Otherwise do the full probe. */ func = card->sdio_single_irq; - if (func) { + if (func && host->sdio_irq_pending) { func->irq_handler(func); return 1; } @@ -116,7 +118,8 @@ static int sdio_irq_thread(void *_host) ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort); if (ret) break; - ret = process_sdio_pending_irqs(host->card); + ret = process_sdio_pending_irqs(host); + host->sdio_irq_pending = false; mmc_release_host(host); /* diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 2bc06e7344d..aa131b32e3b 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -278,10 +278,13 @@ choice Choose which driver to use for the Atmel MCI Silicon config MMC_AT91 - tristate "AT91 SD/MMC Card Interface support" + tristate "AT91 SD/MMC Card Interface support (DEPRECATED)" depends on ARCH_AT91 help - This selects the AT91 MCI controller. + This selects the AT91 MCI controller. This driver will + be removed soon (for more information have a look to + Documentation/feature-removal-schedule.txt). Please use + MMC_ATMEL_MCI. If unsure, say N. @@ -307,16 +310,6 @@ config MMC_ATMELMCI_DMA If unsure, say N. -config MMC_IMX - tristate "Motorola i.MX Multimedia Card Interface support" - depends on ARCH_MX1 - help - This selects the Motorola i.MX Multimedia card Interface. - If you have a i.MX platform with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - config MMC_MSM tristate "Qualcomm SDCC Controller Support" depends on MMC && ARCH_MSM diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 3e7e26d0807..8922b06be92 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o -obj-$(CONFIG_MMC_IMX) += imxmmc.o obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index e94476beca1..420aca642b1 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -45,19 +45,19 @@ #define ATMCI_DMA_THRESHOLD 16 enum { - EVENT_CMD_COMPLETE = 0, + EVENT_CMD_RDY = 0, EVENT_XFER_COMPLETE, - EVENT_DATA_COMPLETE, + EVENT_NOTBUSY, EVENT_DATA_ERROR, }; enum atmel_mci_state { STATE_IDLE = 0, STATE_SENDING_CMD, - STATE_SENDING_DATA, - STATE_DATA_BUSY, + STATE_DATA_XFER, + STATE_WAITING_NOTBUSY, STATE_SENDING_STOP, - STATE_DATA_ERROR, + STATE_END_REQUEST, }; enum atmci_xfer_dir { @@ -78,6 +78,9 @@ struct atmel_mci_caps { bool has_highspeed; bool has_rwproof; bool has_odd_clk_div; + bool has_bad_data_ordering; + bool need_reset_after_xfer; + bool need_blksz_mul_4; }; struct atmel_mci_dma { @@ -91,6 +94,11 @@ struct atmel_mci_dma { * @regs: Pointer to MMIO registers. * @sg: Scatterlist entry currently being processed by PIO or PDC code. * @pio_offset: Offset into the current scatterlist entry. + * @buffer: Buffer used if we don't have the r/w proof capability. We + * don't have the time to switch pdc buffers so we have to use only + * one buffer for the full transaction. + * @buf_size: size of the buffer. + * @phys_buf_addr: buffer address needed for pdc. * @cur_slot: The slot which is currently using the controller. * @mrq: The request currently being processed on @cur_slot, * or NULL if the controller is idle. @@ -116,6 +124,7 @@ struct atmel_mci_dma { * @queue: List of slots waiting for access to the controller. * @need_clock_update: Update the clock rate before the next request. * @need_reset: Reset controller before next request. + * @timer: Timer to balance the data timeout error flag which cannot rise. * @mode_reg: Value of the MR register. * @cfg_reg: Value of the CFG register. * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus @@ -166,6 +175,9 @@ struct atmel_mci { struct scatterlist *sg; unsigned int pio_offset; + unsigned int *buffer; + unsigned int buf_size; + dma_addr_t buf_phys_addr; struct atmel_mci_slot *cur_slot; struct mmc_request *mrq; @@ -189,6 +201,7 @@ struct atmel_mci { bool need_clock_update; bool need_reset; + struct timer_list timer; u32 mode_reg; u32 cfg_reg; unsigned long bus_hz; @@ -480,6 +493,32 @@ err: dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); } +static inline unsigned int atmci_get_version(struct atmel_mci *host) +{ + return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; +} + +static void atmci_timeout_timer(unsigned long data) +{ + struct atmel_mci *host; + + host = (struct atmel_mci *)data; + + dev_dbg(&host->pdev->dev, "software timeout\n"); + + if (host->mrq->cmd->data) { + host->mrq->cmd->data->error = -ETIMEDOUT; + host->data = NULL; + } else { + host->mrq->cmd->error = -ETIMEDOUT; + host->cmd = NULL; + } + host->need_reset = 1; + host->state = STATE_END_REQUEST; + smp_wmb(); + tasklet_schedule(&host->tasklet); +} + static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, unsigned int ns) { @@ -591,6 +630,7 @@ static void atmci_send_command(struct atmel_mci *host, static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) { + dev_dbg(&host->pdev->dev, "send stop command\n"); atmci_send_command(host, data->stop, host->stop_cmdr); atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); } @@ -603,6 +643,7 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host, enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb) { u32 pointer_reg, counter_reg; + unsigned int buf_size; if (dir == XFER_RECEIVE) { pointer_reg = ATMEL_PDC_RPR; @@ -617,8 +658,15 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host, counter_reg += ATMEL_PDC_SCND_BUF_OFF; } - atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); - if (host->data_size <= sg_dma_len(host->sg)) { + if (!host->caps.has_rwproof) { + buf_size = host->buf_size; + atmci_writel(host, pointer_reg, host->buf_phys_addr); + } else { + buf_size = sg_dma_len(host->sg); + atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); + } + + if (host->data_size <= buf_size) { if (host->data_size & 0x3) { /* If size is different from modulo 4, transfer bytes */ atmci_writel(host, counter_reg, host->data_size); @@ -670,7 +718,20 @@ static void atmci_pdc_cleanup(struct atmel_mci *host) */ static void atmci_pdc_complete(struct atmel_mci *host) { + int transfer_size = host->data->blocks * host->data->blksz; + int i; + atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); + + if ((!host->caps.has_rwproof) + && (host->data->flags & MMC_DATA_READ)) { + if (host->caps.has_bad_data_ordering) + for (i = 0; i < transfer_size; i++) + host->buffer[i] = swab32(host->buffer[i]); + sg_copy_from_buffer(host->data->sg, host->data->sg_len, + host->buffer, transfer_size); + } + atmci_pdc_cleanup(host); /* @@ -678,9 +739,10 @@ static void atmci_pdc_complete(struct atmel_mci *host) * to send the stop command or waiting for NBUSY in this case. */ if (host->data) { + dev_dbg(&host->pdev->dev, + "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); tasklet_schedule(&host->tasklet); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } } @@ -716,6 +778,8 @@ static void atmci_dma_complete(void *arg) * to send the stop command or waiting for NBUSY in this case. */ if (data) { + dev_dbg(&host->pdev->dev, + "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); tasklet_schedule(&host->tasklet); @@ -791,6 +855,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) u32 iflags, tmp; unsigned int sg_len; enum dma_data_direction dir; + int i; data->error = -EINPROGRESS; @@ -806,7 +871,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; } else { dir = DMA_TO_DEVICE; - iflags |= ATMCI_ENDTX | ATMCI_TXBUFE; + iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE; } /* Set BLKLEN */ @@ -818,6 +883,16 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) /* Configure PDC */ host->data_size = data->blocks * data->blksz; sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir); + + if ((!host->caps.has_rwproof) + && (host->data->flags & MMC_DATA_WRITE)) { + sg_copy_to_buffer(host->data->sg, host->data->sg_len, + host->buffer, host->data_size); + if (host->caps.has_bad_data_ordering) + for (i = 0; i < host->data_size; i++) + host->buffer[i] = swab32(host->buffer[i]); + } + if (host->data_size) atmci_pdc_set_both_buf(host, ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT)); @@ -931,6 +1006,8 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) static void atmci_stop_transfer(struct atmel_mci *host) { + dev_dbg(&host->pdev->dev, + "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } @@ -940,8 +1017,7 @@ static void atmci_stop_transfer(struct atmel_mci *host) */ static void atmci_stop_transfer_pdc(struct atmel_mci *host) { - atmci_set_pending(host, EVENT_XFER_COMPLETE); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); } static void atmci_stop_transfer_dma(struct atmel_mci *host) @@ -953,6 +1029,8 @@ static void atmci_stop_transfer_dma(struct atmel_mci *host) atmci_dma_cleanup(host); } else { /* Data transfer was stopped by the interrupt handler */ + dev_dbg(&host->pdev->dev, + "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } @@ -977,9 +1055,12 @@ static void atmci_start_request(struct atmel_mci *host, host->pending_events = 0; host->completed_events = 0; + host->cmd_status = 0; host->data_status = 0; - if (host->need_reset) { + dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode); + + if (host->need_reset || host->caps.need_reset_after_xfer) { iflags = atmci_readl(host, ATMCI_IMR); iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB); atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); @@ -994,7 +1075,7 @@ static void atmci_start_request(struct atmel_mci *host, iflags = atmci_readl(host, ATMCI_IMR); if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) - dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", + dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", iflags); if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) { @@ -1043,6 +1124,8 @@ static void atmci_start_request(struct atmel_mci *host, * prepared yet.) */ atmci_writel(host, ATMCI_IER, iflags); + + mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); } static void atmci_queue_request(struct atmel_mci *host, @@ -1057,6 +1140,7 @@ static void atmci_queue_request(struct atmel_mci *host, host->state = STATE_SENDING_CMD; atmci_start_request(host, slot); } else { + dev_dbg(&host->pdev->dev, "queue request\n"); list_add_tail(&slot->queue_node, &host->queue); } spin_unlock_bh(&host->lock); @@ -1069,6 +1153,7 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) struct mmc_data *data; WARN_ON(slot->mrq); + dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode); /* * We may "know" the card is gone even though there's still an @@ -1308,6 +1393,8 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) host->state = STATE_IDLE; } + del_timer(&host->timer); + spin_unlock(&host->lock); mmc_request_done(prev_mmc, mrq); spin_lock(&host->lock); @@ -1330,21 +1417,13 @@ static void atmci_command_complete(struct atmel_mci *host, cmd->error = -EILSEQ; else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE)) cmd->error = -EIO; - else - cmd->error = 0; - - if (cmd->error) { - dev_dbg(&host->pdev->dev, - "command error: status=0x%08x\n", status); - - if (cmd->data) { - host->stop_transfer(host); - host->data = NULL; - atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY - | ATMCI_TXRDY | ATMCI_RXRDY - | ATMCI_DATA_ERROR_FLAGS); + else if (host->mrq->data && (host->mrq->data->blksz & 3)) { + if (host->caps.need_blksz_mul_4) { + cmd->error = -EINVAL; + host->need_reset = 1; } - } + } else + cmd->error = 0; } static void atmci_detect_change(unsigned long data) @@ -1407,23 +1486,21 @@ static void atmci_detect_change(unsigned long data) break; case STATE_SENDING_CMD: mrq->cmd->error = -ENOMEDIUM; - if (!mrq->data) - break; - /* fall through */ - case STATE_SENDING_DATA: + if (mrq->data) + host->stop_transfer(host); + break; + case STATE_DATA_XFER: mrq->data->error = -ENOMEDIUM; host->stop_transfer(host); break; - case STATE_DATA_BUSY: - case STATE_DATA_ERROR: - if (mrq->data->error == -EINPROGRESS) - mrq->data->error = -ENOMEDIUM; - if (!mrq->stop) - break; - /* fall through */ + case STATE_WAITING_NOTBUSY: + mrq->data->error = -ENOMEDIUM; + break; case STATE_SENDING_STOP: mrq->stop->error = -ENOMEDIUM; break; + case STATE_END_REQUEST: + break; } atmci_request_end(host, mrq); @@ -1451,7 +1528,6 @@ static void atmci_tasklet_func(unsigned long priv) struct atmel_mci *host = (struct atmel_mci *)priv; struct mmc_request *mrq = host->mrq; |