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) | |
download | op-kernel-dev-92bf3d09410531a06e06504957271e3978f937e2.zip op-kernel-dev-92bf3d09410531a06e06504957271e3978f937e2.tar.gz |
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 dabec55..dd2d374 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 996f8e3..e360a97 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 c60cee9..9b68933 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 2c14be7..f13e38d 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 ba821fe..0b6141d 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 54df5ad..2d4a4b7 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 2c7c83f..13d0e95 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 f573e7f..3d8ceb4 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 2bc06e7..aa131b3 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 3e7e26d..8922b06 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 e94476b..420aca6 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; struct mmc_data *data = host->data; - struct mmc_command *cmd = host->cmd; enum atmel_mci_state state = host->state; enum atmel_mci_state prev_state; u32 status; @@ -1467,107 +1543,186 @@ static void atmci_tasklet_func(unsigned long priv) do { prev_state = state; + dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state); switch (state) { case STATE_IDLE: break; case STATE_SENDING_CMD: + /* + * Command has been sent, we are waiting for command + * ready. Then we have three next states possible: + * END_REQUEST by default, WAITING_NOTBUSY if it's a + * command needing it or DATA_XFER if there is data. + */ + dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); if (!atmci_test_and_clear_pending(host, - EVENT_CMD_COMPLETE)) + EVENT_CMD_RDY)) break; + dev_dbg(&host->pdev->dev, "set completed cmd ready\n"); host->cmd = NULL; - atmci_set_completed(host, EVENT_CMD_COMPLETE); + atmci_set_completed(host, EVENT_CMD_RDY); atmci_command_complete(host, mrq->cmd); - if (!mrq->data || cmd->error) { - atmci_request_end(host, host->mrq); - goto unlock; - } + if (mrq->data) { + dev_dbg(&host->pdev->dev, + "command with data transfer"); + /* + * If there is a command error don't start + * data transfer. + */ + if (mrq->cmd->error) { + host->stop_transfer(host); + host->data = NULL; + atmci_writel(host, ATMCI_IDR, + ATMCI_TXRDY | ATMCI_RXRDY + | ATMCI_DATA_ERROR_FLAGS); + state = STATE_END_REQUEST; + } else + state = STATE_DATA_XFER; + } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) { + dev_dbg(&host->pdev->dev, + "command response need waiting notbusy"); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + state = STATE_WAITING_NOTBUSY; + } else + state = STATE_END_REQUEST; - prev_state = state = STATE_SENDING_DATA; - /* fall through */ + break; - case STATE_SENDING_DATA: + case STATE_DATA_XFER: if (atmci_test_and_clear_pending(host, EVENT_DATA_ERROR)) { - host->stop_transfer(host); - if (data->stop) - atmci_send_stop_cmd(host, data); - state = STATE_DATA_ERROR; + dev_dbg(&host->pdev->dev, "set completed data error\n"); + atmci_set_completed(host, EVENT_DATA_ERROR); + state = STATE_END_REQUEST; break; } + /* + * A data transfer is in progress. The event expected + * to move to the next state depends of data transfer + * type (PDC or DMA). Once transfer done we can move + * to the next step which is WAITING_NOTBUSY in write + * case and directly SENDING_STOP in read case. + */ + dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n"); if (!atmci_test_and_clear_pending(host, EVENT_XFER_COMPLETE)) break; + dev_dbg(&host->pdev->dev, + "(%s) set completed xfer complete\n", + __func__); atmci_set_completed(host, EVENT_XFER_COMPLETE); - prev_state = state = STATE_DATA_BUSY; - /* fall through */ - case STATE_DATA_BUSY: - if (!atmci_test_and_clear_pending(host, - EVENT_DATA_COMPLETE)) - break; - - host->data = NULL; - atmci_set_completed(host, EVENT_DATA_COMPLETE); - status = host->data_status; - if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) { - if (status & ATMCI_DTOE) { - dev_dbg(&host->pdev->dev, - "data timeout error\n"); - data->error = -ETIMEDOUT; - } else if (status & ATMCI_DCRCE) { - dev_dbg(&host->pdev->dev, - "data CRC error\n"); - data->error = -EILSEQ; - } else { - dev_dbg(&host->pdev->dev, - "data FIFO error (status=%08x)\n", - status); - data->error = -EIO; - } + if (host->data->flags & MMC_DATA_WRITE) { + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + state = STATE_WAITING_NOTBUSY; + } else if (host->mrq->stop) { + atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); + atmci_send_stop_cmd(host, data); + state = STATE_SENDING_STOP; } else { + host->data = NULL; data->bytes_xfered = data->blocks * data->blksz; data->error = 0; - atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS); + state = STATE_END_REQUEST; } + break; - if (!data->stop) { - atmci_request_end(host, host->mrq); - goto unlock; - } + case STATE_WAITING_NOTBUSY: + /* + * We can be in the state for two reasons: a command + * requiring waiting not busy signal (stop command + * included) or a write operation. In the latest case, + * we need to send a stop command. + */ + dev_dbg(&host->pdev->dev, "FSM: not busy?\n"); + if (!atmci_test_and_clear_pending(host, + EVENT_NOTBUSY)) + break; - prev_state = state = STATE_SENDING_STOP; - if (!data->error) - atmci_send_stop_cmd(host, data); - /* fall through */ + dev_dbg(&host->pdev->dev, "set completed not busy\n"); + atmci_set_completed(host, EVENT_NOTBUSY); + + if (host->data) { + /* + * For some commands such as CMD53, even if + * there is data transfer, there is no stop + * command to send. + */ + if (host->mrq->stop) { + atmci_writel(host, ATMCI_IER, + ATMCI_CMDRDY); + atmci_send_stop_cmd(host, data); + state = STATE_SENDING_STOP; + } else { + host->data = NULL; + data->bytes_xfered = data->blocks + * data->blksz; + data->error = 0; + state = STATE_END_REQUEST; + } + } else + state = STATE_END_REQUEST; + break; case STATE_SENDING_STOP: + /* + * In this state, it is important to set host->data to + * NULL (which is tested in the waiting notbusy state) + * in order to go to the end request state instead of + * sending stop again. + */ + dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); if (!atmci_test_and_clear_pending(host, - EVENT_CMD_COMPLETE)) + EVENT_CMD_RDY)) break; + dev_dbg(&host->pdev->dev, "FSM: cmd ready\n"); host->cmd = NULL; + host->data = NULL; + data->bytes_xfered = data->blocks * data->blksz; + data->error = 0; atmci_command_complete(host, mrq->stop); - atmci_request_end(host, host->mrq); - goto unlock; + if (mrq->stop->error) { + host->stop_transfer(host); + atmci_writel(host, ATMCI_IDR, + ATMCI_TXRDY | ATMCI_RXRDY + | ATMCI_DATA_ERROR_FLAGS); + state = STATE_END_REQUEST; + } else { + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + state = STATE_WAITING_NOTBUSY; + } + break; - case STATE_DATA_ERROR: - if (!atmci_test_and_clear_pending(host, - EVENT_XFER_COMPLETE)) - break; + case STATE_END_REQUEST: + atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY + | ATMCI_DATA_ERROR_FLAGS); + status = host->data_status; + if (unlikely(status)) { + host->stop_transfer(host); + host->data = NULL; + if (status & ATMCI_DTOE) { + data->error = -ETIMEDOUT; + } else if (status & ATMCI_DCRCE) { + data->error = -EILSEQ; + } else { + data->error = -EIO; + } + } - state = STATE_DATA_BUSY; + atmci_request_end(host, host->mrq); + state = STATE_IDLE; break; } } while (state != prev_state); host->state = state; -unlock: spin_unlock(&host->lock); } @@ -1620,9 +1775,6 @@ static void atmci_read_data_pio(struct atmel_mci *host) | ATMCI_DATA_ERROR_FLAGS)); host->data_status = status; data->bytes_xfered += nbytes; - smp_wmb(); - atmci_set_pending(host, EVENT_DATA_ERROR); - tasklet_schedule(&host->tasklet); return; } } while (status & ATMCI_RXRDY); @@ -1691,9 +1843,6 @@ static void atmci_write_data_pio(struct atmel_mci *host) | ATMCI_DATA_ERROR_FLAGS)); host->data_status = status; data->bytes_xfered += nbytes; - smp_wmb(); - atmci_set_pending(host, EVENT_DATA_ERROR); - tasklet_schedule(&host->tasklet); return; } } while (status & ATMCI_TXRDY); @@ -1711,16 +1860,6 @@ done: atmci_set_pending(host, EVENT_XFER_COMPLETE); } -static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) -{ - atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); - - host->cmd_status = status; - smp_wmb(); - atmci_set_pending(host, EVENT_CMD_COMPLETE); - tasklet_schedule(&host->tasklet); -} - static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) { int i; @@ -1748,17 +1887,21 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) break; if (pending & ATMCI_DATA_ERROR_FLAGS) { + dev_dbg(&host->pdev->dev, "IRQ: data error\n"); atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS - | ATMCI_RXRDY | ATMCI_TXRDY); - pending &= atmci_readl(host, ATMCI_IMR); + | ATMCI_RXRDY | ATMCI_TXRDY + | ATMCI_ENDRX | ATMCI_ENDTX + | ATMCI_RXBUFF | ATMCI_TXBUFE); host->data_status = status; + dev_dbg(&host->pdev->dev, "set pending data error\n"); smp_wmb(); atmci_set_pending(host, EVENT_DATA_ERROR); tasklet_schedule(&host->tasklet); } if (pending & ATMCI_TXBUFE) { + dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n"); atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); /* @@ -1774,6 +1917,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) atmci_pdc_complete(host); } } else if (pending & ATMCI_ENDTX) { + dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n"); atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); if (host->data_size) { @@ -1784,6 +1928,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) } if (pending & ATMCI_RXBUFF) { + dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n"); atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); /* @@ -1799,6 +1944,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) atmci_pdc_complete(host); } } else if (pending & ATMCI_ENDRX) { + dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n"); atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); if (host->data_size) { @@ -1808,23 +1954,44 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) } } + /* + * First mci IPs, so mainly the ones having pdc, have some + * issues with the notbusy signal. You can't get it after + * data transmission if you have not sent a stop command. + * The appropriate workaround is to use the BLKE signal. + */ + if (pending & ATMCI_BLKE) { + dev_dbg(&host->pdev->dev, "IRQ: blke\n"); + atmci_writel(host, ATMCI_IDR, ATMCI_BLKE); + smp_wmb(); + dev_dbg(&host->pdev->dev, "set pending notbusy\n"); + atmci_set_pending(host, EVENT_NOTBUSY); + tasklet_schedule(&host->tasklet); + } if (pending & ATMCI_NOTBUSY) { - atmci_writel(host, ATMCI_IDR, - ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY); - if (!host->data_status) - host->data_status = status; + dev_dbg(&host->pdev->dev, "IRQ: not_busy\n"); + atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY); smp_wmb(); - atmci_set_pending(host, EVENT_DATA_COMPLETE); + dev_dbg(&host->pdev->dev, "set pending notbusy\n"); + atmci_set_pending(host, EVENT_NOTBUSY); tasklet_schedule(&host->tasklet); } + if (pending & ATMCI_RXRDY) atmci_read_data_pio(host); if (pending & ATMCI_TXRDY) atmci_write_data_pio(host); - if (pending & ATMCI_CMDRDY) - atmci_cmd_interrupt(host, status); + if (pending & ATMCI_CMDRDY) { + dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n"); + atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); + host->cmd_status = status; + smp_wmb(); + dev_dbg(&host->pdev->dev, "set pending cmd rdy\n"); + atmci_set_pending(host, EVENT_CMD_RDY); + tasklet_schedule(&host->tasklet); + } if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) atmci_sdio_interrupt(host, status); @@ -1877,13 +2044,26 @@ static int __init atmci_init_slot(struct atmel_mci *host, mmc->caps |= MMC_CAP_SDIO_IRQ; if (host->caps.has_highspeed) mmc->caps |= MMC_CAP_SD_HIGHSPEED; - if (slot_data->bus_width >= 4) + /* + * Without the read/write proof capability, it is strongly suggested to + * use only one bit for data to prevent fifo underruns and overruns + * which will corrupt data. + */ + if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) mmc->caps |= MMC_CAP_4_BIT_DATA; - mmc->max_segs = 64; - mmc->max_req_size = 32768 * 512; - mmc->max_blk_size = 32768; - mmc->max_blk_count = 512; + if (atmci_get_version(host) < 0x200) { + mmc->max_segs = 256; + mmc->max_blk_size = 4095; + mmc->max_blk_count = 256; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs; + } else { + mmc->max_segs = 64; + mmc->max_req_size = 32768 * 512; + mmc->max_blk_size = 32768; + mmc->max_blk_count = 512; + } /* Assume card is present initially */ set_bit(ATMCI_CARD_PRESENT, &slot->flags); @@ -2007,11 +2187,6 @@ static bool atmci_configure_dma(struct atmel_mci *host) } } -static inline unsigned int atmci_get_version(struct atmel_mci *host) -{ - return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; -} - /* * HSMCI (High Speed MCI) module is not fully compatible with MCI module. * HSMCI provides DMA support and a new config register but no more supports @@ -2032,6 +2207,9 @@ static void __init atmci_get_cap(struct atmel_mci *host) host->caps.has_highspeed = 0; host->caps.has_rwproof = 0; host->caps.has_odd_clk_div = 0; + host->caps.has_bad_data_ordering = 1; + host->caps.need_reset_after_xfer = 1; + host->caps.need_blksz_mul_4 = 1; /* keep only major version number */ switch (version & 0xf00) { @@ -2051,7 +2229,11 @@ static void __init atmci_get_cap(struct atmel_mci *host) host->caps.has_highspeed = 1; case 0x200: host->caps.has_rwproof = 1; + host->caps.need_blksz_mul_4 = 0; case 0x100: + host->caps.has_bad_data_ordering = 0; + host->caps.need_reset_after_xfer = 0; + case 0x0: break; default: host->caps.has_pdc = 0; @@ -2138,14 +2320,20 @@ static int __init atmci_probe(struct platform_device *pdev) if (pdata->slot[0].bus_width) { ret = atmci_init_slot(host, &pdata->slot[0], 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); - if (!ret) + if (!ret) { nr_slots++; + host->buf_size = host->slot[0]->mmc->max_req_size; + } } if (pdata->slot[1].bus_width) { ret = atmci_init_slot(host, &pdata->slot[1], 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); - if (!ret) + if (!ret) { nr_slots++; + if (host->slot[1]->mmc->max_req_size > host->buf_size) + host->buf_size = + host->slot[1]->mmc->max_req_size; + } } if (!nr_slots) { @@ -2153,6 +2341,19 @@ static int __init atmci_probe(struct platform_device *pdev) goto err_init_slot; } + if (!host->caps.has_rwproof) { + host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size, + &host->buf_phys_addr, + GFP_KERNEL); + if (!host->buffer) { + ret = -ENOMEM; + dev_err(&pdev->dev, "buffer allocation failed\n"); + goto err_init_slot; + } + } + + setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host); + dev_info(&pdev->dev, "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", host->mapbase, irq, nr_slots); @@ -2179,6 +2380,10 @@ static int __exit atmci_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); + if (host->buffer) + dma_free_coherent(&pdev->dev, host->buf_size, + host->buffer, host->buf_phys_addr); + for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { if (host->slot[i]) atmci_cleanup_slot(host->slot[i], i); diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index c1f3673..7cf6c62 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1533,4 +1533,5 @@ module_exit(davinci_mmcsd_exit); MODULE_AUTHOR("Texas Instruments India"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MMC/SD driver for Davinci MMC controller"); +MODULE_ALIAS("platform:davinci_mmc"); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index ab3fc46..9bbf45f 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -100,8 +100,6 @@ struct dw_mci_slot { int last_detect_state; }; -static struct workqueue_struct *dw_mci_card_workqueue; - #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) { @@ -859,10 +857,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) int_mask = mci_readl(host, INTMASK); if (enb) { mci_writel(host, INTMASK, - (int_mask | (1 << SDMMC_INT_SDIO(slot->id)))); + (int_mask | SDMMC_INT_SDIO(slot->id))); } else { mci_writel(host, INTMASK, - (int_mask & ~(1 << SDMMC_INT_SDIO(slot->id)))); + (int_mask & ~SDMMC_INT_SDIO(slot->id))); } } @@ -1605,7 +1603,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & SDMMC_INT_CD) { mci_writel(host, RINTSTS, SDMMC_INT_CD); - queue_work(dw_mci_card_workqueue, &host->card_work); + queue_work(host->card_workqueue, &host->card_work); } /* Handle SDIO Interrupts */ @@ -1844,7 +1842,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) * Card may have been plugged in prior to boot so we * need to run the detect tasklet */ - queue_work(dw_mci_card_workqueue, &host->card_work); + queue_work(host->card_workqueue, &host->card_work); return 0; } @@ -2021,9 +2019,9 @@ int dw_mci_probe(struct dw_mci *host) mci_writel(host, CLKSRC, 0); tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); - dw_mci_card_workqueue = alloc_workqueue("dw-mci-card", + host->card_workqueue = alloc_workqueue("dw-mci-card", WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1); - if (!dw_mci_card_workqueue) + if (!host->card_workqueue) goto err_dmaunmap; INIT_WORK(&host->card_work, dw_mci_work_routine_card); ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host); @@ -2085,7 +2083,7 @@ err_init_slot: free_irq(host->irq, host); err_workqueue: - destroy_workqueue(dw_mci_card_workqueue); + destroy_workqueue(host->card_workqueue); err_dmaunmap: if (host->use_dma && host->dma_ops->exit) @@ -2119,7 +2117,7 @@ void dw_mci_remove(struct dw_mci *host) mci_writel(host, CLKSRC, 0); free_irq(host->irq, host); - destroy_workqueue(dw_mci_card_workqueue); + destroy_workqueue(host->card_workqueue); dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); if (host->use_dma && host->dma_ops->exit) diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c deleted file mode 100644 index ea0f3ce..0000000 --- a/drivers/mmc/host/imxmmc.c +++ /dev/null @@ -1,1169 +0,0 @@ -/* - * linux/drivers/mmc/host/imxmmc.c - Motorola i.MX MMCI driver - * - * Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de> - * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> - * - * derived from pxamci.c by Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/dma-mapping.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include <asm/dma.h> -#include <asm/irq.h> -#include <asm/sizes.h> -#include <mach/mmc.h> -#include <mach/imx-dma.h> - -#include "imxmmc.h" - -#define DRIVER_NAME "imx-mmc" - -#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \ - INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \ - INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO) - -struct imxmci_host { - struct mmc_host *mmc; - spinlock_t lock; - struct resource *res; - void __iomem *base; - int irq; - imx_dmach_t dma; - volatile unsigned int imask; - unsigned int power_mode; - unsigned int present; - struct imxmmc_platform_data *pdata; - - struct mmc_request *req; - struct mmc_command *cmd; - struct mmc_data *data; - - struct timer_list timer; - struct tasklet_struct tasklet; - unsigned int status_reg; - unsigned long pending_events; - /* Next two fields are there for CPU driven transfers to overcome SDHC deficiencies */ - u16 *data_ptr; - unsigned int data_cnt; - atomic_t stuck_timeout; - - unsigned int dma_nents; - unsigned int dma_size; - unsigned int dma_dir; - int dma_allocated; - - unsigned char actual_bus_width; - - int prev_cmd_code; - - struct clk *clk; -}; - -#define IMXMCI_PEND_IRQ_b 0 -#define IMXMCI_PEND_DMA_END_b 1 -#define IMXMCI_PEND_DMA_ERR_b 2 -#define IMXMCI_PEND_WAIT_RESP_b 3 -#define IMXMCI_PEND_DMA_DATA_b 4 -#define IMXMCI_PEND_CPU_DATA_b 5 -#define IMXMCI_PEND_CARD_XCHG_b 6 -#define IMXMCI_PEND_SET_INIT_b 7 -#define IMXMCI_PEND_STARTED_b 8 - -#define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b) -#define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b) -#define IMXMCI_PEND_DMA_ERR_m (1 << IMXMCI_PEND_DMA_ERR_b) -#define IMXMCI_PEND_WAIT_RESP_m (1 << IMXMCI_PEND_WAIT_RESP_b) -#define IMXMCI_PEND_DMA_DATA_m (1 << IMXMCI_PEND_DMA_DATA_b) -#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b) -#define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b) -#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b) -#define IMXMCI_PEND_STARTED_m (1 << IMXMCI_PEND_STARTED_b) - -static void imxmci_stop_clock(struct imxmci_host *host) -{ - int i = 0; - u16 reg; - - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg & ~STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); - while (i < 0x1000) { - if (!(i & 0x7f)) { - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_STOP_CLK, - host->base + MMC_REG_STR_STP_CLK); - } - - reg = readw(host->base + MMC_REG_STATUS); - if (!(reg & STATUS_CARD_BUS_CLK_RUN)) { - /* Check twice before cut */ - reg = readw(host->base + MMC_REG_STATUS); - if (!(reg & STATUS_CARD_BUS_CLK_RUN)) - return; - } - - i++; - } - dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n"); -} - -static int imxmci_start_clock(struct imxmci_host *host) -{ - unsigned int trials = 0; - unsigned int delay_limit = 128; - unsigned long flags; - u16 reg; - - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg & ~STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK); - - clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); - - /* - * Command start of the clock, this usually succeeds in less - * then 6 delay loops, but during card detection (low clockrate) - * it takes up to 5000 delay loops and sometimes fails for the first time - */ - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); - - do { - unsigned int delay = delay_limit; - - while (delay--) { - reg = readw(host->base + MMC_REG_STATUS); - if (reg & STATUS_CARD_BUS_CLK_RUN) { - /* Check twice before cut */ - reg = readw(host->base + MMC_REG_STATUS); - if (reg & STATUS_CARD_BUS_CLK_RUN) - return 0; - } - - if (test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) - return 0; - } - - local_irq_save(flags); - /* - * Ensure, that request is not doubled under all possible circumstances. - * It is possible, that cock running state is missed, because some other - * IRQ or schedule delays this function execution and the clocks has - * been already stopped by other means (response processing, SDHC HW) - */ - if (!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) { - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_START_CLK, - host->base + MMC_REG_STR_STP_CLK); - } - local_irq_restore(flags); - - } while (++trials < 256); - - dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); - - return -1; -} - -static void imxmci_softreset(struct imxmci_host *host) -{ - int i; - - /* reset sequence */ - writew(0x08, host->base + MMC_REG_STR_STP_CLK); - writew(0x0D, host->base + MMC_REG_STR_STP_CLK); - - for (i = 0; i < 8; i++) - writew(0x05, host->base + MMC_REG_STR_STP_CLK); - - writew(0xff, host->base + MMC_REG_RES_TO); - writew(512, host->base + MMC_REG_BLK_LEN); - writew(1, host->base + MMC_REG_NOB); -} - -static int imxmci_busy_wait_for_status(struct imxmci_host *host, - unsigned int *pstat, unsigned int stat_mask, - int timeout, const char *where) -{ - int loops = 0; - - while (!(*pstat & stat_mask)) { - loops += 2; - if (loops >= timeout) { - dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n", - where, *pstat, stat_mask); - return -1; - } - udelay(2); - *pstat |= readw(host->base + MMC_REG_STATUS); - } - if (!loops) - return 0; - - /* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */ - if (!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock >= 8000000)) - dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n", - loops, where, *pstat, stat_mask); - return loops; -} - -static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data) -{ - unsigned int nob = data->blocks; - unsigned int blksz = data->blksz; - unsigned int datasz = nob * blksz; - int i; - - if (data->flags & MMC_DATA_STREAM) - nob = 0xffff; - - host->data = data; - data->bytes_xfered = 0; - - writew(nob, host->base + MMC_REG_NOB); - writew(blksz, host->base + MMC_REG_BLK_LEN); - - /* - * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise. - * We are in big troubles for non-512 byte transfers according to note in the paragraph - * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least. - * The situation is even more complex in reality. The SDHC in not able to handle wll - * partial FIFO fills and reads. The length has to be rounded up to burst size multiple. - * This is required for SCR read at least. - */ - if (datasz < 512) { - host->dma_size = datasz; - if (data->flags & MMC_DATA_READ) { - host->dma_dir = DMA_FROM_DEVICE; - - /* Hack to enable read SCR */ - writew(1, host->base + MMC_REG_NOB); - writew(512, host->base + MMC_REG_BLK_LEN); - } else { - host->dma_dir = DMA_TO_DEVICE; - } - - /* Convert back to virtual address */ - host->data_ptr = (u16 *)sg_virt(data->sg); - host->data_cnt = 0; - - clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events); - set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events); - - return; - } - - if (data->flags & MMC_DATA_READ) { - host->dma_dir = DMA_FROM_DEVICE; - host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - - imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz, - host->res->start + MMC_REG_BUFFER_ACCESS, - DMA_MODE_READ); - - /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/ - CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN; - } else { - host->dma_dir = DMA_TO_DEVICE; - - host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - - imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz, - host->res->start + MMC_REG_BUFFER_ACCESS, - DMA_MODE_WRITE); - - /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/ - CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN; - } - -#if 1 /* This code is there only for consistency checking and can be disabled in future */ - host->dma_size = 0; - for (i = 0; i < host->dma_nents; i++) - host->dma_size += data->sg[i].length; - - if (datasz > host->dma_size) { - dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n", - datasz, host->dma_size); - } -#endif - - host->dma_size = datasz; - - wmb(); - - set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events); - clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events); - - /* start DMA engine for read, write is delayed after initial response */ - if (host->dma_dir == DMA_FROM_DEVICE) - imx_dma_enable(host->dma); -} - -static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat) -{ - unsigned long flags; - u32 imask; - - WARN_ON(host->cmd != NULL); - host->cmd = cmd; - - /* Ensure, that clock are stopped else command programming and start fails */ - imxmci_stop_clock(host); - - if (cmd->flags & MMC_RSP_BUSY) - cmdat |= CMD_DAT_CONT_BUSY; - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_R1: /* short CRC, OPCODE */ - case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */ - cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1; - break; - case MMC_RSP_R2: /* long 136 bit + CRC */ - cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2; - break; - case MMC_RSP_R3: /* short */ - cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3; - break; - default: - break; - } - - if (test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events)) - cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */ - - if (host->actual_bus_width == MMC_BUS_WIDTH_4) - cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; - - writew(cmd->opcode, host->base + MMC_REG_CMD); - writew(cmd->arg >> 16, host->base + MMC_REG_ARGH); - writew(cmd->arg & 0xffff, host->base + MMC_REG_ARGL); - writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT); - - atomic_set(&host->stuck_timeout, 0); - set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events); - - - imask = IMXMCI_INT_MASK_DEFAULT; - imask &= ~INT_MASK_END_CMD_RES; - if (cmdat & CMD_DAT_CONT_DATA_ENABLE) { - /* imask &= ~INT_MASK_BUF_READY; */ - imask &= ~INT_MASK_DATA_TRAN; - if (cmdat & CMD_DAT_CONT_WRITE) - imask &= ~INT_MASK_WRITE_OP_DONE; - if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) - imask &= ~INT_MASK_BUF_READY; - } - - spin_lock_irqsave(&host->lock, flags); - host->imask = imask; - writew(host->imask, host->base + MMC_REG_INT_MASK); - spin_unlock_irqrestore(&host->lock, flags); - - dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n", - cmd->opcode, cmd->opcode, imask); - - imxmci_start_clock(host); -} - -static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - - host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m | - IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m); - - host->imask = IMXMCI_INT_MASK_DEFAULT; - writew(host->imask, host->base + MMC_REG_INT_MASK); - - spin_unlock_irqrestore(&host->lock, flags); - - if (req && req->cmd) - host->prev_cmd_code = req->cmd->opcode; - - host->req = NULL; - host->cmd = NULL; - host->data = NULL; - mmc_request_done(host->mmc, req); -} - -static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - int data_error; - - if (test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) { - imx_dma_disable(host->dma); - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents, - host->dma_dir); - } - - if (stat & STATUS_ERR_MASK) { - dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", stat); - if (stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR)) - data->error = -EILSEQ; - else if (stat & STATUS_TIME_OUT_READ) - data->error = -ETIMEDOUT; - else - data->error = -EIO; - } else { - data->bytes_xfered = host->dma_size; - } - - data_error = data->error; - - host->data = NULL; - - return data_error; -} - -static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat) -{ - struct mmc_command *cmd = host->cmd; - int i; - u32 a, b, c; - struct mmc_data *data = host->data; - - if (!cmd) - return 0; - - host->cmd = NULL; - - if (stat & STATUS_TIME_OUT_RESP) { - dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n"); - cmd->error = -ETIMEDOUT; - } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) { - dev_dbg(mmc_dev(host->mmc), "cmd crc error\n"); - cmd->error = -EILSEQ; - } - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - for (i = 0; i < 4; i++) { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); - cmd->resp[i] = a << 16 | b; - } - } else { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); - c = readw(host->base + MMC_REG_RES_FIFO); - cmd->resp[0] = a << 24 | b << 8 | c >> 8; - } - } - - dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n", - cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error); - - if (data && !cmd->error && !(stat & STATUS_ERR_MASK)) { - if (host->req->data->flags & MMC_DATA_WRITE) { - - /* Wait for FIFO to be empty before starting DMA write */ - - stat = readw(host->base + MMC_REG_STATUS); - if (imxmci_busy_wait_for_status(host, &stat, - STATUS_APPL_BUFF_FE, - 40, "imxmci_cmd_done DMA WR") < 0) { - cmd->error = -EIO; - imxmci_finish_data(host, stat); - if (host->req) - imxmci_finish_request(host, host->req); - dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n", - stat); - return 0; - } - - if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) - imx_dma_enable(host->dma); - } - } else { - struct mmc_request *req; - imxmci_stop_clock(host); - req = host->req; - - if (data) - imxmci_finish_data(host, stat); - - if (req) - imxmci_finish_request(host, req); - else - dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n"); - } - - return 1; -} - -static int imxmci_data_done(struct imxmci_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - int data_error; - - if (!data) - return 0; - - data_error = imxmci_finish_data(host, stat); - - if (host->req->stop) { - imxmci_stop_clock(host); - imxmci_start_cmd(host, host->req->stop, 0); - } else { - struct mmc_request *req; - req = host->req; - if (req) - imxmci_finish_request(host, req); - else - dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n"); - } - - return 1; -} - -static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat) -{ - int i; - int burst_len; - int trans_done = 0; - unsigned int stat = *pstat; - - if (host->actual_bus_width != MMC_BUS_WIDTH_4) - burst_len = 16; - else - burst_len = 64; - - /* This is unfortunately required */ - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n", - stat); - - udelay(20); /* required for clocks < 8MHz*/ - - if (host->dma_dir == DMA_FROM_DEVICE) { - imxmci_busy_wait_for_status(host, &stat, - STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE | - STATUS_TIME_OUT_READ, - 50, "imxmci_cpu_driven_data read"); - - while ((stat & (STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE)) && - !(stat & STATUS_TIME_OUT_READ) && - (host->data_cnt < 512)) { - - udelay(20); /* required for clocks < 8MHz*/ - - for (i = burst_len; i >= 2 ; i -= 2) { - u16 data; - data = readw(host->base + MMC_REG_BUFFER_ACCESS); - udelay(10); /* required for clocks < 8MHz*/ - if (host->data_cnt+2 <= host->dma_size) { - *(host->data_ptr++) = data; - } else { - if (host->data_cnt < host->dma_size) - *(u8 *)(host->data_ptr) = data; - } - host->data_cnt += 2; - } - - stat = readw(host->base + MMC_REG_STATUS); - - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n", - host->data_cnt, burst_len, stat); - } - - if ((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512)) - trans_done = 1; - - if (host->dma_size & 0x1ff) - stat &= ~STATUS_CRC_READ_ERR; - - if (stat & STATUS_TIME_OUT_READ) { - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read timeout STATUS = 0x%x\n", - stat); - trans_done = -1; - } - - } else { - imxmci_busy_wait_for_status(host, &stat, - STATUS_APPL_BUFF_FE, - 20, "imxmci_cpu_driven_data write"); - - while ((stat & STATUS_APPL_BUFF_FE) && - (host->data_cnt < host->dma_size)) { - if (burst_len >= host->dma_size - host->data_cnt) { - burst_len = host->dma_size - host->data_cnt; - host->data_cnt = host->dma_size; - trans_done = 1; - } else { - host->data_cnt += burst_len; - } - - for (i = burst_len; i > 0 ; i -= 2) - writew(*(host->data_ptr++), host->base + MMC_REG_BUFFER_ACCESS); - - stat = readw(host->base + MMC_REG_STATUS); - - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n", - burst_len, stat); - } - } - - *pstat = stat; - - return trans_done; -} - -static void imxmci_dma_irq(int dma, void *devid) -{ - struct imxmci_host *host = devid; - u32 stat = readw(host->base + MMC_REG_STATUS); - - atomic_set(&host->stuck_timeout, 0); - host->status_reg = stat; - set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); - tasklet_schedule(&host->tasklet); -} - -static irqreturn_t imxmci_irq(int irq, void *devid) -{ - struct imxmci_host *host = devid; - u32 stat = readw(host->base + MMC_REG_STATUS); - int handled = 1; - - writew(host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT, - host->base + MMC_REG_INT_MASK); - - atomic_set(&host->stuck_timeout, 0); - host->status_reg = stat; - set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); - set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); - tasklet_schedule(&host->tasklet); - - return IRQ_RETVAL(handled); -} - -static void imxmci_tasklet_fnc(unsigned long data) -{ - struct imxmci_host *host = (struct imxmci_host *)data; - u32 stat; - unsigned int data_dir_mask = 0; /* STATUS_WR_CRC_ERROR_CODE_MASK */ - int timeout = 0; - - if (atomic_read(&host->stuck_timeout) > 4) { - char *what; - timeout = 1; - stat = readw(host->base + MMC_REG_STATUS); - host->status_reg = stat; - if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) - if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) - what = "RESP+DMA"; - else - what = "RESP"; - else - if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) - if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events)) - what = "DATA"; - else - what = "DMA"; - else - what = "???"; - - dev_err(mmc_dev(host->mmc), - "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n", - what, stat, - readw(host->base + MMC_REG_INT_MASK)); - dev_err(mmc_dev(host->mmc), - "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n", - readw(host->base + MMC_REG_CMD_DAT_CONT), - readw(host->base + MMC_REG_BLK_LEN), - readw(host->base + MMC_REG_NOB), - CCR(host->dma)); - dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n", - host->cmd ? host->cmd->opcode : 0, - host->prev_cmd_code, - 1 << host->actual_bus_width, host->dma_size); - } - - if (!host->present || timeout) - host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ | - STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR; - - if (test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) { - clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); - - stat = readw(host->base + MMC_REG_STATUS); - /* - * This is not required in theory, but there is chance to miss some flag - * which clears automatically by mask write, FreeScale original code keeps - * stat from IRQ time so do I - */ - stat |= host->status_reg; - - if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) - stat &= ~STATUS_CRC_READ_ERR; - - if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) { - imxmci_busy_wait_for_status(host, &stat, - STATUS_END_CMD_RESP | STATUS_ERR_MASK, - 20, "imxmci_tasklet_fnc resp (ERRATUM #4)"); - } - - if (stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) { - if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) - imxmci_cmd_done(host, stat); - if (host->data && (stat & STATUS_ERR_MASK)) - imxmci_data_done(host, stat); - } - - if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) { - stat |= readw(host->base + MMC_REG_STATUS); - if (imxmci_cpu_driven_data(host, &stat)) { - if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) - imxmci_cmd_done(host, stat); - atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m, - &host->pending_events); - imxmci_data_done(host, stat); - } - } - } - - if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) && - !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) { - - stat = readw(host->base + MMC_REG_STATUS); - /* Same as above */ - stat |= host->status_reg; - - if (host->dma_dir == DMA_TO_DEVICE) - data_dir_mask = STATUS_WRITE_OP_DONE; - else - data_dir_mask = STATUS_DATA_TRANS_DONE; - - if (stat & data_dir_mask) { - clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); - imxmci_data_done(host, stat); - } - } - - if (test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) { - - if (host->cmd) - imxmci_cmd_done(host, STATUS_TIME_OUT_RESP); - - if (host->data) - imxmci_data_done(host, STATUS_TIME_OUT_READ | - STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR); - - if (host->req) - imxmci_finish_request(host, host->req); - - mmc_detect_change(host->mmc, msecs_to_jiffies(100)); - - } -} - -static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct imxmci_host *host = mmc_priv(mmc); - unsigned int cmdat; - - WARN_ON(host->req != NULL); - - host->req = req; - - cmdat = 0; - - if (req->data) { - imxmci_setup_data(host, req->data); - - cmdat |= CMD_DAT_CONT_DATA_ENABLE; - - if (req->data->flags & MMC_DATA_WRITE) - cmdat |= CMD_DAT_CONT_WRITE; - - if (req->data->flags & MMC_DATA_STREAM) - cmdat |= CMD_DAT_CONT_STREAM_BLOCK; - } - - imxmci_start_cmd(host, req->cmd, cmdat); -} - -#define CLK_RATE 19200000 - -static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct imxmci_host *host = mmc_priv(mmc); - int prescaler; - - if (ios->bus_width == MMC_BUS_WIDTH_4) { - host->actual_bus_width = MMC_BUS_WIDTH_4; - imx_gpio_mode(PB11_PF_SD_DAT3); - BLR(host->dma) = 0; /* burst 64 byte read/write */ - } else { - host->actual_bus_width = MMC_BUS_WIDTH_1; - imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11); - BLR(host->dma) = 16; /* burst 16 byte read/write */ - } - - if (host->power_mode != ios->power_mode) { - switch (ios->power_mode) { - case MMC_POWER_OFF: - break; - case MMC_POWER_UP: - set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events); - break; - case MMC_POWER_ON: - break; - } - host->power_mode = ios->power_mode; - } - - if (ios->clock) { - unsigned int clk; - u16 reg; - - /* The prescaler is 5 for PERCLK2 equal to 96MHz - * then 96MHz / 5 = 19.2 MHz - */ - clk = clk_get_rate(host->clk); - prescaler = (clk + (CLK_RATE * 7) / 8) / CLK_RATE; - switch (prescaler) { - case 0: - case 1: prescaler = 0; - break; - case 2: prescaler = 1; - break; - case 3: prescaler = 2; - break; - case 4: prescaler = 4; - break; - default: - case 5: prescaler = 5; - break; - } - - dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n", - clk, prescaler); - - for (clk = 0; clk < 8; clk++) { - int x; - x = CLK_RATE / (1 << clk); - if (x <= ios->clock) - break; - } - - /* enable controller */ - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_ENABLE, - host->base + MMC_REG_STR_STP_CLK); - - imxmci_stop_clock(host); - writew((prescaler << 3) | clk, host->base + MMC_REG_CLK_RATE); - /* - * Under my understanding, clock should not be started there, because it would - * initiate SDHC sequencer and send last or random command into card - */ - /* imxmci_start_clock(host); */ - - dev_dbg(mmc_dev(host->mmc), - "MMC_CLK_RATE: 0x%08x\n", - readw(host->base + MMC_REG_CLK_RATE)); - } else { - imxmci_stop_clock(host); - } -} - -static int imxmci_get_ro(struct mmc_host *mmc) -{ - struct imxmci_host *host = mmc_priv(mmc); - - if (host->pdata && host->pdata->get_ro) - return !!host->pdata->get_ro(mmc_dev(mmc)); - /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. - */ - return -ENOSYS; -} - - -static const struct mmc_host_ops imxmci_ops = { - .request = imxmci_request, - .set_ios = imxmci_set_ios, - .get_ro = imxmci_get_ro, -}; - -static void imxmci_check_status(unsigned long data) -{ - struct imxmci_host *host = (struct imxmci_host *)data; - - if (host->pdata && host->pdata->card_present && - host->pdata->card_present(mmc_dev(host->mmc)) != host->present) { - host->present ^= 1; - dev_info(mmc_dev(host->mmc), "card %s\n", - host->present ? "inserted" : "removed"); - - set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events); - tasklet_schedule(&host->tasklet); - } - - if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) || - test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) { - atomic_inc(&host->stuck_timeout); - if (atomic_read(&host->stuck_timeout) > 4) - tasklet_schedule(&host->tasklet); - } else { - atomic_set(&host->stuck_timeout, 0); - - } - - mod_timer(&host->timer, jiffies + (HZ>>1)); -} - -static int __init imxmci_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct imxmci_host *host = NULL; - struct resource *r; - int ret = 0, irq; - u16 rev_no; - - pr_info("i.MX mmc driver\n"); - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!r || irq < 0) - return -ENXIO; - - r = request_mem_region(r->start, resource_size(r), pdev->name); - if (!r) - return -EBUSY; - - mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } - - mmc->ops = &imxmci_ops; - mmc->f_min = 150000; - mmc->f_max = CLK_RATE/2; - mmc->ocr_avail = MMC_VDD_32_33; - mmc->caps = MMC_CAP_4_BIT_DATA; - - /* MMC core transfer sizes tunable parameters */ - mmc->max_segs = 64; - mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */ - mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */ - mmc->max_blk_size = 2048; - mmc->max_blk_count = 65535; - - host = mmc_priv(mmc); - host->base = ioremap(r->start, resource_size(r)); - if (!host->base) { - ret = -ENOMEM; - goto out; - } - - host->mmc = mmc; - host->dma_allocated = 0; - host->pdata = pdev->dev.platform_data; - if (!host->pdata) - dev_warn(&pdev->dev, "No platform data provided!\n"); - - spin_lock_init(&host->lock); - host->res = r; - host->irq = irq; - - host->clk = clk_get(&pdev->dev, "perclk2"); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto out; - } - clk_enable(host->clk); - - imx_gpio_mode(PB8_PF_SD_DAT0); - imx_gpio_mode(PB9_PF_SD_DAT1); - imx_gpio_mode(PB10_PF_SD_DAT2); - /* Configured as GPIO with pull-up to ensure right MCC card mode */ - /* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */ - imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11); - /* imx_gpio_mode(PB11_PF_SD_DAT3); */ - imx_gpio_mode(PB12_PF_SD_CLK); - imx_gpio_mode(PB13_PF_SD_CMD); - - imxmci_softreset(host); - - rev_no = readw(host->base + MMC_REG_REV_NO); - if (rev_no != 0x390) { - dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n", - readw(host->base + MMC_REG_REV_NO)); - goto out; - } - - /* recommended in data sheet */ - writew(0x2db4, host->base + MMC_REG_READ_TO); - - host->imask = IMXMCI_INT_MASK_DEFAULT; - writew(host->imask, host->base + MMC_REG_INT_MASK); - - host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW); - if(host->dma < 0) { - dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n"); - ret = -EBUSY; - goto out; - } - host->dma_allocated = 1; - imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host); - RSSR(host->dma) = DMA_REQ_SDHC; - - tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host); - host->status_reg=0; - host->pending_events=0; - - ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host); - if (ret) - goto out; - - if (host->pdata && host->pdata->card_present) - host->present = host->pdata->card_present(mmc_dev(mmc)); - else /* if there is no way to detect assume that card is present */ - host->present = 1; - - init_timer(&host->timer); - host->timer.data = (unsigned long)host; - host->timer.function = imxmci_check_status; - add_timer(&host->timer); - mod_timer(&host->timer, jiffies + (HZ >> 1)); - - platform_set_drvdata(pdev, mmc); - - mmc_add_host(mmc); - - return 0; - -out: - if (host) { - if (host->dma_allocated) { - imx_dma_free(host->dma); - host->dma_allocated = 0; - } - if (host->clk) { - clk_disable(host->clk); - clk_put(host->clk); - } - if (host->base) - iounmap(host->base); - } - if (mmc) - mmc_free_host(mmc); - release_mem_region(r->start, resource_size(r)); - return ret; -} - -static int __exit imxmci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (mmc) { - struct imxmci_host *host = mmc_priv(mmc); - - tasklet_disable(&host->tasklet); - - del_timer_sync(&host->timer); - mmc_remove_host(mmc); - - free_irq(host->irq, host); - iounmap(host->base); - if (host->dma_allocated) { - imx_dma_free(host->dma); - host->dma_allocated = 0; - } - - tasklet_kill(&host->tasklet); - - clk_disable(host->clk); - clk_put(host->clk); - - release_mem_region(host->res->start, resource_size(host->res)); - - mmc_free_host(mmc); - } - return 0; -} - -#ifdef CONFIG_PM -static int imxmci_suspend(struct platform_device *dev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_suspend_host(mmc); - - return ret; -} - -static int imxmci_resume(struct platform_device *dev) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - struct imxmci_host *host; - int ret = 0; - - if (mmc) { - host = mmc_priv(mmc); - if (host) - set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events); - ret = mmc_resume_host(mmc); - } - - return ret; -} -#else -#define imxmci_suspend NULL -#define imxmci_resume NULL -#endif /* CONFIG_PM */ - -static struct platform_driver imxmci_driver = { - .remove = __exit_p(imxmci_remove), - .suspend = imxmci_suspend, - .resume = imxmci_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - } -}; - -static int __init imxmci_init(void) -{ - return platform_driver_probe(&imxmci_driver, imxmci_probe); -} - -static void __exit imxmci_exit(void) -{ - platform_driver_unregister(&imxmci_driver); -} - -module_init(imxmci_init); -module_exit(imxmci_exit); - -MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver"); -MODULE_AUTHOR("Sascha Hauer, Pengutronix"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-mmc"); diff --git a/drivers/mmc/host/imxmmc.h b/drivers/mmc/host/imxmmc.h deleted file mode 100644 index 09d5d4e..0000000 --- a/drivers/mmc/host/imxmmc.h +++ /dev/null @@ -1,64 +0,0 @@ -#define MMC_REG_STR_STP_CLK 0x00 -#define MMC_REG_STATUS 0x04 -#define MMC_REG_CLK_RATE 0x08 -#define MMC_REG_CMD_DAT_CONT 0x0C -#define MMC_REG_RES_TO 0x10 -#define MMC_REG_READ_TO 0x14 -#define MMC_REG_BLK_LEN 0x18 -#define MMC_REG_NOB 0x1C -#define MMC_REG_REV_NO 0x20 -#define MMC_REG_INT_MASK 0x24 -#define MMC_REG_CMD 0x28 -#define MMC_REG_ARGH 0x2C -#define MMC_REG_ARGL 0x30 -#define MMC_REG_RES_FIFO 0x34 -#define MMC_REG_BUFFER_ACCESS 0x38 - -#define STR_STP_CLK_IPG_CLK_GATE_DIS (1<<15) -#define STR_STP_CLK_IPG_PERCLK_GATE_DIS (1<<14) -#define STR_STP_CLK_ENDIAN (1<<5) -#define STR_STP_CLK_RESET (1<<3) -#define STR_STP_CLK_ENABLE (1<<2) -#define STR_STP_CLK_START_CLK (1<<1) -#define STR_STP_CLK_STOP_CLK (1<<0) -#define STATUS_CARD_PRESENCE (1<<15) -#define STATUS_SDIO_INT_ACTIVE (1<<14) -#define STATUS_END_CMD_RESP (1<<13) -#define STATUS_WRITE_OP_DONE (1<<12) -#define STATUS_DATA_TRANS_DONE (1<<11) -#define STATUS_WR_CRC_ERROR_CODE_MASK (3<<10) -#define STATUS_CARD_BUS_CLK_RUN (1<<8) -#define STATUS_APPL_BUFF_FF (1<<7) -#define STATUS_APPL_BUFF_FE (1<<6) -#define STATUS_RESP_CRC_ERR (1<<5) -#define STATUS_CRC_READ_ERR (1<<3) -#define STATUS_CRC_WRITE_ERR (1<<2) -#define STATUS_TIME_OUT_RESP (1<<1) -#define STATUS_TIME_OUT_READ (1<<0) -#define STATUS_ERR_MASK 0x2f -#define CLK_RATE_PRESCALER(x) ((x) & 0x7) -#define CLK_RATE_CLK_RATE(x) (((x) & 0x7) << 3) -#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1<<12) -#define CMD_DAT_CONT_STOP_READWAIT (1<<11) -#define CMD_DAT_CONT_START_READWAIT (1<<10) -#define CMD_DAT_CONT_BUS_WIDTH_1 (0<<8) -#define CMD_DAT_CONT_BUS_WIDTH_4 (2<<8) -#define CMD_DAT_CONT_INIT (1<<7) -#define CMD_DAT_CONT_BUSY (1<<6) -#define CMD_DAT_CONT_STREAM_BLOCK (1<<5) -#define CMD_DAT_CONT_WRITE (1<<4) -#define CMD_DAT_CONT_DATA_ENABLE (1<<3) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6) -#define INT_MASK_AUTO_CARD_DETECT (1<<6) -#define INT_MASK_DAT0_EN (1<<5) -#define INT_MASK_SDIO (1<<4) -#define INT_MASK_BUF_READY (1<<3) -#define INT_MASK_END_CMD_RES (1<<2) -#define INT_MASK_WRITE_OP_DONE (1<<1) -#define INT_MASK_DATA_TRAN (1<<0) -#define INT_ALL (0x7f) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index b6f3842..f0fcce4 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -15,6 +15,7 @@ #include <linux/device.h> #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/highmem.h> @@ -25,6 +26,7 @@ #include <linux/clk.h> #include <linux/scatterlist.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/regulator/consumer.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> @@ -1207,21 +1209,76 @@ static const struct mmc_host_ops mmci_ops = { .get_cd = mmci_get_cd, }; +#ifdef CONFIG_OF +static void mmci_dt_populate_generic_pdata(struct device_node *np, + struct mmci_platform_data *pdata) +{ + int bus_width = 0; + + pdata->gpio_wp = of_get_named_gpio(np, "wp-gpios", 0); + if (!pdata->gpio_wp) + pdata->gpio_wp = -1; + + pdata->gpio_cd = of_get_named_gpio(np, "cd-gpios", 0); + if (!pdata->gpio_cd) + pdata->gpio_cd = -1; + + if (of_get_property(np, "cd-inverted", NULL)) + pdata->cd_invert = true; + else + pdata->cd_invert = false; + + of_property_read_u32(np, "max-frequency", &pdata->f_max); + if (!pdata->f_max) + pr_warn("%s has no 'max-frequency' property\n", np->full_name); + + if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) + pdata->capabilities |= MMC_CAP_MMC_HIGHSPEED; + if (of_get_property(np, "mmc-cap-sd-highspeed", NULL)) + pdata->capabilities |= MMC_CAP_SD_HIGHSPEED; + + of_property_read_u32(np, "bus-width", &bus_width); + switch (bus_width) { + case 0 : + /* No bus-width supplied. */ + break; + case 4 : + pdata->capabilities |= MMC_CAP_4_BIT_DATA; + break; + case 8 : + pdata->capabilities |= MMC_CAP_8_BIT_DATA; + break; + default : + pr_warn("%s: Unsupported bus width\n", np->full_name); + } +} +#else +static void mmci_dt_populate_generic_pdata(struct device_node *np, + struct mmci_platform_data *pdata) +{ + return; +} +#endif + static int __devinit mmci_probe(struct amba_device *dev, const struct amba_id *id) { struct mmci_platform_data *plat = dev->dev.platform_data; + struct device_node *np = dev->dev.of_node; struct variant_data *variant = id->data; struct mmci_host *host; struct mmc_host *mmc; int ret; - /* must have platform data */ - if (!plat) { - ret = -EINVAL; - goto out; + /* Must have platform data or Device Tree. */ + if (!plat && !np) { + dev_err(&dev->dev, "No plat data or DT found\n"); + return -EINVAL; } + if (np) + mmci_dt_populate_generic_pdata(np, plat); + ret = amba_request_regions(dev, DRIVER_NAME); if (ret) goto out; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 887c0e5..552196c 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -169,11 +169,11 @@ struct mmc_omap_host { struct timer_list clk_timer; spinlock_t clk_lock; /* for changing enabled state */ unsigned int fclk_enabled:1; + struct workqueue_struct *mmc_omap_wq; struct omap_mmc_platform_data *pdata; }; -static struct workqueue_struct *mmc_omap_wq; static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot) { @@ -291,7 +291,7 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled) host->next_slot = new_slot; host->mmc = new_slot->mmc; spin_unlock_irqrestore(&host->slot_lock, flags); - queue_work(mmc_omap_wq, &host->slot_release_work); + queue_work(host->mmc_omap_wq, &host->slot_release_work); return; } @@ -459,7 +459,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) } host->stop_data = data; - queue_work(mmc_omap_wq, &host->send_stop_work); + queue_work(host->mmc_omap_wq, &host->send_stop_work); } static void @@ -639,7 +639,7 @@ mmc_omap_cmd_timer(unsigned long data) OMAP_MMC_WRITE(host, IE, 0); disable_irq(host->irq); host->abort = 1; - queue_work(mmc_omap_wq, &host->cmd_abort_work); + queue_work(host->mmc_omap_wq, &host->cmd_abort_work); } spin_unlock_irqrestore(&host->slot_lock, flags); } @@ -828,7 +828,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) host->abort = 1; OMAP_MMC_WRITE(host, IE, 0); disable_irq_nosync(host->irq); - queue_work(mmc_omap_wq, &host->cmd_abort_work); + queue_work(host->mmc_omap_wq, &host->cmd_abort_work); return IRQ_HANDLED; } @@ -1389,13 +1389,13 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot) tasklet_kill(&slot->cover_tasklet); del_timer_sync(&slot->cover_timer); - flush_workqueue(mmc_omap_wq); + flush_workqueue(slot->host->mmc_omap_wq); mmc_remove_host(mmc); mmc_free_host(mmc); } -static int __init mmc_omap_probe(struct platform_device *pdev) +static int __devinit mmc_omap_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_omap_host *host = NULL; @@ -1497,6 +1497,10 @@ static int __init mmc_omap_probe(struct platform_device *pdev) host->reg_shift = (cpu_is_omap7xx() ? 1 : 2); + host->mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0); + if (!host->mmc_omap_wq) + goto err_plat_cleanup; + return 0; err_plat_cleanup: @@ -1518,7 +1522,7 @@ err_free_mem_region: return ret; } -static int mmc_omap_remove(struct platform_device *pdev) +static int __devexit mmc_omap_remove(struct platform_device *pdev) { struct mmc_omap_host *host = platform_get_drvdata(pdev); int i; @@ -1542,6 +1546,7 @@ static int mmc_omap_remove(struct platform_device *pdev) iounmap(host->virt_base); release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); + destroy_workqueue(host->mmc_omap_wq); kfree(host); @@ -1599,7 +1604,8 @@ static int mmc_omap_resume(struct platform_device *pdev) #endif static struct platform_driver mmc_omap_driver = { - .remove = mmc_omap_remove, + .probe = mmc_omap_probe, + .remove = __devexit_p(mmc_omap_remove), .suspend = mmc_omap_suspend, .resume = mmc_omap_resume, .driver = { @@ -1608,29 +1614,7 @@ static struct platform_driver mmc_omap_driver = { }, }; -static int __init mmc_omap_init(void) -{ - int ret; - - mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0); - if (!mmc_omap_wq) - return -ENOMEM; - - ret = platform_driver_probe(&mmc_omap_driver, mmc_omap_probe); - if (ret) - destroy_workqueue(mmc_omap_wq); - return ret; -} - -static void __exit mmc_omap_exit(void) -{ - platform_driver_unregister(&mmc_omap_driver); - destroy_workqueue(mmc_omap_wq); -} - -module_init(mmc_omap_init); -module_exit(mmc_omap_exit); - +module_platform_driver(mmc_omap_driver); MODULE_DESCRIPTION("OMAP Multimedia Card driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 56d4499..a9fc714 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -85,12 +85,14 @@ #define BRR_ENABLE (1 << 5) #define DTO_ENABLE (1 << 20) #define INIT_STREAM (1 << 1) +#define ACEN_ACMD12 (1 << 2) #define DP_SELECT (1 << 21) #define DDIR (1 << 4) #define DMA_EN 0x1 #define MSBS (1 << 5) #define BCE (1 << 1) #define FOUR_BIT (1 << 1) +#define DDR (1 << 19) #define DW8 (1 << 5) #define CC 0x1 #define TC 0x02 @@ -115,6 +117,7 @@ #define OMAP_MMC_MAX_CLOCK 52000000 #define DRIVER_NAME "omap_hsmmc" +#define AUTO_CMD12 (1 << 0) /* Auto CMD12 support */ /* * One controller can have multiple slots, like on some omap boards using * omap.c controller driver. Luckily this is not currently done on any known @@ -167,7 +170,6 @@ struct omap_hsmmc_host { int use_dma, dma_ch; int dma_line_tx, dma_line_rx; int slot_id; - int got_dbclk; int response_busy; int context_loss; int vdd; @@ -175,6 +177,7 @@ struct omap_hsmmc_host { int reqs_blocked; int use_reg; int req_in_progress; + unsigned int flags; struct omap_hsmmc_next next_data; struct omap_mmc_platform_data *pdata; @@ -520,6 +523,10 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host) u32 con; con = OMAP_HSMMC_READ(host->base, CON); + if (ios->timing == MMC_TIMING_UHS_DDR50) + con |= DDR; /* configure in DDR mode */ + else + con &= ~DDR; switch (ios->bus_width) { case MMC_BUS_WIDTH_8: OMAP_HSMMC_WRITE(host->base, CON, con | DW8); @@ -766,6 +773,8 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, cmdtype = 0x3; cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22); + if ((host->flags & AUTO_CMD12) && mmc_op_multi(cmd->opcode)) + cmdreg |= ACEN_ACMD12; if (data) { cmdreg |= DP_SELECT | MSBS | BCE; @@ -796,11 +805,12 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data) static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) { int dma_ch; + unsigned long flags; - spin_lock(&host->irq_lock); + spin_lock_irqsave(&host->irq_lock, flags); host->req_in_progress = 0; dma_ch = host->dma_ch; - spin_unlock(&host->irq_lock); + spin_unlock_irqrestore(&host->irq_lock, flags); omap_hsmmc_disable_irq(host); /* Do not complete the request if DMA is still in progress */ @@ -837,11 +847,14 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data) else data->bytes_xfered = 0; - if (!data->stop) { + if (data->stop && ((!(host->flags & AUTO_CMD12)) || data->error)) { + omap_hsmmc_start_command(host, data->stop, NULL); + } else { + if (data->stop) + data->stop->resp[0] = OMAP_HSMMC_READ(host->base, + RSP76); omap_hsmmc_request_done(host, data->mrq); - return; } - omap_hsmmc_start_command(host, data->stop, NULL); } /* @@ -874,13 +887,14 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) { int dma_ch; + unsigned long flags; host->data->error = errno; - spin_lock(&host->irq_lock); + spin_lock_irqsave(&host->irq_lock, flags); dma_ch = host->dma_ch; host->dma_ch = -1; - spin_unlock(&host->irq_lock); + spin_unlock_irqrestore(&host->irq_lock, flags); if (host->use_dma && dma_ch != -1) { dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, @@ -1082,7 +1096,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) /* Disable the clocks */ pm_runtime_put_sync(host->dev); - if (host->got_dbclk) + if (host->dbclk) clk_disable(host->dbclk); /* Turn the power off */ @@ -1093,7 +1107,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd); pm_runtime_get_sync(host->dev); - if (host->got_dbclk) + if (host->dbclk) clk_enable(host->dbclk); if (ret != 0) @@ -1234,6 +1248,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) struct omap_hsmmc_host *host = cb_data; struct mmc_data *data; int dma_ch, req_in_progress; + unsigned long flags; if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n", @@ -1241,9 +1256,9 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) return; } - spin_lock(&host->irq_lock); + spin_lock_irqsave(&host->irq_lock, flags); if (host->dma_ch < 0) { - spin_unlock(&host->irq_lock); + spin_unlock_irqrestore(&host->irq_lock, flags); return; } @@ -1253,7 +1268,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) /* Fire up the next transfer. */ omap_hsmmc_config_dma_params(host, data, data->sg + host->dma_sg_idx); - spin_unlock(&host->irq_lock); + spin_unlock_irqrestore(&host->irq_lock, flags); return; } @@ -1264,7 +1279,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) req_in_progress = host->req_in_progress; dma_ch = host->dma_ch; host->dma_ch = -1; - spin_unlock(&host->irq_lock); + spin_unlock_irqrestore(&host->irq_lock, flags); omap_free_dma(dma_ch); @@ -1844,6 +1859,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) host->mapbase = res->start + pdata->reg_offset; host->base = ioremap(host->mapbase, SZ_4K); host->power_mode = MMC_POWER_OFF; + host->flags = AUTO_CMD12; host->next_data.cookie = 1; platform_set_drvdata(pdev, host); @@ -1885,21 +1901,17 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) omap_hsmmc_context_save(host); - if (cpu_is_omap2430()) { - host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); - /* - * MMC can still work without debounce clock. - */ - if (IS_ERR(host->dbclk)) - dev_warn(mmc_dev(host->mmc), - "Failed to get debounce clock\n"); - else - host->got_dbclk = 1; - - if (host->got_dbclk) - if (clk_enable(host->dbclk) != 0) - dev_dbg(mmc_dev(host->mmc), "Enabling debounce" - " clk failed\n"); + host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); + /* + * MMC can still work without debounce clock. + */ + if (IS_ERR(host->dbclk)) { + dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n"); + host->dbclk = NULL; + } else if (clk_enable(host->dbclk) != 0) { + dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n"); + clk_put(host->dbclk); + host->dbclk = NULL; } /* Since we do only SG emulation, we can have as many segs @@ -1969,7 +1981,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) ret = request_threaded_irq(mmc_slot(host).card_detect_irq, NULL, omap_hsmmc_detect, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), @@ -2019,7 +2031,7 @@ err_irq: pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); clk_put(host->fclk); - if (host->got_dbclk) { + if (host->dbclk) { clk_disable(host->dbclk); clk_put(host->dbclk); } @@ -2030,7 +2042,9 @@ err1: err_alloc: omap_hsmmc_gpio_free(pdata); err: - release_mem_region(res->start, resource_size(res)); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); return ret; } @@ -2052,7 +2066,7 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev) pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); clk_put(host->fclk); - if (host->got_dbclk) { + if (host->dbclk) { clk_disable(host->dbclk); clk_put(host->dbclk); } @@ -2110,7 +2124,7 @@ static int omap_hsmmc_suspend(struct device *dev) OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); } - if (host->got_dbclk) + if (host->dbclk) clk_disable(host->dbclk); err: pm_runtime_put_sync(host->dev); @@ -2131,7 +2145,7 @@ static int omap_hsmmc_resume(struct device *dev) pm_runtime_get_sync(host->dev); - if (host->got_dbclk) + if (host->dbclk) clk_enable(host->dbclk); if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 6dfa82e..1fe32df 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -75,8 +75,6 @@ static int __devinit sdhci_probe(struct platform_device *pdev) struct spear_sdhci *sdhci; int ret; - BUG_ON(pdev == NULL); - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iomem) { ret = -ENOMEM; @@ -84,18 +82,18 @@ static int __devinit sdhci_probe(struct platform_device *pdev) goto err; } - if (!request_mem_region(iomem->start, resource_size(iomem), - "spear-sdhci")) { + if (!devm_request_mem_region(&pdev->dev, iomem->start, + resource_size(iomem), "spear-sdhci")) { ret = -EBUSY; dev_dbg(&pdev->dev, "cannot request region\n"); goto err; } - sdhci = kzalloc(sizeof(*sdhci), GFP_KERNEL); + sdhci = devm_kzalloc(&pdev->dev, sizeof(*sdhci), GFP_KERNEL); if (!sdhci) { ret = -ENOMEM; dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); - goto err_kzalloc; + goto err; } /* clk enable */ @@ -103,13 +101,13 @@ static int __devinit sdhci_probe(struct platform_device *pdev) if (IS_ERR(sdhci->clk)) { ret = PTR_ERR(sdhci->clk); dev_dbg(&pdev->dev, "Error getting clock\n"); - goto err_clk_get; + goto err; } ret = clk_enable(sdhci->clk); if (ret) { dev_dbg(&pdev->dev, "Error enabling clock\n"); - goto err_clk_enb; + goto put_clk; } /* overwrite platform_data */ @@ -124,7 +122,7 @@ static int __devinit sdhci_probe(struct platform_device *pdev) if (IS_ERR(host)) { ret = PTR_ERR(host); dev_dbg(&pdev->dev, "error allocating host\n"); - goto err_alloc_host; + goto disable_clk; } host->hw_name = "sdhci"; @@ -132,17 +130,18 @@ static int __devinit sdhci_probe(struct platform_device *pdev) host->irq = platform_get_irq(pdev, 0); host->quirks = SDHCI_QUIRK_BROKEN_ADMA; - host->ioaddr = ioremap(iomem->start, resource_size(iomem)); + host->ioaddr = devm_ioremap(&pdev->dev, iomem->start, + resource_size(iomem)); if (!host->ioaddr) { ret = -ENOMEM; dev_dbg(&pdev->dev, "failed to remap registers\n"); - goto err_ioremap; + goto free_host; } ret = sdhci_add_host(host); if (ret) { dev_dbg(&pdev->dev, "error adding host\n"); - goto err_add_host; + goto free_host; } platform_set_drvdata(pdev, host); @@ -161,11 +160,12 @@ static int __devinit sdhci_probe(struct platform_device *pdev) if (sdhci->data->card_power_gpio >= 0) { int val = 0; - ret = gpio_request(sdhci->data->card_power_gpio, "sdhci"); + ret = devm_gpio_request(&pdev->dev, + sdhci->data->card_power_gpio, "sdhci"); if (ret < 0) { dev_dbg(&pdev->dev, "gpio request fail: %d\n", sdhci->data->card_power_gpio); - goto err_pgpio_request; + goto set_drvdata; } if (sdhci->data->power_always_enb) @@ -177,60 +177,48 @@ static int __devinit sdhci_probe(struct platform_device *pdev) if (ret) { dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", sdhci->data->card_power_gpio); - goto err_pgpio_direction; + goto set_drvdata; } } if (sdhci->data->card_int_gpio >= 0) { - ret = gpio_request(sdhci->data->card_int_gpio, "sdhci"); + ret = devm_gpio_request(&pdev->dev, sdhci->data->card_int_gpio, + "sdhci"); if (ret < 0) { dev_dbg(&pdev->dev, "gpio request fail: %d\n", sdhci->data->card_int_gpio); - goto err_igpio_request; + goto set_drvdata; } ret = gpio_direction_input(sdhci->data->card_int_gpio); if (ret) { dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", sdhci->data->card_int_gpio); - goto err_igpio_direction; + goto set_drvdata; } - ret = request_irq(gpio_to_irq(sdhci->data->card_int_gpio), + ret = devm_request_irq(&pdev->dev, + gpio_to_irq(sdhci->data->card_int_gpio), sdhci_gpio_irq, IRQF_TRIGGER_LOW, mmc_hostname(host->mmc), pdev); if (ret) { dev_dbg(&pdev->dev, "gpio request irq fail: %d\n", sdhci->data->card_int_gpio); - goto err_igpio_request_irq; + goto set_drvdata; } } return 0; -err_igpio_request_irq: -err_igpio_direction: - if (sdhci->data->card_int_gpio >= 0) - gpio_free(sdhci->data->card_int_gpio); -err_igpio_request: -err_pgpio_direction: - if (sdhci->data->card_power_gpio >= 0) - gpio_free(sdhci->data->card_power_gpio); -err_pgpio_request: +set_drvdata: platform_set_drvdata(pdev, NULL); sdhci_remove_host(host, 1); -err_add_host: - iounmap(host->ioaddr); -err_ioremap: +free_host: sdhci_free_host(host); -err_alloc_host: +disable_clk: clk_disable(sdhci->clk); -err_clk_enb: +put_clk: clk_put(sdhci->clk); -err_clk_get: - kfree(sdhci); -err_kzalloc: - release_mem_region(iomem->start, resource_size(iomem)); err: dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret); return ret; @@ -239,35 +227,19 @@ err: static int __devexit sdhci_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); - struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); - int dead; + int dead = 0; u32 scratch; - if (sdhci->data) { - if (sdhci->data->card_int_gpio >= 0) { - free_irq(gpio_to_irq(sdhci->data->card_int_gpio), pdev); - gpio_free(sdhci->data->card_int_gpio); - } - - if (sdhci->data->card_power_gpio >= 0) - gpio_free(sdhci->data->card_power_gpio); - } - platform_set_drvdata(pdev, NULL); - dead = 0; scratch = readl(host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) dead = 1; sdhci_remove_host(host, dead); - iounmap(host->ioaddr); sdhci_free_host(host); clk_disable(sdhci->clk); clk_put(sdhci->clk); - kfree(sdhci); - if (iomem) - release_mem_region(iomem->start, resource_size(iomem)); return 0; } diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index ff5a169..b38d8a7 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -32,8 +32,13 @@ #include "sdhci-pltfm.h" +/* Tegra SDHOST controller vendor register definitions */ +#define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120 +#define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 + #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) +#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) struct sdhci_tegra_soc_data { struct sdhci_pltfm_data *pdata; @@ -120,6 +125,25 @@ static irqreturn_t carddetect_irq(int irq, void *data) return IRQ_HANDLED; }; +static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; + + if (!(mask & SDHCI_RESET_ALL)) + return; + + /* Erratum: Enable SDHCI spec v3.00 support */ + if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) { + u32 misc_ctrl; + + misc_ctrl = sdhci_readb(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); + misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; + sdhci_writeb(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); + } +} + static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -148,6 +172,7 @@ static struct sdhci_ops tegra_sdhci_ops = { .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, .platform_8bit_width = tegra_sdhci_8bit, + .platform_reset_exit = tegra_sdhci_reset_exit, }; #ifdef CONFIG_ARCH_TEGRA_2x_SOC @@ -178,6 +203,7 @@ static struct sdhci_pltfm_data sdhci_tegra30_pdata = { static struct sdhci_tegra_soc_data soc_data_tegra30 = { .pdata = &sdhci_tegra30_pdata, + .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300, }; #endif diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ccefdeb..e626732 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -680,8 +680,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } if (count >= 0xF) { - pr_warning("%s: Too large timeout requested for CMD%d!\n", - mmc_hostname(host->mmc), cmd->opcode); + pr_warning("%s: Too large timeout 0x%x requested for CMD%d!\n", + mmc_hostname(host->mmc), count, cmd->opcode); count = 0xE; } |