From 8dea78da5cee153b8af9c07a2745f6c55057fe12 Mon Sep 17 00:00:00 2001 From: Jonathan Herman Date: Thu, 17 Jan 2013 16:15:55 -0500 Subject: Patched in Tegra support. --- drivers/mmc/Makefile | 3 +- drivers/mmc/card/Kconfig | 9 + drivers/mmc/card/block.c | 847 +++++++-------------- drivers/mmc/card/mmc_test.c | 259 +++++-- drivers/mmc/card/queue.c | 42 +- drivers/mmc/card/sdio_uart.c | 68 +- drivers/mmc/core/Kconfig | 17 + drivers/mmc/core/Makefile | 2 +- drivers/mmc/core/bus.c | 64 +- drivers/mmc/core/core.c | 1092 ++++++++++----------------- drivers/mmc/core/core.h | 5 +- drivers/mmc/core/debugfs.c | 52 +- drivers/mmc/core/host.c | 71 +- drivers/mmc/core/host.h | 22 + drivers/mmc/core/mmc.c | 636 +++------------- drivers/mmc/core/mmc_ops.c | 160 ++-- drivers/mmc/core/mmc_ops.h | 2 + drivers/mmc/core/quirks.c | 12 - drivers/mmc/core/sd.c | 349 +++++---- drivers/mmc/core/sd_ops.c | 9 +- drivers/mmc/core/sdio.c | 190 +++-- drivers/mmc/core/sdio_bus.c | 38 +- drivers/mmc/core/sdio_cis.c | 4 +- drivers/mmc/core/sdio_io.c | 52 +- drivers/mmc/core/sdio_irq.c | 28 +- drivers/mmc/core/sdio_ops.c | 41 +- drivers/mmc/core/slot-gpio.c | 200 ----- drivers/mmc/host/Kconfig | 114 +-- drivers/mmc/host/Makefile | 13 +- drivers/mmc/host/atmel-mci-regs.h | 242 +++--- drivers/mmc/host/atmel-mci.c | 1421 ++++++++++-------------------------- drivers/mmc/host/au1xmmc.c | 135 ++-- drivers/mmc/host/bfin_sdh.c | 235 +++--- drivers/mmc/host/cb710-mmc.c | 19 +- drivers/mmc/host/davinci_mmc.c | 353 +++++---- drivers/mmc/host/dw_mmc-exynos.c | 253 ------- drivers/mmc/host/dw_mmc-pci.c | 147 ---- drivers/mmc/host/dw_mmc-pltfm.c | 136 ---- drivers/mmc/host/dw_mmc-pltfm.h | 20 - drivers/mmc/host/dw_mmc.c | 982 +++++++++---------------- drivers/mmc/host/dw_mmc.h | 48 +- drivers/mmc/host/jz4740_mmc.c | 24 +- drivers/mmc/host/mmc_spi.c | 23 +- drivers/mmc/host/mmci.c | 371 +++------- drivers/mmc/host/mmci.h | 19 +- drivers/mmc/host/msm_sdcc.c | 107 ++- drivers/mmc/host/msm_sdcc.h | 6 +- drivers/mmc/host/mvsdio.c | 47 +- drivers/mmc/host/mxcmmc.c | 183 ++--- drivers/mmc/host/mxs-mmc.c | 478 ++++++------ drivers/mmc/host/of_mmc_spi.c | 4 +- drivers/mmc/host/omap.c | 506 +++++++------ drivers/mmc/host/omap_hsmmc.c | 1049 ++++++++++++++------------ drivers/mmc/host/pxamci.c | 69 +- drivers/mmc/host/rtsx_pci_sdmmc.c | 1348 ---------------------------------- drivers/mmc/host/s3cmci.c | 45 +- drivers/mmc/host/sdhci-acpi.c | 312 -------- drivers/mmc/host/sdhci-cns3xxx.c | 24 +- drivers/mmc/host/sdhci-dove.c | 161 +--- drivers/mmc/host/sdhci-esdhc-imx.c | 233 ++---- drivers/mmc/host/sdhci-esdhc.h | 8 +- drivers/mmc/host/sdhci-of-esdhc.c | 210 +----- drivers/mmc/host/sdhci-of-hlwd.c | 24 +- drivers/mmc/host/sdhci-pci-data.c | 5 - drivers/mmc/host/sdhci-pci.c | 391 ++-------- drivers/mmc/host/sdhci-pltfm.c | 84 +-- drivers/mmc/host/sdhci-pltfm.h | 8 +- drivers/mmc/host/sdhci-pxav2.c | 88 +-- drivers/mmc/host/sdhci-pxav3.c | 124 +--- drivers/mmc/host/sdhci-s3c.c | 460 +++--------- drivers/mmc/host/sdhci-spear.c | 207 ++---- drivers/mmc/host/sdhci-tegra.c | 1109 ++++++++++++++++++++++++---- drivers/mmc/host/sdhci.c | 996 +++++++++---------------- drivers/mmc/host/sdhci.h | 24 +- drivers/mmc/host/sdricoh_cs.c | 1 - drivers/mmc/host/sh_mmcif.c | 1016 +++++++++----------------- drivers/mmc/host/sh_mobile_sdhi.c | 215 ++---- drivers/mmc/host/tifm_sd.c | 39 +- drivers/mmc/host/tmio_mmc.c | 24 +- drivers/mmc/host/tmio_mmc.h | 27 +- drivers/mmc/host/tmio_mmc_dma.c | 20 +- drivers/mmc/host/tmio_mmc_pio.c | 398 ++++------ drivers/mmc/host/ushc.c | 12 +- drivers/mmc/host/via-sdmmc.c | 25 +- drivers/mmc/host/vub300.c | 17 +- drivers/mmc/host/wbsd.c | 50 +- drivers/mmc/host/wmt-sdmmc.c | 1029 -------------------------- 87 files changed, 6733 insertions(+), 13279 deletions(-) delete mode 100644 drivers/mmc/core/slot-gpio.c delete mode 100644 drivers/mmc/host/dw_mmc-exynos.c delete mode 100644 drivers/mmc/host/dw_mmc-pci.c delete mode 100644 drivers/mmc/host/dw_mmc-pltfm.c delete mode 100644 drivers/mmc/host/dw_mmc-pltfm.h delete mode 100644 drivers/mmc/host/rtsx_pci_sdmmc.c delete mode 100644 drivers/mmc/host/sdhci-acpi.c delete mode 100644 drivers/mmc/host/sdhci-pci-data.c delete mode 100644 drivers/mmc/host/wmt-sdmmc.c (limited to 'drivers/mmc') diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 400756ec7c4..12eef393e21 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -6,4 +6,5 @@ subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG obj-$(CONFIG_MMC) += core/ obj-$(CONFIG_MMC) += card/ -obj-$(subst m,y,$(CONFIG_MMC)) += host/ +obj-$(CONFIG_MMC) += host/ + diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig index 3b1f783bf92..ebb4afe6c70 100644 --- a/drivers/mmc/card/Kconfig +++ b/drivers/mmc/card/Kconfig @@ -50,6 +50,15 @@ config MMC_BLOCK_BOUNCE If unsure, say Y here. +config MMC_BLOCK_DEFERRED_RESUME + bool "Deferr MMC layer resume until I/O is requested" + depends on MMC_BLOCK + default n + help + Say Y here to enable deferred MMC resume until I/O + is requested. This will reduce overall resume latency and + save power when theres an SD card inserted but not being used. + config SDIO_UART tristate "SDIO UART/GPS class support" help diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 21056b9ef0a..2bd93d7a517 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -41,6 +41,7 @@ #include #include +#include #include #include "queue.h" @@ -57,7 +58,8 @@ MODULE_ALIAS("mmc:block"); #define INAND_CMD38_ARG_SECERASE 0x80 #define INAND_CMD38_ARG_SECTRIM1 0x81 #define INAND_CMD38_ARG_SECTRIM2 0x88 -#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ + +#define MMC_CMD_RETRIES 10 static DEFINE_MUTEX(block_mutex); @@ -94,11 +96,6 @@ struct mmc_blk_data { unsigned int read_only; unsigned int part_type; unsigned int name_idx; - unsigned int reset_done; -#define MMC_BLK_READ BIT(0) -#define MMC_BLK_WRITE BIT(1) -#define MMC_BLK_DISCARD BIT(2) -#define MMC_BLK_SECDISCARD BIT(3) /* * Only set in main mmc_blk_data associated @@ -107,8 +104,6 @@ struct mmc_blk_data { */ unsigned int part_curr; struct device_attribute force_ro; - struct device_attribute power_ro_lock; - int area_type; }; static DEFINE_MUTEX(open_lock); @@ -116,21 +111,16 @@ static DEFINE_MUTEX(open_lock); enum mmc_blk_status { MMC_BLK_SUCCESS = 0, MMC_BLK_PARTIAL, - MMC_BLK_CMD_ERR, MMC_BLK_RETRY, - MMC_BLK_ABORT, + MMC_BLK_RETRY_SINGLE, MMC_BLK_DATA_ERR, - MMC_BLK_ECC_ERR, - MMC_BLK_NOMEDIUM, + MMC_BLK_CMD_ERR, + MMC_BLK_ABORT, }; module_param(perdev_minors, int, 0444); MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); -static inline int mmc_blk_part_switch(struct mmc_card *card, - struct mmc_blk_data *md); -static int get_card_status(struct mmc_card *card, u32 *status, int retries); - static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) { struct mmc_blk_data *md; @@ -148,11 +138,7 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) static inline int mmc_get_devidx(struct gendisk *disk) { - int devmaj = MAJOR(disk_devt(disk)); - int devidx = MINOR(disk_devt(disk)) / perdev_minors; - - if (!devmaj) - devidx = disk->first_minor / perdev_minors; + int devidx = disk->first_minor / perdev_minors; return devidx; } @@ -172,70 +158,6 @@ static void mmc_blk_put(struct mmc_blk_data *md) mutex_unlock(&open_lock); } -static ssize_t power_ro_lock_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int ret; - struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); - struct mmc_card *card = md->queue.card; - int locked = 0; - - if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN) - locked = 2; - else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN) - locked = 1; - - ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); - - return ret; -} - -static ssize_t power_ro_lock_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int ret; - struct mmc_blk_data *md, *part_md; - struct mmc_card *card; - unsigned long set; - - if (kstrtoul(buf, 0, &set)) - return -EINVAL; - - if (set != 1) - return count; - - md = mmc_blk_get(dev_to_disk(dev)); - card = md->queue.card; - - mmc_claim_host(card->host); - - ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, - card->ext_csd.boot_ro_lock | - EXT_CSD_BOOT_WP_B_PWR_WP_EN, - card->ext_csd.part_time); - if (ret) - pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret); - else - card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; - - mmc_release_host(card->host); - - if (!ret) { - pr_info("%s: Locking boot partition ro until next power on\n", - md->disk->disk_name); - set_disk_ro(md->disk, 1); - - list_for_each_entry(part_md, &md->part, part) - if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) { - pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name); - set_disk_ro(part_md->disk, 1); - } - } - - mmc_blk_put(md); - return count; -} - static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -337,9 +259,6 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( goto idata_err; } - if (!idata->buf_bytes) - return idata; - idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); if (!idata->buf) { err = -ENOMEM; @@ -362,38 +281,6 @@ out: return ERR_PTR(err); } -static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, - u32 retries_max) -{ - int err; - u32 retry_count = 0; - - if (!status || !retries_max) - return -EINVAL; - - do { - err = get_card_status(card, status, 5); - if (err) - break; - - if (!R1_STATUS(*status) && - (R1_CURRENT_STATE(*status) != R1_STATE_PRG)) - break; /* RPMB programming operation complete */ - - /* - * Rechedule to give the MMC device a chance to continue - * processing the previous command without being polled too - * frequently. - */ - usleep_range(1000, 5000); - } while (++retry_count < retries_max); - - if (retry_count == retries_max) - err = -EPERM; - - return err; -} - static int mmc_blk_ioctl_cmd(struct block_device *bdev, struct mmc_ioc_cmd __user *ic_ptr) { @@ -402,11 +289,9 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, struct mmc_card *card; struct mmc_command cmd = {0}; struct mmc_data data = {0}; - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; struct scatterlist sg; int err; - int is_rpmb = false; - u32 status = 0; /* * The caller must have CAP_SYS_RAWIO, and must be calling this on the @@ -420,80 +305,61 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, if (IS_ERR(idata)) return PTR_ERR(idata); - md = mmc_blk_get(bdev->bd_disk); - if (!md) { - err = -EINVAL; - goto cmd_err; - } - - if (md->area_type & MMC_BLK_DATA_AREA_RPMB) - is_rpmb = true; - - card = md->queue.card; - if (IS_ERR(card)) { - err = PTR_ERR(card); - goto cmd_done; - } - cmd.opcode = idata->ic.opcode; cmd.arg = idata->ic.arg; cmd.flags = idata->ic.flags; - if (idata->buf_bytes) { - data.sg = &sg; - data.sg_len = 1; - data.blksz = idata->ic.blksz; - data.blocks = idata->ic.blocks; - - sg_init_one(data.sg, idata->buf, idata->buf_bytes); - - if (idata->ic.write_flag) - data.flags = MMC_DATA_WRITE; - else - data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + data.blksz = idata->ic.blksz; + data.blocks = idata->ic.blocks; - /* data.flags must already be set before doing this. */ - mmc_set_data_timeout(&data, card); + sg_init_one(data.sg, idata->buf, idata->buf_bytes); - /* Allow overriding the timeout_ns for empirical tuning. */ - if (idata->ic.data_timeout_ns) - data.timeout_ns = idata->ic.data_timeout_ns; + if (idata->ic.write_flag) + data.flags = MMC_DATA_WRITE; + else + data.flags = MMC_DATA_READ; - if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { - /* - * Pretend this is a data transfer and rely on the - * host driver to compute timeout. When all host - * drivers support cmd.cmd_timeout for R1B, this - * can be changed to: - * - * mrq.data = NULL; - * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; - */ - data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; - } + mrq.cmd = &cmd; + mrq.data = &data; - mrq.data = &data; + md = mmc_blk_get(bdev->bd_disk); + if (!md) { + err = -EINVAL; + goto cmd_done; } - mrq.cmd = &cmd; + card = md->queue.card; + if (IS_ERR(card)) { + err = PTR_ERR(card); + goto cmd_done; + } mmc_claim_host(card->host); - err = mmc_blk_part_switch(card, md); - if (err) - goto cmd_rel_host; - if (idata->ic.is_acmd) { err = mmc_app_cmd(card->host, card); if (err) goto cmd_rel_host; } - if (is_rpmb) { - err = mmc_set_blockcount(card, data.blocks, - idata->ic.write_flag & (1 << 31)); - if (err) - goto cmd_rel_host; + /* data.flags must already be set before doing this. */ + mmc_set_data_timeout(&data, card); + /* Allow overriding the timeout_ns for empirical tuning. */ + if (idata->ic.data_timeout_ns) + data.timeout_ns = idata->ic.data_timeout_ns; + + if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { + /* + * Pretend this is a data transfer and rely on the host driver + * to compute timeout. When all host drivers support + * cmd.cmd_timeout for R1B, this can be changed to: + * + * mrq.data = NULL; + * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; + */ + data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; } mmc_wait_for_req(card->host, &mrq); @@ -531,24 +397,11 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, } } - if (is_rpmb) { - /* - * Ensure RPMB command has completed by polling CMD13 - * "Send Status". - */ - err = ioctl_rpmb_card_status_poll(card, &status, 5); - if (err) - dev_err(mmc_dev(card->host), - "%s: Card Status=0x%08X, error %d\n", - __func__, status, err); - } - cmd_rel_host: mmc_release_host(card->host); cmd_done: mmc_blk_put(md); -cmd_err: kfree(idata->buf); kfree(idata); return err; @@ -587,24 +440,19 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, { int ret; struct mmc_blk_data *main_md = mmc_get_drvdata(card); - if (main_md->part_curr == md->part_type) return 0; if (mmc_card_mmc(card)) { - u8 part_config = card->ext_csd.part_config; - - part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; - part_config |= md->part_type; + card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; + card->ext_csd.part_config |= md->part_type; ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_PART_CONFIG, part_config, + EXT_CSD_PART_CONFIG, card->ext_csd.part_config, card->ext_csd.part_time); if (ret) return ret; - - card->ext_csd.part_config = part_config; - } +} main_md->part_curr = md->part_type; return 0; @@ -616,9 +464,10 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) u32 result; __be32 *blocks; - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; + unsigned int timeout_us; struct scatterlist sg; @@ -638,12 +487,23 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) cmd.arg = 0; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + data.timeout_ns = card->csd.tacc_ns * 100; + data.timeout_clks = card->csd.tacc_clks * 100; + + timeout_us = data.timeout_ns / 1000; + timeout_us += data.timeout_clks * 1000 / + (card->host->ios.clock / 1000); + + if (timeout_us > 100000) { + data.timeout_ns = 100000000; + data.timeout_clks = 0; + } + data.blksz = 4; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; - mmc_set_data_timeout(&data, card); mrq.cmd = &cmd; mrq.data = &data; @@ -693,7 +553,6 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries) return err; } -#define ERR_NOMEDIUM 3 #define ERR_RETRY 2 #define ERR_ABORT 1 #define ERR_CONTINUE 0 @@ -714,18 +573,22 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error, req->rq_disk->disk_name, "timed out", name, status); /* If the status cmd initially failed, retry the r/w cmd */ - if (!status_valid) + if (!status_valid) { + pr_err("%s: status not valid, retrying timeout\n", req->rq_disk->disk_name); return ERR_RETRY; - + } /* * If it was a r/w cmd crc error, or illegal command * (eg, issued in wrong state) then retry - we should * have corrected the state problem above. */ - if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) + if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) { + pr_err("%s: command error, retrying timeout\n", req->rq_disk->disk_name); return ERR_RETRY; + } /* Otherwise abort the command */ + pr_err("%s: not retrying timeout\n", req->rq_disk->disk_name); return ERR_ABORT; default: @@ -755,15 +618,12 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error, * Otherwise we don't understand what happened, so abort. */ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, - struct mmc_blk_request *brq, int *ecc_err) + struct mmc_blk_request *brq) { bool prev_cmd_status_valid = true; u32 status, stop_status = 0; int err, retry; - if (mmc_card_removed(card)) - return ERR_NOMEDIUM; - /* * Try to get card status which indicates both the card state * and why there was no response. If the first attempt fails, @@ -780,18 +640,8 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, } /* We couldn't get a response from the card. Give up. */ - if (err) { - /* Check if the card is removed */ - if (mmc_detect_card_removed(card->host)) - return ERR_NOMEDIUM; + if (err) return ERR_ABORT; - } - - /* Flag ECC errors */ - if ((status & R1_CARD_ECC_FAILED) || - (brq->stop.resp[0] & R1_CARD_ECC_FAILED) || - (brq->cmd.resp[0] & R1_CARD_ECC_FAILED)) - *ecc_err = 1; /* * Check the current card state. If it is in some data transfer @@ -810,8 +660,6 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, */ if (err) return ERR_ABORT; - if (stop_status & R1_CARD_ECC_FAILED) - *ecc_err = 1; } /* Check for set block count errors */ @@ -824,10 +672,6 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error, prev_cmd_status_valid, status); - /* Data errors */ - if (!brq->stop.error) - return ERR_CONTINUE; - /* Now for stop errors. These aren't fatal to the transfer. */ pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n", req->rq_disk->disk_name, brq->stop.error, @@ -844,45 +688,12 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, return ERR_CONTINUE; } -static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, - int type) -{ - int err; - - if (md->reset_done & type) - return -EEXIST; - - md->reset_done |= type; - err = mmc_hw_reset(host); - /* Ensure we switch back to the correct partition */ - if (err != -EOPNOTSUPP) { - struct mmc_blk_data *main_md = mmc_get_drvdata(host->card); - int part_err; - - main_md->part_curr = main_md->part_type; - part_err = mmc_blk_part_switch(host->card, md); - if (part_err) { - /* - * We have failed to get back into the correct - * partition, so we need to abort the whole request. - */ - return -ENODEV; - } - } - return err; -} - -static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type) -{ - md->reset_done &= ~type; -} - static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; unsigned int from, nr, arg; - int err = 0, type = MMC_BLK_DISCARD; + int err = 0; if (!mmc_can_erase(card)) { err = -EOPNOTSUPP; @@ -892,13 +703,11 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) from = blk_rq_pos(req); nr = blk_rq_sectors(req); - if (mmc_can_discard(card)) - arg = MMC_DISCARD_ARG; - else if (mmc_can_trim(card)) + if (mmc_can_trim(card)) arg = MMC_TRIM_ARG; else arg = MMC_ERASE_ARG; -retry: + if (card->quirks & MMC_QUIRK_INAND_CMD38) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, INAND_CMD38_ARG_EXT_CSD, @@ -911,11 +720,9 @@ retry: } err = mmc_erase(card, from, nr, arg); out: - if (err == -EIO && !mmc_blk_reset(md, card->host, type)) - goto retry; - if (!err) - mmc_blk_reset_success(md, type); - blk_end_request(req, err, blk_rq_bytes(req)); + spin_lock_irq(&md->lock); + __blk_end_request(req, err, blk_rq_bytes(req)); + spin_unlock_irq(&md->lock); return err ? 0 : 1; } @@ -925,10 +732,10 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, { struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; - unsigned int from, nr, arg, trim_arg, erase_arg; - int err = 0, type = MMC_BLK_SECDISCARD; + unsigned int from, nr, arg; + int err = 0; - if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) { + if (!mmc_can_secure_erase_trim(card)) { err = -EOPNOTSUPP; goto out; } @@ -936,24 +743,11 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, from = blk_rq_pos(req); nr = blk_rq_sectors(req); - /* The sanitize operation is supported at v4.5 only */ - if (mmc_can_sanitize(card)) { - erase_arg = MMC_ERASE_ARG; - trim_arg = MMC_TRIM_ARG; - } else { - erase_arg = MMC_SECURE_ERASE_ARG; - trim_arg = MMC_SECURE_TRIM1_ARG; - } + if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr)) + arg = MMC_SECURE_TRIM1_ARG; + else + arg = MMC_SECURE_ERASE_ARG; - if (mmc_erase_group_aligned(card, from, nr)) - arg = erase_arg; - else if (mmc_can_trim(card)) - arg = trim_arg; - else { - err = -EINVAL; - goto out; - } -retry: if (card->quirks & MMC_QUIRK_INAND_CMD38) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, INAND_CMD38_ARG_EXT_CSD, @@ -962,42 +756,24 @@ retry: INAND_CMD38_ARG_SECERASE, 0); if (err) - goto out_retry; + goto out; } - err = mmc_erase(card, from, nr, arg); - if (err == -EIO) - goto out_retry; - if (err) - goto out; - - if (arg == MMC_SECURE_TRIM1_ARG) { + if (!err && arg == MMC_SECURE_TRIM1_ARG) { if (card->quirks & MMC_QUIRK_INAND_CMD38) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, INAND_CMD38_ARG_EXT_CSD, INAND_CMD38_ARG_SECTRIM2, 0); if (err) - goto out_retry; + goto out; } - err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG); - if (err == -EIO) - goto out_retry; - if (err) - goto out; } - - if (mmc_can_sanitize(card)) - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_SANITIZE_START, 1, 0); -out_retry: - if (err && !mmc_blk_reset(md, card->host, type)) - goto retry; - if (!err) - mmc_blk_reset_success(md, type); out: - blk_end_request(req, err, blk_rq_bytes(req)); + spin_lock_irq(&md->lock); + __blk_end_request(req, err, blk_rq_bytes(req)); + spin_unlock_irq(&md->lock); return err ? 0 : 1; } @@ -1005,16 +781,16 @@ out: static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; - struct mmc_card *card = md->queue.card; - int ret = 0; - ret = mmc_flush_cache(card); - if (ret) - ret = -EIO; - - blk_end_request_all(req, ret); + /* + * No-op, only service this because we need REQ_FUA for reliable + * writes. + */ + spin_lock_irq(&md->lock); + __blk_end_request_all(req, 0); + spin_unlock_irq(&md->lock); - return ret ? 0 : 1; + return 1; } /* @@ -1051,11 +827,11 @@ static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq, static int mmc_blk_err_check(struct mmc_card *card, struct mmc_async_req *areq) { + enum mmc_blk_status ret = MMC_BLK_SUCCESS; struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req, mmc_active); struct mmc_blk_request *brq = &mq_mrq->brq; struct request *req = mq_mrq->req; - int ecc_err = 0; /* * sbc.error indicates a problem with the set block count @@ -1067,15 +843,12 @@ static int mmc_blk_err_check(struct mmc_card *card, * stop.error indicates a problem with the stop command. Data * may have been transferred, or may still be transferring. */ - if (brq->sbc.error || brq->cmd.error || brq->stop.error || - brq->data.error) { - switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err)) { + if (brq->sbc.error || brq->cmd.error || brq->stop.error) { + switch (mmc_blk_cmd_recovery(card, req, brq)) { case ERR_RETRY: return MMC_BLK_RETRY; case ERR_ABORT: return MMC_BLK_ABORT; - case ERR_NOMEDIUM: - return MMC_BLK_NOMEDIUM; case ERR_CONTINUE: break; } @@ -1099,27 +872,13 @@ static int mmc_blk_err_check(struct mmc_card *card, */ if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { u32 status; - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS); do { int err = get_card_status(card, &status, 5); if (err) { - pr_err("%s: error %d requesting status\n", + printk(KERN_ERR "%s: error %d requesting status\n", req->rq_disk->disk_name, err); return MMC_BLK_CMD_ERR; } - - /* Timeout if the device never becomes ready for data - * and never leaves the program state. - */ - if (time_after(jiffies, timeout)) { - pr_err("%s: Card stuck in programming state!"\ - " %s %s\n", mmc_hostname(card->host), - req->rq_disk->disk_name, __func__); - - return MMC_BLK_CMD_ERR; - } /* * Some cards mishandle the status bits, * so make sure to check both the busy @@ -1137,21 +896,23 @@ static int mmc_blk_err_check(struct mmc_card *card, brq->cmd.resp[0], brq->stop.resp[0]); if (rq_data_dir(req) == READ) { - if (ecc_err) - return MMC_BLK_ECC_ERR; + if (brq->data.blocks > 1) { + /* Redo read one sector at a time */ + pr_warning("%s: retrying using single block read\n", + req->rq_disk->disk_name); + return MMC_BLK_RETRY_SINGLE; + } return MMC_BLK_DATA_ERR; } else { return MMC_BLK_CMD_ERR; } } - if (!brq->data.bytes_xfered) - return MMC_BLK_RETRY; + if (ret == MMC_BLK_SUCCESS && + blk_rq_bytes(req) != brq->data.bytes_xfered) + ret = MMC_BLK_PARTIAL; - if (blk_rq_bytes(req) != brq->data.bytes_xfered) - return MMC_BLK_PARTIAL; - - return MMC_BLK_SUCCESS; + return ret; } static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, @@ -1163,7 +924,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, struct mmc_blk_request *brq = &mqrq->brq; struct request *req = mqrq->req; struct mmc_blk_data *md = mq->data; - bool do_data_tag; /* * Reliable writes are used to implement Forced Unit Access and @@ -1185,6 +945,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, if (!mmc_card_blockaddr(card)) brq->cmd.arg <<= 9; brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + brq->cmd.retries = MMC_CMD_RETRIES; brq->data.blksz = 512; brq->stop.opcode = MMC_STOP_TRANSMISSION; brq->stop.arg = 0; @@ -1199,20 +960,13 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, if (brq->data.blocks > card->host->max_blk_count) brq->data.blocks = card->host->max_blk_count; - if (brq->data.blocks > 1) { - /* - * After a read error, we redo the request one sector - * at a time in order to accurately determine which - * sectors can be read successfully. - */ - if (disable_multi) - brq->data.blocks = 1; - - /* Some controllers can't do multiblock reads due to hw bugs */ - if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ && - rq_data_dir(req) == READ) - brq->data.blocks = 1; - } + /* + * After a read error, we redo the request one sector at a time + * in order to accurately determine which sectors can be read + * successfully. + */ + if (disable_multi && brq->data.blocks > 1) + brq->data.blocks = 1; if (brq->data.blocks > 1 || do_rel_wr) { /* SPI multiblock writes terminate using a special @@ -1239,16 +993,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, if (do_rel_wr) mmc_apply_rel_rw(brq, card, req); - /* - * Data tag is used only during writing meta data to speed - * up write and any subsequent read of this meta data - */ - do_data_tag = (card->ext_csd.data_tag_unit_size) && - (req->cmd_flags & REQ_META) && - (rq_data_dir(req) == WRITE) && - ((brq->data.blocks * brq->data.blksz) >= - card->ext_csd.data_tag_unit_size); - /* * Pre-defined multi-block transfers are preferable to * open ended-ones (and necessary for reliable writes). @@ -1267,13 +1011,13 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, * We'll avoid using CMD23-bounded multiblock writes for * these, while retaining features like reliable writes. */ - if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) && - (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) || - do_data_tag)) { + + if ((md->flags & MMC_BLK_CMD23) && + mmc_op_multi(brq->cmd.opcode) && + (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) { brq->sbc.opcode = MMC_SET_BLOCK_COUNT; brq->sbc.arg = brq->data.blocks | - (do_rel_wr ? (1 << 31) : 0) | - (do_data_tag ? (1 << 29) : 0); + (do_rel_wr ? (1 << 31) : 0); brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC; brq->mrq.sbc = &brq->sbc; } @@ -1308,40 +1052,15 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, mmc_queue_bounce_pre(mqrq); } -static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, - struct mmc_blk_request *brq, struct request *req, - int ret) -{ - /* - * If this is an SD card and we're writing, we can first - * mark the known good sectors as ok. - * - * If the card is not SD, we can still ok written sectors - * as reported by the controller (which might be less than - * the real number of written sectors, but never more). - */ - if (mmc_card_sd(card)) { - u32 blocks; - - blocks = mmc_sd_num_wr_blocks(card); - if (blocks != (u32)-1) { - ret = blk_end_request(req, 0, blocks << 9); - } - } else { - ret = blk_end_request(req, 0, brq->data.bytes_xfered); - } - return ret; -} - static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) { struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; struct mmc_blk_request *brq = &mq->mqrq_cur->brq; - int ret = 1, disable_multi = 0, retry = 0, type; + int ret = 1, disable_multi = 0, retry = 0; enum mmc_blk_status status; struct mmc_queue_req *mq_rq; - struct request *req = rqc; + struct request *req; struct mmc_async_req *areq; if (!rqc && !mq->mqrq_prev->req) @@ -1349,16 +1068,6 @@ 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 @@ -1370,7 +1079,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) mq_rq = container_of(areq, struct mmc_queue_req, mmc_active); brq = &mq_rq->brq; req = mq_rq->req; - type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; mmc_queue_bounce_post(mq_rq); switch (status) { @@ -1379,16 +1087,18 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) /* * A block was successfully transferred. */ - mmc_blk_reset_success(md, type); - ret = blk_end_request(req, 0, + spin_lock_irq(&md->lock); + ret = __blk_end_request(req, 0, brq->data.bytes_xfered); - /* - * If the blk_end_request function returns non-zero even - * though all data has been transferred and no errors - * were returned by the host controller, it's a bug. - */ + spin_unlock_irq(&md->lock); if (status == MMC_BLK_SUCCESS && ret) { - pr_err("%s BUG rq_tot %d d_xfer %d\n", + /* + * The blk_end_request has returned non zero + * even though all data is transfered and no + * erros returned by host. + * If this happen it's a bug. + */ + printk(KERN_ERR "%s BUG rq_tot %d d_xfer %d\n", __func__, blk_rq_bytes(req), brq->data.bytes_xfered); rqc = NULL; @@ -1396,53 +1106,33 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) } break; case MMC_BLK_CMD_ERR: - ret = mmc_blk_cmd_err(md, card, brq, req, ret); - if (!mmc_blk_reset(md, card->host, type)) - break; - goto cmd_abort; + goto cmd_err; + case MMC_BLK_RETRY_SINGLE: + disable_multi = 1; + break; case MMC_BLK_RETRY: if (retry++ < 5) break; - /* Fall through */ case MMC_BLK_ABORT: - if (!mmc_blk_reset(md, card->host, type)) - break; goto cmd_abort; - case MMC_BLK_DATA_ERR: { - int err; - - err = mmc_blk_reset(md, card->host, type); - if (!err) - break; - if (err == -ENODEV) - goto cmd_abort; - /* Fall through */ - } - case MMC_BLK_ECC_ERR: - if (brq->data.blocks > 1) { - /* Redo read one sector at a time */ - pr_warning("%s: retrying using single block read\n", - req->rq_disk->disk_name); - disable_multi = 1; - break; - } + case MMC_BLK_DATA_ERR: /* * After an error, we redo I/O one sector at a * time, so we only reach here after trying to * read a single sector. */ - ret = blk_end_request(req, -EIO, + spin_lock_irq(&md->lock); + ret = __blk_end_request(req, -EIO, brq->data.blksz); + spin_unlock_irq(&md->lock); if (!ret) goto start_new_req; break; - case MMC_BLK_NOMEDIUM: - goto cmd_abort; } if (ret) { /* - * In case of a incomplete request + * In case of a none complete request * prepare it again and resend. */ mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq); @@ -1450,13 +1140,40 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) } } while (ret); + if (brq->cmd.resp[0] & R1_URGENT_BKOPS) + mmc_card_set_need_bkops(card); + return 1; + cmd_err: + /* + * If this is an SD card and we're writing, we can first + * mark the known good sectors as ok. + * + * If the card is not SD, we can still ok written sectors + * as reported by the controller (which might be less than + * the real number of written sectors, but never more). + */ + if (mmc_card_sd(card)) { + u32 blocks; + + blocks = mmc_sd_num_wr_blocks(card); + if (blocks != (u32)-1) { + spin_lock_irq(&md->lock); + ret = __blk_end_request(req, 0, blocks << 9); + spin_unlock_irq(&md->lock); + } + } else { + spin_lock_irq(&md->lock); + ret = __blk_end_request(req, 0, brq->data.bytes_xfered); + spin_unlock_irq(&md->lock); + } + cmd_abort: - if (mmc_card_removed(card)) - req->cmd_flags |= REQ_QUIET; + spin_lock_irq(&md->lock); while (ret) - ret = blk_end_request(req, -EIO, blk_rq_cur_bytes(req)); + ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req)); + spin_unlock_irq(&md->lock); start_new_req: if (rqc) { @@ -1467,21 +1184,28 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) return 0; } +static int +mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card); + static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) { int ret; struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME + if (mmc_bus_needs_resume(card->host)) { + mmc_resume_bus(card->host); + mmc_blk_set_blksize(md, card); + } +#endif + if (req && !mq->mqrq_prev->req) /* claim host only for the first request */ mmc_claim_host(card->host); ret = mmc_blk_part_switch(card, md); if (ret) { - if (req) { - blk_end_request_all(req, -EIO); - } ret = 0; goto out; } @@ -1490,8 +1214,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) /* complete ongoing async transfer before issuing discard */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); - if (req->cmd_flags & REQ_SECURE && - !(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN)) + if (req->cmd_flags & REQ_SECURE) ret = mmc_blk_issue_secdiscard_rq(mq, req); else ret = mmc_blk_issue_discard_rq(mq, req); @@ -1501,6 +1224,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) mmc_blk_issue_rw_rq(mq, NULL); ret = mmc_blk_issue_flush(mq, req); } else { + /* Abort any current bk ops of eMMC card by issuing HPI */ + if (mmc_card_mmc(mq->card) && mmc_card_doing_bkops(mq->card)) + mmc_interrupt_hpi(mq->card); + ret = mmc_blk_issue_rw_rq(mq, req); } @@ -1521,8 +1248,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct device *parent, sector_t size, bool default_ro, - const char *subname, - int area_type) + const char *subname) { struct mmc_blk_data *md; int devidx, ret; @@ -1547,12 +1273,11 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, if (!subname) { md->name_idx = find_first_zero_bit(name_use, max_devices); __set_bit(md->name_idx, name_use); - } else + } + else md->name_idx = ((struct mmc_blk_data *) dev_to_disk(parent)->private_data)->name_idx; - md->area_type = area_type; - /* * Set the read-only status based on the supported commands * and the write protect switch. @@ -1583,8 +1308,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, md->disk->queue = md->queue.queue; md->disk->driverfs_dev = parent; set_disk_ro(md->disk, md->read_only || default_ro); - if (area_type & MMC_BLK_DATA_AREA_RPMB) - md->disk->flags |= GENHD_FL_NO_PART_SCAN; + md->disk->flags = GENHD_FL_EXT_DEVT; /* * As discussed on lkml, GENHD_FL_REMOVABLE should: @@ -1601,12 +1325,7 @@ 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 : ""); - 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); - + blk_queue_logical_block_size(md->queue.queue, 512); set_capacity(md->disk, size); if (mmc_host_cmd23(card->host)) { @@ -1653,8 +1372,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) size = card->csd.capacity << (card->csd.read_blkbits - 9); } - md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL, - MMC_BLK_DATA_AREA_MAIN); + md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL); return md; } @@ -1663,14 +1381,13 @@ static int mmc_blk_alloc_part(struct mmc_card *card, unsigned int part_type, sector_t size, bool default_ro, - const char *subname, - int area_type) + const char *subname) { char cap_str[10]; struct mmc_blk_data *part_md; part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro, - subname, area_type); + subname); if (IS_ERR(part_md)) return PTR_ERR(part_md); part_md->part_type = part_type; @@ -1678,53 +1395,60 @@ static int mmc_blk_alloc_part(struct mmc_card *card, string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2, cap_str, sizeof(cap_str)); - pr_info("%s: %s %s partition %u %s\n", + printk(KERN_INFO "%s: %s %s partition %u %s\n", part_md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), part_md->part_type, cap_str); return 0; } -/* MMC Physical partitions consist of two boot partitions and - * up to four general purpose partitions. - * For each partition enabled in EXT_CSD a block device will be allocatedi - * to provide access to the partition. - */ - static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) { - int idx, ret = 0; + int ret = 0; if (!mmc_card_mmc(card)) return 0; - for (idx = 0; idx < card->nr_parts; idx++) { - if (card->part[idx].size) { - ret = mmc_blk_alloc_part(card, md, - card->part[idx].part_cfg, - card->part[idx].size >> 9, - card->part[idx].force_ro, - card->part[idx].name, - card->part[idx].area_type); - if (ret) - return ret; - } + if (card->ext_csd.boot_size) { + ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0, + card->ext_csd.boot_size >> 9, + true, + "boot0"); + if (ret) + return ret; + ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT1, + card->ext_csd.boot_size >> 9, + true, + "boot1"); + if (ret) + return ret; } return ret; } -static void mmc_blk_remove_req(struct mmc_blk_data *md) +static int +mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) { - struct mmc_card *card; + int err; + mmc_claim_host(card->host); + err = mmc_set_blocklen(card, 512); + mmc_release_host(card->host); + + if (err) { + printk(KERN_ERR "%s: unable to set block size to 512: %d\n", + md->disk->disk_name, err); + return -EINVAL; + } + + return 0; +} + +static void mmc_blk_remove_req(struct mmc_blk_data *md) +{ if (md) { - card = md->queue.card; if (md->disk->flags & GENHD_FL_UP) { device_remove_file(disk_to_dev(md->disk), &md->force_ro); - if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && - card->ext_csd.boot_ro_lockable) - device_remove_file(disk_to_dev(md->disk), - &md->power_ro_lock); /* Stop new requests from getting into the queue */ del_gendisk(md->disk); @@ -1753,7 +1477,6 @@ static void mmc_blk_remove_parts(struct mmc_card *card, static int mmc_add_disk(struct mmc_blk_data *md) { int ret; - struct mmc_card *card = md->queue.card; add_disk(md->disk); md->force_ro.show = force_ro_show; @@ -1763,55 +1486,18 @@ static int mmc_add_disk(struct mmc_blk_data *md) md->force_ro.attr.mode = S_IRUGO | S_IWUSR; ret = device_create_file(disk_to_dev(md->disk), &md->force_ro); if (ret) - goto force_ro_fail; - - if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && - card->ext_csd.boot_ro_lockable) { - umode_t mode; - - if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS) - mode = S_IRUGO; - else - mode = S_IRUGO | S_IWUSR; - - md->power_ro_lock.show = power_ro_lock_show; - md->power_ro_lock.store = power_ro_lock_store; - sysfs_attr_init(&md->power_ro_lock.attr); - md->power_ro_lock.attr.mode = mode; - md->power_ro_lock.attr.name = - "ro_lock_until_next_power_on"; - ret = device_create_file(disk_to_dev(md->disk), - &md->power_ro_lock); - if (ret) - goto power_ro_lock_fail; - } - return ret; - -power_ro_lock_fail: - device_remove_file(disk_to_dev(md->disk), &md->force_ro); -force_ro_fail: - del_gendisk(md->disk); + del_gendisk(md->disk); return ret; } -#define CID_MANFID_SANDISK 0x2 -#define CID_MANFID_TOSHIBA 0x11 -#define CID_MANFID_MICRON 0x13 -#define CID_MANFID_SAMSUNG 0x15 - static const struct mmc_fixup blk_fixups[] = { - MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM04G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM08G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), /* * Some MMC cards experience performance degradation with CMD23 @@ -1821,48 +1507,19 @@ static const struct mmc_fixup blk_fixups[] = * * N.B. This doesn't affect SD cards. */ - MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_FIXUP("MMC08G", 0x11, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_FIXUP("MMC16G", 0x11, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), - - /* - * Some Micron MMC cards needs longer data read timeout than - * indicated in CSD. - */ - MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, - MMC_QUIRK_LONG_READ_TIME), - - /* - * On these Samsung MoviNAND parts, performing secure erase or - * secure trim can result in unrecoverable corruption due to a - * firmware bug. - */ - MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - END_FIXUP }; static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md, *part_md; + int err; char cap_str[10]; /* @@ -1875,9 +1532,13 @@ static int mmc_blk_probe(struct mmc_card *card) if (IS_ERR(md)) return PTR_ERR(md); + err = mmc_blk_set_blksize(md, card); + if (err) + goto out; + string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2, cap_str, sizeof(cap_str)); - pr_info("%s: %s %s %s %s\n", + printk(KERN_INFO "%s: %s %s %s %s\n", md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), cap_str, md->read_only ? "(ro)" : ""); @@ -1887,6 +1548,9 @@ static int mmc_blk_probe(struct mmc_card *card) mmc_set_drvdata(card, md); mmc_fixup_device(card, blk_fixups); +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME + mmc_set_bus_resume_policy(card->host, 1); +#endif if (mmc_add_disk(md)) goto out; @@ -1899,7 +1563,7 @@ static int mmc_blk_probe(struct mmc_card *card) out: mmc_blk_remove_parts(card, md); mmc_blk_remove_req(md); - return 0; + return err; } static void mmc_blk_remove(struct mmc_card *card) @@ -1912,10 +1576,13 @@ static void mmc_blk_remove(struct mmc_card *card) mmc_release_host(card->host); mmc_blk_remove_req(md); mmc_set_drvdata(card, NULL); +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME + mmc_set_bus_resume_policy(card->host, 0); +#endif } #ifdef CONFIG_PM -static int mmc_blk_suspend(struct mmc_card *card) +static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state) { struct mmc_blk_data *part_md; struct mmc_blk_data *md = mmc_get_drvdata(card); @@ -1935,6 +1602,10 @@ static int mmc_blk_resume(struct mmc_card *card) struct mmc_blk_data *md = mmc_get_drvdata(card); if (md) { +#ifndef CONFIG_MMC_BLOCK_DEFERRED_RESUME + mmc_blk_set_blksize(md, card); +#endif + /* * Resume involves the card going into idle state, * so current partition is always the main one. diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 759714ed6be..440b97d9e44 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -22,7 +22,6 @@ #include #include #include -#include #define RESULT_OK 0 #define RESULT_FAIL 1 @@ -170,6 +169,96 @@ struct mmc_test_async_req { struct mmc_test_card *test; }; +struct mmc_test_parameter { + const char *name; + long value; + long (*exec)(struct mmc_test_card *); + const char *input; +}; + +static long mmc_test_set_testcase(struct mmc_test_card *test); +static long mmc_test_set_clock(struct mmc_test_card *test); +static long mmc_test_set_bus_width(struct mmc_test_card *test); +static long mmc_test_set_timing(struct mmc_test_card *test); + + +static struct mmc_test_parameter mmc_test_parameter[] = { + { + .name = "Testcase Number", + .value = 1, + .exec = mmc_test_set_testcase, + .input = "-n", + }, + { + .name = "Clock Rate", + .value = -1, + .exec = mmc_test_set_clock, + .input = "-c", + }, + { + .name = "Bus Width", + .value = -1, + .exec = mmc_test_set_bus_width, + .input = "-b", + }, + { + .name = "Timing", + .value = -1, + .exec = mmc_test_set_timing, + .input = "-t", + }, +}; + +static long mmc_test_set_testcase(struct mmc_test_card *test) +{ + return 0; +} + +static long mmc_test_set_clock(struct mmc_test_card *test) +{ + long clock = mmc_test_parameter[1].value; + if (-1 == clock) + return test->card->host->ios.clock; + WARN_ON(clock < test->card->host->f_min); + if (clock > test->card->host->f_max) + clock = test->card->host->f_max; + + test->card->host->ios.clock = clock; + + return test->card->host->ios.clock; +} + +static long mmc_test_set_bus_width(struct mmc_test_card *test) +{ + long bus_width = mmc_test_parameter[2].value; + if (-1 == bus_width) + return test->card->host->ios.bus_width; + + test->card->host->ios.bus_width = bus_width; + + return test->card->host->ios.bus_width = bus_width; +} + +static long mmc_test_set_timing(struct mmc_test_card *test) +{ + long timing = mmc_test_parameter[3].value; + if (-1 == timing) + return test->card->host->ios.timing; + test->card->host->ios.timing = timing; + + return test->card->host->ios.timing; +} + +static void mmc_test_set_parameters(struct mmc_test_card *test) +{ + int i; + for (i = 0; i < ARRAY_SIZE(mmc_test_parameter); i++) { + printk(KERN_INFO "Parameter[%s] set to [%ld]\n", + mmc_test_parameter[i].name, + mmc_test_parameter[i].exec(test)); + } +} + /*******************************************************************/ /* General helper functions */ /*******************************************************************/ @@ -251,7 +340,7 @@ static int mmc_test_wait_busy(struct mmc_test_card *test) if (!busy && mmc_test_busy(&cmd)) { busy = 1; if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) - pr_info("%s: Warning: Host did not " + printk(KERN_INFO "%s: Warning: Host did not " "wait for busy state to end.\n", mmc_hostname(test->card->host)); } @@ -553,7 +642,7 @@ static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes, rate = mmc_test_rate(bytes, &ts); iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */ - pr_info("%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " + printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " "seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n", mmc_hostname(test->card->host), sectors, sectors >> 1, (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec, @@ -579,7 +668,7 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes, rate = mmc_test_rate(tot, &ts); iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */ - pr_info("%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " + printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " "%lu.%09lu seconds (%u kB/s, %u KiB/s, " "%u.%02u IOPS, sg_len %d)\n", mmc_hostname(test->card->host), count, sectors, count, @@ -1409,7 +1498,7 @@ static int mmc_test_multi_read_high(struct mmc_test_card *test) static int mmc_test_no_highmem(struct mmc_test_card *test) { - pr_info("%s: Highmem not configured - test skipped\n", + printk(KERN_INFO "%s: Highmem not configured - test skipped\n", mmc_hostname(test->card->host)); return 0; } @@ -1436,7 +1525,7 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz, t->max_seg_sz, &t->sg_len, min_sg_len); } if (err) - pr_info("%s: Failed to map sg list\n", + printk(KERN_INFO "%s: Failed to map sg list\n", mmc_hostname(test->card->host)); return err; } @@ -1581,7 +1670,6 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) t->max_segs = test->card->host->max_segs; t->max_seg_sz = test->card->host->max_seg_size; - t->max_seg_sz -= t->max_seg_sz % 512; t->max_tfr = t->max_sz; if (t->max_tfr >> 9 > test->card->host->max_blk_count) @@ -2137,7 +2225,7 @@ static int mmc_test_rw_multiple(struct mmc_test_card *test, return ret; err: - pr_info("[%s] error\n", __func__); + printk(KERN_INFO "[%s] error\n", __func__); return ret; } @@ -2151,7 +2239,7 @@ static int mmc_test_rw_multiple_size(struct mmc_test_card *test, if (rw->do_nonblock_req && ((!pre_req && post_req) || (pre_req && !post_req))) { - pr_info("error: only one of pre/post is defined\n"); + printk(KERN_INFO "error: only one of pre/post is defined\n"); return -EINVAL; } @@ -2330,31 +2418,6 @@ static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test) return mmc_test_rw_multiple_sg_len(test, &test_data); } -/* - * eMMC hardware reset. - */ -static int mmc_test_hw_reset(struct mmc_test_card *test) -{ - struct mmc_card *card = test->card; - struct mmc_host *host = card->host; - int err; - - err = mmc_hw_reset_check(host); - if (!err) - return RESULT_OK; - - if (err == -ENOSYS) - return RESULT_FAIL; - - if (err != -EOPNOTSUPP) - return err; - - if (!mmc_can_reset(card)) - return RESULT_UNSUP_CARD; - - return RESULT_UNSUP_HOST; -} - static const struct mmc_test_case mmc_test_cases[] = { { .name = "Basic write (no data verification)", @@ -2677,11 +2740,6 @@ static const struct mmc_test_case mmc_test_cases[] = { .run = mmc_test_profile_sglen_r_nonblock_perf, .cleanup = mmc_test_area_cleanup, }, - - { - .name = "eMMC hardware reset", - .run = mmc_test_hw_reset, - }, }; static DEFINE_MUTEX(mmc_test_lock); @@ -2692,25 +2750,27 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) { int i, ret; - pr_info("%s: Starting tests of card %s...\n", + printk(KERN_INFO "%s: Starting tests of card %s...\n", mmc_hostname(test->card->host), mmc_card_id(test->card)); mmc_claim_host(test->card->host); + mmc_test_set_parameters(test); + for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) { struct mmc_test_general_result *gr; if (testcase && ((i + 1) != testcase)) continue; - pr_info("%s: Test case %d. %s...\n", + printk(KERN_INFO "%s: Test case %d. %s...\n", mmc_hostname(test->card->host), i + 1, mmc_test_cases[i].name); if (mmc_test_cases[i].prepare) { ret = mmc_test_cases[i].prepare(test); if (ret) { - pr_info("%s: Result: Prepare " + printk(KERN_INFO "%s: Result: Prepare " "stage failed! (%d)\n", mmc_hostname(test->card->host), ret); @@ -2740,25 +2800,25 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) ret = mmc_test_cases[i].run(test); switch (ret) { case RESULT_OK: - pr_info("%s: Result: OK\n", + printk(KERN_INFO "%s: Result: OK\n", mmc_hostname(test->card->host)); break; case RESULT_FAIL: - pr_info("%s: Result: FAILED\n", + printk(KERN_INFO "%s: Result: FAILED\n", mmc_hostname(test->card->host)); break; case RESULT_UNSUP_HOST: - pr_info("%s: Result: UNSUPPORTED " + printk(KERN_INFO "%s: Result: UNSUPPORTED " "(by host)\n", mmc_hostname(test->card->host)); break; case RESULT_UNSUP_CARD: - pr_info("%s: Result: UNSUPPORTED " + printk(KERN_INFO "%s: Result: UNSUPPORTED " "(by card)\n", mmc_hostname(test->card->host)); break; default: - pr_info("%s: Result: ERROR (%d)\n", + printk(KERN_INFO "%s: Result: ERROR (%d)\n", mmc_hostname(test->card->host), ret); } @@ -2769,7 +2829,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) if (mmc_test_cases[i].cleanup) { ret = mmc_test_cases[i].cleanup(test); if (ret) { - pr_info("%s: Warning: Cleanup " + printk(KERN_INFO "%s: Warning: Cleanup " "stage failed! (%d)\n", mmc_hostname(test->card->host), ret); @@ -2779,7 +2839,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) mmc_release_host(test->card->host); - pr_info("%s: Tests completed.\n", + printk(KERN_INFO "%s: Tests completed.\n", mmc_hostname(test->card->host)); } @@ -2809,6 +2869,23 @@ static void mmc_test_free_result(struct mmc_card *card) static LIST_HEAD(mmc_test_file_test); +static void mmc_test_usage(struct seq_file *sf) +{ + int i = 0; + + seq_printf(sf, "\nHow to run test:" + "\necho [[param1 value1].... ] > test" + "\nExample:: echo 1 -b 4 -c 2500000 -t 2" + "\n\nSupported parameters in sequence\n"); + + for (i = 0; i < ARRAY_SIZE(mmc_test_parameter); i++) { + seq_printf(sf, "Parameter%d Name:[%s] option:[%s]\n", + i + 1, mmc_test_parameter[i].name, + mmc_test_parameter[i].input); + } + seq_printf(sf, "\'-1\' passed to take default value\n\n\n"); +} + static int mtf_test_show(struct seq_file *sf, void *data) { struct mmc_card *card = (struct mmc_card *)sf->private; @@ -2843,24 +2920,92 @@ static int mtf_test_open(struct inode *inode, struct file *file) return single_open(file, mtf_test_show, inode->i_private); } +static int mmc_test_extract_parameters(char *data_buf) +{ + char *running = NULL; + char *token = NULL; + const char delimiters[] = " "; + long value; + int i; + int set = 0; + + running = data_buf; + + /*Example: + * echo [[param1 value1] [param1 value1]] > test + * $] echo 1 > test | Execute testcase 1 + * $] echo 1 -c 2500000 | execute tesecase 1 and set clock to 2500000 + * $] echo 1 -b 4 -c 2500000 -t 2 | + * execute tesecase 1, set clock to 2500000, set bus_width 4, + * and set timing to 2 + */ + + while ((token = strsep(&running, delimiters))) { + if (strict_strtol(token, 10, &value)) { + /* [Param1 value1] combination + * Compare with available param list + */ + for (i = 0; i < ARRAY_SIZE(mmc_test_parameter); i++) { + if (!strcmp(mmc_test_parameter[i].input, + token)) { + /* Valid Option, extract following + * value and save it + */ + token = strsep(&running, delimiters); + if (strict_strtol(token, 10, + &(mmc_test_parameter[i].value))) { + + printk(KERN_ERR "wrong parameter value\n"); + return -EINVAL; + } else { + break; + } + } + } + if (i == ARRAY_SIZE(mmc_test_parameter)) { + printk(KERN_ERR "uknown mmc_test option\n"); + return -EINVAL; + } + } else { + /* Testcase number */ + if (!set) { + mmc_test_parameter[0].value = value; + set = 1; + } else { + printk(KERN_ERR "invalid options"); + return -EINVAL; + } + } + } + return 0; +} + static ssize_t mtf_test_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct seq_file *sf = (struct seq_file *)file->private_data; struct mmc_card *card = (struct mmc_card *)sf->private; struct mmc_test_card *test; - char lbuf[12]; + char *data_buf = NULL; long testcase; - if (count >= sizeof(lbuf)) - return -EINVAL; + data_buf = kzalloc(count, GFP_KERNEL); + if (data_buf == NULL) + return -ENOMEM; - if (copy_from_user(lbuf, buf, count)) + if (copy_from_user(data_buf, buf, count)) { + kfree(data_buf); return -EFAULT; - lbuf[count] = '\0'; + } + data_buf[strlen(data_buf) - 1] = '\0'; + if (mmc_test_extract_parameters(data_buf)) { + mmc_test_usage(sf); + return -EFAULT; + } - if (strict_strtol(lbuf, 10, &testcase)) - return -EINVAL; + kfree(data_buf); + + testcase = mmc_test_parameter[0].value; test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); if (!test) @@ -2950,7 +3095,7 @@ static void mmc_test_free_dbgfs_file(struct mmc_card *card) } static int __mmc_test_register_dbgfs_file(struct mmc_card *card, - const char *name, umode_t mode, const struct file_operations *fops) + const char *name, mode_t mode, const struct file_operations *fops) { struct dentry *file = NULL; struct mmc_test_dbgfs_file *df; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index fadf52eb5d7..5db38cbcea6 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -29,8 +29,6 @@ */ static int mmc_prep_request(struct request_queue *q, struct request *req) { - struct mmc_queue *mq = q->queuedata; - /* * We only like normal block requests and discards. */ @@ -39,9 +37,6 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) return BLKPREP_KILL; } - if (mq && mmc_card_removed(mq->card)) - return BLKPREP_KILL; - req->cmd_flags |= REQ_DONTPREP; return BLKPREP_OK; @@ -68,17 +63,13 @@ static int mmc_queue_thread(void *d) if (req || mq->mqrq_prev->req) { set_current_state(TASK_RUNNING); mq->issue_fn(mq, req); - + } else { /* - * Current request becomes previous request - * and vice versa. + * Since the queue is empty, start synchronous + * background ops if there is a request for it. */ - mq->mqrq_prev->brq.mrq.data = NULL; - mq->mqrq_prev->req = NULL; - tmp = mq->mqrq_prev; - mq->mqrq_prev = mq->mqrq_cur; - mq->mqrq_cur = tmp; - } else { + if (mmc_card_need_bkops(mq->card)) + mmc_bkops_start(mq->card, true); if (kthread_should_stop()) { set_current_state(TASK_RUNNING); break; @@ -87,6 +78,13 @@ static int mmc_queue_thread(void *d) schedule(); down(&mq->thread_sem); } + + /* Current request becomes previous request and vice versa. */ + mq->mqrq_prev->brq.mrq.data = NULL; + mq->mqrq_prev->req = NULL; + tmp = mq->mqrq_prev; + mq->mqrq_prev = mq->mqrq_cur; + mq->mqrq_cur = tmp; } while (1); up(&mq->thread_sem); @@ -99,7 +97,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_fn(struct request_queue *q) +static void mmc_request(struct request_queue *q) { struct mmc_queue *mq = q->queuedata; struct request *req; @@ -116,7 +114,7 @@ static void mmc_request_fn(struct request_queue *q) wake_up_process(mq->thread); } -static struct scatterlist *mmc_alloc_sg(int sg_len, int *err) +struct scatterlist *mmc_alloc_sg(int sg_len, int *err) { struct scatterlist *sg; @@ -142,13 +140,13 @@ static void mmc_queue_setup_discard(struct request_queue *q, queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); q->limits.max_discard_sectors = max_discard; - if (card->erased_byte == 0 && !mmc_can_discard(card)) + if (card->erased_byte == 0) q->limits.discard_zeroes_data = 1; q->limits.discard_granularity = card->pref_erase << 9; /* granularity must not be greater than max. discard */ if (card->pref_erase > max_discard) q->limits.discard_granularity = 0; - if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card)) + if (mmc_can_secure_erase_trim(card)) queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q); } @@ -174,10 +172,12 @@ 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_fn, lock); + mq->queue = blk_init_queue(mmc_request, 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; @@ -203,13 +203,13 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, if (bouncesz > 512) { mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mqrq_cur->bounce_buf) { - pr_warning("%s: unable to " + printk(KERN_WARNING "%s: unable to " "allocate bounce cur buffer\n", mmc_card_name(card)); } mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mqrq_prev->bounce_buf) { - pr_warning("%s: unable to " + printk(KERN_WARNING "%s: unable to " "allocate bounce prev buffer\n", mmc_card_name(card)); kfree(mqrq_cur->bounce_buf); diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index bd57a11acc7..c8c9edb3d7c 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -66,6 +66,8 @@ struct uart_icount { struct sdio_uart_port { struct tty_port port; + struct kref kref; + struct tty_struct *tty; unsigned int index; struct sdio_func *func; struct mutex func_lock; @@ -91,6 +93,7 @@ static int sdio_uart_add_port(struct sdio_uart_port *port) { int index, ret = -EBUSY; + kref_init(&port->kref); mutex_init(&port->func_lock); spin_lock_init(&port->write_lock); if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL)) @@ -120,15 +123,23 @@ static struct sdio_uart_port *sdio_uart_port_get(unsigned index) spin_lock(&sdio_uart_table_lock); port = sdio_uart_table[index]; if (port) - tty_port_get(&port->port); + kref_get(&port->kref); spin_unlock(&sdio_uart_table_lock); return port; } +static void sdio_uart_port_destroy(struct kref *kref) +{ + struct sdio_uart_port *port = + container_of(kref, struct sdio_uart_port, kref); + kfifo_free(&port->xmit_fifo); + kfree(port); +} + static void sdio_uart_port_put(struct sdio_uart_port *port) { - tty_port_put(&port->port); + kref_put(&port->kref, sdio_uart_port_destroy); } static void sdio_uart_port_remove(struct sdio_uart_port *port) @@ -507,7 +518,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) if (status & UART_MSR_DCTS) { port->icount.cts++; tty = tty_port_tty_get(&port->port); - if (tty && (tty->termios.c_cflag & CRTSCTS)) { + if (tty && (tty->termios->c_cflag & CRTSCTS)) { int cts = (status & UART_MSR_CTS); if (tty->hw_stopped) { if (cts) { @@ -660,12 +671,12 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE; port->mctrl = TIOCM_OUT2; - sdio_uart_change_speed(port, &tty->termios, NULL); + sdio_uart_change_speed(port, tty->termios, NULL); - if (tty->termios.c_cflag & CBAUD) + if (tty->termios->c_cflag & CBAUD) sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); - if (tty->termios.c_cflag & CRTSCTS) + if (tty->termios->c_cflag & CRTSCTS) if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) tty->hw_stopped = 1; @@ -726,14 +737,6 @@ static void sdio_uart_shutdown(struct tty_port *tport) sdio_uart_release_func(port); } -static void sdio_uart_port_destroy(struct tty_port *tport) -{ - struct sdio_uart_port *port = - container_of(tport, struct sdio_uart_port, port); - kfifo_free(&port->xmit_fifo); - kfree(port); -} - /** * sdio_uart_install - install method * @driver: the driver in use (sdio_uart in our case) @@ -747,12 +750,15 @@ static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty) { int idx = tty->index; struct sdio_uart_port *port = sdio_uart_port_get(idx); - int ret = tty_standard_install(driver, tty); + int ret = tty_init_termios(tty); - if (ret == 0) + if (ret == 0) { + tty_driver_kref_get(driver); + tty->count++; /* This is the ref sdio_uart_port get provided */ tty->driver_data = port; - else + driver->ttys[idx] = tty; + } else sdio_uart_port_put(port); return ret; } @@ -847,7 +853,7 @@ static void sdio_uart_throttle(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS)) + if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) return; if (sdio_uart_claim_func(port) != 0) @@ -858,7 +864,7 @@ static void sdio_uart_throttle(struct tty_struct *tty) sdio_uart_start_tx(port); } - if (tty->termios.c_cflag & CRTSCTS) + if (tty->termios->c_cflag & CRTSCTS) sdio_uart_clear_mctrl(port, TIOCM_RTS); sdio_uart_irq(port->func); @@ -869,7 +875,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS)) + if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) return; if (sdio_uart_claim_func(port) != 0) @@ -884,7 +890,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) } } - if (tty->termios.c_cflag & CRTSCTS) + if (tty->termios->c_cflag & CRTSCTS) sdio_uart_set_mctrl(port, TIOCM_RTS); sdio_uart_irq(port->func); @@ -895,12 +901,12 @@ static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct sdio_uart_port *port = tty->driver_data; - unsigned int cflag = tty->termios.c_cflag; + unsigned int cflag = tty->termios->c_cflag; if (sdio_uart_claim_func(port) != 0) return; - sdio_uart_change_speed(port, &tty->termios, old_termios); + sdio_uart_change_speed(port, tty->termios, old_termios); /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) @@ -1042,7 +1048,6 @@ static const struct tty_port_operations sdio_uart_port_ops = { .carrier_raised = uart_carrier_raised, .shutdown = sdio_uart_shutdown, .activate = sdio_uart_activate, - .destruct = sdio_uart_port_destroy, }; static const struct tty_operations sdio_uart_ops = { @@ -1077,7 +1082,7 @@ static int sdio_uart_probe(struct sdio_func *func, return -ENOMEM; if (func->class == SDIO_CLASS_UART) { - pr_warning("%s: need info on UART class basic setup\n", + printk(KERN_WARNING "%s: need info on UART class basic setup\n", sdio_func_id(func)); kfree(port); return -ENOSYS; @@ -1096,23 +1101,23 @@ static int sdio_uart_probe(struct sdio_func *func, break; } if (!tpl) { - pr_warning( + printk(KERN_WARNING "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n", sdio_func_id(func)); kfree(port); return -EINVAL; } - pr_debug("%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", + printk(KERN_DEBUG "%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", sdio_func_id(func), tpl->data[2], tpl->data[3]); port->regs_offset = (tpl->data[4] << 0) | (tpl->data[5] << 8) | (tpl->data[6] << 16); - pr_debug("%s: regs offset = 0x%x\n", + printk(KERN_DEBUG "%s: regs offset = 0x%x\n", sdio_func_id(func), port->regs_offset); port->uartclk = tpl->data[7] * 115200; if (port->uartclk == 0) port->uartclk = 115200; - pr_debug("%s: clk %d baudcode %u 4800-div %u\n", + printk(KERN_DEBUG "%s: clk %d baudcode %u 4800-div %u\n", sdio_func_id(func), port->uartclk, tpl->data[7], tpl->data[8] | (tpl->data[9] << 8)); } else { @@ -1130,8 +1135,8 @@ static int sdio_uart_probe(struct sdio_func *func, kfree(port); } else { struct device *dev; - dev = tty_port_register_device(&port->port, - sdio_uart_tty_driver, port->index, &func->dev); + dev = tty_register_device(sdio_uart_tty_driver, + port->index, &func->dev); if (IS_ERR(dev)) { sdio_uart_port_remove(port); ret = PTR_ERR(dev); @@ -1173,6 +1178,7 @@ static int __init sdio_uart_init(void) if (!tty_drv) return -ENOMEM; + tty_drv->owner = THIS_MODULE; tty_drv->driver_name = "sdio_uart"; tty_drv->name = "ttySDIO"; tty_drv->major = 0; /* dynamically allocated */ diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index ef103871517..85c2e1acd15 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -27,3 +27,20 @@ config MMC_CLKGATE support handling this in order for it to be of any use. If unsure, say N. + +config MMC_EMBEDDED_SDIO + boolean "MMC embedded SDIO device support (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + If you say Y here, support will be added for embedded SDIO + devices which do not contain the necessary enumeration + support in hardware to be properly detected. + +config MMC_PARANOID_SD_INIT + bool "Enable paranoid SD card initialization (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + If you say Y here, the MMC layer will be extra paranoid + about re-trying SD init requests. This can be a useful + work-around for buggy controllers and hardware. Enable + if you are experiencing issues with SD detection. diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 38ed210ce2f..639501970b4 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -7,6 +7,6 @@ mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o \ - quirks.o slot-gpio.o + quirks.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 420cb6753c1..f4bdbe6982c 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -11,11 +11,9 @@ * MMC card bus driver model */ -#include #include #include #include -#include #include #include @@ -27,6 +25,10 @@ #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) +#ifdef CONFIG_MMC_TEST +static struct mmc_driver *mmc_test_drv; +#endif + static ssize_t mmc_type_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -109,6 +111,13 @@ static int mmc_bus_probe(struct device *dev) struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); +#ifdef CONFIG_MMC_TEST + /* + * Hack: Explicitly invoking mmc_test probe to co-exist with mmcblk driver. + */ + mmc_test_drv->probe(card); +#endif + return drv->probe(card); } @@ -122,19 +131,19 @@ static int mmc_bus_remove(struct device *dev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int mmc_bus_suspend(struct device *dev) +static int mmc_bus_pm_suspend(struct device *dev) { struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); int ret = 0; + pm_message_t state = { PM_EVENT_SUSPEND }; if (dev->driver && drv->suspend) - ret = drv->suspend(card); + ret = drv->suspend(card, state); return ret; } -static int mmc_bus_resume(struct device *dev) +static int mmc_bus_pm_resume(struct device *dev) { struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); @@ -144,10 +153,8 @@ static int mmc_bus_resume(struct device *dev) ret = drv->resume(card); return ret; } -#endif #ifdef CONFIG_PM_RUNTIME - static int mmc_runtime_suspend(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); @@ -166,13 +173,11 @@ static int mmc_runtime_idle(struct device *dev) { return pm_runtime_suspend(dev); } - -#endif /* !CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM_RUNTIME */ static const struct dev_pm_ops mmc_bus_pm_ops = { - SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, - mmc_runtime_idle) - SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume) + SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_pm_suspend, mmc_bus_pm_resume) + SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, mmc_runtime_idle) }; static struct bus_type mmc_bus_type = { @@ -202,6 +207,10 @@ void mmc_unregister_bus(void) int mmc_register_driver(struct mmc_driver *drv) { drv->drv.bus = &mmc_bus_type; +#ifdef CONFIG_MMC_TEST + if (!strcmp(drv->drv.name, "mmc_test")) + mmc_test_drv = drv; +#endif return driver_register(&drv->drv); } @@ -225,7 +234,8 @@ static void mmc_release_card(struct device *dev) sdio_free_common_cis(card); - kfree(card->info); + if (card->info) + kfree(card->info); kfree(card); } @@ -260,15 +270,6 @@ int mmc_add_card(struct mmc_card *card) { int ret; const char *type; - const char *uhs_bus_speed_mode = ""; - static const char *const uhs_speeds[] = { - [UHS_SDR12_BUS_SPEED] = "SDR12 ", - [UHS_SDR25_BUS_SPEED] = "SDR25 ", - [UHS_SDR50_BUS_SPEED] = "SDR50 ", - [UHS_SDR104_BUS_SPEED] = "SDR104 ", - [UHS_DDR50_BUS_SPEED] = "DDR50 ", - }; - dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca); @@ -298,24 +299,19 @@ int mmc_add_card(struct mmc_card *card) break; } - if (mmc_sd_card_uhs(card) && - (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) - uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; - if (mmc_host_is_spi(card->host)) { - pr_info("%s: new %s%s%s card on SPI\n", + printk(KERN_INFO "%s: new %s%s%s card on SPI\n", mmc_hostname(card->host), mmc_card_highspeed(card) ? "high speed " : "", mmc_card_ddr_mode(card) ? "DDR " : "", type); } else { - pr_info("%s: new %s%s%s%s%s card at address %04x\n", + printk(KERN_INFO "%s: new %s%s%s card at address %04x\n", mmc_hostname(card->host), - mmc_card_uhs(card) ? "ultra high speed " : + mmc_sd_card_uhs(card) ? "ultra high speed " : (mmc_card_highspeed(card) ? "high speed " : ""), - (mmc_card_hs200(card) ? "HS200 " : ""), mmc_card_ddr_mode(card) ? "DDR " : "", - uhs_bus_speed_mode, type, card->rca); + type, card->rca); } #ifdef CONFIG_DEBUG_FS @@ -343,10 +339,10 @@ void mmc_remove_card(struct mmc_card *card) if (mmc_card_present(card)) { if (mmc_host_is_spi(card->host)) { - pr_info("%s: SPI card removed\n", + printk(KERN_INFO "%s: SPI card removed\n", mmc_hostname(card->host)); } else { - pr_info("%s: card %04x removed\n", + printk(KERN_INFO "%s: card %04x removed\n", mmc_hostname(card->host), card->rca); } device_del(&card->dev); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index aaed7687cf0..2a288e936a8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -5,6 +5,7 @@ * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. + * Copyright (c) 2012 NVIDIA Corporation, All Rights Reserved. * * 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 @@ -24,9 +25,7 @@ #include #include #include -#include -#include -#include +#include #include #include @@ -42,24 +41,14 @@ #include "sd_ops.h" #include "sdio_ops.h" -/* If the device is not responding */ -#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ - -/* - * Background operations can take a long time, depending on the housekeeping - * operations the card has to perform. - */ -#define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */ - 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%) * performance cost, and for other reasons may not always be desired. * So we allow it it to be disabled. */ -bool use_spi_crc = 1; +int use_spi_crc = 1; module_param(use_spi_crc, bool, 0); /* @@ -69,9 +58,9 @@ module_param(use_spi_crc, bool, 0); * overridden if necessary. */ #ifdef CONFIG_MMC_UNSAFE_RESUME -bool mmc_assume_removable; +int mmc_assume_removable; #else -bool mmc_assume_removable = 1; +int mmc_assume_removable = 1; #endif EXPORT_SYMBOL(mmc_assume_removable); module_param_named(removable, mmc_assume_removable, bool, 0644); @@ -96,43 +85,6 @@ static void mmc_flush_scheduled_work(void) flush_workqueue(workqueue); } -#ifdef CONFIG_FAIL_MMC_REQUEST - -/* - * Internal function. Inject random data errors. - * If mmc_data is NULL no errors are injected. - */ -static void mmc_should_fail_request(struct mmc_host *host, - struct mmc_request *mrq) -{ - struct mmc_command *cmd = mrq->cmd; - struct mmc_data *data = mrq->data; - static const int data_errors[] = { - -ETIMEDOUT, - -EILSEQ, - -EIO, - }; - - if (!data) - return; - - if (cmd->error || data->error || - !should_fail(&host->fail_mmc_request, data->blksz * data->blocks)) - return; - - data->error = data_errors[random32() % ARRAY_SIZE(data_errors)]; - data->bytes_xfered = (random32() % (data->bytes_xfered >> 9)) << 9; -} - -#else /* CONFIG_FAIL_MMC_REQUEST */ - -static inline void mmc_should_fail_request(struct mmc_host *host, - struct mmc_request *mrq) -{ -} - -#endif /* CONFIG_FAIL_MMC_REQUEST */ - /** * mmc_request_done - finish processing an MMC request * @host: MMC host which completed request @@ -151,16 +103,19 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) cmd->retries = 0; } - if (err && cmd->retries && !mmc_card_removed(host->card)) { - /* - * Request starter must handle retries - see - * mmc_wait_for_req_done(). - */ - if (mrq->done) - mrq->done(mrq); - } else { - mmc_should_fail_request(host, mrq); + if (err && cmd->retries) { + pr_debug("%s: req failed (CMD%u): %d, retrying...\n", + mmc_hostname(host), cmd->opcode, err); + cmd->retries--; + cmd->error = 0; + if (mrq->data) { + mrq->data->error = 0; + if (mrq->stop) + mrq->stop->error = 0; + } + host->ops->request(host, mrq); + } else { led_trigger_event(host->led, LED_OFF); pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", @@ -199,12 +154,6 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) struct scatterlist *sg; #endif - if (mrq->sbc) { - pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", - mmc_hostname(host), mrq->sbc->opcode, - mrq->sbc->arg, mrq->sbc->flags); - } - pr_debug("%s: starting CMD%u arg %08x flags %08x\n", mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); @@ -255,107 +204,22 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) host->ops->request(host, mrq); } -/** - * mmc_start_bkops - start BKOPS for supported cards - * @card: MMC card to start BKOPS - * @form_exception: A flag to indicate if this function was - * called due to an exception raised by the card - * - * Start background operations whenever requested. - * When the urgent BKOPS bit is set in a R1 command response - * then background operations should be started immediately. -*/ -void mmc_start_bkops(struct mmc_card *card, bool from_exception) -{ - int err; - int timeout; - bool use_busy_signal; - - BUG_ON(!card); - - if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card)) - return; - - err = mmc_read_bkops_status(card); - if (err) { - pr_err("%s: Failed to read bkops status: %d\n", - mmc_hostname(card->host), err); - return; - } - - if (!card->ext_csd.raw_bkops_status) - return; - - if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 && - from_exception) - return; - - mmc_claim_host(card->host); - if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) { - timeout = MMC_BKOPS_MAX_TIMEOUT; - use_busy_signal = true; - } else { - timeout = 0; - use_busy_signal = false; - } - - err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal); - if (err) { - pr_warn("%s: Error %d starting bkops\n", - mmc_hostname(card->host), err); - goto out; - } - - /* - * For urgent bkops status (LEVEL_2 and more) - * bkops executed synchronously, otherwise - * the operation is in progress - */ - if (!use_busy_signal) - mmc_card_set_doing_bkops(card); -out: - mmc_release_host(card->host); -} -EXPORT_SYMBOL(mmc_start_bkops); - static void mmc_wait_done(struct mmc_request *mrq) { complete(&mrq->completion); } -static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) +static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) { init_completion(&mrq->completion); mrq->done = mmc_wait_done; - if (mmc_card_removed(host->card)) { - mrq->cmd->error = -ENOMEDIUM; - complete(&mrq->completion); - return -ENOMEDIUM; - } mmc_start_request(host, mrq); - return 0; } static void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) { - struct mmc_command *cmd; - - while (1) { - wait_for_completion(&mrq->completion); - - cmd = mrq->cmd; - if (!cmd->error || !cmd->retries || - mmc_card_removed(host->card)) - break; - - pr_debug("%s: req failed (CMD%u): %d, retrying...\n", - mmc_hostname(host), cmd->opcode, cmd->error); - cmd->retries--; - cmd->error = 0; - host->ops->request(host, mrq); - } + wait_for_completion(&mrq->completion); } /** @@ -372,11 +236,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host, static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, bool is_first_req) { - if (host->ops->pre_req) { - mmc_host_clk_hold(host); + if (host->ops->pre_req) host->ops->pre_req(host, mrq, is_first_req); - mmc_host_clk_release(host); - } } /** @@ -391,11 +252,8 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, int err) { - if (host->ops->post_req) { - mmc_host_clk_hold(host); + if (host->ops->post_req) host->ops->post_req(host, mrq, err); - mmc_host_clk_release(host); - } } /** @@ -418,7 +276,6 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, struct mmc_async_req *areq, int *error) { int err = 0; - int start_err = 0; struct mmc_async_req *data = host->areq; /* Prepare a new request */ @@ -428,31 +285,24 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, if (host->areq) { mmc_wait_for_req_done(host, host->areq->mrq); err = host->areq->err_check(host->card, host->areq); - /* - * Check BKOPS urgency for each R1 response - */ - if (host->card && mmc_card_mmc(host->card) && - ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) || - (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) && - (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) - mmc_start_bkops(host->card, true); + if (err) { + mmc_post_req(host, host->areq->mrq, 0); + if (areq) + mmc_post_req(host, areq->mrq, -EINVAL); + + host->areq = NULL; + goto out; + } } - if (!err && areq) - start_err = __mmc_start_req(host, areq->mrq); + if (areq) + __mmc_start_req(host, areq->mrq); if (host->areq) mmc_post_req(host, host->areq->mrq, 0); - /* Cancel a prepared request if it was not started. */ - if ((err || start_err) && areq) - mmc_post_req(host, areq->mrq, -EINVAL); - - if (err) - host->areq = NULL; - else - host->areq = areq; - + host->areq = areq; + out: if (error) *error = err; return data; @@ -475,21 +325,64 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) } EXPORT_SYMBOL(mmc_wait_for_req); +/** + * mmc_bkops_start - Issue start for mmc background ops + * @card: the MMC card associated with bkops + * @is_synchronous: is the backops synchronous + * + * Issued background ops without the busy wait. + */ +int mmc_bkops_start(struct mmc_card *card, bool is_synchronous) +{ + int err; + unsigned long flags; + + BUG_ON(!card); + + if (!card->ext_csd.bk_ops_en || mmc_card_doing_bkops(card)) + return 1; + + mmc_claim_host(card->host); + err = mmc_send_bk_ops_cmd(card, is_synchronous); + if (err) + pr_err("%s: abort bk ops (%d error)\n", + mmc_hostname(card->host), err); + + /* + * Incase of asynchronous backops, set card state + * to doing bk ops to ensure that HPI is issued before + * handling any new request in the queue. + */ + spin_lock_irqsave(&card->host->lock, flags); + mmc_card_clr_need_bkops(card); + if (!is_synchronous) + mmc_card_set_doing_bkops(card); + spin_unlock_irqrestore(&card->host->lock, flags); + + mmc_release_host(card->host); + + return err; +} +EXPORT_SYMBOL(mmc_bkops_start); + /** * mmc_interrupt_hpi - Issue for High priority Interrupt * @card: the MMC card associated with the HPI transfer * * Issued High Priority Interrupt, and check for card status - * until out-of prg-state. + * util out-of prg-state. */ int mmc_interrupt_hpi(struct mmc_card *card) { int err; u32 status; - unsigned long prg_wait; + unsigned long flags; BUG_ON(!card); + if (!mmc_card_mmc(card)) + return 1; + if (!card->ext_csd.hpi_en) { pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host)); return 1; @@ -502,41 +395,35 @@ int mmc_interrupt_hpi(struct mmc_card *card) goto out; } - switch (R1_CURRENT_STATE(status)) { - case R1_STATE_IDLE: - case R1_STATE_READY: - case R1_STATE_STBY: - case R1_STATE_TRAN: - /* - * In idle and transfer states, HPI is not needed and the caller - * can issue the next intended command immediately - */ - goto out; - case R1_STATE_PRG: - break; - default: - /* In all other states, it's illegal to issue HPI */ - pr_debug("%s: HPI cannot be sent. Card state=%d\n", - mmc_hostname(card->host), R1_CURRENT_STATE(status)); - err = -EINVAL; - goto out; - } - - err = mmc_send_hpi_cmd(card, &status); - if (err) - goto out; - - prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time); - do { - err = mmc_send_status(card, &status); + /* + * If the card status is in PRG-state, we can send the HPI command. + */ + if (R1_CURRENT_STATE(status) == R1_STATE_PRG) { + do { + /* + * We don't know when the HPI command will finish + * processing, so we need to resend HPI until out + * of prg-state, and keep checking the card status + * with SEND_STATUS. If a timeout error occurs when + * sending the HPI command, we are already out of + * prg-state. + */ + err = mmc_send_hpi_cmd(card, &status); + if (err) + pr_debug("%s: abort HPI (%d error)\n", + mmc_hostname(card->host), err); - if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN) - break; - if (time_after(jiffies, prg_wait)) - err = -ETIMEDOUT; - } while (!err); + err = mmc_send_status(card, &status); + if (err) + break; + } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); + } else + pr_debug("%s: Left prg-state\n", mmc_hostname(card->host)); out: + spin_lock_irqsave(&card->host->lock, flags); + mmc_card_clr_doing_bkops(card); + spin_unlock_irqrestore(&card->host->lock, flags); mmc_release_host(card->host); return err; } @@ -554,7 +441,7 @@ EXPORT_SYMBOL(mmc_interrupt_hpi); */ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) { - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; WARN_ON(!host->claimed); @@ -571,64 +458,6 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries EXPORT_SYMBOL(mmc_wait_for_cmd); -/** - * mmc_stop_bkops - stop ongoing BKOPS - * @card: MMC card to check BKOPS - * - * Send HPI command to stop ongoing background operations to - * allow rapid servicing of foreground operations, e.g. read/ - * writes. Wait until the card comes out of the programming state - * to avoid errors in servicing read/write requests. - */ -int mmc_stop_bkops(struct mmc_card *card) -{ - int err = 0; - - BUG_ON(!card); - err = mmc_interrupt_hpi(card); - - /* - * If err is EINVAL, we can't issue an HPI. - * It should complete the BKOPS. - */ - if (!err || (err == -EINVAL)) { - mmc_card_clr_doing_bkops(card); - err = 0; - } - - return err; -} -EXPORT_SYMBOL(mmc_stop_bkops); - -int mmc_read_bkops_status(struct mmc_card *card) -{ - int err; - u8 *ext_csd; - - /* - * In future work, we should consider storing the entire ext_csd. - */ - ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) { - pr_err("%s: could not allocate buffer to receive the ext_csd.\n", - mmc_hostname(card->host)); - return -ENOMEM; - } - - mmc_claim_host(card->host); - err = mmc_send_ext_csd(card, ext_csd); - mmc_release_host(card->host); - if (err) - goto out; - - card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; - card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS]; -out: - kfree(ext_csd); - return err; -} -EXPORT_SYMBOL(mmc_read_bkops_status); - /** * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command @@ -678,14 +507,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) if (data->flags & MMC_DATA_WRITE) /* - * The MMC spec "It is strongly recommended - * for hosts to implement more than 500ms - * timeout value even if the card indicates - * the 250ms maximum busy length." Even the - * previous value of 300ms is known to be - * insufficient for some cards. + * The limit is really 250 ms, but that is + * insufficient for some crappy cards. */ - limit_us = 3000000; + limit_us = 300000; else limit_us = 100000; @@ -697,18 +522,6 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) data->timeout_clks = 0; } } - - /* - * Some cards require longer data read timeout than indicated in CSD. - * Address this by setting the read timeout to a "reasonably high" - * value. For the cards tested, 300ms has proven enough. If necessary, - * this value can be increased if other problematic cards require this. - */ - if (mmc_card_long_read_time(card) && data->flags & MMC_DATA_READ) { - data->timeout_ns = 300000000; - data->timeout_clks = 0; - } - /* * Some cards need very high timeouts if driven in SPI mode. * The worst observed timeout was 900ms after writing a @@ -754,6 +567,101 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz) } EXPORT_SYMBOL(mmc_align_data_size); +/** + * mmc_host_enable - enable a host. + * @host: mmc host to enable + * + * Hosts that support power saving can use the 'enable' and 'disable' + * methods to exit and enter power saving states. For more information + * see comments for struct mmc_host_ops. + */ +int mmc_host_enable(struct mmc_host *host) +{ + if (!(host->caps & MMC_CAP_DISABLE)) + return 0; + + if (host->en_dis_recurs) + return 0; + + if (host->nesting_cnt++) + return 0; + + cancel_delayed_work_sync(&host->disable); + + if (host->enabled) + return 0; + + if (host->ops->enable) { + int err; + + host->en_dis_recurs = 1; + err = host->ops->enable(host); + host->en_dis_recurs = 0; + + if (err) { + pr_debug("%s: enable error %d\n", + mmc_hostname(host), err); + return err; + } + } + host->enabled = 1; + return 0; +} +EXPORT_SYMBOL(mmc_host_enable); + +static int mmc_host_do_disable(struct mmc_host *host, int lazy) +{ + if (host->ops->disable) { + int err; + + host->en_dis_recurs = 1; + err = host->ops->disable(host, lazy); + host->en_dis_recurs = 0; + + if (err < 0) { + pr_debug("%s: disable error %d\n", + mmc_hostname(host), err); + return err; + } + if (err > 0) { + unsigned long delay = msecs_to_jiffies(err); + + mmc_schedule_delayed_work(&host->disable, delay); + } + } + host->enabled = 0; + return 0; +} + +/** + * mmc_host_disable - disable a host. + * @host: mmc host to disable + * + * Hosts that support power saving can use the 'enable' and 'disable' + * methods to exit and enter power saving states. For more information + * see comments for struct mmc_host_ops. + */ +int mmc_host_disable(struct mmc_host *host) +{ + int err; + + if (!(host->caps & MMC_CAP_DISABLE)) + return 0; + + if (host->en_dis_recurs) + return 0; + + if (--host->nesting_cnt) + return 0; + + if (!host->enabled) + return 0; + + err = mmc_host_do_disable(host, 0); + return err; +} +EXPORT_SYMBOL(mmc_host_disable); + /** * __mmc_claim_host - exclusively claim a host * @host: mmc host to claim @@ -792,8 +700,8 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) wake_up(&host->wq); spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); - if (host->ops->enable && !stop && host->claim_cnt == 1) - host->ops->enable(host); + if (!stop) + mmc_host_enable(host); return stop; } @@ -818,28 +726,21 @@ int mmc_try_claim_host(struct mmc_host *host) claimed_host = 1; } spin_unlock_irqrestore(&host->lock, flags); - if (host->ops->enable && claimed_host && host->claim_cnt == 1) - host->ops->enable(host); return claimed_host; } EXPORT_SYMBOL(mmc_try_claim_host); /** - * mmc_release_host - release a host + * mmc_do_release_host - release a claimed host * @host: mmc host to release * - * Release a MMC host, allowing others to claim the host - * for their operations. + * If you successfully claimed a host, this function will + * release it again. */ -void mmc_release_host(struct mmc_host *host) +void mmc_do_release_host(struct mmc_host *host) { unsigned long flags; - WARN_ON(!host->claimed); - - if (host->ops->disable && host->claim_cnt == 1) - host->ops->disable(host); - spin_lock_irqsave(&host->lock, flags); if (--host->claim_cnt) { /* Release for nested claim */ @@ -851,6 +752,67 @@ void mmc_release_host(struct mmc_host *host) wake_up(&host->wq); } } +EXPORT_SYMBOL(mmc_do_release_host); + +void mmc_host_deeper_disable(struct work_struct *work) +{ + struct mmc_host *host = + container_of(work, struct mmc_host, disable.work); + + /* If the host is claimed then we do not want to disable it anymore */ + if (!mmc_try_claim_host(host)) + return; + mmc_host_do_disable(host, 1); + mmc_do_release_host(host); +} + +/** + * mmc_host_lazy_disable - lazily disable a host. + * @host: mmc host to disable + * + * Hosts that support power saving can use the 'enable' and 'disable' + * methods to exit and enter power saving states. For more information + * see comments for struct mmc_host_ops. + */ +int mmc_host_lazy_disable(struct mmc_host *host) +{ + if (!(host->caps & MMC_CAP_DISABLE)) + return 0; + + if (host->en_dis_recurs) + return 0; + + if (--host->nesting_cnt) + return 0; + + if (!host->enabled) + return 0; + + if (host->disable_delay) { + mmc_schedule_delayed_work(&host->disable, + msecs_to_jiffies(host->disable_delay)); + return 0; + } else + return mmc_host_do_disable(host, 1); +} +EXPORT_SYMBOL(mmc_host_lazy_disable); + +/** + * mmc_release_host - release a host + * @host: mmc host to release + * + * Release a MMC host, allowing others to claim the host + * for their operations. + */ +void mmc_release_host(struct mmc_host *host) +{ + WARN_ON(!host->claimed); + + mmc_host_lazy_disable(host); + + mmc_do_release_host(host); +} + EXPORT_SYMBOL(mmc_release_host); /* @@ -1091,7 +1053,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply) return result; } -EXPORT_SYMBOL_GPL(mmc_regulator_get_ocrmask); +EXPORT_SYMBOL(mmc_regulator_get_ocrmask); /** * mmc_regulator_set_ocr - set regulator to match host->ios voltage @@ -1116,8 +1078,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, int tmp; int voltage; - /* - * REVISIT mmc_vddrange_to_ocrmask() may have set some + /* REVISIT mmc_vddrange_to_ocrmask() may have set some * bits this regulator doesn't quite support ... don't * be too picky, most cards and regulators are OK with * a 0.1V range goof (it's a small error percentage). @@ -1131,15 +1092,10 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, max_uV = min_uV + 100 * 1000; } - /* - * If we're using a fixed/static regulator, don't call - * regulator_set_voltage; it would fail. + /* avoid needless changes to this voltage; the regulator + * might not allow this operation */ voltage = regulator_get_voltage(supply); - - if (regulator_count_voltages(supply) == 1) - min_uV = max_uV = voltage; - if (voltage < 0) result = voltage; else if (voltage < min_uV || voltage > max_uV) @@ -1163,30 +1119,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, "could not set regulator OCR (%d)\n", result); return result; } -EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr); - -int mmc_regulator_get_supply(struct mmc_host *mmc) -{ - struct device *dev = mmc_dev(mmc); - struct regulator *supply; - int ret; - - supply = devm_regulator_get(dev, "vmmc"); - mmc->supply.vmmc = supply; - mmc->supply.vqmmc = devm_regulator_get(dev, "vqmmc"); - - if (IS_ERR(supply)) - return PTR_ERR(supply); - - ret = mmc_regulator_get_ocrmask(supply); - if (ret > 0) - mmc->ocr_avail = ret; - else - dev_warn(mmc_dev(mmc), "Failed getting OCR mask: %d\n", ret); - - return 0; -} -EXPORT_SYMBOL_GPL(mmc_regulator_get_supply); +EXPORT_SYMBOL(mmc_regulator_set_ocr); #endif /* CONFIG_REGULATOR */ @@ -1245,11 +1178,8 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11 host->ios.signal_voltage = signal_voltage; - if (host->ops->start_signal_voltage_switch) { - mmc_host_clk_hold(host); + if (host->ops->start_signal_voltage_switch) err = host->ops->start_signal_voltage_switch(host, &host->ios); - mmc_host_clk_release(host); - } return err; } @@ -1291,9 +1221,6 @@ 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 */ @@ -1303,19 +1230,18 @@ static void mmc_power_up(struct mmc_host *host) bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; - if (mmc_host_is_spi(host)) + if (mmc_host_is_spi(host)) { host->ios.chip_select = MMC_CS_HIGH; - else + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + } else { host->ios.chip_select = MMC_CS_DONTCARE; - host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + } host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); - /* Set signal voltage to 3.3V */ - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false); - /* * This delay should be sufficient to allow the power supply * to reach the minimum voltage. @@ -1338,15 +1264,11 @@ static void mmc_power_up(struct mmc_host *host) void mmc_power_off(struct mmc_host *host) { - if (host->ios.power_mode == MMC_POWER_OFF) - return; - mmc_host_clk_hold(host); host->ios.clock = 0; host->ios.vdd = 0; - /* * Reset ocr mask to be the highest possible voltage supported for * this mmc host. This value will be used at next power up. @@ -1362,13 +1284,6 @@ void mmc_power_off(struct mmc_host *host) host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); - /* - * Some configurations, such as the 802.11 SDIO card in the OLPC - * XO-1.5, require a short delay after poweroff before the card - * can be successfully turned on again. - */ - mmc_delay(1); - mmc_host_clk_release(host); } @@ -1411,6 +1326,36 @@ static inline void mmc_bus_put(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); } +int mmc_resume_bus(struct mmc_host *host) +{ + unsigned long flags; + + if (!mmc_bus_needs_resume(host)) + return -EINVAL; + + printk("%s: Starting deferred resume\n", mmc_hostname(host)); + spin_lock_irqsave(&host->lock, flags); + host->bus_resume_flags &= ~MMC_BUSRESUME_NEEDS_RESUME; + host->rescan_disable = 0; + spin_unlock_irqrestore(&host->lock, flags); + + mmc_bus_get(host); + if (host->bus_ops && !host->bus_dead) { + mmc_power_up(host); + BUG_ON(!host->bus_ops->resume); + host->bus_ops->resume(host); + } + + if (host->bus_ops->detect && !host->bus_dead) + host->bus_ops->detect(host); + + mmc_bus_put(host); + printk("%s: Deferred resume completed\n", mmc_hostname(host)); + return 0; +} + +EXPORT_SYMBOL(mmc_resume_bus); + /* * Assign a mmc bus handler to a host. Only one bus handler may control a * host at any given time. @@ -1475,7 +1420,8 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay) WARN_ON(host->removed); spin_unlock_irqrestore(&host->lock, flags); #endif - host->detect_change = 1; + + wake_lock(&host->detect_wake_lock); mmc_schedule_delayed_work(&host->detect, delay); } @@ -1535,10 +1481,7 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card, { unsigned int erase_timeout; - if (arg == MMC_DISCARD_ARG || - (arg == MMC_TRIM_ARG && card->ext_csd.rev >= 6)) { - erase_timeout = card->ext_csd.trim_timeout; - } else if (card->ext_csd.erase_group_def & 1) { + if (card->ext_csd.erase_group_def & 1) { /* High Capacity Erase Group Size uses HC timeouts */ if (arg == MMC_TRIM_ARG) erase_timeout = card->ext_csd.trim_timeout; @@ -1634,7 +1577,6 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, { struct mmc_command cmd = {0}; unsigned int qty = 0; - unsigned long timeout; int err; /* @@ -1675,9 +1617,9 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { - pr_err("mmc_erase: group start error %d, " + printk(KERN_ERR "mmc_erase: group start error %d, " "status %#x\n", err, cmd.resp[0]); - err = -EIO; + err = -EINVAL; goto out; } @@ -1690,9 +1632,9 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { - pr_err("mmc_erase: group end error %d, status %#x\n", + printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n", err, cmd.resp[0]); - err = -EIO; + err = -EINVAL; goto out; } @@ -1703,7 +1645,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty); err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { - pr_err("mmc_erase: erase error %d, status %#x\n", + printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n", err, cmd.resp[0]); err = -EIO; goto out; @@ -1712,7 +1654,6 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, if (mmc_host_is_spi(card->host)) goto out; - timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS); do { memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_STATUS; @@ -1721,24 +1662,13 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, /* Do not retry else we can't see errors */ err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err || (cmd.resp[0] & 0xFDF92000)) { - pr_err("error %d requesting status %#x\n", + printk(KERN_ERR "error %d requesting status %#x\n", err, cmd.resp[0]); err = -EIO; goto out; } - - /* Timeout if the device never becomes ready for data and - * never leaves the program state. - */ - if (time_after(jiffies, timeout)) { - pr_err("%s: Card stuck in programming state! %s\n", - mmc_hostname(card->host), __func__); - err = -EIO; - goto out; - } - } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || - (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG)); + R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG); out: return err; } @@ -1827,28 +1757,6 @@ int mmc_can_trim(struct mmc_card *card) } EXPORT_SYMBOL(mmc_can_trim); -int mmc_can_discard(struct mmc_card *card) -{ - /* - * As there's no way to detect the discard support bit at v4.5 - * use the s/w feature support filed. - */ - if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE) - return 1; - return 0; -} -EXPORT_SYMBOL(mmc_can_discard); - -int mmc_can_sanitize(struct mmc_card *card) -{ - if (!mmc_can_trim(card) && !mmc_can_erase(card)) - return 0; - if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE) - return 1; - return 0; -} -EXPORT_SYMBOL(mmc_can_sanitize); - int mmc_can_secure_erase_trim(struct mmc_card *card) { if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN) @@ -1958,108 +1866,6 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) } EXPORT_SYMBOL(mmc_set_blocklen); -int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount, - bool is_rel_write) -{ - struct mmc_command cmd = {0}; - - cmd.opcode = MMC_SET_BLOCK_COUNT; - cmd.arg = blockcount & 0x0000FFFF; - if (is_rel_write) - cmd.arg |= 1 << 31; - cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; - return mmc_wait_for_cmd(card->host, &cmd, 5); -} -EXPORT_SYMBOL(mmc_set_blockcount); - -static void mmc_hw_reset_for_init(struct mmc_host *host) -{ - if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) - return; - mmc_host_clk_hold(host); - host->ops->hw_reset(host); - mmc_host_clk_release(host); -} - -int mmc_can_reset(struct mmc_card *card) -{ - u8 rst_n_function; - - if (!mmc_card_mmc(card)) - return 0; - rst_n_function = card->ext_csd.rst_n_function; - if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED) - return 0; - return 1; -} -EXPORT_SYMBOL(mmc_can_reset); - -static int mmc_do_hw_reset(struct mmc_host *host, int check) -{ - struct mmc_card *card = host->card; - - if (!host->bus_ops->power_restore) - return -EOPNOTSUPP; - - if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) - return -EOPNOTSUPP; - - if (!card) - return -EINVAL; - - if (!mmc_can_reset(card)) - return -EOPNOTSUPP; - - mmc_host_clk_hold(host); - mmc_set_clock(host, host->f_init); - - host->ops->hw_reset(host); - - /* If the reset has happened, then a status command will fail */ - if (check) { - struct mmc_command cmd = {0}; - int err; - - cmd.opcode = MMC_SEND_STATUS; - if (!mmc_host_is_spi(card->host)) - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, 0); - if (!err) { - mmc_host_clk_release(host); - return -ENOSYS; - } - } - - host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR); - if (mmc_host_is_spi(host)) { - host->ios.chip_select = MMC_CS_HIGH; - host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; - } else { - host->ios.chip_select = MMC_CS_DONTCARE; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - } - host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ios.timing = MMC_TIMING_LEGACY; - mmc_set_ios(host); - - mmc_host_clk_release(host); - - return host->bus_ops->power_restore(host); -} - -int mmc_hw_reset(struct mmc_host *host) -{ - return mmc_do_hw_reset(host, 0); -} -EXPORT_SYMBOL(mmc_hw_reset); - -int mmc_hw_reset_check(struct mmc_host *host) -{ - return mmc_do_hw_reset(host, 1); -} -EXPORT_SYMBOL(mmc_hw_reset_check); - static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) { host->f_init = freq; @@ -2070,12 +1876,6 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) #endif mmc_power_up(host); - /* - * Some eMMCs (with VCCQ always on) may not be reset after power up, so - * do a hardware reset if possible. - */ - mmc_hw_reset_for_init(host); - /* * sdio_reset sends CMD52 to reset card. Since we do not know * if the card is being re-initialized, just send it. CMD52 @@ -2098,75 +1898,17 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) return -EIO; } -int _mmc_detect_card_removed(struct mmc_host *host) -{ - int ret; - - if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive) - return 0; - - if (!host->card || mmc_card_removed(host->card)) - return 1; - - ret = host->bus_ops->alive(host); - if (ret) { - mmc_card_set_removed(host->card); - pr_debug("%s: card remove detected\n", mmc_hostname(host)); - } - - return ret; -} - -int mmc_detect_card_removed(struct mmc_host *host) -{ - struct mmc_card *card = host->card; - int ret; - - WARN_ON(!host->claimed); - - if (!card) - return 1; - - ret = mmc_card_removed(card); - /* - * The card will be considered unchanged unless we have been asked to - * detect a change or host requires polling to provide card detection. - */ - if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) && - !(host->caps2 & MMC_CAP2_DETECT_ON_ERR)) - return ret; - - host->detect_change = 0; - if (!ret) { - ret = _mmc_detect_card_removed(host); - if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) { - /* - * Schedule a detect work as soon as possible to let a - * rescan handle the card removal. - */ - cancel_delayed_work(&host->detect); - mmc_detect_change(host, 0); - } - } - - return ret; -} -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; + bool extend_wakelock = false; if (host->rescan_disable) return; - /* If there is a non-removable card registered, only scan once */ - if ((host->caps & MMC_CAP_NONREMOVABLE) && host->rescan_entered) - return; - host->rescan_entered = 1; - mmc_bus_get(host); /* @@ -2177,7 +1919,11 @@ void mmc_rescan(struct work_struct *work) && !(host->caps & MMC_CAP_NONREMOVABLE)) host->bus_ops->detect(host); - host->detect_change = 0; + /* If the card was removed the bus will be marked + * as dead - extend the wakelock so userspace + * can respond */ + if (host->bus_dead) + extend_wakelock = 1; /* * Let mmc_bus_put() free the bus/bus_ops if we've found that @@ -2198,32 +1944,34 @@ void mmc_rescan(struct work_struct *work) */ mmc_bus_put(host); - if (host->ops->get_cd && host->ops->get_cd(host) == 0) { - mmc_claim_host(host); - mmc_power_off(host); - mmc_release_host(host); + if (host->ops->get_cd && host->ops->get_cd(host) == 0) goto out; - } mmc_claim_host(host); for (i = 0; i < ARRAY_SIZE(freqs); i++) { - if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) + if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) { + extend_wakelock = true; break; + } if (freqs[i] <= host->f_min) break; } mmc_release_host(host); out: - if (host->caps & MMC_CAP_NEEDS_POLL) + if (extend_wakelock) + wake_lock_timeout(&host->detect_wake_lock, HZ / 2); + else + wake_unlock(&host->detect_wake_lock); + if (host->caps & MMC_CAP_NEEDS_POLL) { + wake_lock(&host->detect_wake_lock); mmc_schedule_delayed_work(&host->detect, HZ); + } } void mmc_start_host(struct mmc_host *host) { - host->f_init = max(freqs[0], host->f_min); - host->rescan_disable = 0; - mmc_power_up(host); + mmc_power_off(host); mmc_detect_change(host, 0); } @@ -2236,8 +1984,10 @@ void mmc_stop_host(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); #endif - host->rescan_disable = 1; - cancel_delayed_work_sync(&host->detect); + if (host->caps & MMC_CAP_DISABLE) + cancel_delayed_work(&host->disable); + if (cancel_delayed_work_sync(&host->detect)) + wake_unlock(&host->detect_wake_lock); mmc_flush_scheduled_work(); /* clear pm flags now and let card drivers set them as needed */ @@ -2245,7 +1995,6 @@ void mmc_stop_host(struct mmc_host *host) mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { - /* Calling bus_ops->remove() with a claimed host can deadlock */ if (host->bus_ops->remove) host->bus_ops->remove(host); @@ -2317,9 +2066,6 @@ int mmc_card_awake(struct mmc_host *host) { int err = -ENOSYS; - if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) - return 0; - mmc_bus_get(host); if (host->bus_ops && !host->bus_dead && host->bus_ops->awake) @@ -2335,12 +2081,9 @@ int mmc_card_sleep(struct mmc_host *host) { int err = -ENOSYS; - if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) - return 0; - mmc_bus_get(host); - if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep) + if (host->bus_ops && !host->bus_dead && host->bus_ops->awake) err = host->bus_ops->sleep(host); mmc_bus_put(host); @@ -2359,70 +2102,6 @@ int mmc_card_can_sleep(struct mmc_host *host) } EXPORT_SYMBOL(mmc_card_can_sleep); -/* - * Flush the cache to the non-volatile storage. - */ -int mmc_flush_cache(struct mmc_card *card) -{ - struct mmc_host *host = card->host; - int err = 0; - - if (!(host->caps2 & MMC_CAP2_CACHE_CTRL)) - return err; - - if (mmc_card_mmc(card) && - (card->ext_csd.cache_size > 0) && - (card->ext_csd.cache_ctrl & 1)) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_FLUSH_CACHE, 1, 0); - if (err) - pr_err("%s: cache flush error %d\n", - mmc_hostname(card->host), err); - } - - return err; -} -EXPORT_SYMBOL(mmc_flush_cache); - -/* - * Turn the cache ON/OFF. - * Turning the cache OFF shall trigger flushing of the data - * to the non-volatile storage. - */ -int mmc_cache_ctrl(struct mmc_host *host, u8 enable) -{ - struct mmc_card *card = host->card; - unsigned int timeout; - int err = 0; - - if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) || - mmc_card_is_removable(host)) - return err; - - mmc_claim_host(host); - if (card && mmc_card_mmc(card) && - (card->ext_csd.cache_size > 0)) { - enable = !!enable; - - if (card->ext_csd.cache_ctrl ^ enable) { - timeout = enable ? card->ext_csd.generic_cmd6_time : 0; - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_CACHE_CTRL, enable, timeout); - if (err) - pr_err("%s: cache %s error %d\n", - mmc_hostname(card->host), - enable ? "on" : "off", - err); - else - card->ext_csd.cache_ctrl = enable; - } - } - mmc_release_host(host); - - return err; -} -EXPORT_SYMBOL(mmc_cache_ctrl); - #ifdef CONFIG_PM /** @@ -2433,30 +2112,27 @@ int mmc_suspend_host(struct mmc_host *host) { int err = 0; - cancel_delayed_work(&host->detect); - mmc_flush_scheduled_work(); + if (mmc_bus_needs_resume(host)) + return 0; - err = mmc_cache_ctrl(host, 0); - if (err) - goto out; + if (mmc_card_mmc(host->card) && mmc_card_doing_bkops(host->card)) + mmc_interrupt_hpi(host->card); + mmc_card_clr_need_bkops(host->card); + + if (host->caps & MMC_CAP_DISABLE) + cancel_delayed_work(&host->disable); + if (cancel_delayed_work(&host->detect)) + wake_unlock(&host->detect_wake_lock); + mmc_flush_scheduled_work(); mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { - if (host->bus_ops->suspend) { - if (mmc_card_doing_bkops(host->card)) { - err = mmc_stop_bkops(host->card); - if (err) - goto out; - } + if (host->bus_ops->suspend) err = host->bus_ops->suspend(host); - } - if (err == -ENOSYS || !host->bus_ops->resume) { /* * We simply "remove" the card in this case. - * It will be redetected on resume. (Calling - * bus_ops->remove() with a claimed host can - * deadlock.) + * It will be redetected on resume. */ if (host->bus_ops->remove) host->bus_ops->remove(host); @@ -2473,7 +2149,6 @@ int mmc_suspend_host(struct mmc_host *host) if (!err && !mmc_card_keep_power(host)) mmc_power_off(host); -out: return err; } @@ -2488,6 +2163,12 @@ int mmc_resume_host(struct mmc_host *host) int err = 0; mmc_bus_get(host); + if (mmc_bus_manual_resume(host)) { + host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME; + mmc_bus_put(host); + return 0; + } + if (host->bus_ops && !host->bus_dead) { if (!mmc_card_keep_power(host)) { mmc_power_up(host); @@ -2508,7 +2189,7 @@ int mmc_resume_host(struct mmc_host *host) BUG_ON(!host->bus_ops->resume); err = host->bus_ops->resume(host); if (err) { - pr_warning("%s: error %d during resume " + printk(KERN_WARNING "%s: error %d during resume " "(card was removed?)\n", mmc_hostname(host), err); err = 0; @@ -2531,35 +2212,30 @@ int mmc_pm_notify(struct notifier_block *notify_block, struct mmc_host *host = container_of( notify_block, struct mmc_host, pm_notify); unsigned long flags; - int err = 0; + switch (mode) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: - if (host->card && mmc_card_mmc(host->card) && - mmc_card_doing_bkops(host->card)) { - err = mmc_stop_bkops(host->card); - if (err) { - pr_err("%s: didn't stop bkops\n", - mmc_hostname(host)); - return err; - } - mmc_card_clr_doing_bkops(host->card); - } spin_lock_irqsave(&host->lock, flags); + if (mmc_bus_needs_resume(host)) { + spin_unlock_irqrestore(&host->lock, flags); + break; + } host->rescan_disable = 1; spin_unlock_irqrestore(&host->lock, flags); - cancel_delayed_work_sync(&host->detect); + if (cancel_delayed_work_sync(&host->detect)) + wake_unlock(&host->detect_wake_lock); if (!host->bus_ops || host->bus_ops->suspend) break; - /* Calling bus_ops->remove() with a claimed host can deadlock */ + mmc_claim_host(host); + if (host->bus_ops->remove) host->bus_ops->remove(host); - mmc_claim_host(host); mmc_detach_bus(host); mmc_power_off(host); mmc_release_host(host); @@ -2571,6 +2247,10 @@ int mmc_pm_notify(struct notifier_block *notify_block, case PM_POST_RESTORE: spin_lock_irqsave(&host->lock, flags); + if (mmc_bus_manual_resume(host)) { + spin_unlock_irqrestore(&host->lock, flags); + break; + } host->rescan_disable = 0; spin_unlock_irqrestore(&host->lock, flags); mmc_detect_change(host, 0); @@ -2581,6 +2261,22 @@ int mmc_pm_notify(struct notifier_block *notify_block, } #endif +#ifdef CONFIG_MMC_EMBEDDED_SDIO +void mmc_set_embedded_sdio_data(struct mmc_host *host, + struct sdio_cis *cis, + struct sdio_cccr *cccr, + struct sdio_embedded_func *funcs, + int num_funcs) +{ + host->embedded_sdio_data.cis = cis; + host->embedded_sdio_data.cccr = cccr; + host->embedded_sdio_data.funcs = funcs; + host->embedded_sdio_data.num_funcs = num_funcs; +} + +EXPORT_SYMBOL(mmc_set_embedded_sdio_data); +#endif + static int __init mmc_init(void) { int ret; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 3bdafbca354..14664f1fb16 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -24,7 +24,6 @@ struct mmc_bus_ops { int (*resume)(struct mmc_host *); int (*power_save)(struct mmc_host *); int (*power_restore)(struct mmc_host *); - int (*alive)(struct mmc_host *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); @@ -60,14 +59,12 @@ void mmc_rescan(struct work_struct *work); void mmc_start_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host); -int _mmc_detect_card_removed(struct mmc_host *host); - int mmc_attach_mmc(struct mmc_host *host); int mmc_attach_sd(struct mmc_host *host); int mmc_attach_sdio(struct mmc_host *host); /* Module parameters */ -extern bool use_spi_crc; +extern int use_spi_crc; /* Debugfs information for hosts and cards */ void mmc_add_host_debugfs(struct mmc_host *host); diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 35c2f85b195..998797ed67a 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -7,14 +7,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include -#include #include #include #include #include #include -#include #include #include @@ -22,14 +19,6 @@ #include "core.h" #include "mmc_ops.h" -#ifdef CONFIG_FAIL_MMC_REQUEST - -static DECLARE_FAULT_ATTR(fail_default_attr); -static char *fail_request; -module_param(fail_request, charp, 0); - -#endif /* CONFIG_FAIL_MMC_REQUEST */ - /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */ static int mmc_ios_show(struct seq_file *s, void *data) { @@ -57,8 +46,6 @@ static int mmc_ios_show(struct seq_file *s, void *data) const char *str; seq_printf(s, "clock:\t\t%u Hz\n", ios->clock); - if (host->actual_clock) - seq_printf(s, "actual clock:\t%u Hz\n", host->actual_clock); seq_printf(s, "vdd:\t\t%u ", ios->vdd); if ((1 << ios->vdd) & MMC_VDD_165_195) seq_printf(s, "(1.65 - 1.95 V)\n"); @@ -126,40 +113,12 @@ static int mmc_ios_show(struct seq_file *s, void *data) case MMC_TIMING_SD_HS: str = "sd high-speed"; break; - case MMC_TIMING_UHS_SDR50: - str = "sd uhs SDR50"; - break; - case MMC_TIMING_UHS_SDR104: - str = "sd uhs SDR104"; - break; - case MMC_TIMING_UHS_DDR50: - str = "sd uhs DDR50"; - break; - case MMC_TIMING_MMC_HS200: - str = "mmc high-speed SDR200"; - break; default: str = "invalid"; break; } seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str); - switch (ios->signal_voltage) { - case MMC_SIGNAL_VOLTAGE_330: - str = "3.30 V"; - break; - case MMC_SIGNAL_VOLTAGE_180: - str = "1.80 V"; - break; - case MMC_SIGNAL_VOLTAGE_120: - str = "1.20 V"; - break; - default: - str = "invalid"; - break; - } - seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str); - return 0; } @@ -228,15 +187,6 @@ void mmc_add_host_debugfs(struct mmc_host *host) if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), root, &host->clk_delay)) goto err_node; -#endif -#ifdef CONFIG_FAIL_MMC_REQUEST - if (fail_request) - setup_fault_attr(&fail_default_attr, fail_request); - host->fail_mmc_request = fail_default_attr; - if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request", - root, - &host->fail_mmc_request))) - goto err_node; #endif return; @@ -297,7 +247,7 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) if (err) goto out_free; - for (i = 0; i < 512; i++) + for (i = 511; i >= 0; i--) n += sprintf(buf + n, "%02x", ext_csd[i]); n += sprintf(buf + n, "\n"); BUG_ON(n != EXT_CSD_STR_LEN); diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index ee2e16b1701..e09f0a7eb65 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -32,7 +31,6 @@ static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); - mutex_destroy(&host->slot.lock); kfree(host); } @@ -55,27 +53,6 @@ static DEFINE_IDR(mmc_host_idr); static DEFINE_SPINLOCK(mmc_host_lock); #ifdef CONFIG_MMC_CLKGATE -static ssize_t clkgate_delay_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mmc_host *host = cls_dev_to_mmc_host(dev); - return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay); -} - -static ssize_t clkgate_delay_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct mmc_host *host = cls_dev_to_mmc_host(dev); - unsigned long flags, value; - - if (kstrtoul(buf, 0, &value)) - return -EINVAL; - - spin_lock_irqsave(&host->clk_lock, flags); - host->clkgate_delay = value; - spin_unlock_irqrestore(&host->clk_lock, flags); - return count; -} /* * Enabling clock gating will make the core call out to the host @@ -136,7 +113,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) static void mmc_host_clk_gate_work(struct work_struct *work) { struct mmc_host *host = container_of(work, struct mmc_host, - clk_gate_work.work); + clk_gate_work); mmc_host_clk_gate_delayed(host); } @@ -153,8 +130,6 @@ void mmc_host_clk_hold(struct mmc_host *host) { unsigned long flags; - /* cancel any clock gating work scheduled by mmc_host_clk_release() */ - cancel_delayed_work_sync(&host->clk_gate_work); mutex_lock(&host->clk_gate_mutex); spin_lock_irqsave(&host->clk_lock, flags); if (host->clk_gated) { @@ -204,8 +179,7 @@ void mmc_host_clk_release(struct mmc_host *host) host->clk_requests--; if (mmc_host_may_gate_card(host->card) && !host->clk_requests) - schedule_delayed_work(&host->clk_gate_work, - msecs_to_jiffies(host->clkgate_delay)); + queue_work(system_nrt_wq, &host->clk_gate_work); spin_unlock_irqrestore(&host->clk_lock, flags); } @@ -238,13 +212,8 @@ static inline void mmc_host_clk_init(struct mmc_host *host) host->clk_requests = 0; /* Hold MCI clock for 8 cycles by default */ host->clk_delay = 8; - /* - * Default clock gating delay is 0ms to avoid wasting power. - * This value can be tuned by writing into sysfs entry. - */ - host->clkgate_delay = 0; host->clk_gated = false; - INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); + INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); spin_lock_init(&host->clk_lock); mutex_init(&host->clk_gate_mutex); } @@ -259,7 +228,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) * Wait for any outstanding gate and then make sure we're * ungated before exiting. */ - if (cancel_delayed_work_sync(&host->clk_gate_work)) + if (cancel_work_sync(&host->clk_gate_work)) mmc_host_clk_gate_delayed(host); if (host->clk_gated) mmc_host_clk_hold(host); @@ -267,17 +236,6 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) WARN_ON(host->clk_requests > 1); } -static inline void mmc_host_clk_sysfs_init(struct mmc_host *host) -{ - host->clkgate_delay_attr.show = clkgate_delay_show; - host->clkgate_delay_attr.store = clkgate_delay_store; - sysfs_attr_init(&host->clkgate_delay_attr.attr); - host->clkgate_delay_attr.attr.name = "clkgate_delay"; - host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR; - if (device_create_file(&host->class_dev, &host->clkgate_delay_attr)) - pr_err("%s: Failed to create clkgate_delay sysfs entry\n", - mmc_hostname(host)); -} #else static inline void mmc_host_clk_init(struct mmc_host *host) @@ -288,10 +246,6 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) { } -static inline void mmc_host_clk_sysfs_init(struct mmc_host *host) -{ -} - #endif /** @@ -313,8 +267,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) if (!host) return NULL; - /* scanning will be enabled when we're ready */ - host->rescan_disable = 1; spin_lock(&mmc_host_lock); err = idr_get_new(&mmc_host_idr, host, &host->index); spin_unlock(&mmc_host_lock); @@ -330,12 +282,12 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) mmc_host_clk_init(host); - mutex_init(&host->slot.lock); - host->slot.cd_irq = -EINVAL; - spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); + wake_lock_init(&host->detect_wake_lock, WAKE_LOCK_SUSPEND, + kasprintf(GFP_KERNEL, "%s_detect", mmc_hostname(host))); INIT_DELAYED_WORK(&host->detect, mmc_rescan); + INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable); #ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify; #endif @@ -384,10 +336,10 @@ int mmc_add_host(struct mmc_host *host) #ifdef CONFIG_DEBUG_FS mmc_add_host_debugfs(host); #endif - mmc_host_clk_sysfs_init(host); mmc_start_host(host); - register_pm_notifier(&host->pm_notify); + if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY)) + register_pm_notifier(&host->pm_notify); return 0; } @@ -404,7 +356,9 @@ EXPORT_SYMBOL(mmc_add_host); */ void mmc_remove_host(struct mmc_host *host) { - unregister_pm_notifier(&host->pm_notify); + if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY)) + unregister_pm_notifier(&host->pm_notify); + mmc_stop_host(host); #ifdef CONFIG_DEBUG_FS @@ -431,6 +385,7 @@ void mmc_free_host(struct mmc_host *host) spin_lock(&mmc_host_lock); idr_remove(&mmc_host_idr, host->index); spin_unlock(&mmc_host_lock); + wake_lock_destroy(&host->detect_wake_lock); put_device(&host->class_dev); } diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index f2ab9e57812..fb8a5cd2e4a 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -15,5 +15,27 @@ int mmc_register_host_class(void); void mmc_unregister_host_class(void); +#ifdef CONFIG_MMC_CLKGATE +void mmc_host_clk_hold(struct mmc_host *host); +void mmc_host_clk_release(struct mmc_host *host); +unsigned int mmc_host_clk_rate(struct mmc_host *host); + +#else +static inline void mmc_host_clk_hold(struct mmc_host *host) +{ +} + +static inline void mmc_host_clk_release(struct mmc_host *host) +{ +} + +static inline unsigned int mmc_host_clk_rate(struct mmc_host *host) +{ + return host->ios.clock; +} +#endif + +void mmc_host_deeper_disable(struct work_struct *work); + #endif diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index e6e39111e05..69fb2275845 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -4,6 +4,7 @@ * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. + * Copyright (c) 2012 NVIDIA Corporation, All Rights Reserved. * * 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 @@ -12,7 +13,6 @@ #include #include -#include #include #include @@ -102,7 +102,7 @@ static int mmc_decode_cid(struct mmc_card *card) break; default: - pr_err("%s: card has unknown MMCA version %d\n", + printk(KERN_ERR "%s: card has unknown MMCA version %d\n", mmc_hostname(card->host), card->csd.mmca_vsn); return -EINVAL; } @@ -136,7 +136,7 @@ static int mmc_decode_csd(struct mmc_card *card) */ csd->structure = UNSTUFF_BITS(resp, 126, 2); if (csd->structure == 0) { - pr_err("%s: unrecognised CSD structure version %d\n", + printk(KERN_ERR "%s: unrecognised CSD structure version %d\n", mmc_hostname(card->host), csd->structure); return -EINVAL; } @@ -196,7 +196,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) */ ext_csd = kmalloc(512, GFP_KERNEL); if (!ext_csd) { - pr_err("%s: could not allocate a buffer to " + printk(KERN_ERR "%s: could not allocate a buffer to " "receive the ext_csd.\n", mmc_hostname(card->host)); return -ENOMEM; } @@ -218,12 +218,12 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) * stored in their CSD. */ if (card->csd.capacity == (4096 * 512)) { - pr_err("%s: unable to read EXT_CSD " + printk(KERN_ERR "%s: unable to read EXT_CSD " "on a possible high capacity card. " "Card will be ignored.\n", mmc_hostname(card->host)); } else { - pr_warning("%s: unable to read " + printk(KERN_WARNING "%s: unable to read " "EXT_CSD, performance might " "suffer.\n", mmc_hostname(card->host)); @@ -235,44 +235,12 @@ 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; - u32 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. */ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) { - int err = 0, idx; - unsigned int part_size; - u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0; + int err = 0; BUG_ON(!card); @@ -283,7 +251,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { if (card->ext_csd.raw_ext_csd_structure > 2) { - pr_err("%s: unrecognised EXT_CSD structure " + printk(KERN_ERR "%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), card->ext_csd.raw_ext_csd_structure); err = -EINVAL; @@ -293,7 +261,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.rev = ext_csd[EXT_CSD_REV]; if (card->ext_csd.rev > 6) { - pr_err("%s: unrecognised EXT_CSD revision %d\n", + printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n", mmc_hostname(card->host), card->ext_csd.rev); err = -EINVAL; goto out; @@ -314,9 +282,35 @@ 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]; - mmc_select_card_type(card); + switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { + 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 */ + printk(KERN_WARNING "%s: card is mmc v4 but doesn't " + "support any high-speed modes.\n", + mmc_hostname(card->host)); + } card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.raw_erase_timeout_mult = @@ -347,19 +341,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) * There are two boot regions of equal size, defined in * multiples of 128K. */ - if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) { - for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) { - part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; - mmc_part_add(card, part_size, - EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, - "boot%d", idx, true, - MMC_BLK_DATA_AREA_BOOT); - } - } + card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; } card->ext_csd.raw_hc_erase_gap_size = - ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; + ext_csd[EXT_CSD_PARTITION_ATTRIBUTE]; card->ext_csd.raw_sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.raw_sec_erase_mult = @@ -377,9 +363,9 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { - hc_erase_grp_sz = + u8 hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; - hc_wp_grp_sz = + u8 hc_wp_grp_sz = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.enhanced_area_en = 1; @@ -408,42 +394,6 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.enhanced_area_offset = -EINVAL; card->ext_csd.enhanced_area_size = -EINVAL; } - - /* - * General purpose partition feature support -- - * If ext_csd has the size of general purpose partitions, - * set size, part_cfg, partition name in mmc_part. - */ - if (ext_csd[EXT_CSD_PARTITION_SUPPORT] & - EXT_CSD_PART_SUPPORT_PART_EN) { - if (card->ext_csd.enhanced_area_en != 1) { - hc_erase_grp_sz = - ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; - hc_wp_grp_sz = - ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; - - card->ext_csd.enhanced_area_en = 1; - } - - for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) { - if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] && - !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] && - !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]) - continue; - part_size = - (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2] - << 16) + - (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] - << 8) + - ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3]; - part_size *= (size_t)(hc_erase_grp_sz * - hc_wp_grp_sz); - mmc_part_add(card, part_size << 19, - EXT_CSD_PART_CONFIG_ACC_GP0 + idx, - "gp%d", idx, false, - MMC_BLK_DATA_AREA_GP); - } - } card->ext_csd.sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.sec_erase_mult = @@ -452,33 +402,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.trim_timeout = 300 * ext_csd[EXT_CSD_TRIM_MULT]; - - /* - * Note that the call to mmc_part_add above defaults to read - * only. If this default assumption is changed, the call must - * take into account the value of boot_locked below. - */ - card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; - card->ext_csd.boot_ro_lockable = true; } + card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; if (card->ext_csd.rev >= 5) { - /* check whether the eMMC card supports BKOPS */ - if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) { - card->ext_csd.bkops = 1; - card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN]; - card->ext_csd.raw_bkops_status = - ext_csd[EXT_CSD_BKOPS_STATUS]; - if (!card->ext_csd.bkops_en) - pr_info("%s: BKOPS_EN bit is not set\n", - mmc_hostname(card->host)); - } - + card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; /* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { card->ext_csd.hpi = 1; if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) - card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; + card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; else card->ext_csd.hpi_cmd = MMC_SEND_STATUS; /* @@ -489,59 +422,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; } - card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; - card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; - - /* - * RPMB regions are defined in multiples of 128K. - */ - card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT]; - if (ext_csd[EXT_CSD_RPMB_MULT]) { - mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17, - EXT_CSD_PART_CONFIG_ACC_RPMB, - "rpmb", 0, false, - MMC_BLK_DATA_AREA_RPMB); - } + /* Check whether the eMMC card supports background ops */ + if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) + card->ext_csd.bk_ops = 1; } - card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; else card->erased_byte = 0x0; - /* eMMC v4.5 or later */ - if (card->ext_csd.rev >= 6) { - card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; - - card->ext_csd.generic_cmd6_time = 10 * - ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; - card->ext_csd.power_off_longtime = 10 * - ext_csd[EXT_CSD_POWER_OFF_LONG_TIME]; - - card->ext_csd.cache_size = - ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 | - ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 | - ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 | - ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24; - - if (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 1) - card->ext_csd.data_sector_size = 4096; - else - card->ext_csd.data_sector_size = 512; - - if ((ext_csd[EXT_CSD_DATA_TAG_SUPPORT] & 1) && - (ext_csd[EXT_CSD_TAG_UNIT_SIZE] <= 8)) { - card->ext_csd.data_tag_unit_size = - ((unsigned int) 1 << ext_csd[EXT_CSD_TAG_UNIT_SIZE]) * - (card->ext_csd.data_sector_size); - } else { - card->ext_csd.data_tag_unit_size = 0; - } - } else { - card->ext_csd.data_sector_size = 512; - } - out: return err; } @@ -563,12 +453,16 @@ 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) { - err = -EINVAL; + if (bus_width != MMC_BUS_WIDTH_1) + 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 == + err = (!(card->ext_csd.raw_partition_support == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && (card->ext_csd.raw_erased_mem_count == bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) && @@ -626,8 +520,6 @@ MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", card->ext_csd.enhanced_area_offset); MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); -MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); -MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); static struct attribute *mmc_std_attrs[] = { &dev_attr_cid.attr, @@ -643,8 +535,6 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_serial.attr, &dev_attr_enhanced_area_offset.attr, &dev_attr_enhanced_area_size.attr, - &dev_attr_raw_rpmb_size_mult.attr, - &dev_attr_rel_sectors.attr, NULL, }; @@ -661,166 +551,6 @@ static struct device_type mmc_type = { .groups = mmc_attr_groups, }; -/* - * Select the PowerClass for the current bus width - * If power class is defined for 4/8 bit bus in the - * extended CSD register, select it by executing the - * mmc_switch command. - */ -static int mmc_select_powerclass(struct mmc_card *card, - unsigned int bus_width, u8 *ext_csd) -{ - int err = 0; - unsigned int pwrclass_val; - unsigned int index = 0; - struct mmc_host *host; - - BUG_ON(!card); - - host = card->host; - BUG_ON(!host); - - if (ext_csd == NULL) - return 0; - - /* Power class selection is supported for versions >= 4.0 */ - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) - return 0; - - /* Power class values are defined only for 4/8 bit bus */ - if (bus_width == EXT_CSD_BUS_WIDTH_1) - return 0; - - switch (1 << host->ios.vdd) { - case MMC_VDD_165_195: - if (host->ios.clock <= 26000000) - index = EXT_CSD_PWR_CL_26_195; - else if (host->ios.clock <= 52000000) - index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? - EXT_CSD_PWR_CL_52_195 : - EXT_CSD_PWR_CL_DDR_52_195; - else if (host->ios.clock <= 200000000) - index = EXT_CSD_PWR_CL_200_195; - break; - case MMC_VDD_27_28: - case MMC_VDD_28_29: - case MMC_VDD_29_30: - case MMC_VDD_30_31: - case MMC_VDD_31_32: - case MMC_VDD_32_33: - case MMC_VDD_33_34: - case MMC_VDD_34_35: - case MMC_VDD_35_36: - if (host->ios.clock <= 26000000) - index = EXT_CSD_PWR_CL_26_360; - else if (host->ios.clock <= 52000000) - index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? - EXT_CSD_PWR_CL_52_360 : - EXT_CSD_PWR_CL_DDR_52_360; - else if (host->ios.clock <= 200000000) - index = EXT_CSD_PWR_CL_200_360; - break; - default: - pr_warning("%s: Voltage range not supported " - "for power class.\n", mmc_hostname(host)); - return -EINVAL; - } - - pwrclass_val = ext_csd[index]; - - if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8)) - pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >> - EXT_CSD_PWR_CL_8BIT_SHIFT; - else - pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >> - EXT_CSD_PWR_CL_4BIT_SHIFT; - - /* If the power class is different from the default value */ - if (pwrclass_val > 0) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_POWER_CLASS, - pwrclass_val, - card->ext_csd.generic_cmd6_time); - } - - return err; -} - -/* - * Selects the desired buswidth and switch to the HS200 mode - * if bus width set without error - */ -static int mmc_select_hs200(struct mmc_card *card) -{ - int idx, err = -EINVAL; - struct mmc_host *host; - static unsigned ext_csd_bits[] = { - EXT_CSD_BUS_WIDTH_4, - EXT_CSD_BUS_WIDTH_8, - }; - static unsigned bus_widths[] = { - MMC_BUS_WIDTH_4, - MMC_BUS_WIDTH_8, - }; - - BUG_ON(!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) - 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) - goto err; - - idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0; - - /* - * Unlike SD, MMC cards dont have a configuration register to notify - * supported bus width. So bus test command should be run to identify - * the supported bus width or compare the ext csd values of current - * bus width and ext csd values of 1 bit mode read earlier. - */ - for (; idx >= 0; idx--) { - - /* - * Host is capable of 8bit transfer, then switch - * the device to work in 8bit transfer mode. If the - * mmc switch command returns error then switch to - * 4bit transfer mode. On success set the corresponding - * bus width on the host. - */ - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BUS_WIDTH, - ext_csd_bits[idx], - card->ext_csd.generic_cmd6_time); - if (err) - continue; - - mmc_set_bus_width(card->host, bus_widths[idx]); - - if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) - err = mmc_compare_ext_csds(card, bus_widths[idx]); - else - err = mmc_bus_test(card, bus_widths[idx]); - if (!err) - break; - } - - /* switch to HS200 mode if bus width set successfully */ - if (!err) - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 2, 0); -err: - return err; -} - /* * Handle the detection and initialisation of a card. * @@ -840,16 +570,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, BUG_ON(!host); WARN_ON(!host->claimed); - /* Set correct bus mode for MMC before attempting init */ - if (!mmc_host_is_spi(host)) - mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); - /* * Since we're changing the OCR value, we seem to * need to tell some cards to go back to the idle * state. We wait 1ms to give cards time to * respond. - * mmc_go_idle is needed for eMMC that are asleep */ mmc_go_idle(host); @@ -963,11 +688,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF * bit. This bit will be lost every time after a reset or power off. */ - if (card->ext_csd.enhanced_area_en || - (card->ext_csd.rev >= 3 && (host->caps2 & MMC_CAP2_HC_ERASE_SZ))) { + if (card->ext_csd.enhanced_area_en) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_ERASE_GROUP_DEF, 1, - card->ext_csd.generic_cmd6_time); + EXT_CSD_ERASE_GROUP_DEF, 1, 0); if (err && err != -EBADMSG) goto free_card; @@ -1005,56 +728,56 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } /* - * If the host supports the power_off_notify capability then - * set the notification byte in the ext_csd register of device + * Activate high speed (if supported) */ - if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) && - (card->ext_csd.rev >= 6)) { + if ((card->ext_csd.hs_max_dtr != 0) && + (host->caps & MMC_CAP_MMC_HIGHSPEED)) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_POWER_OFF_NOTIFICATION, - EXT_CSD_POWER_ON, - card->ext_csd.generic_cmd6_time); + EXT_CSD_HS_TIMING, 1, 0); if (err && err != -EBADMSG) goto free_card; - /* - * The err can be -EBADMSG or 0, - * so check for success and update the flag - */ - if (!err) - card->ext_csd.power_off_notification = EXT_CSD_POWER_ON; + if (err) { + printk(KERN_WARNING "%s: switch to highspeed failed\n", + mmc_hostname(card->host)); + err = 0; + } else { + mmc_card_set_highspeed(card); + mmc_set_timing(card->host, MMC_TIMING_MMC_HS); + } } /* - * Activate high speed (if supported) + * Enable HPI feature (if supported) */ - if (card->ext_csd.hs_max_dtr != 0) { - err = 0; - if (card->ext_csd.hs_max_dtr > 52000000 && - host->caps2 & MMC_CAP2_HS200) - err = mmc_select_hs200(card); - else if (host->caps & MMC_CAP_MMC_HIGHSPEED) - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 1, - card->ext_csd.generic_cmd6_time); - + if (card->ext_csd.hpi && (card->host->caps & MMC_CAP_BKOPS)) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HPI_MGMT, 1, 0); if (err && err != -EBADMSG) goto free_card; + if (err) { + pr_warning("%s: Enabling HPI failed\n", + mmc_hostname(card->host)); + err = 0; + } else { + card->ext_csd.hpi_en = 1; + } + } + /* + * Enable Background ops feature (if supported) + */ + if (card->ext_csd.bk_ops && (card->host->caps & MMC_CAP_BKOPS)) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BKOPS_EN, 1, 0); + if (err && err != -EBADMSG) + goto free_card; if (err) { - pr_warning("%s: switch to highspeed failed\n", - mmc_hostname(card->host)); + pr_warning("%s: Enabling BK ops failed\n", + mmc_hostname(card->host)); err = 0; } else { - if (card->ext_csd.hs_max_dtr > 52000000 && - host->caps2 & MMC_CAP2_HS200) { - mmc_card_set_hs200(card); - mmc_set_timing(card->host, - MMC_TIMING_MMC_HS200); - } else { - mmc_card_set_highspeed(card); - mmc_set_timing(card->host, MMC_TIMING_MMC_HS); - } + card->ext_csd.bk_ops_en = 1; } } @@ -1063,11 +786,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ max_dtr = (unsigned int)-1; - if (mmc_card_highspeed(card) || mmc_card_hs200(card)) { + if (mmc_card_highspeed(card)) { if (max_dtr > card->ext_csd.hs_max_dtr) max_dtr = card->ext_csd.hs_max_dtr; - if (mmc_card_highspeed(card) && (max_dtr > 52000000)) - max_dtr = 52000000; } else if (max_dtr > card->csd.max_dtr) { max_dtr = card->csd.max_dtr; } @@ -1090,51 +811,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ddr = MMC_1_2V_DDR_MODE; } - /* - * Indicate HS200 SDR mode (if supported). - */ - if (mmc_card_hs200(card)) { - u32 ext_csd_bits; - u32 bus_width = card->host->ios.bus_width; - - /* - * For devices supporting HS200 mode, the bus width has - * to be set before executing the tuning function. If - * set before tuning, then device will respond with CRC - * errors for responses on CMD line. So for HS200 the - * sequence will be - * 1. set bus width 4bit / 8 bit (1 bit not supported) - * 2. switch to HS200 mode - * 3. set the clock to > 52Mhz <=200MHz and - * 4. execute tuning for HS200 - */ - if ((host->caps2 & MMC_CAP2_HS200) && - card->host->ops->execute_tuning) { - mmc_host_clk_hold(card->host); - err = card->host->ops->execute_tuning(card->host, - MMC_SEND_TUNING_BLOCK_HS200); - mmc_host_clk_release(card->host); - } - if (err) { - pr_warning("%s: tuning execution failed\n", - mmc_hostname(card->host)); - goto err; - } - - ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? - 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); - } - /* * Activate wide bus and DDR (if supported). */ - if (!mmc_card_hs200(card) && - (card->csd.mmca_vsn >= CSD_SPEC_VER_4) && + if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) && (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) { static unsigned ext_csd_bits[][2] = { { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 }, @@ -1156,18 +836,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, bus_width = bus_widths[idx]; if (bus_width == MMC_BUS_WIDTH_1) ddr = 0; /* no DDR for 1-bit width */ - 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); - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx][0], - card->ext_csd.generic_cmd6_time); + 0); if (!err) { mmc_set_bus_width(card->host, bus_width); @@ -1187,21 +859,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } if (!err && ddr) { - 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); - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx][1], - card->ext_csd.generic_cmd6_time); + 0); } if (err) { - pr_warning("%s: switch to bus width %d ddr %d " + printk(KERN_WARNING "%s: switch to bus width %d ddr %d " "failed\n", mmc_hostname(card->host), 1 << bus_width, ddr); goto free_card; @@ -1220,7 +884,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * * WARNING: eMMC rules are NOT the same as SD DDR */ - if (ddr == MMC_1_2V_DDR_MODE) { + if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0); if (err) @@ -1232,49 +896,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } } - /* - * Enable HPI feature (if supported) - */ - if (card->ext_csd.hpi) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HPI_MGMT, 1, - card->ext_csd.generic_cmd6_time); - if (err && err != -EBADMSG) - goto free_card; - if (err) { - pr_warning("%s: Enabling HPI failed\n", - mmc_hostname(card->host)); - err = 0; - } else - card->ext_csd.hpi_en = 1; - } - - /* - * If cache size is higher than 0, this indicates - * the existence of cache and it can be turned on. - */ - if ((host->caps2 & MMC_CAP2_CACHE_CTRL) && - card->ext_csd.cache_size > 0) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_CACHE_CTRL, 1, - card->ext_csd.generic_cmd6_time); - if (err && err != -EBADMSG) - goto free_card; - - /* - * Only if no error, cache is turned on successfully. - */ - if (err) { - pr_warning("%s: Cache is supported, " - "but failed to turn on (%d)\n", - mmc_hostname(card->host), err); - card->ext_csd.cache_ctrl = 0; - err = 0; - } else { - card->ext_csd.cache_ctrl = 1; - } - } - if (!oldcard) host->card = card; @@ -1290,35 +911,6 @@ err: return err; } -static int mmc_can_poweroff_notify(const struct mmc_card *card) -{ - return card && - mmc_card_mmc(card) && - (card->ext_csd.power_off_notification == EXT_CSD_POWER_ON); -} - -static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) -{ - unsigned int timeout = card->ext_csd.generic_cmd6_time; - int err; - - /* Use EXT_CSD_POWER_OFF_SHORT as default notification type. */ - if (notify_type == EXT_CSD_POWER_OFF_LONG) - timeout = card->ext_csd.power_off_longtime; - - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_POWER_OFF_NOTIFICATION, - notify_type, timeout); - if (err) - pr_err("%s: Power Off Notification timed out, %u\n", - mmc_hostname(card->host), timeout); - - /* Disable the power off notification after the switch operation. */ - card->ext_csd.power_off_notification = EXT_CSD_NO_POWER_NOTIFICATION; - - return err; -} - /* * Host is being removed. Free up the current card. */ @@ -1331,14 +923,6 @@ static void mmc_remove(struct mmc_host *host) host->card = NULL; } -/* - * Card detection - card is alive. - */ -static int mmc_alive(struct mmc_host *host) -{ - return mmc_send_status(host->card, NULL); -} - /* * Card detection callback from host. */ @@ -1354,7 +938,7 @@ static void mmc_detect(struct mmc_host *host) /* * Just check if our card has been removed. */ - err = _mmc_detect_card_removed(host); + err = mmc_send_status(host->card, NULL); mmc_release_host(host); @@ -1373,22 +957,16 @@ static void mmc_detect(struct mmc_host *host) */ static int mmc_suspend(struct mmc_host *host) { - int err = 0; - BUG_ON(!host); BUG_ON(!host->card); mmc_claim_host(host); - if (mmc_can_poweroff_notify(host->card)) - err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT); - else if (mmc_card_can_sleep(host)) - err = mmc_card_sleep(host); - else if (!mmc_host_is_spi(host)) - err = mmc_deselect_cards(host); - host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); + host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); - return err; + return 0; } /* @@ -1415,7 +993,7 @@ static int mmc_power_restore(struct mmc_host *host) { int ret; - host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); + host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_claim_host(host); ret = mmc_init_card(host, host->ocr, host->card); mmc_release_host(host); @@ -1461,7 +1039,6 @@ static const struct mmc_bus_ops mmc_ops = { .suspend = NULL, .resume = NULL, .power_restore = mmc_power_restore, - .alive = mmc_alive, }; static const struct mmc_bus_ops mmc_ops_unsafe = { @@ -1472,7 +1049,6 @@ static const struct mmc_bus_ops mmc_ops_unsafe = { .suspend = mmc_suspend, .resume = mmc_resume, .power_restore = mmc_power_restore, - .alive = mmc_alive, }; static void mmc_attach_bus_ops(struct mmc_host *host) @@ -1497,10 +1073,6 @@ int mmc_attach_mmc(struct mmc_host *host) BUG_ON(!host); WARN_ON(!host->claimed); - /* Set correct bus mode for MMC before attempting attach */ - if (!mmc_host_is_spi(host)) - mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); - err = mmc_send_op_cond(host, 0, &ocr); if (err) return err; @@ -1523,7 +1095,7 @@ int mmc_attach_mmc(struct mmc_host *host) * support. */ if (ocr & 0x7F) { - pr_warning("%s: card claims to support voltages " + printk(KERN_WARNING "%s: card claims to support voltages " "below the defined range. These will be ignored.\n", mmc_hostname(host)); ocr &= ~0x7F; @@ -1562,7 +1134,7 @@ remove_card: err: mmc_detach_bus(host); - pr_err("%s: error %d whilst initialising MMC card\n", + printk(KERN_ERR "%s: error %d whilst initialising MMC card\n", mmc_hostname(host), err); return err; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 6d8f7012d73..330b968393d 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -10,7 +10,6 @@ */ #include -#include #include #include @@ -21,8 +20,6 @@ #include "core.h" #include "mmc_ops.h" -#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ - static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) { int err; @@ -232,32 +229,22 @@ mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) return 0; } -/* - * NOTE: void *buf, caller for the buf is required to use DMA-capable - * buffer or on-stack buffer (with some overhead in callee). - */ static int mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, u32 opcode, void *buf, unsigned len) { - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; void *data_buf; - int is_on_stack; - is_on_stack = object_is_on_stack(buf); - if (is_on_stack) { - /* - * dma onto stack is unsafe/nonportable, but callers to this - * routine normally provide temporary on-stack buffers ... - */ - data_buf = kmalloc(len, GFP_KERNEL); - if (!data_buf) - return -ENOMEM; - } else - data_buf = buf; + /* dma onto stack is unsafe/nonportable, but callers to this + * routine normally provide temporary on-stack buffers ... + */ + data_buf = kmalloc(len, GFP_KERNEL); + if (data_buf == NULL) + return -ENOMEM; mrq.cmd = &cmd; mrq.data = &data; @@ -292,10 +279,8 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, mmc_wait_for_req(host, &mrq); - if (is_on_stack) { - memcpy(buf, data_buf, len); - kfree(data_buf); - } + memcpy(buf, data_buf, len); + kfree(data_buf); if (cmd.error) return cmd.error; @@ -308,32 +293,24 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, int mmc_send_csd(struct mmc_card *card, u32 *csd) { int ret, i; - u32 *csd_tmp; if (!mmc_host_is_spi(card->host)) return mmc_send_cxd_native(card->host, card->rca << 16, csd, MMC_SEND_CSD); - csd_tmp = kmalloc(16, GFP_KERNEL); - if (!csd_tmp) - return -ENOMEM; - - ret = mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd_tmp, 16); + ret = mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16); if (ret) - goto err; + return ret; for (i = 0;i < 4;i++) - csd[i] = be32_to_cpu(csd_tmp[i]); + csd[i] = be32_to_cpu(csd[i]); -err: - kfree(csd_tmp); - return ret; + return 0; } int mmc_send_cid(struct mmc_host *host, u32 *cid) { int ret, i; - u32 *cid_tmp; if (!mmc_host_is_spi(host)) { if (!host->card) @@ -342,20 +319,14 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid) cid, MMC_SEND_CID); } - cid_tmp = kmalloc(16, GFP_KERNEL); - if (!cid_tmp) - return -ENOMEM; - - ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid_tmp, 16); + ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16); if (ret) - goto err; + return ret; for (i = 0;i < 4;i++) - cid[i] = be32_to_cpu(cid_tmp[i]); + cid[i] = be32_to_cpu(cid[i]); -err: - kfree(cid_tmp); - return ret; + return 0; } int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) @@ -395,23 +366,21 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc) } /** - * __mmc_switch - modify EXT_CSD register + * mmc_switch - modify EXT_CSD register * @card: the MMC card associated with the data transfer * @set: cmd set values * @index: EXT_CSD register index * @value: value to program into EXT_CSD register * @timeout_ms: timeout (ms) for operation performed by register write, * timeout of zero implies maximum possible timeout - * @use_busy_signal: use the busy signal as response type * * Modifies the EXT_CSD register for selected card. */ -int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, - unsigned int timeout_ms, bool use_busy_signal) +int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, + unsigned int timeout_ms) { int err; struct mmc_command cmd = {0}; - unsigned long timeout; u32 status; BUG_ON(!card); @@ -422,25 +391,14 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, (index << 16) | (value << 8) | set; - cmd.flags = MMC_CMD_AC; - if (use_busy_signal) - cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B; - else - cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1; - - + cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; cmd.cmd_timeout_ms = timeout_ms; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; - /* No need to check card status in case of unblocking command */ - if (!use_busy_signal) - return 0; - /* Must check status to be sure of no errors */ - timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS); do { err = mmc_send_status(card, &status); if (err) @@ -449,13 +407,6 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, break; if (mmc_host_is_spi(card->host)) break; - - /* Timeout if the device never leaves the program state. */ - if (time_after(jiffies, timeout)) { - pr_err("%s: Card stuck in programming state! %s\n", - mmc_hostname(card->host), __func__); - return -ETIMEDOUT; - } } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); if (mmc_host_is_spi(card->host)) { @@ -463,7 +414,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, return -EBADMSG; } else { if (status & 0xFDFFA000) - pr_warning("%s: unexpected status %#x after " + printk(KERN_WARNING "%s: unexpected status %#x after " "switch", mmc_hostname(card->host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; @@ -471,13 +422,6 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, return 0; } -EXPORT_SYMBOL_GPL(__mmc_switch); - -int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, - unsigned int timeout_ms) -{ - return __mmc_switch(card, set, index, value, timeout_ms, true); -} EXPORT_SYMBOL_GPL(mmc_switch); int mmc_send_status(struct mmc_card *card, u32 *status) @@ -510,7 +454,7 @@ static int mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, u8 len) { - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; @@ -532,7 +476,7 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, else if (len == 4) test_buf = testdata_4bit; else { - pr_err("%s: Invalid bus_width %d\n", + printk(KERN_ERR "%s: Invalid bus_width %d\n", mmc_hostname(host), len); kfree(data_buf); return -EINVAL; @@ -608,22 +552,15 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) { struct mmc_command cmd = {0}; unsigned int opcode; + unsigned int flags; int err; - if (!card->ext_csd.hpi) { - pr_warning("%s: Card didn't support HPI command\n", - mmc_hostname(card->host)); - return -EINVAL; - } - opcode = card->ext_csd.hpi_cmd; - if (opcode == MMC_STOP_TRANSMISSION) - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; - else if (opcode == MMC_SEND_STATUS) - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.opcode = opcode; cmd.arg = card->rca << 16 | 1; + cmd.flags = flags; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { @@ -637,3 +574,46 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) return 0; } + +int mmc_send_bk_ops_cmd(struct mmc_card *card, bool is_synchronous) +{ + int err; + struct mmc_command cmd; + u32 status; + + BUG_ON(!card); + BUG_ON(!card->host); + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BKOPS_EN << 16) | + (1 << 8) | + EXT_CSD_CMD_SET_NORMAL; + if (is_synchronous) + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + else + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); + if (err) + return err; + + /* Must check status to be sure of no errors */ + do { + err = mmc_send_status(card, &status); + if (err) + return err; + if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) + break; + } while (R1_CURRENT_STATE(status) == 7); + + if (status & 0xFDFFA000) + printk(KERN_ERR "%s: unexpected status %#x after " + "switch", mmc_hostname(card->host), status); + if (status & R1_SWITCH_ERROR) + return -EBADMSG; + + return 0; +} diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 3dd8941c298..d8f157dee14 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -2,6 +2,7 @@ * linux/drivers/mmc/core/mmc_ops.h * * Copyright 2006-2007 Pierre Ossman + * Copyright (c) 2012 NVIDIA Corporation, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +28,7 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_card_sleepawake(struct mmc_host *host, int sleep); int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); +int mmc_send_bk_ops_cmd(struct mmc_card *card, bool is_synchronous); #endif diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c index 06ee1aeaace..3a596217029 100644 --- a/drivers/mmc/core/quirks.c +++ b/drivers/mmc/core/quirks.c @@ -11,7 +11,6 @@ #include #include -#include #include #ifndef SDIO_VENDOR_ID_TI @@ -22,14 +21,6 @@ #define SDIO_DEVICE_ID_TI_WL1271 0x4076 #endif -#ifndef SDIO_VENDOR_ID_STE -#define SDIO_VENDOR_ID_STE 0x0020 -#endif - -#ifndef SDIO_DEVICE_ID_STE_CW1200 -#define SDIO_DEVICE_ID_STE_CW1200 0x2280 -#endif - /* * This hook just adds a quirk for all sdio devices */ @@ -55,9 +46,6 @@ static const struct mmc_fixup mmc_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk, MMC_QUIRK_DISABLE_CD), - SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200, - add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512), - END_FIXUP }; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 74972c241df..cb2a9d4d451 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -164,7 +163,7 @@ static int mmc_decode_csd(struct mmc_card *card) csd->erase_size = 1; break; default: - pr_err("%s: unrecognised CSD structure version %d\n", + printk(KERN_ERR "%s: unrecognised CSD structure version %d\n", mmc_hostname(card->host), csd_struct); return -EINVAL; } @@ -188,7 +187,7 @@ static int mmc_decode_scr(struct mmc_card *card) scr_struct = UNSTUFF_BITS(resp, 60, 4); if (scr_struct != 0) { - pr_err("%s: unrecognised SCR structure version %d\n", + printk(KERN_ERR "%s: unrecognised SCR structure version %d\n", mmc_hostname(card->host), scr_struct); return -EINVAL; } @@ -219,7 +218,7 @@ static int mmc_read_ssr(struct mmc_card *card) u32 *ssr; if (!(card->csd.cmdclass & CCC_APP_SPEC)) { - pr_warning("%s: card lacks mandatory SD Status " + printk(KERN_WARNING "%s: card lacks mandatory SD Status " "function.\n", mmc_hostname(card->host)); return 0; } @@ -230,7 +229,7 @@ static int mmc_read_ssr(struct mmc_card *card) err = mmc_app_sd_status(card, ssr); if (err) { - pr_warning("%s: problem reading SD Status " + printk(KERN_WARNING "%s: problem reading SD Status " "register.\n", mmc_hostname(card->host)); err = 0; goto out; @@ -244,7 +243,7 @@ static int mmc_read_ssr(struct mmc_card *card) * bitfield positions accordingly. */ au = UNSTUFF_BITS(ssr, 428 - 384, 4); - if (au > 0 && au <= 9) { + if (au > 0 || au <= 9) { card->ssr.au = 1 << (au + 4); es = UNSTUFF_BITS(ssr, 408 - 384, 16); et = UNSTUFF_BITS(ssr, 402 - 384, 6); @@ -254,7 +253,7 @@ static int mmc_read_ssr(struct mmc_card *card) card->ssr.erase_offset = eo * 1000; } } else { - pr_warning("%s: SD Status: Invalid Allocation Unit " + printk(KERN_WARNING "%s: SD Status: Invalid Allocation Unit " "size.\n", mmc_hostname(card->host)); } out: @@ -274,7 +273,7 @@ static int mmc_read_switch(struct mmc_card *card) return 0; if (!(card->csd.cmdclass & CCC_SWITCH)) { - pr_warning("%s: card lacks mandatory switch " + printk(KERN_WARNING "%s: card lacks mandatory switch " "function, performance might suffer.\n", mmc_hostname(card->host)); return 0; @@ -284,18 +283,14 @@ static int mmc_read_switch(struct mmc_card *card) status = kmalloc(64, GFP_KERNEL); if (!status) { - pr_err("%s: could not allocate a buffer for " + printk(KERN_ERR "%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); return -ENOMEM; } - /* - * Find out the card's support bits with a mode 0 operation. - * The argument does not matter, as the support bits do not - * change with the arguments. - */ - err = mmc_sd_switch(card, 0, 0, 0, status); + /* Find out the supported Bus Speed Modes. */ + err = mmc_sd_switch(card, 0, 0, 1, status); if (err) { /* * If the host or the card can't do the switch, @@ -304,22 +299,60 @@ static int mmc_read_switch(struct mmc_card *card) if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) goto out; - pr_warning("%s: problem reading Bus Speed modes.\n", + printk(KERN_WARNING "%s: problem reading Bus Speed modes.\n", mmc_hostname(card->host)); err = 0; goto out; } - if (status[13] & SD_MODE_HIGH_SPEED) - card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR; - if (card->scr.sda_spec3) { card->sw_caps.sd3_bus_mode = status[13]; - /* Driver Strengths supported by the card */ + + /* Find out Driver Strengths supported by the card */ + err = mmc_sd_switch(card, 0, 2, 1, status); + if (err) { + /* + * If the host or the card can't do the switch, + * fail more gracefully. + */ + if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) + goto out; + + printk(KERN_WARNING "%s: problem reading " + "Driver Strength.\n", + mmc_hostname(card->host)); + err = 0; + + goto out; + } + card->sw_caps.sd3_drv_type = status[9]; + + /* Find out Current Limits supported by the card */ + err = mmc_sd_switch(card, 0, 3, 1, status); + if (err) { + /* + * If the host or the card can't do the switch, + * fail more gracefully. + */ + if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) + goto out; + + printk(KERN_WARNING "%s: problem reading " + "Current Limit.\n", + mmc_hostname(card->host)); + err = 0; + + goto out; + } + + card->sw_caps.sd3_curr_limit = status[7]; } + if (status[13] & 0x02) + card->sw_caps.hs_max_dtr = 50000000; + out: kfree(status); @@ -350,7 +383,7 @@ int mmc_sd_switch_hs(struct mmc_card *card) status = kmalloc(64, GFP_KERNEL); if (!status) { - pr_err("%s: could not allocate a buffer for " + printk(KERN_ERR "%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); return -ENOMEM; } @@ -360,7 +393,7 @@ int mmc_sd_switch_hs(struct mmc_card *card) goto out; if ((status[16] & 0xF) != 1) { - pr_warning("%s: Problem switching card " + printk(KERN_WARNING "%s: Problem switching card " "into high-speed mode!\n", mmc_hostname(card->host)); err = 0; @@ -417,18 +450,16 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) * information and let the hardware specific code * return what is possible given the options */ - mmc_host_clk_hold(card->host); drive_strength = card->host->ops->select_drive_strength( card->sw_caps.uhs_max_dtr, host_drv_type, card_drv_type); - mmc_host_clk_release(card->host); err = mmc_sd_switch(card, 1, 2, drive_strength, status); if (err) return err; if ((status[15] & 0xF) != drive_strength) { - pr_warning("%s: Problem setting drive strength!\n", + printk(KERN_WARNING "%s: Problem setting drive strength!\n", mmc_hostname(card->host)); return 0; } @@ -507,90 +538,72 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status) return err; if ((status[16] & 0xF) != card->sd_bus_speed) - pr_warning("%s: Problem setting bus speed mode!\n", + printk(KERN_WARNING "%s: Problem setting bus speed mode!\n", mmc_hostname(card->host)); else { mmc_set_timing(card->host, timing); + if (timing == MMC_TIMING_UHS_DDR50) + mmc_card_set_ddr_mode(card); mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr); } return 0; } -/* Get host's max current setting at its current voltage */ -static u32 sd_get_host_max_current(struct mmc_host *host) -{ - u32 voltage, max_current; - - voltage = 1 << host->ios.vdd; - switch (voltage) { - case MMC_VDD_165_195: - max_current = host->max_current_180; - break; - case MMC_VDD_29_30: - case MMC_VDD_30_31: - max_current = host->max_current_300; - break; - case MMC_VDD_32_33: - case MMC_VDD_33_34: - max_current = host->max_current_330; - break; - default: - max_current = 0; - } - - return max_current; -} - static int sd_set_current_limit(struct mmc_card *card, u8 *status) { - int current_limit = SD_SET_CURRENT_NO_CHANGE; + int current_limit = 0; int err; - u32 max_current; /* * Current limit switch is only defined for SDR50, SDR104, and DDR50 - * bus speed modes. For other bus speed modes, we do not change the - * current limit. + * bus speed modes. For other bus speed modes, we set the default + * current limit of 200mA. */ - if ((card->sd_bus_speed != UHS_SDR50_BUS_SPEED) && - (card->sd_bus_speed != UHS_SDR104_BUS_SPEED) && - (card->sd_bus_speed != UHS_DDR50_BUS_SPEED)) - return 0; - - /* - * Host has different current capabilities when operating at - * different voltages, so find out its max current first. - */ - max_current = sd_get_host_max_current(card->host); - - /* - * We only check host's capability here, if we set a limit that is - * higher than the card's maximum current, the card will be using its - * maximum current, e.g. if the card's maximum current is 300ma, and - * when we set current limit to 200ma, the card will draw 200ma, and - * when we set current limit to 400/600/800ma, the card will draw its - * maximum 300ma from the host. - */ - if (max_current >= 800) - current_limit = SD_SET_CURRENT_LIMIT_800; - else if (max_current >= 600) - current_limit = SD_SET_CURRENT_LIMIT_600; - else if (max_current >= 400) - current_limit = SD_SET_CURRENT_LIMIT_400; - else if (max_current >= 200) + if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) || + (card->sd_bus_speed == UHS_SDR104_BUS_SPEED) || + (card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) { + if (card->host->caps & MMC_CAP_MAX_CURRENT_800) { + if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800) + current_limit = SD_SET_CURRENT_LIMIT_800; + else if (card->sw_caps.sd3_curr_limit & + SD_MAX_CURRENT_600) + current_limit = SD_SET_CURRENT_LIMIT_600; + else if (card->sw_caps.sd3_curr_limit & + SD_MAX_CURRENT_400) + current_limit = SD_SET_CURRENT_LIMIT_400; + else if (card->sw_caps.sd3_curr_limit & + SD_MAX_CURRENT_200) + current_limit = SD_SET_CURRENT_LIMIT_200; + } else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) { + if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600) + current_limit = SD_SET_CURRENT_LIMIT_600; + else if (card->sw_caps.sd3_curr_limit & + SD_MAX_CURRENT_400) + current_limit = SD_SET_CURRENT_LIMIT_400; + else if (card->sw_caps.sd3_curr_limit & + SD_MAX_CURRENT_200) + current_limit = SD_SET_CURRENT_LIMIT_200; + } else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) { + if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400) + current_limit = SD_SET_CURRENT_LIMIT_400; + else if (card->sw_caps.sd3_curr_limit & + SD_MAX_CURRENT_200) + current_limit = SD_SET_CURRENT_LIMIT_200; + } else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) { + if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200) + current_limit = SD_SET_CURRENT_LIMIT_200; + } + } else current_limit = SD_SET_CURRENT_LIMIT_200; - if (current_limit != SD_SET_CURRENT_NO_CHANGE) { - err = mmc_sd_switch(card, 1, 3, current_limit, status); - if (err) - return err; - - if (((status[15] >> 4) & 0x0F) != current_limit) - pr_warning("%s: Problem setting current limit!\n", - mmc_hostname(card->host)); + err = mmc_sd_switch(card, 1, 3, current_limit, status); + if (err) + return err; - } + if (((status[15] >> 4) & 0x0F) != current_limit) + printk(KERN_WARNING "%s: Problem setting current limit!\n", + mmc_hostname(card->host)); return 0; } @@ -611,7 +624,7 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) status = kmalloc(64, GFP_KERNEL); if (!status) { - pr_err("%s: could not allocate a buffer for " + printk(KERN_ERR "%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); return -ENOMEM; } @@ -648,12 +661,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) goto out; /* SPI mode doesn't define CMD19 */ - if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) { - mmc_host_clk_hold(card->host); - err = card->host->ops->execute_tuning(card->host, - MMC_SEND_TUNING_BLOCK); - mmc_host_clk_release(card->host); - } + if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) + err = card->host->ops->execute_tuning(card->host); out: kfree(status); @@ -712,7 +721,6 @@ struct device_type sd_type = { int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) { int err; - u32 max_current; /* * Since we're changing the OCR value, we seem to @@ -740,12 +748,9 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)) ocr |= SD_OCR_S18R; - /* - * If the host can supply more than 150mA at current voltage, - * XPC should be set to 1. - */ - max_current = sd_get_host_max_current(host); - if (max_current > 150) + /* If the host can supply more than 150mA, XPC should be set to 1. */ + if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 | + MMC_CAP_SET_XPC_180)) ocr |= SD_OCR_XPC; try_again: @@ -796,6 +801,9 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, bool reinit) { int err; +#ifdef CONFIG_MMC_PARANOID_SD_INIT + int retries; +#endif if (!reinit) { /* @@ -822,7 +830,26 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, /* * Fetch switch information from card. */ +#ifdef CONFIG_MMC_PARANOID_SD_INIT + for (retries = 1; retries <= 3; retries++) { + err = mmc_read_switch(card); + if (!err) { + if (retries > 1) { + printk(KERN_WARNING + "%s: recovered\n", + mmc_hostname(host)); + } + break; + } else { + printk(KERN_WARNING + "%s: read switch failed (attempt %d)\n", + mmc_hostname(host), retries); + } + } +#else err = mmc_read_switch(card); +#endif + if (err) return err; } @@ -845,14 +872,11 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, if (!reinit) { int ro = -1; - if (host->ops->get_ro) { - mmc_host_clk_hold(card->host); + if (host->ops->get_ro) ro = host->ops->get_ro(host); - mmc_host_clk_release(card->host); - } if (ro < 0) { - pr_warning("%s: host does not " + printk(KERN_WARNING "%s: host does not " "support reading read-only " "switch. assuming write-enable.\n", mmc_hostname(host)); @@ -929,6 +953,8 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, err = mmc_send_relative_addr(host, &card->rca); if (err) return err; + + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); } if (!oldcard) { @@ -959,17 +985,14 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, goto free_card; /* Card is an ultra-high-speed card */ - mmc_card_set_uhs(card); + mmc_sd_card_set_uhs(card); /* * Since initialization is now complete, enable preset * value registers for UHS-I cards. */ - if (host->ops->enable_preset_value) { - mmc_host_clk_hold(card->host); + if (host->ops->enable_preset_value) host->ops->enable_preset_value(host, true); - mmc_host_clk_release(card->host); - } } else { /* * Attempt to change to high-speed (if supported) @@ -1020,31 +1043,41 @@ static void mmc_sd_remove(struct mmc_host *host) host->card = NULL; } -/* - * Card detection - card is alive. - */ -static int mmc_sd_alive(struct mmc_host *host) -{ - return mmc_send_status(host->card, NULL); -} - /* * Card detection callback from host. */ static void mmc_sd_detect(struct mmc_host *host) { - int err; + int err = 0; +#ifdef CONFIG_MMC_PARANOID_SD_INIT + int retries = 5; +#endif BUG_ON(!host); BUG_ON(!host->card); - + mmc_claim_host(host); /* * Just check if our card has been removed. */ - err = _mmc_detect_card_removed(host); - +#ifdef CONFIG_MMC_PARANOID_SD_INIT + while(retries) { + err = mmc_send_status(host->card, NULL); + if (err) { + retries--; + udelay(5); + continue; + } + break; + } + if (!retries) { + printk(KERN_ERR "%s(%s): Unable to re-detect card (%d)\n", + __func__, mmc_hostname(host), err); + } +#else + err = mmc_send_status(host->card, NULL); +#endif mmc_release_host(host); if (err) { @@ -1062,18 +1095,16 @@ static void mmc_sd_detect(struct mmc_host *host) */ static int mmc_sd_suspend(struct mmc_host *host) { - int err = 0; - BUG_ON(!host); BUG_ON(!host->card); mmc_claim_host(host); if (!mmc_host_is_spi(host)) - err = mmc_deselect_cards(host); + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); - return err; + return 0; } /* @@ -1085,12 +1116,31 @@ static int mmc_sd_suspend(struct mmc_host *host) static int mmc_sd_resume(struct mmc_host *host) { int err; +#ifdef CONFIG_MMC_PARANOID_SD_INIT + int retries; +#endif BUG_ON(!host); BUG_ON(!host->card); mmc_claim_host(host); +#ifdef CONFIG_MMC_PARANOID_SD_INIT + retries = 5; + while (retries) { + err = mmc_sd_init_card(host, host->ocr, host->card); + + if (err) { + printk(KERN_ERR "%s: Re-init card rc = %d (retries = %d)\n", + mmc_hostname(host), err, retries); + mdelay(5); + retries--; + continue; + } + break; + } +#else err = mmc_sd_init_card(host, host->ocr, host->card); +#endif mmc_release_host(host); return err; @@ -1114,7 +1164,6 @@ static const struct mmc_bus_ops mmc_sd_ops = { .suspend = NULL, .resume = NULL, .power_restore = mmc_sd_power_restore, - .alive = mmc_sd_alive, }; static const struct mmc_bus_ops mmc_sd_ops_unsafe = { @@ -1123,7 +1172,6 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = { .suspend = mmc_sd_suspend, .resume = mmc_sd_resume, .power_restore = mmc_sd_power_restore, - .alive = mmc_sd_alive, }; static void mmc_sd_attach_bus_ops(struct mmc_host *host) @@ -1144,16 +1192,21 @@ int mmc_attach_sd(struct mmc_host *host) { int err; u32 ocr; +#ifdef CONFIG_MMC_PARANOID_SD_INIT + int retries; +#endif BUG_ON(!host); WARN_ON(!host->claimed); + /* Make sure we are at 3.3V signalling voltage */ + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false); + if (err) + return err; + /* Disable preset value enable if already set since last time */ - if (host->ops->enable_preset_value) { - mmc_host_clk_hold(host); + if (host->ops->enable_preset_value) host->ops->enable_preset_value(host, false); - mmc_host_clk_release(host); - } err = mmc_send_app_op_cond(host, 0, &ocr); if (err) @@ -1179,7 +1232,7 @@ int mmc_attach_sd(struct mmc_host *host) * support. */ if (ocr & 0x7F) { - pr_warning("%s: card claims to support voltages " + printk(KERN_WARNING "%s: card claims to support voltages " "below the defined range. These will be ignored.\n", mmc_hostname(host)); ocr &= ~0x7F; @@ -1187,7 +1240,7 @@ int mmc_attach_sd(struct mmc_host *host) if ((ocr & MMC_VDD_165_195) && !(host->ocr_avail_sd & MMC_VDD_165_195)) { - pr_warning("%s: SD card claims to support the " + printk(KERN_WARNING "%s: SD card claims to support the " "incompletely defined 'low voltage range'. This " "will be ignored.\n", mmc_hostname(host)); ocr &= ~MMC_VDD_165_195; @@ -1206,9 +1259,27 @@ int mmc_attach_sd(struct mmc_host *host) /* * Detect and init the card. */ +#ifdef CONFIG_MMC_PARANOID_SD_INIT + retries = 5; + while (retries) { + err = mmc_sd_init_card(host, host->ocr, NULL); + if (err) { + retries--; + continue; + } + break; + } + + if (!retries) { + printk(KERN_ERR "%s: mmc_sd_init_card() failure (err = %d)\n", + mmc_hostname(host), err); + goto err; + } +#else err = mmc_sd_init_card(host, host->ocr, NULL); if (err) goto err; +#endif mmc_release_host(host); err = mmc_add_card(host->card); @@ -1226,7 +1297,7 @@ remove_card: err: mmc_detach_bus(host); - pr_err("%s: error %d whilst initialising SD card\n", + printk(KERN_ERR "%s: error %d whilst initialising SD card\n", mmc_hostname(host), err); return err; diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 274ef00b446..021fed15380 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -68,7 +67,7 @@ EXPORT_SYMBOL_GPL(mmc_app_cmd); int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, struct mmc_command *cmd, int retries) { - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; int i, err; @@ -245,7 +244,7 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) int mmc_app_send_scr(struct mmc_card *card, u32 *scr) { int err; - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; @@ -304,7 +303,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) int mmc_sd_switch(struct mmc_card *card, int mode, int group, u8 value, u8 *resp) { - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; @@ -349,7 +348,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, int mmc_app_sd_status(struct mmc_card *card, void *ssr) { int err; - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2273ce6b6c1..3d8a5e41a48 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -28,6 +27,10 @@ #include "sdio_ops.h" #include "sdio_cis.h" +#ifdef CONFIG_MMC_EMBEDDED_SDIO +#include +#endif + static int sdio_read_fbr(struct sdio_func *func) { int ret; @@ -98,11 +101,10 @@ fail: return ret; } -static int sdio_read_cccr(struct mmc_card *card, u32 ocr) +static int sdio_read_cccr(struct mmc_card *card) { int ret; int cccr_vsn; - int uhs = ocr & R4_18V_PRESENT; unsigned char data; unsigned char speed; @@ -150,7 +152,7 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr) card->scr.sda_spec3 = 0; card->sw_caps.sd3_bus_mode = 0; card->sw_caps.sd3_drv_type = 0; - if (cccr_vsn >= SDIO_CCCR_REV_3_00 && uhs) { + if (cccr_vsn >= SDIO_CCCR_REV_3_00) { card->scr.sda_spec3 = 1; ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_UHS, 0, &data); @@ -218,12 +220,6 @@ static int sdio_enable_wide(struct mmc_card *card) if (ret) return ret; - if ((ctrl & SDIO_BUS_WIDTH_MASK) == SDIO_BUS_WIDTH_RESERVED) - pr_warning("%s: SDIO_CCCR_IF is invalid: 0x%02x\n", - mmc_hostname(card->host), ctrl); - - /* set as 4-bit bus width */ - ctrl &= ~SDIO_BUS_WIDTH_MASK; ctrl |= SDIO_BUS_WIDTH_4BIT; ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); @@ -564,8 +560,7 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) /* Initialize and start re-tuning timer */ if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) - err = card->host->ops->execute_tuning(card->host, - MMC_SEND_TUNING_BLOCK); + err = card->host->ops->execute_tuning(card->host); out: @@ -641,7 +636,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, /* * If the host and card support UHS-I mode request the card * to switch to 1.8V signaling level. No 1.8v signalling if - * UHS mode is not enabled to maintain compatibility and some + * UHS mode is not enabled to maintain compatibilty and some * systems that claim 1.8v signalling in fact do not support * it. */ @@ -650,8 +645,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) { - err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, - true); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true); if (err) { ocr &= ~R4_18V_PRESENT; host->ocr &= ~R4_18V_PRESENT; @@ -677,6 +671,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, */ if (oldcard) oldcard->rca = card->rca; + + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); } /* @@ -716,19 +712,35 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, goto finish; } - /* - * Read the common registers. - */ - err = sdio_read_cccr(card, ocr); - if (err) - goto remove; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (host->embedded_sdio_data.cccr) + memcpy(&card->cccr, host->embedded_sdio_data.cccr, sizeof(struct sdio_cccr)); + else { +#endif + /* + * Read the common registers. + */ + err = sdio_read_cccr(card); + if (err) + goto remove; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + } +#endif - /* - * Read the common CIS tuples. - */ - err = sdio_read_common_cis(card); - if (err) - goto remove; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (host->embedded_sdio_data.cis) + memcpy(&card->cis, host->embedded_sdio_data.cis, sizeof(struct sdio_cis)); + else { +#endif + /* + * Read the common CIS tuples. + */ + err = sdio_read_common_cis(card); + if (err) + goto remove; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + } +#endif if (oldcard) { int same = (card->cis.vendor == oldcard->cis.vendor && @@ -769,7 +781,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, goto remove; /* Card is an ultra-high-speed card */ - mmc_card_set_uhs(card); + mmc_sd_card_set_uhs(card); } else { /* * Switch to high-speed (if supported). @@ -828,14 +840,6 @@ static void mmc_sdio_remove(struct mmc_host *host) host->card = NULL; } -/* - * Card detection - card is alive. - */ -static int mmc_sdio_alive(struct mmc_host *host) -{ - return mmc_select_card(host->card); -} - /* * Card detection callback from host. */ @@ -858,7 +862,7 @@ static void mmc_sdio_detect(struct mmc_host *host) /* * Just check if our card has been removed. */ - err = _mmc_detect_card_removed(host); + err = mmc_select_card(host->card); mmc_release_host(host); @@ -950,7 +954,7 @@ static int mmc_sdio_resume(struct mmc_host *host) } if (!err && host->sdio_irqs) - wake_up_process(host->sdio_irq_thread); + mmc_signal_sdio_irq(host); mmc_release_host(host); /* @@ -1002,7 +1006,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host) * With these steps taken, mmc_select_voltage() is also required to * restore the correct voltage setting of the card. */ - sdio_reset(host); mmc_go_idle(host); mmc_send_if_cond(host, host->ocr_avail); @@ -1037,7 +1040,6 @@ static const struct mmc_bus_ops mmc_sdio_ops = { .suspend = mmc_sdio_suspend, .resume = mmc_sdio_resume, .power_restore = mmc_sdio_power_restore, - .alive = mmc_sdio_alive, }; @@ -1066,7 +1068,7 @@ int mmc_attach_sdio(struct mmc_host *host) * support. */ if (ocr & 0x7F) { - pr_warning("%s: card claims to support voltages " + printk(KERN_WARNING "%s: card claims to support voltages " "below the defined range. These will be ignored.\n", mmc_hostname(host)); ocr &= ~0x7F; @@ -1123,14 +1125,36 @@ int mmc_attach_sdio(struct mmc_host *host) funcs = (ocr & 0x70000000) >> 28; card->sdio_funcs = 0; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (host->embedded_sdio_data.funcs) + card->sdio_funcs = funcs = host->embedded_sdio_data.num_funcs; +#endif + /* * Initialize (but don't add) all present functions. */ for (i = 0; i < funcs; i++, card->sdio_funcs++) { - err = sdio_init_func(host->card, i + 1); - if (err) - goto remove; - +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (host->embedded_sdio_data.funcs) { + struct sdio_func *tmp; + + tmp = sdio_alloc_func(host->card); + if (IS_ERR(tmp)) + goto remove; + tmp->num = (i + 1); + card->sdio_func[i] = tmp; + tmp->class = host->embedded_sdio_data.funcs[i].f_class; + tmp->max_blksize = host->embedded_sdio_data.funcs[i].f_maxblksize; + tmp->vendor = card->cis.vendor; + tmp->device = card->cis.device; + } else { +#endif + err = sdio_init_func(host->card, i + 1); + if (err) + goto remove; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + } +#endif /* * Enable Runtime PM for this func (if supported) */ @@ -1172,9 +1196,83 @@ remove: err: mmc_detach_bus(host); - pr_err("%s: error %d whilst initialising SDIO card\n", + printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", mmc_hostname(host), err); return err; } +int sdio_reset_comm(struct mmc_card *card) +{ + struct mmc_host *host = card->host; + u32 ocr; + int err; + + printk("%s():\n", __func__); + mmc_claim_host(host); + + mmc_go_idle(host); + + mmc_set_clock(host, host->f_min); + + err = mmc_send_io_op_cond(host, 0, &ocr); + if (err) + goto err; + + host->ocr = mmc_select_voltage(host, ocr); + if (!host->ocr) { + err = -EINVAL; + goto err; + } + + err = mmc_send_io_op_cond(host, host->ocr, &ocr); + if (err) + goto err; + + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host, use_spi_crc); + if (err) + goto err; + } + + if (!mmc_host_is_spi(host)) { + err = mmc_send_relative_addr(host, &card->rca); + if (err) + goto err; + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err) + goto err; + } + + /* + * Switch to high-speed (if supported). + */ + err = sdio_enable_hs(card); + if (err > 0) + mmc_sd_go_highspeed(card); + else if (err) + goto err; + + /* + * Change to the card's maximum speed. + */ + mmc_set_clock(host, mmc_sdio_get_max_clock(card)); + + err = sdio_enable_4bit_bus(card); + if (err > 0) + mmc_set_bus_width(host, MMC_BUS_WIDTH_4); + else if (err) + goto err; + + mmc_release_host(host); + return 0; +err: + printk("%s: Error resetting SDIO communications (%d)\n", + mmc_hostname(host), err); + mmc_release_host(host); + return err; +} +EXPORT_SYMBOL(sdio_reset_comm); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 5e57048e2c1..ca58c307a12 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -13,7 +13,6 @@ #include #include -#include #include #include @@ -24,6 +23,10 @@ #include "sdio_cis.h" #include "sdio_bus.h" +#ifdef CONFIG_MMC_EMBEDDED_SDIO +#include +#endif + /* show configuration fields */ #define sdio_config_attr(field, format_string) \ static ssize_t \ @@ -174,7 +177,7 @@ static int sdio_bus_remove(struct device *dev) drv->remove(func); if (func->irq_handler) { - pr_warning("WARNING: driver %s did not remove " + printk(KERN_WARNING "WARNING: driver %s did not remove " "its interrupt handler!\n", drv->name); sdio_claim_host(func); sdio_release_irq(func); @@ -192,22 +195,9 @@ static int sdio_bus_remove(struct device *dev) return ret; } -#ifdef CONFIG_PM - -#ifdef CONFIG_PM_SLEEP -static int pm_no_operation(struct device *dev) -{ - /* - * Prevent the PM core from calling SDIO device drivers' suspend - * callback routines, which it is not supposed to do, by using this - * empty function as the bus type suspend callaback for SDIO. - */ - return 0; -} -#endif +#ifdef CONFIG_PM_RUNTIME static const struct dev_pm_ops sdio_bus_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation) SET_RUNTIME_PM_OPS( pm_generic_runtime_suspend, pm_generic_runtime_resume, @@ -217,11 +207,11 @@ static const struct dev_pm_ops sdio_bus_pm_ops = { #define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops) -#else /* !CONFIG_PM */ +#else /* !CONFIG_PM_RUNTIME */ #define SDIO_PM_OPS_PTR NULL -#endif /* !CONFIG_PM */ +#endif /* !CONFIG_PM_RUNTIME */ static struct bus_type sdio_bus_type = { .name = "sdio", @@ -270,9 +260,17 @@ static void sdio_release_func(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); - sdio_free_func_cis(func); +#ifdef CONFIG_MMC_EMBEDDED_SDIO + /* + * If this device is embedded then we never allocated + * cis tables for this func + */ + if (!func->card->host->embedded_sdio_data.funcs) +#endif + sdio_free_func_cis(func); - kfree(func->info); + if (func->info) + kfree(func->info); kfree(func); } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index 8e94e555b78..541bdb89e0c 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -132,7 +132,7 @@ static int cis_tpl_parse(struct mmc_card *card, struct sdio_func *func, ret = -EINVAL; } if (ret && ret != -EILSEQ && ret != -ENOENT) { - pr_err("%s: bad %s tuple 0x%02x (%u bytes)\n", + printk(KERN_ERR "%s: bad %s tuple 0x%02x (%u bytes)\n", mmc_hostname(card->host), tpl_descr, code, size); } } else { @@ -313,7 +313,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) if (ret == -ENOENT) { /* warn about unknown tuples */ - pr_warn_ratelimited("%s: queuing unknown" + printk(KERN_WARNING "%s: queuing unknown" " CIS tuple 0x%02x (%u bytes)\n", mmc_hostname(card->host), tpl_code, tpl_link); diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 78cb4d5d9d5..549a3414464 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -9,7 +9,6 @@ * your option) any later version. */ -#include #include #include #include @@ -188,16 +187,14 @@ EXPORT_SYMBOL_GPL(sdio_set_block_size); */ static inline unsigned int sdio_max_byte_size(struct sdio_func *func) { - unsigned mval = func->card->host->max_blk_size; + unsigned mval = min(func->card->host->max_seg_size, + func->card->host->max_blk_size); if (mmc_blksz_for_byte_mode(func->card)) mval = min(mval, func->cur_blksize); else mval = min(mval, func->max_blksize); - if (mmc_card_broken_byte_mode_512(func->card)) - return min(mval, 511u); - return min(mval, 512u); /* maximum size for byte mode */ } @@ -310,10 +307,13 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, /* Do the bulk of the transfer using block mode (if supported). */ if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) { /* Blocks per command is limited by host count, host transfer - * size and the maximum for IO_RW_EXTENDED of 511 blocks. */ - max_blocks = min(func->card->host->max_blk_count, 511u); + * size (we only use a single sg entry) and the maximum for + * IO_RW_EXTENDED of 511 blocks. */ + max_blocks = min(func->card->host->max_blk_count, + func->card->host->max_seg_size / func->cur_blksize); + max_blocks = min(max_blocks, 511u); - while (remainder >= func->cur_blksize) { + while (remainder > func->cur_blksize) { unsigned blocks; blocks = remainder / func->cur_blksize; @@ -338,9 +338,8 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, while (remainder > 0) { size = min(remainder, sdio_max_byte_size(func)); - /* Indicate byte mode by setting "blocks" = 0 */ ret = mmc_io_rw_extended(func->card, write, func->num, addr, - incr_addr, buf, 0, size); + incr_addr, buf, 1, size); if (ret) return ret; @@ -383,6 +382,39 @@ u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret) } EXPORT_SYMBOL_GPL(sdio_readb); +/** + * sdio_readb_ext - read a single byte from a SDIO function + * @func: SDIO function to access + * @addr: address to read + * @err_ret: optional status value from transfer + * @in: value to add to argument + * + * Reads a single byte from the address space of a given SDIO + * function. If there is a problem reading the address, 0xff + * is returned and @err_ret will contain the error code. + */ +unsigned char sdio_readb_ext(struct sdio_func *func, unsigned int addr, + int *err_ret, unsigned in) +{ + int ret; + unsigned char val; + + BUG_ON(!func); + + if (err_ret) + *err_ret = 0; + + ret = mmc_io_rw_direct(func->card, 0, func->num, addr, (u8)in, &val); + if (ret) { + if (err_ret) + *err_ret = ret; + return 0xFF; + } + + return val; +} +EXPORT_SYMBOL_GPL(sdio_readb_ext); + /** * sdio_writeb - write a single byte to a SDIO function * @func: SDIO function to access diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 3d8ceb4084d..03ead028d2c 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -28,27 +27,25 @@ #include "sdio_ops.h" -static int process_sdio_pending_irqs(struct mmc_host *host) +static int process_sdio_pending_irqs(struct mmc_card *card) { - 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 - * and we know an IRQ was signaled then call irq handler directly. - * Otherwise do the full probe. + * call irq handler directly */ func = card->sdio_single_irq; - if (func && host->sdio_irq_pending) { + if (func) { func->irq_handler(func); return 1; } ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending); if (ret) { - pr_debug("%s: error %d reading SDIO_CCCR_INTx\n", + printk(KERN_DEBUG "%s: error %d reading SDIO_CCCR_INTx\n", mmc_card_id(card), ret); return ret; } @@ -58,7 +55,7 @@ static int process_sdio_pending_irqs(struct mmc_host *host) if (pending & (1 << i)) { func = card->sdio_func[i - 1]; if (!func) { - pr_warning("%s: pending IRQ for " + printk(KERN_WARNING "%s: pending IRQ for " "non-existent function\n", mmc_card_id(card)); ret = -EINVAL; @@ -66,7 +63,7 @@ static int process_sdio_pending_irqs(struct mmc_host *host) func->irq_handler(func); count++; } else { - pr_warning("%s: pending IRQ with no handler\n", + printk(KERN_WARNING "%s: pending IRQ with no handler\n", sdio_func_id(func)); ret = -EINVAL; } @@ -118,8 +115,7 @@ 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); - host->sdio_irq_pending = false; + ret = process_sdio_pending_irqs(host->card); mmc_release_host(host); /* @@ -149,21 +145,15 @@ static int sdio_irq_thread(void *_host) } set_current_state(TASK_INTERRUPTIBLE); - if (host->caps & MMC_CAP_SDIO_IRQ) { - mmc_host_clk_hold(host); + if (host->caps & MMC_CAP_SDIO_IRQ) host->ops->enable_sdio_irq(host, 1); - mmc_host_clk_release(host); - } if (!kthread_should_stop()) schedule_timeout(period); set_current_state(TASK_RUNNING); } while (!kthread_should_stop()); - if (host->caps & MMC_CAP_SDIO_IRQ) { - mmc_host_clk_hold(host); + if (host->caps & MMC_CAP_SDIO_IRQ) host->ops->enable_sdio_irq(host, 0); - mmc_host_clk_release(host); - } pr_debug("%s: IRQ thread exiting with code %d\n", mmc_hostname(host), ret); diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 62508b457c4..f087d876c57 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -121,16 +121,15 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) { - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; - struct scatterlist sg, *sg_ptr; - struct sg_table sgtable; - unsigned int nents, left_size, i; - unsigned int seg_size = card->host->max_seg_size; + struct scatterlist sg; BUG_ON(!card); BUG_ON(fn > 7); + BUG_ON(blocks == 1 && blksz > 512); + WARN_ON(blocks == 0); WARN_ON(blksz == 0); /* sanity check */ @@ -145,46 +144,24 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, cmd.arg |= fn << 28; cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; cmd.arg |= addr << 9; - if (blocks == 0) + if (blocks == 1 && blksz <= 512) cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ else cmd.arg |= 0x08000000 | blocks; /* block mode */ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; data.blksz = blksz; - /* Code in host drivers/fwk assumes that "blocks" always is >=1 */ - data.blocks = blocks ? blocks : 1; + data.blocks = blocks; data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; - left_size = data.blksz * data.blocks; - nents = (left_size - 1) / seg_size + 1; - if (nents > 1) { - if (sg_alloc_table(&sgtable, nents, GFP_KERNEL)) - return -ENOMEM; - - data.sg = sgtable.sgl; - data.sg_len = nents; - - for_each_sg(data.sg, sg_ptr, data.sg_len, i) { - sg_set_page(sg_ptr, virt_to_page(buf + (i * seg_size)), - min(seg_size, left_size), - offset_in_page(buf + (i * seg_size))); - left_size = left_size - seg_size; - } - } else { - data.sg = &sg; - data.sg_len = 1; - - sg_init_one(&sg, buf, left_size); - } + sg_init_one(&sg, buf, blksz * blocks); mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); - if (nents > 1) - sg_free_table(&sgtable); - if (cmd.error) return cmd.error; if (data.error) diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c deleted file mode 100644 index 16a1c0b6f26..00000000000 --- a/drivers/mmc/core/slot-gpio.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Generic GPIO card-detect helper - * - * Copyright (C) 2011, Guennadi Liakhovetski - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -struct mmc_gpio { - int ro_gpio; - int cd_gpio; - char *ro_label; - char cd_label[0]; -}; - -static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) -{ - /* Schedule a card detection after a debounce timeout */ - struct mmc_host *host = dev_id; - - if (host->ops->card_event) - host->ops->card_event(host); - - mmc_detect_change(host, msecs_to_jiffies(200)); - - return IRQ_HANDLED; -} - -static int mmc_gpio_alloc(struct mmc_host *host) -{ - size_t len = strlen(dev_name(host->parent)) + 4; - struct mmc_gpio *ctx; - - mutex_lock(&host->slot.lock); - - ctx = host->slot.handler_priv; - if (!ctx) { - /* - * devm_kzalloc() can be called after device_initialize(), even - * before device_add(), i.e., between mmc_alloc_host() and - * mmc_add_host() - */ - ctx = devm_kzalloc(&host->class_dev, sizeof(*ctx) + 2 * len, - GFP_KERNEL); - if (ctx) { - ctx->ro_label = ctx->cd_label + len; - snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); - snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); - ctx->cd_gpio = -EINVAL; - ctx->ro_gpio = -EINVAL; - host->slot.handler_priv = ctx; - } - } - - mutex_unlock(&host->slot.lock); - - return ctx ? 0 : -ENOMEM; -} - -int mmc_gpio_get_ro(struct mmc_host *host) -{ - struct mmc_gpio *ctx = host->slot.handler_priv; - - if (!ctx || !gpio_is_valid(ctx->ro_gpio)) - return -ENOSYS; - - return !gpio_get_value_cansleep(ctx->ro_gpio) ^ - !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); -} -EXPORT_SYMBOL(mmc_gpio_get_ro); - -int mmc_gpio_get_cd(struct mmc_host *host) -{ - struct mmc_gpio *ctx = host->slot.handler_priv; - - if (!ctx || !gpio_is_valid(ctx->cd_gpio)) - return -ENOSYS; - - return !gpio_get_value_cansleep(ctx->cd_gpio) ^ - !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); -} -EXPORT_SYMBOL(mmc_gpio_get_cd); - -int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) -{ - struct mmc_gpio *ctx; - int ret; - - if (!gpio_is_valid(gpio)) - return -EINVAL; - - ret = mmc_gpio_alloc(host); - if (ret < 0) - return ret; - - ctx = host->slot.handler_priv; - - ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->ro_label); - if (ret < 0) - return ret; - - ctx->ro_gpio = gpio; - - return 0; -} -EXPORT_SYMBOL(mmc_gpio_request_ro); - -int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) -{ - struct mmc_gpio *ctx; - int irq = gpio_to_irq(gpio); - int ret; - - ret = mmc_gpio_alloc(host); - if (ret < 0) - return ret; - - ctx = host->slot.handler_priv; - - ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label); - if (ret < 0) - /* - * don't bother freeing memory. It might still get used by other - * slot functions, in any case it will be freed, when the device - * is destroyed. - */ - return ret; - - /* - * Even if gpio_to_irq() returns a valid IRQ number, the platform might - * still prefer to poll, e.g., because that IRQ number is already used - * by another unit and cannot be shared. - */ - if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) - irq = -EINVAL; - - if (irq >= 0) { - ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - ctx->cd_label, host); - if (ret < 0) - irq = ret; - } - - host->slot.cd_irq = irq; - - if (irq < 0) - host->caps |= MMC_CAP_NEEDS_POLL; - - ctx->cd_gpio = gpio; - - return 0; -} -EXPORT_SYMBOL(mmc_gpio_request_cd); - -void mmc_gpio_free_ro(struct mmc_host *host) -{ - struct mmc_gpio *ctx = host->slot.handler_priv; - int gpio; - - if (!ctx || !gpio_is_valid(ctx->ro_gpio)) - return; - - gpio = ctx->ro_gpio; - ctx->ro_gpio = -EINVAL; - - gpio_free(gpio); -} -EXPORT_SYMBOL(mmc_gpio_free_ro); - -void mmc_gpio_free_cd(struct mmc_host *host) -{ - struct mmc_gpio *ctx = host->slot.handler_priv; - int gpio; - - if (!ctx || !gpio_is_valid(ctx->cd_gpio)) - return; - - if (host->slot.cd_irq >= 0) { - free_irq(host->slot.cd_irq, host); - host->slot.cd_irq = -EINVAL; - } - - gpio = ctx->cd_gpio; - ctx->cd_gpio = -EINVAL; - - gpio_free(gpio); -} -EXPORT_SYMBOL(mmc_gpio_free_cd); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 8d13c659452..8c87096531e 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -81,18 +81,6 @@ config MMC_RICOH_MMC If unsure, say Y. -config MMC_SDHCI_ACPI - tristate "SDHCI support for ACPI enumerated SDHCI controllers" - depends on MMC_SDHCI && ACPI - help - This selects support for ACPI enumerated SDHCI controllers, - identified by ACPI Compatibility ID PNP0D40 or specific - ACPI Hardware IDs. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - config MMC_SDHCI_PLTFM tristate "SDHCI platform and OF driver helper" depends on MMC_SDHCI @@ -142,13 +130,13 @@ config MMC_SDHCI_CNS3XXX If unsure, say N. config MMC_SDHCI_ESDHC_IMX - tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" - depends on ARCH_MXC + tristate "SDHCI platform support for the Freescale eSDHC i.MX controller" + depends on ARCH_MX25 || ARCH_MX35 || ARCH_MX5 depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS help - This selects the Freescale eSDHC/uSDHC controller support - found on i.MX25, i.MX35 i.MX5x and i.MX6x. + This selects the Freescale eSDHC controller support on the platform + bus, found on platforms like mx35/51. If you have a controller with this interface, say Y or M here. @@ -275,15 +263,30 @@ config MMC_WBSD config MMC_AU1X tristate "Alchemy AU1XX0 MMC Card Interface support" - depends on MIPS_ALCHEMY + depends on SOC_AU1200 help This selects the AMD Alchemy(R) Multimedia card interface. If you have a Alchemy platform with a MMC slot, say Y or M here. If unsure, say N. +choice + prompt "Atmel SD/MMC Driver" + depends on AVR32 || ARCH_AT91 + default MMC_ATMELMCI if AVR32 + help + Choose which driver to use for the Atmel MCI Silicon + +config MMC_AT91 + tristate "AT91 SD/MMC Card Interface support" + depends on ARCH_AT91 + help + This selects the AT91 MCI controller. + + If unsure, say N. + config MMC_ATMELMCI - tristate "Atmel SD/MMC Driver (Multimedia Card Interface)" + tristate "Atmel Multimedia Card Interface support" depends on AVR32 || ARCH_AT91 help This selects the Atmel Multimedia Card Interface driver. If @@ -292,6 +295,8 @@ config MMC_ATMELMCI If unsure, say N. +endchoice + config MMC_ATMELMCI_DMA bool "Atmel MCI DMA support" depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE @@ -302,6 +307,16 @@ 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 @@ -311,11 +326,11 @@ config MMC_MSM support for SDIO devices. config MMC_MXC - tristate "Freescale i.MX21/27/31 Multimedia Card Interface support" - depends on ARCH_MXC + tristate "Freescale i.MX2/3 Multimedia Card Interface support" + depends on MACH_MX21 || MACH_MX27 || ARCH_MX31 help - This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card - Interface. If you have a i.MX platform with a Multimedia Card slot, + This selects the Freescale i.MX2/3 Multimedia card Interface. + If you have a i.MX platform with a Multimedia Card slot, say Y or M here. If unsure, say N. @@ -380,7 +395,7 @@ config MMC_SPI config MMC_S3C tristate "Samsung S3C SD/MMC Card Interface support" - depends on ARCH_S3C24XX + depends on ARCH_S3C2410 help This selects a driver for the MCI interface found in Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. @@ -462,6 +477,7 @@ config MMC_SDHI config MMC_CB710 tristate "ENE CB710 MMC/SD Interface support" depends on PCI + select MISC_DEVICES select CB710_CORE help This option enables support for MMC/SD part of ENE CB710/720 Flash @@ -518,40 +534,6 @@ config MMC_DW_IDMAC Designware Mobile Storage IP block. This disables the external DMA interface. -config MMC_DW_PLTFM - tristate "Synopsys Designware MCI Support as platform device" - depends on MMC_DW - default y - help - This selects the common helper functions support for Host Controller - Interface based platform driver. Please select this option if the IP - is present as a platform device. This is the common interface for the - Synopsys Designware IP. - - If you have a controller with this interface, say Y or M here. - - If unsure, say Y. - -config MMC_DW_EXYNOS - tristate "Exynos specific extensions for Synopsys DW Memory Card Interface" - depends on MMC_DW - select MMC_DW_PLTFM - help - This selects support for Samsung Exynos SoC specific extensions to the - Synopsys DesignWare Memory Card Interface driver. Select this option - for platforms based on Exynos4 and Exynos5 SoC's. - -config MMC_DW_PCI - tristate "Synopsys Designware MCI support on PCI bus" - depends on MMC_DW && PCI - help - This selects the PCI bus for the Synopsys Designware Mobile Storage IP. - Select this option if the IP is present on PCI platform. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - config MMC_SH_MMCIF tristate "SuperH Internal MMCIF support" depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE) @@ -613,21 +595,3 @@ config MMC_USHC Note: These controllers only support SDIO cards and do not support MMC or SD memory cards. - -config MMC_WMT - tristate "Wondermedia SD/MMC Host Controller support" - depends on ARCH_VT8500 - default y - help - This selects support for the SD/MMC Host Controller on - Wondermedia WM8505/WM8650 based SoCs. - - To compile this driver as a module, choose M here: the - module will be called wmt-sdmmc. - -config MMC_REALTEK_PCI - tristate "Realtek PCI-E SD/MMC Card Interface Driver" - depends on MFD_RTSX_PCI - help - Say Y here to include driver code to support SD/MMC card interface - of Realtek PCI-E card reader diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index e4e218c930b..f5ea51bd0ed 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -1,15 +1,15 @@ # # Makefile for MMC/SD host controller drivers # +GCOV_PROFILE_sdhci-tegra.o := y 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 obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o -obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o -obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o @@ -18,6 +18,7 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o +obj-$(CONFIG_MMC_AT91) += at91_mci.o obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o obj-$(CONFIG_MMC_MSM) += msm_sdcc.o @@ -38,18 +39,10 @@ obj-$(CONFIG_MMC_CB710) += cb710-mmc.o obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o obj-$(CONFIG_MMC_DW) += dw_mmc.o -obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o -obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o -obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o obj-$(CONFIG_MMC_VUB300) += vub300.o obj-$(CONFIG_MMC_USHC) += ushc.o -obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o - -obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o - -obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index c97001e1522..fc8a0fe7c5c 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -17,148 +17,112 @@ #define __DRIVERS_MMC_ATMEL_MCI_H__ /* MCI Register Definitions */ -#define ATMCI_CR 0x0000 /* Control */ -# define ATMCI_CR_MCIEN ( 1 << 0) /* MCI Enable */ -# define ATMCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */ -# define ATMCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */ -# define ATMCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */ -# define ATMCI_CR_SWRST ( 1 << 7) /* Software Reset */ -#define ATMCI_MR 0x0004 /* Mode */ -# define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ -# define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ -# define ATMCI_MR_RDPROOF ( 1 << 11) /* Read Proof */ -# define ATMCI_MR_WRPROOF ( 1 << 12) /* Write Proof */ -# define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ -# define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ -# define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ -# define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ -#define ATMCI_DTOR 0x0008 /* Data Timeout */ -# define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ -# define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ -#define ATMCI_SDCR 0x000c /* SD Card / SDIO */ -# define ATMCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */ -# define ATMCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */ -# define ATMCI_SDCSEL_MASK ( 3 << 0) -# define ATMCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */ -# define ATMCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */ -# define ATMCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */ -# define ATMCI_SDCBUS_MASK ( 3 << 6) -#define ATMCI_ARGR 0x0010 /* Command Argument */ -#define ATMCI_CMDR 0x0014 /* Command */ -# define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ -# define ATMCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */ -# define ATMCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */ -# define ATMCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */ -# define ATMCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */ -# define ATMCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */ -# define ATMCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */ -# define ATMCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */ -# define ATMCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */ -# define ATMCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */ -# define ATMCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */ -# define ATMCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */ -# define ATMCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */ -# define ATMCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */ -# define ATMCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */ -# define ATMCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */ -# define ATMCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */ -# define ATMCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */ -# define ATMCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */ -# define ATMCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */ -# define ATMCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */ -# define ATMCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */ -#define ATMCI_BLKR 0x0018 /* Block */ -# define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */ -# define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ -#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ -# define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ -# define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ -#define ATMCI_RSPR 0x0020 /* Response 0 */ -#define ATMCI_RSPR1 0x0024 /* Response 1 */ -#define ATMCI_RSPR2 0x0028 /* Response 2 */ -#define ATMCI_RSPR3 0x002c /* Response 3 */ -#define ATMCI_RDR 0x0030 /* Receive Data */ -#define ATMCI_TDR 0x0034 /* Transmit Data */ -#define ATMCI_SR 0x0040 /* Status */ -#define ATMCI_IER 0x0044 /* Interrupt Enable */ -#define ATMCI_IDR 0x0048 /* Interrupt Disable */ -#define ATMCI_IMR 0x004c /* Interrupt Mask */ -# define ATMCI_CMDRDY ( 1 << 0) /* Command Ready */ -# define ATMCI_RXRDY ( 1 << 1) /* Receiver Ready */ -# define ATMCI_TXRDY ( 1 << 2) /* Transmitter Ready */ -# define ATMCI_BLKE ( 1 << 3) /* Data Block Ended */ -# define ATMCI_DTIP ( 1 << 4) /* Data Transfer In Progress */ -# define ATMCI_NOTBUSY ( 1 << 5) /* Data Not Busy */ -# define ATMCI_ENDRX ( 1 << 6) /* End of RX Buffer */ -# define ATMCI_ENDTX ( 1 << 7) /* End of TX Buffer */ -# define ATMCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ -# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ -# define ATMCI_SDIOWAIT ( 1 << 12) /* SDIO Read Wait Operation Status */ -# define ATMCI_CSRCV ( 1 << 13) /* CE-ATA Completion Signal Received */ -# define ATMCI_RXBUFF ( 1 << 14) /* RX Buffer Full */ -# define ATMCI_TXBUFE ( 1 << 15) /* TX Buffer Empty */ -# define ATMCI_RINDE ( 1 << 16) /* Response Index Error */ -# define ATMCI_RDIRE ( 1 << 17) /* Response Direction Error */ -# define ATMCI_RCRCE ( 1 << 18) /* Response CRC Error */ -# define ATMCI_RENDE ( 1 << 19) /* Response End Bit Error */ -# define ATMCI_RTOE ( 1 << 20) /* Response Time-Out Error */ -# define ATMCI_DCRCE ( 1 << 21) /* Data CRC Error */ -# define ATMCI_DTOE ( 1 << 22) /* Data Time-Out Error */ -# define ATMCI_CSTOE ( 1 << 23) /* Completion Signal Time-out Error */ -# define ATMCI_BLKOVRE ( 1 << 24) /* DMA Block Overrun Error */ -# define ATMCI_DMADONE ( 1 << 25) /* DMA Transfer Done */ -# define ATMCI_FIFOEMPTY ( 1 << 26) /* FIFO Empty Flag */ -# define ATMCI_XFRDONE ( 1 << 27) /* Transfer Done Flag */ -# define ATMCI_ACKRCV ( 1 << 28) /* Boot Operation Acknowledge Received */ -# define ATMCI_ACKRCVE ( 1 << 29) /* Boot Operation Acknowledge Error */ -# define ATMCI_OVRE ( 1 << 30) /* RX Overrun Error */ -# define ATMCI_UNRE ( 1 << 31) /* TX Underrun Error */ -#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */ -# define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ -# define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ -# define ATMCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */ -#define ATMCI_CFG 0x0054 /* Configuration[2] */ -# define ATMCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */ -# define ATMCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */ -# define ATMCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */ -# define ATMCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */ -#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */ -# define ATMCI_WP_EN ( 1 << 0) /* WP Enable */ -# define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */ -#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */ -# define ATMCI_GET_WP_VS(x) ((x) & 0x0f) -# define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) -#define ATMCI_VERSION 0x00FC /* Version */ -#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ +#define MCI_CR 0x0000 /* Control */ +# define MCI_CR_MCIEN ( 1 << 0) /* MCI Enable */ +# define MCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */ +# define MCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */ +# define MCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */ +# define MCI_CR_SWRST ( 1 << 7) /* Software Reset */ +#define MCI_MR 0x0004 /* Mode */ +# define MCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ +# define MCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ +# define MCI_MR_RDPROOF ( 1 << 11) /* Read Proof */ +# define MCI_MR_WRPROOF ( 1 << 12) /* Write Proof */ +# define MCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ +# define MCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ +# define MCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ +#define MCI_DTOR 0x0008 /* Data Timeout */ +# define MCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ +# define MCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ +#define MCI_SDCR 0x000c /* SD Card / SDIO */ +# define MCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */ +# define MCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */ +# define MCI_SDCSEL_MASK ( 3 << 0) +# define MCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */ +# define MCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */ +# define MCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */ +# define MCI_SDCBUS_MASK ( 3 << 6) +#define MCI_ARGR 0x0010 /* Command Argument */ +#define MCI_CMDR 0x0014 /* Command */ +# define MCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ +# define MCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */ +# define MCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */ +# define MCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */ +# define MCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */ +# define MCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */ +# define MCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */ +# define MCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */ +# define MCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */ +# define MCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */ +# define MCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */ +# define MCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */ +# define MCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */ +# define MCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */ +# define MCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */ +# define MCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */ +# define MCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */ +# define MCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */ +# define MCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */ +# define MCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */ +# define MCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */ +# define MCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */ +#define MCI_BLKR 0x0018 /* Block */ +# define MCI_BCNT(x) ((x) << 0) /* Data Block Count */ +# define MCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ +#define MCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ +# define MCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ +# define MCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ +#define MCI_RSPR 0x0020 /* Response 0 */ +#define MCI_RSPR1 0x0024 /* Response 1 */ +#define MCI_RSPR2 0x0028 /* Response 2 */ +#define MCI_RSPR3 0x002c /* Response 3 */ +#define MCI_RDR 0x0030 /* Receive Data */ +#define MCI_TDR 0x0034 /* Transmit Data */ +#define MCI_SR 0x0040 /* Status */ +#define MCI_IER 0x0044 /* Interrupt Enable */ +#define MCI_IDR 0x0048 /* Interrupt Disable */ +#define MCI_IMR 0x004c /* Interrupt Mask */ +# define MCI_CMDRDY ( 1 << 0) /* Command Ready */ +# define MCI_RXRDY ( 1 << 1) /* Receiver Ready */ +# define MCI_TXRDY ( 1 << 2) /* Transmitter Ready */ +# define MCI_BLKE ( 1 << 3) /* Data Block Ended */ +# define MCI_DTIP ( 1 << 4) /* Data Transfer In Progress */ +# define MCI_NOTBUSY ( 1 << 5) /* Data Not Busy */ +# define MCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ +# define MCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ +# define MCI_RINDE ( 1 << 16) /* Response Index Error */ +# define MCI_RDIRE ( 1 << 17) /* Response Direction Error */ +# define MCI_RCRCE ( 1 << 18) /* Response CRC Error */ +# define MCI_RENDE ( 1 << 19) /* Response End Bit Error */ +# define MCI_RTOE ( 1 << 20) /* Response Time-Out Error */ +# define MCI_DCRCE ( 1 << 21) /* Data CRC Error */ +# define MCI_DTOE ( 1 << 22) /* Data Time-Out Error */ +# define MCI_OVRE ( 1 << 30) /* RX Overrun Error */ +# define MCI_UNRE ( 1 << 31) /* TX Underrun Error */ +#define MCI_DMA 0x0050 /* DMA Configuration[2] */ +# define MCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ +# define MCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ +# define MCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */ +#define MCI_CFG 0x0054 /* Configuration[2] */ +# define MCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */ +# define MCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */ +# define MCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */ +# define MCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */ +#define MCI_WPMR 0x00e4 /* Write Protection Mode[2] */ +# define MCI_WP_EN ( 1 << 0) /* WP Enable */ +# define MCI_WP_KEY (0x4d4349 << 8) /* WP Key */ +#define MCI_WPSR 0x00e8 /* Write Protection Status[2] */ +# define MCI_GET_WP_VS(x) ((x) & 0x0f) +# define MCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) +#define MCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ /* This is not including the FIFO Aperture on MCI2 */ -#define ATMCI_REGS_SIZE 0x100 +#define MCI_REGS_SIZE 0x100 /* Register access macros */ -#define atmci_readl(port,reg) \ - __raw_readl((port)->regs + reg) -#define atmci_writel(port,reg,value) \ - __raw_writel((value), (port)->regs + reg) - -/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */ -#ifdef CONFIG_AVR32 -# define ATMCI_PDC_CONNECTED 0 -#else -# define ATMCI_PDC_CONNECTED 1 -#endif - -/* - * Fix sconfig's burst size according to atmel MCI. We need to convert them as: - * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. - * - * This can be done by finding most significant bit set. - */ -static inline unsigned int atmci_convert_chksize(unsigned int maxburst) -{ - if (maxburst > 1) - return fls(maxburst) - 2; - else - return 0; -} +#define mci_readl(port,reg) \ + __raw_readl((port)->regs + MCI_##reg) +#define mci_writel(port,reg,value) \ + __raw_writel((value), (port)->regs + MCI_##reg) #endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */ diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 722af1de796..fa8cae1d700 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -19,97 +19,64 @@ #include #include #include -#include -#include -#include #include #include #include #include #include -#include -#include #include #include #include #include -#include #include #include #include +#include #include "atmel-mci-regs.h" -#define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) +#define ATMCI_DATA_ERROR_FLAGS (MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE) #define ATMCI_DMA_THRESHOLD 16 enum { - EVENT_CMD_RDY = 0, + EVENT_CMD_COMPLETE = 0, EVENT_XFER_COMPLETE, - EVENT_NOTBUSY, + EVENT_DATA_COMPLETE, EVENT_DATA_ERROR, }; enum atmel_mci_state { STATE_IDLE = 0, STATE_SENDING_CMD, - STATE_DATA_XFER, - STATE_WAITING_NOTBUSY, + STATE_SENDING_DATA, + STATE_DATA_BUSY, STATE_SENDING_STOP, - STATE_END_REQUEST, -}; - -enum atmci_xfer_dir { - XFER_RECEIVE = 0, - XFER_TRANSMIT, -}; - -enum atmci_pdc_buf { - PDC_FIRST_BUF = 0, - PDC_SECOND_BUF, -}; - -struct atmel_mci_caps { - bool has_dma_conf_reg; - bool has_pdc; - bool has_cfg_reg; - bool has_cstor_reg; - 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; - bool need_notbusy_for_read_ops; + STATE_DATA_ERROR, }; struct atmel_mci_dma { +#ifdef CONFIG_MMC_ATMELMCI_DMA struct dma_chan *chan; struct dma_async_tx_descriptor *data_desc; +#endif }; /** * struct atmel_mci - MMC controller state shared between all slots * @lock: Spinlock protecting the queue and associated data. * @regs: Pointer to MMIO registers. - * @sg: Scatterlist entry currently being processed by PIO or PDC code. + * @sg: Scatterlist entry currently being processed by PIO code, if any. * @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. * @cmd: The command currently being sent to the card, or NULL. * @data: The data currently being transferred, or NULL if no data * transfer is in progress. - * @data_size: just data->blocks * data->blksz. * @dma: DMA client state. * @data_chan: DMA channel being used for the current data transfer. * @cmd_status: Snapshot of SR taken upon completion of the current @@ -128,7 +95,6 @@ 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 @@ -137,13 +103,6 @@ struct atmel_mci_dma { * @mck: The peripheral bus clock hooked up to the MMC controller. * @pdev: Platform device associated with the MMC controller. * @slot: Slots sharing this MMC controller. - * @caps: MCI capabilities depending on MCI version. - * @prepare_data: function to setup MCI before data transfer which - * depends on MCI capabilities. - * @submit_data: function to start data transfer which depends on MCI - * capabilities. - * @stop_transfer: function to stop data transfer which depends on MCI - * capabilities. * * Locking * ======= @@ -179,19 +138,14 @@ 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; struct mmc_command *cmd; struct mmc_data *data; - unsigned int data_size; struct atmel_mci_dma dma; struct dma_chan *data_chan; - struct dma_slave_config dma_conf; u32 cmd_status; u32 data_status; @@ -205,7 +159,6 @@ struct atmel_mci { bool need_clock_update; bool need_reset; - struct timer_list timer; u32 mode_reg; u32 cfg_reg; unsigned long bus_hz; @@ -213,13 +166,7 @@ struct atmel_mci { struct clk *mck; struct platform_device *pdev; - struct atmel_mci_slot *slot[ATMCI_MAX_NR_SLOTS]; - - struct atmel_mci_caps caps; - - u32 (*prepare_data)(struct atmel_mci *host, struct mmc_data *data); - void (*submit_data)(struct atmel_mci *host, struct mmc_data *data); - void (*stop_transfer)(struct atmel_mci *host); + struct atmel_mci_slot *slot[ATMEL_MCI_MAX_NR_SLOTS]; }; /** @@ -272,6 +219,31 @@ struct atmel_mci_slot { #define atmci_set_pending(host, event) \ set_bit(event, &host->pending_events) +/* + * Enable or disable features/registers based on + * whether the processor supports them + */ +static bool mci_has_rwproof(void) +{ + if (cpu_is_at91sam9261() || cpu_is_at91rm9200()) + return false; + else + return true; +} + +/* + * The new MCI2 module isn't 100% compatible with the old MCI module, + * and it has a few nice features which we want to use... + */ +static inline bool atmci_is_mci2(void) +{ + if (cpu_is_at91sam9g45()) + return true; + + return false; +} + + /* * The debugfs stuff below is mostly optimized away when * CONFIG_DEBUG_FS is not set. @@ -380,7 +352,7 @@ static int atmci_regs_show(struct seq_file *s, void *v) struct atmel_mci *host = s->private; u32 *buf; - buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL); + buf = kmalloc(MCI_REGS_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -391,56 +363,47 @@ static int atmci_regs_show(struct seq_file *s, void *v) */ spin_lock_bh(&host->lock); clk_enable(host->mck); - memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); + memcpy_fromio(buf, host->regs, MCI_REGS_SIZE); clk_disable(host->mck); spin_unlock_bh(&host->lock); - seq_printf(s, "MR:\t0x%08x%s%s ", - buf[ATMCI_MR / 4], - buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "", - buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : ""); - if (host->caps.has_odd_clk_div) - seq_printf(s, "{CLKDIV,CLKODD}=%u\n", - ((buf[ATMCI_MR / 4] & 0xff) << 1) - | ((buf[ATMCI_MR / 4] >> 16) & 1)); - else - seq_printf(s, "CLKDIV=%u\n", - (buf[ATMCI_MR / 4] & 0xff)); - seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]); - seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]); - seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]); + seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n", + buf[MCI_MR / 4], + buf[MCI_MR / 4] & MCI_MR_RDPROOF ? " RDPROOF" : "", + buf[MCI_MR / 4] & MCI_MR_WRPROOF ? " WRPROOF" : "", + buf[MCI_MR / 4] & 0xff); + seq_printf(s, "DTOR:\t0x%08x\n", buf[MCI_DTOR / 4]); + seq_printf(s, "SDCR:\t0x%08x\n", buf[MCI_SDCR / 4]); + seq_printf(s, "ARGR:\t0x%08x\n", buf[MCI_ARGR / 4]); seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n", - buf[ATMCI_BLKR / 4], - buf[ATMCI_BLKR / 4] & 0xffff, - (buf[ATMCI_BLKR / 4] >> 16) & 0xffff); - if (host->caps.has_cstor_reg) - seq_printf(s, "CSTOR:\t0x%08x\n", buf[ATMCI_CSTOR / 4]); + buf[MCI_BLKR / 4], + buf[MCI_BLKR / 4] & 0xffff, + (buf[MCI_BLKR / 4] >> 16) & 0xffff); + if (atmci_is_mci2()) + seq_printf(s, "CSTOR:\t0x%08x\n", buf[MCI_CSTOR / 4]); /* Don't read RSPR and RDR; it will consume the data there */ - atmci_show_status_reg(s, "SR", buf[ATMCI_SR / 4]); - atmci_show_status_reg(s, "IMR", buf[ATMCI_IMR / 4]); + atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]); + atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]); - if (host->caps.has_dma_conf_reg) { + if (atmci_is_mci2()) { u32 val; - val = buf[ATMCI_DMA / 4]; + val = buf[MCI_DMA / 4]; seq_printf(s, "DMA:\t0x%08x OFFSET=%u CHKSIZE=%u%s\n", val, val & 3, ((val >> 4) & 3) ? 1 << (((val >> 4) & 3) + 1) : 1, - val & ATMCI_DMAEN ? " DMAEN" : ""); - } - if (host->caps.has_cfg_reg) { - u32 val; + val & MCI_DMAEN ? " DMAEN" : ""); - val = buf[ATMCI_CFG / 4]; + val = buf[MCI_CFG / 4]; seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n", val, - val & ATMCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "", - val & ATMCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "", - val & ATMCI_CFG_HSMODE ? " HSMODE" : "", - val & ATMCI_CFG_LSYNC ? " LSYNC" : ""); + val & MCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "", + val & MCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "", + val & MCI_CFG_HSMODE ? " HSMODE" : "", + val & MCI_CFG_LSYNC ? " LSYNC" : ""); } kfree(buf); @@ -503,107 +466,10 @@ err: dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); } -#if defined(CONFIG_OF) -static const struct of_device_id atmci_dt_ids[] = { - { .compatible = "atmel,hsmci" }, - { /* sentinel */ } -}; - -MODULE_DEVICE_TABLE(of, atmci_dt_ids); - -static struct mci_platform_data* -atmci_of_init(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct device_node *cnp; - struct mci_platform_data *pdata; - u32 slot_id; - - if (!np) { - dev_err(&pdev->dev, "device node not found\n"); - return ERR_PTR(-EINVAL); - } - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&pdev->dev, "could not allocate memory for pdata\n"); - return ERR_PTR(-ENOMEM); - } - - for_each_child_of_node(np, cnp) { - if (of_property_read_u32(cnp, "reg", &slot_id)) { - dev_warn(&pdev->dev, "reg property is missing for %s\n", - cnp->full_name); - continue; - } - - if (slot_id >= ATMCI_MAX_NR_SLOTS) { - dev_warn(&pdev->dev, "can't have more than %d slots\n", - ATMCI_MAX_NR_SLOTS); - break; - } - - if (of_property_read_u32(cnp, "bus-width", - &pdata->slot[slot_id].bus_width)) - pdata->slot[slot_id].bus_width = 1; - - pdata->slot[slot_id].detect_pin = - of_get_named_gpio(cnp, "cd-gpios", 0); - - pdata->slot[slot_id].detect_is_active_high = - of_property_read_bool(cnp, "cd-inverted"); - - pdata->slot[slot_id].wp_pin = - of_get_named_gpio(cnp, "wp-gpios", 0); - } - - return pdata; -} -#else /* CONFIG_OF */ -static inline struct mci_platform_data* -atmci_of_init(struct platform_device *dev) -{ - return ERR_PTR(-EINVAL); -} -#endif - -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, +static inline unsigned int ns_to_clocks(struct atmel_mci *host, unsigned int ns) { - /* - * It is easier here to use us instead of ns for the timeout, - * it prevents from overflows during calculation. - */ - unsigned int us = DIV_ROUND_UP(ns, 1000); - - /* Maximum clock frequency is host->bus_hz/2 */ - return us * (DIV_ROUND_UP(host->bus_hz, 2000000)); + return (ns * (host->bus_hz / 1000000) + 999) / 1000; } static void atmci_set_timeout(struct atmel_mci *host, @@ -616,8 +482,7 @@ static void atmci_set_timeout(struct atmel_mci *host, unsigned dtocyc; unsigned dtomul; - timeout = atmci_ns_to_clocks(host, data->timeout_ns) - + data->timeout_clks; + timeout = ns_to_clocks(host, data->timeout_ns) + data->timeout_clks; for (dtomul = 0; dtomul < 8; dtomul++) { unsigned shift = dtomul_to_shift[dtomul]; @@ -633,7 +498,7 @@ static void atmci_set_timeout(struct atmel_mci *host, dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n", dtocyc << dtomul_to_shift[dtomul]); - atmci_writel(host, ATMCI_DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc))); + mci_writel(host, DTOR, (MCI_DTOMUL(dtomul) | MCI_DTOCYC(dtocyc))); } /* @@ -647,13 +512,13 @@ static u32 atmci_prepare_command(struct mmc_host *mmc, cmd->error = -EINPROGRESS; - cmdr = ATMCI_CMDR_CMDNB(cmd->opcode); + cmdr = MCI_CMDR_CMDNB(cmd->opcode); if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) - cmdr |= ATMCI_CMDR_RSPTYP_136BIT; + cmdr |= MCI_CMDR_RSPTYP_136BIT; else - cmdr |= ATMCI_CMDR_RSPTYP_48BIT; + cmdr |= MCI_CMDR_RSPTYP_48BIT; } /* @@ -661,34 +526,34 @@ static u32 atmci_prepare_command(struct mmc_host *mmc, * it's too difficult to determine whether this is an ACMD or * not. Better make it 64. */ - cmdr |= ATMCI_CMDR_MAXLAT_64CYC; + cmdr |= MCI_CMDR_MAXLAT_64CYC; if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN) - cmdr |= ATMCI_CMDR_OPDCMD; + cmdr |= MCI_CMDR_OPDCMD; data = cmd->data; if (data) { - cmdr |= ATMCI_CMDR_START_XFER; + cmdr |= MCI_CMDR_START_XFER; if (cmd->opcode == SD_IO_RW_EXTENDED) { - cmdr |= ATMCI_CMDR_SDIO_BLOCK; + cmdr |= MCI_CMDR_SDIO_BLOCK; } else { if (data->flags & MMC_DATA_STREAM) - cmdr |= ATMCI_CMDR_STREAM; + cmdr |= MCI_CMDR_STREAM; else if (data->blocks > 1) - cmdr |= ATMCI_CMDR_MULTI_BLOCK; + cmdr |= MCI_CMDR_MULTI_BLOCK; else - cmdr |= ATMCI_CMDR_BLOCK; + cmdr |= MCI_CMDR_BLOCK; } if (data->flags & MMC_DATA_READ) - cmdr |= ATMCI_CMDR_TRDIR_READ; + cmdr |= MCI_CMDR_TRDIR_READ; } return cmdr; } -static void atmci_send_command(struct atmel_mci *host, +static void atmci_start_command(struct atmel_mci *host, struct mmc_command *cmd, u32 cmd_flags) { WARN_ON(host->cmd); @@ -698,142 +563,43 @@ static void atmci_send_command(struct atmel_mci *host, "start command: ARGR=0x%08x CMDR=0x%08x\n", cmd->arg, cmd_flags); - atmci_writel(host, ATMCI_ARGR, cmd->arg); - atmci_writel(host, ATMCI_CMDR, cmd_flags); -} - -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); + mci_writel(host, ARGR, cmd->arg); + mci_writel(host, CMDR, cmd_flags); } -/* - * Configure given PDC buffer taking care of alignement issues. - * Update host->data_size and host->sg. - */ -static void atmci_pdc_set_single_buf(struct atmel_mci *host, - enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb) +static void send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) { - u32 pointer_reg, counter_reg; - unsigned int buf_size; - - if (dir == XFER_RECEIVE) { - pointer_reg = ATMEL_PDC_RPR; - counter_reg = ATMEL_PDC_RCR; - } else { - pointer_reg = ATMEL_PDC_TPR; - counter_reg = ATMEL_PDC_TCR; - } - - if (buf_nb == PDC_SECOND_BUF) { - pointer_reg += ATMEL_PDC_SCND_BUF_OFF; - counter_reg += ATMEL_PDC_SCND_BUF_OFF; - } - - 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); - atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCFBYTE); - } else { - /* Else transfer 32-bits words */ - atmci_writel(host, counter_reg, host->data_size / 4); - } - host->data_size = 0; - } else { - /* We assume the size of a page is 32-bits aligned */ - atmci_writel(host, counter_reg, sg_dma_len(host->sg) / 4); - host->data_size -= sg_dma_len(host->sg); - if (host->data_size) - host->sg = sg_next(host->sg); - } + atmci_start_command(host, data->stop, host->stop_cmdr); + mci_writel(host, IER, MCI_CMDRDY); } -/* - * Configure PDC buffer according to the data size ie configuring one or two - * buffers. Don't use this function if you want to configure only the second - * buffer. In this case, use atmci_pdc_set_single_buf. - */ -static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir) -{ - atmci_pdc_set_single_buf(host, dir, PDC_FIRST_BUF); - if (host->data_size) - atmci_pdc_set_single_buf(host, dir, PDC_SECOND_BUF); -} - -/* - * Unmap sg lists, called when transfer is finished. - */ -static void atmci_pdc_cleanup(struct atmel_mci *host) +#ifdef CONFIG_MMC_ATMELMCI_DMA +static void atmci_dma_cleanup(struct atmel_mci *host) { - struct mmc_data *data = host->data; + struct mmc_data *data = host->data; if (data) - dma_unmap_sg(&host->pdev->dev, - data->sg, data->sg_len, - ((data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); + dma_unmap_sg(host->dma.chan->device->dev, + data->sg, data->sg_len, + ((data->flags & MMC_DATA_WRITE) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); } -/* - * Disable PDC transfers. Update pending flags to EVENT_XFER_COMPLETE after - * having received ATMCI_TXBUFE or ATMCI_RXBUFF interrupt. Enable ATMCI_NOTBUSY - * interrupt needed for both transfer directions. - */ -static void atmci_pdc_complete(struct atmel_mci *host) +static void atmci_stop_dma(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); + struct dma_chan *chan = host->data_chan; - /* - * If the card was removed, data will be NULL. No point trying - * 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__); + if (chan) { + dmaengine_terminate_all(chan); + atmci_dma_cleanup(host); + } else { + /* Data transfer was stopped by the interrupt handler */ atmci_set_pending(host, EVENT_XFER_COMPLETE); - tasklet_schedule(&host->tasklet); + mci_writel(host, IER, MCI_NOTBUSY); } } -static void atmci_dma_cleanup(struct atmel_mci *host) -{ - struct mmc_data *data = host->data; - - if (data) - dma_unmap_sg(host->dma.chan->device->dev, - data->sg, data->sg_len, - ((data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); -} - -/* - * This function is called by the DMA driver from tasklet context. - */ +/* This function is called by the DMA driver from tasklet context. */ static void atmci_dma_complete(void *arg) { struct atmel_mci *host = arg; @@ -841,9 +607,9 @@ static void atmci_dma_complete(void *arg) dev_vdbg(&host->pdev->dev, "DMA complete\n"); - if (host->caps.has_dma_conf_reg) + if (atmci_is_mci2()) /* Disable DMA hardware handshaking on MCI */ - atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN); + mci_writel(host, DMA, mci_readl(host, DMA) & ~MCI_DMAEN); atmci_dma_cleanup(host); @@ -852,8 +618,6 @@ 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); @@ -877,104 +641,11 @@ static void atmci_dma_complete(void *arg) * completion callback" rule of the dma engine * framework. */ - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + mci_writel(host, IER, MCI_NOTBUSY); } } -/* - * Returns a mask of interrupt flags to be enabled after the whole - * request has been prepared. - */ -static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) -{ - u32 iflags; - - data->error = -EINPROGRESS; - - host->sg = data->sg; - host->data = data; - host->data_chan = NULL; - - iflags = ATMCI_DATA_ERROR_FLAGS; - - /* - * Errata: MMC data write operation with less than 12 - * bytes is impossible. - * - * Errata: MCI Transmit Data Register (TDR) FIFO - * corruption when length is not multiple of 4. - */ - if (data->blocks * data->blksz < 12 - || (data->blocks * data->blksz) & 3) - host->need_reset = true; - - host->pio_offset = 0; - if (data->flags & MMC_DATA_READ) - iflags |= ATMCI_RXRDY; - else - iflags |= ATMCI_TXRDY; - - return iflags; -} - -/* - * Set interrupt flags and set block length into the MCI mode register even - * if this value is also accessible in the MCI block register. It seems to be - * necessary before the High Speed MCI version. It also map sg and configure - * PDC registers. - */ -static u32 -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; - - host->data = data; - host->sg = data->sg; - iflags = ATMCI_DATA_ERROR_FLAGS; - - /* Enable pdc mode */ - atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE); - - if (data->flags & MMC_DATA_READ) { - dir = DMA_FROM_DEVICE; - iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; - } else { - dir = DMA_TO_DEVICE; - iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE; - } - - /* Set BLKLEN */ - tmp = atmci_readl(host, ATMCI_MR); - tmp &= 0x0000ffff; - tmp |= ATMCI_BLKLEN(data->blksz); - atmci_writel(host, ATMCI_MR, tmp); - - /* 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)); - - return iflags; -} - -static u32 +static int atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) { struct dma_chan *chan; @@ -982,18 +653,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) struct scatterlist *sg; unsigned int i; enum dma_data_direction direction; - enum dma_transfer_direction slave_dirn; unsigned int sglen; - u32 maxburst; - u32 iflags; - - data->error = -EINPROGRESS; - - WARN_ON(host->data); - host->sg = NULL; - host->data = data; - - iflags = ATMCI_DATA_ERROR_FLAGS; /* * We don't do DMA on "complex" transfers, i.e. with @@ -1001,13 +661,13 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) * with all the DMA setup overhead for short transfers. */ if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD) - return atmci_prepare_data(host, data); + return -EINVAL; if (data->blksz & 3) - return atmci_prepare_data(host, data); + return -EINVAL; for_each_sg(data->sg, sg, data->sg_len, i) { if (sg->offset & 3 || sg->length & 3) - return atmci_prepare_data(host, data); + return -EINVAL; } /* If we don't have a channel, we can't do DMA */ @@ -1018,26 +678,19 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) if (!chan) return -ENODEV; - if (data->flags & MMC_DATA_READ) { + if (atmci_is_mci2()) + mci_writel(host, DMA, MCI_DMA_CHKSIZE(3) | MCI_DMAEN); + + if (data->flags & MMC_DATA_READ) direction = DMA_FROM_DEVICE; - host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM; - maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst); - } else { + else direction = DMA_TO_DEVICE; - host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV; - maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst); - } - - if (host->caps.has_dma_conf_reg) - atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | - ATMCI_DMAEN); sglen = dma_map_sg(chan->device->dev, data->sg, - data->sg_len, direction); + data->sg_len, direction); - dmaengine_slave_config(chan, &host->dma_conf); - desc = dmaengine_prep_slave_sg(chan, - data->sg, sglen, slave_dirn, + desc = chan->device->device_prep_slave_sg(chan, + data->sg, sglen, direction, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) goto unmap_exit; @@ -1046,32 +699,13 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) desc->callback = atmci_dma_complete; desc->callback_param = host; - return iflags; + return 0; unmap_exit: dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction); return -ENOMEM; } -static void -atmci_submit_data(struct atmel_mci *host, struct mmc_data *data) -{ - return; -} - -/* - * Start PDC according to transfer direction. - */ -static void -atmci_submit_data_pdc(struct atmel_mci *host, struct mmc_data *data) -{ - if (data->flags & MMC_DATA_READ) - atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); - else - atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); -} - -static void -atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) +static void atmci_submit_data(struct atmel_mci *host) { struct dma_chan *chan = host->data_chan; struct dma_async_tx_descriptor *desc = host->dma.data_desc; @@ -1082,42 +716,64 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) } } -static void atmci_stop_transfer(struct atmel_mci *host) +#else /* CONFIG_MMC_ATMELMCI_DMA */ + +static int atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) +{ + return -ENOSYS; +} + +static void atmci_submit_data(struct atmel_mci *host) {} + +static void atmci_stop_dma(struct atmel_mci *host) { - dev_dbg(&host->pdev->dev, - "(%s) set pending xfer complete\n", __func__); + /* Data transfer was stopped by the interrupt handler */ atmci_set_pending(host, EVENT_XFER_COMPLETE); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + mci_writel(host, IER, MCI_NOTBUSY); } +#endif /* CONFIG_MMC_ATMELMCI_DMA */ + /* - * Stop data transfer because error(s) occurred. + * Returns a mask of interrupt flags to be enabled after the whole + * request has been prepared. */ -static void atmci_stop_transfer_pdc(struct atmel_mci *host) +static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) { - atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); -} + u32 iflags; -static void atmci_stop_transfer_dma(struct atmel_mci *host) -{ - struct dma_chan *chan = host->data_chan; + data->error = -EINPROGRESS; - if (chan) { - dmaengine_terminate_all(chan); - 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); + WARN_ON(host->data); + host->sg = NULL; + host->data = data; + + iflags = ATMCI_DATA_ERROR_FLAGS; + if (atmci_prepare_data_dma(host, data)) { + host->data_chan = NULL; + + /* + * Errata: MMC data write operation with less than 12 + * bytes is impossible. + * + * Errata: MCI Transmit Data Register (TDR) FIFO + * corruption when length is not multiple of 4. + */ + if (data->blocks * data->blksz < 12 + || (data->blocks * data->blksz) & 3) + host->need_reset = true; + + host->sg = data->sg; + host->pio_offset = 0; + if (data->flags & MMC_DATA_READ) + iflags |= MCI_RXRDY; + else + iflags |= MCI_TXRDY; } + + return iflags; } -/* - * Start a request: prepare data if needed, prepare the command and activate - * interrupts. - */ static void atmci_start_request(struct atmel_mci *host, struct atmel_mci_slot *slot) { @@ -1133,33 +789,27 @@ 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; - 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); - atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); - atmci_writel(host, ATMCI_MR, host->mode_reg); - if (host->caps.has_cfg_reg) - atmci_writel(host, ATMCI_CFG, host->cfg_reg); - atmci_writel(host, ATMCI_IER, iflags); + if (host->need_reset) { + mci_writel(host, CR, MCI_CR_SWRST); + mci_writel(host, CR, MCI_CR_MCIEN); + mci_writel(host, MR, host->mode_reg); + if (atmci_is_mci2()) + mci_writel(host, CFG, host->cfg_reg); host->need_reset = false; } - atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); + mci_writel(host, SDCR, slot->sdc_reg); - iflags = atmci_readl(host, ATMCI_IMR); - if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) - dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", + iflags = mci_readl(host, IMR); + if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB)) + dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", iflags); if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) { /* Send init sequence (74 clock cycles) */ - atmci_writel(host, ATMCI_CMDR, ATMCI_CMDR_SPCMD_INIT); - while (!(atmci_readl(host, ATMCI_SR) & ATMCI_CMDRDY)) + mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT); + while (!(mci_readl(host, SR) & MCI_CMDRDY)) cpu_relax(); } iflags = 0; @@ -1168,31 +818,31 @@ static void atmci_start_request(struct atmel_mci *host, atmci_set_timeout(host, slot, data); /* Must set block count/size before sending command */ - atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(data->blocks) - | ATMCI_BLKLEN(data->blksz)); + mci_writel(host, BLKR, MCI_BCNT(data->blocks) + | MCI_BLKLEN(data->blksz)); dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n", - ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz)); + MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz)); - iflags |= host->prepare_data(host, data); + iflags |= atmci_prepare_data(host, data); } - iflags |= ATMCI_CMDRDY; + iflags |= MCI_CMDRDY; cmd = mrq->cmd; cmdflags = atmci_prepare_command(slot->mmc, cmd); - atmci_send_command(host, cmd, cmdflags); + atmci_start_command(host, cmd, cmdflags); if (data) - host->submit_data(host, data); + atmci_submit_data(host); if (mrq->stop) { host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop); - host->stop_cmdr |= ATMCI_CMDR_STOP_XFER; + host->stop_cmdr |= MCI_CMDR_STOP_XFER; if (!(data->flags & MMC_DATA_WRITE)) - host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ; + host->stop_cmdr |= MCI_CMDR_TRDIR_READ; if (data->flags & MMC_DATA_STREAM) - host->stop_cmdr |= ATMCI_CMDR_STREAM; + host->stop_cmdr |= MCI_CMDR_STREAM; else - host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK; + host->stop_cmdr |= MCI_CMDR_MULTI_BLOCK; } /* @@ -1201,9 +851,7 @@ static void atmci_start_request(struct atmel_mci *host, * conditions (e.g. command and data complete, but stop not * prepared yet.) */ - atmci_writel(host, ATMCI_IER, iflags); - - mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); + mci_writel(host, IER, iflags); } static void atmci_queue_request(struct atmel_mci *host, @@ -1218,7 +866,6 @@ 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); @@ -1231,7 +878,6 @@ 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 @@ -1263,13 +909,13 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct atmel_mci *host = slot->host; unsigned int i; - slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; + slot->sdc_reg &= ~MCI_SDCBUS_MASK; switch (ios->bus_width) { case MMC_BUS_WIDTH_1: - slot->sdc_reg |= ATMCI_SDCBUS_1BIT; + slot->sdc_reg |= MCI_SDCBUS_1BIT; break; case MMC_BUS_WIDTH_4: - slot->sdc_reg |= ATMCI_SDCBUS_4BIT; + slot->sdc_reg |= MCI_SDCBUS_4BIT; break; } @@ -1280,10 +926,10 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_bh(&host->lock); if (!host->mode_reg) { clk_enable(host->mck); - atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); - atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); - if (host->caps.has_cfg_reg) - atmci_writel(host, ATMCI_CFG, host->cfg_reg); + mci_writel(host, CR, MCI_CR_SWRST); + mci_writel(host, CR, MCI_CR_MCIEN); + if (atmci_is_mci2()) + mci_writel(host, CFG, host->cfg_reg); } /* @@ -1291,54 +937,43 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) * core ios update when finding the minimum. */ slot->clock = ios->clock; - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { if (host->slot[i] && host->slot[i]->clock && host->slot[i]->clock < clock_min) clock_min = host->slot[i]->clock; } /* Calculate clock divider */ - if (host->caps.has_odd_clk_div) { - clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2; - if (clkdiv > 511) { - dev_warn(&mmc->class_dev, - "clock %u too slow; using %lu\n", - clock_min, host->bus_hz / (511 + 2)); - clkdiv = 511; - } - host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1) - | ATMCI_MR_CLKODD(clkdiv & 1); - } else { - clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; - if (clkdiv > 255) { - dev_warn(&mmc->class_dev, - "clock %u too slow; using %lu\n", - clock_min, host->bus_hz / (2 * 256)); - clkdiv = 255; - } - host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); + clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; + if (clkdiv > 255) { + dev_warn(&mmc->class_dev, + "clock %u too slow; using %lu\n", + clock_min, host->bus_hz / (2 * 256)); + clkdiv = 255; } + host->mode_reg = MCI_MR_CLKDIV(clkdiv); + /* * WRPROOF and RDPROOF prevent overruns/underruns by * stopping the clock when the FIFO is full/empty. * This state is not expected to last for long. */ - if (host->caps.has_rwproof) - host->mode_reg |= (ATMCI_MR_WRPROOF | ATMCI_MR_RDPROOF); + if (mci_has_rwproof()) + host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF); - if (host->caps.has_cfg_reg) { + if (atmci_is_mci2()) { /* setup High Speed mode in relation with card capacity */ if (ios->timing == MMC_TIMING_SD_HS) - host->cfg_reg |= ATMCI_CFG_HSMODE; + host->cfg_reg |= MCI_CFG_HSMODE; else - host->cfg_reg &= ~ATMCI_CFG_HSMODE; + host->cfg_reg &= ~MCI_CFG_HSMODE; } if (list_empty(&host->queue)) { - atmci_writel(host, ATMCI_MR, host->mode_reg); - if (host->caps.has_cfg_reg) - atmci_writel(host, ATMCI_CFG, host->cfg_reg); + mci_writel(host, MR, host->mode_reg); + if (atmci_is_mci2()) + mci_writel(host, CFG, host->cfg_reg); } else { host->need_clock_update = true; } @@ -1349,16 +984,16 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_bh(&host->lock); slot->clock = 0; - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { if (host->slot[i] && host->slot[i]->clock) { any_slot_active = true; break; } } if (!any_slot_active) { - atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); + mci_writel(host, CR, MCI_CR_MCIDIS); if (host->mode_reg) { - atmci_readl(host, ATMCI_MR); + mci_readl(host, MR); clk_disable(host->mck); } host->mode_reg = 0; @@ -1422,9 +1057,9 @@ static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable) struct atmel_mci *host = slot->host; if (enable) - atmci_writel(host, ATMCI_IER, slot->sdio_irq); + mci_writel(host, IER, slot->sdio_irq); else - atmci_writel(host, ATMCI_IDR, slot->sdio_irq); + mci_writel(host, IDR, slot->sdio_irq); } static const struct mmc_host_ops atmci_ops = { @@ -1451,9 +1086,9 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) * busy transferring data. */ if (host->need_clock_update) { - atmci_writel(host, ATMCI_MR, host->mode_reg); - if (host->caps.has_cfg_reg) - atmci_writel(host, ATMCI_CFG, host->cfg_reg); + mci_writel(host, MR, host->mode_reg); + if (atmci_is_mci2()) + mci_writel(host, CFG, host->cfg_reg); } host->cur_slot->mrq = NULL; @@ -1471,8 +1106,6 @@ 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); @@ -1484,24 +1117,32 @@ static void atmci_command_complete(struct atmel_mci *host, u32 status = host->cmd_status; /* Read the response from the card (up to 16 bytes) */ - cmd->resp[0] = atmci_readl(host, ATMCI_RSPR); - cmd->resp[1] = atmci_readl(host, ATMCI_RSPR); - cmd->resp[2] = atmci_readl(host, ATMCI_RSPR); - cmd->resp[3] = atmci_readl(host, ATMCI_RSPR); + cmd->resp[0] = mci_readl(host, RSPR); + cmd->resp[1] = mci_readl(host, RSPR); + cmd->resp[2] = mci_readl(host, RSPR); + cmd->resp[3] = mci_readl(host, RSPR); - if (status & ATMCI_RTOE) + if (status & MCI_RTOE) cmd->error = -ETIMEDOUT; - else if ((cmd->flags & MMC_RSP_CRC) && (status & ATMCI_RCRCE)) + else if ((cmd->flags & MMC_RSP_CRC) && (status & MCI_RCRCE)) cmd->error = -EILSEQ; - else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE)) + else if (status & (MCI_RINDE | MCI_RDIRE | MCI_RENDE)) cmd->error = -EIO; - 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 + else cmd->error = 0; + + if (cmd->error) { + dev_dbg(&host->pdev->dev, + "command error: status=0x%08x\n", status); + + if (cmd->data) { + atmci_stop_dma(host); + host->data = NULL; + mci_writel(host, IDR, MCI_NOTBUSY + | MCI_TXRDY | MCI_RXRDY + | ATMCI_DATA_ERROR_FLAGS); + } + } } static void atmci_detect_change(unsigned long data) @@ -1550,11 +1191,11 @@ static void atmci_detect_change(unsigned long data) * Reset controller to terminate any ongoing * commands or data transfers. */ - atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); - atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); - atmci_writel(host, ATMCI_MR, host->mode_reg); - if (host->caps.has_cfg_reg) - atmci_writel(host, ATMCI_CFG, host->cfg_reg); + mci_writel(host, CR, MCI_CR_SWRST); + mci_writel(host, CR, MCI_CR_MCIEN); + mci_writel(host, MR, host->mode_reg); + if (atmci_is_mci2()) + mci_writel(host, CFG, host->cfg_reg); host->data = NULL; host->cmd = NULL; @@ -1564,21 +1205,23 @@ static void atmci_detect_change(unsigned long data) break; case STATE_SENDING_CMD: mrq->cmd->error = -ENOMEDIUM; - if (mrq->data) - host->stop_transfer(host); - break; - case STATE_DATA_XFER: - mrq->data->error = -ENOMEDIUM; - host->stop_transfer(host); - break; - case STATE_WAITING_NOTBUSY: + if (!mrq->data) + break; + /* fall through */ + case STATE_SENDING_DATA: mrq->data->error = -ENOMEDIUM; + atmci_stop_dma(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_SENDING_STOP: mrq->stop->error = -ENOMEDIUM; break; - case STATE_END_REQUEST: - break; } atmci_request_end(host, mrq); @@ -1606,6 +1249,7 @@ 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; @@ -1617,191 +1261,111 @@ static void atmci_tasklet_func(unsigned long priv) dev_vdbg(&host->pdev->dev, "tasklet: state %u pending/completed/mask %lx/%lx/%x\n", state, host->pending_events, host->completed_events, - atmci_readl(host, ATMCI_IMR)); + mci_readl(host, IMR)); 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_RDY)) + EVENT_CMD_COMPLETE)) break; - dev_dbg(&host->pdev->dev, "set completed cmd ready\n"); host->cmd = NULL; - atmci_set_completed(host, EVENT_CMD_RDY); + atmci_set_completed(host, EVENT_CMD_COMPLETE); atmci_command_complete(host, mrq->cmd); - 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; + if (!mrq->data || cmd->error) { + atmci_request_end(host, host->mrq); + goto unlock; + } - break; + prev_state = state = STATE_SENDING_DATA; + /* fall through */ - case STATE_DATA_XFER: + case STATE_SENDING_DATA: if (atmci_test_and_clear_pending(host, EVENT_DATA_ERROR)) { - dev_dbg(&host->pdev->dev, "set completed data error\n"); - atmci_set_completed(host, EVENT_DATA_ERROR); - state = STATE_END_REQUEST; + atmci_stop_dma(host); + if (data->stop) + send_stop_cmd(host, data); + state = STATE_DATA_ERROR; 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 */ - if (host->caps.need_notbusy_for_read_ops || - (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; + 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 & MCI_DTOE) { + dev_dbg(&host->pdev->dev, + "data timeout error\n"); + data->error = -ETIMEDOUT; + } else if (status & MCI_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; + } } else { - host->data = NULL; data->bytes_xfered = data->blocks * data->blksz; data->error = 0; - state = STATE_END_REQUEST; + mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS); } - break; - 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; + if (!data->stop) { + atmci_request_end(host, host->mrq); + goto unlock; + } - 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; + prev_state = state = STATE_SENDING_STOP; + if (!data->error) + send_stop_cmd(host, data); + /* fall through */ 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_RDY)) + EVENT_CMD_COMPLETE)) break; - dev_dbg(&host->pdev->dev, "FSM: cmd ready\n"); host->cmd = NULL; - data->bytes_xfered = data->blocks * data->blksz; - data->error = 0; atmci_command_complete(host, mrq->stop); - 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; - } - host->data = NULL; - break; + atmci_request_end(host, host->mrq); + goto unlock; - 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; - } - } + case STATE_DATA_ERROR: + if (!atmci_test_and_clear_pending(host, + EVENT_XFER_COMPLETE)) + break; - atmci_request_end(host, host->mrq); - state = STATE_IDLE; + state = STATE_DATA_BUSY; break; } } while (state != prev_state); host->state = state; +unlock: spin_unlock(&host->lock); } @@ -1816,7 +1380,7 @@ static void atmci_read_data_pio(struct atmel_mci *host) unsigned int nbytes = 0; do { - value = atmci_readl(host, ATMCI_RDR); + value = mci_readl(host, RDR); if (likely(offset + 4 <= sg->length)) { put_unaligned(value, (u32 *)(buf + offset)); @@ -1848,15 +1412,18 @@ static void atmci_read_data_pio(struct atmel_mci *host) nbytes += offset; } - status = atmci_readl(host, ATMCI_SR); + status = mci_readl(host, SR); if (status & ATMCI_DATA_ERROR_FLAGS) { - atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY + mci_writel(host, IDR, (MCI_NOTBUSY | MCI_RXRDY | 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); + } while (status & MCI_RXRDY); host->pio_offset = offset; data->bytes_xfered += nbytes; @@ -1864,8 +1431,8 @@ static void atmci_read_data_pio(struct atmel_mci *host) return; done: - atmci_writel(host, ATMCI_IDR, ATMCI_RXRDY); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + mci_writel(host, IDR, MCI_RXRDY); + mci_writel(host, IER, MCI_NOTBUSY); data->bytes_xfered += nbytes; smp_wmb(); atmci_set_pending(host, EVENT_XFER_COMPLETE); @@ -1884,7 +1451,7 @@ static void atmci_write_data_pio(struct atmel_mci *host) do { if (likely(offset + 4 <= sg->length)) { value = get_unaligned((u32 *)(buf + offset)); - atmci_writel(host, ATMCI_TDR, value); + mci_writel(host, TDR, value); offset += 4; nbytes += 4; @@ -1905,26 +1472,29 @@ static void atmci_write_data_pio(struct atmel_mci *host) host->sg = sg = sg_next(sg); if (!sg) { - atmci_writel(host, ATMCI_TDR, value); + mci_writel(host, TDR, value); goto done; } offset = 4 - remaining; buf = sg_virt(sg); memcpy((u8 *)&value + remaining, buf, offset); - atmci_writel(host, ATMCI_TDR, value); + mci_writel(host, TDR, value); nbytes += offset; } - status = atmci_readl(host, ATMCI_SR); + status = mci_readl(host, SR); if (status & ATMCI_DATA_ERROR_FLAGS) { - atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY + mci_writel(host, IDR, (MCI_NOTBUSY | MCI_TXRDY | 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); + } while (status & MCI_TXRDY); host->pio_offset = offset; data->bytes_xfered += nbytes; @@ -1932,18 +1502,28 @@ static void atmci_write_data_pio(struct atmel_mci *host) return; done: - atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + mci_writel(host, IDR, MCI_TXRDY); + mci_writel(host, IER, MCI_NOTBUSY); data->bytes_xfered += nbytes; smp_wmb(); atmci_set_pending(host, EVENT_XFER_COMPLETE); } +static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) +{ + mci_writel(host, IDR, MCI_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; - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { struct atmel_mci_slot *slot = host->slot[i]; if (slot && (status & slot->sdio_irq)) { mmc_signal_sdio_irq(slot->mmc); @@ -1959,120 +1539,40 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) unsigned int pass_count = 0; do { - status = atmci_readl(host, ATMCI_SR); - mask = atmci_readl(host, ATMCI_IMR); + status = mci_readl(host, SR); + mask = mci_readl(host, IMR); pending = status & mask; if (!pending) 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 - | ATMCI_ENDRX | ATMCI_ENDTX - | ATMCI_RXBUFF | ATMCI_TXBUFE); + mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS + | MCI_RXRDY | MCI_TXRDY); + pending &= mci_readl(host, IMR); 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); - /* - * We can receive this interruption before having configured - * the second pdc buffer, so we need to reconfigure first and - * second buffers again - */ - if (host->data_size) { - atmci_pdc_set_both_buf(host, XFER_TRANSMIT); - atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); - atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE); - } else { - 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) { - atmci_pdc_set_single_buf(host, - XFER_TRANSMIT, PDC_SECOND_BUF); - atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); - } - } - - 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); - /* - * We can receive this interruption before having configured - * the second pdc buffer, so we need to reconfigure first and - * second buffers again - */ - if (host->data_size) { - atmci_pdc_set_both_buf(host, XFER_RECEIVE); - atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); - atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF); - } else { - 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) { - atmci_pdc_set_single_buf(host, - XFER_RECEIVE, PDC_SECOND_BUF); - atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); - } - } - - /* - * 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); + if (pending & MCI_NOTBUSY) { + mci_writel(host, IDR, + ATMCI_DATA_ERROR_FLAGS | MCI_NOTBUSY); + if (!host->data_status) + host->data_status = status; smp_wmb(); - dev_dbg(&host->pdev->dev, "set pending notbusy\n"); - atmci_set_pending(host, EVENT_NOTBUSY); + atmci_set_pending(host, EVENT_DATA_COMPLETE); tasklet_schedule(&host->tasklet); } - - if (pending & ATMCI_NOTBUSY) { - dev_dbg(&host->pdev->dev, "IRQ: not_busy\n"); - atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY); - smp_wmb(); - dev_dbg(&host->pdev->dev, "set pending notbusy\n"); - atmci_set_pending(host, EVENT_NOTBUSY); - tasklet_schedule(&host->tasklet); - } - - if (pending & ATMCI_RXRDY) + if (pending & MCI_RXRDY) atmci_read_data_pio(host); - if (pending & ATMCI_TXRDY) + if (pending & MCI_TXRDY) atmci_write_data_pio(host); - 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 & MCI_CMDRDY) + atmci_cmd_interrupt(host, status); - if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) + if (pending & (MCI_SDIOIRQA | MCI_SDIOIRQB)) atmci_sdio_interrupt(host, status); } while (pass_count++ < 5); @@ -2115,41 +1615,21 @@ static int __init atmci_init_slot(struct atmel_mci *host, slot->sdc_reg = sdc_reg; slot->sdio_irq = sdio_irq; - dev_dbg(&mmc->class_dev, - "slot[%u]: bus_width=%u, detect_pin=%d, " - "detect_is_active_high=%s, wp_pin=%d\n", - id, slot_data->bus_width, slot_data->detect_pin, - slot_data->detect_is_active_high ? "true" : "false", - slot_data->wp_pin); - mmc->ops = &atmci_ops; mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); mmc->f_max = host->bus_hz / 2; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; if (sdio_irq) mmc->caps |= MMC_CAP_SDIO_IRQ; - if (host->caps.has_highspeed) + if (atmci_is_mci2()) mmc->caps |= MMC_CAP_SD_HIGHSPEED; - /* - * 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) + if (slot_data->bus_width >= 4) mmc->caps |= MMC_CAP_4_BIT_DATA; - 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; - } + 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); @@ -2224,7 +1704,8 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot, mmc_free_host(slot->mmc); } -static bool atmci_filter(struct dma_chan *chan, void *slave) +#ifdef CONFIG_MMC_ATMELMCI_DMA +static bool filter(struct dma_chan *chan, void *slave) { struct mci_dma_data *sl = slave; @@ -2236,98 +1717,38 @@ static bool atmci_filter(struct dma_chan *chan, void *slave) } } -static bool atmci_configure_dma(struct atmel_mci *host) +static void atmci_configure_dma(struct atmel_mci *host) { struct mci_platform_data *pdata; if (host == NULL) - return false; + return; pdata = host->pdev->dev.platform_data; - if (!pdata) - return false; - - if (pdata->dma_slave && find_slave_dev(pdata->dma_slave)) { + if (pdata && find_slave_dev(pdata->dma_slave)) { dma_cap_mask_t mask; + setup_dma_addr(pdata->dma_slave, + host->mapbase + MCI_TDR, + host->mapbase + MCI_RDR); + /* Try to grab a DMA channel */ dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); host->dma.chan = - dma_request_channel(mask, atmci_filter, pdata->dma_slave); + dma_request_channel(mask, filter, pdata->dma_slave); } - if (!host->dma.chan) { - dev_warn(&host->pdev->dev, "no DMA channel available\n"); - return false; - } else { + if (!host->dma.chan) + dev_notice(&host->pdev->dev, "DMA not available, using PIO\n"); + else dev_info(&host->pdev->dev, - "using %s for DMA transfers\n", + "Using %s for DMA transfers\n", dma_chan_name(host->dma.chan)); - - host->dma_conf.src_addr = host->mapbase + ATMCI_RDR; - host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_conf.src_maxburst = 1; - host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR; - host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_conf.dst_maxburst = 1; - host->dma_conf.device_fc = false; - return true; - } -} - -/* - * 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 - * PDC. - */ -static void __init atmci_get_cap(struct atmel_mci *host) -{ - unsigned int version; - - version = atmci_get_version(host); - dev_info(&host->pdev->dev, - "version: 0x%x\n", version); - - host->caps.has_dma_conf_reg = 0; - host->caps.has_pdc = ATMCI_PDC_CONNECTED; - host->caps.has_cfg_reg = 0; - host->caps.has_cstor_reg = 0; - 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; - host->caps.need_notbusy_for_read_ops = 0; - - /* keep only major version number */ - switch (version & 0xf00) { - case 0x500: - host->caps.has_odd_clk_div = 1; - case 0x400: - case 0x300: - host->caps.has_dma_conf_reg = 1; - host->caps.has_pdc = 0; - host->caps.has_cfg_reg = 1; - host->caps.has_cstor_reg = 1; - host->caps.has_highspeed = 1; - case 0x200: - host->caps.has_rwproof = 1; - host->caps.need_blksz_mul_4 = 0; - host->caps.need_notbusy_for_read_ops = 1; - 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; - dev_warn(&host->pdev->dev, - "Unmanaged mci version, set minimum capabilities\n"); - break; - } } +#else +static void atmci_configure_dma(struct atmel_mci *host) {} +#endif static int __init atmci_probe(struct platform_device *pdev) { @@ -2342,14 +1763,8 @@ static int __init atmci_probe(struct platform_device *pdev) if (!regs) return -ENXIO; pdata = pdev->dev.platform_data; - if (!pdata) { - pdata = atmci_of_init(pdev); - if (IS_ERR(pdata)) { - dev_err(&pdev->dev, "platform data not available\n"); - return PTR_ERR(pdata); - } - } - + if (!pdata) + return -ENXIO; irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -2374,7 +1789,7 @@ static int __init atmci_probe(struct platform_device *pdev) goto err_ioremap; clk_enable(host->mck); - atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); + mci_writel(host, CR, MCI_CR_SWRST); host->bus_hz = clk_get_rate(host->mck); clk_disable(host->mck); @@ -2386,48 +1801,24 @@ static int __init atmci_probe(struct platform_device *pdev) if (ret) goto err_request_irq; - /* Get MCI capabilities and set operations according to it */ - atmci_get_cap(host); - if (atmci_configure_dma(host)) { - host->prepare_data = &atmci_prepare_data_dma; - host->submit_data = &atmci_submit_data_dma; - host->stop_transfer = &atmci_stop_transfer_dma; - } else if (host->caps.has_pdc) { - dev_info(&pdev->dev, "using PDC\n"); - host->prepare_data = &atmci_prepare_data_pdc; - host->submit_data = &atmci_submit_data_pdc; - host->stop_transfer = &atmci_stop_transfer_pdc; - } else { - dev_info(&pdev->dev, "using PIO\n"); - host->prepare_data = &atmci_prepare_data; - host->submit_data = &atmci_submit_data; - host->stop_transfer = &atmci_stop_transfer; - } + atmci_configure_dma(host); platform_set_drvdata(pdev, host); - setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host); - /* We need at least one slot to succeed */ nr_slots = 0; ret = -ENODEV; if (pdata->slot[0].bus_width) { ret = atmci_init_slot(host, &pdata->slot[0], - 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); - if (!ret) { + 0, MCI_SDCSEL_SLOT_A, MCI_SDIOIRQA); + 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) { + 1, MCI_SDCSEL_SLOT_B, MCI_SDIOIRQB); + 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) { @@ -2435,17 +1826,6 @@ 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; - } - } - dev_info(&pdev->dev, "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", host->mapbase, irq, nr_slots); @@ -2453,8 +1833,10 @@ static int __init atmci_probe(struct platform_device *pdev) return 0; err_init_slot: +#ifdef CONFIG_MMC_ATMELMCI_DMA if (host->dma.chan) dma_release_channel(host->dma.chan); +#endif free_irq(irq, host); err_request_irq: iounmap(host->regs); @@ -2472,19 +1854,15 @@ 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++) { + for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { if (host->slot[i]) atmci_cleanup_slot(host->slot[i], i); } clk_enable(host->mck); - atmci_writel(host, ATMCI_IDR, ~0UL); - atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); - atmci_readl(host, ATMCI_SR); + mci_writel(host, IDR, ~0UL); + mci_writel(host, CR, MCI_CR_MCIDIS); + mci_readl(host, SR); clk_disable(host->mck); #ifdef CONFIG_MMC_ATMELMCI_DMA @@ -2507,7 +1885,7 @@ static int atmci_suspend(struct device *dev) struct atmel_mci *host = dev_get_drvdata(dev); int i; - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { struct atmel_mci_slot *slot = host->slot[i]; int ret; @@ -2538,7 +1916,7 @@ static int atmci_resume(struct device *dev) int i; int ret = 0; - for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { struct atmel_mci_slot *slot = host->slot[i]; int err; @@ -2567,7 +1945,6 @@ static struct platform_driver atmci_driver = { .driver = { .name = "atmel_mci", .pm = ATMCI_PM_OPS, - .of_match_table = of_match_ptr(atmci_dt_ids), }, }; diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 127a8fade4d..ef72e874ca3 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -55,7 +55,7 @@ #ifdef DEBUG #define DBG(fmt, idx, args...) \ - pr_debug("au1xmmc(%d): DEBUG: " fmt, idx, ##args) + printk(KERN_DEBUG "au1xmmc(%d): DEBUG: " fmt, idx, ##args) #else #define DBG(fmt, idx, args...) do {} while (0) #endif @@ -64,8 +64,11 @@ #define AU1XMMC_DESCRIPTOR_COUNT 1 /* max DMA seg size: 64KB on Au1100, 4MB on Au1200 */ -#define AU1100_MMC_DESCRIPTOR_SIZE 0x0000ffff -#define AU1200_MMC_DESCRIPTOR_SIZE 0x003fffff +#ifdef CONFIG_SOC_AU1100 +#define AU1XMMC_DESCRIPTOR_SIZE 0x0000ffff +#else /* Au1200 */ +#define AU1XMMC_DESCRIPTOR_SIZE 0x003fffff +#endif #define AU1XMMC_OCR (MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \ MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \ @@ -124,7 +127,6 @@ struct au1xmmc_host { #define HOST_F_XMIT 0x0001 #define HOST_F_RECV 0x0002 #define HOST_F_DMA 0x0010 -#define HOST_F_DBDMA 0x0020 #define HOST_F_ACTIVE 0x0100 #define HOST_F_STOP 0x1000 @@ -149,17 +151,6 @@ struct au1xmmc_host { #define DMA_CHANNEL(h) \ (((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan) -static inline int has_dbdma(void) -{ - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1200: - case ALCHEMY_CPU_AU1300: - return 1; - default: - return 0; - } -} - static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask) { u32 val = au_readl(HOST_CONFIG(host)); @@ -277,7 +268,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, mmccmd |= SD_CMD_RT_3; break; default: - pr_info("au1xmmc: unhandled response type %02x\n", + printk(KERN_INFO "au1xmmc: unhandled response type %02x\n", mmc_resp_type(cmd)); return -EINVAL; } @@ -362,12 +353,14 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) data->bytes_xfered = 0; if (!data->error) { - if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) { + if (host->flags & HOST_F_DMA) { +#ifdef CONFIG_SOC_AU1200 /* DBDMA */ u32 chan = DMA_CHANNEL(host); chan_tab_t *c = *((chan_tab_t **)chan); au1x_dma_chan_t *cp = c->chan_ptr; data->bytes_xfered = cp->ddma_bytecnt; +#endif } else data->bytes_xfered = (data->blocks * data->blksz) - host->pio.len; @@ -577,10 +570,11 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) host->status = HOST_S_DATA; - if ((host->flags & (HOST_F_DMA | HOST_F_DBDMA))) { + if (host->flags & HOST_F_DMA) { +#ifdef CONFIG_SOC_AU1200 /* DBDMA */ u32 channel = DMA_CHANNEL(host); - /* Start the DBDMA as soon as the buffer gets something in it */ + /* Start the DMA as soon as the buffer gets something in it */ if (host->flags & HOST_F_RECV) { u32 mask = SD_STATUS_DB | SD_STATUS_NE; @@ -590,6 +584,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) } au1xxx_dbdma_start(channel); +#endif } } @@ -638,7 +633,8 @@ static int au1xmmc_prepare_data(struct au1xmmc_host *host, au_writel(data->blksz - 1, HOST_BLKSIZE(host)); - if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) { + if (host->flags & HOST_F_DMA) { +#ifdef CONFIG_SOC_AU1200 /* DBDMA */ int i; u32 channel = DMA_CHANNEL(host); @@ -667,6 +663,7 @@ static int au1xmmc_prepare_data(struct au1xmmc_host *host, datalen -= len; } +#endif } else { host->pio.index = 0; host->pio.offset = 0; @@ -769,15 +766,11 @@ static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) config2 = au_readl(HOST_CONFIG2(host)); switch (ios->bus_width) { - case MMC_BUS_WIDTH_8: - config2 |= SD_CONFIG2_BB; - break; case MMC_BUS_WIDTH_4: - config2 &= ~SD_CONFIG2_BB; config2 |= SD_CONFIG2_WB; break; case MMC_BUS_WIDTH_1: - config2 &= ~(SD_CONFIG2_WB | SD_CONFIG2_BB); + config2 &= ~SD_CONFIG2_WB; break; } au_writel(config2, HOST_CONFIG2(host)); @@ -845,6 +838,7 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_SOC_AU1200 /* 8bit memory DMA device */ static dbdev_tab_t au1xmmc_mem_dbdev = { .dev_id = DSCR_CMD0_ALWAYS, @@ -911,7 +905,7 @@ static int au1xmmc_dbdma_init(struct au1xmmc_host *host) au1xxx_dbdma_ring_alloc(host->rx_chan, AU1XMMC_DESCRIPTOR_COUNT); /* DBDMA is good to go */ - host->flags |= HOST_F_DMA | HOST_F_DBDMA; + host->flags |= HOST_F_DMA; return 0; } @@ -924,6 +918,7 @@ static void au1xmmc_dbdma_shutdown(struct au1xmmc_host *host) au1xxx_dbdma_chan_free(host->rx_chan); } } +#endif static void au1xmmc_enable_sdio_irq(struct mmc_host *mmc, int en) { @@ -943,12 +938,12 @@ static const struct mmc_host_ops au1xmmc_ops = { .enable_sdio_irq = au1xmmc_enable_sdio_irq, }; -static int au1xmmc_probe(struct platform_device *pdev) +static int __devinit au1xmmc_probe(struct platform_device *pdev) { struct mmc_host *mmc; struct au1xmmc_host *host; struct resource *r; - int ret, iflag; + int ret; mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev); if (!mmc) { @@ -987,43 +982,29 @@ static int au1xmmc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no IRQ defined\n"); goto out3; } + host->irq = r->start; + /* IRQ is shared among both SD controllers */ + ret = request_irq(host->irq, au1xmmc_irq, IRQF_SHARED, + DRIVER_NAME, host); + if (ret) { + dev_err(&pdev->dev, "cannot grab IRQ\n"); + goto out3; + } mmc->ops = &au1xmmc_ops; mmc->f_min = 450000; mmc->f_max = 24000000; + mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE; + mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; + mmc->max_blk_size = 2048; mmc->max_blk_count = 512; mmc->ocr_avail = AU1XMMC_OCR; mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; - mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; - - iflag = IRQF_SHARED; /* Au1100/Au1200: one int for both ctrls */ - - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1100: - mmc->max_seg_size = AU1100_MMC_DESCRIPTOR_SIZE; - break; - case ALCHEMY_CPU_AU1200: - mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE; - break; - case ALCHEMY_CPU_AU1300: - iflag = 0; /* nothing is shared */ - mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE; - mmc->f_max = 52000000; - if (host->ioarea->start == AU1100_SD0_PHYS_ADDR) - mmc->caps |= MMC_CAP_8_BIT_DATA; - break; - } - - ret = request_irq(host->irq, au1xmmc_irq, iflag, DRIVER_NAME, host); - if (ret) { - dev_err(&pdev->dev, "cannot grab IRQ\n"); - goto out3; - } host->status = HOST_S_IDLE; @@ -1047,11 +1028,11 @@ static int au1xmmc_probe(struct platform_device *pdev) tasklet_init(&host->finish_task, au1xmmc_tasklet_finish, (unsigned long)host); - if (has_dbdma()) { - ret = au1xmmc_dbdma_init(host); - if (ret) - pr_info(DRIVER_NAME ": DBDMA init failed; using PIO\n"); - } +#ifdef CONFIG_SOC_AU1200 + ret = au1xmmc_dbdma_init(host); + if (ret) + printk(KERN_INFO DRIVER_NAME ": DBDMA init failed; using PIO\n"); +#endif #ifdef CONFIG_LEDS_CLASS if (host->platdata && host->platdata->led) { @@ -1075,7 +1056,7 @@ static int au1xmmc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); - pr_info(DRIVER_NAME ": MMC Controller %d set up at %8.8X" + printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X" " (mode=%s)\n", pdev->id, host->iobase, host->flags & HOST_F_DMA ? "dma" : "pio"); @@ -1092,8 +1073,9 @@ out5: au_writel(0, HOST_CONFIG2(host)); au_sync(); - if (host->flags & HOST_F_DBDMA) - au1xmmc_dbdma_shutdown(host); +#ifdef CONFIG_SOC_AU1200 + au1xmmc_dbdma_shutdown(host); +#endif tasklet_kill(&host->data_task); tasklet_kill(&host->finish_task); @@ -1114,7 +1096,7 @@ out0: return ret; } -static int au1xmmc_remove(struct platform_device *pdev) +static int __devexit au1xmmc_remove(struct platform_device *pdev) { struct au1xmmc_host *host = platform_get_drvdata(pdev); @@ -1138,9 +1120,9 @@ static int au1xmmc_remove(struct platform_device *pdev) tasklet_kill(&host->data_task); tasklet_kill(&host->finish_task); - if (host->flags & HOST_F_DBDMA) - au1xmmc_dbdma_shutdown(host); - +#ifdef CONFIG_SOC_AU1200 + au1xmmc_dbdma_shutdown(host); +#endif au1xmmc_set_power(host, 0); free_irq(host->irq, host); @@ -1199,23 +1181,24 @@ static struct platform_driver au1xmmc_driver = { static int __init au1xmmc_init(void) { - if (has_dbdma()) { - /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride - * of 8 bits. And since devices are shared, we need to create - * our own to avoid freaking out other devices. - */ - memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev); - if (!memid) - pr_err("au1xmmc: cannot add memory dbdma\n"); - } +#ifdef CONFIG_SOC_AU1200 + /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride + * of 8 bits. And since devices are shared, we need to create + * our own to avoid freaking out other devices. + */ + memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev); + if (!memid) + printk(KERN_ERR "au1xmmc: cannot add memory dbdma dev\n"); +#endif return platform_driver_register(&au1xmmc_driver); } static void __exit au1xmmc_exit(void) { - if (has_dbdma() && memid) +#ifdef CONFIG_SOC_AU1200 + if (memid) au1xxx_ddma_del_device(memid); - +#endif platform_driver_unregister(&au1xmmc_driver); } diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c index fb4348c5b6a..0371bf50224 100644 --- a/drivers/mmc/host/bfin_sdh.c +++ b/drivers/mmc/host/bfin_sdh.c @@ -24,7 +24,9 @@ #include #include -#if defined(CONFIG_BF51x) || defined(__ADSPBF60x__) +#if defined(CONFIG_BF51x) +#define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CTL +#define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CTL #define bfin_read_SDH_CLK_CTL bfin_read_RSI_CLK_CTL #define bfin_write_SDH_CLK_CTL bfin_write_RSI_CLK_CTL #define bfin_write_SDH_ARGUMENT bfin_write_RSI_ARGUMENT @@ -43,18 +45,17 @@ #define bfin_write_SDH_E_STATUS bfin_write_RSI_E_STATUS #define bfin_read_SDH_STATUS bfin_read_RSI_STATUS #define bfin_write_SDH_MASK0 bfin_write_RSI_MASK0 -#define bfin_write_SDH_E_MASK bfin_write_RSI_E_MASK #define bfin_read_SDH_CFG bfin_read_RSI_CFG #define bfin_write_SDH_CFG bfin_write_RSI_CFG -# if defined(__ADSPBF60x__) -# define bfin_read_SDH_BLK_SIZE bfin_read_RSI_BLKSZ -# define bfin_write_SDH_BLK_SIZE bfin_write_RSI_BLKSZ -# else -# define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CTL -# define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CTL -# endif #endif +struct dma_desc_array { + unsigned long start_addr; + unsigned short cfg; + unsigned short x_count; + short x_modify; +} __packed; + struct sdh_host { struct mmc_host *mmc; spinlock_t lock; @@ -68,7 +69,6 @@ struct sdh_host { dma_addr_t sg_dma; int dma_len; - unsigned long sclk; unsigned int imask; unsigned int power_mode; unsigned int clk_div; @@ -134,15 +134,11 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) /* Only supports power-of-2 block size */ if (data->blksz & (data->blksz - 1)) return -EINVAL; -#ifndef RSI_BLKSZ data_ctl |= ((ffs(data->blksz) - 1) << 4); -#else - bfin_write_SDH_BLK_SIZE(data->blksz); -#endif bfin_write_SDH_DATA_CTL(data_ctl); /* the time of a host clock period in ns */ - cycle_ns = 1000000000 / (host->sclk / (2 * (host->clk_div + 1))); + cycle_ns = 1000000000 / (get_sclk() / (2 * (host->clk_div + 1))); timeout = data->timeout_ns / cycle_ns; timeout += data->timeout_clks; bfin_write_SDH_DATA_TIMER(timeout); @@ -156,13 +152,8 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) sdh_enable_stat_irq(host, (DAT_CRC_FAIL | DAT_TIME_OUT | DAT_END)); host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma_dir); -#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x) - dma_cfg |= DMAFLOW_ARRAY | RESTART | WDSIZE_32 | DMAEN; -# ifdef RSI_BLKSZ - dma_cfg |= PSIZE_32 | NDSIZE_3; -# else - dma_cfg |= NDSIZE_5; -# endif +#if defined(CONFIG_BF54x) + dma_cfg |= DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_32 | DMAEN; { struct scatterlist *sg; int i; @@ -172,7 +163,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) host->sg_cpu[i].x_count = sg_dma_len(sg) / 4; host->sg_cpu[i].x_modify = 4; dev_dbg(mmc_dev(host->mmc), "%d: start_addr:0x%lx, " - "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n", + "cfg:0x%x, x_count:0x%x, x_modify:0x%x\n", i, host->sg_cpu[i].start_addr, host->sg_cpu[i].cfg, host->sg_cpu[i].x_count, host->sg_cpu[i].x_modify); @@ -188,7 +179,6 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) set_dma_curr_desc_addr(host->dma_ch, (unsigned long *)host->sg_dma); set_dma_x_count(host->dma_ch, 0); set_dma_x_modify(host->dma_ch, 0); - SSYNC(); set_dma_config(host->dma_ch, dma_cfg); #elif defined(CONFIG_BF51x) /* RSI DMA doesn't work in array mode */ @@ -196,7 +186,6 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) set_dma_start_addr(host->dma_ch, sg_dma_address(&data->sg[0])); set_dma_x_count(host->dma_ch, length / 4); set_dma_x_modify(host->dma_ch, 4); - SSYNC(); set_dma_config(host->dma_ch, dma_cfg); #endif bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E); @@ -314,6 +303,7 @@ static int sdh_data_done(struct sdh_host *host, unsigned int stat) else data->bytes_xfered = 0; + sdh_disable_stat_irq(host, DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN); bfin_write_SDH_STATUS_CLR(DAT_END_STAT | DAT_TIMEOUT_STAT | \ DAT_CRC_FAIL_STAT | DAT_BLK_END_STAT | RX_OVERRUN | TX_UNDERRUN); bfin_write_SDH_DATA_CTL(0); @@ -338,115 +328,74 @@ static void sdh_request(struct mmc_host *mmc, struct mmc_request *mrq) dev_dbg(mmc_dev(host->mmc), "%s enter, mrp:%p, cmd:%p\n", __func__, mrq, mrq->cmd); WARN_ON(host->mrq != NULL); - spin_lock(&host->lock); host->mrq = mrq; host->data = mrq->data; if (mrq->data && mrq->data->flags & MMC_DATA_READ) { ret = sdh_setup_data(host, mrq->data); if (ret) - goto data_err; + return; } sdh_start_cmd(host, mrq->cmd); -data_err: - spin_unlock(&host->lock); } static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct sdh_host *host; + unsigned long flags; u16 clk_ctl = 0; -#ifndef RSI_BLKSZ u16 pwr_ctl = 0; -#endif u16 cfg; host = mmc_priv(mmc); - spin_lock(&host->lock); + spin_lock_irqsave(&host->lock, flags); + if (ios->clock) { + unsigned long sys_clk, ios_clk; + unsigned char clk_div; + ios_clk = 2 * ios->clock; + sys_clk = get_sclk(); + clk_div = sys_clk / ios_clk; + if (sys_clk % ios_clk == 0) + clk_div -= 1; + clk_div = min_t(unsigned char, clk_div, 0xFF); + clk_ctl |= clk_div; + clk_ctl |= CLK_E; + host->clk_div = clk_div; + } else + sdh_stop_clock(host); - cfg = bfin_read_SDH_CFG(); - cfg |= MWE; - switch (ios->bus_width) { - case MMC_BUS_WIDTH_4: -#ifndef RSI_BLKSZ - cfg &= ~PD_SDDAT3; + if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) +#ifdef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND + pwr_ctl |= ROD_CTL; +#else + pwr_ctl |= SD_CMD_OD | ROD_CTL; #endif - cfg |= PUP_SDDAT3; - /* Enable 4 bit SDIO */ - cfg |= SD4E; - clk_ctl |= WIDE_BUS_4; - break; - case MMC_BUS_WIDTH_8: -#ifndef RSI_BLKSZ + + if (ios->bus_width == MMC_BUS_WIDTH_4) { + cfg = bfin_read_SDH_CFG(); cfg &= ~PD_SDDAT3; -#endif cfg |= PUP_SDDAT3; - /* Disable 4 bit SDIO */ - cfg &= ~SD4E; - clk_ctl |= BYTE_BUS_8; - break; - default: - cfg &= ~PUP_SDDAT3; - /* Disable 4 bit SDIO */ - cfg &= ~SD4E; + /* Enable 4 bit SDIO */ + cfg |= (SD4E | MWE); + bfin_write_SDH_CFG(cfg); + clk_ctl |= WIDE_BUS; + } else { + cfg = bfin_read_SDH_CFG(); + cfg |= MWE; + bfin_write_SDH_CFG(cfg); } - host->power_mode = ios->power_mode; -#ifndef RSI_BLKSZ - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { - pwr_ctl |= ROD_CTL; -# ifndef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND - pwr_ctl |= SD_CMD_OD; -# endif - } + bfin_write_SDH_CLK_CTL(clk_ctl); - if (ios->power_mode != MMC_POWER_OFF) + host->power_mode = ios->power_mode; + if (ios->power_mode == MMC_POWER_ON) pwr_ctl |= PWR_ON; - else - pwr_ctl &= ~PWR_ON; bfin_write_SDH_PWR_CTL(pwr_ctl); -#else -# ifndef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) - cfg |= SD_CMD_OD; - else - cfg &= ~SD_CMD_OD; -# endif - - - if (ios->power_mode != MMC_POWER_OFF) - cfg |= PWR_ON; - else - cfg &= ~PWR_ON; - - bfin_write_SDH_CFG(cfg); -#endif SSYNC(); - if (ios->power_mode == MMC_POWER_ON && ios->clock) { - unsigned char clk_div; - clk_div = (get_sclk() / ios->clock - 1) / 2; - clk_div = min_t(unsigned char, clk_div, 0xFF); - clk_ctl |= clk_div; - clk_ctl |= CLK_E; - host->clk_div = clk_div; - bfin_write_SDH_CLK_CTL(clk_ctl); - - } else - sdh_stop_clock(host); - - /* set up sdh interrupt mask*/ - if (ios->power_mode == MMC_POWER_ON) - bfin_write_SDH_MASK0(DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | - RX_OVERRUN | TX_UNDERRUN | CMD_SENT | CMD_RESP_END | - CMD_TIME_OUT | CMD_CRC_FAIL); - else - bfin_write_SDH_MASK0(0); - SSYNC(); - - spin_unlock(&host->lock); + spin_unlock_irqrestore(&host->lock, flags); dev_dbg(mmc_dev(host->mmc), "SDH: clk_div = 0x%x actual clock:%ld expected clock:%d\n", host->clk_div, @@ -463,7 +412,7 @@ static irqreturn_t sdh_dma_irq(int irq, void *devid) { struct sdh_host *host = devid; - dev_dbg(mmc_dev(host->mmc), "%s enter, irq_stat: 0x%04lx\n", __func__, + dev_dbg(mmc_dev(host->mmc), "%s enter, irq_stat: 0x%04x\n", __func__, get_dma_curr_irqstat(host->dma_ch)); clear_dma_irqstat(host->dma_ch); SSYNC(); @@ -478,9 +427,6 @@ static irqreturn_t sdh_stat_irq(int irq, void *devid) int handled = 0; dev_dbg(mmc_dev(host->mmc), "%s enter\n", __func__); - - spin_lock(&host->lock); - status = bfin_read_SDH_E_STATUS(); if (status & SD_CARD_DET) { mmc_detect_change(host->mmc, 0); @@ -498,31 +444,12 @@ static irqreturn_t sdh_stat_irq(int irq, void *devid) if (status & (DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN)) handled |= sdh_data_done(host, status); - spin_unlock(&host->lock); - dev_dbg(mmc_dev(host->mmc), "%s exit\n\n", __func__); return IRQ_RETVAL(handled); } -static void sdh_reset(void) -{ -#if defined(CONFIG_BF54x) - /* Secure Digital Host shares DMA with Nand controller */ - bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1); -#endif - - bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN); - SSYNC(); - - /* Disable card inserting detection pin. set MMC_CAP_NEEDS_POLL, and - * mmc stack will do the detection. - */ - bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3)); - SSYNC(); -} - -static int sdh_probe(struct platform_device *pdev) +static int __devinit sdh_probe(struct platform_device *pdev) { struct mmc_host *mmc; struct sdh_host *host; @@ -542,16 +469,8 @@ static int sdh_probe(struct platform_device *pdev) } mmc->ops = &sdh_ops; -#if defined(CONFIG_BF51x) - mmc->max_segs = 1; -#else - mmc->max_segs = PAGE_SIZE / sizeof(struct dma_desc_array); -#endif -#ifdef RSI_BLKSZ - mmc->max_seg_size = -1; -#else + mmc->max_segs = 32; mmc->max_seg_size = 1 << 16; -#endif mmc->max_blk_size = 1 << 11; mmc->max_blk_count = 1 << 11; mmc->max_req_size = PAGE_SIZE; @@ -561,7 +480,6 @@ static int sdh_probe(struct platform_device *pdev) mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NEEDS_POLL; host = mmc_priv(mmc); host->mmc = mmc; - host->sclk = get_sclk(); spin_lock_init(&host->lock); host->irq = drv_data->irq_int0; @@ -586,6 +504,7 @@ static int sdh_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, mmc); + mmc_add_host(mmc); ret = request_irq(host->irq, sdh_stat_irq, 0, "SDH Status IRQ", host); if (ret) { @@ -598,10 +517,20 @@ static int sdh_probe(struct platform_device *pdev) dev_err(&pdev->dev, "unable to request peripheral pins\n"); goto out4; } +#if defined(CONFIG_BF54x) + /* Secure Digital Host shares DMA with Nand controller */ + bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1); +#endif - sdh_reset(); + bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN); + SSYNC(); + + /* Disable card inserting detection pin. set MMC_CAP_NEES_POLL, and + * mmc stack will do the detection. + */ + bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3)); + SSYNC(); - mmc_add_host(mmc); return 0; out4: @@ -617,7 +546,7 @@ out1: return ret; } -static int sdh_remove(struct platform_device *pdev) +static int __devexit sdh_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); @@ -649,6 +578,7 @@ static int sdh_suspend(struct platform_device *dev, pm_message_t state) if (mmc) ret = mmc_suspend_host(mmc); + bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() & ~PWR_ON); peripheral_free_list(drv_data->pin_req); return ret; @@ -666,7 +596,16 @@ static int sdh_resume(struct platform_device *dev) return ret; } - sdh_reset(); + bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() | PWR_ON); +#if defined(CONFIG_BF54x) + /* Secure Digital Host shares DMA with Nand controller */ + bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1); +#endif + bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN); + SSYNC(); + + bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3)); + SSYNC(); if (mmc) ret = mmc_resume_host(mmc); @@ -680,7 +619,7 @@ static int sdh_resume(struct platform_device *dev) static struct platform_driver sdh_driver = { .probe = sdh_probe, - .remove = sdh_remove, + .remove = __devexit_p(sdh_remove), .suspend = sdh_suspend, .resume = sdh_resume, .driver = { @@ -688,7 +627,17 @@ static struct platform_driver sdh_driver = { }, }; -module_platform_driver(sdh_driver); +static int __init sdh_init(void) +{ + return platform_driver_register(&sdh_driver); +} +module_init(sdh_init); + +static void __exit sdh_exit(void) +{ + platform_driver_unregister(&sdh_driver); +} +module_exit(sdh_exit); MODULE_DESCRIPTION("Blackfin Secure Digital Host Driver"); MODULE_AUTHOR("Cliff Cai, Roy Huang"); diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index 777ca2046b2..ce2a47b71dd 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c @@ -690,7 +690,7 @@ static int cb710_mmc_resume(struct platform_device *pdev) #endif /* CONFIG_PM */ -static int cb710_mmc_init(struct platform_device *pdev) +static int __devinit cb710_mmc_init(struct platform_device *pdev) { struct cb710_slot *slot = cb710_pdev_to_slot(pdev); struct cb710_chip *chip = cb710_slot_to_chip(slot); @@ -746,7 +746,7 @@ err_free_mmc: return err; } -static int cb710_mmc_exit(struct platform_device *pdev) +static int __devexit cb710_mmc_exit(struct platform_device *pdev) { struct cb710_slot *slot = cb710_pdev_to_slot(pdev); struct mmc_host *mmc = cb710_slot_to_mmc(slot); @@ -773,14 +773,25 @@ static int cb710_mmc_exit(struct platform_device *pdev) static struct platform_driver cb710_mmc_driver = { .driver.name = "cb710-mmc", .probe = cb710_mmc_init, - .remove = cb710_mmc_exit, + .remove = __devexit_p(cb710_mmc_exit), #ifdef CONFIG_PM .suspend = cb710_mmc_suspend, .resume = cb710_mmc_resume, #endif }; -module_platform_driver(cb710_mmc_driver); +static int __init cb710_mmc_init_module(void) +{ + return platform_driver_register(&cb710_mmc_driver); +} + +static void __exit cb710_mmc_cleanup_module(void) +{ + platform_driver_unregister(&cb710_mmc_driver); +} + +module_init(cb710_mmc_init_module); +module_exit(cb710_mmc_cleanup_module); MODULE_AUTHOR("MichaÅ‚ MirosÅ‚aw "); MODULE_DESCRIPTION("ENE CB710 memory card reader driver - MMC/SD part"); diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 20636772c09..0076c7448fe 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -30,12 +30,11 @@ #include #include #include -#include #include -#include #include -#include +#include +#include /* * Register Definitions @@ -161,16 +160,6 @@ module_param(rw_threshold, uint, S_IRUGO); MODULE_PARM_DESC(rw_threshold, "Read/Write threshold. Default = 32"); -static unsigned poll_threshold = 128; -module_param(poll_threshold, uint, S_IRUGO); -MODULE_PARM_DESC(poll_threshold, - "Polling transaction size threshold. Default = 128"); - -static unsigned poll_loopcount = 32; -module_param(poll_loopcount, uint, S_IRUGO); -MODULE_PARM_DESC(poll_loopcount, - "Maximum polling loop count. Default = 32"); - static unsigned __initdata use_dma = 1; module_param(use_dma, uint, 0); MODULE_PARM_DESC(use_dma, "Whether to use DMA or not. Default = 1"); @@ -201,12 +190,19 @@ struct mmc_davinci_host { u32 bytes_left; u32 rxdma, txdma; - struct dma_chan *dma_tx; - struct dma_chan *dma_rx; bool use_dma; bool do_dma; bool sdio_int; - bool active_request; + + /* Scatterlist DMA uses one or more parameter RAM entries: + * the main one (associated with rxdma or txdma) plus zero or + * more links. The entries for a given transfer differ only + * by memory buffer (address, length) and link field. + */ + struct edmacc_param tx_template; + struct edmacc_param rx_template; + unsigned n_link; + u32 links[MAX_NR_SG - 1]; /* For PIO we walk scatterlists one segment at a time. */ unsigned int sg_len; @@ -223,7 +219,6 @@ struct mmc_davinci_host { #endif }; -static irqreturn_t mmc_davinci_irq(int irq, void *dev_id); /* PIO only */ static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host) @@ -381,20 +376,7 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host, writel(cmd->arg, host->base + DAVINCI_MMCARGHL); writel(cmd_reg, host->base + DAVINCI_MMCCMD); - - host->active_request = true; - - if (!host->do_dma && host->bytes_left <= poll_threshold) { - u32 count = poll_loopcount; - - while (host->active_request && count--) { - mmc_davinci_irq(0, host); - cpu_relax(); - } - } - - if (host->active_request) - writel(im_val, host->base + DAVINCI_MMCIM); + writel(im_val, host->base + DAVINCI_MMCIM); } /*----------------------------------------------------------------------*/ @@ -403,74 +385,153 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host, static void davinci_abort_dma(struct mmc_davinci_host *host) { - struct dma_chan *sync_dev; + int sync_dev; if (host->data_dir == DAVINCI_MMC_DATADIR_READ) - sync_dev = host->dma_rx; + sync_dev = host->rxdma; else - sync_dev = host->dma_tx; + sync_dev = host->txdma; + + edma_stop(sync_dev); + edma_clean_channel(sync_dev); +} + +static void +mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data); + +static void mmc_davinci_dma_cb(unsigned channel, u16 ch_status, void *data) +{ + if (DMA_COMPLETE != ch_status) { + struct mmc_davinci_host *host = data; + + /* Currently means: DMA Event Missed, or "null" transfer + * request was seen. In the future, TC errors (like bad + * addresses) might be presented too. + */ + dev_warn(mmc_dev(host->mmc), "DMA %s error\n", + (host->data->flags & MMC_DATA_WRITE) + ? "write" : "read"); + host->data->error = -EIO; + mmc_davinci_xfer_done(host, host->data); + } +} + +/* Set up tx or rx template, to be modified and updated later */ +static void __init mmc_davinci_dma_setup(struct mmc_davinci_host *host, + bool tx, struct edmacc_param *template) +{ + unsigned sync_dev; + const u16 acnt = 4; + const u16 bcnt = rw_threshold >> 2; + const u16 ccnt = 0; + u32 src_port = 0; + u32 dst_port = 0; + s16 src_bidx, dst_bidx; + s16 src_cidx, dst_cidx; + + /* + * A-B Sync transfer: each DMA request is for one "frame" of + * rw_threshold bytes, broken into "acnt"-size chunks repeated + * "bcnt" times. Each segment needs "ccnt" such frames; since + * we tell the block layer our mmc->max_seg_size limit, we can + * trust (later) that it's within bounds. + * + * The FIFOs are read/written in 4-byte chunks (acnt == 4) and + * EDMA will optimize memory operations to use larger bursts. + */ + if (tx) { + sync_dev = host->txdma; + + /* src_prt, ccnt, and link to be set up later */ + src_bidx = acnt; + src_cidx = acnt * bcnt; + + dst_port = host->mem_res->start + DAVINCI_MMCDXR; + dst_bidx = 0; + dst_cidx = 0; + } else { + sync_dev = host->rxdma; - dmaengine_terminate_all(sync_dev); + src_port = host->mem_res->start + DAVINCI_MMCDRR; + src_bidx = 0; + src_cidx = 0; + + /* dst_prt, ccnt, and link to be set up later */ + dst_bidx = acnt; + dst_cidx = acnt * bcnt; + } + + /* + * We can't use FIFO mode for the FIFOs because MMC FIFO addresses + * are not 256-bit (32-byte) aligned. So we use INCR, and the W8BIT + * parameter is ignored. + */ + edma_set_src(sync_dev, src_port, INCR, W8BIT); + edma_set_dest(sync_dev, dst_port, INCR, W8BIT); + + edma_set_src_index(sync_dev, src_bidx, src_cidx); + edma_set_dest_index(sync_dev, dst_bidx, dst_cidx); + + edma_set_transfer_params(sync_dev, acnt, bcnt, ccnt, 8, ABSYNC); + + edma_read_slot(sync_dev, template); + + /* don't bother with irqs or chaining */ + template->opt |= EDMA_CHAN_SLOT(sync_dev) << 12; } -static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host, +static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host, struct mmc_data *data) { - struct dma_chan *chan; - struct dma_async_tx_descriptor *desc; - int ret = 0; + struct edmacc_param *template; + int channel, slot; + unsigned link; + struct scatterlist *sg; + unsigned sg_len; + unsigned bytes_left = host->bytes_left; + const unsigned shift = ffs(rw_threshold) - 1; if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { - struct dma_slave_config dma_tx_conf = { - .direction = DMA_MEM_TO_DEV, - .dst_addr = host->mem_res->start + DAVINCI_MMCDXR, - .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, - .dst_maxburst = - rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES, - }; - chan = host->dma_tx; - dmaengine_slave_config(host->dma_tx, &dma_tx_conf); - - desc = dmaengine_prep_slave_sg(host->dma_tx, - data->sg, - host->sg_len, - DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dev_dbg(mmc_dev(host->mmc), - "failed to allocate DMA TX descriptor"); - ret = -1; - goto out; - } + template = &host->tx_template; + channel = host->txdma; } else { - struct dma_slave_config dma_rx_conf = { - .direction = DMA_DEV_TO_MEM, - .src_addr = host->mem_res->start + DAVINCI_MMCDRR, - .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, - .src_maxburst = - rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES, - }; - chan = host->dma_rx; - dmaengine_slave_config(host->dma_rx, &dma_rx_conf); - - desc = dmaengine_prep_slave_sg(host->dma_rx, - data->sg, - host->sg_len, - DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dev_dbg(mmc_dev(host->mmc), - "failed to allocate DMA RX descriptor"); - ret = -1; - goto out; - } + template = &host->rx_template; + channel = host->rxdma; } - dmaengine_submit(desc); - dma_async_issue_pending(chan); + /* We know sg_len and ccnt will never be out of range because + * we told the mmc layer which in turn tells the block layer + * to ensure that it only hands us one scatterlist segment + * per EDMA PARAM entry. Update the PARAM + * entries needed for each segment of this scatterlist. + */ + for (slot = channel, link = 0, sg = data->sg, sg_len = host->sg_len; + sg_len-- != 0 && bytes_left; + sg = sg_next(sg), slot = host->links[link++]) { + u32 buf = sg_dma_address(sg); + unsigned count = sg_dma_len(sg); + + template->link_bcntrld = sg_len + ? (EDMA_CHAN_SLOT(host->links[link]) << 5) + : 0xffff; + + if (count > bytes_left) + count = bytes_left; + bytes_left -= count; + + if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) + template->src = buf; + else + template->dst = buf; + template->ccnt = count >> shift; + + edma_write_slot(slot, template); + } -out: - return ret; + if (host->version == MMC_CTLR_VERSION_2) + edma_clear_event(channel); + + edma_start(channel); } static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, @@ -478,7 +539,6 @@ static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, { int i; int mask = rw_threshold - 1; - int ret = 0; host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, ((data->flags & MMC_DATA_WRITE) @@ -498,48 +558,70 @@ static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, } host->do_dma = 1; - ret = mmc_davinci_send_dma_request(host, data); + mmc_davinci_send_dma_request(host, data); - return ret; + return 0; } static void __init_or_module davinci_release_dma_channels(struct mmc_davinci_host *host) { + unsigned i; + if (!host->use_dma) return; - dma_release_channel(host->dma_tx); - dma_release_channel(host->dma_rx); + for (i = 0; i < host->n_link; i++) + edma_free_slot(host->links[i]); + + edma_free_channel(host->txdma); + edma_free_channel(host->rxdma); } static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host) { - int r; - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->dma_tx = - dma_request_channel(mask, edma_filter_fn, &host->txdma); - if (!host->dma_tx) { - dev_err(mmc_dev(host->mmc), "Can't get dma_tx channel\n"); - return -ENODEV; + u32 link_size; + int r, i; + + /* Acquire master DMA write channel */ + r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb, host, + EVENTQ_DEFAULT); + if (r < 0) { + dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n", + "tx", r); + return r; } - - host->dma_rx = - dma_request_channel(mask, edma_filter_fn, &host->rxdma); - if (!host->dma_rx) { - dev_err(mmc_dev(host->mmc), "Can't get dma_rx channel\n"); - r = -ENODEV; + mmc_davinci_dma_setup(host, true, &host->tx_template); + + /* Acquire master DMA read channel */ + r = edma_alloc_channel(host->rxdma, mmc_davinci_dma_cb, host, + EVENTQ_DEFAULT); + if (r < 0) { + dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n", + "rx", r); goto free_master_write; } + mmc_davinci_dma_setup(host, false, &host->rx_template); + + /* Allocate parameter RAM slots, which will later be bound to a + * channel as needed to handle a scatterlist. + */ + link_size = min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links)); + for (i = 0; i < link_size; i++) { + r = edma_alloc_slot(EDMA_CTLR(host->txdma), EDMA_SLOT_ANY); + if (r < 0) { + dev_dbg(mmc_dev(host->mmc), "dma PaRAM alloc --> %d\n", + r); + break; + } + host->links[i] = r; + } + host->n_link = i; return 0; free_master_write: - dma_release_channel(host->dma_tx); + edma_free_channel(host->txdma); return r; } @@ -725,25 +807,12 @@ static void calculate_clk_divider(struct mmc_host *mmc, struct mmc_ios *ios) static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmc_davinci_host *host = mmc_priv(mmc); - struct platform_device *pdev = to_platform_device(mmc->parent); - struct davinci_mmc_config *config = pdev->dev.platform_data; dev_dbg(mmc_dev(host->mmc), "clock %dHz busmode %d powermode %d Vdd %04x\n", ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); - switch (ios->power_mode) { - case MMC_POWER_OFF: - if (config && config->set_power) - config->set_power(pdev->id, false); - break; - case MMC_POWER_UP: - if (config && config->set_power) - config->set_power(pdev->id, true); - break; - } - switch (ios->bus_width) { case MMC_BUS_WIDTH_8: dev_dbg(mmc_dev(host->mmc), "Enabling 8 bit mode\n"); @@ -833,7 +902,6 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data) if (!data->stop || (host->cmd && host->cmd->error)) { mmc_request_done(host->mmc, data->mrq); writel(0, host->base + DAVINCI_MMCIM); - host->active_request = false; } else mmc_davinci_start_command(host, data->stop); } @@ -861,7 +929,6 @@ static void mmc_davinci_cmd_done(struct mmc_davinci_host *host, cmd->mrq->cmd->retries = 0; mmc_request_done(host->mmc, cmd->mrq); writel(0, host->base + DAVINCI_MMCIM); - host->active_request = false; } } @@ -929,33 +996,12 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) * by read. So, it is not unbouned loop even in the case of * non-dma. */ - if (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) { - unsigned long im_val; - - /* - * If interrupts fire during the following loop, they will be - * handled by the handler, but the PIC will still buffer these. - * As a result, the handler will be called again to serve these - * needlessly. In order to avoid these spurious interrupts, - * keep interrupts masked during the loop. - */ - im_val = readl(host->base + DAVINCI_MMCIM); - writel(0, host->base + DAVINCI_MMCIM); - - do { - davinci_fifo_data_trans(host, rw_threshold); - status = readl(host->base + DAVINCI_MMCST0); - qstatus |= status; - } while (host->bytes_left && - (status & (MMCST0_DXRDY | MMCST0_DRRDY))); - - /* - * If an interrupt is pending, it is assumed it will fire when - * it is unmasked. This assumption is also taken when the MMCIM - * is first set. Otherwise, writing to MMCIM after reading the - * status is race-prone. - */ - writel(im_val, host->base + DAVINCI_MMCIM); + while (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) { + davinci_fifo_data_trans(host, rw_threshold); + status = readl(host->base + DAVINCI_MMCST0); + if (!status) + break; + qstatus |= status; } if (qstatus & MMCST0_DATDNE) { @@ -1252,7 +1298,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) * Each hw_seg uses one EDMA parameter RAM slot, always one * channel and then usually some linked slots. */ - mmc->max_segs = MAX_NR_SG; + mmc->max_segs = 1 + host->n_link; /* EDMA limit per hw segment (one or two MBytes) */ mmc->max_seg_size = MAX_CCNT * rw_threshold; @@ -1359,14 +1405,17 @@ static int davinci_mmcsd_suspend(struct device *dev) struct mmc_davinci_host *host = platform_get_drvdata(pdev); int ret; + mmc_host_enable(host->mmc); ret = mmc_suspend_host(host->mmc); if (!ret) { writel(0, host->base + DAVINCI_MMCIM); mmc_davinci_reset_ctrl(host, 1); + mmc_host_disable(host->mmc); clk_disable(host->clk); host->suspended = 1; } else { host->suspended = 0; + mmc_host_disable(host->mmc); } return ret; @@ -1382,6 +1431,7 @@ static int davinci_mmcsd_resume(struct device *dev) return 0; clk_enable(host->clk); + mmc_host_enable(host->mmc); mmc_davinci_reset_ctrl(host, 0); ret = mmc_resume_host(host->mmc); @@ -1426,5 +1476,4 @@ 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-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c deleted file mode 100644 index 4d50da61816..00000000000 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Exynos Specific Extensions for Synopsys DW Multimedia Card Interface driver - * - * Copyright (C) 2012, Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "dw_mmc.h" -#include "dw_mmc-pltfm.h" - -#define NUM_PINS(x) (x + 2) - -#define SDMMC_CLKSEL 0x09C -#define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) -#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16) -#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24) -#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7) -#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \ - SDMMC_CLKSEL_CCLK_DRIVE(y) | \ - SDMMC_CLKSEL_CCLK_DIVIDER(z)) - -#define SDMMC_CMD_USE_HOLD_REG BIT(29) - -#define EXYNOS4210_FIXED_CIU_CLK_DIV 2 -#define EXYNOS4412_FIXED_CIU_CLK_DIV 4 - -/* Variations in Exynos specific dw-mshc controller */ -enum dw_mci_exynos_type { - DW_MCI_TYPE_EXYNOS4210, - DW_MCI_TYPE_EXYNOS4412, - DW_MCI_TYPE_EXYNOS5250, -}; - -/* Exynos implementation specific driver private data */ -struct dw_mci_exynos_priv_data { - enum dw_mci_exynos_type ctrl_type; - u8 ciu_div; - u32 sdr_timing; - u32 ddr_timing; -}; - -static struct dw_mci_exynos_compatible { - char *compatible; - enum dw_mci_exynos_type ctrl_type; -} exynos_compat[] = { - { - .compatible = "samsung,exynos4210-dw-mshc", - .ctrl_type = DW_MCI_TYPE_EXYNOS4210, - }, { - .compatible = "samsung,exynos4412-dw-mshc", - .ctrl_type = DW_MCI_TYPE_EXYNOS4412, - }, { - .compatible = "samsung,exynos5250-dw-mshc", - .ctrl_type = DW_MCI_TYPE_EXYNOS5250, - }, -}; - -static int dw_mci_exynos_priv_init(struct dw_mci *host) -{ - struct dw_mci_exynos_priv_data *priv; - int idx; - - priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(host->dev, "mem alloc failed for private data\n"); - return -ENOMEM; - } - - for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) { - if (of_device_is_compatible(host->dev->of_node, - exynos_compat[idx].compatible)) - priv->ctrl_type = exynos_compat[idx].ctrl_type; - } - - host->priv = priv; - return 0; -} - -static int dw_mci_exynos_setup_clock(struct dw_mci *host) -{ - struct dw_mci_exynos_priv_data *priv = host->priv; - - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5250) - host->bus_hz /= (priv->ciu_div + 1); - else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412) - host->bus_hz /= EXYNOS4412_FIXED_CIU_CLK_DIV; - else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) - host->bus_hz /= EXYNOS4210_FIXED_CIU_CLK_DIV; - - return 0; -} - -static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) -{ - /* - * Exynos4412 and Exynos5250 extends the use of CMD register with the - * use of bit 29 (which is reserved on standard MSHC controllers) for - * optionally bypassing the HOLD register for command and data. The - * HOLD register should be bypassed in case there is no phase shift - * applied on CMD/DATA that is sent to the card. - */ - if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL))) - *cmdr |= SDMMC_CMD_USE_HOLD_REG; -} - -static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) -{ - struct dw_mci_exynos_priv_data *priv = host->priv; - - if (ios->timing == MMC_TIMING_UHS_DDR50) - mci_writel(host, CLKSEL, priv->ddr_timing); - else - mci_writel(host, CLKSEL, priv->sdr_timing); -} - -static int dw_mci_exynos_parse_dt(struct dw_mci *host) -{ - struct dw_mci_exynos_priv_data *priv = host->priv; - struct device_node *np = host->dev->of_node; - u32 timing[2]; - u32 div = 0; - int ret; - - of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div); - priv->ciu_div = div; - - ret = of_property_read_u32_array(np, - "samsung,dw-mshc-sdr-timing", timing, 2); - if (ret) - return ret; - - priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); - - ret = of_property_read_u32_array(np, - "samsung,dw-mshc-ddr-timing", timing, 2); - if (ret) - return ret; - - priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); - return 0; -} - -static int dw_mci_exynos_setup_bus(struct dw_mci *host, - struct device_node *slot_np, u8 bus_width) -{ - int idx, gpio, ret; - - if (!slot_np) - return -EINVAL; - - /* cmd + clock + bus-width pins */ - for (idx = 0; idx < NUM_PINS(bus_width); idx++) { - gpio = of_get_gpio(slot_np, idx); - if (!gpio_is_valid(gpio)) { - dev_err(host->dev, "invalid gpio: %d\n", gpio); - return -EINVAL; - } - - ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus"); - if (ret) { - dev_err(host->dev, "gpio [%d] request failed\n", gpio); - return -EBUSY; - } - } - - gpio = of_get_named_gpio(slot_np, "wp-gpios", 0); - if (gpio_is_valid(gpio)) { - if (devm_gpio_request(host->dev, gpio, "dw-mci-wp")) - dev_info(host->dev, "gpio [%d] request failed\n", - gpio); - } else { - dev_info(host->dev, "wp gpio not available"); - host->pdata->quirks |= DW_MCI_QUIRK_NO_WRITE_PROTECT; - } - - if (host->pdata->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) - return 0; - - gpio = of_get_named_gpio(slot_np, "samsung,cd-pinmux-gpio", 0); - if (gpio_is_valid(gpio)) { - if (devm_gpio_request(host->dev, gpio, "dw-mci-cd")) - dev_err(host->dev, "gpio [%d] request failed\n", gpio); - } else { - dev_info(host->dev, "cd gpio not available"); - } - - return 0; -} - -/* Exynos5250 controller specific capabilities */ -static unsigned long exynos5250_dwmmc_caps[4] = { - MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR | - MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, - MMC_CAP_CMD23, - MMC_CAP_CMD23, - MMC_CAP_CMD23, -}; - -static const struct dw_mci_drv_data exynos5250_drv_data = { - .caps = exynos5250_dwmmc_caps, - .init = dw_mci_exynos_priv_init, - .setup_clock = dw_mci_exynos_setup_clock, - .prepare_command = dw_mci_exynos_prepare_command, - .set_ios = dw_mci_exynos_set_ios, - .parse_dt = dw_mci_exynos_parse_dt, - .setup_bus = dw_mci_exynos_setup_bus, -}; - -static const struct of_device_id dw_mci_exynos_match[] = { - { .compatible = "samsung,exynos5250-dw-mshc", - .data = &exynos5250_drv_data, }, - {}, -}; -MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); - -int dw_mci_exynos_probe(struct platform_device *pdev) -{ - const struct dw_mci_drv_data *drv_data; - const struct of_device_id *match; - - match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node); - drv_data = match->data; - return dw_mci_pltfm_register(pdev, drv_data); -} - -static struct platform_driver dw_mci_exynos_pltfm_driver = { - .probe = dw_mci_exynos_probe, - .remove = __exit_p(dw_mci_pltfm_remove), - .driver = { - .name = "dwmmc_exynos", - .of_match_table = of_match_ptr(dw_mci_exynos_match), - .pm = &dw_mci_pltfm_pmops, - }, -}; - -module_platform_driver(dw_mci_exynos_pltfm_driver); - -MODULE_DESCRIPTION("Samsung Specific DW-MSHC Driver Extension"); -MODULE_AUTHOR("Thomas Abraham -#include -#include -#include -#include -#include -#include -#include -#include -#include "dw_mmc.h" - -#define PCI_BAR_NO 2 -#define COMPLETE_BAR 0 -#define SYNOPSYS_DW_MCI_VENDOR_ID 0x700 -#define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107 -/* Defining the Capabilities */ -#define DW_MCI_CAPABILITIES (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |\ - MMC_CAP_SD_HIGHSPEED | MMC_CAP_8_BIT_DATA |\ - MMC_CAP_SDIO_IRQ) - -static struct dw_mci_board pci_board_data = { - .num_slots = 1, - .caps = DW_MCI_CAPABILITIES, - .bus_hz = 33 * 1000 * 1000, - .detect_delay_ms = 200, - .fifo_depth = 32, -}; - -static int dw_mci_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *entries) -{ - struct dw_mci *host; - int ret; - - ret = pci_enable_device(pdev); - if (ret) - return ret; - if (pci_request_regions(pdev, "dw_mmc_pci")) { - ret = -ENODEV; - goto err_disable_dev; - } - - host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL); - if (!host) { - ret = -ENOMEM; - goto err_release; - } - - host->irq = pdev->irq; - host->irq_flags = IRQF_SHARED; - host->dev = &pdev->dev; - host->pdata = &pci_board_data; - - host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR); - if (!host->regs) { - ret = -EIO; - goto err_unmap; - } - - pci_set_drvdata(pdev, host); - ret = dw_mci_probe(host); - if (ret) - goto err_probe_failed; - return ret; - -err_probe_failed: - pci_iounmap(pdev, host->regs); -err_unmap: - kfree(host); -err_release: - pci_release_regions(pdev); -err_disable_dev: - pci_disable_device(pdev); - return ret; -} - -static void dw_mci_pci_remove(struct pci_dev *pdev) -{ - struct dw_mci *host = pci_get_drvdata(pdev); - - dw_mci_remove(host); - pci_set_drvdata(pdev, NULL); - pci_release_regions(pdev); - pci_iounmap(pdev, host->regs); - kfree(host); - pci_disable_device(pdev); -} - -#ifdef CONFIG_PM_SLEEP -static int dw_mci_pci_suspend(struct device *dev) -{ - int ret; - struct pci_dev *pdev = to_pci_dev(dev); - struct dw_mci *host = pci_get_drvdata(pdev); - - ret = dw_mci_suspend(host); - return ret; -} - -static int dw_mci_pci_resume(struct device *dev) -{ - int ret; - struct pci_dev *pdev = to_pci_dev(dev); - struct dw_mci *host = pci_get_drvdata(pdev); - - ret = dw_mci_resume(host); - return ret; -} -#else -#define dw_mci_pci_suspend NULL -#define dw_mci_pci_resume NULL -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(dw_mci_pci_pmops, dw_mci_pci_suspend, dw_mci_pci_resume); - -static DEFINE_PCI_DEVICE_TABLE(dw_mci_pci_id) = { - { PCI_DEVICE(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) }, - {} -}; -MODULE_DEVICE_TABLE(pci, dw_mci_pci_id); - -static struct pci_driver dw_mci_pci_driver = { - .name = "dw_mmc_pci", - .id_table = dw_mci_pci_id, - .probe = dw_mci_pci_probe, - .remove = dw_mci_pci_remove, - .driver = { - .pm = &dw_mci_pci_pmops - }, -}; - -module_pci_driver(dw_mci_pci_driver); - -MODULE_DESCRIPTION("DW Multimedia Card PCI Interface driver"); -MODULE_AUTHOR("Shashidhar Hiremath "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c deleted file mode 100644 index 5e1fb1d2c42..00000000000 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Synopsys DesignWare Multimedia Card Interface driver - * - * Copyright (C) 2009 NXP Semiconductors - * Copyright (C) 2009, 2010 Imagination Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dw_mmc.h" - -int dw_mci_pltfm_register(struct platform_device *pdev, - const struct dw_mci_drv_data *drv_data) -{ - struct dw_mci *host; - struct resource *regs; - int ret; - - host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL); - if (!host) - return -ENOMEM; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) - return -ENXIO; - - host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) - return host->irq; - - host->drv_data = drv_data; - host->dev = &pdev->dev; - host->irq_flags = 0; - host->pdata = pdev->dev.platform_data; - host->regs = devm_request_and_ioremap(&pdev->dev, regs); - if (!host->regs) - return -ENOMEM; - - if (drv_data && drv_data->init) { - ret = drv_data->init(host); - if (ret) - return ret; - } - - platform_set_drvdata(pdev, host); - ret = dw_mci_probe(host); - return ret; -} -EXPORT_SYMBOL_GPL(dw_mci_pltfm_register); - -static int dw_mci_pltfm_probe(struct platform_device *pdev) -{ - return dw_mci_pltfm_register(pdev, NULL); -} - -static int dw_mci_pltfm_remove(struct platform_device *pdev) -{ - struct dw_mci *host = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - dw_mci_remove(host); - return 0; -} -EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove); - -#ifdef CONFIG_PM_SLEEP -/* - * TODO: we should probably disable the clock to the card in the suspend path. - */ -static int dw_mci_pltfm_suspend(struct device *dev) -{ - int ret; - struct dw_mci *host = dev_get_drvdata(dev); - - ret = dw_mci_suspend(host); - if (ret) - return ret; - - return 0; -} - -static int dw_mci_pltfm_resume(struct device *dev) -{ - int ret; - struct dw_mci *host = dev_get_drvdata(dev); - - ret = dw_mci_resume(host); - if (ret) - return ret; - - return 0; -} -#else -#define dw_mci_pltfm_suspend NULL -#define dw_mci_pltfm_resume NULL -#endif /* CONFIG_PM_SLEEP */ - -SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume); -EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops); - -static const struct of_device_id dw_mci_pltfm_match[] = { - { .compatible = "snps,dw-mshc", }, - {}, -}; -MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match); - -static struct platform_driver dw_mci_pltfm_driver = { - .probe = dw_mci_pltfm_probe, - .remove = dw_mci_pltfm_remove, - .driver = { - .name = "dw_mmc", - .of_match_table = of_match_ptr(dw_mci_pltfm_match), - .pm = &dw_mci_pltfm_pmops, - }, -}; - -module_platform_driver(dw_mci_pltfm_driver); - -MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); -MODULE_AUTHOR("NXP Semiconductor VietNam"); -MODULE_AUTHOR("Imagination Technologies Ltd"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/dw_mmc-pltfm.h b/drivers/mmc/host/dw_mmc-pltfm.h deleted file mode 100644 index 68e7fd2f614..00000000000 --- a/drivers/mmc/host/dw_mmc-pltfm.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Synopsys DesignWare Multimedia Card Interface Platform driver - * - * Copyright (C) 2012, Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef _DW_MMC_PLTFM_H_ -#define _DW_MMC_PLTFM_H_ - -extern int dw_mci_pltfm_register(struct platform_device *pdev, - const struct dw_mci_drv_data *drv_data); -extern int dw_mci_pltfm_remove(struct platform_device *pdev); -extern const struct dev_pm_ops dw_mci_pltfm_pmops; - -#endif /* _DW_MMC_PLTFM_H_ */ diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 323c5022c2c..ff0f714b012 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include #include "dw_mmc.h" @@ -101,6 +101,8 @@ 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) { @@ -231,8 +233,6 @@ static void dw_mci_set_timeout(struct dw_mci *host) static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) { struct mmc_data *data; - struct dw_mci_slot *slot = mmc_priv(mmc); - const struct dw_mci_drv_data *drv_data = slot->host->drv_data; u32 cmdr; cmd->error = -EINPROGRESS; @@ -262,9 +262,6 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) cmdr |= SDMMC_CMD_DAT_WR; } - if (drv_data && drv_data->prepare_command) - drv_data->prepare_command(slot->host, &cmdr); - return cmdr; } @@ -272,7 +269,7 @@ static void dw_mci_start_command(struct dw_mci *host, struct mmc_command *cmd, u32 cmd_flags) { host->cmd = cmd; - dev_vdbg(host->dev, + dev_vdbg(&host->pdev->dev, "start command: ARGR=0x%08x CMDR=0x%08x\n", cmd->arg, cmd_flags); @@ -299,25 +296,15 @@ static void dw_mci_stop_dma(struct dw_mci *host) } } -static int dw_mci_get_dma_dir(struct mmc_data *data) -{ - if (data->flags & MMC_DATA_WRITE) - return DMA_TO_DEVICE; - else - return DMA_FROM_DEVICE; -} - #ifdef CONFIG_MMC_DW_IDMAC static void dw_mci_dma_cleanup(struct dw_mci *host) { struct mmc_data *data = host->data; if (data) - if (!data->host_cookie) - dma_unmap_sg(host->dev, - data->sg, - data->sg_len, - dw_mci_get_dma_dir(data)); + dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, + ((data->flags & MMC_DATA_WRITE) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); } static void dw_mci_idmac_stop_dma(struct dw_mci *host) @@ -340,7 +327,7 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host) { struct mmc_data *data = host->data; - dev_vdbg(host->dev, "DMA complete\n"); + dev_vdbg(&host->pdev->dev, "DMA complete\n"); host->dma_ops->cleanup(host); @@ -424,8 +411,6 @@ static int dw_mci_idmac_init(struct dw_mci *host) p->des3 = host->sg_dma; p->des0 = IDMAC_DES0_ER; - mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET); - /* Mask out interrupts - get Tx & Rx complete only */ mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); @@ -435,7 +420,7 @@ static int dw_mci_idmac_init(struct dw_mci *host) return 0; } -static const struct dw_mci_dma_ops dw_mci_idmac_ops = { +static struct dw_mci_dma_ops dw_mci_idmac_ops = { .init = dw_mci_idmac_init, .start = dw_mci_idmac_start_dma, .stop = dw_mci_idmac_stop_dma, @@ -444,15 +429,17 @@ static const struct dw_mci_dma_ops dw_mci_idmac_ops = { }; #endif /* CONFIG_MMC_DW_IDMAC */ -static int dw_mci_pre_dma_transfer(struct dw_mci *host, - struct mmc_data *data, - bool next) +static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) { struct scatterlist *sg; - unsigned int i, sg_len; + unsigned int i, direction, sg_len; + u32 temp; - if (!next && data->host_cookie) - return data->host_cookie; + host->using_dma = 0; + + /* If we don't have a channel, we can't do DMA */ + if (!host->use_dma) + return -ENODEV; /* * We don't do DMA on "complex" transfers, i.e. with @@ -461,7 +448,6 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host, */ if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) return -EINVAL; - if (data->blksz & 3) return -EINVAL; @@ -470,76 +456,17 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host, return -EINVAL; } - sg_len = dma_map_sg(host->dev, - data->sg, - data->sg_len, - dw_mci_get_dma_dir(data)); - if (sg_len == 0) - return -EINVAL; - - if (next) - data->host_cookie = sg_len; - - return sg_len; -} - -static void dw_mci_pre_req(struct mmc_host *mmc, - struct mmc_request *mrq, - bool is_first_req) -{ - struct dw_mci_slot *slot = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - - if (!slot->host->use_dma || !data) - return; - - if (data->host_cookie) { - data->host_cookie = 0; - return; - } - - if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0) - data->host_cookie = 0; -} - -static void dw_mci_post_req(struct mmc_host *mmc, - struct mmc_request *mrq, - int err) -{ - struct dw_mci_slot *slot = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - - if (!slot->host->use_dma || !data) - return; - - if (data->host_cookie) - dma_unmap_sg(slot->host->dev, - data->sg, - data->sg_len, - dw_mci_get_dma_dir(data)); - data->host_cookie = 0; -} - -static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) -{ - int sg_len; - u32 temp; - - host->using_dma = 0; - - /* If we don't have a channel, we can't do DMA */ - if (!host->use_dma) - return -ENODEV; + host->using_dma = 1; - sg_len = dw_mci_pre_dma_transfer(host, data, 0); - if (sg_len < 0) { - host->dma_ops->stop(host); - return sg_len; - } + if (data->flags & MMC_DATA_READ) + direction = DMA_FROM_DEVICE; + else + direction = DMA_TO_DEVICE; - host->using_dma = 1; + sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, + direction); - dev_vdbg(host->dev, + dev_vdbg(&host->pdev->dev, "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma, sg_len); @@ -575,14 +502,8 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) host->dir_status = DW_MCI_SEND_STATUS; if (dw_mci_submit_data_dma(host, data)) { - int flags = SG_MITER_ATOMIC; - if (host->data->flags & MMC_DATA_READ) - flags |= SG_MITER_TO_SG; - else - flags |= SG_MITER_FROM_SG; - - sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); host->sg = data->sg; + host->pio_offset = 0; host->part_buf_start = 0; host->part_buf_count = 0; @@ -617,22 +538,20 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) cmd, arg, cmd_status); } -static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) +static void dw_mci_setup_bus(struct dw_mci_slot *slot) { struct dw_mci *host = slot->host; u32 div; - u32 clk_en_a; - if (slot->clock != host->current_speed || force_clkinit) { - div = host->bus_hz / slot->clock; - if (host->bus_hz % slot->clock && host->bus_hz > slot->clock) + if (slot->clock != host->current_speed) { + if (host->bus_hz % slot->clock) /* * move the + 1 after the divide to prevent * over-clocking the card. */ - div += 1; - - div = (host->bus_hz != slot->clock) ? DIV_ROUND_UP(div, 2) : 0; + div = ((host->bus_hz / slot->clock) >> 1) + 1; + else + div = (host->bus_hz / slot->clock) >> 1; dev_info(&slot->mmc->class_dev, "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ" @@ -654,11 +573,9 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); - /* enable clock; only low power if no SDIO */ - clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; - if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id))) - clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; - mci_writel(host, CLKENA, clk_en_a); + /* enable clock */ + mci_writel(host, CLKENA, SDMMC_CLKEN_ENABLE | + SDMMC_CLKEN_LOW_PWR); /* inform CIU */ mci_send_cmd(slot, @@ -671,11 +588,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) mci_writel(host, CTYPE, (slot->ctype << slot->id)); } -static void __dw_mci_start_request(struct dw_mci *host, - struct dw_mci_slot *slot, - struct mmc_command *cmd) +static void dw_mci_start_request(struct dw_mci *host, + struct dw_mci_slot *slot) { struct mmc_request *mrq; + struct mmc_command *cmd; struct mmc_data *data; u32 cmdflags; @@ -683,6 +600,9 @@ static void __dw_mci_start_request(struct dw_mci *host, if (host->pdata->select_slot) host->pdata->select_slot(slot->id); + /* Slot specific timing and width adjustment */ + dw_mci_setup_bus(slot); + host->cur_slot = slot; host->mrq = mrq; @@ -690,13 +610,14 @@ static void __dw_mci_start_request(struct dw_mci *host, host->completed_events = 0; host->data_status = 0; - data = cmd->data; + data = mrq->data; if (data) { dw_mci_set_timeout(host); mci_writel(host, BYTCNT, data->blksz*data->blocks); mci_writel(host, BLKSIZ, data->blksz); } + cmd = mrq->cmd; cmdflags = dw_mci_prepare_command(slot->mmc, cmd); /* this is the first command, send the initialization clock */ @@ -714,16 +635,6 @@ static void __dw_mci_start_request(struct dw_mci *host, host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); } -static void dw_mci_start_request(struct dw_mci *host, - struct dw_mci_slot *slot) -{ - struct mmc_request *mrq = slot->mrq; - struct mmc_command *cmd; - - cmd = mrq->sbc ? mrq->sbc : mrq->cmd; - __dw_mci_start_request(host, slot, cmd); -} - /* must be called with host->lock held */ static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, struct mmc_request *mrq) @@ -770,30 +681,29 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct dw_mci_slot *slot = mmc_priv(mmc); - const struct dw_mci_drv_data *drv_data = slot->host->drv_data; u32 regs; + /* set default 1 bit mode */ + slot->ctype = SDMMC_CTYPE_1BIT; + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + slot->ctype = SDMMC_CTYPE_1BIT; + break; case MMC_BUS_WIDTH_4: slot->ctype = SDMMC_CTYPE_4BIT; break; case MMC_BUS_WIDTH_8: slot->ctype = SDMMC_CTYPE_8BIT; break; - default: - /* set default 1 bit mode */ - slot->ctype = SDMMC_CTYPE_1BIT; } - regs = mci_readl(slot->host, UHS_REG); - /* DDR mode set */ - if (ios->timing == MMC_TIMING_UHS_DDR50) + if (ios->timing == MMC_TIMING_UHS_DDR50) { + regs = mci_readl(slot->host, UHS_REG); regs |= (0x1 << slot->id) << 16; - else - regs &= ~(0x1 << slot->id) << 16; - - mci_writel(slot->host, UHS_REG, regs); + mci_writel(slot->host, UHS_REG, regs); + } if (ios->clock) { /* @@ -803,12 +713,6 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) slot->clock = ios->clock; } - if (drv_data && drv_data->set_ios) - drv_data->set_ios(slot->host, ios); - - /* Slot specific timing and width adjustment */ - dw_mci_setup_bus(slot, false); - switch (ios->power_mode) { case MMC_POWER_UP: set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); @@ -825,9 +729,7 @@ static int dw_mci_get_ro(struct mmc_host *mmc) struct dw_mci_board *brd = slot->host->pdata; /* Use platform get_ro function, else try on board write protect */ - if (brd->quirks & DW_MCI_QUIRK_NO_WRITE_PROTECT) - read_only = 0; - else if (brd->get_ro) + if (brd->get_ro) read_only = brd->get_ro(slot->id); else read_only = @@ -862,63 +764,11 @@ static int dw_mci_get_cd(struct mmc_host *mmc) return present; } -/* - * Disable lower power mode. - * - * Low power mode will stop the card clock when idle. According to the - * description of the CLKENA register we should disable low power mode - * for SDIO cards if we need SDIO interrupts to work. - * - * This function is fast if low power mode is already disabled. - */ -static void dw_mci_disable_low_power(struct dw_mci_slot *slot) -{ - struct dw_mci *host = slot->host; - u32 clk_en_a; - const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; - - clk_en_a = mci_readl(host, CLKENA); - - if (clk_en_a & clken_low_pwr) { - mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); - mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | - SDMMC_CMD_PRV_DAT_WAIT, 0); - } -} - -static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) -{ - struct dw_mci_slot *slot = mmc_priv(mmc); - struct dw_mci *host = slot->host; - u32 int_mask; - - /* Enable/disable Slot Specific SDIO interrupt */ - int_mask = mci_readl(host, INTMASK); - if (enb) { - /* - * Turn off low power mode if it was enabled. This is a bit of - * a heavy operation and we disable / enable IRQs a lot, so - * we'll leave low power mode disabled and it will get - * re-enabled again in dw_mci_setup_bus(). - */ - dw_mci_disable_low_power(slot); - - mci_writel(host, INTMASK, - (int_mask | SDMMC_INT_SDIO(slot->id))); - } else { - mci_writel(host, INTMASK, - (int_mask & ~SDMMC_INT_SDIO(slot->id))); - } -} - static const struct mmc_host_ops dw_mci_ops = { - .request = dw_mci_request, - .pre_req = dw_mci_pre_req, - .post_req = dw_mci_post_req, - .set_ios = dw_mci_set_ios, - .get_ro = dw_mci_get_ro, - .get_cd = dw_mci_get_cd, - .enable_sdio_irq = dw_mci_enable_sdio_irq, + .request = dw_mci_request, + .set_ios = dw_mci_set_ios, + .get_ro = dw_mci_get_ro, + .get_cd = dw_mci_get_cd, }; static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) @@ -936,12 +786,12 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) slot = list_entry(host->queue.next, struct dw_mci_slot, queue_node); list_del(&slot->queue_node); - dev_vdbg(host->dev, "list not empty: %s is next\n", + dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n", mmc_hostname(slot->mmc)); host->state = STATE_SENDING_CMD; dw_mci_start_request(host, slot); } else { - dev_vdbg(host->dev, "list empty\n"); + dev_vdbg(&host->pdev->dev, "list empty\n"); host->state = STATE_IDLE; } @@ -986,8 +836,8 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd mdelay(20); if (cmd->data) { - dw_mci_stop_dma(host); host->data = NULL; + dw_mci_stop_dma(host); } } } @@ -1021,14 +871,7 @@ static void dw_mci_tasklet_func(unsigned long priv) cmd = host->cmd; host->cmd = NULL; set_bit(EVENT_CMD_COMPLETE, &host->completed_events); - dw_mci_command_complete(host, cmd); - if (cmd == host->mrq->sbc && !cmd->error) { - prev_state = state = STATE_SENDING_CMD; - __dw_mci_start_request(host, host->cur_slot, - host->mrq->cmd); - goto unlock; - } - + dw_mci_command_complete(host, host->mrq->cmd); if (!host->mrq->data || cmd->error) { dw_mci_request_end(host, host->mrq); goto unlock; @@ -1080,7 +923,7 @@ static void dw_mci_tasklet_func(unsigned long priv) data->bytes_xfered = 0; data->error = -ETIMEDOUT; } else { - dev_err(host->dev, + dev_err(&host->pdev->dev, "data FIFO error " "(status=%08x)\n", status); @@ -1092,7 +935,6 @@ static void dw_mci_tasklet_func(unsigned long priv) * generates a block interrupt, hence setting * the scatter-gather pointer to NULL. */ - sg_miter_stop(&host->sg_miter); host->sg = NULL; ctrl = mci_readl(host, CTRL); ctrl |= SDMMC_CTRL_FIFO_RESET; @@ -1107,12 +949,6 @@ static void dw_mci_tasklet_func(unsigned long priv) goto unlock; } - if (host->mrq->sbc && !data->error) { - data->stop->error = 0; - dw_mci_request_end(host, host->mrq); - goto unlock; - } - prev_state = state = STATE_SENDING_STOP; if (!data->error) send_stop_cmd(host, data); @@ -1189,8 +1025,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (!sg_next(host->sg) || host->part_buf_count == 2) { - mci_writew(host, DATA(host->data_offset), - host->part_buf16); + mci_writew(host, DATA, host->part_buf16); host->part_buf_count = 0; } } @@ -1207,23 +1042,21 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) cnt -= len; /* push data from aligned buffer into fifo */ for (i = 0; i < items; ++i) - mci_writew(host, DATA(host->data_offset), - aligned_buf[i]); + mci_writew(host, DATA, aligned_buf[i]); } } else #endif { u16 *pdata = buf; for (; cnt >= 2; cnt -= 2) - mci_writew(host, DATA(host->data_offset), *pdata++); + mci_writew(host, DATA, *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); if (!sg_next(host->sg)) - mci_writew(host, DATA(host->data_offset), - host->part_buf16); + mci_writew(host, DATA, host->part_buf16); } } @@ -1238,8 +1071,7 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) int items = len >> 1; int i; for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readw(host, - DATA(host->data_offset)); + aligned_buf[i] = mci_readw(host, DATA); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1250,11 +1082,11 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) { u16 *pdata = buf; for (; cnt >= 2; cnt -= 2) - *pdata++ = mci_readw(host, DATA(host->data_offset)); + *pdata++ = mci_readw(host, DATA); buf = pdata; } if (cnt) { - host->part_buf16 = mci_readw(host, DATA(host->data_offset)); + host->part_buf16 = mci_readw(host, DATA); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1267,8 +1099,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (!sg_next(host->sg) || host->part_buf_count == 4) { - mci_writel(host, DATA(host->data_offset), - host->part_buf32); + mci_writel(host, DATA, host->part_buf32); host->part_buf_count = 0; } } @@ -1285,23 +1116,21 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) cnt -= len; /* push data from aligned buffer into fifo */ for (i = 0; i < items; ++i) - mci_writel(host, DATA(host->data_offset), - aligned_buf[i]); + mci_writel(host, DATA, aligned_buf[i]); } } else #endif { u32 *pdata = buf; for (; cnt >= 4; cnt -= 4) - mci_writel(host, DATA(host->data_offset), *pdata++); + mci_writel(host, DATA, *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); if (!sg_next(host->sg)) - mci_writel(host, DATA(host->data_offset), - host->part_buf32); + mci_writel(host, DATA, host->part_buf32); } } @@ -1316,8 +1145,7 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) int items = len >> 2; int i; for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readl(host, - DATA(host->data_offset)); + aligned_buf[i] = mci_readl(host, DATA); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1328,11 +1156,11 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) { u32 *pdata = buf; for (; cnt >= 4; cnt -= 4) - *pdata++ = mci_readl(host, DATA(host->data_offset)); + *pdata++ = mci_readl(host, DATA); buf = pdata; } if (cnt) { - host->part_buf32 = mci_readl(host, DATA(host->data_offset)); + host->part_buf32 = mci_readl(host, DATA); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1345,8 +1173,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (!sg_next(host->sg) || host->part_buf_count == 8) { - mci_writew(host, DATA(host->data_offset), - host->part_buf); + mci_writew(host, DATA, host->part_buf); host->part_buf_count = 0; } } @@ -1363,23 +1190,21 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) cnt -= len; /* push data from aligned buffer into fifo */ for (i = 0; i < items; ++i) - mci_writeq(host, DATA(host->data_offset), - aligned_buf[i]); + mci_writeq(host, DATA, aligned_buf[i]); } } else #endif { u64 *pdata = buf; for (; cnt >= 8; cnt -= 8) - mci_writeq(host, DATA(host->data_offset), *pdata++); + mci_writeq(host, DATA, *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); if (!sg_next(host->sg)) - mci_writeq(host, DATA(host->data_offset), - host->part_buf); + mci_writeq(host, DATA, host->part_buf); } } @@ -1394,8 +1219,7 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) int items = len >> 3; int i; for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readq(host, - DATA(host->data_offset)); + aligned_buf[i] = mci_readq(host, DATA); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1406,11 +1230,11 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) { u64 *pdata = buf; for (; cnt >= 8; cnt -= 8) - *pdata++ = mci_readq(host, DATA(host->data_offset)); + *pdata++ = mci_readq(host, DATA); buf = pdata; } if (cnt) { - host->part_buf = mci_readq(host, DATA(host->data_offset)); + host->part_buf = mci_readq(host, DATA); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1432,110 +1256,136 @@ static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) static void dw_mci_read_data_pio(struct dw_mci *host) { - struct sg_mapping_iter *sg_miter = &host->sg_miter; - void *buf; - unsigned int offset; + struct scatterlist *sg = host->sg; + void *buf = sg_virt(sg); + unsigned int offset = host->pio_offset; struct mmc_data *data = host->data; int shift = host->data_shift; u32 status; unsigned int nbytes = 0, len; - unsigned int remain, fcnt; do { - if (!sg_miter_next(sg_miter)) - goto done; - - host->sg = sg_miter->__sg; - buf = sg_miter->addr; - remain = sg_miter->length; - offset = 0; - - do { - fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) - << shift) + host->part_buf_count; - len = min(remain, fcnt); - if (!len) - break; + len = host->part_buf_count + + (SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift); + if (offset + len <= sg->length) { dw_mci_pull_data(host, (void *)(buf + offset), len); + offset += len; nbytes += len; - remain -= len; - } while (remain); - sg_miter->consumed = offset; + if (offset == sg->length) { + flush_dcache_page(sg_page(sg)); + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + + offset = 0; + buf = sg_virt(sg); + } + } else { + unsigned int remaining = sg->length - offset; + dw_mci_pull_data(host, (void *)(buf + offset), + remaining); + nbytes += remaining; + + flush_dcache_page(sg_page(sg)); + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + + offset = len - remaining; + buf = sg_virt(sg); + dw_mci_pull_data(host, buf, offset); + nbytes += offset; + } + status = mci_readl(host, MINTSTS); mci_writel(host, RINTSTS, SDMMC_INT_RXDR); + if (status & DW_MCI_DATA_ERROR_FLAGS) { + host->data_status = status; + data->bytes_xfered += nbytes; + smp_wmb(); + + set_bit(EVENT_DATA_ERROR, &host->pending_events); + + tasklet_schedule(&host->tasklet); + return; + } } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/ + host->pio_offset = offset; data->bytes_xfered += nbytes; - - if (!remain) { - if (!sg_miter_next(sg_miter)) - goto done; - sg_miter->consumed = 0; - } - sg_miter_stop(sg_miter); return; done: data->bytes_xfered += nbytes; - sg_miter_stop(sg_miter); - host->sg = NULL; smp_wmb(); set_bit(EVENT_XFER_COMPLETE, &host->pending_events); } static void dw_mci_write_data_pio(struct dw_mci *host) { - struct sg_mapping_iter *sg_miter = &host->sg_miter; - void *buf; - unsigned int offset; + struct scatterlist *sg = host->sg; + void *buf = sg_virt(sg); + unsigned int offset = host->pio_offset; struct mmc_data *data = host->data; int shift = host->data_shift; u32 status; unsigned int nbytes = 0, len; - unsigned int fifo_depth = host->fifo_depth; - unsigned int remain, fcnt; do { - if (!sg_miter_next(sg_miter)) - goto done; - - host->sg = sg_miter->__sg; - buf = sg_miter->addr; - remain = sg_miter->length; - offset = 0; - - do { - fcnt = ((fifo_depth - - SDMMC_GET_FCNT(mci_readl(host, STATUS))) - << shift) - host->part_buf_count; - len = min(remain, fcnt); - if (!len) - break; + len = ((host->fifo_depth - + SDMMC_GET_FCNT(mci_readl(host, STATUS))) << shift) + - host->part_buf_count; + if (offset + len <= sg->length) { host->push_data(host, (void *)(buf + offset), len); + offset += len; nbytes += len; - remain -= len; - } while (remain); + if (offset == sg->length) { + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + + offset = 0; + buf = sg_virt(sg); + } + } else { + unsigned int remaining = sg->length - offset; + + host->push_data(host, (void *)(buf + offset), + remaining); + nbytes += remaining; + + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + + offset = len - remaining; + buf = sg_virt(sg); + host->push_data(host, (void *)buf, offset); + nbytes += offset; + } - sg_miter->consumed = offset; status = mci_readl(host, MINTSTS); mci_writel(host, RINTSTS, SDMMC_INT_TXDR); + if (status & DW_MCI_DATA_ERROR_FLAGS) { + host->data_status = status; + data->bytes_xfered += nbytes; + + smp_wmb(); + + set_bit(EVENT_DATA_ERROR, &host->pending_events); + + tasklet_schedule(&host->tasklet); + return; + } } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ + host->pio_offset = offset; data->bytes_xfered += nbytes; - - if (!remain) { - if (!sg_miter_next(sg_miter)) - goto done; - sg_miter->consumed = 0; - } - sg_miter_stop(sg_miter); return; done: data->bytes_xfered += nbytes; - sg_miter_stop(sg_miter); - host->sg = NULL; smp_wmb(); set_bit(EVENT_XFER_COMPLETE, &host->pending_events); } @@ -1554,11 +1404,11 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) { struct dw_mci *host = dev_id; - u32 pending; + u32 status, pending; unsigned int pass_count = 0; - int i; do { + status = mci_readl(host, RINTSTS); pending = mci_readl(host, MINTSTS); /* read-only mask reg */ /* @@ -1576,7 +1426,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & DW_MCI_CMD_ERROR_FLAGS) { mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); - host->cmd_status = pending; + host->cmd_status = status; smp_wmb(); set_bit(EVENT_CMD_COMPLETE, &host->pending_events); } @@ -1584,16 +1434,18 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & DW_MCI_DATA_ERROR_FLAGS) { /* if there is an error report DATA_ERROR */ mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); - host->data_status = pending; + host->data_status = status; smp_wmb(); set_bit(EVENT_DATA_ERROR, &host->pending_events); - tasklet_schedule(&host->tasklet); + if (!(pending & (SDMMC_INT_DTO | SDMMC_INT_DCRC | + SDMMC_INT_SBE | SDMMC_INT_EBE))) + tasklet_schedule(&host->tasklet); } if (pending & SDMMC_INT_DATA_OVER) { mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); if (!host->data_status) - host->data_status = pending; + host->data_status = status; smp_wmb(); if (host->dir_status == DW_MCI_RECV_STATUS) { if (host->sg != NULL) @@ -1617,21 +1469,12 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & SDMMC_INT_CMD_DONE) { mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); - dw_mci_cmd_interrupt(host, pending); + dw_mci_cmd_interrupt(host, status); } if (pending & SDMMC_INT_CD) { mci_writel(host, RINTSTS, SDMMC_INT_CD); - queue_work(host->card_workqueue, &host->card_work); - } - - /* Handle SDIO Interrupts */ - for (i = 0; i < host->num_slots; i++) { - struct dw_mci_slot *slot = host->slot[i]; - if (pending & SDMMC_INT_SDIO(i)) { - mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i)); - mmc_signal_sdio_irq(slot->mmc); - } + queue_work(dw_mci_card_workqueue, &host->card_work); } } while (pass_count++ < 5); @@ -1642,6 +1485,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); + set_bit(EVENT_DATA_COMPLETE, &host->pending_events); host->dma_ops->complete(host); } #endif @@ -1734,7 +1578,6 @@ static void dw_mci_work_routine_card(struct work_struct *work) * block interrupt, hence setting the * scatter-gather pointer to NULL. */ - sg_miter_stop(&host->sg_miter); host->sg = NULL; ctrl = mci_readl(host, CTRL); @@ -1743,8 +1586,7 @@ static void dw_mci_work_routine_card(struct work_struct *work) #ifdef CONFIG_MMC_DW_IDMAC ctrl = mci_readl(host, BMOD); - /* Software reset of DMA */ - ctrl |= SDMMC_IDMAC_SWRESET; + ctrl |= 0x01; /* Software reset of DMA */ mci_writel(host, BMOD, ctrl); #endif @@ -1764,61 +1606,12 @@ static void dw_mci_work_routine_card(struct work_struct *work) } } -#ifdef CONFIG_OF -/* given a slot id, find out the device node representing that slot */ -static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) -{ - struct device_node *np; - const __be32 *addr; - int len; - - if (!dev || !dev->of_node) - return NULL; - - for_each_child_of_node(dev->of_node, np) { - addr = of_get_property(np, "reg", &len); - if (!addr || (len < sizeof(int))) - continue; - if (be32_to_cpup(addr) == slot) - return np; - } - return NULL; -} - -/* find out bus-width for a given slot */ -static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot) -{ - struct device_node *np = dw_mci_of_find_slot_node(dev, slot); - u32 bus_wd = 1; - - if (!np) - return 1; - - if (of_property_read_u32(np, "bus-width", &bus_wd)) - dev_err(dev, "bus-width property not found, assuming width" - " as 1\n"); - return bus_wd; -} -#else /* CONFIG_OF */ -static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot) -{ - return 1; -} -static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) -{ - return NULL; -} -#endif /* CONFIG_OF */ - -static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) +static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) { struct mmc_host *mmc; struct dw_mci_slot *slot; - const struct dw_mci_drv_data *drv_data = host->drv_data; - int ctrl_id, ret; - u8 bus_width; - mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); + mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->pdev->dev); if (!mmc) return -ENOMEM; @@ -1826,7 +1619,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) slot->id = id; slot->mmc = mmc; slot->host = host; - host->slot[id] = slot; mmc->ops = &dw_mci_ops; mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510); @@ -1846,48 +1638,23 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (host->pdata->caps) mmc->caps = host->pdata->caps; - - if (host->pdata->pm_caps) - mmc->pm_caps = host->pdata->pm_caps; - - if (host->dev->of_node) { - ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); - if (ctrl_id < 0) - ctrl_id = 0; - } else { - ctrl_id = to_platform_device(host->dev)->id; - } - if (drv_data && drv_data->caps) - mmc->caps |= drv_data->caps[ctrl_id]; - - if (host->pdata->caps2) - mmc->caps2 = host->pdata->caps2; - - if (host->pdata->get_bus_wd) - bus_width = host->pdata->get_bus_wd(slot->id); - else if (host->dev->of_node) - bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id); else - bus_width = 1; - - if (drv_data && drv_data->setup_bus) { - struct device_node *slot_np; - slot_np = dw_mci_of_find_slot_node(host->dev, slot->id); - ret = drv_data->setup_bus(host, slot_np, bus_width); - if (ret) - goto err_setup_bus; - } + mmc->caps = 0; - switch (bus_width) { - case 8: - mmc->caps |= MMC_CAP_8_BIT_DATA; - case 4: - mmc->caps |= MMC_CAP_4_BIT_DATA; - } + if (host->pdata->get_bus_wd) + if (host->pdata->get_bus_wd(slot->id) >= 4) + mmc->caps |= MMC_CAP_4_BIT_DATA; if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED) mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; +#ifdef CONFIG_MMC_DW_IDMAC + mmc->max_segs = host->ring_size; + mmc->max_blk_size = 65536; + mmc->max_blk_count = host->ring_size; + mmc->max_seg_size = 0x1000; + mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count; +#else if (host->pdata->blk_settings) { mmc->max_segs = host->pdata->blk_settings->max_segs; mmc->max_blk_size = host->pdata->blk_settings->max_blk_size; @@ -1896,24 +1663,17 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) mmc->max_seg_size = host->pdata->blk_settings->max_seg_size; } else { /* Useful defaults if platform data is unset. */ -#ifdef CONFIG_MMC_DW_IDMAC - mmc->max_segs = host->ring_size; - mmc->max_blk_size = 65536; - mmc->max_blk_count = host->ring_size; - mmc->max_seg_size = 0x1000; - mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count; -#else mmc->max_segs = 64; mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ mmc->max_blk_count = 512; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; -#endif /* CONFIG_MMC_DW_IDMAC */ } +#endif /* CONFIG_MMC_DW_IDMAC */ - host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc"); + host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); if (IS_ERR(host->vmmc)) { - pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); + printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); host->vmmc = NULL; } else regulator_enable(host->vmmc); @@ -1923,6 +1683,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) else clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); + host->slot[id] = slot; mmc_add_host(mmc); #if defined(CONFIG_DEBUG_FS) @@ -1936,13 +1697,9 @@ static int 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(host->card_workqueue, &host->card_work); + queue_work(dw_mci_card_workqueue, &host->card_work); return 0; - -err_setup_bus: - mmc_free_host(mmc); - return -EINVAL; } static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) @@ -1960,10 +1717,10 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) static void dw_mci_init_dma(struct dw_mci *host) { /* Alloc memory for sg translation */ - host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, + host->sg_cpu = dma_alloc_coherent(&host->pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); if (!host->sg_cpu) { - dev_err(host->dev, "%s: could not alloc DMA memory\n", + dev_err(&host->pdev->dev, "%s: could not alloc DMA memory\n", __func__); goto no_dma; } @@ -1971,21 +1728,20 @@ static void dw_mci_init_dma(struct dw_mci *host) /* Determine which DMA interface to use */ #ifdef CONFIG_MMC_DW_IDMAC host->dma_ops = &dw_mci_idmac_ops; - dev_info(host->dev, "Using internal DMA controller.\n"); + dev_info(&host->pdev->dev, "Using internal DMA controller.\n"); #endif if (!host->dma_ops) goto no_dma; - if (host->dma_ops->init && host->dma_ops->start && - host->dma_ops->stop && host->dma_ops->cleanup) { + if (host->dma_ops->init) { if (host->dma_ops->init(host)) { - dev_err(host->dev, "%s: Unable to initialize " + dev_err(&host->pdev->dev, "%s: Unable to initialize " "DMA Controller.\n", __func__); goto no_dma; } } else { - dev_err(host->dev, "DMA initialization not found.\n"); + dev_err(&host->pdev->dev, "DMA initialization not found.\n"); goto no_dma; } @@ -1993,7 +1749,7 @@ static void dw_mci_init_dma(struct dw_mci *host) return; no_dma: - dev_info(host->dev, "Using PIO mode.\n"); + dev_info(&host->pdev->dev, "Using PIO mode.\n"); host->use_dma = 0; return; } @@ -2019,144 +1775,63 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host) return false; } -#ifdef CONFIG_OF -static struct dw_mci_of_quirks { - char *quirk; - int id; -} of_quirks[] = { - { - .quirk = "supports-highspeed", - .id = DW_MCI_QUIRK_HIGHSPEED, - }, { - .quirk = "broken-cd", - .id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION, - }, -}; - -static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) +static int dw_mci_probe(struct platform_device *pdev) { + struct dw_mci *host; + struct resource *regs; struct dw_mci_board *pdata; - struct device *dev = host->dev; - struct device_node *np = dev->of_node; - const struct dw_mci_drv_data *drv_data = host->drv_data; - int idx, ret; - - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(dev, "could not allocate memory for pdata\n"); - return ERR_PTR(-ENOMEM); - } - - /* find out number of slots supported */ - if (of_property_read_u32(dev->of_node, "num-slots", - &pdata->num_slots)) { - dev_info(dev, "num-slots property not found, " - "assuming 1 slot is available\n"); - pdata->num_slots = 1; - } - - /* get quirks */ - for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++) - if (of_get_property(np, of_quirks[idx].quirk, NULL)) - pdata->quirks |= of_quirks[idx].id; - - if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) - dev_info(dev, "fifo-depth property not found, using " - "value of FIFOTH register as default\n"); - - of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); - - if (drv_data && drv_data->parse_dt) { - ret = drv_data->parse_dt(host); - if (ret) - return ERR_PTR(ret); - } - - if (of_find_property(np, "keep-power-in-suspend", NULL)) - pdata->pm_caps |= MMC_PM_KEEP_POWER; - - if (of_find_property(np, "enable-sdio-wakeup", NULL)) - pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; - - return pdata; -} - -#else /* CONFIG_OF */ -static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) -{ - return ERR_PTR(-EINVAL); -} -#endif /* CONFIG_OF */ - -int dw_mci_probe(struct dw_mci *host) -{ - const struct dw_mci_drv_data *drv_data = host->drv_data; - int width, i, ret = 0; + int irq, ret, i, width; u32 fifo_size; - int init_slots = 0; - if (!host->pdata) { - host->pdata = dw_mci_parse_dt(host); - if (IS_ERR(host->pdata)) { - dev_err(host->dev, "platform data not available\n"); - return -EINVAL; - } - } + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -ENXIO; - if (!host->pdata->select_slot && host->pdata->num_slots > 1) { - dev_err(host->dev, - "Platform data must supply select_slot function\n"); - return -ENODEV; - } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; - host->biu_clk = devm_clk_get(host->dev, "biu"); - if (IS_ERR(host->biu_clk)) { - dev_dbg(host->dev, "biu clock not available\n"); - } else { - ret = clk_prepare_enable(host->biu_clk); - if (ret) { - dev_err(host->dev, "failed to enable biu clock\n"); - return ret; - } - } + host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL); + if (!host) + return -ENOMEM; - host->ciu_clk = devm_clk_get(host->dev, "ciu"); - if (IS_ERR(host->ciu_clk)) { - dev_dbg(host->dev, "ciu clock not available\n"); - } else { - ret = clk_prepare_enable(host->ciu_clk); - if (ret) { - dev_err(host->dev, "failed to enable ciu clock\n"); - goto err_clk_biu; - } + host->pdev = pdev; + host->pdata = pdata = pdev->dev.platform_data; + if (!pdata || !pdata->init) { + dev_err(&pdev->dev, + "Platform data must supply init function\n"); + ret = -ENODEV; + goto err_freehost; } - if (IS_ERR(host->ciu_clk)) - host->bus_hz = host->pdata->bus_hz; - else - host->bus_hz = clk_get_rate(host->ciu_clk); - - if (drv_data && drv_data->setup_clock) { - ret = drv_data->setup_clock(host); - if (ret) { - dev_err(host->dev, - "implementation specific clock setup failed\n"); - goto err_clk_ciu; - } + if (!pdata->select_slot && pdata->num_slots > 1) { + dev_err(&pdev->dev, + "Platform data must supply select_slot function\n"); + ret = -ENODEV; + goto err_freehost; } - if (!host->bus_hz) { - dev_err(host->dev, + if (!pdata->bus_hz) { + dev_err(&pdev->dev, "Platform data must supply bus speed\n"); ret = -ENODEV; - goto err_clk_ciu; + goto err_freehost; } - host->quirks = host->pdata->quirks; + host->bus_hz = pdata->bus_hz; + host->quirks = pdata->quirks; spin_lock_init(&host->lock); INIT_LIST_HEAD(&host->queue); + ret = -ENOMEM; + host->regs = ioremap(regs->start, resource_size(regs)); + if (!host->regs) + goto err_freehost; + + host->dma_ops = pdata->dma_ops; + dw_mci_init_dma(host); + /* * Get the host data width - this assumes that HCON has been set with * the correct values. @@ -2184,11 +1859,10 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!mci_wait_reset(host->dev, host)) - return -ENODEV; - - host->dma_ops = host->pdata->dma_ops; - dw_mci_init_dma(host); + if (!mci_wait_reset(&pdev->dev, host)) { + ret = -ENODEV; + goto err_dmaunmap; + } /* Clear the interrupts for the host controller */ mci_writel(host, RINTSTS, 0xFFFFFFFF); @@ -2209,7 +1883,7 @@ int dw_mci_probe(struct dw_mci *host) * should put it in the platform data. */ fifo_size = mci_readl(host, FIFOTH); - fifo_size = 1 + ((fifo_size >> 16) & 0xfff); + fifo_size = 1 + ((fifo_size >> 16) & 0x7ff); } else { fifo_size = host->pdata->fifo_depth; } @@ -2223,21 +1897,32 @@ int dw_mci_probe(struct dw_mci *host) mci_writel(host, CLKSRC, 0); tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); - host->card_workqueue = alloc_workqueue("dw-mci-card", + dw_mci_card_workqueue = alloc_workqueue("dw-mci-card", WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1); - if (!host->card_workqueue) + if (!dw_mci_card_workqueue) goto err_dmaunmap; INIT_WORK(&host->card_work, dw_mci_work_routine_card); - ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, - host->irq_flags, "dw-mci", host); + + ret = request_irq(irq, dw_mci_interrupt, 0, "dw-mci", host); if (ret) goto err_workqueue; + platform_set_drvdata(pdev, host); + if (host->pdata->num_slots) host->num_slots = host->pdata->num_slots; else host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; + /* We need at least one slot to succeed */ + for (i = 0; i < host->num_slots; i++) { + ret = dw_mci_init_slot(host, i); + if (ret) { + ret = -ENODEV; + goto err_init_slot; + } + } + /* * Enable interrupts for command done, data over, data empty, card det, * receive ready and error such as transmit, receive timeout, crc error @@ -2248,76 +1933,57 @@ int dw_mci_probe(struct dw_mci *host) DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ - dev_info(host->dev, "DW MMC controller at irq %d, " + dev_info(&pdev->dev, "DW MMC controller at irq %d, " "%d bit host data width, " "%u deep fifo\n", - host->irq, width, fifo_size); - - /* We need at least one slot to succeed */ - for (i = 0; i < host->num_slots; i++) { - ret = dw_mci_init_slot(host, i); - if (ret) - dev_dbg(host->dev, "slot %d init failed\n", i); - else - init_slots++; - } - - if (init_slots) { - dev_info(host->dev, "%d slots initialized\n", init_slots); - } else { - dev_dbg(host->dev, "attempted to initialize %d slots, " - "but failed on all\n", host->num_slots); - goto err_workqueue; - } - - /* - * In 2.40a spec, Data offset is changed. - * Need to check the version-id and set data-offset for DATA register. - */ - host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); - dev_info(host->dev, "Version ID is %04x\n", host->verid); - - if (host->verid < DW_MMC_240A) - host->data_offset = DATA_OFFSET; - else - host->data_offset = DATA_240A_OFFSET; - + irq, width, fifo_size); if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) - dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); + dev_info(&pdev->dev, "Internal DMAC interrupt fix enabled.\n"); return 0; +err_init_slot: + /* De-init any initialized slots */ + while (i > 0) { + if (host->slot[i]) + dw_mci_cleanup_slot(host->slot[i], i); + i--; + } + free_irq(irq, host); + err_workqueue: - destroy_workqueue(host->card_workqueue); + destroy_workqueue(dw_mci_card_workqueue); err_dmaunmap: if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); + dma_free_coherent(&host->pdev->dev, PAGE_SIZE, + host->sg_cpu, host->sg_dma); + iounmap(host->regs); - if (host->vmmc) + if (host->vmmc) { regulator_disable(host->vmmc); + regulator_put(host->vmmc); + } -err_clk_ciu: - if (!IS_ERR(host->ciu_clk)) - clk_disable_unprepare(host->ciu_clk); - -err_clk_biu: - if (!IS_ERR(host->biu_clk)) - clk_disable_unprepare(host->biu_clk); +err_freehost: + kfree(host); return ret; } -EXPORT_SYMBOL(dw_mci_probe); -void dw_mci_remove(struct dw_mci *host) +static int __exit dw_mci_remove(struct platform_device *pdev) { + struct dw_mci *host = platform_get_drvdata(pdev); int i; mci_writel(host, RINTSTS, 0xFFFFFFFF); mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ + platform_set_drvdata(pdev, NULL); + for (i = 0; i < host->num_slots; i++) { - dev_dbg(host->dev, "remove slot %d\n", i); + dev_dbg(&pdev->dev, "remove slot %d\n", i); if (host->slot[i]) dw_mci_cleanup_slot(host->slot[i], i); } @@ -2326,31 +1992,32 @@ void dw_mci_remove(struct dw_mci *host) mci_writel(host, CLKENA, 0); mci_writel(host, CLKSRC, 0); - destroy_workqueue(host->card_workqueue); + free_irq(platform_get_irq(pdev, 0), host); + destroy_workqueue(dw_mci_card_workqueue); + dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); - if (host->vmmc) + if (host->vmmc) { regulator_disable(host->vmmc); + regulator_put(host->vmmc); + } - if (!IS_ERR(host->ciu_clk)) - clk_disable_unprepare(host->ciu_clk); + iounmap(host->regs); - if (!IS_ERR(host->biu_clk)) - clk_disable_unprepare(host->biu_clk); + kfree(host); + return 0; } -EXPORT_SYMBOL(dw_mci_remove); - - -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM /* * TODO: we should probably disable the clock to the card in the suspend path. */ -int dw_mci_suspend(struct dw_mci *host) +static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg) { - int i, ret = 0; + int i, ret; + struct dw_mci *host = platform_get_drvdata(pdev); for (i = 0; i < host->num_slots; i++) { struct dw_mci_slot *slot = host->slot[i]; @@ -2372,23 +2039,23 @@ int dw_mci_suspend(struct dw_mci *host) return 0; } -EXPORT_SYMBOL(dw_mci_suspend); -int dw_mci_resume(struct dw_mci *host) +static int dw_mci_resume(struct platform_device *pdev) { int i, ret; + struct dw_mci *host = platform_get_drvdata(pdev); if (host->vmmc) regulator_enable(host->vmmc); - if (!mci_wait_reset(host->dev, host)) { + if (host->dma_ops->init) + host->dma_ops->init(host); + + if (!mci_wait_reset(&pdev->dev, host)) { ret = -ENODEV; return ret; } - if (host->use_dma && host->dma_ops->init) - host->dma_ops->init(host); - /* Restore the old value at FIFOTH register */ mci_writel(host, FIFOTH, host->fifoth_val); @@ -2402,28 +2069,35 @@ int dw_mci_resume(struct dw_mci *host) struct dw_mci_slot *slot = host->slot[i]; if (!slot) continue; - if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { - dw_mci_set_ios(slot->mmc, &slot->mmc->ios); - dw_mci_setup_bus(slot, true); - } - ret = mmc_resume_host(host->slot[i]->mmc); if (ret < 0) return ret; } + return 0; } -EXPORT_SYMBOL(dw_mci_resume); -#endif /* CONFIG_PM_SLEEP */ +#else +#define dw_mci_suspend NULL +#define dw_mci_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver dw_mci_driver = { + .remove = __exit_p(dw_mci_remove), + .suspend = dw_mci_suspend, + .resume = dw_mci_resume, + .driver = { + .name = "dw_mmc", + }, +}; static int __init dw_mci_init(void) { - printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver"); - return 0; + return platform_driver_probe(&dw_mci_driver, dw_mci_probe); } static void __exit dw_mci_exit(void) { + platform_driver_unregister(&dw_mci_driver); } module_init(dw_mci_init); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 53b8fd987e4..027d3773539 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -14,8 +14,6 @@ #ifndef _DW_MMC_H_ #define _DW_MMC_H_ -#define DW_MMC_240A 0x240a - #define SDMMC_CTRL 0x000 #define SDMMC_PWREN 0x004 #define SDMMC_CLKDIV 0x008 @@ -53,14 +51,7 @@ #define SDMMC_IDINTEN 0x090 #define SDMMC_DSCADDR 0x094 #define SDMMC_BUFADDR 0x098 -#define SDMMC_DATA(x) (x) - -/* - * Data offset is difference according to Version - * Lower than 2.40a : data register offest is 0x100 - */ -#define DATA_OFFSET 0x100 -#define DATA_240A_OFFSET 0x200 +#define SDMMC_DATA 0x100 /* shift bit field */ #define _SBF(f, v) ((v) << (f)) @@ -91,7 +82,7 @@ #define SDMMC_CTYPE_4BIT BIT(0) #define SDMMC_CTYPE_1BIT 0 /* Interrupt status & mask register defines */ -#define SDMMC_INT_SDIO(n) BIT(16 + (n)) +#define SDMMC_INT_SDIO BIT(16) #define SDMMC_INT_EBE BIT(15) #define SDMMC_INT_ACD BIT(14) #define SDMMC_INT_SBE BIT(13) @@ -126,7 +117,7 @@ #define SDMMC_CMD_RESP_EXP BIT(6) #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ -#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FF) /* Internal DMAC interrupt defines */ #define SDMMC_IDMAC_INT_AI BIT(9) #define SDMMC_IDMAC_INT_NI BIT(8) @@ -139,8 +130,6 @@ #define SDMMC_IDMAC_ENABLE BIT(7) #define SDMMC_IDMAC_FB BIT(1) #define SDMMC_IDMAC_SWRESET BIT(0) -/* Version ID register define */ -#define SDMMC_GET_VERID(x) ((x) & 0xFFFF) /* Register access macros */ #define mci_readl(dev, reg) \ @@ -175,35 +164,4 @@ (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value)) #endif -extern int dw_mci_probe(struct dw_mci *host); -extern void dw_mci_remove(struct dw_mci *host); -#ifdef CONFIG_PM -extern int dw_mci_suspend(struct dw_mci *host); -extern int dw_mci_resume(struct dw_mci *host); -#endif - -/** - * dw_mci driver data - dw-mshc implementation specific driver data. - * @caps: mmc subsystem specified capabilities of the controller(s). - * @init: early implementation specific initialization. - * @setup_clock: implementation specific clock configuration. - * @prepare_command: handle CMD register extensions. - * @set_ios: handle bus specific extensions. - * @parse_dt: parse implementation specific device tree properties. - * @setup_bus: initialize io-interface - * - * Provide controller implementation specific extensions. The usage of this - * data structure is fully optional and usage of each member in this structure - * is optional as well. - */ -struct dw_mci_drv_data { - unsigned long *caps; - int (*init)(struct dw_mci *host); - int (*setup_clock)(struct dw_mci *host); - void (*prepare_command)(struct dw_mci *host, u32 *cmdr); - void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); - int (*parse_dt)(struct dw_mci *host); - int (*setup_bus)(struct dw_mci *host, - struct device_node *slot_np, u8 bus_width); -}; #endif /* _DW_MMC_H_ */ diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 2391c6b7a4b..74218ad677e 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -702,7 +702,7 @@ static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = { JZ_GPIO_BULK_PIN(MSC_DATA3), }; -static int jz4740_mmc_request_gpio(struct device *dev, int gpio, +static int __devinit jz4740_mmc_request_gpio(struct device *dev, int gpio, const char *name, bool output, int value) { int ret; @@ -724,7 +724,7 @@ static int jz4740_mmc_request_gpio(struct device *dev, int gpio, return 0; } -static int jz4740_mmc_request_gpios(struct platform_device *pdev) +static int __devinit jz4740_mmc_request_gpios(struct platform_device *pdev) { int ret; struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; @@ -759,7 +759,7 @@ err: return ret; } -static int jz4740_mmc_request_cd_irq(struct platform_device *pdev, +static int __devinit jz4740_mmc_request_cd_irq(struct platform_device *pdev, struct jz4740_mmc_host *host) { struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; @@ -802,7 +802,7 @@ static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host) return num_pins; } -static int jz4740_mmc_probe(struct platform_device* pdev) +static int __devinit jz4740_mmc_probe(struct platform_device* pdev) { int ret; struct mmc_host *mmc; @@ -938,7 +938,7 @@ err_free_host: return ret; } -static int jz4740_mmc_remove(struct platform_device *pdev) +static int __devexit jz4740_mmc_remove(struct platform_device *pdev) { struct jz4740_mmc_host *host = platform_get_drvdata(pdev); @@ -1004,7 +1004,7 @@ const struct dev_pm_ops jz4740_mmc_pm_ops = { static struct platform_driver jz4740_mmc_driver = { .probe = jz4740_mmc_probe, - .remove = jz4740_mmc_remove, + .remove = __devexit_p(jz4740_mmc_remove), .driver = { .name = "jz4740-mmc", .owner = THIS_MODULE, @@ -1012,7 +1012,17 @@ static struct platform_driver jz4740_mmc_driver = { }, }; -module_platform_driver(jz4740_mmc_driver); +static int __init jz4740_mmc_init(void) +{ + return platform_driver_register(&jz4740_mmc_driver); +} +module_init(jz4740_mmc_init); + +static void __exit jz4740_mmc_exit(void) +{ + platform_driver_unregister(&jz4740_mmc_driver); +} +module_exit(jz4740_mmc_exit); MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 74145d1d51f..7c1e16aaf17 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -1485,7 +1484,7 @@ nomem: } -static int mmc_spi_remove(struct spi_device *spi) +static int __devexit mmc_spi_remove(struct spi_device *spi) { struct mmc_host *mmc = dev_get_drvdata(&spi->dev); struct mmc_spi_host *host; @@ -1517,7 +1516,7 @@ static int mmc_spi_remove(struct spi_device *spi) return 0; } -static struct of_device_id mmc_spi_of_match_table[] = { +static struct of_device_id mmc_spi_of_match_table[] __devinitdata = { { .compatible = "mmc-spi-slot", }, {}, }; @@ -1525,14 +1524,28 @@ static struct of_device_id mmc_spi_of_match_table[] = { static struct spi_driver mmc_spi_driver = { .driver = { .name = "mmc_spi", + .bus = &spi_bus_type, .owner = THIS_MODULE, .of_match_table = mmc_spi_of_match_table, }, .probe = mmc_spi_probe, - .remove = mmc_spi_remove, + .remove = __devexit_p(mmc_spi_remove), }; -module_spi_driver(mmc_spi_driver); + +static int __init mmc_spi_init(void) +{ + return spi_register_driver(&mmc_spi_driver); +} +module_init(mmc_spi_init); + + +static void __exit mmc_spi_exit(void) +{ + spi_unregister_driver(&mmc_spi_driver); +} +module_exit(mmc_spi_exit); + MODULE_AUTHOR("Mike Lavender, David Brownell, " "Hans-Peter Nilsson, Jan Nikitenko"); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 150772395cc..d8eac248ee4 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -26,14 +25,10 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include #include #include @@ -57,8 +52,6 @@ static unsigned int fmax = 515633; * @sdio: variant supports SDIO * @st_clkdiv: true if using a ST-specific clock divider algorithm * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register - * @pwrreg_powerup: power up value for MMCIPOWER register - * @signal_direction: input/out direction of bus signals can be indicated */ struct variant_data { unsigned int clkreg; @@ -69,22 +62,18 @@ struct variant_data { bool sdio; bool st_clkdiv; bool blksz_datactrl16; - u32 pwrreg_powerup; - bool signal_direction; }; static struct variant_data variant_arm = { .fifosize = 16 * 4, .fifohalfsize = 8 * 4, .datalength_bits = 16, - .pwrreg_powerup = MCI_PWR_UP, }; static struct variant_data variant_arm_extended_fifo = { .fifosize = 128 * 4, .fifohalfsize = 64 * 4, .datalength_bits = 16, - .pwrreg_powerup = MCI_PWR_UP, }; static struct variant_data variant_u300 = { @@ -93,19 +82,6 @@ static struct variant_data variant_u300 = { .clkreg_enable = MCI_ST_U300_HWFCEN, .datalength_bits = 16, .sdio = true, - .pwrreg_powerup = MCI_PWR_ON, - .signal_direction = true, -}; - -static struct variant_data variant_nomadik = { - .fifosize = 16 * 4, - .fifohalfsize = 8 * 4, - .clkreg = MCI_CLK_ENABLE, - .datalength_bits = 24, - .sdio = true, - .st_clkdiv = true, - .pwrreg_powerup = MCI_PWR_ON, - .signal_direction = true, }; static struct variant_data variant_ux500 = { @@ -116,8 +92,6 @@ static struct variant_data variant_ux500 = { .datalength_bits = 24, .sdio = true, .st_clkdiv = true, - .pwrreg_powerup = MCI_PWR_ON, - .signal_direction = true, }; static struct variant_data variant_ux500v2 = { @@ -129,32 +103,8 @@ static struct variant_data variant_ux500v2 = { .sdio = true, .st_clkdiv = true, .blksz_datactrl16 = true, - .pwrreg_powerup = MCI_PWR_ON, - .signal_direction = true, }; -/* - * This must be called with host->lock held - */ -static void mmci_write_clkreg(struct mmci_host *host, u32 clk) -{ - if (host->clk_reg != clk) { - host->clk_reg = clk; - writel(clk, host->base + MMCICLOCK); - } -} - -/* - * This must be called with host->lock held - */ -static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) -{ - if (host->pwr_reg != pwr) { - host->pwr_reg = pwr; - writel(pwr, host->base + MMCIPOWER); - } -} - /* * This must be called with host->lock held */ @@ -202,7 +152,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) clk |= MCI_ST_8BIT_BUS; - mmci_write_clkreg(host, clk); + writel(clk, host->base + MMCICLOCK); } static void @@ -215,10 +165,13 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) host->mrq = NULL; host->cmd = NULL; + /* + * Need to drop the host lock here; mmc_request_done may call + * back into the driver... + */ + spin_unlock(&host->lock); mmc_request_done(host->mmc, mrq); - - pm_runtime_mark_last_busy(mmc_dev(host->mmc)); - pm_runtime_put_autosuspend(mmc_dev(host->mmc)); + spin_lock(&host->lock); } static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) @@ -262,7 +215,7 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) * no custom DMA interfaces are supported. */ #ifdef CONFIG_DMA_ENGINE -static void mmci_dma_setup(struct mmci_host *host) +static void __devinit mmci_dma_setup(struct mmci_host *host) { struct mmci_platform_data *plat = host->plat; const char *rxname, *txname; @@ -338,7 +291,7 @@ static void mmci_dma_setup(struct mmci_host *host) } /* - * This is used in or so inline it + * This is used in __devinit or __devexit so inline it * so it can be discarded. */ static inline void mmci_dma_release(struct mmci_host *host) @@ -415,12 +368,10 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, .src_maxburst = variant->fifohalfsize >> 2, /* # of words */ .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */ - .device_fc = false, }; struct dma_chan *chan; struct dma_device *device; struct dma_async_tx_descriptor *desc; - enum dma_data_direction buffer_dirn; int nr_sg; /* Check if next job is already prepared */ @@ -434,12 +385,10 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, } if (data->flags & MMC_DATA_READ) { - conf.direction = DMA_DEV_TO_MEM; - buffer_dirn = DMA_FROM_DEVICE; + conf.direction = DMA_FROM_DEVICE; chan = host->dma_rx_channel; } else { - conf.direction = DMA_MEM_TO_DEV; - buffer_dirn = DMA_TO_DEVICE; + conf.direction = DMA_TO_DEVICE; chan = host->dma_tx_channel; } @@ -452,12 +401,12 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, return -EINVAL; device = chan->device; - nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, buffer_dirn); + nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, conf.direction); if (nr_sg == 0) return -EINVAL; dmaengine_slave_config(chan, &conf); - desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg, + desc = device->device_prep_slave_sg(chan, data->sg, nr_sg, conf.direction, DMA_CTRL_ACK); if (!desc) goto unmap_exit; @@ -475,7 +424,7 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, unmap_exit: if (!next) dmaengine_terminate_all(chan); - dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn); + dma_unmap_sg(device->dev, data->sg, data->sg_len, conf.direction); return -ENOMEM; } @@ -515,7 +464,7 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) struct mmci_host_next *next = &host->next_data; if (data->host_cookie && data->host_cookie != next->cookie) { - pr_warning("[%s] invalid cookie: data->host_cookie %d" + printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d" " host->next_data.cookie %d\n", __func__, data->host_cookie, host->next_data.cookie); data->host_cookie = 0; @@ -580,7 +529,7 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, if (chan) { if (err) dmaengine_terminate_all(chan); - if (data->host_cookie) + if (err || data->host_cookie) dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, dir); mrq->data->host_cookie = 0; @@ -653,33 +602,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; - /* The ST Micro variants has a special bit to enable SDIO */ - if (variant->sdio && host->mmc->card) - if (mmc_card_sdio(host->mmc->card)) { - /* - * The ST Micro variants has a special bit - * to enable SDIO. - */ - u32 clk; - - datactrl |= MCI_ST_DPSM_SDIOEN; - - /* - * The ST Micro variant for SDIO small write transfers - * needs to have clock H/W flow control disabled, - * otherwise the transfer will not start. The threshold - * depends on the rate of MCLK. - */ - if (data->flags & MMC_DATA_WRITE && - (host->size < 8 || - (host->size <= 8 && host->mclk > 50000000))) - clk = host->clk_reg & ~variant->clkreg_enable; - else - clk = host->clk_reg | variant->clkreg_enable; - - mmci_write_clkreg(host, clk); - } - /* * Attempt to use DMA operation mode, if this * should fail, fall back to PIO mode @@ -708,6 +630,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) irqmask = MCI_TXFIFOHALFEMPTYMASK; } + /* The ST Micro variants has a special bit to enable SDIO */ + if (variant->sdio && host->mmc->card) + if (mmc_card_sdio(host->mmc->card)) + datactrl |= MCI_ST_DPSM_SDIOEN; + writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); mmci_set_mask1(host, irqmask); @@ -854,24 +781,7 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema if (count <= 0) break; - /* - * SDIO especially may want to send something that is - * not divisible by 4 (as opposed to card sectors - * etc). Therefore make sure to always read the last bytes - * while only doing full 32-bit reads towards the FIFO. - */ - if (unlikely(count & 0x3)) { - if (count < 4) { - unsigned char buf[4]; - ioread32_rep(base + MMCIFIFO, buf, 1); - memcpy(ptr, buf, count); - } else { - ioread32_rep(base + MMCIFIFO, ptr, count >> 2); - count &= ~0x3; - } - } else { - ioread32_rep(base + MMCIFIFO, ptr, count >> 2); - } + readsl(base + MMCIFIFO, ptr, count >> 2); ptr += count; remain -= count; @@ -899,6 +809,23 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem variant->fifosize : variant->fifohalfsize; count = min(remain, maxcnt); + /* + * The ST Micro variant for SDIO transfer sizes + * less then 8 bytes should have clock H/W flow + * control disabled. + */ + if (variant->sdio && + mmc_card_sdio(host->mmc->card)) { + if (count < 8) + writel(readl(host->base + MMCICLOCK) & + ~variant->clkreg_enable, + host->base + MMCICLOCK); + else + writel(readl(host->base + MMCICLOCK) | + variant->clkreg_enable, + host->base + MMCICLOCK); + } + /* * SDIO especially may want to send something that is * not divisible by 4 (as opposed to card sectors @@ -907,7 +834,7 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem * byte become a 32bit write, 7 bytes will be two * 32bit writes etc. */ - iowrite32_rep(base + MMCIFIFO, ptr, (count + 3) >> 2); + writesl(base + MMCIFIFO, ptr, (count + 3) >> 2); ptr += count; remain -= count; @@ -1063,8 +990,6 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) return; } - pm_runtime_get_sync(mmc_dev(mmc)); - spin_lock_irqsave(&host->lock, flags); host->mrq = mrq; @@ -1083,17 +1008,10 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmci_host *host = mmc_priv(mmc); - struct variant_data *variant = host->variant; u32 pwr = 0; unsigned long flags; int ret; - pm_runtime_get_sync(mmc_dev(mmc)); - - if (host->plat->ios_handler && - host->plat->ios_handler(mmc_dev(mmc), ios)) - dev_err(mmc_dev(mmc), "platform ios_handler failed\n"); - switch (ios->power_mode) { case MMC_POWER_OFF: if (host->vcc) @@ -1110,38 +1028,22 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) * power should be rare so we print an error * and return here. */ - goto out; + return; } } - /* - * The ST Micro variant doesn't have the PL180s MCI_PWR_UP - * and instead uses MCI_PWR_ON so apply whatever value is - * configured in the variant data. - */ - pwr |= variant->pwrreg_powerup; - - break; + if (host->plat->vdd_handler) + pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd, + ios->power_mode); + /* The ST version does not have this, fall through to POWER_ON */ + if (host->hw_designer != AMBA_VENDOR_ST) { + pwr |= MCI_PWR_UP; + break; + } case MMC_POWER_ON: pwr |= MCI_PWR_ON; break; } - if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) { - /* - * The ST Micro variant has some additional bits - * indicating signal direction for the signals in - * the SD/MMC bus and feedback-clock usage. - */ - pwr |= host->plat->sigdir; - - if (ios->bus_width == MMC_BUS_WIDTH_4) - pwr &= ~MCI_ST_DATA74DIREN; - else if (ios->bus_width == MMC_BUS_WIDTH_1) - pwr &= (~MCI_ST_DATA74DIREN & - ~MCI_ST_DATA31DIREN & - ~MCI_ST_DATA2DIREN); - } - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { if (host->hw_designer != AMBA_VENDOR_ST) pwr |= MCI_ROD; @@ -1157,13 +1059,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_irqsave(&host->lock, flags); mmci_set_clkreg(host, ios->clock); - mmci_write_pwrreg(host, pwr); - spin_unlock_irqrestore(&host->lock, flags); + if (host->pwr != pwr) { + host->pwr = pwr; + writel(pwr, host->base + MMCIPOWER); + } - out: - pm_runtime_mark_last_busy(mmc_dev(mmc)); - pm_runtime_put_autosuspend(mmc_dev(mmc)); + spin_unlock_irqrestore(&host->lock, flags); } static int mmci_get_ro(struct mmc_host *mmc) @@ -1216,77 +1118,21 @@ 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); - pdata->gpio_cd = of_get_named_gpio(np, "cd-gpios", 0); - - 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 mmci_probe(struct amba_device *dev, +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 or Device Tree. */ - if (!plat && !np) { - dev_err(&dev->dev, "No plat data or DT found\n"); - return -EINVAL; - } - + /* must have platform data */ if (!plat) { - plat = devm_kzalloc(&dev->dev, sizeof(*plat), GFP_KERNEL); - if (!plat) - return -ENOMEM; + ret = -EINVAL; + goto out; } - if (np) - mmci_dt_populate_generic_pdata(np, plat); - ret = amba_request_regions(dev, DRIVER_NAME); if (ret) goto out; @@ -1316,7 +1162,7 @@ static int mmci_probe(struct amba_device *dev, goto host_free; } - ret = clk_prepare_enable(host->clk); + ret = clk_enable(host->clk); if (ret) goto clk_free; @@ -1367,23 +1213,6 @@ static int mmci_probe(struct amba_device *dev, mmc->f_max = min(host->mclk, fmax); dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); - host->pinctrl = devm_pinctrl_get(&dev->dev); - if (IS_ERR(host->pinctrl)) { - ret = PTR_ERR(host->pinctrl); - goto clk_disable; - } - - host->pins_default = pinctrl_lookup_state(host->pinctrl, - PINCTRL_STATE_DEFAULT); - - /* enable pins to be muxed in and configured */ - if (!IS_ERR(host->pins_default)) { - ret = pinctrl_select_state(host->pinctrl, host->pins_default); - if (ret) - dev_warn(&dev->dev, "could not set default pins\n"); - } else - dev_warn(&dev->dev, "could not get default pinstate\n"); - #ifdef CONFIG_REGULATOR /* If we're using the regulator framework, try to fetch a regulator */ host->vcc = regulator_get(&dev->dev, "vmmc"); @@ -1408,7 +1237,6 @@ static int mmci_probe(struct amba_device *dev, if (host->vcc == NULL) mmc->ocr_avail = plat->ocr_mask; mmc->caps = plat->capabilities; - mmc->caps2 = plat->capabilities2; /* * We can do SGIO @@ -1431,13 +1259,12 @@ static int mmci_probe(struct amba_device *dev, /* * Block size can be up to 2048 bytes, but must be a power of two. */ - mmc->max_blk_size = 1 << 11; + mmc->max_blk_size = 2048; /* - * Limit the number of blocks transferred so that we don't overflow - * the maximum request size. + * No limit on the number of blocks transferred. */ - mmc->max_blk_count = mmc->max_req_size >> 11; + mmc->max_blk_count = mmc->max_req_size; spin_lock_init(&host->lock); @@ -1445,10 +1272,6 @@ static int mmci_probe(struct amba_device *dev, writel(0, host->base + MMCIMASK1); writel(0xfff, host->base + MMCICLEAR); - if (plat->gpio_cd == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto err_gpio_cd; - } if (gpio_is_valid(plat->gpio_cd)) { ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)"); if (ret == 0) @@ -1472,10 +1295,6 @@ static int mmci_probe(struct amba_device *dev, if (ret >= 0) host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd); } - if (plat->gpio_wp == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto err_gpio_wp; - } if (gpio_is_valid(plat->gpio_wp)) { ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)"); if (ret == 0) @@ -1494,7 +1313,7 @@ static int mmci_probe(struct amba_device *dev, if (ret) goto unmap; - if (!dev->irq[1]) + if (dev->irq[1] == NO_IRQ) host->singleirq = true; else { ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, @@ -1514,10 +1333,6 @@ static int mmci_probe(struct amba_device *dev, mmci_dma_setup(host); - pm_runtime_set_autosuspend_delay(&dev->dev, 50); - pm_runtime_use_autosuspend(&dev->dev); - pm_runtime_put(&dev->dev); - mmc_add_host(mmc); return 0; @@ -1535,7 +1350,7 @@ static int mmci_probe(struct amba_device *dev, err_gpio_cd: iounmap(host->base); clk_disable: - clk_disable_unprepare(host->clk); + clk_disable(host->clk); clk_free: clk_put(host->clk); host_free: @@ -1546,7 +1361,7 @@ static int mmci_probe(struct amba_device *dev, return ret; } -static int mmci_remove(struct amba_device *dev) +static int __devexit mmci_remove(struct amba_device *dev) { struct mmc_host *mmc = amba_get_drvdata(dev); @@ -1555,12 +1370,6 @@ static int mmci_remove(struct amba_device *dev) if (mmc) { struct mmci_host *host = mmc_priv(mmc); - /* - * Undo pm_runtime_put() in probe. We use the _sync - * version here so that we can access the primecell. - */ - pm_runtime_get_sync(&dev->dev); - mmc_remove_host(mmc); writel(0, host->base + MMCIMASK0); @@ -1582,7 +1391,7 @@ static int mmci_remove(struct amba_device *dev) gpio_free(host->gpio_cd); iounmap(host->base); - clk_disable_unprepare(host->clk); + clk_disable(host->clk); clk_put(host->clk); if (host->vcc) @@ -1597,49 +1406,43 @@ static int mmci_remove(struct amba_device *dev) return 0; } -#ifdef CONFIG_SUSPEND -static int mmci_suspend(struct device *dev) +#ifdef CONFIG_PM +static int mmci_suspend(struct amba_device *dev, pm_message_t state) { - struct amba_device *adev = to_amba_device(dev); - struct mmc_host *mmc = amba_get_drvdata(adev); + struct mmc_host *mmc = amba_get_drvdata(dev); int ret = 0; if (mmc) { struct mmci_host *host = mmc_priv(mmc); ret = mmc_suspend_host(mmc); - if (ret == 0) { - pm_runtime_get_sync(dev); + if (ret == 0) writel(0, host->base + MMCIMASK0); - } } return ret; } -static int mmci_resume(struct device *dev) +static int mmci_resume(struct amba_device *dev) { - struct amba_device *adev = to_amba_device(dev); - struct mmc_host *mmc = amba_get_drvdata(adev); + struct mmc_host *mmc = amba_get_drvdata(dev); int ret = 0; if (mmc) { struct mmci_host *host = mmc_priv(mmc); writel(MCI_IRQENABLE, host->base + MMCIMASK0); - pm_runtime_put(dev); ret = mmc_resume_host(mmc); } return ret; } +#else +#define mmci_suspend NULL +#define mmci_resume NULL #endif -static const struct dev_pm_ops mmci_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume) -}; - static struct amba_id mmci_ids[] = { { .id = 0x00041180, @@ -1662,11 +1465,6 @@ static struct amba_id mmci_ids[] = { .mask = 0x00ffffff, .data = &variant_u300, }, - { - .id = 0x10180180, - .mask = 0xf0ffffff, - .data = &variant_nomadik, - }, { .id = 0x00280180, .mask = 0x00ffffff, @@ -1685,20 +1483,29 @@ static struct amba_id mmci_ids[] = { { 0, 0 }, }; -MODULE_DEVICE_TABLE(amba, mmci_ids); - static struct amba_driver mmci_driver = { .drv = { .name = DRIVER_NAME, - .pm = &mmci_dev_pm_ops, }, .probe = mmci_probe, - .remove = mmci_remove, + .remove = __devexit_p(mmci_remove), + .suspend = mmci_suspend, + .resume = mmci_resume, .id_table = mmci_ids, }; -module_amba_driver(mmci_driver); +static int __init mmci_init(void) +{ + return amba_driver_register(&mmci_driver); +} + +static void __exit mmci_exit(void) +{ + amba_driver_unregister(&mmci_driver); +} +module_init(mmci_init); +module_exit(mmci_exit); module_param(fmax, uint, 0444); MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver"); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index d34d8c0add8..79e4143ab9d 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -13,6 +13,16 @@ #define MCI_PWR_ON 0x03 #define MCI_OD (1 << 6) #define MCI_ROD (1 << 7) +/* + * The ST Micro version does not have ROD and reuse the voltage registers + * for direction settings + */ +#define MCI_ST_DATA2DIREN (1 << 2) +#define MCI_ST_CMDDIREN (1 << 3) +#define MCI_ST_DATA0DIREN (1 << 4) +#define MCI_ST_DATA31DIREN (1 << 5) +#define MCI_ST_FBCLKEN (1 << 7) +#define MCI_ST_DATA74DIREN (1 << 8) #define MMCICLOCK 0x004 #define MCI_CLK_ENABLE (1 << 8) @@ -150,7 +160,7 @@ (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ MCI_TXFIFOHALFEMPTYMASK) -#define NR_SG 128 +#define NR_SG 16 struct clk; struct variant_data; @@ -179,8 +189,7 @@ struct mmci_host { unsigned int mclk; unsigned int cclk; - u32 pwr_reg; - u32 clk_reg; + u32 pwr; struct mmci_platform_data *plat; struct variant_data *variant; @@ -195,10 +204,6 @@ struct mmci_host { unsigned int size; struct regulator *vcc; - /* pinctrl handles */ - struct pinctrl *pinctrl; - struct pinctrl_state *pins_default; - #ifdef CONFIG_DMA_ENGINE /* DMA stuff */ struct dma_chan *dma_current; diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 7c0af0e8004..a4c865a5286 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include #include @@ -213,8 +213,7 @@ msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, MMCIDATALENGTH); - msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & - (~MCI_IRQ_PIO)) | host->cmd_pio_irqmask, MMCIMASK0); + msmsdcc_writel(host, host->cmd_pio_irqmask, MMCIMASK1); msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); if (host->cmd_cmd) { @@ -389,7 +388,7 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, host->dma.dir); if (n == 0) { - pr_err("%s: Unable to map in all sg elements\n", + printk(KERN_ERR "%s: Unable to map in all sg elements\n", mmc_hostname(host->mmc)); host->dma.sg = NULL; host->dma.num_ents = 0; @@ -475,7 +474,7 @@ msmsdcc_start_command_deferred(struct msmsdcc_host *host, *c |= MCI_CSPM_MCIABORT; if (host->curr.cmd != NULL) { - pr_err("%s: Overlapping command requests\n", + printk(KERN_ERR "%s: Overlapping command requests\n", mmc_hostname(host->mmc)); } host->curr.cmd = cmd; @@ -544,9 +543,7 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); - msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & - (~MCI_IRQ_PIO)) | pio_irqmask, MMCIMASK0); - + msmsdcc_writel(host, pio_irqmask, MMCIMASK1); msmsdcc_writel(host, datactrl, MMCIDATACTRL); if (cmd) { @@ -662,13 +659,8 @@ msmsdcc_pio_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; uint32_t status; - u32 mci_mask0; status = msmsdcc_readl(host, MMCISTATUS); - mci_mask0 = msmsdcc_readl(host, MMCIMASK0); - - if (((mci_mask0 & status) & MCI_IRQ_PIO) == 0) - return IRQ_NONE; do { unsigned long flags; @@ -689,8 +681,8 @@ msmsdcc_pio_irq(int irq, void *dev_id) /* Map the current scatter buffer */ local_irq_save(flags); - buffer = kmap_atomic(sg_page(host->pio.sg)) - + host->pio.sg->offset; + buffer = kmap_atomic(sg_page(host->pio.sg), + KM_BIO_SRC_IRQ) + host->pio.sg->offset; buffer += host->pio.sg_off; remain = host->pio.sg->length - host->pio.sg_off; len = 0; @@ -700,7 +692,7 @@ msmsdcc_pio_irq(int irq, void *dev_id) len = msmsdcc_pio_write(host, buffer, remain, status); /* Unmap the buffer */ - kunmap_atomic(buffer); + kunmap_atomic(buffer, KM_BIO_SRC_IRQ); local_irq_restore(flags); host->pio.sg_off += len; @@ -727,12 +719,10 @@ msmsdcc_pio_irq(int irq, void *dev_id) } while (1); if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) - msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | - MCI_RXDATAAVLBLMASK, MMCIMASK0); + msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1); if (!host->curr.xfer_remain) - msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | 0, - MMCIMASK0); + msmsdcc_writel(host, 0, MMCIMASK1); return IRQ_HANDLED; } @@ -864,8 +854,6 @@ msmsdcc_irq(int irq, void *dev_id) do { status = msmsdcc_readl(host, MMCISTATUS); status &= msmsdcc_readl(host, MMCIMASK0); - if ((status & (~MCI_IRQ_PIO)) == 0) - break; msmsdcc_writel(host, status, MMCICLEAR); if (status & MCI_SDIOINTR) @@ -951,7 +939,7 @@ static void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable) struct msm_mmc_gpio_data *curr; int i, rc = 0; - if (!host->plat->gpio_data || host->gpio_config_status == enable) + if (!host->plat->gpio_data && host->gpio_config_status == enable) return; curr = host->plat->gpio_data; @@ -1064,19 +1052,10 @@ static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_unlock_irqrestore(&host->lock, flags); } -static void msmsdcc_init_card(struct mmc_host *mmc, struct mmc_card *card) -{ - struct msmsdcc_host *host = mmc_priv(mmc); - - if (host->plat->init_card) - host->plat->init_card(card); -} - static const struct mmc_host_ops msmsdcc_ops = { .request = msmsdcc_request, .set_ios = msmsdcc_set_ios, .enable_sdio_irq = msmsdcc_enable_sdio_irq, - .init_card = msmsdcc_init_card, }; static void @@ -1113,7 +1092,7 @@ msmsdcc_platform_status_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; - pr_debug("%s: %d\n", __func__, irq); + printk(KERN_DEBUG "%s: %d\n", __func__, irq); msmsdcc_check_status((unsigned long) host); return IRQ_HANDLED; } @@ -1123,7 +1102,7 @@ msmsdcc_status_notify_cb(int card_present, void *dev_id) { struct msmsdcc_host *host = dev_id; - pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc), + printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc), card_present); msmsdcc_check_status((unsigned long) host); } @@ -1171,6 +1150,7 @@ msmsdcc_probe(struct platform_device *pdev) struct msmsdcc_host *host; struct mmc_host *mmc; struct resource *cmd_irqres = NULL; + struct resource *pio_irqres = NULL; struct resource *stat_irqres = NULL; struct resource *memres = NULL; struct resource *dmares = NULL; @@ -1195,10 +1175,12 @@ msmsdcc_probe(struct platform_device *pdev) dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "cmd_irq"); + pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, + "pio_irq"); stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq"); - if (!cmd_irqres || !memres) { + if (!cmd_irqres || !pio_irqres || !memres) { pr_err("%s: Invalid resource\n", __func__); return -ENXIO; } @@ -1218,20 +1200,17 @@ msmsdcc_probe(struct platform_device *pdev) host->plat = plat; host->mmc = mmc; host->curr.cmd = NULL; - init_timer(&host->busclk_timer); - host->busclk_timer.data = (unsigned long) host; - host->busclk_timer.function = msmsdcc_busclk_expired; - host->cmdpoll = 1; host->base = ioremap(memres->start, PAGE_SIZE); if (!host->base) { ret = -ENOMEM; - goto host_free; + goto out; } host->cmd_irqres = cmd_irqres; + host->pio_irqres = pio_irqres; host->memres = memres; host->dmares = dmares; spin_lock_init(&host->lock); @@ -1242,19 +1221,13 @@ msmsdcc_probe(struct platform_device *pdev) /* * Setup DMA */ - if (host->dmares) { - ret = msmsdcc_init_dma(host); - if (ret) - goto ioremap_free; - } else { - host->dma.channel = -1; - } + msmsdcc_init_dma(host); /* Get our clocks */ host->pclk = clk_get(&pdev->dev, "sdc_pclk"); if (IS_ERR(host->pclk)) { ret = PTR_ERR(host->pclk); - goto dma_free; + goto host_free; } host->clk = clk_get(&pdev->dev, "sdc_clk"); @@ -1263,17 +1236,17 @@ msmsdcc_probe(struct platform_device *pdev) goto pclk_put; } - ret = clk_set_rate(host->clk, msmsdcc_fmin); - if (ret) { - pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); - goto clk_put; - } - /* Enable clocks */ ret = msmsdcc_enable_clocks(host); if (ret) goto clk_put; + ret = clk_set_rate(host->clk, msmsdcc_fmin); + if (ret) { + pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); + goto clk_disable; + } + host->pclk_rate = clk_get_rate(host->pclk); host->clk_rate = clk_get_rate(host->clk); @@ -1343,12 +1316,16 @@ msmsdcc_probe(struct platform_device *pdev) host->eject = !host->oldstat; } + init_timer(&host->busclk_timer); + host->busclk_timer.data = (unsigned long) host; + host->busclk_timer.function = msmsdcc_busclk_expired; + ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) goto stat_irq_free; - ret = request_irq(cmd_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, + ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); if (ret) goto cmd_irq_free; @@ -1391,13 +1368,6 @@ msmsdcc_probe(struct platform_device *pdev) clk_put(host->clk); pclk_put: clk_put(host->pclk); -dma_free: - if (host->dmares) - dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata), - host->dma.nc, host->dma.nc_busaddr); -ioremap_free: - tasklet_kill(&host->dma_tlet); - iounmap(host->base); host_free: mmc_free_host(mmc); out: @@ -1480,7 +1450,18 @@ static struct platform_driver msmsdcc_driver = { }, }; -module_platform_driver(msmsdcc_driver); +static int __init msmsdcc_init(void) +{ + return platform_driver_register(&msmsdcc_driver); +} + +static void __exit msmsdcc_exit(void) +{ + platform_driver_unregister(&msmsdcc_driver); +} + +module_init(msmsdcc_init); +module_exit(msmsdcc_exit); MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 402028d16b8..42d7bbc977c 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h @@ -140,11 +140,6 @@ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|MCI_PROGDONEMASK) -#define MCI_IRQ_PIO \ - (MCI_RXDATAAVLBLMASK | MCI_TXDATAAVLBLMASK | MCI_RXFIFOEMPTYMASK | \ - MCI_TXFIFOEMPTYMASK | MCI_RXFIFOFULLMASK | MCI_TXFIFOFULLMASK | \ - MCI_RXFIFOHALFFULLMASK | MCI_TXFIFOHALFEMPTYMASK | \ - MCI_RXACTIVEMASK | MCI_TXACTIVEMASK) /* * The size of the FIFO in bytes. */ @@ -207,6 +202,7 @@ struct msmsdcc_stats { struct msmsdcc_host { struct resource *cmd_irqres; + struct resource *pio_irqres; struct resource *memres; struct resource *dmares; void __iomem *base; diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index de4c20b3936..a5bf60e01af 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -19,13 +19,12 @@ #include #include #include -#include #include #include #include #include -#include +#include #include "mvsdio.h" @@ -52,7 +51,6 @@ struct mvsd_host { struct device *dev; struct resource *res; int irq; - struct clk *clk; int gpio_card_detect; int gpio_write_protect; }; @@ -119,7 +117,7 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) host->pio_size = data->blocks * data->blksz; host->pio_ptr = sg_virt(data->sg); if (!nodma) - pr_debug("%s: fallback to PIO for data " + printk(KERN_DEBUG "%s: fallback to PIO for data " "at 0x%p size %d\n", mmc_hostname(host->mmc), host->pio_ptr, host->pio_size); @@ -473,7 +471,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev) if (mrq->data) err_status = mvsd_finish_data(host, mrq->data, err_status); if (err_status) { - pr_err("%s: unhandled error status %#04x\n", + printk(KERN_ERR "%s: unhandled error status %#04x\n", mmc_hostname(host->mmc), err_status); cmd->error = -ENOMSG; } @@ -491,7 +489,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev) if (irq_handled) return IRQ_HANDLED; - pr_err("%s: unhandled interrupt status=0x%04x en=0x%04x " + printk(KERN_ERR "%s: unhandled interrupt status=0x%04x en=0x%04x " "pio=%d\n", mmc_hostname(host->mmc), intr_status, host->intr_en, host->pio_size); return IRQ_NONE; @@ -507,9 +505,9 @@ static void mvsd_timeout_timer(unsigned long data) spin_lock_irqsave(&host->lock, flags); mrq = host->mrq; if (mrq) { - pr_err("%s: Timeout waiting for hardware interrupt.\n", + printk(KERN_ERR "%s: Timeout waiting for hardware interrupt.\n", mmc_hostname(host->mmc)); - pr_err("%s: hw_state=0x%04x, intr_status=0x%04x " + printk(KERN_ERR "%s: hw_state=0x%04x, intr_status=0x%04x " "intr_en=0x%04x\n", mmc_hostname(host->mmc), mvsd_read(MVSD_HW_STATE), mvsd_read(MVSD_NOR_INTR_STATUS), @@ -681,9 +679,8 @@ static const struct mmc_host_ops mvsd_ops = { .enable_sdio_irq = mvsd_enable_sdio_irq, }; -static void __init -mv_conf_mbus_windows(struct mvsd_host *host, - const struct mbus_dram_target_info *dram) +static void __init mv_conf_mbus_windows(struct mvsd_host *host, + struct mbus_dram_target_info *dram) { void __iomem *iobase = host->base; int i; @@ -694,7 +691,7 @@ mv_conf_mbus_windows(struct mvsd_host *host, } for (i = 0; i < dram->num_cs; i++) { - const struct mbus_dram_window *cs = dram->cs + i; + struct mbus_dram_window *cs = dram->cs + i; writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | (dram->mbus_dram_target_id << 4) | 1, @@ -708,7 +705,6 @@ static int __init mvsd_probe(struct platform_device *pdev) struct mmc_host *mmc = NULL; struct mvsd_host *host = NULL; const struct mvsdio_platform_data *mvsd_data; - const struct mbus_dram_target_info *dram; struct resource *r; int ret, irq; @@ -759,26 +755,18 @@ static int __init mvsd_probe(struct platform_device *pdev) } /* (Re-)program MBUS remapping windows if we are asked to. */ - dram = mv_mbus_dram_info(); - if (dram) - mv_conf_mbus_windows(host, dram); + if (mvsd_data->dram != NULL) + mv_conf_mbus_windows(host, mvsd_data->dram); mvsd_power_down(host); ret = request_irq(irq, mvsd_irq, 0, DRIVER_NAME, host); if (ret) { - pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, irq); + printk(KERN_ERR "%s: cannot assign irq %d\n", DRIVER_NAME, irq); goto out; } else host->irq = irq; - /* Not all platforms can gate the clock, so it is not - an error if the clock does not exists. */ - host->clk = clk_get(&pdev->dev, NULL); - if (!IS_ERR(host->clk)) { - clk_prepare_enable(host->clk); - } - if (mvsd_data->gpio_card_detect) { ret = gpio_request(mvsd_data->gpio_card_detect, DRIVER_NAME " cd"); @@ -814,7 +802,7 @@ static int __init mvsd_probe(struct platform_device *pdev) if (ret) goto out; - pr_notice("%s: %s driver initialized, ", + printk(KERN_NOTICE "%s: %s driver initialized, ", mmc_hostname(mmc), DRIVER_NAME); if (host->gpio_card_detect) printk("using GPIO %d for card detection\n", @@ -839,10 +827,6 @@ out: if (r) release_resource(r); if (mmc) - if (!IS_ERR_OR_NULL(host->clk)) { - clk_disable_unprepare(host->clk); - clk_put(host->clk); - } mmc_free_host(mmc); return ret; @@ -867,11 +851,6 @@ static int __exit mvsd_remove(struct platform_device *pdev) mvsd_power_down(host); iounmap(host->base); release_resource(host->res); - - if (!IS_ERR(host->clk)) { - clk_disable_unprepare(host->clk); - clk_put(host->clk); - } mmc_free_host(mmc); } platform_set_drvdata(pdev, NULL); diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index a72936eea6f..b87143d0aeb 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -33,17 +33,15 @@ #include #include #include -#include #include #include #include -#include +#include -#include +#include #define DRIVER_NAME "mxc-mmc" -#define MXCMCI_TIMEOUT_MS 10000 #define MMC_REG_STR_STP_CLK 0x00 #define MMC_REG_STATUS 0x04 @@ -112,11 +110,6 @@ #define INT_WRITE_OP_DONE_EN (1 << 1) #define INT_READ_OP_EN (1 << 0) -enum mxcmci_type { - IMX21_MMC, - IMX31_MMC, -}; - struct mxcmci_host { struct mmc_host *mmc; struct resource *res; @@ -141,8 +134,7 @@ struct mxcmci_host { u16 rev_no; unsigned int cmdat; - struct clk *clk_ipg; - struct clk *clk_per; + struct clk *clk; int clock; @@ -155,28 +147,7 @@ struct mxcmci_host { int dmareq; struct dma_slave_config dma_slave_config; struct imx_dma_data dma_data; - - struct timer_list watchdog; - enum mxcmci_type devtype; -}; - -static struct platform_device_id mxcmci_devtype[] = { - { - .name = "imx21-mmc", - .driver_data = IMX21_MMC, - }, { - .name = "imx31-mmc", - .driver_data = IMX31_MMC, - }, { - /* sentinel */ - } }; -MODULE_DEVICE_TABLE(platform, mxcmci_devtype); - -static inline int is_imx31_mmc(struct mxcmci_host *host) -{ - return host->devtype == IMX31_MMC; -} static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); @@ -246,7 +217,6 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) unsigned int blksz = data->blksz; unsigned int datasize = nob * blksz; struct scatterlist *sg; - enum dma_transfer_direction slave_dirn; int i, nents; if (data->flags & MMC_DATA_STREAM) @@ -263,27 +233,24 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) return 0; for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->offset & 3 || sg->length & 3 || sg->length < 512) { + if (sg->offset & 3 || sg->length & 3) { host->do_dma = 0; return 0; } } - if (data->flags & MMC_DATA_READ) { + if (data->flags & MMC_DATA_READ) host->dma_dir = DMA_FROM_DEVICE; - slave_dirn = DMA_DEV_TO_MEM; - } else { + else host->dma_dir = DMA_TO_DEVICE; - slave_dirn = DMA_MEM_TO_DEV; - } nents = dma_map_sg(host->dma->device->dev, data->sg, data->sg_len, host->dma_dir); if (nents != data->sg_len) return -EINVAL; - host->desc = dmaengine_prep_slave_sg(host->dma, - data->sg, data->sg_len, slave_dirn, + host->desc = host->dma->device->device_prep_slave_sg(host->dma, + data->sg, data->sg_len, host->dma_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!host->desc) { @@ -295,34 +262,10 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) wmb(); dmaengine_submit(host->desc); - dma_async_issue_pending(host->dma); - - mod_timer(&host->watchdog, jiffies + msecs_to_jiffies(MXCMCI_TIMEOUT_MS)); return 0; } -static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat); -static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat); - -static void mxcmci_dma_callback(void *data) -{ - struct mxcmci_host *host = data; - u32 stat; - - del_timer(&host->watchdog); - - stat = readl(host->base + MMC_REG_STATUS); - writel(stat & ~STATUS_DATA_TRANS_DONE, host->base + MMC_REG_STATUS); - - dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); - - if (stat & STATUS_READ_OP_DONE) - writel(STATUS_READ_OP_DONE, host->base + MMC_REG_STATUS); - - mxcmci_data_done(host, stat); -} - static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, unsigned int cmdat) { @@ -354,14 +297,8 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, int_cntr = INT_END_CMD_RES_EN; - if (mxcmci_use_dma(host)) { - if (host->dma_dir == DMA_FROM_DEVICE) { - host->desc->callback = mxcmci_dma_callback; - host->desc->callback_param = host; - } else { - int_cntr |= INT_WRITE_OP_DONE_EN; - } - } + if (mxcmci_use_dma(host)) + int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN; spin_lock_irqsave(&host->lock, flags); if (host->use_sdio) @@ -400,9 +337,11 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat) struct mmc_data *data = host->data; int data_error; - if (mxcmci_use_dma(host)) + if (mxcmci_use_dma(host)) { + dmaengine_terminate_all(host->dma); dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len, host->dma_dir); + } if (stat & STATUS_ERR_MASK) { dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", @@ -677,10 +616,8 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) mxcmci_cmd_done(host, stat); if (mxcmci_use_dma(host) && - (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) { - del_timer(&host->watchdog); + (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) mxcmci_data_done(host, stat); - } if (host->default_irq_mask && (stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL))) @@ -728,7 +665,7 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios) { unsigned int divider; int prescaler = 0; - unsigned int clk_in = clk_get_rate(host->clk_per); + unsigned int clk_in = clk_get_rate(host->clk); while (prescaler <= 0x800) { for (divider = 1; divider <= 0xF; divider++) { @@ -768,7 +705,6 @@ static int mxcmci_setup_dma(struct mmc_host *mmc) config->src_addr_width = 4; config->dst_maxburst = host->burstlen; config->src_maxburst = host->burstlen; - config->device_fc = false; return dmaengine_slave_config(host->dma, config); } @@ -866,8 +802,6 @@ static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) { - struct mxcmci_host *mxcmci = mmc_priv(host); - /* * MX3 SoCs have a silicon bug which corrupts CRC calculation of * multi-block transfers when connected SDIO peripheral doesn't @@ -875,7 +809,7 @@ static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) * One way to prevent this is to only allow 1-bit transfers. */ - if (is_imx31_mmc(mxcmci) && card->type == MMC_TYPE_SDIO) + if (cpu_is_mx3() && card->type == MMC_TYPE_SDIO) host->caps &= ~MMC_CAP_4_BIT_DATA; else host->caps |= MMC_CAP_4_BIT_DATA; @@ -893,34 +827,6 @@ static bool filter(struct dma_chan *chan, void *param) return true; } -static void mxcmci_watchdog(unsigned long data) -{ - struct mmc_host *mmc = (struct mmc_host *)data; - struct mxcmci_host *host = mmc_priv(mmc); - struct mmc_request *req = host->req; - unsigned int stat = readl(host->base + MMC_REG_STATUS); - - if (host->dma_dir == DMA_FROM_DEVICE) { - dmaengine_terminate_all(host->dma); - dev_err(mmc_dev(host->mmc), - "%s: read time out (status = 0x%08x)\n", - __func__, stat); - } else { - dev_err(mmc_dev(host->mmc), - "%s: write time out (status = 0x%08x)\n", - __func__, stat); - mxcmci_softreset(host); - } - - /* Mark transfer as erroneus and inform the upper layers */ - - host->data->error = -ETIMEDOUT; - host->req = NULL; - host->cmd = NULL; - host->data = NULL; - mmc_request_done(host->mmc, req); -} - static const struct mmc_host_ops mxcmci_ops = { .request = mxcmci_request, .set_ios = mxcmci_set_ios, @@ -937,7 +843,7 @@ static int mxcmci_probe(struct platform_device *pdev) int ret = 0, irq; dma_cap_mask_t mask; - pr_info("i.MX SDHC driver\n"); + printk(KERN_INFO "i.MX SDHC driver\n"); iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); @@ -973,7 +879,6 @@ static int mxcmci_probe(struct platform_device *pdev) host->mmc = mmc; host->pdata = pdev->dev.platform_data; - host->devtype = pdev->id_entry->driver_data; spin_lock_init(&host->lock); mxcmci_init_ocr(host); @@ -987,20 +892,12 @@ static int mxcmci_probe(struct platform_device *pdev) host->res = r; host->irq = irq; - host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(host->clk_ipg)) { - ret = PTR_ERR(host->clk_ipg); + host->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); goto out_iounmap; } - - host->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(host->clk_per)) { - ret = PTR_ERR(host->clk_per); - goto out_iounmap; - } - - clk_prepare_enable(host->clk_per); - clk_prepare_enable(host->clk_ipg); + clk_enable(host->clk); mxcmci_softreset(host); @@ -1012,8 +909,8 @@ static int mxcmci_probe(struct platform_device *pdev) goto out_clk_put; } - mmc->f_min = clk_get_rate(host->clk_per) >> 16; - mmc->f_max = clk_get_rate(host->clk_per) >> 1; + mmc->f_min = clk_get_rate(host->clk) >> 16; + mmc->f_max = clk_get_rate(host->clk) >> 1; /* recommended in data sheet */ writew(0x2db4, host->base + MMC_REG_READ_TO); @@ -1054,10 +951,6 @@ static int mxcmci_probe(struct platform_device *pdev) mmc_add_host(mmc); - init_timer(&host->watchdog); - host->watchdog.function = &mxcmci_watchdog; - host->watchdog.data = (unsigned long)mmc; - return 0; out_free_irq: @@ -1066,8 +959,8 @@ out_free_dma: if (host->dma) dma_release_channel(host->dma); out_clk_put: - clk_disable_unprepare(host->clk_per); - clk_disable_unprepare(host->clk_ipg); + clk_disable(host->clk); + clk_put(host->clk); out_iounmap: iounmap(host->base); out_free: @@ -1098,8 +991,8 @@ static int mxcmci_remove(struct platform_device *pdev) if (host->dma) dma_release_channel(host->dma); - clk_disable_unprepare(host->clk_per); - clk_disable_unprepare(host->clk_ipg); + clk_disable(host->clk); + clk_put(host->clk); release_mem_region(host->res->start, resource_size(host->res)); @@ -1117,8 +1010,7 @@ static int mxcmci_suspend(struct device *dev) if (mmc) ret = mmc_suspend_host(mmc); - clk_disable_unprepare(host->clk_per); - clk_disable_unprepare(host->clk_ipg); + clk_disable(host->clk); return ret; } @@ -1129,8 +1021,7 @@ static int mxcmci_resume(struct device *dev) struct mxcmci_host *host = mmc_priv(mmc); int ret = 0; - clk_prepare_enable(host->clk_per); - clk_prepare_enable(host->clk_ipg); + clk_enable(host->clk); if (mmc) ret = mmc_resume_host(mmc); @@ -1146,7 +1037,6 @@ static const struct dev_pm_ops mxcmci_pm_ops = { static struct platform_driver mxcmci_driver = { .probe = mxcmci_probe, .remove = mxcmci_remove, - .id_table = mxcmci_devtype, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, @@ -1156,9 +1046,20 @@ static struct platform_driver mxcmci_driver = { } }; -module_platform_driver(mxcmci_driver); +static int __init mxcmci_init(void) +{ + return platform_driver_register(&mxcmci_driver); +} + +static void __exit mxcmci_exit(void) +{ + platform_driver_unregister(&mxcmci_driver); +} + +module_init(mxcmci_init); +module_exit(mxcmci_exit); MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:mxc-mmc"); +MODULE_ALIAS("platform:imx-mmc"); diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 206fe499ded..d513d47364d 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -23,9 +23,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -40,13 +37,95 @@ #include #include #include -#include -#include -#include -#include + +#include +#include +#include +#include #define DRIVER_NAME "mxs-mmc" +/* card detect polling timeout */ +#define MXS_MMC_DETECT_TIMEOUT (HZ/2) + +#define SSP_VERSION_LATEST 4 +#define ssp_is_old() (host->version < SSP_VERSION_LATEST) + +/* SSP registers */ +#define HW_SSP_CTRL0 0x000 +#define BM_SSP_CTRL0_RUN (1 << 29) +#define BM_SSP_CTRL0_SDIO_IRQ_CHECK (1 << 28) +#define BM_SSP_CTRL0_IGNORE_CRC (1 << 26) +#define BM_SSP_CTRL0_READ (1 << 25) +#define BM_SSP_CTRL0_DATA_XFER (1 << 24) +#define BP_SSP_CTRL0_BUS_WIDTH (22) +#define BM_SSP_CTRL0_BUS_WIDTH (0x3 << 22) +#define BM_SSP_CTRL0_WAIT_FOR_IRQ (1 << 21) +#define BM_SSP_CTRL0_LONG_RESP (1 << 19) +#define BM_SSP_CTRL0_GET_RESP (1 << 17) +#define BM_SSP_CTRL0_ENABLE (1 << 16) +#define BP_SSP_CTRL0_XFER_COUNT (0) +#define BM_SSP_CTRL0_XFER_COUNT (0xffff) +#define HW_SSP_CMD0 0x010 +#define BM_SSP_CMD0_DBL_DATA_RATE_EN (1 << 25) +#define BM_SSP_CMD0_SLOW_CLKING_EN (1 << 22) +#define BM_SSP_CMD0_CONT_CLKING_EN (1 << 21) +#define BM_SSP_CMD0_APPEND_8CYC (1 << 20) +#define BP_SSP_CMD0_BLOCK_SIZE (16) +#define BM_SSP_CMD0_BLOCK_SIZE (0xf << 16) +#define BP_SSP_CMD0_BLOCK_COUNT (8) +#define BM_SSP_CMD0_BLOCK_COUNT (0xff << 8) +#define BP_SSP_CMD0_CMD (0) +#define BM_SSP_CMD0_CMD (0xff) +#define HW_SSP_CMD1 0x020 +#define HW_SSP_XFER_SIZE 0x030 +#define HW_SSP_BLOCK_SIZE 0x040 +#define BP_SSP_BLOCK_SIZE_BLOCK_COUNT (4) +#define BM_SSP_BLOCK_SIZE_BLOCK_COUNT (0xffffff << 4) +#define BP_SSP_BLOCK_SIZE_BLOCK_SIZE (0) +#define BM_SSP_BLOCK_SIZE_BLOCK_SIZE (0xf) +#define HW_SSP_TIMING (ssp_is_old() ? 0x050 : 0x070) +#define BP_SSP_TIMING_TIMEOUT (16) +#define BM_SSP_TIMING_TIMEOUT (0xffff << 16) +#define BP_SSP_TIMING_CLOCK_DIVIDE (8) +#define BM_SSP_TIMING_CLOCK_DIVIDE (0xff << 8) +#define BP_SSP_TIMING_CLOCK_RATE (0) +#define BM_SSP_TIMING_CLOCK_RATE (0xff) +#define HW_SSP_CTRL1 (ssp_is_old() ? 0x060 : 0x080) +#define BM_SSP_CTRL1_SDIO_IRQ (1 << 31) +#define BM_SSP_CTRL1_SDIO_IRQ_EN (1 << 30) +#define BM_SSP_CTRL1_RESP_ERR_IRQ (1 << 29) +#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN (1 << 28) +#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ (1 << 27) +#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN (1 << 26) +#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ (1 << 25) +#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN (1 << 24) +#define BM_SSP_CTRL1_DATA_CRC_IRQ (1 << 23) +#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN (1 << 22) +#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ (1 << 21) +#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ_EN (1 << 20) +#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ (1 << 17) +#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN (1 << 16) +#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ (1 << 15) +#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN (1 << 14) +#define BM_SSP_CTRL1_DMA_ENABLE (1 << 13) +#define BM_SSP_CTRL1_POLARITY (1 << 9) +#define BP_SSP_CTRL1_WORD_LENGTH (4) +#define BM_SSP_CTRL1_WORD_LENGTH (0xf << 4) +#define BP_SSP_CTRL1_SSP_MODE (0) +#define BM_SSP_CTRL1_SSP_MODE (0xf) +#define HW_SSP_SDRESP0 (ssp_is_old() ? 0x080 : 0x0a0) +#define HW_SSP_SDRESP1 (ssp_is_old() ? 0x090 : 0x0b0) +#define HW_SSP_SDRESP2 (ssp_is_old() ? 0x0a0 : 0x0c0) +#define HW_SSP_SDRESP3 (ssp_is_old() ? 0x0b0 : 0x0d0) +#define HW_SSP_STATUS (ssp_is_old() ? 0x0c0 : 0x100) +#define BM_SSP_STATUS_CARD_DETECT (1 << 28) +#define BM_SSP_STATUS_SDIO_IRQ (1 << 17) +#define HW_SSP_VERSION (cpu_is_mx23() ? 0x110 : 0x130) +#define BP_SSP_VERSION_MAJOR (24) + +#define BF_SSP(value, field) (((value) << BP_SSP_##field) & BM_SSP_##field) + #define MXS_MMC_IRQ_BITS (BM_SSP_CTRL1_SDIO_IRQ | \ BM_SSP_CTRL1_RESP_ERR_IRQ | \ BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ @@ -56,55 +135,60 @@ BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \ BM_SSP_CTRL1_FIFO_OVERRUN_IRQ) -/* card detect polling timeout */ -#define MXS_MMC_DETECT_TIMEOUT (HZ/2) +#define SSP_PIO_NUM 3 struct mxs_mmc_host { - struct mxs_ssp ssp; - struct mmc_host *mmc; struct mmc_request *mrq; struct mmc_command *cmd; struct mmc_data *data; + void __iomem *base; + int irq; + struct resource *res; + struct resource *dma_res; + struct clk *clk; + unsigned int clk_rate; + + struct dma_chan *dmach; + struct mxs_dma_data dma_data; + unsigned int dma_dir; + u32 ssp_pio_words[SSP_PIO_NUM]; + + unsigned int version; unsigned char bus_width; spinlock_t lock; int sdio_irq_en; - int wp_gpio; - bool wp_inverted; }; static int mxs_mmc_get_ro(struct mmc_host *mmc) { struct mxs_mmc_host *host = mmc_priv(mmc); - int ret; - - if (!gpio_is_valid(host->wp_gpio)) - return -EINVAL; + struct mxs_mmc_platform_data *pdata = + mmc_dev(host->mmc)->platform_data; - ret = gpio_get_value(host->wp_gpio); + if (!pdata) + return -EFAULT; - if (host->wp_inverted) - ret = !ret; + if (!gpio_is_valid(pdata->wp_gpio)) + return -EINVAL; - return ret; + return gpio_get_value(pdata->wp_gpio); } static int mxs_mmc_get_cd(struct mmc_host *mmc) { struct mxs_mmc_host *host = mmc_priv(mmc); - struct mxs_ssp *ssp = &host->ssp; - return !(readl(ssp->base + HW_SSP_STATUS(ssp)) & + return !(readl(host->base + HW_SSP_STATUS) & BM_SSP_STATUS_CARD_DETECT); } static void mxs_mmc_reset(struct mxs_mmc_host *host) { - struct mxs_ssp *ssp = &host->ssp; u32 ctrl0, ctrl1; - stmp_reset_block(ssp->base); + mxs_reset_block(host->base); ctrl0 = BM_SSP_CTRL0_IGNORE_CRC; ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) | @@ -120,15 +204,15 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host) writel(BF_SSP(0xffff, TIMING_TIMEOUT) | BF_SSP(2, TIMING_CLOCK_DIVIDE) | BF_SSP(0, TIMING_CLOCK_RATE), - ssp->base + HW_SSP_TIMING(ssp)); + host->base + HW_SSP_TIMING); if (host->sdio_irq_en) { ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; ctrl1 |= BM_SSP_CTRL1_SDIO_IRQ_EN; } - writel(ctrl0, ssp->base + HW_SSP_CTRL0); - writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp)); + writel(ctrl0, host->base + HW_SSP_CTRL0); + writel(ctrl1, host->base + HW_SSP_CTRL1); } static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, @@ -139,22 +223,21 @@ static void mxs_mmc_request_done(struct mxs_mmc_host *host) struct mmc_command *cmd = host->cmd; struct mmc_data *data = host->data; struct mmc_request *mrq = host->mrq; - struct mxs_ssp *ssp = &host->ssp; if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) { if (mmc_resp_type(cmd) & MMC_RSP_136) { - cmd->resp[3] = readl(ssp->base + HW_SSP_SDRESP0(ssp)); - cmd->resp[2] = readl(ssp->base + HW_SSP_SDRESP1(ssp)); - cmd->resp[1] = readl(ssp->base + HW_SSP_SDRESP2(ssp)); - cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP3(ssp)); + cmd->resp[3] = readl(host->base + HW_SSP_SDRESP0); + cmd->resp[2] = readl(host->base + HW_SSP_SDRESP1); + cmd->resp[1] = readl(host->base + HW_SSP_SDRESP2); + cmd->resp[0] = readl(host->base + HW_SSP_SDRESP3); } else { - cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP0(ssp)); + cmd->resp[0] = readl(host->base + HW_SSP_SDRESP0); } } if (data) { dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, ssp->dma_dir); + data->sg_len, host->dma_dir); /* * If there was an error on any block, we mark all * data blocks as being in error. @@ -187,20 +270,19 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id) struct mxs_mmc_host *host = dev_id; struct mmc_command *cmd = host->cmd; struct mmc_data *data = host->data; - struct mxs_ssp *ssp = &host->ssp; u32 stat; spin_lock(&host->lock); - stat = readl(ssp->base + HW_SSP_CTRL1(ssp)); + stat = readl(host->base + HW_SSP_CTRL1); writel(stat & MXS_MMC_IRQ_BITS, - ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); - - spin_unlock(&host->lock); + host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN)) mmc_signal_sdio_irq(host->mmc); + spin_unlock(&host->lock); + if (stat & BM_SSP_CTRL1_RESP_TIMEOUT_IRQ) cmd->error = -ETIMEDOUT; else if (stat & BM_SSP_CTRL1_RESP_ERR_IRQ) @@ -221,9 +303,8 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id) } static struct dma_async_tx_descriptor *mxs_mmc_prep_dma( - struct mxs_mmc_host *host, unsigned long flags) + struct mxs_mmc_host *host, unsigned int append) { - struct mxs_ssp *ssp = &host->ssp; struct dma_async_tx_descriptor *desc; struct mmc_data *data = host->data; struct scatterlist * sgl; @@ -232,24 +313,24 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma( if (data) { /* data */ dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, ssp->dma_dir); + data->sg_len, host->dma_dir); sgl = data->sg; sg_len = data->sg_len; } else { /* pio */ - sgl = (struct scatterlist *) ssp->ssp_pio_words; + sgl = (struct scatterlist *) host->ssp_pio_words; sg_len = SSP_PIO_NUM; } - desc = dmaengine_prep_slave_sg(ssp->dmach, - sgl, sg_len, ssp->slave_dirn, flags); + desc = host->dmach->device->device_prep_slave_sg(host->dmach, + sgl, sg_len, host->dma_dir, append); if (desc) { desc->callback = mxs_mmc_dma_irq_callback; desc->callback_param = host; } else { if (data) dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, ssp->dma_dir); + data->sg_len, host->dma_dir); } return desc; @@ -257,7 +338,6 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma( static void mxs_mmc_bc(struct mxs_mmc_host *host) { - struct mxs_ssp *ssp = &host->ssp; struct mmc_command *cmd = host->cmd; struct dma_async_tx_descriptor *desc; u32 ctrl0, cmd0, cmd1; @@ -271,17 +351,15 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; } - ssp->ssp_pio_words[0] = ctrl0; - ssp->ssp_pio_words[1] = cmd0; - ssp->ssp_pio_words[2] = cmd1; - ssp->dma_dir = DMA_NONE; - ssp->slave_dirn = DMA_TRANS_NONE; - desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK); + host->ssp_pio_words[0] = ctrl0; + host->ssp_pio_words[1] = cmd0; + host->ssp_pio_words[2] = cmd1; + host->dma_dir = DMA_NONE; + desc = mxs_mmc_prep_dma(host, 0); if (!desc) goto out; dmaengine_submit(desc); - dma_async_issue_pending(ssp->dmach); return; out: @@ -291,7 +369,6 @@ out: static void mxs_mmc_ac(struct mxs_mmc_host *host) { - struct mxs_ssp *ssp = &host->ssp; struct mmc_command *cmd = host->cmd; struct dma_async_tx_descriptor *desc; u32 ignore_crc, get_resp, long_resp; @@ -313,17 +390,15 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; } - ssp->ssp_pio_words[0] = ctrl0; - ssp->ssp_pio_words[1] = cmd0; - ssp->ssp_pio_words[2] = cmd1; - ssp->dma_dir = DMA_NONE; - ssp->slave_dirn = DMA_TRANS_NONE; - desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK); + host->ssp_pio_words[0] = ctrl0; + host->ssp_pio_words[1] = cmd0; + host->ssp_pio_words[2] = cmd1; + host->dma_dir = DMA_NONE; + desc = mxs_mmc_prep_dma(host, 0); if (!desc) goto out; dmaengine_submit(desc); - dma_async_issue_pending(ssp->dmach); return; out: @@ -357,12 +432,9 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) int i; unsigned short dma_data_dir, timeout; - enum dma_transfer_direction slave_dirn; unsigned int data_size = 0, log2_blksz; unsigned int blocks = data->blocks; - struct mxs_ssp *ssp = &host->ssp; - u32 ignore_crc, get_resp, long_resp, read; u32 ctrl0, cmd0, cmd1, val; @@ -375,11 +447,9 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) if (data->flags & MMC_DATA_WRITE) { dma_data_dir = DMA_TO_DEVICE; - slave_dirn = DMA_MEM_TO_DEV; read = 0; } else { dma_data_dir = DMA_FROM_DEVICE; - slave_dirn = DMA_DEV_TO_MEM; read = BM_SSP_CTRL0_READ; } @@ -405,15 +475,15 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) blocks = 1; /* xfer count, block size and count need to be set differently */ - if (ssp_is_old(ssp)) { + if (ssp_is_old()) { ctrl0 |= BF_SSP(data_size, CTRL0_XFER_COUNT); cmd0 |= BF_SSP(log2_blksz, CMD0_BLOCK_SIZE) | BF_SSP(blocks - 1, CMD0_BLOCK_COUNT); } else { - writel(data_size, ssp->base + HW_SSP_XFER_SIZE); + writel(data_size, host->base + HW_SSP_XFER_SIZE); writel(BF_SSP(log2_blksz, BLOCK_SIZE_BLOCK_SIZE) | BF_SSP(blocks - 1, BLOCK_SIZE_BLOCK_COUNT), - ssp->base + HW_SSP_BLOCK_SIZE); + host->base + HW_SSP_BLOCK_SIZE); } if ((cmd->opcode == MMC_STOP_TRANSMISSION) || @@ -428,18 +498,17 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) } /* set the timeout count */ - timeout = mxs_ns_to_ssp_ticks(ssp->clk_rate, data->timeout_ns); - val = readl(ssp->base + HW_SSP_TIMING(ssp)); + timeout = mxs_ns_to_ssp_ticks(host->clk_rate, data->timeout_ns); + val = readl(host->base + HW_SSP_TIMING); val &= ~(BM_SSP_TIMING_TIMEOUT); val |= BF_SSP(timeout, TIMING_TIMEOUT); - writel(val, ssp->base + HW_SSP_TIMING(ssp)); + writel(val, host->base + HW_SSP_TIMING); /* pio */ - ssp->ssp_pio_words[0] = ctrl0; - ssp->ssp_pio_words[1] = cmd0; - ssp->ssp_pio_words[2] = cmd1; - ssp->dma_dir = DMA_NONE; - ssp->slave_dirn = DMA_TRANS_NONE; + host->ssp_pio_words[0] = ctrl0; + host->ssp_pio_words[1] = cmd0; + host->ssp_pio_words[2] = cmd1; + host->dma_dir = DMA_NONE; desc = mxs_mmc_prep_dma(host, 0); if (!desc) goto out; @@ -447,14 +516,12 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) /* append data sg */ WARN_ON(host->data != NULL); host->data = data; - ssp->dma_dir = dma_data_dir; - ssp->slave_dirn = slave_dirn; - desc = mxs_mmc_prep_dma(host, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + host->dma_dir = dma_data_dir; + desc = mxs_mmc_prep_dma(host, 1); if (!desc) goto out; dmaengine_submit(desc); - dma_async_issue_pending(ssp->dmach); return; out: dev_warn(mmc_dev(host->mmc), @@ -495,6 +562,42 @@ static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) mxs_mmc_start_cmd(host, mrq->cmd); } +static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate) +{ + unsigned int ssp_clk, ssp_sck; + u32 clock_divide, clock_rate; + u32 val; + + ssp_clk = clk_get_rate(host->clk); + + for (clock_divide = 2; clock_divide <= 254; clock_divide += 2) { + clock_rate = DIV_ROUND_UP(ssp_clk, rate * clock_divide); + clock_rate = (clock_rate > 0) ? clock_rate - 1 : 0; + if (clock_rate <= 255) + break; + } + + if (clock_divide > 254) { + dev_err(mmc_dev(host->mmc), + "%s: cannot set clock to %d\n", __func__, rate); + return; + } + + ssp_sck = ssp_clk / clock_divide / (1 + clock_rate); + + val = readl(host->base + HW_SSP_TIMING); + val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE); + val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE); + val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE); + writel(val, host->base + HW_SSP_TIMING); + + host->clk_rate = ssp_sck; + + dev_dbg(mmc_dev(host->mmc), + "%s: clock_divide %d, clock_rate %d, ssp_clk %d, rate_actual %d, rate_requested %d\n", + __func__, clock_divide, clock_rate, ssp_clk, ssp_sck, rate); +} + static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mxs_mmc_host *host = mmc_priv(mmc); @@ -507,13 +610,12 @@ static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->bus_width = 0; if (ios->clock) - mxs_ssp_set_clk_rate(&host->ssp, ios->clock); + mxs_mmc_set_clk_rate(host, ios->clock); } static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct mxs_mmc_host *host = mmc_priv(mmc); - struct mxs_ssp *ssp = &host->ssp; unsigned long flags; spin_lock_irqsave(&host->lock, flags); @@ -522,22 +624,21 @@ static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) if (enable) { writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); + host->base + HW_SSP_CTRL0 + MXS_SET_ADDR); writel(BM_SSP_CTRL1_SDIO_IRQ_EN, - ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_SET); + host->base + HW_SSP_CTRL1 + MXS_SET_ADDR); + + if (readl(host->base + HW_SSP_STATUS) & BM_SSP_STATUS_SDIO_IRQ) + mmc_signal_sdio_irq(host->mmc); + } else { writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); + host->base + HW_SSP_CTRL0 + MXS_CLR_ADDR); writel(BM_SSP_CTRL1_SDIO_IRQ_EN, - ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); + host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); } spin_unlock_irqrestore(&host->lock, flags); - - if (enable && readl(ssp->base + HW_SSP_STATUS(ssp)) & - BM_SSP_STATUS_SDIO_IRQ) - mmc_signal_sdio_irq(host->mmc); - } static const struct mmc_host_ops mxs_mmc_ops = { @@ -551,126 +652,75 @@ static const struct mmc_host_ops mxs_mmc_ops = { static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param) { struct mxs_mmc_host *host = param; - struct mxs_ssp *ssp = &host->ssp; if (!mxs_dma_is_apbh(chan)) return false; - if (chan->chan_id != ssp->dma_channel) + if (chan->chan_id != host->dma_res->start) return false; - chan->private = &ssp->dma_data; + chan->private = &host->dma_data; return true; } -static struct platform_device_id mxs_ssp_ids[] = { - { - .name = "imx23-mmc", - .driver_data = IMX23_SSP, - }, { - .name = "imx28-mmc", - .driver_data = IMX28_SSP, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(platform, mxs_ssp_ids); - -static const struct of_device_id mxs_mmc_dt_ids[] = { - { .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_SSP, }, - { .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_SSP, }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids); - static int mxs_mmc_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = - of_match_device(mxs_mmc_dt_ids, &pdev->dev); - struct device_node *np = pdev->dev.of_node; struct mxs_mmc_host *host; struct mmc_host *mmc; - struct resource *iores, *dmares; - struct pinctrl *pinctrl; + struct resource *iores, *dmares, *r; + struct mxs_mmc_platform_data *pdata; int ret = 0, irq_err, irq_dma; dma_cap_mask_t mask; - struct regulator *reg_vmmc; - enum of_gpio_flags flags; - struct mxs_ssp *ssp; - u32 bus_width = 0; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); irq_err = platform_get_irq(pdev, 0); irq_dma = platform_get_irq(pdev, 1); - if (!iores || irq_err < 0 || irq_dma < 0) + if (!iores || !dmares || irq_err < 0 || irq_dma < 0) return -EINVAL; + r = request_mem_region(iores->start, resource_size(iores), pdev->name); + if (!r) + return -EBUSY; + mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); - if (!mmc) - return -ENOMEM; + if (!mmc) { + ret = -ENOMEM; + goto out_release_mem; + } host = mmc_priv(mmc); - ssp = &host->ssp; - ssp->dev = &pdev->dev; - ssp->base = devm_request_and_ioremap(&pdev->dev, iores); - if (!ssp->base) { - ret = -EADDRNOTAVAIL; + host->base = ioremap(r->start, resource_size(r)); + if (!host->base) { + ret = -ENOMEM; goto out_mmc_free; } - if (np) { - ssp->devid = (enum mxs_ssp_id) of_id->data; - /* - * TODO: This is a temporary solution and should be changed - * to use generic DMA binding later when the helpers get in. - */ - ret = of_property_read_u32(np, "fsl,ssp-dma-channel", - &ssp->dma_channel); - if (ret) { - dev_err(mmc_dev(host->mmc), - "failed to get dma channel\n"); - goto out_mmc_free; - } - } else { - ssp->devid = pdev->id_entry->driver_data; - ssp->dma_channel = dmares->start; - } + /* only major verion does matter */ + host->version = readl(host->base + HW_SSP_VERSION) >> + BP_SSP_VERSION_MAJOR; host->mmc = mmc; + host->res = r; + host->dma_res = dmares; + host->irq = irq_err; host->sdio_irq_en = 0; - reg_vmmc = devm_regulator_get(&pdev->dev, "vmmc"); - if (!IS_ERR(reg_vmmc)) { - ret = regulator_enable(reg_vmmc); - if (ret) { - dev_err(&pdev->dev, - "Failed to enable vmmc regulator: %d\n", ret); - goto out_mmc_free; - } + host->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); + goto out_iounmap; } - - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - ret = PTR_ERR(pinctrl); - goto out_mmc_free; - } - - ssp->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(ssp->clk)) { - ret = PTR_ERR(ssp->clk); - goto out_mmc_free; - } - clk_prepare_enable(ssp->clk); + clk_enable(host->clk); mxs_mmc_reset(host); dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - ssp->dma_data.chan_irq = irq_dma; - ssp->dmach = dma_request_channel(mask, mxs_mmc_dma_filter, host); - if (!ssp->dmach) { + host->dma_data.chan_irq = irq_dma; + host->dmach = dma_request_channel(mask, mxs_mmc_dma_filter, host); + if (!host->dmach) { dev_err(mmc_dev(host->mmc), "%s: failed to request dma\n", __func__); goto out_clk_put; @@ -681,15 +731,13 @@ static int mxs_mmc_probe(struct platform_device *pdev) mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; - of_property_read_u32(np, "bus-width", &bus_width); - if (bus_width == 4) - mmc->caps |= MMC_CAP_4_BIT_DATA; - else if (bus_width == 8) - mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; - host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags); - - if (flags & OF_GPIO_ACTIVE_LOW) - host->wp_inverted = 1; + pdata = mmc_dev(host->mmc)->platform_data; + if (pdata) { + if (pdata->flags & SLOTF_8_BIT_CAPABLE) + mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; + if (pdata->flags & SLOTF_4_BIT_CAPABLE) + mmc->caps |= MMC_CAP_4_BIT_DATA; + } mmc->f_min = 400000; mmc->f_max = 288000000; @@ -697,14 +745,13 @@ static int mxs_mmc_probe(struct platform_device *pdev) mmc->max_segs = 52; mmc->max_blk_size = 1 << 0xf; - mmc->max_blk_count = (ssp_is_old(ssp)) ? 0xff : 0xffffff; - mmc->max_req_size = (ssp_is_old(ssp)) ? 0xffff : 0xffffffff; - mmc->max_seg_size = dma_get_max_seg_size(ssp->dmach->device->dev); + mmc->max_blk_count = (ssp_is_old()) ? 0xff : 0xffffff; + mmc->max_req_size = (ssp_is_old()) ? 0xffff : 0xffffffff; + mmc->max_seg_size = dma_get_max_seg_size(host->dmach->device->dev); platform_set_drvdata(pdev, mmc); - ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0, - DRIVER_NAME, host); + ret = request_irq(host->irq, mxs_mmc_irq_handler, 0, DRIVER_NAME, host); if (ret) goto out_free_dma; @@ -712,20 +759,26 @@ static int mxs_mmc_probe(struct platform_device *pdev) ret = mmc_add_host(mmc); if (ret) - goto out_free_dma; + goto out_free_irq; dev_info(mmc_dev(host->mmc), "initialized\n"); return 0; +out_free_irq: + free_irq(host->irq, host); out_free_dma: - if (ssp->dmach) - dma_release_channel(ssp->dmach); + if (host->dmach) + dma_release_channel(host->dmach); out_clk_put: - clk_disable_unprepare(ssp->clk); - clk_put(ssp->clk); + clk_disable(host->clk); + clk_put(host->clk); +out_iounmap: + iounmap(host->base); out_mmc_free: mmc_free_host(mmc); +out_release_mem: + release_mem_region(iores->start, resource_size(iores)); return ret; } @@ -733,20 +786,26 @@ static int mxs_mmc_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct mxs_mmc_host *host = mmc_priv(mmc); - struct mxs_ssp *ssp = &host->ssp; + struct resource *res = host->res; mmc_remove_host(mmc); + free_irq(host->irq, host); + platform_set_drvdata(pdev, NULL); - if (ssp->dmach) - dma_release_channel(ssp->dmach); + if (host->dmach) + dma_release_channel(host->dmach); - clk_disable_unprepare(ssp->clk); - clk_put(ssp->clk); + clk_disable(host->clk); + clk_put(host->clk); + + iounmap(host->base); mmc_free_host(mmc); + release_mem_region(res->start, resource_size(res)); + return 0; } @@ -755,12 +814,11 @@ static int mxs_mmc_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct mxs_mmc_host *host = mmc_priv(mmc); - struct mxs_ssp *ssp = &host->ssp; int ret = 0; ret = mmc_suspend_host(mmc); - clk_disable_unprepare(ssp->clk); + clk_disable(host->clk); return ret; } @@ -769,10 +827,9 @@ static int mxs_mmc_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct mxs_mmc_host *host = mmc_priv(mmc); - struct mxs_ssp *ssp = &host->ssp; int ret = 0; - clk_prepare_enable(ssp->clk); + clk_enable(host->clk); ret = mmc_resume_host(mmc); @@ -788,18 +845,27 @@ static const struct dev_pm_ops mxs_mmc_pm_ops = { static struct platform_driver mxs_mmc_driver = { .probe = mxs_mmc_probe, .remove = mxs_mmc_remove, - .id_table = mxs_ssp_ids, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &mxs_mmc_pm_ops, #endif - .of_match_table = mxs_mmc_dt_ids, }, }; -module_platform_driver(mxs_mmc_driver); +static int __init mxs_mmc_init(void) +{ + return platform_driver_register(&mxs_mmc_driver); +} + +static void __exit mxs_mmc_exit(void) +{ + platform_driver_unregister(&mxs_mmc_driver); +} + +module_init(mxs_mmc_init); +module_exit(mxs_mmc_exit); MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral"); MODULE_AUTHOR("Freescale Semiconductor"); diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index 1534b582c41..ab66f2454dc 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c @@ -113,8 +113,8 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) const int j = i * 2; u32 mask; - mask = mmc_vddrange_to_ocrmask(be32_to_cpu(voltage_ranges[j]), - be32_to_cpu(voltage_ranges[j + 1])); + mask = mmc_vddrange_to_ocrmask(voltage_ranges[j], + voltage_ranges[j + 1]); if (!mask) { ret = -EINVAL; dev_err(dev, "OF: voltage-range #%d is invalid\n", i); diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 4254975f931..a6c32904014 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -2,7 +2,7 @@ * linux/drivers/mmc/host/omap.c * * Copyright (C) 2004 Nokia Corporation - * Written by Tuukka Tikkanen and Juha Yrjölä + * Written by Tuukka Tikkanen and Juha Yrjölä * Misc hacks here and there by Tony Lindgren * Other hacks (DMA, SD, etc) by David Brownell * @@ -17,19 +17,26 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include #include +#include #include -#include +#include +#include + +#include +#include +#include +#include +#include +#include #define OMAP_MMC_REG_CMD 0x00 #define OMAP_MMC_REG_ARGL 0x01 @@ -71,13 +78,6 @@ #define OMAP_MMC_STAT_CARD_BUSY (1 << 2) #define OMAP_MMC_STAT_END_OF_CMD (1 << 0) -#define mmc_omap7xx() (host->features & MMC_OMAP7XX) -#define mmc_omap15xx() (host->features & MMC_OMAP15XX) -#define mmc_omap16xx() (host->features & MMC_OMAP16XX) -#define MMC_OMAP1_MASK (MMC_OMAP7XX | MMC_OMAP15XX | MMC_OMAP16XX) -#define mmc_omap1() (host->features & MMC_OMAP1_MASK) -#define mmc_omap2() (!mmc_omap1()) - #define OMAP_MMC_REG(host, reg) (OMAP_MMC_REG_##reg << (host)->reg_shift) #define OMAP_MMC_READ(host, reg) __raw_readw((host)->virt_base + OMAP_MMC_REG(host, reg)) #define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG(host, reg)) @@ -90,16 +90,6 @@ #define OMAP_MMC_CMDTYPE_AC 2 #define OMAP_MMC_CMDTYPE_ADTC 3 -#define OMAP_DMA_MMC_TX 21 -#define OMAP_DMA_MMC_RX 22 -#define OMAP_DMA_MMC2_TX 54 -#define OMAP_DMA_MMC2_RX 55 - -#define OMAP24XX_DMA_MMC2_TX 47 -#define OMAP24XX_DMA_MMC2_RX 48 -#define OMAP24XX_DMA_MMC1_TX 61 -#define OMAP24XX_DMA_MMC1_RX 62 - #define DRIVER_NAME "mmci-omap" @@ -115,6 +105,7 @@ struct mmc_omap_slot { u16 saved_con; u16 bus_mode; unsigned int fclk_freq; + unsigned powered:1; struct tasklet_struct cover_tasklet; struct timer_list cover_timer; @@ -137,15 +128,12 @@ struct mmc_omap_host { unsigned char id; /* 16xx chips have 2 MMC blocks */ struct clk * iclk; struct clk * fclk; - struct dma_chan *dma_rx; - u32 dma_rx_burst; - struct dma_chan *dma_tx; - u32 dma_tx_burst; struct resource *mem_res; void __iomem *virt_base; unsigned int phys_base; int irq; unsigned char bus_mode; + unsigned char hw_bus_mode; unsigned int reg_shift; struct work_struct cmd_abort_work; @@ -163,11 +151,14 @@ struct mmc_omap_host { u32 buffer_bytes_left; u32 total_bytes_left; - unsigned features; unsigned use_dma:1; unsigned brs_received:1, dma_done:1; + unsigned dma_is_read:1; unsigned dma_in_use:1; + int dma_ch; spinlock_t dma_lock; + struct timer_list dma_timer; + unsigned dma_len; struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS]; struct mmc_omap_slot *current_slot; @@ -178,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) { @@ -300,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(host->mmc_omap_wq, &host->slot_release_work); + queue_work(mmc_omap_wq, &host->slot_release_work); return; } @@ -415,25 +406,18 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, int abort) { enum dma_data_direction dma_data_dir; - struct device *dev = mmc_dev(host->mmc); - struct dma_chan *c; - if (data->flags & MMC_DATA_WRITE) { + BUG_ON(host->dma_ch < 0); + if (data->error) + omap_stop_dma(host->dma_ch); + /* Release DMA channel lazily */ + mod_timer(&host->dma_timer, jiffies + HZ); + if (data->flags & MMC_DATA_WRITE) dma_data_dir = DMA_TO_DEVICE; - c = host->dma_tx; - } else { + else dma_data_dir = DMA_FROM_DEVICE; - c = host->dma_rx; - } - if (c) { - if (data->error) { - dmaengine_terminate_all(c); - /* Claim nothing transferred on error... */ - data->bytes_xfered = 0; - } - dev = c->device->dev; - } - dma_unmap_sg(dev, data->sg, host->sg_len, dma_data_dir); + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, + dma_data_dir); } static void mmc_omap_send_stop_work(struct work_struct *work) @@ -475,7 +459,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) } host->stop_data = data; - queue_work(host->mmc_omap_wq, &host->send_stop_work); + queue_work(mmc_omap_wq, &host->send_stop_work); } static void @@ -540,6 +524,16 @@ mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) mmc_omap_xfer_done(host, data); } +static void +mmc_omap_dma_timer(unsigned long data) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) data; + + BUG_ON(host->dma_ch < 0); + omap_free_dma(host->dma_ch); + host->dma_ch = -1; +} + static void mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data) { @@ -645,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(host->mmc_omap_wq, &host->cmd_abort_work); + queue_work(mmc_omap_wq, &host->cmd_abort_work); } spin_unlock_irqrestore(&host->slot_lock, flags); } @@ -675,7 +669,7 @@ mmc_omap_clk_timer(unsigned long data) static void mmc_omap_xfer_data(struct mmc_omap_host *host, int write) { - int n, nwords; + int n; if (host->buffer_bytes_left == 0) { host->sg_idx++; @@ -685,48 +679,33 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write) n = 64; if (n > host->buffer_bytes_left) n = host->buffer_bytes_left; - - nwords = n / 2; - nwords += n & 1; /* handle odd number of bytes to transfer */ - host->buffer_bytes_left -= n; host->total_bytes_left -= n; host->data->bytes_xfered += n; if (write) { - __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), - host->buffer, nwords); + __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n); } else { - __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), - host->buffer, nwords); + __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n); } - - host->buffer += nwords; } -#ifdef CONFIG_MMC_DEBUG -static void mmc_omap_report_irq(struct mmc_omap_host *host, u16 status) +static inline void mmc_omap_report_irq(u16 status) { static const char *mmc_omap_status_bits[] = { "EOC", "CD", "CB", "BRS", "EOFB", "DTO", "DCRC", "CTO", "CCRC", "CRW", "AF", "AE", "OCRB", "CIRQ", "CERR" }; - int i; - char res[64], *buf = res; - - buf += sprintf(buf, "MMC IRQ 0x%x:", status); + int i, c = 0; for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++) - if (status & (1 << i)) - buf += sprintf(buf, " %s", mmc_omap_status_bits[i]); - dev_vdbg(mmc_dev(host->mmc), "%s\n", res); -} -#else -static void mmc_omap_report_irq(struct mmc_omap_host *host, u16 status) -{ + if (status & (1 << i)) { + if (c) + printk(" "); + printk("%s", mmc_omap_status_bits[i]); + c++; + } } -#endif - static irqreturn_t mmc_omap_irq(int irq, void *dev_id) { @@ -760,10 +739,12 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) cmd = host->cmd->opcode; else cmd = -1; +#ifdef CONFIG_MMC_DEBUG dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ", status, cmd); - mmc_omap_report_irq(host, status); - + mmc_omap_report_irq(status); + printk("\n"); +#endif if (host->total_bytes_left) { if ((status & OMAP_MMC_STAT_A_FULL) || (status & OMAP_MMC_STAT_END_OF_DATA)) @@ -847,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(host->mmc_omap_wq, &host->cmd_abort_work); + queue_work(mmc_omap_wq, &host->cmd_abort_work); return IRQ_HANDLED; } @@ -910,15 +891,159 @@ static void mmc_omap_cover_handler(unsigned long param) jiffies + msecs_to_jiffies(OMAP_MMC_COVER_POLL_DELAY)); } -static void mmc_omap_dma_callback(void *priv) +/* Prepare to transfer the next segment of a scatterlist */ +static void +mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) { - struct mmc_omap_host *host = priv; - struct mmc_data *data = host->data; + int dma_ch = host->dma_ch; + unsigned long data_addr; + u16 buf, frame; + u32 count; + struct scatterlist *sg = &data->sg[host->sg_idx]; + int src_port = 0; + int dst_port = 0; + int sync_dev = 0; + + data_addr = host->phys_base + OMAP_MMC_REG(host, DATA); + frame = data->blksz; + count = sg_dma_len(sg); + + if ((data->blocks == 1) && (count > data->blksz)) + count = frame; + + host->dma_len = count; + + /* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx. + * Use 16 or 32 word frames when the blocksize is at least that large. + * Blocksize is usually 512 bytes; but not for some SD reads. + */ + if (cpu_is_omap15xx() && frame > 32) + frame = 32; + else if (frame > 64) + frame = 64; + count /= frame; + frame >>= 1; + + if (!(data->flags & MMC_DATA_WRITE)) { + buf = 0x800f | ((frame - 1) << 8); + + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_TIPB; + dst_port = OMAP_DMA_PORT_EMIFF; + } + if (cpu_is_omap24xx()) + sync_dev = OMAP24XX_DMA_MMC1_RX; + + omap_set_dma_src_params(dma_ch, src_port, + OMAP_DMA_AMODE_CONSTANT, + data_addr, 0, 0); + omap_set_dma_dest_params(dma_ch, dst_port, + OMAP_DMA_AMODE_POST_INC, + sg_dma_address(sg), 0, 0); + omap_set_dma_dest_data_pack(dma_ch, 1); + omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); + } else { + buf = 0x0f80 | ((frame - 1) << 0); + + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_EMIFF; + dst_port = OMAP_DMA_PORT_TIPB; + } + if (cpu_is_omap24xx()) + sync_dev = OMAP24XX_DMA_MMC1_TX; + + omap_set_dma_dest_params(dma_ch, dst_port, + OMAP_DMA_AMODE_CONSTANT, + data_addr, 0, 0); + omap_set_dma_src_params(dma_ch, src_port, + OMAP_DMA_AMODE_POST_INC, + sg_dma_address(sg), 0, 0); + omap_set_dma_src_data_pack(dma_ch, 1); + omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); + } - /* If we got to the end of DMA, assume everything went well */ - data->bytes_xfered += data->blocks * data->blksz; + /* Max limit for DMA frame count is 0xffff */ + BUG_ON(count > 0xffff); + + OMAP_MMC_WRITE(host, BUF, buf); + omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16, + frame, count, OMAP_DMA_SYNC_FRAME, + sync_dev, 0); +} + +/* A scatterlist segment completed */ +static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) data; + struct mmc_data *mmcdat = host->data; + + if (unlikely(host->dma_ch < 0)) { + dev_err(mmc_dev(host->mmc), + "DMA callback while DMA not enabled\n"); + return; + } + /* FIXME: We really should do something to _handle_ the errors */ + if (ch_status & OMAP1_DMA_TOUT_IRQ) { + dev_err(mmc_dev(host->mmc),"DMA timeout\n"); + return; + } + if (ch_status & OMAP_DMA_DROP_IRQ) { + dev_err(mmc_dev(host->mmc), "DMA sync error\n"); + return; + } + if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { + return; + } + mmcdat->bytes_xfered += host->dma_len; + host->sg_idx++; + if (host->sg_idx < host->sg_len) { + mmc_omap_prepare_dma(host, host->data); + omap_start_dma(host->dma_ch); + } else + mmc_omap_dma_done(host, host->data); +} + +static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data) +{ + const char *dma_dev_name; + int sync_dev, dma_ch, is_read, r; + + is_read = !(data->flags & MMC_DATA_WRITE); + del_timer_sync(&host->dma_timer); + if (host->dma_ch >= 0) { + if (is_read == host->dma_is_read) + return 0; + omap_free_dma(host->dma_ch); + host->dma_ch = -1; + } + + if (is_read) { + if (host->id == 0) { + sync_dev = OMAP_DMA_MMC_RX; + dma_dev_name = "MMC1 read"; + } else { + sync_dev = OMAP_DMA_MMC2_RX; + dma_dev_name = "MMC2 read"; + } + } else { + if (host->id == 0) { + sync_dev = OMAP_DMA_MMC_TX; + dma_dev_name = "MMC1 write"; + } else { + sync_dev = OMAP_DMA_MMC2_TX; + dma_dev_name = "MMC2 write"; + } + } + r = omap_request_dma(sync_dev, dma_dev_name, mmc_omap_dma_cb, + host, &dma_ch); + if (r != 0) { + dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r); + return r; + } + host->dma_ch = dma_ch; + host->dma_is_read = is_read; - mmc_omap_dma_done(host, data); + return 0; } static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req) @@ -993,85 +1118,33 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) host->sg_idx = 0; if (use_dma) { - enum dma_data_direction dma_data_dir; - struct dma_async_tx_descriptor *tx; - struct dma_chan *c; - u32 burst, *bp; - u16 buf; - - /* - * FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx - * and 24xx. Use 16 or 32 word frames when the - * blocksize is at least that large. Blocksize is - * usually 512 bytes; but not for some SD reads. - */ - burst = mmc_omap15xx() ? 32 : 64; - if (burst > data->blksz) - burst = data->blksz; - - burst >>= 1; - - if (data->flags & MMC_DATA_WRITE) { - c = host->dma_tx; - bp = &host->dma_tx_burst; - buf = 0x0f80 | (burst - 1) << 0; - dma_data_dir = DMA_TO_DEVICE; - } else { - c = host->dma_rx; - bp = &host->dma_rx_burst; - buf = 0x800f | (burst - 1) << 8; - dma_data_dir = DMA_FROM_DEVICE; - } - - if (!c) - goto use_pio; - - /* Only reconfigure if we have a different burst size */ - if (*bp != burst) { - struct dma_slave_config cfg; - - cfg.src_addr = host->phys_base + OMAP_MMC_REG(host, DATA); - cfg.dst_addr = host->phys_base + OMAP_MMC_REG(host, DATA); - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - cfg.src_maxburst = burst; - cfg.dst_maxburst = burst; - - if (dmaengine_slave_config(c, &cfg)) - goto use_pio; - - *bp = burst; - } - - host->sg_len = dma_map_sg(c->device->dev, data->sg, sg_len, - dma_data_dir); - if (host->sg_len == 0) - goto use_pio; - - tx = dmaengine_prep_slave_sg(c, data->sg, host->sg_len, - data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!tx) - goto use_pio; - - OMAP_MMC_WRITE(host, BUF, buf); - - tx->callback = mmc_omap_dma_callback; - tx->callback_param = host; - dmaengine_submit(tx); - host->brs_received = 0; - host->dma_done = 0; - host->dma_in_use = 1; - return; + if (mmc_omap_get_dma_channel(host, data) == 0) { + enum dma_data_direction dma_data_dir; + + if (data->flags & MMC_DATA_WRITE) + dma_data_dir = DMA_TO_DEVICE; + else + dma_data_dir = DMA_FROM_DEVICE; + + host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, + sg_len, dma_data_dir); + host->total_bytes_left = 0; + mmc_omap_prepare_dma(host, req->data); + host->brs_received = 0; + host->dma_done = 0; + host->dma_in_use = 1; + } else + use_dma = 0; } - use_pio: /* Revert to PIO? */ - OMAP_MMC_WRITE(host, BUF, 0x1f1f); - host->total_bytes_left = data->blocks * block_size; - host->sg_len = sg_len; - mmc_omap_sg_to_buf(host); - host->dma_in_use = 0; + if (!use_dma) { + OMAP_MMC_WRITE(host, BUF, 0x1f1f); + host->total_bytes_left = data->blocks * block_size; + host->sg_len = sg_len; + mmc_omap_sg_to_buf(host); + host->dma_in_use = 0; + } } static void mmc_omap_start_request(struct mmc_omap_host *host, @@ -1084,12 +1157,8 @@ static void mmc_omap_start_request(struct mmc_omap_host *host, /* only touch fifo AFTER the controller readies it */ mmc_omap_prepare_data(host, req); mmc_omap_start_command(host, req->cmd); - if (host->dma_in_use) { - struct dma_chan *c = host->data->flags & MMC_DATA_WRITE ? - host->dma_tx : host->dma_rx; - - dma_async_issue_pending(c); - } + if (host->dma_in_use) + omap_start_dma(host->dma_ch); } static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req) @@ -1121,7 +1190,8 @@ static void mmc_omap_set_power(struct mmc_omap_slot *slot, int power_on, if (slot->pdata->set_power != NULL) slot->pdata->set_power(mmc_dev(slot->mmc), slot->id, power_on, vdd); - if (mmc_omap2()) { + + if (cpu_is_omap24xx()) { u16 w; if (power_on) { @@ -1230,7 +1300,7 @@ static const struct mmc_host_ops mmc_omap_ops = { .set_ios = mmc_omap_set_ios, }; -static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) +static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id) { struct mmc_omap_slot *slot = NULL; struct mmc_host *mmc; @@ -1255,7 +1325,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; - if (mmc_omap2()) + if (cpu_class_is_omap2()) mmc->f_max = 48000000; else mmc->f_max = 24000000; @@ -1319,19 +1389,17 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot) tasklet_kill(&slot->cover_tasklet); del_timer_sync(&slot->cover_timer); - flush_workqueue(slot->host->mmc_omap_wq); + flush_workqueue(mmc_omap_wq); mmc_remove_host(mmc); mmc_free_host(mmc); } -static int mmc_omap_probe(struct platform_device *pdev) +static int __init mmc_omap_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_omap_host *host = NULL; struct resource *res; - dma_cap_mask_t mask; - unsigned sig; int i, ret = 0; int irq; @@ -1371,18 +1439,22 @@ static int mmc_omap_probe(struct platform_device *pdev) setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host); spin_lock_init(&host->dma_lock); + setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host); spin_lock_init(&host->slot_lock); init_waitqueue_head(&host->slot_wq); host->pdata = pdata; - host->features = host->pdata->slots[0].features; host->dev = &pdev->dev; platform_set_drvdata(pdev, host); host->id = pdev->id; host->mem_res = res; host->irq = irq; + host->use_dma = 1; + host->dev->dma_mask = &pdata->dma_mask; + host->dma_ch = -1; + host->irq = irq; host->phys_base = host->mem_res->start; host->virt_base = ioremap(res->start, resource_size(res)); @@ -1402,48 +1474,9 @@ static int mmc_omap_probe(struct platform_device *pdev) goto err_free_iclk; } - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->dma_tx_burst = -1; - host->dma_rx_burst = -1; - - if (mmc_omap2()) - sig = host->id == 0 ? OMAP24XX_DMA_MMC1_TX : OMAP24XX_DMA_MMC2_TX; - else - sig = host->id == 0 ? OMAP_DMA_MMC_TX : OMAP_DMA_MMC2_TX; - host->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig); -#if 0 - if (!host->dma_tx) { - dev_err(host->dev, "unable to obtain TX DMA engine channel %u\n", - sig); - goto err_dma; - } -#else - if (!host->dma_tx) - dev_warn(host->dev, "unable to obtain TX DMA engine channel %u\n", - sig); -#endif - if (mmc_omap2()) - sig = host->id == 0 ? OMAP24XX_DMA_MMC1_RX : OMAP24XX_DMA_MMC2_RX; - else - sig = host->id == 0 ? OMAP_DMA_MMC_RX : OMAP_DMA_MMC2_RX; - host->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig); -#if 0 - if (!host->dma_rx) { - dev_err(host->dev, "unable to obtain RX DMA engine channel %u\n", - sig); - goto err_dma; - } -#else - if (!host->dma_rx) - dev_warn(host->dev, "unable to obtain RX DMA engine channel %u\n", - sig); -#endif - ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host); if (ret) - goto err_free_dma; + goto err_free_fclk; if (pdata->init != NULL) { ret = pdata->init(&pdev->dev); @@ -1452,36 +1485,26 @@ static int mmc_omap_probe(struct platform_device *pdev) } host->nr_slots = pdata->nr_slots; - host->reg_shift = (mmc_omap7xx() ? 1 : 2); - - host->mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0); - if (!host->mmc_omap_wq) - goto err_plat_cleanup; - for (i = 0; i < pdata->nr_slots; i++) { ret = mmc_omap_new_slot(host, i); if (ret < 0) { while (--i >= 0) mmc_omap_remove_slot(host->slots[i]); - goto err_destroy_wq; + goto err_plat_cleanup; } } + host->reg_shift = (cpu_is_omap7xx() ? 1 : 2); + return 0; -err_destroy_wq: - destroy_workqueue(host->mmc_omap_wq); err_plat_cleanup: if (pdata->cleanup) pdata->cleanup(&pdev->dev); err_free_irq: free_irq(host->irq, host); -err_free_dma: - if (host->dma_tx) - dma_release_channel(host->dma_tx); - if (host->dma_rx) - dma_release_channel(host->dma_rx); +err_free_fclk: clk_put(host->fclk); err_free_iclk: clk_disable(host->iclk); @@ -1516,15 +1539,9 @@ static int mmc_omap_remove(struct platform_device *pdev) clk_disable(host->iclk); clk_put(host->iclk); - if (host->dma_tx) - dma_release_channel(host->dma_tx); - if (host->dma_rx) - dma_release_channel(host->dma_rx); - 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); @@ -1582,7 +1599,6 @@ static int mmc_omap_resume(struct platform_device *pdev) #endif static struct platform_driver mmc_omap_driver = { - .probe = mmc_omap_probe, .remove = mmc_omap_remove, .suspend = mmc_omap_suspend, .resume = mmc_omap_resume, @@ -1592,8 +1608,30 @@ static struct platform_driver mmc_omap_driver = { }, }; -module_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_DESCRIPTION("OMAP Multimedia Card driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME); -MODULE_AUTHOR("Juha Yrjölä"); +MODULE_AUTHOR("Juha Yrjölä"); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index bc5807873b2..21e4a799df4 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -19,29 +19,30 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include -#include -#include -#include -#include #include #include #include #include +#include #include #include -#include #include -#include +#include +#include +#include +#include +#include /* OMAP HSMMC Host Controller Registers */ +#define OMAP_HSMMC_SYSCONFIG 0x0010 #define OMAP_HSMMC_SYSSTATUS 0x0014 #define OMAP_HSMMC_CON 0x002C #define OMAP_HSMMC_BLK 0x0104 @@ -61,7 +62,6 @@ #define VS18 (1 << 26) #define VS30 (1 << 25) -#define HSS (1 << 21) #define SDVS18 (0x5 << 9) #define SDVS30 (0x6 << 9) #define SDVS33 (0x7 << 9) @@ -78,17 +78,27 @@ #define CLKD_SHIFT 6 #define DTO_MASK 0x000F0000 #define DTO_SHIFT 16 +#define INT_EN_MASK 0x307F0033 +#define BWR_ENABLE (1 << 4) +#define BRR_ENABLE (1 << 5) +#define DTO_ENABLE (1 << 20) #define INIT_STREAM (1 << 1) #define DP_SELECT (1 << 21) #define DDIR (1 << 4) -#define DMAE 0x1 +#define DMA_EN 0x1 #define MSBS (1 << 5) #define BCE (1 << 1) #define FOUR_BIT (1 << 1) -#define HSPE (1 << 2) -#define DDR (1 << 19) #define DW8 (1 << 5) +#define CC 0x1 +#define TC 0x02 #define OD 0x1 +#define ERR (1 << 15) +#define CMD_TIMEOUT (1 << 16) +#define DATA_TIMEOUT (1 << 20) +#define CMD_CRC (1 << 17) +#define DATA_CRC (1 << 21) +#define CARD_ERR (1 << 28) #define STAT_CLEAR 0xFFFFFFFF #define INIT_STREAM_CMD 0x00000000 #define DUAL_VOLT_OCR_BIT 7 @@ -97,28 +107,20 @@ #define SOFTRESET (1 << 1) #define RESETDONE (1 << 0) -/* Interrupt masks for IE and ISE register */ -#define CC_EN (1 << 0) -#define TC_EN (1 << 1) -#define BWR_EN (1 << 4) -#define BRR_EN (1 << 5) -#define ERR_EN (1 << 15) -#define CTO_EN (1 << 16) -#define CCRC_EN (1 << 17) -#define CEB_EN (1 << 18) -#define CIE_EN (1 << 19) -#define DTO_EN (1 << 20) -#define DCRC_EN (1 << 21) -#define DEB_EN (1 << 22) -#define CERR_EN (1 << 28) -#define BADA_EN (1 << 29) - -#define INT_EN_MASK (BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\ - DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \ - BRR_EN | BWR_EN | TC_EN | CC_EN) +/* + * FIXME: Most likely all the data using these _DEVID defines should come + * from the platform_data, or implemented in controller and slot specific + * functions. + */ +#define OMAP_MMC1_DEVID 0 +#define OMAP_MMC2_DEVID 1 +#define OMAP_MMC3_DEVID 2 +#define OMAP_MMC4_DEVID 3 +#define OMAP_MMC5_DEVID 4 #define MMC_AUTOSUSPEND_DELAY 100 #define MMC_TIMEOUT_MS 20 +#define OMAP_MMC_MASTER_CLOCK 96000000 #define OMAP_MMC_MIN_CLOCK 400000 #define OMAP_MMC_MAX_CLOCK 52000000 #define DRIVER_NAME "omap_hsmmc" @@ -161,21 +163,27 @@ struct omap_hsmmc_host { */ struct regulator *vcc; struct regulator *vcc_aux; + struct work_struct mmc_carddetect_work; void __iomem *base; resource_size_t mapbase; spinlock_t irq_lock; /* Prevent races with irq handler */ + unsigned int id; unsigned int dma_len; unsigned int dma_sg_idx; unsigned char bus_mode; unsigned char power_mode; + u32 *buffer; + u32 bytesleft; int suspended; int irq; int use_dma, dma_ch; - struct dma_chan *tx_chan; - struct dma_chan *rx_chan; + int dma_line_tx, dma_line_rx; int slot_id; + int got_dbclk; int response_busy; int context_loss; + int dpm_state; + int vdd; int protect_card; int reqs_blocked; int use_reg; @@ -187,8 +195,7 @@ struct omap_hsmmc_host { static int omap_hsmmc_card_detect(struct device *dev, int slot) { - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; + struct omap_mmc_platform_data *mmc = dev->platform_data; /* NOTE: assumes card detect signal is active-low */ return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); @@ -196,8 +203,7 @@ static int omap_hsmmc_card_detect(struct device *dev, int slot) static int omap_hsmmc_get_wp(struct device *dev, int slot) { - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; + struct omap_mmc_platform_data *mmc = dev->platform_data; /* NOTE: assumes write protect signal is active-high */ return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); @@ -205,8 +211,7 @@ static int omap_hsmmc_get_wp(struct device *dev, int slot) static int omap_hsmmc_get_cover_state(struct device *dev, int slot) { - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; + struct omap_mmc_platform_data *mmc = dev->platform_data; /* NOTE: assumes card detect signal is active-low */ return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); @@ -216,8 +221,7 @@ static int omap_hsmmc_get_cover_state(struct device *dev, int slot) static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) { - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; + struct omap_mmc_platform_data *mmc = dev->platform_data; disable_irq(mmc->slots[0].card_detect_irq); return 0; @@ -225,8 +229,7 @@ static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) { - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; + struct omap_mmc_platform_data *mmc = dev->platform_data; enable_irq(mmc->slots[0].card_detect_irq); return 0; @@ -241,7 +244,28 @@ static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) #ifdef CONFIG_REGULATOR -static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, +static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + struct omap_hsmmc_host *host = + platform_get_drvdata(to_platform_device(dev)); + int ret; + + if (mmc_slot(host).before_set_reg) + mmc_slot(host).before_set_reg(dev, slot, power_on, vdd); + + if (power_on) + ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); + else + ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0); + + if (mmc_slot(host).after_set_reg) + mmc_slot(host).after_set_reg(dev, slot, power_on, vdd); + + return ret; +} + +static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on, int vdd) { struct omap_hsmmc_host *host = @@ -254,13 +278,6 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, */ if (!host->vcc) return 0; - /* - * With DT, never turn OFF the regulator. This is because - * the pbias cell programming support is still missing when - * booting with Device tree - */ - if (dev->of_node && !vdd) - return 0; if (mmc_slot(host).before_set_reg) mmc_slot(host).before_set_reg(dev, slot, power_on, vdd); @@ -304,25 +321,115 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, return ret; } +static int omap_hsmmc_4_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + return 0; +} + +static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep, + int vdd, int cardsleep) +{ + struct omap_hsmmc_host *host = + platform_get_drvdata(to_platform_device(dev)); + int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL; + + return regulator_set_mode(host->vcc, mode); +} + +static int omap_hsmmc_235_set_sleep(struct device *dev, int slot, int sleep, + int vdd, int cardsleep) +{ + struct omap_hsmmc_host *host = + platform_get_drvdata(to_platform_device(dev)); + int err, mode; + + /* + * If we don't see a Vcc regulator, assume it's a fixed + * voltage always-on regulator. + */ + if (!host->vcc) + return 0; + + mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL; + + if (!host->vcc_aux) + return regulator_set_mode(host->vcc, mode); + + if (cardsleep) { + /* VCC can be turned off if card is asleep */ + if (sleep) + err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0); + else + err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); + } else + err = regulator_set_mode(host->vcc, mode); + if (err) + return err; + + if (!mmc_slot(host).vcc_aux_disable_is_sleep) + return regulator_set_mode(host->vcc_aux, mode); + + if (sleep) + return regulator_disable(host->vcc_aux); + else + return regulator_enable(host->vcc_aux); +} + +static int omap_hsmmc_4_set_sleep(struct device *dev, int slot, int sleep, + int vdd, int cardsleep) +{ + return 0; +} + static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { struct regulator *reg; + int ret = 0; int ocr_value = 0; + switch (host->id) { + case OMAP_MMC1_DEVID: + /* On-chip level shifting via PBIAS0/PBIAS1 */ + mmc_slot(host).set_power = omap_hsmmc_1_set_power; + mmc_slot(host).set_sleep = omap_hsmmc_1_set_sleep; + break; + case OMAP_MMC2_DEVID: + case OMAP_MMC3_DEVID: + case OMAP_MMC5_DEVID: + /* Off-chip level shifting, or none */ + mmc_slot(host).set_power = omap_hsmmc_235_set_power; + mmc_slot(host).set_sleep = omap_hsmmc_235_set_sleep; + break; + case OMAP_MMC4_DEVID: + mmc_slot(host).set_power = omap_hsmmc_4_set_power; + mmc_slot(host).set_sleep = omap_hsmmc_4_set_sleep; + default: + pr_err("MMC%d configuration not supported!\n", host->id); + return -EINVAL; + } + reg = regulator_get(host->dev, "vmmc"); if (IS_ERR(reg)) { - dev_err(host->dev, "vmmc regulator missing\n"); - return PTR_ERR(reg); + dev_dbg(host->dev, "vmmc regulator missing\n"); + /* + * HACK: until fixed.c regulator is usable, + * we don't require a main regulator + * for MMC2 or MMC3 + */ + if (host->id == OMAP_MMC1_DEVID) { + ret = PTR_ERR(reg); + goto err; + } } else { - mmc_slot(host).set_power = omap_hsmmc_set_power; host->vcc = reg; ocr_value = mmc_regulator_get_ocrmask(reg); if (!mmc_slot(host).ocr_mask) { mmc_slot(host).ocr_mask = ocr_value; } else { if (!(mmc_slot(host).ocr_mask & ocr_value)) { - dev_err(host->dev, "ocrmask %x is not supported\n", - mmc_slot(host).ocr_mask); + pr_err("MMC%d ocrmask %x is not supported\n", + host->id, mmc_slot(host).ocr_mask); mmc_slot(host).ocr_mask = 0; return -EINVAL; } @@ -343,18 +450,24 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) * framework is fixed, we need a workaround like this * (which is safe for MMC, but not in general). */ - if (regulator_is_enabled(host->vcc) > 0 || - (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { - int vdd = ffs(mmc_slot(host).ocr_mask) - 1; - - mmc_slot(host).set_power(host->dev, host->slot_id, - 1, vdd); - mmc_slot(host).set_power(host->dev, host->slot_id, - 0, 0); + if (regulator_is_enabled(host->vcc) > 0) { + regulator_enable(host->vcc); + regulator_disable(host->vcc); + } + if (host->vcc_aux) { + if (regulator_is_enabled(reg) > 0) { + regulator_enable(reg); + regulator_disable(reg); + } } } return 0; + +err: + mmc_slot(host).set_power = NULL; + mmc_slot(host).set_sleep = NULL; + return ret; } static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) @@ -362,6 +475,7 @@ static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) regulator_put(host->vcc); regulator_put(host->vcc_aux); mmc_slot(host).set_power = NULL; + mmc_slot(host).set_sleep = NULL; } static inline int omap_hsmmc_have_reg(void) @@ -455,7 +569,7 @@ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host) OMAP_HSMMC_WRITE(host->base, SYSCTL, OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN); if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0) - dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stopped\n"); + dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n"); } static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, @@ -464,13 +578,13 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, unsigned int irq_mask; if (host->use_dma) - irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN); + irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE); else irq_mask = INT_EN_MASK; /* Disable timeout for erases */ if (cmd->opcode == MMC_ERASE) - irq_mask &= ~DTO_EN; + irq_mask &= ~DTO_ENABLE; OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); OMAP_HSMMC_WRITE(host->base, ISE, irq_mask); @@ -485,12 +599,12 @@ static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host) } /* Calculate divisor for the given clock frequency */ -static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios) +static u16 calc_divisor(struct mmc_ios *ios) { u16 dsor = 0; if (ios->clock) { - dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock); + dsor = DIV_ROUND_UP(OMAP_MMC_MASTER_CLOCK, ios->clock); if (dsor > 250) dsor = 250; } @@ -503,16 +617,14 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) struct mmc_ios *ios = &host->mmc->ios; unsigned long regval; unsigned long timeout; - unsigned long clkdiv; - dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock); + dev_dbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock); omap_hsmmc_stop_clock(host); regval = OMAP_HSMMC_READ(host->base, SYSCTL); regval = regval & ~(CLKD_MASK | DTO_MASK); - clkdiv = calc_divisor(host, ios); - regval = regval | (clkdiv << 6) | (DTO << 16); + regval = regval | (calc_divisor(ios) << 6) | (DTO << 16); OMAP_HSMMC_WRITE(host->base, SYSCTL, regval); OMAP_HSMMC_WRITE(host->base, SYSCTL, OMAP_HSMMC_READ(host->base, SYSCTL) | ICE); @@ -523,27 +635,6 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) && time_before(jiffies, timeout)) cpu_relax(); - /* - * Enable High-Speed Support - * Pre-Requisites - * - Controller should support High-Speed-Enable Bit - * - Controller should not be using DDR Mode - * - Controller should advertise that it supports High Speed - * in capabilities register - * - MMC/SD clock coming out of controller > 25MHz - */ - if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) && - (ios->timing != MMC_TIMING_UHS_DDR50) && - ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) { - regval = OMAP_HSMMC_READ(host->base, HCTL); - if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000) - regval |= HSPE; - else - regval &= ~HSPE; - - OMAP_HSMMC_WRITE(host->base, HCTL, regval); - } - omap_hsmmc_start_clock(host); } @@ -553,10 +644,6 @@ 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); @@ -611,10 +698,23 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) if (host->context_loss == context_loss) return 1; - if (!OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) - return 1; + /* Wait for hardware reset */ + timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); + while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE + && time_before(jiffies, timeout)) + ; - if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) { + /* Do software reset */ + OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET); + timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); + while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE + && time_before(jiffies, timeout)) + ; + + OMAP_HSMMC_WRITE(host->base, SYSCONFIG, + OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE); + + if (host->id == OMAP_MMC1_DEVID) { if (host->power_mode != MMC_POWER_OFF && (1 << ios->vdd) <= MMC_VDD_23_24) hctl = SDVS18; @@ -708,8 +808,8 @@ static void send_init_stream(struct omap_hsmmc_host *host) OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD); timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); - while ((reg != CC_EN) && time_before(jiffies, timeout)) - reg = OMAP_HSMMC_READ(host->base, STAT) & CC_EN; + while ((reg != CC) && time_before(jiffies, timeout)) + reg = OMAP_HSMMC_READ(host->base, STAT) & CC; OMAP_HSMMC_WRITE(host->base, CON, OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM); @@ -764,7 +864,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, { int cmdreg = 0, resptype = 0, cmdtype = 0; - dev_vdbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n", + dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n", mmc_hostname(host->mmc), cmd->opcode, cmd->arg); host->cmd = cmd; @@ -800,7 +900,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, } if (host->use_dma) - cmdreg |= DMAE; + cmdreg |= DMA_EN; host->req_in_progress = 1; @@ -817,21 +917,14 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data) return DMA_FROM_DEVICE; } -static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host, - struct mmc_data *data) -{ - return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan; -} - static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) { int dma_ch; - unsigned long flags; - spin_lock_irqsave(&host->irq_lock, flags); + spin_lock(&host->irq_lock); host->req_in_progress = 0; dma_ch = host->dma_ch; - spin_unlock_irqrestore(&host->irq_lock, flags); + spin_unlock(&host->irq_lock); omap_hsmmc_disable_irq(host); /* Do not complete the request if DMA is still in progress */ @@ -905,24 +998,19 @@ 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_irqsave(&host->irq_lock, flags); + spin_lock(&host->irq_lock); dma_ch = host->dma_ch; host->dma_ch = -1; - spin_unlock_irqrestore(&host->irq_lock, flags); + spin_unlock(&host->irq_lock); if (host->use_dma && dma_ch != -1) { - struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host->data); - - dmaengine_terminate_all(chan); - dma_unmap_sg(chan->device->dev, - host->data->sg, host->data->sg_len, + dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, + host->data->sg_len, omap_hsmmc_get_dma_dir(host, host->data)); - - host->data->host_cookie = 0; + omap_free_dma(dma_ch); } host->data = NULL; } @@ -953,7 +1041,7 @@ static void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, u32 status) buf += len; } - dev_vdbg(mmc_dev(host->mmc), "%s\n", res); + dev_dbg(mmc_dev(host->mmc), "%s\n", res); } #else static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, @@ -1000,49 +1088,75 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, __func__); } -static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, - int err, int end_cmd) -{ - if (end_cmd) { - omap_hsmmc_reset_controller_fsm(host, SRC); - if (host->cmd) - host->cmd->error = err; - } - - if (host->data) { - omap_hsmmc_reset_controller_fsm(host, SRD); - omap_hsmmc_dma_cleanup(host, err); - } else if (host->mrq && host->mrq->cmd) - host->mrq->cmd->error = err; -} - static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) { struct mmc_data *data; int end_cmd = 0, end_trans = 0; + if (!host->req_in_progress) { + do { + OMAP_HSMMC_WRITE(host->base, STAT, status); + /* Flush posted write */ + status = OMAP_HSMMC_READ(host->base, STAT); + } while (status & INT_EN_MASK); + return; + } + data = host->data; - dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status); + dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status); - if (status & ERR_EN) { + if (status & ERR) { omap_hsmmc_dbg_report_irq(host, status); - - if (status & (CTO_EN | CCRC_EN)) - end_cmd = 1; - if (status & (CTO_EN | DTO_EN)) - hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd); - else if (status & (CCRC_EN | DCRC_EN)) - hsmmc_command_incomplete(host, -EILSEQ, end_cmd); - - if (host->data || host->response_busy) { - end_trans = !end_cmd; - host->response_busy = 0; + if ((status & CMD_TIMEOUT) || + (status & CMD_CRC)) { + if (host->cmd) { + if (status & CMD_TIMEOUT) { + omap_hsmmc_reset_controller_fsm(host, + SRC); + host->cmd->error = -ETIMEDOUT; + } else { + host->cmd->error = -EILSEQ; + } + end_cmd = 1; + } + if (host->data || host->response_busy) { + if (host->data) + omap_hsmmc_dma_cleanup(host, + -ETIMEDOUT); + host->response_busy = 0; + omap_hsmmc_reset_controller_fsm(host, SRD); + } + } + if ((status & DATA_TIMEOUT) || + (status & DATA_CRC)) { + if (host->data || host->response_busy) { + int err = (status & DATA_TIMEOUT) ? + -ETIMEDOUT : -EILSEQ; + + if (host->data) + omap_hsmmc_dma_cleanup(host, err); + else + host->mrq->cmd->error = err; + host->response_busy = 0; + omap_hsmmc_reset_controller_fsm(host, SRD); + end_trans = 1; + } + } + if (status & CARD_ERR) { + dev_dbg(mmc_dev(host->mmc), + "Ignoring card err CMD%d\n", host->cmd->opcode); + if (host->cmd) + end_cmd = 1; + if (host->data) + end_trans = 1; } } - if (end_cmd || ((status & CC_EN) && host->cmd)) + OMAP_HSMMC_WRITE(host->base, STAT, status); + + if (end_cmd || ((status & CC) && host->cmd)) omap_hsmmc_cmd_done(host, host->cmd); - if ((end_trans || (status & TC_EN)) && host->mrq) + if ((end_trans || (status & TC)) && host->mrq) omap_hsmmc_xfer_done(host, data); } @@ -1055,13 +1169,11 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) int status; status = OMAP_HSMMC_READ(host->base, STAT); - while (status & INT_EN_MASK && host->req_in_progress) { + do { omap_hsmmc_do_irq(host, status); - /* Flush posted write */ - OMAP_HSMMC_WRITE(host->base, STAT, status); status = OMAP_HSMMC_READ(host->base, STAT); - } + } while (status & INT_EN_MASK); return IRQ_HANDLED; } @@ -1093,8 +1205,8 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) /* Disable the clocks */ pm_runtime_put_sync(host->dev); - if (host->dbclk) - clk_disable_unprepare(host->dbclk); + if (host->got_dbclk) + clk_disable(host->dbclk); /* Turn the power off */ ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); @@ -1104,8 +1216,8 @@ 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->dbclk) - clk_prepare_enable(host->dbclk); + if (host->got_dbclk) + clk_enable(host->dbclk); if (ret != 0) goto err; @@ -1139,7 +1251,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) return 0; err: - dev_err(mmc_dev(host->mmc), "Unable to switch operating voltage\n"); + dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n"); return ret; } @@ -1152,14 +1264,14 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) host->reqs_blocked = 0; if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) { if (host->protect_card) { - dev_info(host->dev, "%s: cover is closed, " + printk(KERN_INFO "%s: cover is closed, " "card is now accessible\n", mmc_hostname(host->mmc)); host->protect_card = 0; } } else { if (!host->protect_card) { - dev_info(host->dev, "%s: cover is open, " + printk(KERN_INFO "%s: cover is open, " "card is now inaccessible\n", mmc_hostname(host->mmc)); host->protect_card = 1; @@ -1168,16 +1280,17 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) } /* - * irq handler to notify the core about card insertion/removal + * Work Item to notify the core about card insertion/removal */ -static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) +static void omap_hsmmc_detect(struct work_struct *work) { - struct omap_hsmmc_host *host = dev_id; + struct omap_hsmmc_host *host = + container_of(work, struct omap_hsmmc_host, mmc_carddetect_work); struct omap_mmc_slot_data *slot = &mmc_slot(host); int carddetect; if (host->suspended) - return IRQ_HANDLED; + return; sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); @@ -1192,32 +1305,105 @@ static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) mmc_detect_change(host->mmc, (HZ * 200) / 1000); else mmc_detect_change(host->mmc, (HZ * 50) / 1000); +} + +/* + * ISR for handling card insertion and removal + */ +static irqreturn_t omap_hsmmc_cd_handler(int irq, void *dev_id) +{ + struct omap_hsmmc_host *host = (struct omap_hsmmc_host *)dev_id; + + if (host->suspended) + return IRQ_HANDLED; + schedule_work(&host->mmc_carddetect_work); + return IRQ_HANDLED; } -static void omap_hsmmc_dma_callback(void *param) +static int omap_hsmmc_get_dma_sync_dev(struct omap_hsmmc_host *host, + struct mmc_data *data) +{ + int sync_dev; + + if (data->flags & MMC_DATA_WRITE) + sync_dev = host->dma_line_tx; + else + sync_dev = host->dma_line_rx; + return sync_dev; +} + +static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host, + struct mmc_data *data, + struct scatterlist *sgl) +{ + int blksz, nblk, dma_ch; + + dma_ch = host->dma_ch; + if (data->flags & MMC_DATA_WRITE) { + omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, + (host->mapbase + OMAP_HSMMC_DATA), 0, 0); + omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC, + sg_dma_address(sgl), 0, 0); + } else { + omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, + (host->mapbase + OMAP_HSMMC_DATA), 0, 0); + omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC, + sg_dma_address(sgl), 0, 0); + } + + blksz = host->data->blksz; + nblk = sg_dma_len(sgl) / blksz; + + omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32, + blksz / 4, nblk, OMAP_DMA_SYNC_FRAME, + omap_hsmmc_get_dma_sync_dev(host, data), + !(data->flags & MMC_DATA_WRITE)); + + omap_start_dma(dma_ch); +} + +/* + * DMA call back function + */ +static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) { - struct omap_hsmmc_host *host = param; - struct dma_chan *chan; + struct omap_hsmmc_host *host = cb_data; struct mmc_data *data; - int req_in_progress; + int dma_ch, req_in_progress; - spin_lock_irq(&host->irq_lock); + if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { + dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n", + ch_status); + return; + } + + spin_lock(&host->irq_lock); if (host->dma_ch < 0) { - spin_unlock_irq(&host->irq_lock); + spin_unlock(&host->irq_lock); return; } data = host->mrq->data; - chan = omap_hsmmc_get_dma_chan(host, data); + host->dma_sg_idx++; + if (host->dma_sg_idx < host->dma_len) { + /* Fire up the next transfer. */ + omap_hsmmc_config_dma_params(host, data, + data->sg + host->dma_sg_idx); + spin_unlock(&host->irq_lock); + return; + } + if (!data->host_cookie) - dma_unmap_sg(chan->device->dev, - data->sg, data->sg_len, + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, omap_hsmmc_get_dma_dir(host, data)); req_in_progress = host->req_in_progress; + dma_ch = host->dma_ch; host->dma_ch = -1; - spin_unlock_irq(&host->irq_lock); + spin_unlock(&host->irq_lock); + + omap_free_dma(dma_ch); /* If DMA has finished after TC, complete the request */ if (!req_in_progress) { @@ -1230,14 +1416,13 @@ static void omap_hsmmc_dma_callback(void *param) static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, struct mmc_data *data, - struct omap_hsmmc_next *next, - struct dma_chan *chan) + struct omap_hsmmc_next *next) { int dma_len; if (!next && data->host_cookie && data->host_cookie != host->next_data.cookie) { - dev_warn(host->dev, "[%s] invalid cookie: data->host_cookie %d" + printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d" " host->next_data.cookie %d\n", __func__, data->host_cookie, host->next_data.cookie); data->host_cookie = 0; @@ -1246,7 +1431,8 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, /* Check if next job is already prepared */ if (next || (!next && data->host_cookie != host->next_data.cookie)) { - dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len, + dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, omap_hsmmc_get_dma_dir(host, data)); } else { @@ -1273,11 +1459,8 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, struct mmc_request *req) { - struct dma_slave_config cfg; - struct dma_async_tx_descriptor *tx; - int ret = 0, i; + int dma_ch = 0, ret = 0, i; struct mmc_data *data = req->data; - struct dma_chan *chan; /* Sanity check: all the SG entries must be aligned by block size. */ for (i = 0; i < data->sg_len; i++) { @@ -1295,41 +1478,22 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, BUG_ON(host->dma_ch != -1); - chan = omap_hsmmc_get_dma_chan(host, data); - - cfg.src_addr = host->mapbase + OMAP_HSMMC_DATA; - cfg.dst_addr = host->mapbase + OMAP_HSMMC_DATA; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.src_maxburst = data->blksz / 4; - cfg.dst_maxburst = data->blksz / 4; - - ret = dmaengine_slave_config(chan, &cfg); - if (ret) + ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data), + "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch); + if (ret != 0) { + dev_err(mmc_dev(host->mmc), + "%s: omap_request_dma() failed with %d\n", + mmc_hostname(host->mmc), ret); return ret; - - ret = omap_hsmmc_pre_dma_transfer(host, data, NULL, chan); + } + ret = omap_hsmmc_pre_dma_transfer(host, data, NULL); if (ret) return ret; - tx = dmaengine_prep_slave_sg(chan, data->sg, data->sg_len, - data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!tx) { - dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n"); - /* FIXME: cleanup */ - return -1; - } - - tx->callback = omap_hsmmc_dma_callback; - tx->callback_param = host; - - /* Does not fail */ - dmaengine_submit(tx); - - host->dma_ch = 1; + host->dma_ch = dma_ch; + host->dma_sg_idx = 0; - dma_async_issue_pending(chan); + omap_hsmmc_config_dma_params(host, data, data->sg); return 0; } @@ -1398,7 +1562,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req) if (host->use_dma) { ret = omap_hsmmc_start_dma_transfer(host, req); if (ret != 0) { - dev_err(mmc_dev(host->mmc), "MMC start dma failure\n"); + dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n"); return ret; } } @@ -1411,10 +1575,8 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, struct omap_hsmmc_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; - if (host->use_dma && data->host_cookie) { - struct dma_chan *c = omap_hsmmc_get_dma_chan(host, data); - - dma_unmap_sg(c->device->dev, data->sg, data->sg_len, + if (host->use_dma) { + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, omap_hsmmc_get_dma_dir(host, data)); data->host_cookie = 0; } @@ -1430,13 +1592,10 @@ static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, return ; } - if (host->use_dma) { - struct dma_chan *c = omap_hsmmc_get_dma_chan(host, mrq->data); - + if (host->use_dma) if (omap_hsmmc_pre_dma_transfer(host, mrq->data, - &host->next_data, c)) + &host->next_data)) mrq->data->host_cookie = 0; - } } /* @@ -1496,10 +1655,12 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_POWER_OFF: mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); + host->vdd = 0; break; case MMC_POWER_UP: mmc_slot(host).set_power(host->dev, host->slot_id, 1, ios->vdd); + host->vdd = ios->vdd; break; case MMC_POWER_ON: do_send_init_stream = 1; @@ -1517,13 +1678,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) * of external transceiver; but they all handle 1.8V. */ if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) && - (ios->vdd == DUAL_VOLT_OCR_BIT) && - /* - * With pbias cell programming missing, this - * can't be allowed when booting with device - * tree. - */ - !host->dev->of_node) { + (ios->vdd == DUAL_VOLT_OCR_BIT)) { /* * The mmc_select_voltage fn of the core does * not seem to set the power_mode to @@ -1591,6 +1746,10 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) value = OMAP_HSMMC_READ(host->base, CAPA); OMAP_HSMMC_WRITE(host->base, CAPA, value | capa); + /* Set the controller to AUTO IDLE mode */ + value = OMAP_HSMMC_READ(host->base, SYSCONFIG); + OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE); + /* Set SD bus power bit */ set_sd_bus_power(host); } @@ -1604,7 +1763,7 @@ static int omap_hsmmc_enable_fclk(struct mmc_host *mmc) return 0; } -static int omap_hsmmc_disable_fclk(struct mmc_host *mmc) +static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy) { struct omap_hsmmc_host *host = mmc_priv(mmc); @@ -1638,8 +1797,15 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data) if (host->pdata->get_context_loss_count) context_loss = host->pdata->get_context_loss_count(host->dev); - seq_printf(s, "mmc%d:\n ctx_loss:\t%d:%d\n\nregs:\n", - mmc->index, host->context_loss, context_loss); + seq_printf(s, "mmc%d:\n" + " enabled:\t%d\n" + " dpm_state:\t%d\n" + " nesting_cnt:\t%d\n" + " ctx_loss:\t%d:%d\n" + "\nregs:\n", + mmc->index, mmc->enabled ? 1 : 0, + host->dpm_state, mmc->nesting_cnt, + host->context_loss, context_loss); if (host->suspended) { seq_printf(s, "host suspended, can't read registers\n"); @@ -1648,6 +1814,8 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data) pm_runtime_get_sync(host->dev); + seq_printf(s, "SYSCONFIG:\t0x%08x\n", + OMAP_HSMMC_READ(host->base, SYSCONFIG)); seq_printf(s, "CON:\t\t0x%08x\n", OMAP_HSMMC_READ(host->base, CON)); seq_printf(s, "HCTL:\t\t0x%08x\n", @@ -1694,91 +1862,13 @@ static void omap_hsmmc_debugfs(struct mmc_host *mmc) #endif -#ifdef CONFIG_OF -static u16 omap4_reg_offset = 0x100; - -static const struct of_device_id omap_mmc_of_match[] = { - { - .compatible = "ti,omap2-hsmmc", - }, - { - .compatible = "ti,omap3-hsmmc", - }, - { - .compatible = "ti,omap4-hsmmc", - .data = &omap4_reg_offset, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, omap_mmc_of_match); - -static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) -{ - struct omap_mmc_platform_data *pdata; - struct device_node *np = dev->of_node; - u32 bus_width, max_freq; - - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; /* out of memory */ - - if (of_find_property(np, "ti,dual-volt", NULL)) - pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT; - - /* This driver only supports 1 slot */ - pdata->nr_slots = 1; - pdata->slots[0].switch_pin = of_get_named_gpio(np, "cd-gpios", 0); - pdata->slots[0].gpio_wp = of_get_named_gpio(np, "wp-gpios", 0); - - if (of_find_property(np, "ti,non-removable", NULL)) { - pdata->slots[0].nonremovable = true; - pdata->slots[0].no_regulator_off_init = true; - } - of_property_read_u32(np, "bus-width", &bus_width); - if (bus_width == 4) - pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA; - else if (bus_width == 8) - pdata->slots[0].caps |= MMC_CAP_8_BIT_DATA; - - if (of_find_property(np, "ti,needs-special-reset", NULL)) - pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET; - - if (!of_property_read_u32(np, "max-frequency", &max_freq)) - pdata->max_freq = max_freq; - - if (of_find_property(np, "ti,needs-special-hs-handling", NULL)) - pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT; - - return pdata; -} -#else -static inline struct omap_mmc_platform_data - *of_get_hsmmc_pdata(struct device *dev) -{ - return NULL; -} -#endif - -static int omap_hsmmc_probe(struct platform_device *pdev) +static int __init omap_hsmmc_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_host *mmc; struct omap_hsmmc_host *host = NULL; struct resource *res; int ret, irq; - const struct of_device_id *match; - dma_cap_mask_t mask; - unsigned tx_req, rx_req; - struct pinctrl *pinctrl; - - match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev); - if (match) { - pdata = of_get_hsmmc_pdata(&pdev->dev); - if (match->data) { - const u16 *offsetp = match->data; - pdata->reg_offset = *offsetp; - } - } if (pdata == NULL) { dev_err(&pdev->dev, "Platform Data is missing\n"); @@ -1795,6 +1885,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (res == NULL || irq < 0) return -ENXIO; + res->start += pdata->reg_offset; + res->end += pdata->reg_offset; res = request_mem_region(res->start, resource_size(res), pdev->name); if (res == NULL) return -EBUSY; @@ -1814,15 +1906,18 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->pdata = pdata; host->dev = &pdev->dev; host->use_dma = 1; + host->dev->dma_mask = &pdata->dma_mask; host->dma_ch = -1; host->irq = irq; + host->id = pdev->id; host->slot_id = 0; - host->mapbase = res->start + pdata->reg_offset; + host->mapbase = res->start; host->base = ioremap(host->mapbase, SZ_4K); host->power_mode = MMC_POWER_OFF; host->next_data.cookie = 1; platform_set_drvdata(pdev, host); + INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect); mmc->ops = &omap_hsmmc_ops; @@ -1833,12 +1928,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (mmc_slot(host).vcc_aux_disable_is_sleep) mmc_slot(host).no_off = 1; - mmc->f_min = OMAP_MMC_MIN_CLOCK; - - if (pdata->max_freq > 0) - mmc->f_max = pdata->max_freq; - else - mmc->f_max = OMAP_MMC_MAX_CLOCK; + mmc->f_min = OMAP_MMC_MIN_CLOCK; + mmc->f_max = OMAP_MMC_MAX_CLOCK; spin_lock_init(&host->irq_lock); @@ -1849,28 +1940,30 @@ static int omap_hsmmc_probe(struct platform_device *pdev) goto err1; } - if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) { - dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n"); - mmc->caps2 |= MMC_CAP2_NO_MULTI_READ; - } + omap_hsmmc_context_save(host); + + mmc->caps |= MMC_CAP_DISABLE; pm_runtime_enable(host->dev); pm_runtime_get_sync(host->dev); pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY); pm_runtime_use_autosuspend(host->dev); - 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; - host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); - /* - * MMC can still work without debounce clock. - */ - if (IS_ERR(host->dbclk)) { - host->dbclk = NULL; - } else if (clk_prepare_enable(host->dbclk) != 0) { - dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n"); - clk_put(host->dbclk); - host->dbclk = NULL; + if (host->got_dbclk) + if (clk_enable(host->dbclk) != 0) + dev_dbg(mmc_dev(host->mmc), "Enabling debounce" + " clk failed\n"); } /* Since we do only SG emulation, we can have as many segs @@ -1892,54 +1985,46 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (mmc_slot(host).nonremovable) mmc->caps |= MMC_CAP_NONREMOVABLE; - mmc->pm_caps = mmc_slot(host).pm_caps; - omap_hsmmc_conf_bus_power(host); - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (!res) { - dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n"); - ret = -ENXIO; - goto err_irq; - } - tx_req = res->start; - - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (!res) { - dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n"); - ret = -ENXIO; - goto err_irq; - } - rx_req = res->start; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &rx_req); - if (!host->rx_chan) { - dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req); - ret = -ENXIO; - goto err_irq; - } - - host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &tx_req); - if (!host->tx_chan) { - dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req); - ret = -ENXIO; + /* Select DMA lines */ + switch (host->id) { + case OMAP_MMC1_DEVID: + host->dma_line_tx = OMAP24XX_DMA_MMC1_TX; + host->dma_line_rx = OMAP24XX_DMA_MMC1_RX; + break; + case OMAP_MMC2_DEVID: + host->dma_line_tx = OMAP24XX_DMA_MMC2_TX; + host->dma_line_rx = OMAP24XX_DMA_MMC2_RX; + break; + case OMAP_MMC3_DEVID: + host->dma_line_tx = OMAP34XX_DMA_MMC3_TX; + host->dma_line_rx = OMAP34XX_DMA_MMC3_RX; + break; + case OMAP_MMC4_DEVID: + host->dma_line_tx = OMAP44XX_DMA_MMC4_TX; + host->dma_line_rx = OMAP44XX_DMA_MMC4_RX; + break; + case OMAP_MMC5_DEVID: + host->dma_line_tx = OMAP44XX_DMA_MMC5_TX; + host->dma_line_rx = OMAP44XX_DMA_MMC5_RX; + break; + default: + dev_err(mmc_dev(host->mmc), "Invalid MMC id\n"); goto err_irq; } /* Request IRQ for MMC operations */ - ret = request_irq(host->irq, omap_hsmmc_irq, 0, + ret = request_irq(host->irq, omap_hsmmc_irq, IRQF_DISABLED, mmc_hostname(mmc), host); if (ret) { - dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); + dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); goto err_irq; } if (pdata->init != NULL) { if (pdata->init(&pdev->dev) != 0) { - dev_err(mmc_dev(host->mmc), + dev_dbg(mmc_dev(host->mmc), "Unable to configure MMC IRQs\n"); goto err_irq_cd_init; } @@ -1956,13 +2041,13 @@ static int omap_hsmmc_probe(struct platform_device *pdev) /* Request IRQ for card detect */ if ((mmc_slot(host).card_detect_irq)) { - ret = request_threaded_irq(mmc_slot(host).card_detect_irq, - NULL, - omap_hsmmc_detect, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - mmc_hostname(mmc), host); + ret = request_irq(mmc_slot(host).card_detect_irq, + omap_hsmmc_cd_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_DISABLED, + mmc_hostname(mmc), host); if (ret) { - dev_err(mmc_dev(host->mmc), + dev_dbg(mmc_dev(host->mmc), "Unable to grab MMC CD IRQ\n"); goto err_irq_cd; } @@ -1972,11 +2057,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) omap_hsmmc_disable_irq(host); - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - dev_warn(&pdev->dev, - "pins are not configured from the driver\n"); - omap_hsmmc_protect_card(host); mmc_add_host(mmc); @@ -2011,15 +2091,11 @@ err_reg: err_irq_cd_init: free_irq(host->irq, host); err_irq: - if (host->tx_chan) - dma_release_channel(host->tx_chan); - if (host->rx_chan) - dma_release_channel(host->rx_chan); - pm_runtime_put_sync(host->dev); - pm_runtime_disable(host->dev); + pm_runtime_mark_last_busy(host->dev); + pm_runtime_put_autosuspend(host->dev); clk_put(host->fclk); - if (host->dbclk) { - clk_disable_unprepare(host->dbclk); + if (host->got_dbclk) { + clk_disable(host->dbclk); clk_put(host->dbclk); } err1: @@ -2029,9 +2105,7 @@ err1: err_alloc: omap_hsmmc_gpio_free(pdata); err: - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); + release_mem_region(res->start, resource_size(res)); return ret; } @@ -2040,33 +2114,31 @@ static int omap_hsmmc_remove(struct platform_device *pdev) struct omap_hsmmc_host *host = platform_get_drvdata(pdev); struct resource *res; - pm_runtime_get_sync(host->dev); - mmc_remove_host(host->mmc); - if (host->use_reg) - omap_hsmmc_reg_put(host); - if (host->pdata->cleanup) - host->pdata->cleanup(&pdev->dev); - free_irq(host->irq, host); - if (mmc_slot(host).card_detect_irq) - free_irq(mmc_slot(host).card_detect_irq, host); - - if (host->tx_chan) - dma_release_channel(host->tx_chan); - if (host->rx_chan) - dma_release_channel(host->rx_chan); + if (host) { + pm_runtime_get_sync(host->dev); + mmc_remove_host(host->mmc); + if (host->use_reg) + omap_hsmmc_reg_put(host); + if (host->pdata->cleanup) + host->pdata->cleanup(&pdev->dev); + free_irq(host->irq, host); + if (mmc_slot(host).card_detect_irq) + free_irq(mmc_slot(host).card_detect_irq, host); + flush_work_sync(&host->mmc_carddetect_work); + + pm_runtime_put_sync(host->dev); + pm_runtime_disable(host->dev); + clk_put(host->fclk); + if (host->got_dbclk) { + clk_disable(host->dbclk); + clk_put(host->dbclk); + } - pm_runtime_put_sync(host->dev); - pm_runtime_disable(host->dev); - clk_put(host->fclk); - if (host->dbclk) { - clk_disable_unprepare(host->dbclk); - clk_put(host->dbclk); + mmc_free_host(host->mmc); + iounmap(host->base); + omap_hsmmc_gpio_free(pdev->dev.platform_data); } - omap_hsmmc_gpio_free(host->pdata); - iounmap(host->base); - mmc_free_host(host->mmc); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) release_mem_region(res->start, resource_size(res)); @@ -2076,55 +2148,50 @@ static int omap_hsmmc_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int omap_hsmmc_prepare(struct device *dev) -{ - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - if (host->pdata->suspend) - return host->pdata->suspend(dev, host->slot_id); - - return 0; -} - -static void omap_hsmmc_complete(struct device *dev) -{ - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - if (host->pdata->resume) - host->pdata->resume(dev, host->slot_id); - -} - static int omap_hsmmc_suspend(struct device *dev) { int ret = 0; - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - if (!host) - return 0; + struct platform_device *pdev = to_platform_device(dev); + struct omap_hsmmc_host *host = platform_get_drvdata(pdev); if (host && host->suspended) return 0; - pm_runtime_get_sync(host->dev); - host->suspended = 1; - ret = mmc_suspend_host(host->mmc); - - if (ret) { - host->suspended = 0; - goto err; - } + if (host) { + pm_runtime_get_sync(host->dev); + host->suspended = 1; + if (host->pdata->suspend) { + ret = host->pdata->suspend(&pdev->dev, + host->slot_id); + if (ret) { + dev_dbg(mmc_dev(host->mmc), + "Unable to handle MMC board" + " level suspend\n"); + host->suspended = 0; + return ret; + } + } + cancel_work_sync(&host->mmc_carddetect_work); + ret = mmc_suspend_host(host->mmc); - if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) { - omap_hsmmc_disable_irq(host); - OMAP_HSMMC_WRITE(host->base, HCTL, + if (ret == 0) { + omap_hsmmc_disable_irq(host); + OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); + if (host->got_dbclk) + clk_disable(host->dbclk); + } else { + host->suspended = 0; + if (host->pdata->resume) { + ret = host->pdata->resume(&pdev->dev, + host->slot_id); + if (ret) + dev_dbg(mmc_dev(host->mmc), + "Unmask interrupt failed\n"); + } + } + pm_runtime_put_sync(host->dev); } - - if (host->dbclk) - clk_disable_unprepare(host->dbclk); -err: - pm_runtime_put_sync(host->dev); return ret; } @@ -2132,41 +2199,45 @@ err: static int omap_hsmmc_resume(struct device *dev) { int ret = 0; - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - if (!host) - return 0; + struct platform_device *pdev = to_platform_device(dev); + struct omap_hsmmc_host *host = platform_get_drvdata(pdev); if (host && !host->suspended) return 0; - pm_runtime_get_sync(host->dev); + if (host) { + pm_runtime_get_sync(host->dev); - if (host->dbclk) - clk_prepare_enable(host->dbclk); + if (host->got_dbclk) + clk_enable(host->dbclk); - if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) omap_hsmmc_conf_bus_power(host); - omap_hsmmc_protect_card(host); + if (host->pdata->resume) { + ret = host->pdata->resume(&pdev->dev, host->slot_id); + if (ret) + dev_dbg(mmc_dev(host->mmc), + "Unmask interrupt failed\n"); + } - /* Notify the core to resume the host */ - ret = mmc_resume_host(host->mmc); - if (ret == 0) - host->suspended = 0; + omap_hsmmc_protect_card(host); - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); + /* Notify the core to resume the host */ + ret = mmc_resume_host(host->mmc); + if (ret == 0) + host->suspended = 0; + + pm_runtime_mark_last_busy(host->dev); + pm_runtime_put_autosuspend(host->dev); + } return ret; } #else -#define omap_hsmmc_prepare NULL -#define omap_hsmmc_complete NULL #define omap_hsmmc_suspend NULL -#define omap_hsmmc_resume NULL +#define omap_hsmmc_resume NULL #endif static int omap_hsmmc_runtime_suspend(struct device *dev) @@ -2175,7 +2246,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev) host = platform_get_drvdata(to_platform_device(dev)); omap_hsmmc_context_save(host); - dev_dbg(dev, "disabled\n"); + dev_dbg(mmc_dev(host->mmc), "disabled\n"); return 0; } @@ -2186,7 +2257,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev) host = platform_get_drvdata(to_platform_device(dev)); omap_hsmmc_context_restore(host); - dev_dbg(dev, "enabled\n"); + dev_dbg(mmc_dev(host->mmc), "enabled\n"); return 0; } @@ -2194,24 +2265,34 @@ static int omap_hsmmc_runtime_resume(struct device *dev) static struct dev_pm_ops omap_hsmmc_dev_pm_ops = { .suspend = omap_hsmmc_suspend, .resume = omap_hsmmc_resume, - .prepare = omap_hsmmc_prepare, - .complete = omap_hsmmc_complete, .runtime_suspend = omap_hsmmc_runtime_suspend, .runtime_resume = omap_hsmmc_runtime_resume, }; static struct platform_driver omap_hsmmc_driver = { - .probe = omap_hsmmc_probe, .remove = omap_hsmmc_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .pm = &omap_hsmmc_dev_pm_ops, - .of_match_table = of_match_ptr(omap_mmc_of_match), }, }; -module_platform_driver(omap_hsmmc_driver); +static int __init omap_hsmmc_init(void) +{ + /* Register the MMC driver */ + return platform_driver_probe(&omap_hsmmc_driver, omap_hsmmc_probe); +} + +static void __exit omap_hsmmc_cleanup(void) +{ + /* Unregister MMC driver */ + platform_driver_unregister(&omap_hsmmc_driver); +} + +module_init(omap_hsmmc_init); +module_exit(omap_hsmmc_cleanup); + MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 2b2f65ada22..7257738fd7d 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -30,15 +30,12 @@ #include #include #include -#include -#include -#include #include #include #include -#include +#include #include "pxamci.h" @@ -561,7 +558,7 @@ static void pxamci_dma_irq(int dma, void *devid) if (dcsr & DCSR_ENDINTR) { writel(BUF_PART_FULL, host->base + MMC_PRTBUF); } else { - pr_err("%s: DMA error on channel %d (DCSR=%#x)\n", + printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", mmc_hostname(host->mmc), dma, dcsr); host->data->error = -EIO; pxamci_data_done(host, 0); @@ -576,50 +573,6 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid) return IRQ_HANDLED; } -#ifdef CONFIG_OF -static const struct of_device_id pxa_mmc_dt_ids[] = { - { .compatible = "marvell,pxa-mmc" }, - { } -}; - -MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids); - -static int pxamci_of_init(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct pxamci_platform_data *pdata; - u32 tmp; - - if (!np) - return 0; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - pdata->gpio_card_detect = - of_get_named_gpio(np, "cd-gpios", 0); - pdata->gpio_card_ro = - of_get_named_gpio(np, "wp-gpios", 0); - - /* pxa-mmc specific */ - pdata->gpio_power = - of_get_named_gpio(np, "pxa-mmc,gpio-power", 0); - - if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0) - pdata->detect_delay_ms = tmp; - - pdev->dev.platform_data = pdata; - - return 0; -} -#else -static int pxamci_of_init(struct platform_device *pdev) -{ - return 0; -} -#endif - static int pxamci_probe(struct platform_device *pdev) { struct mmc_host *mmc; @@ -627,10 +580,6 @@ static int pxamci_probe(struct platform_device *pdev) struct resource *r, *dmarx, *dmatx; int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1; - ret = pxamci_of_init(pdev); - if (ret) - return ret; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!r || irq < 0) @@ -917,14 +866,24 @@ static struct platform_driver pxamci_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, - .of_match_table = of_match_ptr(pxa_mmc_dt_ids), #ifdef CONFIG_PM .pm = &pxamci_pm_ops, #endif }, }; -module_platform_driver(pxamci_driver); +static int __init pxamci_init(void) +{ + return platform_driver_register(&pxamci_driver); +} + +static void __exit pxamci_exit(void) +{ + platform_driver_unregister(&pxamci_driver); +} + +module_init(pxamci_init); +module_exit(pxamci_exit); MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c deleted file mode 100644 index 571915dfb21..00000000000 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ /dev/null @@ -1,1348 +0,0 @@ -/* Realtek PCI-Express SD/MMC Card Interface driver - * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* SD Tuning Data Structure - * Record continuous timing phase path - */ -struct timing_phase_path { - int start; - int end; - int mid; - int len; -}; - -struct realtek_pci_sdmmc { - struct platform_device *pdev; - struct rtsx_pcr *pcr; - struct mmc_host *mmc; - struct mmc_request *mrq; - - struct mutex host_mutex; - - u8 ssc_depth; - unsigned int clock; - bool vpclk; - bool double_clk; - bool eject; - bool initial_mode; - bool ddr_mode; -}; - -static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) -{ - return &(host->pdev->dev); -} - -static inline void sd_clear_error(struct realtek_pci_sdmmc *host) -{ - rtsx_pci_write_register(host->pcr, CARD_STOP, - SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); -} - -#ifdef DEBUG -static void sd_print_debug_regs(struct realtek_pci_sdmmc *host) -{ - struct rtsx_pcr *pcr = host->pcr; - u16 i; - u8 *ptr; - - /* Print SD host internal registers */ - rtsx_pci_init_cmd(pcr); - for (i = 0xFDA0; i <= 0xFDAE; i++) - rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); - for (i = 0xFD52; i <= 0xFD69; i++) - rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); - rtsx_pci_send_cmd(pcr, 100); - - ptr = rtsx_pci_get_cmd_data(pcr); - for (i = 0xFDA0; i <= 0xFDAE; i++) - dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); - for (i = 0xFD52; i <= 0xFD69; i++) - dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); -} -#else -#define sd_print_debug_regs(host) -#endif /* DEBUG */ - -static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, - u8 *buf, int buf_len, int timeout) -{ - struct rtsx_pcr *pcr = host->pcr; - int err, i; - u8 trans_mode; - - dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__, cmd[0] - 0x40); - - if (!buf) - buf_len = 0; - - if ((cmd[0] & 0x3F) == MMC_SEND_TUNING_BLOCK) - trans_mode = SD_TM_AUTO_TUNING; - else - trans_mode = SD_TM_NORMAL_READ; - - rtsx_pci_init_cmd(pcr); - - for (i = 0; i < 5; i++) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0 + i, 0xFF, cmd[i]); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, - 0xFF, (u8)(byte_cnt >> 8)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, - SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); - if (trans_mode != SD_TM_AUTO_TUNING) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, - 0xFF, trans_mode | SD_TRANSFER_START); - rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - err = rtsx_pci_send_cmd(pcr, timeout); - if (err < 0) { - sd_print_debug_regs(host); - dev_dbg(sdmmc_dev(host), - "rtsx_pci_send_cmd fail (err = %d)\n", err); - return err; - } - - if (buf && buf_len) { - err = rtsx_pci_read_ppbuf(pcr, buf, buf_len); - if (err < 0) { - dev_dbg(sdmmc_dev(host), - "rtsx_pci_read_ppbuf fail (err = %d)\n", err); - return err; - } - } - - return 0; -} - -static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, - u8 *buf, int buf_len, int timeout) -{ - struct rtsx_pcr *pcr = host->pcr; - int err, i; - u8 trans_mode; - - if (!buf) - buf_len = 0; - - if (buf && buf_len) { - err = rtsx_pci_write_ppbuf(pcr, buf, buf_len); - if (err < 0) { - dev_dbg(sdmmc_dev(host), - "rtsx_pci_write_ppbuf fail (err = %d)\n", err); - return err; - } - } - - trans_mode = cmd ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3; - rtsx_pci_init_cmd(pcr); - - if (cmd) { - dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d\n", __func__, - cmd[0] - 0x40); - - for (i = 0; i < 5; i++) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD_CMD0 + i, 0xFF, cmd[i]); - } - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, - 0xFF, (u8)(byte_cnt >> 8)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, - SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, - trans_mode | SD_TRANSFER_START); - rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - err = rtsx_pci_send_cmd(pcr, timeout); - if (err < 0) { - sd_print_debug_regs(host); - dev_dbg(sdmmc_dev(host), - "rtsx_pci_send_cmd fail (err = %d)\n", err); - return err; - } - - return 0; -} - -static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, - struct mmc_command *cmd) -{ - struct rtsx_pcr *pcr = host->pcr; - u8 cmd_idx = (u8)cmd->opcode; - u32 arg = cmd->arg; - int err = 0; - int timeout = 100; - int i; - u8 *ptr; - int stat_idx = 0; - u8 rsp_type; - int rsp_len = 5; - - dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", - __func__, cmd_idx, arg); - - /* Response type: - * R0 - * R1, R5, R6, R7 - * R1b - * R2 - * R3, R4 - */ - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: - rsp_type = SD_RSP_TYPE_R0; - rsp_len = 0; - break; - case MMC_RSP_R1: - rsp_type = SD_RSP_TYPE_R1; - break; - case MMC_RSP_R1B: - rsp_type = SD_RSP_TYPE_R1b; - break; - case MMC_RSP_R2: - rsp_type = SD_RSP_TYPE_R2; - rsp_len = 16; - break; - case MMC_RSP_R3: - rsp_type = SD_RSP_TYPE_R3; - break; - default: - dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n"); - err = -EINVAL; - goto out; - } - - if (rsp_type == SD_RSP_TYPE_R1b) - timeout = 3000; - - if (cmd->opcode == SD_SWITCH_VOLTAGE) { - err = rtsx_pci_write_register(pcr, SD_BUS_STAT, - 0xFF, SD_CLK_TOGGLE_EN); - if (err < 0) - goto out; - } - - rtsx_pci_init_cmd(pcr); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, PINGPONG_BUFFER); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, - 0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START); - rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, - SD_TRANSFER_END | SD_STAT_IDLE, - SD_TRANSFER_END | SD_STAT_IDLE); - - if (rsp_type == SD_RSP_TYPE_R2) { - /* Read data from ping-pong buffer */ - for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++) - rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); - stat_idx = 16; - } else if (rsp_type != SD_RSP_TYPE_R0) { - /* Read data from SD_CMDx registers */ - for (i = SD_CMD0; i <= SD_CMD4; i++) - rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); - stat_idx = 5; - } - - rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0); - - err = rtsx_pci_send_cmd(pcr, timeout); - if (err < 0) { - sd_print_debug_regs(host); - sd_clear_error(host); - dev_dbg(sdmmc_dev(host), - "rtsx_pci_send_cmd error (err = %d)\n", err); - goto out; - } - - if (rsp_type == SD_RSP_TYPE_R0) { - err = 0; - goto out; - } - - /* Eliminate returned value of CHECK_REG_CMD */ - ptr = rtsx_pci_get_cmd_data(pcr) + 1; - - /* Check (Start,Transmission) bit of Response */ - if ((ptr[0] & 0xC0) != 0) { - err = -EILSEQ; - dev_dbg(sdmmc_dev(host), "Invalid response bit\n"); - goto out; - } - - /* Check CRC7 */ - if (!(rsp_type & SD_NO_CHECK_CRC7)) { - if (ptr[stat_idx] & SD_CRC7_ERR) { - err = -EILSEQ; - dev_dbg(sdmmc_dev(host), "CRC7 error\n"); - goto out; - } - } - - if (rsp_type == SD_RSP_TYPE_R2) { - for (i = 0; i < 4; i++) { - cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4); - dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n", - i, cmd->resp[i]); - } - } else { - cmd->resp[0] = get_unaligned_be32(ptr + 1); - dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", - cmd->resp[0]); - } - -out: - cmd->error = err; -} - -static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) -{ - struct rtsx_pcr *pcr = host->pcr; - struct mmc_host *mmc = host->mmc; - struct mmc_card *card = mmc->card; - struct mmc_data *data = mrq->data; - int uhs = mmc_sd_card_uhs(card); - int read = (data->flags & MMC_DATA_READ) ? 1 : 0; - u8 cfg2, trans_mode; - int err; - size_t data_len = data->blksz * data->blocks; - - if (read) { - cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0; - trans_mode = SD_TM_AUTO_READ_3; - } else { - cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; - trans_mode = SD_TM_AUTO_WRITE_3; - } - - if (!uhs) - cfg2 |= SD_NO_CHECK_WAIT_CRC_TO; - - rtsx_pci_init_cmd(pcr); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, - 0xFF, (u8)data->blocks); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, - 0xFF, (u8)(data->blocks >> 8)); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, - DMA_DONE_INT, DMA_DONE_INT); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3, - 0xFF, (u8)(data_len >> 24)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, - 0xFF, (u8)(data_len >> 16)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, - 0xFF, (u8)(data_len >> 8)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)data_len); - if (read) { - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, - 0x03 | DMA_PACK_SIZE_MASK, - DMA_DIR_FROM_CARD | DMA_EN | DMA_512); - } else { - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, - 0x03 | DMA_PACK_SIZE_MASK, - DMA_DIR_TO_CARD | DMA_EN | DMA_512); - } - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, RING_BUFFER); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, - trans_mode | SD_TRANSFER_START); - rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - rtsx_pci_send_cmd_no_wait(pcr); - - err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000); - if (err < 0) { - sd_clear_error(host); - return err; - } - - return 0; -} - -static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host) -{ - rtsx_pci_write_register(host->pcr, SD_CFG1, - SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128); -} - -static inline void sd_disable_initial_mode(struct realtek_pci_sdmmc *host) -{ - rtsx_pci_write_register(host->pcr, SD_CFG1, - SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0); -} - -static void sd_normal_rw(struct realtek_pci_sdmmc *host, - struct mmc_request *mrq) -{ - struct mmc_command *cmd = mrq->cmd; - struct mmc_data *data = mrq->data; - u8 _cmd[5], *buf; - - _cmd[0] = 0x40 | (u8)cmd->opcode; - put_unaligned_be32(cmd->arg, (u32 *)(&_cmd[1])); - - buf = kzalloc(data->blksz, GFP_NOIO); - if (!buf) { - cmd->error = -ENOMEM; - return; - } - - if (data->flags & MMC_DATA_READ) { - if (host->initial_mode) - sd_disable_initial_mode(host); - - cmd->error = sd_read_data(host, _cmd, (u16)data->blksz, buf, - data->blksz, 200); - - if (host->initial_mode) - sd_enable_initial_mode(host); - - sg_copy_from_buffer(data->sg, data->sg_len, buf, data->blksz); - } else { - sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz); - - cmd->error = sd_write_data(host, _cmd, (u16)data->blksz, buf, - data->blksz, 200); - } - - kfree(buf); -} - -static int sd_change_phase(struct realtek_pci_sdmmc *host, u8 sample_point) -{ - struct rtsx_pcr *pcr = host->pcr; - int err; - - dev_dbg(sdmmc_dev(host), "%s: sample_point = %d\n", - __func__, sample_point); - - rtsx_pci_init_cmd(pcr); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, CHANGE_CLK); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPRX_CTL, 0x1F, sample_point); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, - PHASE_NOT_RESET, PHASE_NOT_RESET); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, 0); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0); - - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - return 0; -} - -static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map) -{ - struct timing_phase_path path[MAX_PHASE + 1]; - int i, j, cont_path_cnt; - int new_block, max_len, final_path_idx; - u8 final_phase = 0xFF; - - /* Parse phase_map, take it as a bit-ring */ - cont_path_cnt = 0; - new_block = 1; - j = 0; - for (i = 0; i < MAX_PHASE + 1; i++) { - if (phase_map & (1 << i)) { - if (new_block) { - new_block = 0; - j = cont_path_cnt++; - path[j].start = i; - path[j].end = i; - } else { - path[j].end = i; - } - } else { - new_block = 1; - if (cont_path_cnt) { - /* Calculate path length and middle point */ - int idx = cont_path_cnt - 1; - path[idx].len = - path[idx].end - path[idx].start + 1; - path[idx].mid = - path[idx].start + path[idx].len / 2; - } - } - } - - if (cont_path_cnt == 0) { - dev_dbg(sdmmc_dev(host), "No continuous phase path\n"); - goto finish; - } else { - /* Calculate last continuous path length and middle point */ - int idx = cont_path_cnt - 1; - path[idx].len = path[idx].end - path[idx].start + 1; - path[idx].mid = path[idx].start + path[idx].len / 2; - } - - /* Connect the first and last continuous paths if they are adjacent */ - if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) { - /* Using negative index */ - path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1; - path[0].len += path[cont_path_cnt - 1].len; - path[0].mid = path[0].start + path[0].len / 2; - /* Convert negative middle point index to positive one */ - if (path[0].mid < 0) - path[0].mid += MAX_PHASE + 1; - cont_path_cnt--; - } - - /* Choose the longest continuous phase path */ - max_len = 0; - final_phase = 0; - final_path_idx = 0; - for (i = 0; i < cont_path_cnt; i++) { - if (path[i].len > max_len) { - max_len = path[i].len; - final_phase = (u8)path[i].mid; - final_path_idx = i; - } - - dev_dbg(sdmmc_dev(host), "path[%d].start = %d\n", - i, path[i].start); - dev_dbg(sdmmc_dev(host), "path[%d].end = %d\n", - i, path[i].end); - dev_dbg(sdmmc_dev(host), "path[%d].len = %d\n", - i, path[i].len); - dev_dbg(sdmmc_dev(host), "path[%d].mid = %d\n", - i, path[i].mid); - } - -finish: - dev_dbg(sdmmc_dev(host), "Final chosen phase: %d\n", final_phase); - return final_phase; -} - -static void sd_wait_data_idle(struct realtek_pci_sdmmc *host) -{ - int err, i; - u8 val = 0; - - for (i = 0; i < 100; i++) { - err = rtsx_pci_read_register(host->pcr, SD_DATA_STATE, &val); - if (val & SD_DATA_IDLE) - return; - - udelay(100); - } -} - -static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, - u8 opcode, u8 sample_point) -{ - int err; - u8 cmd[5] = {0}; - - err = sd_change_phase(host, sample_point); - if (err < 0) - return err; - - cmd[0] = 0x40 | opcode; - err = sd_read_data(host, cmd, 0x40, NULL, 0, 100); - if (err < 0) { - /* Wait till SD DATA IDLE */ - sd_wait_data_idle(host); - sd_clear_error(host); - return err; - } - - return 0; -} - -static int sd_tuning_phase(struct realtek_pci_sdmmc *host, - u8 opcode, u32 *phase_map) -{ - int err, i; - u32 raw_phase_map = 0; - - for (i = MAX_PHASE; i >= 0; i--) { - err = sd_tuning_rx_cmd(host, opcode, (u8)i); - if (err == 0) - raw_phase_map |= 1 << i; - } - - if (phase_map) - *phase_map = raw_phase_map; - - return 0; -} - -static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode) -{ - int err, i; - u32 raw_phase_map[RX_TUNING_CNT] = {0}, phase_map; - u8 final_phase; - - for (i = 0; i < RX_TUNING_CNT; i++) { - err = sd_tuning_phase(host, opcode, &(raw_phase_map[i])); - if (err < 0) - return err; - - if (raw_phase_map[i] == 0) - break; - } - - phase_map = 0xFFFFFFFF; - for (i = 0; i < RX_TUNING_CNT; i++) { - dev_dbg(sdmmc_dev(host), "RX raw_phase_map[%d] = 0x%08x\n", - i, raw_phase_map[i]); - phase_map &= raw_phase_map[i]; - } - dev_dbg(sdmmc_dev(host), "RX phase_map = 0x%08x\n", phase_map); - - if (phase_map) { - final_phase = sd_search_final_phase(host, phase_map); - if (final_phase == 0xFF) - return -EINVAL; - - err = sd_change_phase(host, final_phase); - if (err < 0) - return err; - } else { - return -EINVAL; - } - - return 0; -} - -static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct realtek_pci_sdmmc *host = mmc_priv(mmc); - struct rtsx_pcr *pcr = host->pcr; - struct mmc_command *cmd = mrq->cmd; - struct mmc_data *data = mrq->data; - unsigned int data_size = 0; - - if (host->eject) { - cmd->error = -ENOMEDIUM; - goto finish; - } - - mutex_lock(&pcr->pcr_mutex); - - rtsx_pci_start_run(pcr); - - rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth, - host->initial_mode, host->double_clk, host->vpclk); - rtsx_pci_write_register(pcr, CARD_SELECT, 0x07, SD_MOD_SEL); - rtsx_pci_write_register(pcr, CARD_SHARE_MODE, - CARD_SHARE_MASK, CARD_SHARE_48_SD); - - mutex_lock(&host->host_mutex); - host->mrq = mrq; - mutex_unlock(&host->host_mutex); - - if (mrq->data) - data_size = data->blocks * data->blksz; - - if (!data_size || mmc_op_multi(cmd->opcode) || - (cmd->opcode == MMC_READ_SINGLE_BLOCK) || - (cmd->opcode == MMC_WRITE_BLOCK)) { - sd_send_cmd_get_rsp(host, cmd); - - if (!cmd->error && data_size) { - sd_rw_multi(host, mrq); - - if (mmc_op_multi(cmd->opcode) && mrq->stop) - sd_send_cmd_get_rsp(host, mrq->stop); - } - } else { - sd_normal_rw(host, mrq); - } - - if (mrq->data) { - if (cmd->error || data->error) - data->bytes_xfered = 0; - else - data->bytes_xfered = data->blocks * data->blksz; - } - - mutex_unlock(&pcr->pcr_mutex); - -finish: - if (cmd->error) - dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error); - - mutex_lock(&host->host_mutex); - host->mrq = NULL; - mutex_unlock(&host->host_mutex); - - mmc_request_done(mmc, mrq); -} - -static int sd_set_bus_width(struct realtek_pci_sdmmc *host, - unsigned char bus_width) -{ - int err = 0; - u8 width[] = { - [MMC_BUS_WIDTH_1] = SD_BUS_WIDTH_1BIT, - [MMC_BUS_WIDTH_4] = SD_BUS_WIDTH_4BIT, - [MMC_BUS_WIDTH_8] = SD_BUS_WIDTH_8BIT, - }; - - if (bus_width <= MMC_BUS_WIDTH_8) - err = rtsx_pci_write_register(host->pcr, SD_CFG1, - 0x03, width[bus_width]); - - return err; -} - -static int sd_power_on(struct realtek_pci_sdmmc *host) -{ - struct rtsx_pcr *pcr = host->pcr; - int err; - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE, - CARD_SHARE_MASK, CARD_SHARE_48_SD); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, - SD_CLK_EN, SD_CLK_EN); - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - err = rtsx_pci_card_pull_ctl_enable(pcr, RTSX_SD_CARD); - if (err < 0) - return err; - - err = rtsx_pci_card_power_on(pcr, RTSX_SD_CARD); - if (err < 0) - return err; - - err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); - if (err < 0) - return err; - - return 0; -} - -static int sd_power_off(struct realtek_pci_sdmmc *host) -{ - struct rtsx_pcr *pcr = host->pcr; - int err; - - rtsx_pci_init_cmd(pcr); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0); - - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - err = rtsx_pci_card_power_off(pcr, RTSX_SD_CARD); - if (err < 0) - return err; - - return rtsx_pci_card_pull_ctl_disable(pcr, RTSX_SD_CARD); -} - -static int sd_set_power_mode(struct realtek_pci_sdmmc *host, - unsigned char power_mode) -{ - int err; - - if (power_mode == MMC_POWER_OFF) - err = sd_power_off(host); - else - err = sd_power_on(host); - - return err; -} - -static int sd_set_timing(struct realtek_pci_sdmmc *host, - unsigned char timing, bool *ddr_mode) -{ - struct rtsx_pcr *pcr = host->pcr; - int err = 0; - - *ddr_mode = false; - - rtsx_pci_init_cmd(pcr); - - switch (timing) { - case MMC_TIMING_UHS_SDR104: - case MMC_TIMING_UHS_SDR50: - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, - 0x0C | SD_ASYNC_FIFO_NOT_RST, - SD_30_MODE | SD_ASYNC_FIFO_NOT_RST); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, - CLK_LOW_FREQ, CLK_LOW_FREQ); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, - CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); - break; - - case MMC_TIMING_UHS_DDR50: - *ddr_mode = true; - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, - 0x0C | SD_ASYNC_FIFO_NOT_RST, - SD_DDR_MODE | SD_ASYNC_FIFO_NOT_RST); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, - CLK_LOW_FREQ, CLK_LOW_FREQ); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, - CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, - DDR_VAR_TX_CMD_DAT, DDR_VAR_TX_CMD_DAT); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, - DDR_VAR_RX_DAT | DDR_VAR_RX_CMD, - DDR_VAR_RX_DAT | DDR_VAR_RX_CMD); - break; - - case MMC_TIMING_MMC_HS: - case MMC_TIMING_SD_HS: - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, - 0x0C, SD_20_MODE); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, - CLK_LOW_FREQ, CLK_LOW_FREQ); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, - CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, - SD20_TX_SEL_MASK, SD20_TX_14_AHEAD); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, - SD20_RX_SEL_MASK, SD20_RX_14_DELAY); - break; - - default: - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD_CFG1, 0x0C, SD_20_MODE); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, - CLK_LOW_FREQ, CLK_LOW_FREQ); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, - CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD_PUSH_POINT_CTL, 0xFF, 0); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, - SD20_RX_SEL_MASK, SD20_RX_POS_EDGE); - break; - } - - err = rtsx_pci_send_cmd(pcr, 100); - - return err; -} - -static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct realtek_pci_sdmmc *host = mmc_priv(mmc); - struct rtsx_pcr *pcr = host->pcr; - - if (host->eject) - return; - - mutex_lock(&pcr->pcr_mutex); - - rtsx_pci_start_run(pcr); - - sd_set_bus_width(host, ios->bus_width); - sd_set_power_mode(host, ios->power_mode); - sd_set_timing(host, ios->timing, &host->ddr_mode); - - host->vpclk = false; - host->double_clk = true; - - switch (ios->timing) { - case MMC_TIMING_UHS_SDR104: - case MMC_TIMING_UHS_SDR50: - host->ssc_depth = RTSX_SSC_DEPTH_2M; - host->vpclk = true; - host->double_clk = false; - break; - case MMC_TIMING_UHS_DDR50: - case MMC_TIMING_UHS_SDR25: - host->ssc_depth = RTSX_SSC_DEPTH_1M; - break; - default: - host->ssc_depth = RTSX_SSC_DEPTH_500K; - break; - } - - host->initial_mode = (ios->clock <= 1000000) ? true : false; - - host->clock = ios->clock; - rtsx_pci_switch_clock(pcr, ios->clock, host->ssc_depth, - host->initial_mode, host->double_clk, host->vpclk); - - mutex_unlock(&pcr->pcr_mutex); -} - -static int sdmmc_get_ro(struct mmc_host *mmc) -{ - struct realtek_pci_sdmmc *host = mmc_priv(mmc); - struct rtsx_pcr *pcr = host->pcr; - int ro = 0; - u32 val; - - if (host->eject) - return -ENOMEDIUM; - - mutex_lock(&pcr->pcr_mutex); - - rtsx_pci_start_run(pcr); - - /* Check SD mechanical write-protect switch */ - val = rtsx_pci_readl(pcr, RTSX_BIPR); - dev_dbg(sdmmc_dev(host), "%s: RTSX_BIPR = 0x%08x\n", __func__, val); - if (val & SD_WRITE_PROTECT) - ro = 1; - - mutex_unlock(&pcr->pcr_mutex); - - return ro; -} - -static int sdmmc_get_cd(struct mmc_host *mmc) -{ - struct realtek_pci_sdmmc *host = mmc_priv(mmc); - struct rtsx_pcr *pcr = host->pcr; - int cd = 0; - u32 val; - - if (host->eject) - return -ENOMEDIUM; - - mutex_lock(&pcr->pcr_mutex); - - rtsx_pci_start_run(pcr); - - /* Check SD card detect */ - val = rtsx_pci_card_exist(pcr); - dev_dbg(sdmmc_dev(host), "%s: RTSX_BIPR = 0x%08x\n", __func__, val); - if (val & SD_EXIST) - cd = 1; - - mutex_unlock(&pcr->pcr_mutex); - - return cd; -} - -static int sd_wait_voltage_stable_1(struct realtek_pci_sdmmc *host) -{ - struct rtsx_pcr *pcr = host->pcr; - int err; - u8 stat; - - /* Reference to Signal Voltage Switch Sequence in SD spec. - * Wait for a period of time so that the card can drive SD_CMD and - * SD_DAT[3:0] to low after sending back CMD11 response. - */ - mdelay(1); - - /* SD_CMD, SD_DAT[3:0] should be driven to low by card; - * If either one of SD_CMD,SD_DAT[3:0] is not low, - * abort the voltage switch sequence; - */ - err = rtsx_pci_read_register(pcr, SD_BUS_STAT, &stat); - if (err < 0) - return err; - - if (stat & (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | - SD_DAT1_STATUS | SD_DAT0_STATUS)) - return -EINVAL; - - /* Stop toggle SD clock */ - err = rtsx_pci_write_register(pcr, SD_BUS_STAT, - 0xFF, SD_CLK_FORCE_STOP); - if (err < 0) - return err; - - return 0; -} - -static int sd_wait_voltage_stable_2(struct realtek_pci_sdmmc *host) -{ - struct rtsx_pcr *pcr = host->pcr; - int err; - u8 stat, mask, val; - - /* Wait 1.8V output of voltage regulator in card stable */ - msleep(50); - - /* Toggle SD clock again */ - err = rtsx_pci_write_register(pcr, SD_BUS_STAT, 0xFF, SD_CLK_TOGGLE_EN); - if (err < 0) - return err; - - /* Wait for a period of time so that the card can drive - * SD_DAT[3:0] to high at 1.8V - */ - msleep(20); - - /* SD_CMD, SD_DAT[3:0] should be pulled high by host */ - err = rtsx_pci_read_register(pcr, SD_BUS_STAT, &stat); - if (err < 0) - return err; - - mask = SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | - SD_DAT1_STATUS | SD_DAT0_STATUS; - val = SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | - SD_DAT1_STATUS | SD_DAT0_STATUS; - if ((stat & mask) != val) { - dev_dbg(sdmmc_dev(host), - "%s: SD_BUS_STAT = 0x%x\n", __func__, stat); - rtsx_pci_write_register(pcr, SD_BUS_STAT, - SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); - rtsx_pci_write_register(pcr, CARD_CLK_EN, 0xFF, 0); - return -EINVAL; - } - - return 0; -} - -static int sd_change_bank_voltage(struct realtek_pci_sdmmc *host, u8 voltage) -{ - struct rtsx_pcr *pcr = host->pcr; - int err; - - if (voltage == SD_IO_3V3) { - err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); - if (err < 0) - return err; - } else if (voltage == SD_IO_1V8) { - err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); - if (err < 0) - return err; - } else { - return -EINVAL; - } - - return 0; -} - -static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct realtek_pci_sdmmc *host = mmc_priv(mmc); - struct rtsx_pcr *pcr = host->pcr; - int err = 0; - u8 voltage; - - dev_dbg(sdmmc_dev(host), "%s: signal_voltage = %d\n", - __func__, ios->signal_voltage); - - if (host->eject) - return -ENOMEDIUM; - - mutex_lock(&pcr->pcr_mutex); - - rtsx_pci_start_run(pcr); - - if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) - voltage = SD_IO_3V3; - else - voltage = SD_IO_1V8; - - if (voltage == SD_IO_1V8) { - err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); - if (err < 0) - goto out; - - err = sd_wait_voltage_stable_1(host); - if (err < 0) - goto out; - } - - err = sd_change_bank_voltage(host, voltage); - if (err < 0) - goto out; - - if (voltage == SD_IO_1V8) { - err = sd_wait_voltage_stable_2(host); - if (err < 0) - goto out; - } - - /* Stop toggle SD clock in idle */ - err = rtsx_pci_write_register(pcr, SD_BUS_STAT, - SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); - -out: - mutex_unlock(&pcr->pcr_mutex); - - return err; -} - -static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) -{ - struct realtek_pci_sdmmc *host = mmc_priv(mmc); - struct rtsx_pcr *pcr = host->pcr; - int err = 0; - - if (host->eject) - return -ENOMEDIUM; - - mutex_lock(&pcr->pcr_mutex); - - rtsx_pci_start_run(pcr); - - if (!host->ddr_mode) - err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK); - - mutex_unlock(&pcr->pcr_mutex); - - return err; -} - -static const struct mmc_host_ops realtek_pci_sdmmc_ops = { - .request = sdmmc_request, - .set_ios = sdmmc_set_ios, - .get_ro = sdmmc_get_ro, - .get_cd = sdmmc_get_cd, - .start_signal_voltage_switch = sdmmc_switch_voltage, - .execute_tuning = sdmmc_execute_tuning, -}; - -#ifdef CONFIG_PM -static int rtsx_pci_sdmmc_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); - struct mmc_host *mmc = host->mmc; - int err; - - dev_dbg(sdmmc_dev(host), "--> %s\n", __func__); - - err = mmc_suspend_host(mmc); - if (err) - return err; - - return 0; -} - -static int rtsx_pci_sdmmc_resume(struct platform_device *pdev) -{ - struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); - struct mmc_host *mmc = host->mmc; - - dev_dbg(sdmmc_dev(host), "--> %s\n", __func__); - - return mmc_resume_host(mmc); -} -#else /* CONFIG_PM */ -#define rtsx_pci_sdmmc_suspend NULL -#define rtsx_pci_sdmmc_resume NULL -#endif /* CONFIG_PM */ - -static void init_extra_caps(struct realtek_pci_sdmmc *host) -{ - struct mmc_host *mmc = host->mmc; - struct rtsx_pcr *pcr = host->pcr; - - dev_dbg(sdmmc_dev(host), "pcr->extra_caps = 0x%x\n", pcr->extra_caps); - - if (pcr->extra_caps & EXTRA_CAPS_SD_SDR50) - mmc->caps |= MMC_CAP_UHS_SDR50; - if (pcr->extra_caps & EXTRA_CAPS_SD_SDR104) - mmc->caps |= MMC_CAP_UHS_SDR104; - if (pcr->extra_caps & EXTRA_CAPS_SD_DDR50) - mmc->caps |= MMC_CAP_UHS_DDR50; - if (pcr->extra_caps & EXTRA_CAPS_MMC_HSDDR) - mmc->caps |= MMC_CAP_1_8V_DDR; - if (pcr->extra_caps & EXTRA_CAPS_MMC_8BIT) - mmc->caps |= MMC_CAP_8_BIT_DATA; -} - -static void realtek_init_host(struct realtek_pci_sdmmc *host) -{ - struct mmc_host *mmc = host->mmc; - - mmc->f_min = 250000; - mmc->f_max = 208000000; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | - MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; - mmc->max_current_330 = 400; - mmc->max_current_180 = 800; - mmc->ops = &realtek_pci_sdmmc_ops; - - init_extra_caps(host); - - mmc->max_segs = 256; - mmc->max_seg_size = 65536; - mmc->max_blk_size = 512; - mmc->max_blk_count = 65535; - mmc->max_req_size = 524288; -} - -static void rtsx_pci_sdmmc_card_event(struct platform_device *pdev) -{ - struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); - - mmc_detect_change(host->mmc, 0); -} - -static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct realtek_pci_sdmmc *host; - struct rtsx_pcr *pcr; - struct pcr_handle *handle = pdev->dev.platform_data; - - if (!handle) - return -ENXIO; - - pcr = handle->pcr; - if (!pcr) - return -ENXIO; - - dev_dbg(&(pdev->dev), ": Realtek PCI-E SDMMC controller found\n"); - - mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); - if (!mmc) - return -ENOMEM; - - host = mmc_priv(mmc); - host->pcr = pcr; - host->mmc = mmc; - host->pdev = pdev; - platform_set_drvdata(pdev, host); - pcr->slots[RTSX_SD_CARD].p_dev = pdev; - pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; - - mutex_init(&host->host_mutex); - - realtek_init_host(host); - - mmc_add_host(mmc); - - return 0; -} - -static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) -{ - struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); - struct rtsx_pcr *pcr; - struct mmc_host *mmc; - - if (!host) - return 0; - - pcr = host->pcr; - pcr->slots[RTSX_SD_CARD].p_dev = NULL; - pcr->slots[RTSX_SD_CARD].card_event = NULL; - mmc = host->mmc; - host->eject = true; - - mutex_lock(&host->host_mutex); - if (host->mrq) { - dev_dbg(&(pdev->dev), - "%s: Controller removed during transfer\n", - mmc_hostname(mmc)); - - rtsx_pci_complete_unfinished_transfer(pcr); - - host->mrq->cmd->error = -ENOMEDIUM; - if (host->mrq->stop) - host->mrq->stop->error = -ENOMEDIUM; - mmc_request_done(mmc, host->mrq); - } - mutex_unlock(&host->host_mutex); - - mmc_remove_host(mmc); - mmc_free_host(mmc); - - platform_set_drvdata(pdev, NULL); - - dev_dbg(&(pdev->dev), - ": Realtek PCI-E SDMMC controller has been removed\n"); - - return 0; -} - -static struct platform_device_id rtsx_pci_sdmmc_ids[] = { - { - .name = DRV_NAME_RTSX_PCI_SDMMC, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(platform, rtsx_pci_sdmmc_ids); - -static struct platform_driver rtsx_pci_sdmmc_driver = { - .probe = rtsx_pci_sdmmc_drv_probe, - .remove = rtsx_pci_sdmmc_drv_remove, - .id_table = rtsx_pci_sdmmc_ids, - .suspend = rtsx_pci_sdmmc_suspend, - .resume = rtsx_pci_sdmmc_resume, - .driver = { - .owner = THIS_MODULE, - .name = DRV_NAME_RTSX_PCI_SDMMC, - }, -}; -module_platform_driver(rtsx_pci_sdmmc_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Wei WANG "); -MODULE_DESCRIPTION("Realtek PCI-E SD/MMC Card Host Driver"); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 63fb265e0da..a04f87d7ee3 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -26,8 +26,9 @@ #include #include +#include -#include +#include #include "s3cmci.h" @@ -246,7 +247,7 @@ static void s3cmci_check_sdio_irq(struct s3cmci_host *host) { if (host->sdio_irqen) { if (gpio_get_value(S3C2410_GPE(8)) == 0) { - pr_debug("%s: signalling irq\n", __func__); + printk(KERN_DEBUG "%s: signalling irq\n", __func__); mmc_signal_sdio_irq(host->mmc); } } @@ -343,7 +344,7 @@ static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer) local_irq_save(flags); - /* pr_debug("%s: transfer %d\n", __func__, transfer); */ + //printk(KERN_DEBUG "%s: transfer %d\n", __func__, transfer); host->irq_disabled = transfer; @@ -912,9 +913,9 @@ request_done: } static void s3cmci_dma_setup(struct s3cmci_host *host, - enum dma_data_direction source) + enum s3c2410_dmasrc source) { - static enum dma_data_direction last_source = -1; + static enum s3c2410_dmasrc last_source = -1; static int setup_ok; if (last_source == source) @@ -1086,7 +1087,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); - s3cmci_dma_setup(host, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW); s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, @@ -1236,9 +1237,12 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_ON: case MMC_POWER_UP: - /* Configure GPE5...GPE10 pins in SD mode */ - s3c_gpio_cfgall_range(S3C2410_GPE(5), 6, S3C_GPIO_SFN(2), - S3C_GPIO_PULL_NONE); + s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK); + s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD); + s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0); + s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1); + s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2); + s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3); if (host->pdata->set_power) host->pdata->set_power(ios->power_mode, ios->vdd); @@ -1540,7 +1544,7 @@ static inline void s3cmci_debugfs_remove(struct s3cmci_host *host) { } #endif /* CONFIG_DEBUG_FS */ -static int s3cmci_probe(struct platform_device *pdev) +static int __devinit s3cmci_probe(struct platform_device *pdev) { struct s3cmci_host *host; struct mmc_host *mmc; @@ -1602,7 +1606,7 @@ static int s3cmci_probe(struct platform_device *pdev) host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!host->mem) { dev_err(&pdev->dev, - "failed to get io memory region resource.\n"); + "failed to get io memory region resouce.\n"); ret = -ENOENT; goto probe_free_gpio; @@ -1626,7 +1630,7 @@ static int s3cmci_probe(struct platform_device *pdev) host->irq = platform_get_irq(pdev, 0); if (host->irq == 0) { - dev_err(&pdev->dev, "failed to get interrupt resource.\n"); + dev_err(&pdev->dev, "failed to get interrupt resouce.\n"); ret = -EINVAL; goto probe_iounmap; } @@ -1819,7 +1823,7 @@ static void s3cmci_shutdown(struct platform_device *pdev) clk_disable(host->clk); } -static int s3cmci_remove(struct platform_device *pdev) +static int __devexit s3cmci_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct s3cmci_host *host = mmc_priv(mmc); @@ -1906,11 +1910,22 @@ static struct platform_driver s3cmci_driver = { }, .id_table = s3cmci_driver_ids, .probe = s3cmci_probe, - .remove = s3cmci_remove, + .remove = __devexit_p(s3cmci_remove), .shutdown = s3cmci_shutdown, }; -module_platform_driver(s3cmci_driver); +static int __init s3cmci_init(void) +{ + return platform_driver_register(&s3cmci_driver); +} + +static void __exit s3cmci_exit(void) +{ + platform_driver_unregister(&s3cmci_driver); +} + +module_init(s3cmci_init); +module_exit(s3cmci_exit); MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c deleted file mode 100644 index 2592dddbd96..00000000000 --- a/drivers/mmc/host/sdhci-acpi.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Secure Digital Host Controller Interface ACPI driver. - * - * Copyright (c) 2012, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "sdhci.h" - -enum { - SDHCI_ACPI_SD_CD = BIT(0), - SDHCI_ACPI_RUNTIME_PM = BIT(1), -}; - -struct sdhci_acpi_chip { - const struct sdhci_ops *ops; - unsigned int quirks; - unsigned int quirks2; - unsigned long caps; - unsigned int caps2; - mmc_pm_flag_t pm_caps; -}; - -struct sdhci_acpi_slot { - const struct sdhci_acpi_chip *chip; - unsigned int quirks; - unsigned int quirks2; - unsigned long caps; - unsigned int caps2; - mmc_pm_flag_t pm_caps; - unsigned int flags; -}; - -struct sdhci_acpi_host { - struct sdhci_host *host; - const struct sdhci_acpi_slot *slot; - struct platform_device *pdev; - bool use_runtime_pm; -}; - -static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) -{ - return c->slot && (c->slot->flags & flag); -} - -static int sdhci_acpi_enable_dma(struct sdhci_host *host) -{ - return 0; -} - -static const struct sdhci_ops sdhci_acpi_ops_dflt = { - .enable_dma = sdhci_acpi_enable_dma, -}; - -static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { - .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, - .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD, - .flags = SDHCI_ACPI_RUNTIME_PM, - .pm_caps = MMC_PM_KEEP_POWER, -}; - -static const struct acpi_device_id sdhci_acpi_ids[] = { - { "INT33C6", (kernel_ulong_t)&sdhci_acpi_slot_int_sdio }, - { "PNP0D40" }, - { }, -}; -MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); - -static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid) -{ - const struct acpi_device_id *id; - - for (id = sdhci_acpi_ids; id->id[0]; id++) - if (!strcmp(id->id, hid)) - return (const struct sdhci_acpi_slot *)id->driver_data; - return NULL; -} - -static int sdhci_acpi_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - acpi_handle handle = ACPI_HANDLE(dev); - struct acpi_device *device; - struct sdhci_acpi_host *c; - struct sdhci_host *host; - struct resource *iomem; - resource_size_t len; - const char *hid; - int err; - - if (acpi_bus_get_device(handle, &device)) - return -ENODEV; - - if (acpi_bus_get_status(device) || !device->status.present) - return -ENODEV; - - hid = acpi_device_hid(device); - - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem) - return -ENOMEM; - - len = resource_size(iomem); - if (len < 0x100) - dev_err(dev, "Invalid iomem size!\n"); - - if (!devm_request_mem_region(dev, iomem->start, len, dev_name(dev))) - return -ENOMEM; - - host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host)); - if (IS_ERR(host)) - return PTR_ERR(host); - - c = sdhci_priv(host); - c->host = host; - c->slot = sdhci_acpi_get_slot(hid); - c->pdev = pdev; - c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM); - - platform_set_drvdata(pdev, c); - - host->hw_name = "ACPI"; - host->ops = &sdhci_acpi_ops_dflt; - host->irq = platform_get_irq(pdev, 0); - - host->ioaddr = devm_ioremap_nocache(dev, iomem->start, - resource_size(iomem)); - if (host->ioaddr == NULL) { - err = -ENOMEM; - goto err_free; - } - - if (!dev->dma_mask) { - u64 dma_mask; - - if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) { - /* 64-bit DMA is not supported at present */ - dma_mask = DMA_BIT_MASK(32); - } else { - dma_mask = DMA_BIT_MASK(32); - } - - dev->dma_mask = &dev->coherent_dma_mask; - dev->coherent_dma_mask = dma_mask; - } - - if (c->slot) { - if (c->slot->chip) { - host->ops = c->slot->chip->ops; - host->quirks |= c->slot->chip->quirks; - host->quirks2 |= c->slot->chip->quirks2; - host->mmc->caps |= c->slot->chip->caps; - host->mmc->caps2 |= c->slot->chip->caps2; - host->mmc->pm_caps |= c->slot->chip->pm_caps; - } - host->quirks |= c->slot->quirks; - host->quirks2 |= c->slot->quirks2; - host->mmc->caps |= c->slot->caps; - host->mmc->caps2 |= c->slot->caps2; - host->mmc->pm_caps |= c->slot->pm_caps; - } - - err = sdhci_add_host(host); - if (err) - goto err_free; - - if (c->use_runtime_pm) { - pm_suspend_ignore_children(dev, 1); - pm_runtime_set_autosuspend_delay(dev, 50); - pm_runtime_use_autosuspend(dev); - pm_runtime_enable(dev); - } - - return 0; - -err_free: - platform_set_drvdata(pdev, NULL); - sdhci_free_host(c->host); - return err; -} - -static int sdhci_acpi_remove(struct platform_device *pdev) -{ - struct sdhci_acpi_host *c = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; - int dead; - - if (c->use_runtime_pm) { - pm_runtime_get_sync(dev); - pm_runtime_disable(dev); - pm_runtime_put_noidle(dev); - } - - dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0); - sdhci_remove_host(c->host, dead); - platform_set_drvdata(pdev, NULL); - sdhci_free_host(c->host); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP - -static int sdhci_acpi_suspend(struct device *dev) -{ - struct sdhci_acpi_host *c = dev_get_drvdata(dev); - - return sdhci_suspend_host(c->host); -} - -static int sdhci_acpi_resume(struct device *dev) -{ - struct sdhci_acpi_host *c = dev_get_drvdata(dev); - - return sdhci_resume_host(c->host); -} - -#else - -#define sdhci_acpi_suspend NULL -#define sdhci_acpi_resume NULL - -#endif - -#ifdef CONFIG_PM_RUNTIME - -static int sdhci_acpi_runtime_suspend(struct device *dev) -{ - struct sdhci_acpi_host *c = dev_get_drvdata(dev); - - return sdhci_runtime_suspend_host(c->host); -} - -static int sdhci_acpi_runtime_resume(struct device *dev) -{ - struct sdhci_acpi_host *c = dev_get_drvdata(dev); - - return sdhci_runtime_resume_host(c->host); -} - -static int sdhci_acpi_runtime_idle(struct device *dev) -{ - return 0; -} - -#else - -#define sdhci_acpi_runtime_suspend NULL -#define sdhci_acpi_runtime_resume NULL -#define sdhci_acpi_runtime_idle NULL - -#endif - -static const struct dev_pm_ops sdhci_acpi_pm_ops = { - .suspend = sdhci_acpi_suspend, - .resume = sdhci_acpi_resume, - .runtime_suspend = sdhci_acpi_runtime_suspend, - .runtime_resume = sdhci_acpi_runtime_resume, - .runtime_idle = sdhci_acpi_runtime_idle, -}; - -static struct platform_driver sdhci_acpi_driver = { - .driver = { - .name = "sdhci-acpi", - .owner = THIS_MODULE, - .acpi_match_table = sdhci_acpi_ids, - .pm = &sdhci_acpi_pm_ops, - }, - .probe = sdhci_acpi_probe, - .remove = sdhci_acpi_remove, -}; - -module_platform_driver(sdhci_acpi_driver); - -MODULE_DESCRIPTION("Secure Digital Host Controller Interface ACPI driver"); -MODULE_AUTHOR("Adrian Hunter"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index 30bfdc4ae52..4b920b7621c 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "sdhci-pltfm.h" @@ -95,12 +94,12 @@ static struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { SDHCI_QUIRK_NONSTANDARD_CLOCK, }; -static int sdhci_cns3xxx_probe(struct platform_device *pdev) +static int __devinit sdhci_cns3xxx_probe(struct platform_device *pdev) { return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata); } -static int sdhci_cns3xxx_remove(struct platform_device *pdev) +static int __devexit sdhci_cns3xxx_remove(struct platform_device *pdev) { return sdhci_pltfm_unregister(pdev); } @@ -109,13 +108,26 @@ static struct platform_driver sdhci_cns3xxx_driver = { .driver = { .name = "sdhci-cns3xxx", .owner = THIS_MODULE, - .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_cns3xxx_probe, - .remove = sdhci_cns3xxx_remove, + .remove = __devexit_p(sdhci_cns3xxx_remove), +#ifdef CONFIG_PM + .suspend = sdhci_pltfm_suspend, + .resume = sdhci_pltfm_resume, +#endif }; -module_platform_driver(sdhci_cns3xxx_driver); +static int __init sdhci_cns3xxx_init(void) +{ + return platform_driver_register(&sdhci_cns3xxx_driver); +} +module_init(sdhci_cns3xxx_init); + +static void __exit sdhci_cns3xxx_exit(void) +{ + platform_driver_unregister(&sdhci_cns3xxx_driver); +} +module_exit(sdhci_cns3xxx_exit); MODULE_DESCRIPTION("SDHCI driver for CNS3xxx"); MODULE_AUTHOR("Scott Shu, " diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 169fab91778..f2d29dca442 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -19,30 +19,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include -#include #include #include -#include -#include -#include #include "sdhci-pltfm.h" -struct sdhci_dove_priv { - struct clk *clk; - int gpio_cd; -}; - -static irqreturn_t sdhci_dove_carddetect_irq(int irq, void *data) -{ - struct sdhci_host *host = data; - - tasklet_schedule(&host->card_tasklet); - return IRQ_HANDLED; -} - static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) { u16 ret; @@ -60,25 +41,16 @@ static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) static u32 sdhci_dove_readl(struct sdhci_host *host, int reg) { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_dove_priv *priv = pltfm_host->priv; u32 ret; - ret = readl(host->ioaddr + reg); - switch (reg) { case SDHCI_CAPABILITIES: + ret = readl(host->ioaddr + reg); /* Mask the support for 3.0V */ ret &= ~SDHCI_CAN_VDD_300; break; - case SDHCI_PRESENT_STATE: - if (gpio_is_valid(priv->gpio_cd)) { - if (gpio_get_value(priv->gpio_cd) == 0) - ret |= SDHCI_CARD_PRESENT; - else - ret &= ~SDHCI_CARD_PRESENT; - } - break; + default: + ret = readl(host->ioaddr + reg); } return ret; } @@ -93,128 +65,43 @@ static struct sdhci_pltfm_data sdhci_dove_pdata = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_FORCE_DMA | - SDHCI_QUIRK_NO_HISPD_BIT, + SDHCI_QUIRK_FORCE_DMA, }; -static int sdhci_dove_probe(struct platform_device *pdev) +static int __devinit sdhci_dove_probe(struct platform_device *pdev) { - struct sdhci_host *host; - struct sdhci_pltfm_host *pltfm_host; - struct sdhci_dove_priv *priv; - int ret; - - priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv), - GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "unable to allocate private data"); - return -ENOMEM; - } - - priv->clk = devm_clk_get(&pdev->dev, NULL); - - if (pdev->dev.of_node) { - priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node, - "cd-gpios", 0); - } else { - priv->gpio_cd = -EINVAL; - } - - if (gpio_is_valid(priv->gpio_cd)) { - ret = gpio_request(priv->gpio_cd, "sdhci-cd"); - if (ret) { - dev_err(&pdev->dev, "card detect gpio request failed: %d\n", - ret); - return ret; - } - gpio_direction_input(priv->gpio_cd); - } - - host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata); - if (IS_ERR(host)) { - ret = PTR_ERR(host); - goto err_sdhci_pltfm_init; - } - - pltfm_host = sdhci_priv(host); - pltfm_host->priv = priv; - - if (!IS_ERR(priv->clk)) - clk_prepare_enable(priv->clk); - - sdhci_get_of_property(pdev); - - ret = sdhci_add_host(host); - if (ret) - goto err_sdhci_add; - - /* - * We must request the IRQ after sdhci_add_host(), as the tasklet only - * gets setup in sdhci_add_host() and we oops. - */ - if (gpio_is_valid(priv->gpio_cd)) { - ret = request_irq(gpio_to_irq(priv->gpio_cd), - sdhci_dove_carddetect_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - mmc_hostname(host->mmc), host); - if (ret) { - dev_err(&pdev->dev, "card detect irq request failed: %d\n", - ret); - goto err_request_irq; - } - } - - return 0; - -err_request_irq: - sdhci_remove_host(host, 0); -err_sdhci_add: - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); - sdhci_pltfm_free(pdev); -err_sdhci_pltfm_init: - if (gpio_is_valid(priv->gpio_cd)) - gpio_free(priv->gpio_cd); - return ret; + return sdhci_pltfm_register(pdev, &sdhci_dove_pdata); } -static int sdhci_dove_remove(struct platform_device *pdev) +static int __devexit sdhci_dove_remove(struct platform_device *pdev) { - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_dove_priv *priv = pltfm_host->priv; - - sdhci_pltfm_unregister(pdev); - - if (gpio_is_valid(priv->gpio_cd)) { - free_irq(gpio_to_irq(priv->gpio_cd), host); - gpio_free(priv->gpio_cd); - } - - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); - - return 0; + return sdhci_pltfm_unregister(pdev); } -static const struct of_device_id sdhci_dove_of_match_table[] = { - { .compatible = "marvell,dove-sdhci", }, - {} -}; -MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table); - static struct platform_driver sdhci_dove_driver = { .driver = { .name = "sdhci-dove", .owner = THIS_MODULE, - .pm = SDHCI_PLTFM_PMOPS, - .of_match_table = of_match_ptr(sdhci_dove_of_match_table), }, .probe = sdhci_dove_probe, - .remove = sdhci_dove_remove, + .remove = __devexit_p(sdhci_dove_remove), +#ifdef CONFIG_PM + .suspend = sdhci_pltfm_suspend, + .resume = sdhci_pltfm_resume, +#endif }; -module_platform_driver(sdhci_dove_driver); +static int __init sdhci_dove_init(void) +{ + return platform_driver_register(&sdhci_dove_driver); +} +module_init(sdhci_dove_init); + +static void __exit sdhci_dove_exit(void) +{ + platform_driver_unregister(&sdhci_dove_driver); +} +module_exit(sdhci_dove_exit); MODULE_DESCRIPTION("SDHCI driver for Dove"); MODULE_AUTHOR("Saeed Bishara , " diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index e07df812ff1..4dc0028086a 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -24,8 +24,7 @@ #include #include #include -#include -#include +#include #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" @@ -33,16 +32,6 @@ /* VENDOR SPEC register */ #define SDHCI_VENDOR_SPEC 0xC0 #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 -#define SDHCI_WTMK_LVL 0x44 -#define SDHCI_MIX_CTRL 0x48 - -/* - * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: - * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, - * but bit28 is used as the INT DMA ERR in fsl eSDHC design. - * Define this macro DMA error INT for fsl eSDHC - */ -#define SDHCI_INT_VENDOR_SPEC_DMA_ERR 0x10000000 /* * The CMDTYPE of the CMD register (offset 0xE) should be set to @@ -62,18 +51,13 @@ enum imx_esdhc_type { IMX35_ESDHC, IMX51_ESDHC, IMX53_ESDHC, - IMX6Q_USDHC, }; struct pltfm_imx_data { int flags; u32 scratchpad; enum imx_esdhc_type devtype; - struct pinctrl *pinctrl; struct esdhc_platform_data boarddata; - struct clk *clk_ipg; - struct clk *clk_ahb; - struct clk *clk_per; }; static struct platform_device_id imx_esdhc_devtype[] = { @@ -89,9 +73,6 @@ static struct platform_device_id imx_esdhc_devtype[] = { }, { .name = "sdhci-esdhc-imx53", .driver_data = IMX53_ESDHC, - }, { - .name = "sdhci-usdhc-imx6q", - .driver_data = IMX6Q_USDHC, }, { /* sentinel */ } @@ -103,7 +84,6 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, - { .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); @@ -128,11 +108,6 @@ static inline int is_imx53_esdhc(struct pltfm_imx_data *data) return data->devtype == IMX53_ESDHC; } -static inline int is_imx6q_usdhc(struct pltfm_imx_data *data) -{ - return data->devtype == IMX6Q_USDHC; -} - static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) { void __iomem *base = host->ioaddr + (reg & ~0x3); @@ -160,27 +135,6 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) val |= SDHCI_CARD_PRESENT; } - if (unlikely(reg == SDHCI_CAPABILITIES)) { - /* In FSL esdhc IC module, only bit20 is used to indicate the - * ADMA2 capability of esdhc, but this bit is messed up on - * some SOCs (e.g. on MX25, MX35 this bit is set, but they - * don't actually support ADMA2). So set the BROKEN_ADMA - * uirk on MX25/35 platforms. - */ - - if (val & SDHCI_CAN_DO_ADMA1) { - val &= ~SDHCI_CAN_DO_ADMA1; - val |= SDHCI_CAN_DO_ADMA2; - } - } - - if (unlikely(reg == SDHCI_INT_STATUS)) { - if (val & SDHCI_INT_VENDOR_SPEC_DMA_ERR) { - val &= ~SDHCI_INT_VENDOR_SPEC_DMA_ERR; - val |= SDHCI_INT_ADMA_ERROR; - } - } - return val; } @@ -225,28 +179,13 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); } - if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { - if (val & SDHCI_INT_ADMA_ERROR) { - val &= ~SDHCI_INT_ADMA_ERROR; - val |= SDHCI_INT_VENDOR_SPEC_DMA_ERR; - } - } - writel(val, host->ioaddr + reg); } static u16 esdhc_readw_le(struct sdhci_host *host, int reg) { - if (unlikely(reg == SDHCI_HOST_VERSION)) { - u16 val = readw(host->ioaddr + (reg ^ 2)); - /* - * uSDHC supports SDHCI v3.0, but it's encoded as value - * 0x3 in host controller version register, which violates - * SDHCI_SPEC_300 definition. Work it around here. - */ - if ((val & SDHCI_SPEC_VER_MASK) == 3) - return --val; - } + if (unlikely(reg == SDHCI_HOST_VERSION)) + reg ^= 2; return readw(host->ioaddr + reg); } @@ -274,21 +213,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) imx_data->scratchpad = val; return; case SDHCI_COMMAND: - if ((host->cmd->opcode == MMC_STOP_TRANSMISSION || - host->cmd->opcode == MMC_SET_BLOCK_COUNT) && - (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) + if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) + && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) val |= SDHCI_CMD_ABORTCMD; - - if (is_imx6q_usdhc(imx_data)) { - u32 m = readl(host->ioaddr + SDHCI_MIX_CTRL); - m = imx_data->scratchpad | (m & 0xffff0000); - writel(m, host->ioaddr + SDHCI_MIX_CTRL); - writel(val << 16, - host->ioaddr + SDHCI_TRANSFER_MODE); - } else { - writel(val << 16 | imx_data->scratchpad, - host->ioaddr + SDHCI_TRANSFER_MODE); - } + writel(val << 16 | imx_data->scratchpad, + host->ioaddr + SDHCI_TRANSFER_MODE); return; case SDHCI_BLOCK_SIZE: val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); @@ -299,8 +228,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; u32 new_val; switch (reg) { @@ -315,13 +242,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) new_val = val & (SDHCI_CTRL_LED | \ SDHCI_CTRL_4BITBUS | \ SDHCI_CTRL_D3CD); - /* ensure the endianness */ + /* ensure the endianess */ new_val |= ESDHC_HOST_CONTROL_LE; - /* bits 8&9 are reserved on mx25 */ - if (!is_imx25_esdhc(imx_data)) { - /* DMA mode bits are shifted */ - new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; - } + /* DMA mode bits are shifted */ + new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; esdhc_clrset_le(host, 0xffff, new_val, reg); return; @@ -387,10 +311,9 @@ static struct sdhci_ops sdhci_esdhc_ops = { }; static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { - .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT - | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC - | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC + .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_CARD_DETECTION, + /* ADMA has issues. Might be fixable */ .ops = &sdhci_esdhc_ops, }; @@ -403,7 +326,7 @@ static irqreturn_t cd_irq(int irq, void *data) }; #ifdef CONFIG_OF -static int +static int __devinit sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, struct esdhc_platform_data *boarddata) { @@ -412,7 +335,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, if (!np) return -ENODEV; - if (of_get_property(np, "non-removable", NULL)) + if (of_get_property(np, "fsl,card-wired", NULL)) boarddata->cd_type = ESDHC_CD_PERMANENT; if (of_get_property(np, "fsl,cd-controller", NULL)) @@ -440,13 +363,14 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, } #endif -static int sdhci_esdhc_imx_probe(struct platform_device *pdev) +static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(imx_esdhc_dt_ids, &pdev->dev); struct sdhci_pltfm_host *pltfm_host; struct sdhci_host *host; struct esdhc_platform_data *boarddata; + struct clk *clk; int err; struct pltfm_imx_data *imx_data; @@ -456,10 +380,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) pltfm_host = sdhci_priv(host); - imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL); + imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); if (!imx_data) { err = -ENOMEM; - goto free_sdhci; + goto err_imx_data; } if (of_id) @@ -467,59 +391,31 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) imx_data->devtype = pdev->id_entry->driver_data; pltfm_host->priv = imx_data; - imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(imx_data->clk_ipg)) { - err = PTR_ERR(imx_data->clk_ipg); - goto free_sdhci; - } - - imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); - if (IS_ERR(imx_data->clk_ahb)) { - err = PTR_ERR(imx_data->clk_ahb); - goto free_sdhci; + clk = clk_get(mmc_dev(host->mmc), NULL); + if (IS_ERR(clk)) { + dev_err(mmc_dev(host->mmc), "clk err\n"); + err = PTR_ERR(clk); + goto err_clk_get; } + clk_enable(clk); + pltfm_host->clk = clk; - imx_data->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(imx_data->clk_per)) { - err = PTR_ERR(imx_data->clk_per); - goto free_sdhci; - } - - pltfm_host->clk = imx_data->clk_per; - - clk_prepare_enable(imx_data->clk_per); - clk_prepare_enable(imx_data->clk_ipg); - clk_prepare_enable(imx_data->clk_ahb); - - imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(imx_data->pinctrl)) { - err = PTR_ERR(imx_data->pinctrl); - goto disable_clk; - } - - host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; + if (!is_imx25_esdhc(imx_data)) + host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ - host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK - | SDHCI_QUIRK_BROKEN_ADMA; + host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; if (is_imx53_esdhc(imx_data)) imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; - /* - * The imx6q ROM code will change the default watermark level setting - * to something insane. Change it back here. - */ - if (is_imx6q_usdhc(imx_data)) - writel(0x08100810, host->ioaddr + SDHCI_WTMK_LVL); - boarddata = &imx_data->boarddata; if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { if (!host->mmc->parent->platform_data) { dev_err(mmc_dev(host->mmc), "no board data!\n"); err = -EINVAL; - goto disable_clk; + goto no_board_data; } imx_data->boarddata = *((struct esdhc_platform_data *) host->mmc->parent->platform_data); @@ -527,8 +423,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) /* write_protect */ if (boarddata->wp_type == ESDHC_WP_GPIO) { - err = devm_gpio_request_one(&pdev->dev, boarddata->wp_gpio, - GPIOF_IN, "ESDHC_WP"); + err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); if (err) { dev_warn(mmc_dev(host->mmc), "no write-protect pin available!\n"); @@ -544,21 +439,19 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) switch (boarddata->cd_type) { case ESDHC_CD_GPIO: - err = devm_gpio_request_one(&pdev->dev, boarddata->cd_gpio, - GPIOF_IN, "ESDHC_CD"); + err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); if (err) { dev_err(mmc_dev(host->mmc), "no card-detect pin available!\n"); - goto disable_clk; + goto no_card_detect_pin; } - err = devm_request_irq(&pdev->dev, - gpio_to_irq(boarddata->cd_gpio), cd_irq, + err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, mmc_hostname(host->mmc), host); if (err) { dev_err(mmc_dev(host->mmc), "request irq error\n"); - goto disable_clk; + goto no_card_detect_irq; } /* fall through */ @@ -577,31 +470,50 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) err = sdhci_add_host(host); if (err) - goto disable_clk; + goto err_add_host; return 0; -disable_clk: - clk_disable_unprepare(imx_data->clk_per); - clk_disable_unprepare(imx_data->clk_ipg); - clk_disable_unprepare(imx_data->clk_ahb); -free_sdhci: +err_add_host: + if (gpio_is_valid(boarddata->cd_gpio)) + free_irq(gpio_to_irq(boarddata->cd_gpio), host); +no_card_detect_irq: + if (gpio_is_valid(boarddata->cd_gpio)) + gpio_free(boarddata->cd_gpio); + if (gpio_is_valid(boarddata->wp_gpio)) + gpio_free(boarddata->wp_gpio); +no_card_detect_pin: +no_board_data: + clk_disable(pltfm_host->clk); + clk_put(pltfm_host->clk); +err_clk_get: + kfree(imx_data); +err_imx_data: sdhci_pltfm_free(pdev); return err; } -static int sdhci_esdhc_imx_remove(struct platform_device *pdev) +static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct esdhc_platform_data *boarddata = &imx_data->boarddata; int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); sdhci_remove_host(host, dead); - clk_disable_unprepare(imx_data->clk_per); - clk_disable_unprepare(imx_data->clk_ipg); - clk_disable_unprepare(imx_data->clk_ahb); + if (gpio_is_valid(boarddata->wp_gpio)) + gpio_free(boarddata->wp_gpio); + + if (gpio_is_valid(boarddata->cd_gpio)) { + free_irq(gpio_to_irq(boarddata->cd_gpio), host); + gpio_free(boarddata->cd_gpio); + } + + clk_disable(pltfm_host->clk); + clk_put(pltfm_host->clk); + kfree(imx_data); sdhci_pltfm_free(pdev); @@ -613,14 +525,27 @@ static struct platform_driver sdhci_esdhc_imx_driver = { .name = "sdhci-esdhc-imx", .owner = THIS_MODULE, .of_match_table = imx_esdhc_dt_ids, - .pm = SDHCI_PLTFM_PMOPS, }, .id_table = imx_esdhc_devtype, .probe = sdhci_esdhc_imx_probe, - .remove = sdhci_esdhc_imx_remove, + .remove = __devexit_p(sdhci_esdhc_imx_remove), +#ifdef CONFIG_PM + .suspend = sdhci_pltfm_suspend, + .resume = sdhci_pltfm_resume, +#endif }; -module_platform_driver(sdhci_esdhc_imx_driver); +static int __init sdhci_esdhc_imx_init(void) +{ + return platform_driver_register(&sdhci_esdhc_imx_driver); +} +module_init(sdhci_esdhc_imx_init); + +static void __exit sdhci_esdhc_imx_exit(void) +{ + platform_driver_unregister(&sdhci_esdhc_imx_driver); +} +module_exit(sdhci_esdhc_imx_exit); MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); MODULE_AUTHOR("Wolfram Sang "); diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index d25f9ab9a54..c3b08f11194 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -48,14 +48,14 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) int div = 1; u32 temp; - if (clock == 0) - goto out; - temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); + if (clock == 0) + goto out; + while (host->max_clk / pre_div / 16 > clock && pre_div < 256) pre_div *= 2; @@ -73,7 +73,7 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) | (div << ESDHC_DIVIDER_SHIFT) | (pre_div << ESDHC_PREDIV_SHIFT)); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - mdelay(1); + mdelay(100); out: host->clock = clock; } diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index f32526d2d96..fe604df6501 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -1,7 +1,7 @@ /* * Freescale eSDHC controller driver. * - * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc. + * Copyright (c) 2007 Freescale Semiconductor, Inc. * Copyright (c) 2009 MontaVista Software, Inc. * * Authors: Xiaobo Xie @@ -14,90 +14,22 @@ */ #include -#include #include -#include #include #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" -#define VENDOR_V_22 0x12 -#define VENDOR_V_23 0x13 -static u32 esdhc_readl(struct sdhci_host *host, int reg) -{ - u32 ret; - - ret = in_be32(host->ioaddr + reg); - /* - * The bit of ADMA flag in eSDHC is not compatible with standard - * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is - * supported by eSDHC. - * And for many FSL eSDHC controller, the reset value of field - * SDHCI_CAN_DO_ADMA1 is one, but some of them can't support ADMA, - * only these vendor version is greater than 2.2/0x12 support ADMA. - * For FSL eSDHC, must aligned 4-byte, so use 0xFC to read the - * the verdor version number, oxFE is SDHCI_HOST_VERSION. - */ - if ((reg == SDHCI_CAPABILITIES) && (ret & SDHCI_CAN_DO_ADMA1)) { - u32 tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS); - tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; - if (tmp > VENDOR_V_22) - ret |= SDHCI_CAN_DO_ADMA2; - } - - return ret; -} - static u16 esdhc_readw(struct sdhci_host *host, int reg) { u16 ret; - int base = reg & ~0x3; - int shift = (reg & 0x2) * 8; if (unlikely(reg == SDHCI_HOST_VERSION)) - ret = in_be32(host->ioaddr + base) & 0xffff; + ret = in_be16(host->ioaddr + reg); else - ret = (in_be32(host->ioaddr + base) >> shift) & 0xffff; + ret = sdhci_be32bs_readw(host, reg); return ret; } -static u8 esdhc_readb(struct sdhci_host *host, int reg) -{ - int base = reg & ~0x3; - int shift = (reg & 0x3) * 8; - u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff; - - /* - * "DMA select" locates at offset 0x28 in SD specification, but on - * P5020 or P3041, it locates at 0x29. - */ - if (reg == SDHCI_HOST_CONTROL) { - u32 dma_bits; - - dma_bits = in_be32(host->ioaddr + reg); - /* DMA select is 22,23 bits in Protocol Control Register */ - dma_bits = (dma_bits >> 5) & SDHCI_CTRL_DMA_MASK; - - /* fixup the result */ - ret &= ~SDHCI_CTRL_DMA_MASK; - ret |= dma_bits; - } - - return ret; -} - -static void esdhc_writel(struct sdhci_host *host, u32 val, int reg) -{ - /* - * Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE] - * when SYSCTL[RSTD]) is set for some special operations. - * No any impact other operation. - */ - if (reg == SDHCI_INT_ENABLE) - val |= SDHCI_INT_BLK_GAP; - sdhci_be32bs_writel(host, val, reg); -} - static void esdhc_writew(struct sdhci_host *host, u16 val, int reg) { if (reg == SDHCI_BLOCK_SIZE) { @@ -113,62 +45,12 @@ static void esdhc_writew(struct sdhci_host *host, u16 val, int reg) static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) { - /* - * "DMA select" location is offset 0x28 in SD specification, but on - * P5020 or P3041, it's located at 0x29. - */ - if (reg == SDHCI_HOST_CONTROL) { - u32 dma_bits; - - /* DMA select is 22,23 bits in Protocol Control Register */ - dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5; - clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5, - dma_bits); - val &= ~SDHCI_CTRL_DMA_MASK; - val |= in_be32(host->ioaddr + reg) & SDHCI_CTRL_DMA_MASK; - } - /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ if (reg == SDHCI_HOST_CONTROL) val &= ~ESDHC_HOST_CONTROL_RES; sdhci_be32bs_writeb(host, val, reg); } -/* - * For Abort or Suspend after Stop at Block Gap, ignore the ADMA - * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC]) - * and Block Gap Event(IRQSTAT[BGE]) are also set. - * For Continue, apply soft reset for data(SYSCTL[RSTD]); - * and re-issue the entire read transaction from beginning. - */ -static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask) -{ - u32 tmp; - bool applicable; - dma_addr_t dmastart; - dma_addr_t dmanow; - - tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS); - tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; - - applicable = (intmask & SDHCI_INT_DATA_END) && - (intmask & SDHCI_INT_BLK_GAP) && - (tmp == VENDOR_V_23); - if (!applicable) - return; - - host->data->error = 0; - dmastart = sg_dma_address(host->data->sg); - dmanow = dmastart + host->data->bytes_xfered; - /* - * Force update to the next DMA block boundary. - */ - dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) + - SDHCI_DEFAULT_BOUNDARY_SIZE; - host->data->bytes_xfered = dmanow - dmastart; - sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS); -} - static int esdhc_of_enable_dma(struct sdhci_host *host) { setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP); @@ -189,83 +71,32 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) return pltfm_host->clock / 256 / 16; } -static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) -{ - /* Workaround to reduce the clock frequency for p1010 esdhc */ - if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { - if (clock > 20000000) - clock -= 5000000; - if (clock > 40000000) - clock -= 5000000; - } - - /* Set the clock */ - esdhc_set_clock(host, clock); -} - -#ifdef CONFIG_PM -static u32 esdhc_proctl; -static void esdhc_of_suspend(struct sdhci_host *host) -{ - esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL); -} - -static void esdhc_of_resume(struct sdhci_host *host) -{ - esdhc_of_enable_dma(host); - sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL); -} -#endif - -static void esdhc_of_platform_init(struct sdhci_host *host) -{ - u32 vvn; - - vvn = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS); - vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; - if (vvn == VENDOR_V_22) - host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; - - if (vvn > VENDOR_V_22) - host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; -} - static struct sdhci_ops sdhci_esdhc_ops = { - .read_l = esdhc_readl, + .read_l = sdhci_be32bs_readl, .read_w = esdhc_readw, - .read_b = esdhc_readb, - .write_l = esdhc_writel, + .read_b = sdhci_be32bs_readb, + .write_l = sdhci_be32bs_writel, .write_w = esdhc_writew, .write_b = esdhc_writeb, - .set_clock = esdhc_of_set_clock, + .set_clock = esdhc_set_clock, .enable_dma = esdhc_of_enable_dma, .get_max_clock = esdhc_of_get_max_clock, .get_min_clock = esdhc_of_get_min_clock, - .platform_init = esdhc_of_platform_init, -#ifdef CONFIG_PM - .platform_suspend = esdhc_of_suspend, - .platform_resume = esdhc_of_resume, -#endif - .adma_workaround = esdhci_of_adma_workaround, }; static struct sdhci_pltfm_data sdhci_esdhc_pdata = { - /* - * card detection could be handled via GPIO - * eSDHC cannot support End Attribute in NOP ADMA descriptor - */ + /* card detection could be handled via GPIO */ .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION - | SDHCI_QUIRK_NO_CARD_NO_RESET - | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + | SDHCI_QUIRK_NO_CARD_NO_RESET, .ops = &sdhci_esdhc_ops, }; -static int sdhci_esdhc_probe(struct platform_device *pdev) +static int __devinit sdhci_esdhc_probe(struct platform_device *pdev) { return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata); } -static int sdhci_esdhc_remove(struct platform_device *pdev) +static int __devexit sdhci_esdhc_remove(struct platform_device *pdev) { return sdhci_pltfm_unregister(pdev); } @@ -283,13 +114,26 @@ static struct platform_driver sdhci_esdhc_driver = { .name = "sdhci-esdhc", .owner = THIS_MODULE, .of_match_table = sdhci_esdhc_of_match, - .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_esdhc_probe, - .remove = sdhci_esdhc_remove, + .remove = __devexit_p(sdhci_esdhc_remove), +#ifdef CONFIG_PM + .suspend = sdhci_pltfm_suspend, + .resume = sdhci_pltfm_resume, +#endif }; -module_platform_driver(sdhci_esdhc_driver); +static int __init sdhci_esdhc_init(void) +{ + return platform_driver_register(&sdhci_esdhc_driver); +} +module_init(sdhci_esdhc_init); + +static void __exit sdhci_esdhc_exit(void) +{ + platform_driver_unregister(&sdhci_esdhc_driver); +} +module_exit(sdhci_esdhc_exit); MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC"); MODULE_AUTHOR("Xiaobo Xie , " diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index c3d3715ec3d..735be131dca 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -20,7 +20,6 @@ */ #include -#include #include #include "sdhci-pltfm.h" @@ -66,12 +65,12 @@ static struct sdhci_pltfm_data sdhci_hlwd_pdata = { .ops = &sdhci_hlwd_ops, }; -static int sdhci_hlwd_probe(struct platform_device *pdev) +static int __devinit sdhci_hlwd_probe(struct platform_device *pdev) { return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata); } -static int sdhci_hlwd_remove(struct platform_device *pdev) +static int __devexit sdhci_hlwd_remove(struct platform_device *pdev) { return sdhci_pltfm_unregister(pdev); } @@ -87,13 +86,26 @@ static struct platform_driver sdhci_hlwd_driver = { .name = "sdhci-hlwd", .owner = THIS_MODULE, .of_match_table = sdhci_hlwd_of_match, - .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_hlwd_probe, - .remove = sdhci_hlwd_remove, + .remove = __devexit_p(sdhci_hlwd_remove), +#ifdef CONFIG_PM + .suspend = sdhci_pltfm_suspend, + .resume = sdhci_pltfm_resume, +#endif }; -module_platform_driver(sdhci_hlwd_driver); +static int __init sdhci_hlwd_init(void) +{ + return platform_driver_register(&sdhci_hlwd_driver); +} +module_init(sdhci_hlwd_init); + +static void __exit sdhci_hlwd_exit(void) +{ + platform_driver_unregister(&sdhci_hlwd_driver); +} +module_exit(sdhci_hlwd_exit); MODULE_DESCRIPTION("Nintendo Wii SDHCI OF driver"); MODULE_AUTHOR("The GameCube Linux Team, Albert Herranz"); diff --git a/drivers/mmc/host/sdhci-pci-data.c b/drivers/mmc/host/sdhci-pci-data.c deleted file mode 100644 index a611217769f..00000000000 --- a/drivers/mmc/host/sdhci-pci-data.c +++ /dev/null @@ -1,5 +0,0 @@ -#include -#include - -struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno); -EXPORT_SYMBOL_GPL(sdhci_pci_get_data); diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index c7dd0cbc99d..26c528648f3 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -22,18 +21,9 @@ #include #include #include -#include -#include -#include #include "sdhci.h" -/* - * PCI device IDs - */ -#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 -#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a - /* * PCI registers */ @@ -53,35 +43,28 @@ struct sdhci_pci_slot; struct sdhci_pci_fixes { unsigned int quirks; - unsigned int quirks2; - bool allow_runtime_pm; int (*probe) (struct sdhci_pci_chip *); int (*probe_slot) (struct sdhci_pci_slot *); void (*remove_slot) (struct sdhci_pci_slot *, int); - int (*suspend) (struct sdhci_pci_chip *); + int (*suspend) (struct sdhci_pci_chip *, + pm_message_t); int (*resume) (struct sdhci_pci_chip *); }; struct sdhci_pci_slot { struct sdhci_pci_chip *chip; struct sdhci_host *host; - struct sdhci_pci_data *data; int pci_bar; - int rst_n_gpio; - int cd_gpio; - int cd_irq; }; struct sdhci_pci_chip { struct pci_dev *pdev; unsigned int quirks; - unsigned int quirks2; - bool allow_runtime_pm; const struct sdhci_pci_fixes *fixes; int num_slots; /* Slots on controller */ @@ -114,7 +97,6 @@ static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot) SDHCI_TIMEOUT_CLK_UNIT | SDHCI_CAN_VDD_330 | - SDHCI_CAN_DO_HISPD | SDHCI_CAN_DO_SDMA; return 0; } @@ -158,7 +140,6 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = { static const struct sdhci_pci_fixes sdhci_cafe = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | - SDHCI_QUIRK_BROKEN_CARD_DETECTION | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, }; @@ -182,92 +163,9 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip) return 0; } -static int pch_hc_probe_slot(struct sdhci_pci_slot *slot) -{ - slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; - return 0; -} - -#ifdef CONFIG_PM_RUNTIME - -static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id) -{ - struct sdhci_pci_slot *slot = dev_id; - struct sdhci_host *host = slot->host; - - mmc_detect_change(host->mmc, msecs_to_jiffies(200)); - return IRQ_HANDLED; -} - -static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) -{ - int err, irq, gpio = slot->cd_gpio; - - slot->cd_gpio = -EINVAL; - slot->cd_irq = -EINVAL; - - if (!gpio_is_valid(gpio)) - return; - - err = gpio_request(gpio, "sd_cd"); - if (err < 0) - goto out; - - err = gpio_direction_input(gpio); - if (err < 0) - goto out_free; - - irq = gpio_to_irq(gpio); - if (irq < 0) - goto out_free; - - err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING, "sd_cd", slot); - if (err) - goto out_free; - - slot->cd_gpio = gpio; - slot->cd_irq = irq; - - return; - -out_free: - gpio_free(gpio); -out: - dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); -} - -static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) -{ - if (slot->cd_irq >= 0) - free_irq(slot->cd_irq, slot); - if (gpio_is_valid(slot->cd_gpio)) - gpio_free(slot->cd_gpio); -} - -#else - -static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) -{ -} - -static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) -{ -} - -#endif - static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) { - slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; - slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC | - MMC_CAP2_HC_ERASE_SZ; - return 0; -} - -static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) -{ - slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE; + slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; return 0; } @@ -283,27 +181,17 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, - .allow_runtime_pm = true, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, - .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, - .allow_runtime_pm = true, - .probe_slot = mfd_sdio_probe_slot, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, - .allow_runtime_pm = true, .probe_slot = mfd_emmc_probe_slot, }; -static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { - .quirks = SDHCI_QUIRK_BROKEN_ADMA, - .probe_slot = pch_hc_probe_slot, -}; - /* O2Micro extra registers */ #define O2_SD_LOCK_WP 0xD3 #define O2_SD_MULTI_VCC3V 0xEE @@ -529,7 +417,7 @@ static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead) jmicron_enable_mmc(slot->host, 0); } -static int jmicron_suspend(struct sdhci_pci_chip *chip) +static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state) { int i; @@ -654,7 +542,7 @@ static const struct sdhci_pci_fixes sdhci_via = { .probe = via_probe, }; -static const struct pci_device_id pci_ids[] = { +static const struct pci_device_id pci_ids[] __devinitdata = { { .vendor = PCI_VENDOR_ID_RICOH, .device = PCI_DEVICE_ID_RICOH_R5C822, @@ -839,22 +727,6 @@ static const struct pci_device_id pci_ids[] = { .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc, }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PCH_SDIO0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PCH_SDIO1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio, - }, - { .vendor = PCI_VENDOR_ID_O2, .device = PCI_DEVICE_ID_O2_8120, @@ -960,25 +832,9 @@ static int sdhci_pci_8bit_width(struct sdhci_host *host, int width) return 0; } -static void sdhci_pci_hw_reset(struct sdhci_host *host) -{ - struct sdhci_pci_slot *slot = sdhci_priv(host); - int rst_n_gpio = slot->rst_n_gpio; - - if (!gpio_is_valid(rst_n_gpio)) - return; - gpio_set_value_cansleep(rst_n_gpio, 0); - /* For eMMC, minimum is 1us but give it 10us for good measure */ - udelay(10); - gpio_set_value_cansleep(rst_n_gpio, 1); - /* For eMMC, minimum is 200us but give it 300us for good measure */ - usleep_range(300, 1000); -} - static struct sdhci_ops sdhci_pci_ops = { .enable_dma = sdhci_pci_enable_dma, .platform_8bit_width = sdhci_pci_8bit_width, - .hw_reset = sdhci_pci_hw_reset, }; /*****************************************************************************\ @@ -989,9 +845,8 @@ static struct sdhci_ops sdhci_pci_ops = { #ifdef CONFIG_PM -static int sdhci_pci_suspend(struct device *dev) +static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state) { - struct pci_dev *pdev = to_pci_dev(dev); struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; mmc_pm_flag_t slot_pm_flags; @@ -1007,10 +862,13 @@ static int sdhci_pci_suspend(struct device *dev) if (!slot) continue; - ret = sdhci_suspend_host(slot->host); + ret = sdhci_suspend_host(slot->host, state); - if (ret) - goto err_pci_suspend; + if (ret) { + for (i--; i >= 0; i--) + sdhci_resume_host(chip->slots[i]->host); + return ret; + } slot_pm_flags = slot->host->mmc->pm_flags; if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ) @@ -1020,9 +878,12 @@ static int sdhci_pci_suspend(struct device *dev) } if (chip->fixes && chip->fixes->suspend) { - ret = chip->fixes->suspend(chip); - if (ret) - goto err_pci_suspend; + ret = chip->fixes->suspend(chip, state); + if (ret) { + for (i = chip->num_slots - 1; i >= 0; i--) + sdhci_resume_host(chip->slots[i]->host); + return ret; + } } pci_save_state(pdev); @@ -1033,22 +894,16 @@ static int sdhci_pci_suspend(struct device *dev) } pci_set_power_state(pdev, PCI_D3hot); } else { - pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); } return 0; - -err_pci_suspend: - while (--i >= 0) - sdhci_resume_host(chip->slots[i]->host); - return ret; } -static int sdhci_pci_resume(struct device *dev) +static int sdhci_pci_resume(struct pci_dev *pdev) { - struct pci_dev *pdev = to_pci_dev(dev); struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; int i, ret; @@ -1089,115 +944,25 @@ static int sdhci_pci_resume(struct device *dev) #endif /* CONFIG_PM */ -#ifdef CONFIG_PM_RUNTIME - -static int sdhci_pci_runtime_suspend(struct device *dev) -{ - struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); - struct sdhci_pci_chip *chip; - struct sdhci_pci_slot *slot; - int i, ret; - - chip = pci_get_drvdata(pdev); - if (!chip) - return 0; - - for (i = 0; i < chip->num_slots; i++) { - slot = chip->slots[i]; - if (!slot) - continue; - - ret = sdhci_runtime_suspend_host(slot->host); - - if (ret) - goto err_pci_runtime_suspend; - } - - if (chip->fixes && chip->fixes->suspend) { - ret = chip->fixes->suspend(chip); - if (ret) - goto err_pci_runtime_suspend; - } - - return 0; - -err_pci_runtime_suspend: - while (--i >= 0) - sdhci_runtime_resume_host(chip->slots[i]->host); - return ret; -} - -static int sdhci_pci_runtime_resume(struct device *dev) -{ - struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); - struct sdhci_pci_chip *chip; - struct sdhci_pci_slot *slot; - int i, ret; - - chip = pci_get_drvdata(pdev); - if (!chip) - return 0; - - if (chip->fixes && chip->fixes->resume) { - ret = chip->fixes->resume(chip); - if (ret) - return ret; - } - - for (i = 0; i < chip->num_slots; i++) { - slot = chip->slots[i]; - if (!slot) - continue; - - ret = sdhci_runtime_resume_host(slot->host); - if (ret) - return ret; - } - - return 0; -} - -static int sdhci_pci_runtime_idle(struct device *dev) -{ - return 0; -} - -#else - -#define sdhci_pci_runtime_suspend NULL -#define sdhci_pci_runtime_resume NULL -#define sdhci_pci_runtime_idle NULL - -#endif - -static const struct dev_pm_ops sdhci_pci_pm_ops = { - .suspend = sdhci_pci_suspend, - .resume = sdhci_pci_resume, - .runtime_suspend = sdhci_pci_runtime_suspend, - .runtime_resume = sdhci_pci_runtime_resume, - .runtime_idle = sdhci_pci_runtime_idle, -}; - /*****************************************************************************\ * * * Device probing/removal * * * \*****************************************************************************/ -static struct sdhci_pci_slot *sdhci_pci_probe_slot( - struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, - int slotno) +static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( + struct pci_dev *pdev, struct sdhci_pci_chip *chip, int bar) { struct sdhci_pci_slot *slot; struct sdhci_host *host; - int ret, bar = first_bar + slotno; + int ret; if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); return ERR_PTR(-ENODEV); } - if (pci_resource_len(pdev, bar) < 0x100) { + if (pci_resource_len(pdev, bar) != 0x100) { dev_err(&pdev->dev, "Invalid iomem size. You may " "experience problems.\n"); } @@ -1223,36 +988,17 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( slot->chip = chip; slot->host = host; slot->pci_bar = bar; - slot->rst_n_gpio = -EINVAL; - slot->cd_gpio = -EINVAL; - - /* Retrieve platform data if there is any */ - if (*sdhci_pci_get_data) - slot->data = sdhci_pci_get_data(pdev, slotno); - - if (slot->data) { - if (slot->data->setup) { - ret = slot->data->setup(slot->data); - if (ret) { - dev_err(&pdev->dev, "platform setup failed\n"); - goto free; - } - } - slot->rst_n_gpio = slot->data->rst_n_gpio; - slot->cd_gpio = slot->data->cd_gpio; - } host->hw_name = "PCI"; host->ops = &sdhci_pci_ops; host->quirks = chip->quirks; - host->quirks2 = chip->quirks2; host->irq = pdev->irq; ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc)); if (ret) { dev_err(&pdev->dev, "cannot request region\n"); - goto cleanup; + goto free; } host->ioaddr = pci_ioremap_bar(pdev, bar); @@ -1268,30 +1014,15 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( goto unmap; } - if (gpio_is_valid(slot->rst_n_gpio)) { - if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) { - gpio_direction_output(slot->rst_n_gpio, 1); - slot->host->mmc->caps |= MMC_CAP_HW_RESET; - } else { - dev_warn(&pdev->dev, "failed to request rst_n_gpio\n"); - slot->rst_n_gpio = -EINVAL; - } - } - host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; ret = sdhci_add_host(host); if (ret) goto remove; - sdhci_pci_add_own_cd(slot); - return slot; remove: - if (gpio_is_valid(slot->rst_n_gpio)) - gpio_free(slot->rst_n_gpio); - if (chip->fixes && chip->fixes->remove_slot) chip->fixes->remove_slot(slot, 0); @@ -1301,10 +1032,6 @@ unmap: release: pci_release_region(pdev, bar); -cleanup: - if (slot->data && slot->data->cleanup) - slot->data->cleanup(slot->data); - free: sdhci_free_host(host); @@ -1316,8 +1043,6 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) int dead; u32 scratch; - sdhci_pci_remove_own_cd(slot); - dead = 0; scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) @@ -1325,36 +1050,15 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) sdhci_remove_host(slot->host, dead); - if (gpio_is_valid(slot->rst_n_gpio)) - gpio_free(slot->rst_n_gpio); - if (slot->chip->fixes && slot->chip->fixes->remove_slot) slot->chip->fixes->remove_slot(slot, dead); - if (slot->data && slot->data->cleanup) - slot->data->cleanup(slot->data); - pci_release_region(slot->chip->pdev, slot->pci_bar); sdhci_free_host(slot->host); } -static void sdhci_pci_runtime_pm_allow(struct device *dev) -{ - pm_runtime_put_noidle(dev); - pm_runtime_allow(dev); - pm_runtime_set_autosuspend_delay(dev, 50); - pm_runtime_use_autosuspend(dev); - pm_suspend_ignore_children(dev, 1); -} - -static void sdhci_pci_runtime_pm_forbid(struct device *dev) -{ - pm_runtime_forbid(dev); - pm_runtime_get_noresume(dev); -} - -static int sdhci_pci_probe(struct pci_dev *pdev, +static int __devinit sdhci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct sdhci_pci_chip *chip; @@ -1403,11 +1107,8 @@ static int sdhci_pci_probe(struct pci_dev *pdev, chip->pdev = pdev; chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data; - if (chip->fixes) { + if (chip->fixes) chip->quirks = chip->fixes->quirks; - chip->quirks2 = chip->fixes->quirks2; - chip->allow_runtime_pm = chip->fixes->allow_runtime_pm; - } chip->num_slots = slots; pci_set_drvdata(pdev, chip); @@ -1421,7 +1122,7 @@ static int sdhci_pci_probe(struct pci_dev *pdev, slots = chip->num_slots; /* Quirk may have changed this */ for (i = 0; i < slots; i++) { - slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); + slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i); if (IS_ERR(slot)) { for (i--; i >= 0; i--) sdhci_pci_remove_slot(chip->slots[i]); @@ -1432,9 +1133,6 @@ static int sdhci_pci_probe(struct pci_dev *pdev, chip->slots[i] = slot; } - if (chip->allow_runtime_pm) - sdhci_pci_runtime_pm_allow(&pdev->dev); - return 0; free: @@ -1446,7 +1144,7 @@ err: return ret; } -static void sdhci_pci_remove(struct pci_dev *pdev) +static void __devexit sdhci_pci_remove(struct pci_dev *pdev) { int i; struct sdhci_pci_chip *chip; @@ -1454,9 +1152,6 @@ static void sdhci_pci_remove(struct pci_dev *pdev) chip = pci_get_drvdata(pdev); if (chip) { - if (chip->allow_runtime_pm) - sdhci_pci_runtime_pm_forbid(&pdev->dev); - for (i = 0; i < chip->num_slots; i++) sdhci_pci_remove_slot(chip->slots[i]); @@ -1471,13 +1166,29 @@ static struct pci_driver sdhci_driver = { .name = "sdhci-pci", .id_table = pci_ids, .probe = sdhci_pci_probe, - .remove = sdhci_pci_remove, - .driver = { - .pm = &sdhci_pci_pm_ops - }, + .remove = __devexit_p(sdhci_pci_remove), + .suspend = sdhci_pci_suspend, + .resume = sdhci_pci_resume, }; -module_pci_driver(sdhci_driver); +/*****************************************************************************\ + * * + * Driver init/exit * + * * +\*****************************************************************************/ + +static int __init sdhci_drv_init(void) +{ + return pci_register_driver(&sdhci_driver); +} + +static void __exit sdhci_drv_exit(void) +{ + pci_unregister_driver(&sdhci_driver); +} + +module_init(sdhci_drv_init); +module_exit(sdhci_drv_exit); MODULE_AUTHOR("Pierre Ossman "); MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver"); diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index d4283ef5917..1179f1be431 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -2,7 +2,7 @@ * sdhci-pltfm.c Support for SDHCI platform devices * Copyright (c) 2009 Intel Corporation * - * Copyright (c) 2007, 2011 Freescale Semiconductor, Inc. + * Copyright (c) 2007 Freescale Semiconductor, Inc. * Copyright (c) 2009 MontaVista Software, Inc. * * Authors: Xiaobo Xie @@ -29,7 +29,6 @@ */ #include -#include #include #ifdef CONFIG_PPC #include @@ -42,8 +41,7 @@ static struct sdhci_ops sdhci_pltfm_ops = { #ifdef CONFIG_OF static bool sdhci_of_wp_inverted(struct device_node *np) { - if (of_get_property(np, "sdhci,wp-inverted", NULL) || - of_get_property(np, "wp-inverted", NULL)) + if (of_get_property(np, "sdhci,wp-inverted", NULL)) return true; /* Old device trees don't have the wp-inverted property. */ @@ -60,44 +58,21 @@ void sdhci_get_of_property(struct platform_device *pdev) struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); const __be32 *clk; - u32 bus_width; int size; if (of_device_is_available(np)) { if (of_get_property(np, "sdhci,auto-cmd12", NULL)) host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; - if (of_get_property(np, "sdhci,1-bit-only", NULL) || - (of_property_read_u32(np, "bus-width", &bus_width) == 0 && - bus_width == 1)) + if (of_get_property(np, "sdhci,1-bit-only", NULL)) host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; if (sdhci_of_wp_inverted(np)) host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; - if (of_get_property(np, "broken-cd", NULL)) - host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; - - if (of_get_property(np, "no-1-8-v", NULL)) - host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; - - if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc")) - host->quirks |= SDHCI_QUIRK_BROKEN_DMA; - - if (of_device_is_compatible(np, "fsl,p2020-esdhc") || - of_device_is_compatible(np, "fsl,p1010-esdhc") || - of_device_is_compatible(np, "fsl,mpc8536-esdhc")) - host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; - clk = of_get_property(np, "clock-frequency", &size); if (clk && size == sizeof(*clk) && *clk) pltfm_host->clock = be32_to_cpup(clk); - - if (of_find_property(np, "keep-power-in-suspend", NULL)) - host->mmc->pm_caps |= MMC_PM_KEEP_POWER; - - if (of_find_property(np, "enable-sdio-wakeup", NULL)) - host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; } } #else @@ -159,13 +134,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, goto err_remap; } - /* - * Some platforms need to probe the controller to be able to - * determine which caps should be used. - */ - if (host->ops && host->ops->platform_init) - host->ops->platform_init(host); - platform_set_drvdata(pdev, host); return host; @@ -225,25 +193,47 @@ int sdhci_pltfm_unregister(struct platform_device *pdev) EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister); #ifdef CONFIG_PM -static int sdhci_pltfm_suspend(struct device *dev) +int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state) { - struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_host *host = platform_get_drvdata(dev); + int ret; - return sdhci_suspend_host(host); + ret = sdhci_suspend_host(host, state); + if (ret) { + dev_err(&dev->dev, "suspend failed, error = %d\n", ret); + return ret; + } + + if (host->ops && host->ops->suspend) + ret = host->ops->suspend(host, state); + if (ret) { + dev_err(&dev->dev, "suspend hook failed, error = %d\n", ret); + sdhci_resume_host(host); + } + + return ret; } +EXPORT_SYMBOL_GPL(sdhci_pltfm_suspend); -static int sdhci_pltfm_resume(struct device *dev) +int sdhci_pltfm_resume(struct platform_device *dev) { - struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_host *host = platform_get_drvdata(dev); + int ret = 0; - return sdhci_resume_host(host); -} + if (host->ops && host->ops->resume) + ret = host->ops->resume(host); + if (ret) { + dev_err(&dev->dev, "resume hook failed, error = %d\n", ret); + return ret; + } -const struct dev_pm_ops sdhci_pltfm_pmops = { - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -}; -EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops); + ret = sdhci_resume_host(host); + if (ret) + dev_err(&dev->dev, "resume failed, error = %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(sdhci_pltfm_resume); #endif /* CONFIG_PM */ static int __init sdhci_pltfm_drv_init(void) diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 37e0e184a0b..b92c7f29a4e 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -17,7 +17,7 @@ struct sdhci_pltfm_data { struct sdhci_ops *ops; - unsigned int quirks; + u64 quirks; }; struct sdhci_pltfm_host { @@ -99,10 +99,8 @@ extern int sdhci_pltfm_register(struct platform_device *pdev, extern int sdhci_pltfm_unregister(struct platform_device *pdev); #ifdef CONFIG_PM -extern const struct dev_pm_ops sdhci_pltfm_pmops; -#define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops) -#else -#define SDHCI_PLTFM_PMOPS NULL +extern int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state); +extern int sdhci_pltfm_resume(struct platform_device *dev); #endif #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index ac854aa192a..38f58994f79 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -21,16 +21,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include -#include - #include "sdhci.h" #include "sdhci-pltfm.h" @@ -63,7 +59,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) * tune timing of read data/command when crc error happen * no performance impact */ - if (pdata && pdata->clk_delay_sel == 1) { + if (pdata->clk_delay_sel == 1) { tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); tmp &= ~(SDCLK_DELAY_MASK << SDCLK_DELAY_SHIFT); @@ -75,7 +71,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); } - if (pdata && (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING)) { + if (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING) { tmp = readw(host->ioaddr + SD_FIFO_PARAM); tmp &= ~CLK_GATE_SETTING_BITS; writew(tmp, host->ioaddr + SD_FIFO_PARAM); @@ -124,57 +120,13 @@ static struct sdhci_ops pxav2_sdhci_ops = { .platform_8bit_width = pxav2_mmc_set_width, }; -#ifdef CONFIG_OF -static const struct of_device_id sdhci_pxav2_of_match[] = { - { - .compatible = "mrvl,pxav2-mmc", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, sdhci_pxav2_of_match); - -static struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev) -{ - struct sdhci_pxa_platdata *pdata; - struct device_node *np = dev->of_node; - u32 bus_width; - u32 clk_delay_cycles; - - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; - - if (of_find_property(np, "non-removable", NULL)) - pdata->flags |= PXA_FLAG_CARD_PERMANENT; - - of_property_read_u32(np, "bus-width", &bus_width); - if (bus_width == 8) - pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT; - - of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles); - if (clk_delay_cycles > 0) { - pdata->clk_delay_sel = 1; - pdata->clk_delay_cycles = clk_delay_cycles; - } - - return pdata; -} -#else -static inline struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev) -{ - return NULL; -} -#endif - -static int sdhci_pxav2_probe(struct platform_device *pdev) +static int __devinit sdhci_pxav2_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; struct device *dev = &pdev->dev; struct sdhci_host *host = NULL; struct sdhci_pxa *pxa = NULL; - const struct of_device_id *match; - int ret; struct clk *clk; @@ -197,16 +149,12 @@ static int sdhci_pxav2_probe(struct platform_device *pdev) goto err_clk_get; } pltfm_host->clk = clk; - clk_prepare_enable(clk); + clk_enable(clk); host->quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; - match = of_match_device(of_match_ptr(sdhci_pxav2_of_match), &pdev->dev); - if (match) { - pdata = pxav2_get_mmc_pdata(dev); - } if (pdata) { if (pdata->flags & PXA_FLAG_CARD_PERMANENT) { /* on-chip device */ @@ -239,7 +187,7 @@ static int sdhci_pxav2_probe(struct platform_device *pdev) return 0; err_add_host: - clk_disable_unprepare(clk); + clk_disable(clk); clk_put(clk); err_clk_get: sdhci_pltfm_free(pdev); @@ -247,7 +195,7 @@ err_clk_get: return ret; } -static int sdhci_pxav2_remove(struct platform_device *pdev) +static int __devexit sdhci_pxav2_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -255,7 +203,7 @@ static int sdhci_pxav2_remove(struct platform_device *pdev) sdhci_remove_host(host, 1); - clk_disable_unprepare(pltfm_host->clk); + clk_disable(pltfm_host->clk); clk_put(pltfm_host->clk); sdhci_pltfm_free(pdev); kfree(pxa); @@ -269,16 +217,26 @@ static struct platform_driver sdhci_pxav2_driver = { .driver = { .name = "sdhci-pxav2", .owner = THIS_MODULE, -#ifdef CONFIG_OF - .of_match_table = sdhci_pxav2_of_match, -#endif - .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_pxav2_probe, - .remove = sdhci_pxav2_remove, + .remove = __devexit_p(sdhci_pxav2_remove), +#ifdef CONFIG_PM + .suspend = sdhci_pltfm_suspend, + .resume = sdhci_pltfm_resume, +#endif }; +static int __init sdhci_pxav2_init(void) +{ + return platform_driver_register(&sdhci_pxav2_driver); +} + +static void __exit sdhci_pxav2_exit(void) +{ + platform_driver_unregister(&sdhci_pxav2_driver); +} -module_platform_driver(sdhci_pxav2_driver); +module_init(sdhci_pxav2_init); +module_exit(sdhci_pxav2_exit); MODULE_DESCRIPTION("SDHCI driver for pxav2"); MODULE_AUTHOR("Marvell International Ltd."); diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index fad0966427f..fc7e4a51562 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -24,15 +24,9 @@ #include #include #include -#include #include #include #include -#include -#include -#include -#include - #include "sdhci.h" #include "sdhci-pltfm.h" @@ -163,74 +157,19 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) return 0; } -static u32 pxav3_get_max_clock(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - - return clk_get_rate(pltfm_host->clk); -} - static struct sdhci_ops pxav3_sdhci_ops = { .platform_reset_exit = pxav3_set_private_registers, .set_uhs_signaling = pxav3_set_uhs_signaling, .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, - .get_max_clock = pxav3_get_max_clock, -}; - -#ifdef CONFIG_OF -static const struct of_device_id sdhci_pxav3_of_match[] = { - { - .compatible = "mrvl,pxav3-mmc", - }, - {}, }; -MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match); - -static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) -{ - struct sdhci_pxa_platdata *pdata; - struct device_node *np = dev->of_node; - u32 bus_width; - u32 clk_delay_cycles; - enum of_gpio_flags gpio_flags; - - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; - - if (of_find_property(np, "non-removable", NULL)) - pdata->flags |= PXA_FLAG_CARD_PERMANENT; - - of_property_read_u32(np, "bus-width", &bus_width); - if (bus_width == 8) - pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT; - - of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles); - if (clk_delay_cycles > 0) - pdata->clk_delay_cycles = clk_delay_cycles; - - pdata->ext_cd_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &gpio_flags); - if (gpio_flags != OF_GPIO_ACTIVE_LOW) - pdata->host_caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; - - return pdata; -} -#else -static inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) -{ - return NULL; -} -#endif -static int sdhci_pxav3_probe(struct platform_device *pdev) +static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; struct device *dev = &pdev->dev; struct sdhci_host *host = NULL; struct sdhci_pxa *pxa = NULL; - const struct of_device_id *match; - int ret; struct clk *clk; @@ -246,27 +185,22 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) pltfm_host = sdhci_priv(host); pltfm_host->priv = pxa; - clk = clk_get(dev, NULL); + clk = clk_get(dev, "PXA-SDHCLK"); if (IS_ERR(clk)) { dev_err(dev, "failed to get io clock\n"); ret = PTR_ERR(clk); goto err_clk_get; } pltfm_host->clk = clk; - clk_prepare_enable(clk); + clk_enable(clk); host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC - | SDHCI_QUIRK_32BIT_ADMA_SIZE - | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; + | SDHCI_QUIRK_32BIT_ADMA_SIZE; /* enable 1/8V DDR capable */ host->mmc->caps |= MMC_CAP_1_8V_DDR; - match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev); - if (match) - pdata = pxav3_get_mmc_pdata(dev); - if (pdata) { if (pdata->flags & PXA_FLAG_CARD_PERMANENT) { /* on-chip device */ @@ -280,29 +214,14 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) if (pdata->quirks) host->quirks |= pdata->quirks; - if (pdata->quirks2) - host->quirks2 |= pdata->quirks2; if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; - if (pdata->host_caps2) - host->mmc->caps2 |= pdata->host_caps2; if (pdata->pm_caps) host->mmc->pm_caps |= pdata->pm_caps; - - if (gpio_is_valid(pdata->ext_cd_gpio)) { - ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio); - if (ret) { - dev_err(mmc_dev(host->mmc), - "failed to allocate card detect gpio\n"); - goto err_cd_req; - } - } } host->ops = &pxav3_sdhci_ops; - sdhci_get_of_property(pdev); - ret = sdhci_add_host(host); if (ret) { dev_err(&pdev->dev, "failed to add host\n"); @@ -314,31 +233,24 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) return 0; err_add_host: - clk_disable_unprepare(clk); + clk_disable(clk); clk_put(clk); - mmc_gpio_free_cd(host->mmc); -err_cd_req: err_clk_get: sdhci_pltfm_free(pdev); kfree(pxa); return ret; } -static int sdhci_pxav3_remove(struct platform_device *pdev) +static int __devexit sdhci_pxav3_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pxa *pxa = pltfm_host->priv; - struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; sdhci_remove_host(host, 1); - clk_disable_unprepare(pltfm_host->clk); + clk_disable(pltfm_host->clk); clk_put(pltfm_host->clk); - - if (gpio_is_valid(pdata->ext_cd_gpio)) - mmc_gpio_free_cd(host->mmc); - sdhci_pltfm_free(pdev); kfree(pxa); @@ -350,17 +262,27 @@ static int sdhci_pxav3_remove(struct platform_device *pdev) static struct platform_driver sdhci_pxav3_driver = { .driver = { .name = "sdhci-pxav3", -#ifdef CONFIG_OF - .of_match_table = sdhci_pxav3_of_match, -#endif .owner = THIS_MODULE, - .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_pxav3_probe, - .remove = sdhci_pxav3_remove, + .remove = __devexit_p(sdhci_pxav3_remove), +#ifdef CONFIG_PM + .suspend = sdhci_pltfm_suspend, + .resume = sdhci_pltfm_resume, +#endif }; +static int __init sdhci_pxav3_init(void) +{ + return platform_driver_register(&sdhci_pxav3_driver); +} + +static void __exit sdhci_pxav3_exit(void) +{ + platform_driver_unregister(&sdhci_pxav3_driver); +} -module_platform_driver(sdhci_pxav3_driver); +module_init(sdhci_pxav3_init); +module_exit(sdhci_pxav3_exit); MODULE_DESCRIPTION("SDHCI driver for pxav3"); MODULE_AUTHOR("Marvell International Ltd."); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 82a8de148a8..fe886d6c474 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -20,11 +20,6 @@ #include #include #include -#include -#include -#include -#include -#include #include @@ -35,9 +30,6 @@ #define MAX_BUS_CLK (4) -/* Number of gpio's used is max data bus width + command and clock lines */ -#define NUM_GPIOS(x) (x + 2) - /** * struct sdhci_s3c - S3C SDHCI instance * @host: The SDHCI host created @@ -45,7 +37,6 @@ * @ioarea: The resource created when we claimed the IO area. * @pdata: The platform data for this controller. * @cur_clk: The index of the current bus clock. - * @gpios: List of gpio numbers parsed from device tree. * @clk_io: The clock for the internal bus interface. * @clk_bus: The clocks that are available for the SD/MMC bus clock. */ @@ -57,25 +48,11 @@ struct sdhci_s3c { unsigned int cur_clk; int ext_cd_irq; int ext_cd_gpio; - int *gpios; - struct pinctrl *pctrl; struct clk *clk_io; struct clk *clk_bus[MAX_BUS_CLK]; }; -/** - * struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data - * @sdhci_quirks: sdhci host specific quirks. - * - * Specifies platform specific configuration of sdhci controller. - * Note: A structure for driver specific platform data is used for future - * expansion of its usage. - */ -struct sdhci_s3c_drv_data { - unsigned int sdhci_quirks; -}; - static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) { return sdhci_priv(host); @@ -103,7 +80,7 @@ static void sdhci_s3c_check_sclk(struct sdhci_host *host) tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; - writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2); + writel(tmp, host->ioaddr + 0x80); } } @@ -155,10 +132,10 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, return UINT_MAX; /* - * If controller uses a non-standard clock division, find the best clock - * speed possible with selected clock source and skip the division. + * Clock divider's step is different as 1 from that of host controller + * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL. */ - if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { + if (ourhost->pdata->clk_type) { rate = clk_round_rate(clksrc, wanted); return wanted - rate; } @@ -173,7 +150,7 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, dev_dbg(&ourhost->pdev->dev, "clk %d: rate %ld, want %d, got %ld\n", src, rate, wanted, rate / div); - return wanted - (rate / div); + return (wanted - (rate / div)); } /** @@ -210,12 +187,10 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) best_src, clock, best); /* select the new clock source */ + if (ourhost->cur_clk != best_src) { struct clk *clk = ourhost->clk_bus[best_src]; - clk_prepare_enable(clk); - clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); - /* turn clock off to card before changing clock source */ writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); @@ -228,23 +203,17 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); } - /* reprogram default hardware configuration */ - writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, - host->ioaddr + S3C64XX_SDHCI_CONTROL4); - - ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); - ctrl |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR | - S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK | - S3C_SDHCI_CTRL2_ENFBCLKRX | - S3C_SDHCI_CTRL2_DFCNT_NONE | - S3C_SDHCI_CTRL2_ENCLKOUTHOLD); - writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); - - /* reconfigure the controller for new clock rate */ - ctrl = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0); - if (clock < 25 * 1000000) - ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2); - writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3); + /* reconfigure the hardware for new clock rate */ + + { + struct mmc_ios ios; + + ios.clock = clock; + + if (ourhost->pdata->cfg_card) + (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr, + &ios, NULL); + } } /** @@ -297,9 +266,6 @@ static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host) static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_s3c *ourhost = to_s3c(host); - struct device *dev = &ourhost->pdev->dev; - unsigned long timeout; - u16 clk = 0; /* don't bother if the clock is going off */ if (clock == 0) @@ -310,25 +276,6 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); host->clock = clock; - - clk = SDHCI_CLOCK_INT_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - /* Wait max 20 ms */ - timeout = 20; - while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) - & SDHCI_CLOCK_INT_STABLE)) { - if (timeout == 0) { - dev_err(dev, "%s: Internal clock never stabilised.\n", - mmc_hostname(host->mmc)); - return; - } - timeout--; - mdelay(1); - } - - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); } /** @@ -375,27 +322,18 @@ static struct sdhci_ops sdhci_s3c_ops = { static void sdhci_s3c_notify_change(struct platform_device *dev, int state) { struct sdhci_host *host = platform_get_drvdata(dev); -#ifdef CONFIG_PM_RUNTIME - struct sdhci_s3c *sc = sdhci_priv(host); -#endif unsigned long flags; if (host) { spin_lock_irqsave(&host->lock, flags); if (state) { dev_dbg(&dev->dev, "card inserted.\n"); -#ifdef CONFIG_PM_RUNTIME - clk_prepare_enable(sc->clk_io); -#endif host->flags &= ~SDHCI_DEVICE_DEAD; host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; } else { dev_dbg(&dev->dev, "card removed.\n"); host->flags |= SDHCI_DEVICE_DEAD; host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; -#ifdef CONFIG_PM_RUNTIME - clk_disable_unprepare(sc->clk_io); -#endif } tasklet_schedule(&host->card_tasklet); spin_unlock_irqrestore(&host->lock, flags); @@ -417,15 +355,13 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc) struct s3c_sdhci_platdata *pdata = sc->pdata; struct device *dev = &sc->pdev->dev; - if (devm_gpio_request(dev, pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) { + if (gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) { sc->ext_cd_gpio = pdata->ext_cd_gpio; sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio); if (sc->ext_cd_irq && request_threaded_irq(sc->ext_cd_irq, NULL, sdhci_s3c_gpio_card_detect_thread, - IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev_name(dev), sc) == 0) { int status = gpio_get_value(sc->ext_cd_gpio); if (pdata->ext_cd_gpio_invert) @@ -440,132 +376,16 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc) } } -#ifdef CONFIG_OF -static int sdhci_s3c_parse_dt(struct device *dev, - struct sdhci_host *host, struct s3c_sdhci_platdata *pdata) +static int __devinit sdhci_s3c_probe(struct platform_device *pdev) { - struct device_node *node = dev->of_node; - struct sdhci_s3c *ourhost = to_s3c(host); - u32 max_width; - int gpio, cnt, ret; - - /* if the bus-width property is not specified, assume width as 1 */ - if (of_property_read_u32(node, "bus-width", &max_width)) - max_width = 1; - pdata->max_width = max_width; - - ourhost->gpios = devm_kzalloc(dev, NUM_GPIOS(pdata->max_width) * - sizeof(int), GFP_KERNEL); - if (!ourhost->gpios) - return -ENOMEM; - - /* get the card detection method */ - if (of_get_property(node, "broken-cd", NULL)) { - pdata->cd_type = S3C_SDHCI_CD_NONE; - goto setup_bus; - } - - if (of_get_property(node, "non-removable", NULL)) { - pdata->cd_type = S3C_SDHCI_CD_PERMANENT; - goto setup_bus; - } - - gpio = of_get_named_gpio(node, "cd-gpios", 0); - if (gpio_is_valid(gpio)) { - pdata->cd_type = S3C_SDHCI_CD_GPIO; - goto found_cd; - } else if (gpio != -ENOENT) { - dev_err(dev, "invalid card detect gpio specified\n"); - return -EINVAL; - } - - gpio = of_get_named_gpio(node, "samsung,cd-pinmux-gpio", 0); - if (gpio_is_valid(gpio)) { - pdata->cd_type = S3C_SDHCI_CD_INTERNAL; - goto found_cd; - } else if (gpio != -ENOENT) { - dev_err(dev, "invalid card detect gpio specified\n"); - return -EINVAL; - } - - /* assuming internal card detect that will be configured by pinctrl */ - pdata->cd_type = S3C_SDHCI_CD_INTERNAL; - goto setup_bus; - - found_cd: - if (pdata->cd_type == S3C_SDHCI_CD_GPIO) { - pdata->ext_cd_gpio = gpio; - ourhost->ext_cd_gpio = -1; - if (of_get_property(node, "cd-inverted", NULL)) - pdata->ext_cd_gpio_invert = 1; - } else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { - ret = devm_gpio_request(dev, gpio, "sdhci-cd"); - if (ret) { - dev_err(dev, "card detect gpio request failed\n"); - return -EINVAL; - } - ourhost->ext_cd_gpio = gpio; - } - - setup_bus: - if (!IS_ERR(ourhost->pctrl)) - return 0; - - /* get the gpios for command, clock and data lines */ - for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { - gpio = of_get_gpio(node, cnt); - if (!gpio_is_valid(gpio)) { - dev_err(dev, "invalid gpio[%d]\n", cnt); - return -EINVAL; - } - ourhost->gpios[cnt] = gpio; - } - - for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { - ret = devm_gpio_request(dev, ourhost->gpios[cnt], "sdhci-gpio"); - if (ret) { - dev_err(dev, "gpio[%d] request failed\n", cnt); - return -EINVAL; - } - } - - return 0; -} -#else -static int sdhci_s3c_parse_dt(struct device *dev, - struct sdhci_host *host, struct s3c_sdhci_platdata *pdata) -{ - return -EINVAL; -} -#endif - -static const struct of_device_id sdhci_s3c_dt_match[]; - -static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data( - struct platform_device *pdev) -{ -#ifdef CONFIG_OF - if (pdev->dev.of_node) { - const struct of_device_id *match; - match = of_match_node(sdhci_s3c_dt_match, pdev->dev.of_node); - return (struct sdhci_s3c_drv_data *)match->data; - } -#endif - return (struct sdhci_s3c_drv_data *) - platform_get_device_id(pdev)->driver_data; -} - -static int sdhci_s3c_probe(struct platform_device *pdev) -{ - struct s3c_sdhci_platdata *pdata; - struct sdhci_s3c_drv_data *drv_data; + struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data; struct device *dev = &pdev->dev; struct sdhci_host *host; struct sdhci_s3c *sc; struct resource *res; int ret, irq, ptr, clks; - if (!pdev->dev.platform_data && !pdev->dev.of_node) { + if (!pdata) { dev_err(dev, "no device data specified\n"); return -ENOENT; } @@ -576,35 +396,24 @@ static int sdhci_s3c_probe(struct platform_device *pdev) return irq; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no memory specified\n"); + return -ENOENT; + } + host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c)); if (IS_ERR(host)) { dev_err(dev, "sdhci_alloc_host() failed\n"); return PTR_ERR(host); } - sc = sdhci_priv(host); - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - ret = -ENOMEM; - goto err_pdata_io_clk; - } - - sc->pctrl = devm_pinctrl_get_select_default(&pdev->dev); - - if (pdev->dev.of_node) { - ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata); - if (ret) - goto err_pdata_io_clk; - } else { - memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); - sc->ext_cd_gpio = -1; /* invalid gpio number */ - } - - drv_data = sdhci_s3c_get_driver_data(pdev); + sc = sdhci_priv(host); sc->host = host; sc->pdev = pdev; sc->pdata = pdata; + sc->ext_cd_gpio = -1; /* invalid gpio number */ platform_set_drvdata(pdev, host); @@ -612,20 +421,24 @@ static int sdhci_s3c_probe(struct platform_device *pdev) if (IS_ERR(sc->clk_io)) { dev_err(dev, "failed to get io clock\n"); ret = PTR_ERR(sc->clk_io); - goto err_pdata_io_clk; + goto err_io_clk; } /* enable the local io clock and keep it running for the moment. */ - clk_prepare_enable(sc->clk_io); + clk_enable(sc->clk_io); for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) { struct clk *clk; - char name[14]; + char *name = pdata->clocks[ptr]; + + if (name == NULL) + continue; - snprintf(name, 14, "mmc_busclk.%d", ptr); clk = clk_get(dev, name); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + dev_err(dev, "failed to get clock %s\n", name); continue; + } clks++; sc->clk_bus[ptr] = clk; @@ -636,6 +449,8 @@ static int sdhci_s3c_probe(struct platform_device *pdev) */ sc->cur_clk = ptr; + clk_enable(clk); + dev_info(dev, "clock source %d: %s (%ld Hz)\n", ptr, name, clk_get_rate(clk)); } @@ -646,12 +461,15 @@ static int sdhci_s3c_probe(struct platform_device *pdev) goto err_no_busclks; } -#ifndef CONFIG_PM_RUNTIME - clk_prepare_enable(sc->clk_bus[sc->cur_clk]); -#endif + sc->ioarea = request_mem_region(res->start, resource_size(res), + mmc_hostname(host->mmc)); + if (!sc->ioarea) { + dev_err(dev, "failed to reserve register area\n"); + ret = -ENXIO; + goto err_req_regs; + } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->ioaddr = devm_request_and_ioremap(&pdev->dev, res); + host->ioaddr = ioremap_nocache(res->start, resource_size(res)); if (!host->ioaddr) { dev_err(dev, "failed to map registers\n"); ret = -ENXIO; @@ -670,8 +488,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) /* Setup quirks for the controller */ host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; - if (drv_data) - host->quirks |= drv_data->sdhci_quirks; #ifndef CONFIG_MMC_SDHCI_S3C_DMA @@ -699,16 +515,8 @@ static int sdhci_s3c_probe(struct platform_device *pdev) if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT) host->mmc->caps = MMC_CAP_NONREMOVABLE; - switch (pdata->max_width) { - case 8: - host->mmc->caps |= MMC_CAP_8_BIT_DATA; - case 4: - host->mmc->caps |= MMC_CAP_4_BIT_DATA; - break; - } - - if (pdata->pm_caps) - host->mmc->pm_caps |= pdata->pm_caps; + if (pdata->host_caps) + host->mmc->caps |= pdata->host_caps; host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE); @@ -720,7 +528,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) * If controller does not have internal clock divider, * we can use overriding functions instead of default. */ - if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { + if (pdata->clk_type) { sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; @@ -730,20 +538,10 @@ static int sdhci_s3c_probe(struct platform_device *pdev) if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; - if (pdata->host_caps2) - host->mmc->caps2 |= pdata->host_caps2; - - pm_runtime_enable(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, 50); - pm_runtime_use_autosuspend(&pdev->dev); - pm_suspend_ignore_children(&pdev->dev, 1); - ret = sdhci_add_host(host); if (ret) { dev_err(dev, "sdhci_add_host() failed\n"); - pm_runtime_forbid(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); - goto err_req_regs; + goto err_add_host; } /* The following two methods of card detection might call @@ -755,37 +553,33 @@ static int sdhci_s3c_probe(struct platform_device *pdev) gpio_is_valid(pdata->ext_cd_gpio)) sdhci_s3c_setup_card_detect_gpio(sc); -#ifdef CONFIG_PM_RUNTIME - if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) - clk_disable_unprepare(sc->clk_io); -#endif return 0; + err_add_host: + release_resource(sc->ioarea); + kfree(sc->ioarea); + err_req_regs: -#ifndef CONFIG_PM_RUNTIME - clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); -#endif for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { - if (sc->clk_bus[ptr]) { - clk_put(sc->clk_bus[ptr]); - } + clk_disable(sc->clk_bus[ptr]); + clk_put(sc->clk_bus[ptr]); } err_no_busclks: - clk_disable_unprepare(sc->clk_io); + clk_disable(sc->clk_io); clk_put(sc->clk_io); - err_pdata_io_clk: + err_io_clk: sdhci_free_host(host); return ret; } -static int sdhci_s3c_remove(struct platform_device *pdev) +static int __devexit sdhci_s3c_remove(struct platform_device *pdev) { + struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data; struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_s3c *sc = sdhci_priv(host); - struct s3c_sdhci_platdata *pdata = sc->pdata; int ptr; if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup) @@ -794,134 +588,74 @@ static int sdhci_s3c_remove(struct platform_device *pdev) if (sc->ext_cd_irq) free_irq(sc->ext_cd_irq, sc); -#ifdef CONFIG_PM_RUNTIME - if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) - clk_prepare_enable(sc->clk_io); -#endif - sdhci_remove_host(host, 1); + if (gpio_is_valid(sc->ext_cd_gpio)) + gpio_free(sc->ext_cd_gpio); - pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_disable(&pdev->dev); + sdhci_remove_host(host, 1); -#ifndef CONFIG_PM_RUNTIME - clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); -#endif - for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { + for (ptr = 0; ptr < 3; ptr++) { if (sc->clk_bus[ptr]) { + clk_disable(sc->clk_bus[ptr]); clk_put(sc->clk_bus[ptr]); } } - clk_disable_unprepare(sc->clk_io); + clk_disable(sc->clk_io); clk_put(sc->clk_io); + iounmap(host->ioaddr); + release_resource(sc->ioarea); + kfree(sc->ioarea); + sdhci_free_host(host); platform_set_drvdata(pdev, NULL); return 0; } -#ifdef CONFIG_PM_SLEEP -static int sdhci_s3c_suspend(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - - return sdhci_suspend_host(host); -} - -static int sdhci_s3c_resume(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - - return sdhci_resume_host(host); -} -#endif +#ifdef CONFIG_PM -#ifdef CONFIG_PM_RUNTIME -static int sdhci_s3c_runtime_suspend(struct device *dev) +static int sdhci_s3c_suspend(struct platform_device *dev, pm_message_t pm) { - struct sdhci_host *host = dev_get_drvdata(dev); - struct sdhci_s3c *ourhost = to_s3c(host); - struct clk *busclk = ourhost->clk_io; - int ret; - - ret = sdhci_runtime_suspend_host(host); + struct sdhci_host *host = platform_get_drvdata(dev); - clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); - clk_disable_unprepare(busclk); - return ret; + return sdhci_suspend_host(host, pm); } -static int sdhci_s3c_runtime_resume(struct device *dev) +static int sdhci_s3c_resume(struct platform_device *dev) { - struct sdhci_host *host = dev_get_drvdata(dev); - struct sdhci_s3c *ourhost = to_s3c(host); - struct clk *busclk = ourhost->clk_io; - int ret; + struct sdhci_host *host = platform_get_drvdata(dev); - clk_prepare_enable(busclk); - clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]); - ret = sdhci_runtime_resume_host(host); - return ret; + return sdhci_resume_host(host); } -#endif - -#ifdef CONFIG_PM -static const struct dev_pm_ops sdhci_s3c_pmops = { - SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume) - SET_RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume, - NULL) -}; -#define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops) - -#else -#define SDHCI_S3C_PMOPS NULL -#endif - -#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212) -static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { - .sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK, -}; -#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data) #else -#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)NULL) -#endif - -static struct platform_device_id sdhci_s3c_driver_ids[] = { - { - .name = "s3c-sdhci", - .driver_data = (kernel_ulong_t)NULL, - }, { - .name = "exynos4-sdhci", - .driver_data = EXYNOS4_SDHCI_DRV_DATA, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids); - -#ifdef CONFIG_OF -static const struct of_device_id sdhci_s3c_dt_match[] = { - { .compatible = "samsung,s3c6410-sdhci", }, - { .compatible = "samsung,exynos4210-sdhci", - .data = (void *)EXYNOS4_SDHCI_DRV_DATA }, - {}, -}; -MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match); +#define sdhci_s3c_suspend NULL +#define sdhci_s3c_resume NULL #endif static struct platform_driver sdhci_s3c_driver = { .probe = sdhci_s3c_probe, - .remove = sdhci_s3c_remove, - .id_table = sdhci_s3c_driver_ids, + .remove = __devexit_p(sdhci_s3c_remove), + .suspend = sdhci_s3c_suspend, + .resume = sdhci_s3c_resume, .driver = { .owner = THIS_MODULE, .name = "s3c-sdhci", - .of_match_table = of_match_ptr(sdhci_s3c_dt_match), - .pm = SDHCI_S3C_PMOPS, }, }; -module_platform_driver(sdhci_s3c_driver); +static int __init sdhci_s3c_init(void) +{ + return platform_driver_register(&sdhci_s3c_driver); +} + +static void __exit sdhci_s3c_exit(void) +{ + platform_driver_unregister(&sdhci_s3c_driver); +} + +module_init(sdhci_s3c_init); +module_exit(sdhci_s3c_exit); MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue"); MODULE_AUTHOR("Ben Dooks, "); diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index c6ece0bd03b..60a4c97d3d1 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -4,7 +4,7 @@ * Support of SDHCI platform devices for spear soc family * * Copyright (C) 2010 ST Microelectronics - * Viresh Kumar + * Viresh Kumar * * Inspired by sdhci-pltfm.c * @@ -17,13 +17,9 @@ #include #include #include -#include #include #include -#include -#include #include -#include #include #include #include @@ -70,45 +66,15 @@ static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id) return IRQ_HANDLED; } -#ifdef CONFIG_OF -static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) +static int __devinit sdhci_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; - struct sdhci_plat_data *pdata = NULL; - int cd_gpio; - - cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); - if (!gpio_is_valid(cd_gpio)) - cd_gpio = -1; - - /* If pdata is required */ - if (cd_gpio != -1) { - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&pdev->dev, "DT: kzalloc failed\n"); - return ERR_PTR(-ENOMEM); - } - } - - pdata->card_int_gpio = cd_gpio; - - return pdata; -} -#else -static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) -{ - return ERR_PTR(-ENOSYS); -} -#endif - -static int sdhci_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; struct sdhci_host *host; struct resource *iomem; struct spear_sdhci *sdhci; int ret; + BUG_ON(pdev == NULL); + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iomem) { ret = -ENOMEM; @@ -116,18 +82,18 @@ static int sdhci_probe(struct platform_device *pdev) goto err; } - if (!devm_request_mem_region(&pdev->dev, iomem->start, - resource_size(iomem), "spear-sdhci")) { + if (!request_mem_region(iomem->start, resource_size(iomem), + "spear-sdhci")) { ret = -EBUSY; dev_dbg(&pdev->dev, "cannot request region\n"); goto err; } - sdhci = devm_kzalloc(&pdev->dev, sizeof(*sdhci), GFP_KERNEL); + sdhci = kzalloc(sizeof(*sdhci), GFP_KERNEL); if (!sdhci) { ret = -ENOMEM; dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); - goto err; + goto err_kzalloc; } /* clk enable */ @@ -135,30 +101,17 @@ static int 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; + goto err_clk_get; } - ret = clk_prepare_enable(sdhci->clk); + ret = clk_enable(sdhci->clk); if (ret) { dev_dbg(&pdev->dev, "Error enabling clock\n"); - goto put_clk; - } - - ret = clk_set_rate(sdhci->clk, 50000000); - if (ret) - dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n", - clk_get_rate(sdhci->clk)); - - if (np) { - sdhci->data = sdhci_probe_config_dt(pdev); - if (IS_ERR(sdhci->data)) { - dev_err(&pdev->dev, "DT: Failed to get pdata\n"); - return -ENODEV; - } - } else { - sdhci->data = dev_get_platdata(&pdev->dev); + goto err_clk_enb; } + /* overwrite platform_data */ + sdhci->data = dev_get_platdata(&pdev->dev); pdev->dev.platform_data = sdhci; if (pdev->dev.parent) @@ -169,7 +122,7 @@ static int sdhci_probe(struct platform_device *pdev) if (IS_ERR(host)) { ret = PTR_ERR(host); dev_dbg(&pdev->dev, "error allocating host\n"); - goto disable_clk; + goto err_alloc_host; } host->hw_name = "sdhci"; @@ -177,18 +130,17 @@ static int sdhci_probe(struct platform_device *pdev) host->irq = platform_get_irq(pdev, 0); host->quirks = SDHCI_QUIRK_BROKEN_ADMA; - host->ioaddr = devm_ioremap(&pdev->dev, iomem->start, - resource_size(iomem)); + host->ioaddr = ioremap(iomem->start, resource_size(iomem)); if (!host->ioaddr) { ret = -ENOMEM; dev_dbg(&pdev->dev, "failed to remap registers\n"); - goto free_host; + goto err_ioremap; } ret = sdhci_add_host(host); if (ret) { dev_dbg(&pdev->dev, "error adding host\n"); - goto free_host; + goto err_add_host; } platform_set_drvdata(pdev, host); @@ -207,12 +159,11 @@ static int sdhci_probe(struct platform_device *pdev) if (sdhci->data->card_power_gpio >= 0) { int val = 0; - ret = devm_gpio_request(&pdev->dev, - sdhci->data->card_power_gpio, "sdhci"); + ret = gpio_request(sdhci->data->card_power_gpio, "sdhci"); if (ret < 0) { dev_dbg(&pdev->dev, "gpio request fail: %d\n", sdhci->data->card_power_gpio); - goto set_drvdata; + goto err_pgpio_request; } if (sdhci->data->power_always_enb) @@ -224,126 +175,124 @@ static int sdhci_probe(struct platform_device *pdev) if (ret) { dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", sdhci->data->card_power_gpio); - goto set_drvdata; + goto err_pgpio_direction; } + + gpio_set_value(sdhci->data->card_power_gpio, 1); } if (sdhci->data->card_int_gpio >= 0) { - ret = devm_gpio_request(&pdev->dev, sdhci->data->card_int_gpio, - "sdhci"); + ret = gpio_request(sdhci->data->card_int_gpio, "sdhci"); if (ret < 0) { dev_dbg(&pdev->dev, "gpio request fail: %d\n", sdhci->data->card_int_gpio); - goto set_drvdata; + goto err_igpio_request; } 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 set_drvdata; + goto err_igpio_direction; } - ret = devm_request_irq(&pdev->dev, - gpio_to_irq(sdhci->data->card_int_gpio), + ret = request_irq(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 set_drvdata; + goto err_igpio_request_irq; } } return 0; -set_drvdata: +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: platform_set_drvdata(pdev, NULL); sdhci_remove_host(host, 1); -free_host: +err_add_host: + iounmap(host->ioaddr); +err_ioremap: sdhci_free_host(host); -disable_clk: - clk_disable_unprepare(sdhci->clk); -put_clk: +err_alloc_host: + clk_disable(sdhci->clk); +err_clk_enb: 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; } -static int sdhci_remove(struct platform_device *pdev) +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 = 0; + int dead; 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_unprepare(sdhci->clk); + clk_disable(sdhci->clk); clk_put(sdhci->clk); + kfree(sdhci); + if (iomem) + release_mem_region(iomem->start, resource_size(iomem)); return 0; } -#ifdef CONFIG_PM -static int sdhci_suspend(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - struct spear_sdhci *sdhci = dev_get_platdata(dev); - int ret; - - ret = sdhci_suspend_host(host); - if (!ret) - clk_disable(sdhci->clk); - - return ret; -} - -static int sdhci_resume(struct device *dev) -{ - struct sdhci_host *host = dev_get_drvdata(dev); - struct spear_sdhci *sdhci = dev_get_platdata(dev); - int ret; - - ret = clk_enable(sdhci->clk); - if (ret) { - dev_dbg(dev, "Resume: Error enabling clock\n"); - return ret; - } - - return sdhci_resume_host(host); -} -#endif - -static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume); - -#ifdef CONFIG_OF -static const struct of_device_id sdhci_spear_id_table[] = { - { .compatible = "st,spear300-sdhci" }, - {} -}; -MODULE_DEVICE_TABLE(of, sdhci_spear_id_table); -#endif - static struct platform_driver sdhci_driver = { .driver = { .name = "sdhci", .owner = THIS_MODULE, - .pm = &sdhci_pm_ops, - .of_match_table = of_match_ptr(sdhci_spear_id_table), }, .probe = sdhci_probe, - .remove = sdhci_remove, + .remove = __devexit_p(sdhci_remove), }; -module_platform_driver(sdhci_driver); +static int __init sdhci_init(void) +{ + return platform_driver_register(&sdhci_driver); +} +module_init(sdhci_init); + +static void __exit sdhci_exit(void) +{ + platform_driver_unregister(&sdhci_driver); +} +module_exit(sdhci_exit); MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver"); -MODULE_AUTHOR("Viresh Kumar "); +MODULE_AUTHOR("Viresh Kumar "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 3695b2e0cbd..67950782e09 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -1,6 +1,8 @@ /* * Copyright (C) 2010 Google, Inc. * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. @@ -13,40 +15,103 @@ */ #include -#include #include #include #include #include -#include -#include -#include #include +#include #include #include +#include +#include +#include -#include - -#include +#include +#include +#include #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 SDHCI_VENDOR_CLOCK_CNTRL 0x100 +#define SDHCI_VENDOR_CLOCK_CNTRL_SDMMC_CLK 0x1 +#define SDHCI_VENDOR_CLOCK_CNTRL_PADPIPE_CLKEN_OVERRIDE 0x8 +#define SDHCI_VENDOR_CLOCK_CNTRL_SPI_MODE_CLKEN_OVERRIDE 0x4 +#define SDHCI_VENDOR_CLOCK_CNTRL_BASE_CLK_FREQ_SHIFT 8 +#define SDHCI_VENDOR_CLOCK_CNTRL_TAP_VALUE_SHIFT 16 +#define SDHCI_VENDOR_CLOCK_CNTRL_SDR50_TUNING 0x20 + +#define SDHCI_VENDOR_MISC_CNTRL 0x120 +#define SDHCI_VENDOR_MISC_CNTRL_ENABLE_SDR104_SUPPORT 0x8 +#define SDHCI_VENDOR_MISC_CNTRL_ENABLE_SDR50_SUPPORT 0x10 +#define SDHCI_VENDOR_MISC_CNTRL_ENABLE_SD_3_0 0x20 + +#define SDMMC_SDMEMCOMPPADCTRL 0x1E0 +#define SDMMC_SDMEMCOMPPADCTRL_VREF_SEL_MASK 0xF + +#define SDMMC_AUTO_CAL_CONFIG 0x1E4 +#define SDMMC_AUTO_CAL_CONFIG_AUTO_CAL_ENABLE 0x20000000 +#define SDMMC_AUTO_CAL_CONFIG_AUTO_CAL_PD_OFFSET_SHIFT 0x8 +#define SDMMC_AUTO_CAL_CONFIG_AUTO_CAL_PD_OFFSET 0x70 +#define SDMMC_AUTO_CAL_CONFIG_AUTO_CAL_PU_OFFSET 0x62 + +#define SDHOST_1V8_OCR_MASK 0x8 +#define SDHOST_HIGH_VOLT_MIN 2700000 +#define SDHOST_HIGH_VOLT_MAX 3600000 +#define SDHOST_LOW_VOLT_MIN 1800000 +#define SDHOST_LOW_VOLT_MAX 1800000 + +#define TEGRA_SDHOST_MIN_FREQ 50000000 +#define TEGRA2_SDHOST_STD_FREQ 50000000 +#define TEGRA3_SDHOST_STD_FREQ 104000000 + +#define SD_SEND_TUNING_PATTERN 19 +#define MAX_TAP_VALUES 256 + +static unsigned int tegra_sdhost_min_freq; +static unsigned int tegra_sdhost_std_freq; +static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock); +static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci); + +static unsigned int tegra3_sdhost_max_clk[4] = { + 208000000, 104000000, 208000000, 104000000 }; + +struct tegra_sdhci_hw_ops{ + /* Set the internal clk and card clk.*/ + void (*set_card_clock)(struct sdhci_host *sdhci, unsigned int clock); + /* Post reset vendor registers configuration */ + void (*sdhost_init)(struct sdhci_host *sdhci); +}; -#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) -#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) -#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +static struct tegra_sdhci_hw_ops tegra_2x_sdhci_ops = { +}; +#endif -struct sdhci_tegra_soc_data { - struct sdhci_pltfm_data *pdata; - u32 nvquirks; +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +static struct tegra_sdhci_hw_ops tegra_3x_sdhci_ops = { + .set_card_clock = tegra_3x_sdhci_set_card_clock, + .sdhost_init = tegra3_sdhci_post_reset_init, }; +#endif -struct sdhci_tegra { - const struct tegra_sdhci_platform_data *plat; - const struct sdhci_tegra_soc_data *soc_data; +struct tegra_sdhci_host { + bool clk_enabled; + struct regulator *vdd_io_reg; + struct regulator *vdd_slot_reg; + /* Pointer to the chip specific HW ops */ + struct tegra_sdhci_hw_ops *hw_ops; + /* Host controller instance */ + unsigned int instance; + /* vddio_min */ + unsigned int vddio_min_uv; + /* vddio_max */ + unsigned int vddio_max_uv; + /* max clk supported by the platform */ + unsigned int max_clk_limit; + struct tegra_io_dpd *dpd; + bool card_present; + bool is_rail_enabled; }; static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) @@ -64,25 +129,17 @@ static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) { - 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 (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) && - (reg == SDHCI_HOST_VERSION))) { +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + if (unlikely(reg == SDHCI_HOST_VERSION)) { /* Erratum: Version register is invalid in HW. */ return SDHCI_SPEC_200; } - +#endif return readw(host->ioaddr + reg); } static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) { - 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; - /* Seems like we're getting spurious timeout and crc errors, so * disable signalling of them. In case of real errors software * timers should take care of eventually detecting them. @@ -92,8 +149,8 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) writel(val, host->ioaddr + reg); - if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) && - (reg == SDHCI_INT_ENABLE))) { +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + if (unlikely(reg == SDHCI_INT_ENABLE)) { /* Erratum: Must enable block gap interrupt detection */ u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); if (val & SDHCI_INT_CARD_INT) @@ -102,13 +159,23 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) gap_ctrl &= ~0x8; writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); } +#endif } -static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) +static unsigned int tegra_sdhci_get_cd(struct sdhci_host *sdhci) { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - const struct tegra_sdhci_platform_data *plat = tegra_host->plat; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + + return tegra_host->card_present; +} + +static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc)); + struct tegra_sdhci_platform_data *plat; + + plat = pdev->dev.platform_data; if (!gpio_is_valid(plat->wp_gpio)) return -1; @@ -116,40 +183,163 @@ static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) return gpio_get_value(plat->wp_gpio); } -static irqreturn_t carddetect_irq(int irq, void *data) +static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci) { - struct sdhci_host *sdhost = (struct sdhci_host *)data; + u16 misc_ctrl; + u32 vendor_ctrl; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc)); + struct tegra_sdhci_platform_data *plat; - tasklet_schedule(&sdhost->card_tasklet); - return IRQ_HANDLED; -}; + plat = pdev->dev.platform_data; + /* Set the base clock frequency */ + vendor_ctrl = sdhci_readl(sdhci, SDHCI_VENDOR_CLOCK_CNTRL); + vendor_ctrl &= ~(0xFF << SDHCI_VENDOR_CLOCK_CNTRL_BASE_CLK_FREQ_SHIFT); + vendor_ctrl |= (tegra3_sdhost_max_clk[tegra_host->instance] / 1000000) << + SDHCI_VENDOR_CLOCK_CNTRL_BASE_CLK_FREQ_SHIFT; + vendor_ctrl |= SDHCI_VENDOR_CLOCK_CNTRL_PADPIPE_CLKEN_OVERRIDE; + vendor_ctrl &= ~SDHCI_VENDOR_CLOCK_CNTRL_SPI_MODE_CLKEN_OVERRIDE; + + /* Set tap delay */ + if (plat->tap_delay) { + vendor_ctrl &= ~(0xFF << + SDHCI_VENDOR_CLOCK_CNTRL_TAP_VALUE_SHIFT); + vendor_ctrl |= (plat->tap_delay << + SDHCI_VENDOR_CLOCK_CNTRL_TAP_VALUE_SHIFT); + } + /* Enable frequency tuning for SDR50 mode */ + vendor_ctrl |= SDHCI_VENDOR_CLOCK_CNTRL_SDR50_TUNING; + sdhci_writel(sdhci, vendor_ctrl, SDHCI_VENDOR_CLOCK_CNTRL); + + /* Enable SDHOST v3.0 support */ + misc_ctrl = sdhci_readw(sdhci, SDHCI_VENDOR_MISC_CNTRL); + misc_ctrl |= SDHCI_VENDOR_MISC_CNTRL_ENABLE_SD_3_0 | + SDHCI_VENDOR_MISC_CNTRL_ENABLE_SDR104_SUPPORT | + SDHCI_VENDOR_MISC_CNTRL_ENABLE_SDR50_SUPPORT; + sdhci_writew(sdhci, misc_ctrl, SDHCI_VENDOR_MISC_CNTRL); +} -static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) +static int tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, + unsigned int uhs) { - 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; + u16 clk, ctrl_2; + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + + /* Select Bus Speed Mode for host */ + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + switch (uhs) { + case MMC_TIMING_UHS_SDR12: + ctrl_2 |= SDHCI_CTRL_UHS_SDR12; + break; + case MMC_TIMING_UHS_SDR25: + ctrl_2 |= SDHCI_CTRL_UHS_SDR25; + break; + case MMC_TIMING_UHS_SDR50: + ctrl_2 |= SDHCI_CTRL_UHS_SDR50; + break; + case MMC_TIMING_UHS_SDR104: + ctrl_2 |= SDHCI_CTRL_UHS_SDR104; + break; + case MMC_TIMING_UHS_DDR50: + ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + break; + } + + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); + + if (uhs == MMC_TIMING_UHS_DDR50) { + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~(0xFF << SDHCI_DIVIDER_SHIFT); + clk |= 1 << SDHCI_DIVIDER_SHIFT; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + } + return 0; +} + +static void tegra_sdhci_reset_exit(struct sdhci_host *sdhci, u8 mask) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; - if (!(mask & SDHCI_RESET_ALL)) + if (mask & SDHCI_RESET_ALL) { + if (tegra_host->hw_ops->sdhost_init) + tegra_host->hw_ops->sdhost_init(sdhci); + } +} + +static void sdhci_status_notify_cb(int card_present, void *dev_id) +{ + struct sdhci_host *sdhci = (struct sdhci_host *)dev_id; + struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc)); + struct tegra_sdhci_platform_data *plat; + unsigned int status, oldstat; + + pr_debug("%s: card_present %d\n", mmc_hostname(sdhci->mmc), + card_present); + + plat = pdev->dev.platform_data; + if (!plat->mmc_data.status) { + mmc_detect_change(sdhci->mmc, 0); return; + } - /* Erratum: Enable SDHCI spec v3.00 support */ - if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) { - u32 misc_ctrl; + status = plat->mmc_data.status(mmc_dev(sdhci->mmc)); - 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); + oldstat = plat->mmc_data.card_present; + plat->mmc_data.card_present = status; + if (status ^ oldstat) { + pr_debug("%s: Slot status change detected (%d -> %d)\n", + mmc_hostname(sdhci->mmc), oldstat, status); + if (status && !plat->mmc_data.built_in) + mmc_detect_change(sdhci->mmc, (5 * HZ) / 2); + else + mmc_detect_change(sdhci->mmc, 0); } } +static irqreturn_t carddetect_irq(int irq, void *data) +{ + struct sdhci_host *sdhost = (struct sdhci_host *)data; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhost); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + struct platform_device *pdev = to_platform_device(mmc_dev(sdhost->mmc)); + struct tegra_sdhci_platform_data *plat; + + plat = pdev->dev.platform_data; + + tegra_host->card_present = (gpio_get_value(plat->cd_gpio) == 0); + + if (tegra_host->card_present) { + if (!tegra_host->is_rail_enabled) { + if (tegra_host->vdd_slot_reg) + regulator_enable(tegra_host->vdd_slot_reg); + if (tegra_host->vdd_io_reg) + regulator_enable(tegra_host->vdd_io_reg); + tegra_host->is_rail_enabled = 1; + } + } /* else { + if (tegra_host->is_rail_enabled) { + if (tegra_host->vdd_io_reg) + regulator_disable(tegra_host->vdd_io_reg); + if (tegra_host->vdd_slot_reg) + regulator_disable(tegra_host->vdd_slot_reg); + tegra_host->is_rail_enabled = 0; + } + } */ + + tasklet_schedule(&sdhost->card_tasklet); + return IRQ_HANDLED; +}; + static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - const struct tegra_sdhci_platform_data *plat = tegra_host->plat; + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + struct tegra_sdhci_platform_data *plat; u32 ctrl; + plat = pdev->dev.platform_data; + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) { ctrl &= ~SDHCI_CTRL_4BITBUS; @@ -165,102 +355,562 @@ static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) return 0; } +static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci, + unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + unsigned int clk_rate; + + if (sdhci->mmc->card && + mmc_card_ddr_mode(sdhci->mmc->card)) { + /* + * In ddr mode, tegra sdmmc controller clock frequency + * should be double the card clock frequency. + */ + clk_rate = clock * 2; + } else { + if (clock <= tegra_sdhost_min_freq) + clk_rate = tegra_sdhost_min_freq; + else if (clock <= tegra_sdhost_std_freq) + clk_rate = tegra_sdhost_std_freq; + else + clk_rate = clock; + + /* + * In SDR50 mode, run the sdmmc controller at 208MHz to ensure + * the core voltage is at 1.2V. If the core voltage is below 1.2V, CRC + * errors would occur during data transfers. + */ + if ((sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50) && + (clk_rate == tegra_sdhost_std_freq)) + clk_rate <<= 1; + } + + if (tegra_host->max_clk_limit && + (clk_rate > tegra_host->max_clk_limit)) + clk_rate = tegra_host->max_clk_limit; + + clk_set_rate(pltfm_host->clk, clk_rate); + sdhci->max_clk = clk_get_rate(pltfm_host->clk); +} + +static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock) +{ + int div; + u16 clk; + unsigned long timeout; + u8 ctrl; + + if (clock && clock == sdhci->clock) + return; + + sdhci_writew(sdhci, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) + goto out; + if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_DDR50) { + div = 1; + goto set_clk; + } + + if (sdhci->version >= SDHCI_SPEC_300) { + /* Version 3.00 divisors must be a multiple of 2. */ + if (sdhci->max_clk <= clock) { + div = 1; + } else { + for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { + if ((sdhci->max_clk / div) <= clock) + break; + } + } + } else { + /* Version 2.00 divisors must be a power of 2. */ + for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) { + if ((sdhci->max_clk / div) <= clock) + break; + } + } + div >>= 1; + + /* + * Tegra3 sdmmc controller internal clock will not be stabilized when + * we use a clock divider value greater than 4. The WAR is as follows. + * - Enable internal clock. + * - Wait for 5 usec and do a dummy write. + * - Poll for clk stable. + */ +set_clk: + clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; + clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) + << SDHCI_DIVIDER_HI_SHIFT; + clk |= SDHCI_CLOCK_INT_EN; + sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL); + + /* Wait for 5 usec */ + udelay(5); + + /* Do a dummy write */ + ctrl = sdhci_readb(sdhci, SDHCI_CAPABILITIES); + ctrl |= 1; + sdhci_writeb(sdhci, ctrl, SDHCI_CAPABILITIES); + + /* Wait max 20 ms */ + timeout = 20; + while (!((clk = sdhci_readw(sdhci, SDHCI_CLOCK_CONTROL)) + & SDHCI_CLOCK_INT_STABLE)) { + if (timeout == 0) { + dev_err(mmc_dev(sdhci->mmc), "Internal clock never stabilised\n"); + return; + } + timeout--; + mdelay(1); + } + + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL); +out: + sdhci->clock = clock; +} + +static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + u8 ctrl; + + pr_debug("%s %s %u enabled=%u\n", __func__, + mmc_hostname(sdhci->mmc), clock, tegra_host->clk_enabled); + + if (clock) { + /* bring out sd instance from io dpd mode */ + tegra_io_dpd_disable(tegra_host->dpd); + + if (!tegra_host->clk_enabled) { + clk_enable(pltfm_host->clk); + ctrl = sdhci_readb(sdhci, SDHCI_VENDOR_CLOCK_CNTRL); + ctrl |= SDHCI_VENDOR_CLOCK_CNTRL_SDMMC_CLK; + sdhci_writeb(sdhci, ctrl, SDHCI_VENDOR_CLOCK_CNTRL); + tegra_host->clk_enabled = true; + } + tegra_sdhci_set_clk_rate(sdhci, clock); + if (tegra_host->hw_ops->set_card_clock) + tegra_host->hw_ops->set_card_clock(sdhci, clock); + } else if (!clock && tegra_host->clk_enabled) { + if (tegra_host->hw_ops->set_card_clock) + tegra_host->hw_ops->set_card_clock(sdhci, clock); + ctrl = sdhci_readb(sdhci, SDHCI_VENDOR_CLOCK_CNTRL); + ctrl &= ~SDHCI_VENDOR_CLOCK_CNTRL_SDMMC_CLK; + sdhci_writeb(sdhci, ctrl, SDHCI_VENDOR_CLOCK_CNTRL); + clk_disable(pltfm_host->clk); + tegra_host->clk_enabled = false; + /* io dpd enable call for sd instance */ + tegra_io_dpd_enable(tegra_host->dpd); + } +} + +static int tegra_sdhci_signal_voltage_switch(struct sdhci_host *sdhci, + unsigned int signal_voltage) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + unsigned int min_uV = SDHOST_HIGH_VOLT_MIN; + unsigned int max_uV = SDHOST_HIGH_VOLT_MAX; + unsigned int rc = 0; + u16 clk, ctrl; + unsigned int val; + + /* Switch OFF the card clock to prevent glitches on the clock line */ + clk = sdhci_readw(sdhci, SDHCI_CLOCK_CONTROL); + clk &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL); + + ctrl = sdhci_readw(sdhci, SDHCI_HOST_CONTROL2); + if (signal_voltage == MMC_SIGNAL_VOLTAGE_180) { + ctrl |= SDHCI_CTRL_VDD_180; + min_uV = SDHOST_LOW_VOLT_MIN; + max_uV = SDHOST_LOW_VOLT_MAX; + } else if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + if (ctrl & SDHCI_CTRL_VDD_180) + ctrl &= ~SDHCI_CTRL_VDD_180; + } + sdhci_writew(sdhci, ctrl, SDHCI_HOST_CONTROL2); + + /* Switch the I/O rail voltage */ + if (tegra_host->vdd_io_reg) { + rc = regulator_set_voltage(tegra_host->vdd_io_reg, + min_uV, max_uV); + if (rc) { + dev_err(mmc_dev(sdhci->mmc), "switching to 1.8V" + "failed . Switching back to 3.3V\n"); + regulator_set_voltage(tegra_host->vdd_io_reg, + SDHOST_HIGH_VOLT_MIN, + SDHOST_HIGH_VOLT_MAX); + goto out; + } + } + + /* Wait for 10 msec for the voltage to be switched */ + mdelay(10); + + /* Enable the card clock */ + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL); + + /* Wait for 1 msec after enabling clock */ + mdelay(1); + + if (signal_voltage == MMC_SIGNAL_VOLTAGE_180) { + /* Do Auto Calibration for 1.8V signal voltage */ + val = sdhci_readl(sdhci, SDMMC_AUTO_CAL_CONFIG); + val |= SDMMC_AUTO_CAL_CONFIG_AUTO_CAL_ENABLE; + /* Program Auto cal PD offset(bits 8:14) */ + val &= ~(0x7F << + SDMMC_AUTO_CAL_CONFIG_AUTO_CAL_PD_OFFSET_SHIFT); + val |= (SDMMC_AUTO_CAL_CONFIG_AUTO_CAL_PD_OFFSET << + SDMMC_AUTO_CAL_CONFIG_AUTO_CAL_PD_OFFSET_SHIFT); + /* Program Auto cal PU offset(bits 0:6) */ + val &= ~0x7F; + val |= SDMMC_AUTO_CAL_CONFIG_AUTO_CAL_PU_OFFSET; + sdhci_writel(sdhci, val, SDMMC_AUTO_CAL_CONFIG); + + val = sdhci_readl(sdhci, SDMMC_SDMEMCOMPPADCTRL); + val &= ~SDMMC_SDMEMCOMPPADCTRL_VREF_SEL_MASK; + val |= 0x7; + sdhci_writel(sdhci, val, SDMMC_SDMEMCOMPPADCTRL); + } + + return rc; +out: + /* Enable the card clock */ + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(sdhci, clk, SDHCI_CLOCK_CONTROL); + + /* Wait for 1 msec for the clock to stabilize */ + mdelay(1); + + return rc; +} + +static void tegra_sdhci_reset(struct sdhci_host *sdhci, u8 mask) +{ + unsigned long timeout; + + sdhci_writeb(sdhci, mask, SDHCI_SOFTWARE_RESET); + + /* Wait max 100 ms */ + timeout = 100; + + /* hw clears the bit when it's done */ + while (sdhci_readb(sdhci, SDHCI_SOFTWARE_RESET) & mask) { + if (timeout == 0) { + dev_err(mmc_dev(sdhci->mmc), "Reset 0x%x never" + "completed.\n", (int)mask); + return; + } + timeout--; + mdelay(1); + } +} + +static void sdhci_tegra_set_tap_delay(struct sdhci_host *sdhci, + unsigned int tap_delay) +{ + u32 vendor_ctrl; + + /* Max tap delay value is 255 */ + BUG_ON(tap_delay > MAX_TAP_VALUES); + + vendor_ctrl = sdhci_readl(sdhci, SDHCI_VENDOR_CLOCK_CNTRL); + vendor_ctrl &= ~(0xFF << SDHCI_VENDOR_CLOCK_CNTRL_TAP_VALUE_SHIFT); + vendor_ctrl |= (tap_delay << SDHCI_VENDOR_CLOCK_CNTRL_TAP_VALUE_SHIFT); + sdhci_writel(sdhci, vendor_ctrl, SDHCI_VENDOR_CLOCK_CNTRL); +} + +static void sdhci_tegra_clear_set_irqs(struct sdhci_host *host, + u32 clear, u32 set) +{ + u32 ier; + + ier = sdhci_readl(host, SDHCI_INT_ENABLE); + ier &= ~clear; + ier |= set; + sdhci_writel(host, ier, SDHCI_INT_ENABLE); + sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); +} + +static int sdhci_tegra_run_frequency_tuning(struct sdhci_host *sdhci) +{ + int err = 0; + u8 ctrl; + u32 ier; + u32 mask; + unsigned int timeout = 10; + int flags; + u32 intstatus; + + /* + * As per the Host Controller spec v3.00, tuning command + * generates Buffer Read Ready interrupt only, so enable that. + */ + ier = sdhci_readl(sdhci, SDHCI_INT_ENABLE); + sdhci_tegra_clear_set_irqs(sdhci, ier, SDHCI_INT_DATA_AVAIL | + SDHCI_INT_DATA_CRC); + + mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; + while (sdhci_readl(sdhci, SDHCI_PRESENT_STATE) & mask) { + if (timeout == 0) { + dev_err(mmc_dev(sdhci->mmc), "Controller never" + "released inhibit bit(s).\n"); + err = -ETIMEDOUT; + goto out; + } + timeout--; + mdelay(1); + } + + ctrl = sdhci_readb(sdhci, SDHCI_HOST_CONTROL2); + ctrl &= ~SDHCI_CTRL_TUNED_CLK; + sdhci_writeb(sdhci, ctrl, SDHCI_HOST_CONTROL2); + + ctrl = sdhci_readb(sdhci, SDHCI_HOST_CONTROL2); + ctrl |= SDHCI_CTRL_EXEC_TUNING; + sdhci_writeb(sdhci, ctrl, SDHCI_HOST_CONTROL2); + + /* + * In response to CMD19, the card sends 64 bytes of tuning + * block to the Host Controller. So we set the block size + * to 64 here. + */ + sdhci_writew(sdhci, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE); + + sdhci_writeb(sdhci, 0xE, SDHCI_TIMEOUT_CONTROL); + + sdhci_writeb(sdhci, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); + + sdhci_writel(sdhci, 0x0, SDHCI_ARGUMENT); + + /* Set the cmd flags */ + flags = SDHCI_CMD_RESP_SHORT | SDHCI_CMD_CRC | SDHCI_CMD_DATA; + /* Issue the command */ + sdhci_writew(sdhci, SDHCI_MAKE_CMD( + SD_SEND_TUNING_PATTERN, flags), SDHCI_COMMAND); + + timeout = 5; + do { + timeout--; + mdelay(1); + intstatus = sdhci_readl(sdhci, SDHCI_INT_STATUS); + if (intstatus) { + sdhci_writel(sdhci, intstatus, SDHCI_INT_STATUS); + break; + } + } while(timeout); + + if ((intstatus & SDHCI_INT_DATA_AVAIL) && + !(intstatus & SDHCI_INT_DATA_CRC)) { + err = 0; + sdhci->tuning_done = 1; + } else { + tegra_sdhci_reset(sdhci, SDHCI_RESET_CMD); + tegra_sdhci_reset(sdhci, SDHCI_RESET_DATA); + err = -EIO; + } + + if (sdhci->tuning_done) { + sdhci->tuning_done = 0; + ctrl = sdhci_readb(sdhci, SDHCI_HOST_CONTROL2); + if (!(ctrl & SDHCI_CTRL_EXEC_TUNING) && + (ctrl & SDHCI_CTRL_TUNED_CLK)) + err = 0; + else + err = -EIO; + } + mdelay(1); +out: + sdhci_tegra_clear_set_irqs(sdhci, SDHCI_INT_DATA_AVAIL, ier); + return err; +} + +static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci) +{ + int err; + u16 ctrl_2; + u8 *tap_delay_status; + unsigned int i = 0; + unsigned int temp_low_pass_tap = 0; + unsigned int temp_pass_window = 0; + unsigned int best_low_pass_tap = 0; + unsigned int best_pass_window = 0; + + /* Tuning is valid only in SDR104 and SDR50 modes */ + ctrl_2 = sdhci_readw(sdhci, SDHCI_HOST_CONTROL2); + if (!(((ctrl_2 & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) || + (((ctrl_2 & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && + (sdhci->flags & SDHCI_SDR50_NEEDS_TUNING)))) + return 0; + + tap_delay_status = kzalloc(MAX_TAP_VALUES, GFP_KERNEL); + if (tap_delay_status == NULL) { + dev_err(mmc_dev(sdhci->mmc), "failed to allocate memory" + "for storing tap_delay_status\n"); + err = -ENOMEM; + goto out; + } + + /* + * Set each tap delay value and run frequency tuning. After each + * run, update the tap delay status as working or not working. + */ + do { + /* Set the tap delay */ + sdhci_tegra_set_tap_delay(sdhci, i); + + /* Run frequency tuning */ + err = sdhci_tegra_run_frequency_tuning(sdhci); + + /* Update whether the tap delay worked or not */ + tap_delay_status[i] = (err) ? 0: 1; + i++; + } while (i < 0xFF); + + /* Find the best possible tap range */ + for (i = 0; i < 0xFF; i++) { + temp_pass_window = 0; + + /* Find the first passing tap in the current window */ + if (tap_delay_status[i]) { + temp_low_pass_tap = i; + + /* Find the pass window */ + do { + temp_pass_window++; + i++; + if (i > 0xFF) + break; + } while (tap_delay_status[i]); + + if ((temp_pass_window > best_pass_window) && (temp_pass_window > 1)){ + best_low_pass_tap = temp_low_pass_tap; + best_pass_window = temp_pass_window; + } + } + } + + + pr_debug("%s: best pass tap window: start %d, end %d\n", + mmc_hostname(sdhci->mmc), best_low_pass_tap, + (best_low_pass_tap + best_pass_window)); + + /* Set the best tap */ + sdhci_tegra_set_tap_delay(sdhci, + (best_low_pass_tap + ((best_pass_window * 3) / 4))); + + /* Run frequency tuning */ + err = sdhci_tegra_run_frequency_tuning(sdhci); + +out: + if (tap_delay_status) + kfree(tap_delay_status); + + return err; +} + +static int tegra_sdhci_suspend(struct sdhci_host *sdhci, pm_message_t state) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + + tegra_sdhci_set_clock(sdhci, 0); + + /* Disable the power rails if any */ + if (tegra_host->card_present) { + if (tegra_host->is_rail_enabled) { + if (tegra_host->vdd_io_reg) + regulator_disable(tegra_host->vdd_io_reg); + if (tegra_host->vdd_slot_reg) + regulator_disable(tegra_host->vdd_slot_reg); + tegra_host->is_rail_enabled = 0; + } + } + + return 0; +} + +static int tegra_sdhci_resume(struct sdhci_host *sdhci) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + + /* Enable the power rails if any */ + if (tegra_host->card_present) { + if (!tegra_host->is_rail_enabled) { + if (tegra_host->vdd_slot_reg) + regulator_enable(tegra_host->vdd_slot_reg); + if (tegra_host->vdd_io_reg) { + regulator_enable(tegra_host->vdd_io_reg); + tegra_sdhci_signal_voltage_switch(sdhci, MMC_SIGNAL_VOLTAGE_330); + } + tegra_host->is_rail_enabled = 1; + } + } + /* Setting the min identification clock of freq 400KHz */ + tegra_sdhci_set_clock(sdhci, 400000); + + /* Reset the controller and power on if MMC_KEEP_POWER flag is set*/ + if (sdhci->mmc->pm_flags & MMC_PM_KEEP_POWER) { + tegra_sdhci_reset(sdhci, SDHCI_RESET_ALL); + sdhci_writeb(sdhci, SDHCI_POWER_ON, SDHCI_POWER_CONTROL); + sdhci->pwr = 0; + } + + return 0; +} + static struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, + .get_cd = tegra_sdhci_get_cd, .read_l = tegra_sdhci_readl, .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, .platform_8bit_width = tegra_sdhci_8bit, + .set_clock = tegra_sdhci_set_clock, + .suspend = tegra_sdhci_suspend, + .resume = tegra_sdhci_resume, .platform_reset_exit = tegra_sdhci_reset_exit, + .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, + .switch_signal_voltage = tegra_sdhci_signal_voltage_switch, + .execute_freq_tuning = sdhci_tegra_execute_tuning, }; -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -static struct sdhci_pltfm_data sdhci_tegra20_pdata = { +static struct sdhci_pltfm_data sdhci_tegra_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_SINGLE_POWER_WRITE | - SDHCI_QUIRK_NO_HISPD_BIT | - SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, - .ops = &tegra_sdhci_ops, -}; - -static struct sdhci_tegra_soc_data soc_data_tegra20 = { - .pdata = &sdhci_tegra20_pdata, - .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 | - NVQUIRK_ENABLE_BLOCK_GAP_DET, -}; +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_NON_STD_VOLTAGE_SWITCHING | #endif - #ifdef CONFIG_ARCH_TEGRA_3x_SOC -static struct sdhci_pltfm_data sdhci_tegra30_pdata = { - .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_NONSTANDARD_CLOCK | + SDHCI_QUIRK_NON_STANDARD_TUNING | +#endif SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_NO_HISPD_BIT | - SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | + SDHCI_QUIRK_NO_CALC_MAX_DISCARD_TO | + SDHCI_QUIRK_BROKEN_CARD_DETECTION, .ops = &tegra_sdhci_ops, }; -static struct sdhci_tegra_soc_data soc_data_tegra30 = { - .pdata = &sdhci_tegra30_pdata, - .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300, -}; -#endif - -static const struct of_device_id sdhci_tegra_dt_match[] = { -#ifdef CONFIG_ARCH_TEGRA_3x_SOC - { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, -#endif -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, -#endif - {} -}; -MODULE_DEVICE_TABLE(of, sdhci_dt_ids); - -static struct tegra_sdhci_platform_data *sdhci_tegra_dt_parse_pdata( - struct platform_device *pdev) +static int __devinit sdhci_tegra_probe(struct platform_device *pdev) { - struct tegra_sdhci_platform_data *plat; - struct device_node *np = pdev->dev.of_node; - u32 bus_width; - - if (!np) - return NULL; - - plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); - if (!plat) { - dev_err(&pdev->dev, "Can't allocate platform data\n"); - return NULL; - } - - plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); - plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); - plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0); - - if (of_property_read_u32(np, "bus-width", &bus_width) == 0 && - bus_width == 8) - plat->is_8bit = 1; - - return plat; -} - -static int sdhci_tegra_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - const struct sdhci_tegra_soc_data *soc_data; - struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct tegra_sdhci_platform_data *plat; - struct sdhci_tegra *tegra_host; + struct sdhci_host *host; + struct tegra_sdhci_host *tegra_host; struct clk *clk; int rc; - match = of_match_device(sdhci_tegra_dt_match, &pdev->dev); - if (!match) - return -EINVAL; - soc_data = match->data; - - host = sdhci_pltfm_init(pdev, soc_data->pdata); + host = sdhci_pltfm_init(pdev, &sdhci_tegra_pdata); if (IS_ERR(host)) return PTR_ERR(host); @@ -268,26 +918,27 @@ static int sdhci_tegra_probe(struct platform_device *pdev) plat = pdev->dev.platform_data; - if (plat == NULL) - plat = sdhci_tegra_dt_parse_pdata(pdev); - if (plat == NULL) { dev_err(mmc_dev(host->mmc), "missing platform data\n"); rc = -ENXIO; goto err_no_plat; } - tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL); - if (!tegra_host) { - dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n"); + tegra_host = kzalloc(sizeof(struct tegra_sdhci_host), GFP_KERNEL); + if (tegra_host == NULL) { + dev_err(mmc_dev(host->mmc), "failed to allocate tegra host\n"); rc = -ENOMEM; - goto err_no_plat; + goto err_no_mem; } - tegra_host->plat = plat; - tegra_host->soc_data = soc_data; - - pltfm_host->priv = tegra_host; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (plat->mmc_data.embedded_sdio) + mmc_set_embedded_sdio_data(host->mmc, + &plat->mmc_data.embedded_sdio->cis, + &plat->mmc_data.embedded_sdio->cccr, + plat->mmc_data.embedded_sdio->funcs, + plat->mmc_data.embedded_sdio->num_funcs); +#endif if (gpio_is_valid(plat->power_gpio)) { rc = gpio_request(plat->power_gpio, "sdhci_power"); @@ -296,6 +947,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) "failed to allocate power gpio\n"); goto err_power_req; } + tegra_gpio_enable(plat->power_gpio); gpio_direction_output(plat->power_gpio, 1); } @@ -306,9 +958,13 @@ static int sdhci_tegra_probe(struct platform_device *pdev) "failed to allocate cd gpio\n"); goto err_cd_req; } + tegra_gpio_enable(plat->cd_gpio); gpio_direction_input(plat->cd_gpio); - rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq, + tegra_host->card_present = (gpio_get_value(plat->cd_gpio) == 0); + + rc = request_threaded_irq(gpio_to_irq(plat->cd_gpio), NULL, + carddetect_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, mmc_hostname(host->mmc), host); @@ -316,7 +972,18 @@ static int sdhci_tegra_probe(struct platform_device *pdev) dev_err(mmc_dev(host->mmc), "request irq error\n"); goto err_cd_irq_req; } + rc = enable_irq_wake(gpio_to_irq(plat->cd_gpio)); + if (rc < 0) + dev_err(mmc_dev(host->mmc), + "SD card wake-up event registration" + "failed with eroor: %d\n", rc); + + } else if (plat->mmc_data.register_status_notify) { + plat->mmc_data.register_status_notify(sdhci_status_notify_cb, host); + } + if (plat->mmc_data.status) { + plat->mmc_data.card_present = plat->mmc_data.status(mmc_dev(host->mmc)); } if (gpio_is_valid(plat->wp_gpio)) { @@ -326,22 +993,104 @@ static int sdhci_tegra_probe(struct platform_device *pdev) "failed to allocate wp gpio\n"); goto err_wp_req; } + tegra_gpio_enable(plat->wp_gpio); gpio_direction_input(plat->wp_gpio); } + /* + * If there is no card detect gpio, assume that the + * card is always present. + */ + if (!gpio_is_valid(plat->cd_gpio)) + tegra_host->card_present = 1; + + if (!plat->mmc_data.built_in) { + if (plat->mmc_data.ocr_mask & SDHOST_1V8_OCR_MASK) { + tegra_host->vddio_min_uv = SDHOST_LOW_VOLT_MIN; + tegra_host->vddio_max_uv = SDHOST_LOW_VOLT_MAX; + } else { + /* + * Set the minV and maxV to default + * voltage range of 2.7V - 3.6V + */ + tegra_host->vddio_min_uv = SDHOST_HIGH_VOLT_MIN; + tegra_host->vddio_max_uv = SDHOST_HIGH_VOLT_MAX; + } + tegra_host->vdd_io_reg = regulator_get(mmc_dev(host->mmc), "vddio_sdmmc"); + if (IS_ERR_OR_NULL(tegra_host->vdd_io_reg)) { + dev_err(mmc_dev(host->mmc), "%s regulator not found: %ld\n", + "vddio_sdmmc", PTR_ERR(tegra_host->vdd_io_reg)); + tegra_host->vdd_io_reg = NULL; + } else { + rc = regulator_set_voltage(tegra_host->vdd_io_reg, + tegra_host->vddio_min_uv, + tegra_host->vddio_max_uv); + if (rc) { + dev_err(mmc_dev(host->mmc), "%s regulator_set_voltage failed: %d", + "vddio_sdmmc", rc); + } + } + + tegra_host->vdd_slot_reg = regulator_get(mmc_dev(host->mmc), "vddio_sd_slot"); + if (IS_ERR_OR_NULL(tegra_host->vdd_slot_reg)) { + dev_err(mmc_dev(host->mmc), "%s regulator not found: %ld\n", + "vddio_sd_slot", PTR_ERR(tegra_host->vdd_slot_reg)); + tegra_host->vdd_slot_reg = NULL; + } + + if (tegra_host->card_present) { + if (tegra_host->vdd_slot_reg) + regulator_enable(tegra_host->vdd_slot_reg); + if (tegra_host->vdd_io_reg) + regulator_enable(tegra_host->vdd_io_reg); + tegra_host->is_rail_enabled = 1; + } + } + clk = clk_get(mmc_dev(host->mmc), NULL); if (IS_ERR(clk)) { dev_err(mmc_dev(host->mmc), "clk err\n"); rc = PTR_ERR(clk); goto err_clk_get; } - clk_prepare_enable(clk); + rc = clk_enable(clk); + if (rc != 0) + goto err_clk_put; pltfm_host->clk = clk; - - host->mmc->pm_caps = plat->pm_flags; - + pltfm_host->priv = tegra_host; + tegra_host->clk_enabled = true; + tegra_host->max_clk_limit = plat->max_clk_limit; + tegra_host->instance = pdev->id; + tegra_host->dpd = tegra_io_dpd_get(mmc_dev(host->mmc)); + + host->mmc->pm_caps |= plat->pm_caps; + host->mmc->pm_flags |= plat->pm_flags; + + host->mmc->caps |= MMC_CAP_ERASE; + host->mmc->caps |= MMC_CAP_DISABLE; + /* enable 1/8V DDR capable */ + host->mmc->caps |= MMC_CAP_1_8V_DDR; if (plat->is_8bit) host->mmc->caps |= MMC_CAP_8_BIT_DATA; + host->mmc->caps |= MMC_CAP_SDIO_IRQ; + + host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY; + if (plat->mmc_data.built_in) { + host->mmc->caps |= MMC_CAP_NONREMOVABLE; + host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; + } + /* Do not turn OFF embedded sdio cards as it support Wake on Wireless */ + if (plat->mmc_data.embedded_sdio) + host->mmc->pm_flags |= MMC_PM_KEEP_POWER; + + tegra_sdhost_min_freq = TEGRA_SDHOST_MIN_FREQ; +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + tegra_host->hw_ops = &tegra_2x_sdhci_ops; + tegra_sdhost_std_freq = TEGRA2_SDHOST_STD_FREQ; +#else + tegra_host->hw_ops = &tegra_3x_sdhci_ops; + tegra_sdhost_std_freq = TEGRA3_SDHOST_STD_FREQ; +#endif rc = sdhci_add_host(host); if (rc) @@ -350,51 +1099,81 @@ static int sdhci_tegra_probe(struct platform_device *pdev) return 0; err_add_host: - clk_disable_unprepare(pltfm_host->clk); + clk_disable(pltfm_host->clk); +err_clk_put: clk_put(pltfm_host->clk); err_clk_get: - if (gpio_is_valid(plat->wp_gpio)) + if (gpio_is_valid(plat->wp_gpio)) { + tegra_gpio_disable(plat->wp_gpio); gpio_free(plat->wp_gpio); + } err_wp_req: if (gpio_is_valid(plat->cd_gpio)) free_irq(gpio_to_irq(plat->cd_gpio), host); err_cd_irq_req: - if (gpio_is_valid(plat->cd_gpio)) + if (gpio_is_valid(plat->cd_gpio)) { + tegra_gpio_disable(plat->cd_gpio); gpio_free(plat->cd_gpio); + } err_cd_req: - if (gpio_is_valid(plat->power_gpio)) + if (gpio_is_valid(plat->power_gpio)) { + tegra_gpio_disable(plat->power_gpio); gpio_free(plat->power_gpio); + } err_power_req: +err_no_mem: + kfree(tegra_host); err_no_plat: sdhci_pltfm_free(pdev); return rc; } -static int sdhci_tegra_remove(struct platform_device *pdev) +static int __devexit sdhci_tegra_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - const struct tegra_sdhci_platform_data *plat = tegra_host->plat; + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + struct tegra_sdhci_platform_data *plat; int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); sdhci_remove_host(host, dead); - if (gpio_is_valid(plat->wp_gpio)) + plat = pdev->dev.platform_data; + + disable_irq_wake(gpio_to_irq(plat->cd_gpio)); + + if (tegra_host->vdd_slot_reg) { + regulator_disable(tegra_host->vdd_slot_reg); + regulator_put(tegra_host->vdd_slot_reg); + } + + if (tegra_host->vdd_io_reg) { + regulator_disable(tegra_host->vdd_io_reg); + regulator_put(tegra_host->vdd_io_reg); + } + + if (gpio_is_valid(plat->wp_gpio)) { + tegra_gpio_disable(plat->wp_gpio); gpio_free(plat->wp_gpio); + } if (gpio_is_valid(plat->cd_gpio)) { free_irq(gpio_to_irq(plat->cd_gpio), host); + tegra_gpio_disable(plat->cd_gpio); gpio_free(plat->cd_gpio); } - if (gpio_is_valid(plat->power_gpio)) + if (gpio_is_valid(plat->power_gpio)) { + tegra_gpio_disable(plat->power_gpio); gpio_free(plat->power_gpio); + } - clk_disable_unprepare(pltfm_host->clk); + if (tegra_host->clk_enabled) + clk_disable(pltfm_host->clk); clk_put(pltfm_host->clk); sdhci_pltfm_free(pdev); + kfree(tegra_host); return 0; } @@ -403,15 +1182,27 @@ static struct platform_driver sdhci_tegra_driver = { .driver = { .name = "sdhci-tegra", .owner = THIS_MODULE, - .of_match_table = sdhci_tegra_dt_match, - .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_tegra_probe, - .remove = sdhci_tegra_remove, + .remove = __devexit_p(sdhci_tegra_remove), +#ifdef CONFIG_PM + .suspend = sdhci_pltfm_suspend, + .resume = sdhci_pltfm_resume, +#endif }; -module_platform_driver(sdhci_tegra_driver); +static int __init sdhci_tegra_init(void) +{ + return platform_driver_register(&sdhci_tegra_driver); +} +module_init(sdhci_tegra_init); + +static void __exit sdhci_tegra_exit(void) +{ + platform_driver_unregister(&sdhci_tegra_driver); +} +module_exit(sdhci_tegra_exit); MODULE_DESCRIPTION("SDHCI driver for Tegra"); -MODULE_AUTHOR("Google, Inc."); +MODULE_AUTHOR(" Google, Inc."); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6f0bfc0c8c9..c6822c39541 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -16,19 +16,16 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include #include -#include #include "sdhci.h" @@ -45,76 +42,61 @@ #define MAX_TUNING_LOOP 40 static unsigned int debug_quirks = 0; -static unsigned int debug_quirks2; static void sdhci_finish_data(struct sdhci_host *); static void sdhci_send_command(struct sdhci_host *, struct mmc_command *); static void sdhci_finish_command(struct sdhci_host *); -static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); +static int sdhci_execute_tuning(struct mmc_host *mmc); static void sdhci_tuning_timer(unsigned long data); -#ifdef CONFIG_PM_RUNTIME -static int sdhci_runtime_pm_get(struct sdhci_host *host); -static int sdhci_runtime_pm_put(struct sdhci_host *host); -#else -static inline int sdhci_runtime_pm_get(struct sdhci_host *host) -{ - return 0; -} -static inline int sdhci_runtime_pm_put(struct sdhci_host *host) -{ - return 0; -} -#endif - static void sdhci_dumpregs(struct sdhci_host *host) { - pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", + printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", mmc_hostname(host->mmc)); - pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", sdhci_readl(host, SDHCI_DMA_ADDRESS), sdhci_readw(host, SDHCI_HOST_VERSION)); - pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", sdhci_readw(host, SDHCI_BLOCK_SIZE), sdhci_readw(host, SDHCI_BLOCK_COUNT)); - pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", sdhci_readl(host, SDHCI_ARGUMENT), sdhci_readw(host, SDHCI_TRANSFER_MODE)); - pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", sdhci_readl(host, SDHCI_PRESENT_STATE), sdhci_readb(host, SDHCI_HOST_CONTROL)); - pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", sdhci_readb(host, SDHCI_POWER_CONTROL), sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); - pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), sdhci_readw(host, SDHCI_CLOCK_CONTROL)); - pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), sdhci_readl(host, SDHCI_INT_STATUS)); - pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", sdhci_readl(host, SDHCI_INT_ENABLE), sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); - pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", sdhci_readw(host, SDHCI_ACMD12_ERR), sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); - pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", sdhci_readl(host, SDHCI_CAPABILITIES), sdhci_readl(host, SDHCI_CAPABILITIES_1)); - pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", sdhci_readw(host, SDHCI_COMMAND), sdhci_readl(host, SDHCI_MAX_CURRENT)); - pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Host ctl2: 0x%08x\n", sdhci_readw(host, SDHCI_HOST_CONTROL2)); if (host->flags & SDHCI_USE_ADMA) - pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", readl(host->ioaddr + SDHCI_ADMA_ERROR), readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); - pr_debug(DRIVER_NAME ": ===========================================\n"); + printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n"); } /*****************************************************************************\ @@ -148,8 +130,7 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) { u32 present, irqs; - if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || - (host->mmc->caps & MMC_CAP_NONREMOVABLE)) + if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) return; present = sdhci_readl(host, SDHCI_PRESENT_STATE) & @@ -200,7 +181,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) /* hw clears the bit when it's done */ while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { - pr_err("%s: Reset 0x%x never completed.\n", + printk(KERN_ERR "%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask); sdhci_dumpregs(host); return; @@ -214,11 +195,6 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); - - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { - if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL)) - host->ops->enable_dma(host); - } } static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); @@ -246,19 +222,6 @@ static void sdhci_init(struct sdhci_host *host, int soft) static void sdhci_reinit(struct sdhci_host *host) { sdhci_init(host, 0); - /* - * Retuning stuffs are affected by different cards inserted and only - * applicable to UHS-I cards. So reset these fields to their initial - * value when card is removed. - */ - if (host->flags & SDHCI_USING_RETUNING_TIMER) { - host->flags &= ~SDHCI_USING_RETUNING_TIMER; - - del_timer_sync(&host->tuning_timer); - host->flags &= ~SDHCI_NEEDS_RETUNING; - host->mmc->max_blk_count = - (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535; - } sdhci_enable_card_detection(host); } @@ -289,14 +252,11 @@ static void sdhci_led_control(struct led_classdev *led, spin_lock_irqsave(&host->lock, flags); - if (host->runtime_suspended) - goto out; - if (brightness == LED_OFF) sdhci_deactivate_led(host); else sdhci_activate_led(host); -out: + spin_unlock_irqrestore(&host->lock, flags); } #endif @@ -441,12 +401,12 @@ static void sdhci_transfer_pio(struct sdhci_host *host) static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { local_irq_save(*flags); - return kmap_atomic(sg_page(sg)) + sg->offset; + return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; } static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) { - kunmap_atomic(buffer); + kunmap_atomic(buffer, KM_BIO_SRC_IRQ); local_irq_restore(*flags); } @@ -695,8 +655,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } if (count >= 0xF) { - DBG("%s: Too large timeout 0x%x requested for CMD%d!\n", - mmc_hostname(host->mmc), count, cmd->opcode); + printk(KERN_WARNING "%s: Too large timeout requested for CMD%d!\n", + mmc_hostname(host->mmc), cmd->opcode); count = 0xE; } @@ -990,7 +950,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (timeout == 0) { - pr_err("%s: Controller never released " + printk(KERN_ERR "%s: Controller never released " "inhibit bit(s).\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); cmd->error = -EIO; @@ -1012,7 +972,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) sdhci_set_transfer_mode(host, cmd); if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { - pr_err("%s: Unsupported response type!\n", + printk(KERN_ERR "%s: Unsupported response type!\n", mmc_hostname(host->mmc)); cmd->error = -EINVAL; tasklet_schedule(&host->finish_tasklet); @@ -1034,8 +994,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) flags |= SDHCI_CMD_INDEX; /* CMD19 is special in that the Data Present Select should be set */ - if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK || - cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) + if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK)) flags |= SDHCI_CMD_DATA; sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); @@ -1085,20 +1044,14 @@ static void sdhci_finish_command(struct sdhci_host *host) static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { int div = 0; /* Initialized for compiler warning */ - int real_div = div, clk_mul = 1; u16 clk = 0; unsigned long timeout; if (clock && clock == host->clock) return; - host->mmc->actual_clock = 0; - - if (host->ops->set_clock) { - host->ops->set_clock(host, clock); - if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) - return; - } + if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) + return; sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); @@ -1131,8 +1084,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) * Control register. */ clk = SDHCI_PROG_CLOCK_MODE; - real_div = div; - clk_mul = host->clk_mul; div--; } } else { @@ -1146,7 +1097,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) break; } } - real_div = div; div >>= 1; } } else { @@ -1155,13 +1105,9 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) if ((host->max_clk / div) <= clock) break; } - real_div = div; div >>= 1; } - if (real_div) - host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div; - clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; @@ -1173,7 +1119,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - pr_err("%s: Internal clock never " + printk(KERN_ERR "%s: Internal clock never " "stabilised.\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); return; @@ -1189,7 +1135,7 @@ out: host->clock = clock; } -static int sdhci_set_power(struct sdhci_host *host, unsigned short power) +static void sdhci_set_power(struct sdhci_host *host, unsigned short power) { u8 pwr = 0; @@ -1212,13 +1158,13 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power) } if (host->pwr == pwr) - return -1; + return; host->pwr = pwr; if (pwr == 0) { sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - return 0; + return; } /* @@ -1245,8 +1191,6 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power) */ if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) mdelay(10); - - return power; } /*****************************************************************************\ @@ -1260,12 +1204,9 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) struct sdhci_host *host; bool present; unsigned long flags; - u32 tuning_opcode; host = mmc_priv(mmc); - sdhci_runtime_pm_get(host); - spin_lock_irqsave(&host->lock, flags); WARN_ON(host->mrq != NULL); @@ -1288,17 +1229,14 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; /* If polling, assume that the card is always present. */ - if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) - present = true; - else + if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) { + if (host->ops->get_cd) + present = host->ops->get_cd(host); + else + present = true; + } else { present = sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT; - - /* If we're using a cd-gpio, testing the presence bit might fail. */ - if (!present) { - int ret = mmc_gpio_get_cd(host->mmc); - if (ret > 0) - present = true; } if (!present || host->flags & SDHCI_DEVICE_DEAD) { @@ -1315,19 +1253,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) */ if ((host->flags & SDHCI_NEEDS_RETUNING) && !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) { - if (mmc->card) { - /* eMMC uses cmd21 but sd and sdio use cmd19 */ - tuning_opcode = - mmc->card->type == MMC_TYPE_MMC ? - MMC_SEND_TUNING_BLOCK_HS200 : - MMC_SEND_TUNING_BLOCK; - spin_unlock_irqrestore(&host->lock, flags); - sdhci_execute_tuning(mmc, tuning_opcode); - spin_lock_irqsave(&host->lock, flags); - - /* Restore original mmc_request structure */ - host->mrq = mrq; - } + spin_unlock_irqrestore(&host->lock, flags); + sdhci_execute_tuning(mmc); + spin_lock_irqsave(&host->lock, flags); + + /* Restore original mmc_request structure */ + host->mrq = mrq; } if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) @@ -1340,21 +1271,33 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_unlock_irqrestore(&host->lock, flags); } -static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) +static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { + struct sdhci_host *host; unsigned long flags; - int vdd_bit = -1; u8 ctrl; - spin_lock_irqsave(&host->lock, flags); + host = mmc_priv(mmc); - if (host->flags & SDHCI_DEVICE_DEAD) { - spin_unlock_irqrestore(&host->lock, flags); - if (host->vmmc && ios->power_mode == MMC_POWER_OFF) - mmc_regulator_set_ocr(host->mmc, host->vmmc, 0); - return; + /* + * Controller registers should not be updated without the + * controller clock enabled. Set the minimum controller + * clock if there is no clock. + */ + if (host->ops->set_clock) { + if (!host->clock && !ios->clock) { + host->ops->set_clock(host, host->mmc->f_min); + host->clock = host->mmc->f_min; + } else if (ios->clock && (ios->clock != host->clock)) { + host->ops->set_clock(host, ios->clock); + } } + spin_lock_irqsave(&host->lock, flags); + + if (host->flags & SDHCI_DEVICE_DEAD) + goto out; + /* * Reset the chip on each power off. * Should clear out any weird states. @@ -1364,18 +1307,12 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) sdhci_reinit(host); } - sdhci_set_clock(host, ios->clock); - if (ios->power_mode == MMC_POWER_OFF) - vdd_bit = sdhci_set_power(host, -1); + sdhci_set_power(host, -1); else - vdd_bit = sdhci_set_power(host, ios->vdd); + sdhci_set_power(host, ios->vdd); - if (host->vmmc && vdd_bit != -1) { - spin_unlock_irqrestore(&host->lock, flags); - mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit); - spin_lock_irqsave(&host->lock, flags); - } + sdhci_set_clock(host, ios->clock); if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks(host, ios->power_mode); @@ -1418,11 +1355,12 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) unsigned int clock; /* In case of UHS-I modes, set High Speed Enable */ - if ((ios->timing == MMC_TIMING_MMC_HS200) || - (ios->timing == MMC_TIMING_UHS_SDR50) || + if (((ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR104) || (ios->timing == MMC_TIMING_UHS_DDR50) || - (ios->timing == MMC_TIMING_UHS_SDR25)) + (ios->timing == MMC_TIMING_UHS_SDR25) || + (ios->timing == MMC_TIMING_UHS_SDR12)) + && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) ctrl |= SDHCI_CTRL_HISPD; ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); @@ -1455,9 +1393,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); /* Re-enable SD Clock */ - clock = host->clock; - host->clock = 0; - sdhci_set_clock(host, clock); + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); } @@ -1472,9 +1410,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; - if (ios->timing == MMC_TIMING_MMC_HS200) - ctrl_2 |= SDHCI_CTRL_HS_SDR200; - else if (ios->timing == MMC_TIMING_UHS_SDR12) + if (ios->timing == MMC_TIMING_UHS_SDR12) ctrl_2 |= SDHCI_CTRL_UHS_SDR12; else if (ios->timing == MMC_TIMING_UHS_SDR25) ctrl_2 |= SDHCI_CTRL_UHS_SDR25; @@ -1488,9 +1424,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) } /* Re-enable SD Clock */ - clock = host->clock; - host->clock = 0; - sdhci_set_clock(host, clock); + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); } else sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); @@ -1502,20 +1438,18 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); +out: mmiowb(); spin_unlock_irqrestore(&host->lock, flags); + /* + * Controller clock should only be disabled after all the register + * writes are done. + */ + if (!ios->clock && host->ops->set_clock) + host->ops->set_clock(host, ios->clock); } -static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct sdhci_host *host = mmc_priv(mmc); - - sdhci_runtime_pm_get(host); - sdhci_do_set_ios(host, ios); - sdhci_runtime_pm_put(host); -} - -static int sdhci_check_ro(struct sdhci_host *host) +static int check_ro(struct sdhci_host *host) { unsigned long flags; int is_readonly; @@ -1539,16 +1473,19 @@ static int sdhci_check_ro(struct sdhci_host *host) #define SAMPLE_COUNT 5 -static int sdhci_do_get_ro(struct sdhci_host *host) +static int sdhci_get_ro(struct mmc_host *mmc) { + struct sdhci_host *host; int i, ro_count; + host = mmc_priv(mmc); + if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT)) - return sdhci_check_ro(host); + return check_ro(host); ro_count = 0; for (i = 0; i < SAMPLE_COUNT; i++) { - if (sdhci_check_ro(host)) { + if (check_ro(host)) { if (++ro_count > SAMPLE_COUNT / 2) return 1; } @@ -1557,125 +1494,96 @@ static int sdhci_do_get_ro(struct sdhci_host *host) return 0; } -static void sdhci_hw_reset(struct mmc_host *mmc) +static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) { - struct sdhci_host *host = mmc_priv(mmc); - - if (host->ops && host->ops->hw_reset) - host->ops->hw_reset(host); -} + struct sdhci_host *host; + unsigned long flags; -static int sdhci_get_ro(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - int ret; + host = mmc_priv(mmc); - sdhci_runtime_pm_get(host); - ret = sdhci_do_get_ro(host); - sdhci_runtime_pm_put(host); - return ret; -} + spin_lock_irqsave(&host->lock, flags); -static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) -{ if (host->flags & SDHCI_DEVICE_DEAD) goto out; - if (enable) - host->flags |= SDHCI_SDIO_IRQ_ENABLED; - else - host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; - - /* SDIO IRQ will be enabled as appropriate in runtime resume */ - if (host->runtime_suspended) - goto out; - if (enable) sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT); else sdhci_mask_irqs(host, SDHCI_INT_CARD_INT); out: mmiowb(); -} -static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct sdhci_host *host = mmc_priv(mmc); - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - sdhci_enable_sdio_irq_nolock(host, enable); spin_unlock_irqrestore(&host->lock, flags); } -static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host, - u16 ctrl) +static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) { - int ret; - - /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ - ctrl &= ~SDHCI_CTRL_VDD_180; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + struct sdhci_host *host; + u8 pwr; + u16 clk, ctrl; + u32 present_state; - if (host->vqmmc) { - ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000); - if (ret) { - pr_warning("%s: Switching to 3.3V signalling voltage " - " failed\n", mmc_hostname(host->mmc)); - return -EIO; - } - } - /* Wait for 5ms */ - usleep_range(5000, 5500); + host = mmc_priv(mmc); - /* 3.3V regulator output should be stable within 5 ms */ - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (!(ctrl & SDHCI_CTRL_VDD_180)) + /* + * Signal Voltage Switching is only applicable for Host Controllers + * v3.00 and above. + */ + if (host->version < SDHCI_SPEC_300) return 0; - pr_warning("%s: 3.3V regulator output did not became stable\n", - mmc_hostname(host->mmc)); - - return -EIO; -} + if (host->quirks & SDHCI_QUIRK_NON_STD_VOLTAGE_SWITCHING) { + if (host->ops->switch_signal_voltage) + return host->ops->switch_signal_voltage( + host, ios->signal_voltage); + } -static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host, - u16 ctrl) -{ - u8 pwr; - u16 clk; - u32 present_state; - int ret; + /* + * We first check whether the request is to set signalling voltage + * to 3.3V. If so, we change the voltage to 3.3V and return quickly. + */ + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ + ctrl &= ~SDHCI_CTRL_VDD_180; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - /* Stop SDCLK */ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - clk &= ~SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + /* Wait for 5ms */ + usleep_range(5000, 5500); - /* Check whether DAT[3:0] is 0000 */ - present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); - if (!((present_state & SDHCI_DATA_LVL_MASK) >> - SDHCI_DATA_LVL_SHIFT)) { - /* - * Enable 1.8V Signal Enable in the Host Control2 - * register - */ - if (host->vqmmc) - ret = regulator_set_voltage(host->vqmmc, - 1700000, 1950000); - else - ret = 0; + /* 3.3V regulator output should be stable within 5 ms */ + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (!(ctrl & SDHCI_CTRL_VDD_180)) + return 0; + else { + printk(KERN_INFO DRIVER_NAME ": Switching to 3.3V " + "signalling voltage failed\n"); + return -EIO; + } + } else if (!(ctrl & SDHCI_CTRL_VDD_180) && + (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) { + /* Stop SDCLK */ + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - if (!ret) { + /* Check whether DAT[3:0] is 0000 */ + present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); + if (!((present_state & SDHCI_DATA_LVL_MASK) >> + SDHCI_DATA_LVL_SHIFT)) { + /* + * Enable 1.8V Signal Enable in the Host Control2 + * register + */ ctrl |= SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); /* Wait for 5ms */ usleep_range(5000, 5500); - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); if (ctrl & SDHCI_CTRL_VDD_180) { - /* Provide SDCLK again and wait for 1ms */ + /* Provide SDCLK again and wait for 1ms*/ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); clk |= SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); @@ -1692,74 +1600,30 @@ static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host, return 0; } } - } - - /* - * If we are here, that means the switch to 1.8V signaling - * failed. We power cycle the card, and retry initialization - * sequence by setting S18R to 0. - */ - pwr = sdhci_readb(host, SDHCI_POWER_CONTROL); - pwr &= ~SDHCI_POWER_ON; - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - if (host->vmmc) - regulator_disable(host->vmmc); - - /* Wait for 1ms as per the spec */ - usleep_range(1000, 1500); - pwr |= SDHCI_POWER_ON; - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - if (host->vmmc) - regulator_enable(host->vmmc); - - pr_warning("%s: Switching to 1.8V signalling voltage failed, " - "retrying with S18R set to 0\n", mmc_hostname(host->mmc)); - return -EAGAIN; -} - -static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, - struct mmc_ios *ios) -{ - u16 ctrl; + /* + * If we are here, that means the switch to 1.8V signaling + * failed. We power cycle the card, and retry initialization + * sequence by setting S18R to 0. + */ + pwr = sdhci_readb(host, SDHCI_POWER_CONTROL); + pwr &= ~SDHCI_POWER_ON; + sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - /* - * Signal Voltage Switching is only applicable for Host Controllers - * v3.00 and above. - */ - if (host->version < SDHCI_SPEC_300) - return 0; + /* Wait for 1ms as per the spec */ + usleep_range(1000, 1500); + pwr |= SDHCI_POWER_ON; + sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - /* - * We first check whether the request is to set signalling voltage - * to 3.3V. If so, we change the voltage to 3.3V and return quickly. - */ - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) - return sdhci_do_3_3v_signal_voltage_switch(host, ctrl); - else if (!(ctrl & SDHCI_CTRL_VDD_180) && - (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) - return sdhci_do_1_8v_signal_voltage_switch(host, ctrl); - else + printk(KERN_INFO DRIVER_NAME ": Switching to 1.8V signalling " + "voltage failed, retrying with S18R set to 0\n"); + return -EAGAIN; + } else /* No signal voltage switch required */ return 0; } -static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, - struct mmc_ios *ios) -{ - struct sdhci_host *host = mmc_priv(mmc); - int err; - - if (host->version < SDHCI_SPEC_300) - return 0; - sdhci_runtime_pm_get(host); - err = sdhci_do_start_signal_voltage_switch(host, ios); - sdhci_runtime_pm_put(host); - return err; -} - -static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) +static int sdhci_execute_tuning(struct mmc_host *mmc) { struct sdhci_host *host; u16 ctrl; @@ -1767,35 +1631,34 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) int tuning_loop_counter = MAX_TUNING_LOOP; unsigned long timeout; int err = 0; - bool requires_tuning_nonuhs = false; host = mmc_priv(mmc); - sdhci_runtime_pm_get(host); disable_irq(host->irq); spin_lock(&host->lock); + if ((host->quirks & SDHCI_QUIRK_NON_STANDARD_TUNING) && + host->ops->execute_freq_tuning) { + err = host->ops->execute_freq_tuning(host); + spin_unlock(&host->lock); + enable_irq(host->irq); + return err; + } + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* - * The Host Controller needs tuning only in case of SDR104 mode - * and for SDR50 mode when Use Tuning for SDR50 is set in the + * Host Controller needs tuning only in case of SDR104 mode + * and for SDR50 mode when Use Tuning for SDR50 is set in * Capabilities register. - * If the Host Controller supports the HS200 mode then the - * tuning function has to be executed. */ - if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && - (host->flags & SDHCI_SDR50_NEEDS_TUNING || - host->flags & SDHCI_HS200_NEEDS_TUNING)) - requires_tuning_nonuhs = true; - if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) || - requires_tuning_nonuhs) + (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && + (host->flags & SDHCI_SDR50_NEEDS_TUNING))) ctrl |= SDHCI_CTRL_EXEC_TUNING; else { spin_unlock(&host->lock); enable_irq(host->irq); - sdhci_runtime_pm_put(host); return 0; } @@ -1821,12 +1684,12 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) timeout = 150; do { struct mmc_command cmd = {0}; - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {0}; if (!tuning_loop_counter && !timeout) break; - cmd.opcode = opcode; + cmd.opcode = MMC_SEND_TUNING_BLOCK; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.retries = 0; @@ -1841,17 +1704,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) * block to the Host Controller. So we set the block size * to 64 here. */ - if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) { - if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), - SDHCI_BLOCK_SIZE); - else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), - SDHCI_BLOCK_SIZE); - } else { - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), - SDHCI_BLOCK_SIZE); - } + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE); /* * The tuning block is sent by the card to the host controller. @@ -1877,7 +1730,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) spin_lock(&host->lock); if (!host->tuning_done) { - pr_info(DRIVER_NAME ": Timeout waiting for " + printk(KERN_INFO DRIVER_NAME ": Timeout waiting for " "Buffer Read Ready interrupt during tuning " "procedure, falling back to fixed sampling " "clock\n"); @@ -1907,7 +1760,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); } else { if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { - pr_info(DRIVER_NAME ": Tuning procedure" + printk(KERN_INFO DRIVER_NAME ": Tuning procedure" " failed, falling back to fixed sampling" " clock\n"); err = -EIO; @@ -1923,7 +1776,6 @@ out: */ if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count && (host->tuning_mode == SDHCI_TUNING_MODE_1)) { - host->flags |= SDHCI_USING_RETUNING_TIMER; mod_timer(&host->tuning_timer, jiffies + host->tuning_count * HZ); /* Tuning mode 1 limits the maximum data length to 4MB */ @@ -1941,29 +1793,41 @@ out: * try tuning again at a later time, when the re-tuning timer expires. * So for these controllers, we return 0. Since there might be other * controllers who do not have this capability, we return error for - * them. SDHCI_USING_RETUNING_TIMER means the host is currently using - * a retuning timer to do the retuning for the card. + * them. */ - if (err && (host->flags & SDHCI_USING_RETUNING_TIMER)) + if (err && host->tuning_count && + host->tuning_mode == SDHCI_TUNING_MODE_1) err = 0; sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); spin_unlock(&host->lock); enable_irq(host->irq); - sdhci_runtime_pm_put(host); return err; } -static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable) +static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) { + struct sdhci_host *host; u16 ctrl; unsigned long flags; + host = mmc_priv(mmc); + /* Host Controller v3.00 defines preset value registers */ if (host->version < SDHCI_SPEC_300) return; + /* + * Enabling preset value would make programming clock + * divider ineffective. The controller would use the + * values present in the preset value registers. In + * case of non-standard clock, let the platform driver + * decide whether to enable preset or not. + */ + if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) + return; + spin_lock_irqsave(&host->lock, flags); ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); @@ -1975,60 +1839,54 @@ static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable) if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - host->flags |= SDHCI_PV_ENABLED; } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - host->flags &= ~SDHCI_PV_ENABLED; } spin_unlock_irqrestore(&host->lock, flags); } -static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) +int sdhci_enable(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); - sdhci_runtime_pm_get(host); - sdhci_do_enable_preset_value(host, enable); - sdhci_runtime_pm_put(host); + if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO) + return 0; + + if (mmc->ios.clock) { + if (host->ops->set_clock) + host->ops->set_clock(host, mmc->ios.clock); + sdhci_set_clock(host, mmc->ios.clock); + } + + return 0; } -static void sdhci_card_event(struct mmc_host *mmc) +int sdhci_disable(struct mmc_host *mmc, int lazy) { struct sdhci_host *host = mmc_priv(mmc); - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - /* Check host->mrq first in case we are runtime suspended */ - if (host->mrq && - !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { - pr_err("%s: Card removed during transfer!\n", - mmc_hostname(host->mmc)); - pr_err("%s: Resetting controller.\n", - mmc_hostname(host->mmc)); - - sdhci_reset(host, SDHCI_RESET_CMD); - sdhci_reset(host, SDHCI_RESET_DATA); + if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO) + return 0; - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); - } + sdhci_set_clock(host, 0); + if (host->ops->set_clock) + host->ops->set_clock(host, 0); - spin_unlock_irqrestore(&host->lock, flags); + return 0; } static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, .get_ro = sdhci_get_ro, - .hw_reset = sdhci_hw_reset, + .enable = sdhci_enable, + .disable = sdhci_disable, .enable_sdio_irq = sdhci_enable_sdio_irq, .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, .execute_tuning = sdhci_execute_tuning, .enable_preset_value = sdhci_enable_preset_value, - .card_event = sdhci_card_event, }; /*****************************************************************************\ @@ -2039,9 +1897,29 @@ static const struct mmc_host_ops sdhci_ops = { static void sdhci_tasklet_card(unsigned long param) { - struct sdhci_host *host = (struct sdhci_host*)param; + struct sdhci_host *host; + unsigned long flags; + + host = (struct sdhci_host*)param; + + spin_lock_irqsave(&host->lock, flags); + + if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { + if (host->mrq) { + printk(KERN_ERR "%s: Card removed during transfer!\n", + mmc_hostname(host->mmc)); + printk(KERN_ERR "%s: Resetting controller.\n", + mmc_hostname(host->mmc)); - sdhci_card_event(host->mmc); + sdhci_reset(host, SDHCI_RESET_CMD); + sdhci_reset(host, SDHCI_RESET_DATA); + + host->mrq->cmd->error = -ENOMEDIUM; + tasklet_schedule(&host->finish_tasklet); + } + } + + spin_unlock_irqrestore(&host->lock, flags); mmc_detect_change(host->mmc, msecs_to_jiffies(200)); } @@ -2054,16 +1932,14 @@ static void sdhci_tasklet_finish(unsigned long param) host = (struct sdhci_host*)param; - spin_lock_irqsave(&host->lock, flags); - /* * If this tasklet gets rescheduled while running, it will * be run again afterwards but without any active request. */ - if (!host->mrq) { - spin_unlock_irqrestore(&host->lock, flags); + if (!host->mrq) return; - } + + spin_lock_irqsave(&host->lock, flags); del_timer(&host->timer); @@ -2086,6 +1962,8 @@ static void sdhci_tasklet_finish(unsigned long param) /* This is to force an update */ clock = host->clock; host->clock = 0; + if (host->ops->set_clock) + host->ops->set_clock(host, clock); sdhci_set_clock(host, clock); } @@ -2107,7 +1985,6 @@ static void sdhci_tasklet_finish(unsigned long param) spin_unlock_irqrestore(&host->lock, flags); mmc_request_done(host->mmc, mrq); - sdhci_runtime_pm_put(host); } static void sdhci_timeout_timer(unsigned long data) @@ -2120,7 +1997,7 @@ static void sdhci_timeout_timer(unsigned long data) spin_lock_irqsave(&host->lock, flags); if (host->mrq) { - pr_err("%s: Timeout waiting for hardware " + printk(KERN_ERR "%s: Timeout waiting for hardware " "interrupt.\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); @@ -2166,7 +2043,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) BUG_ON(intmask == 0); if (!host->cmd) { - pr_err("%s: Got command interrupt 0x%08x even " + printk(KERN_ERR "%s: Got command interrupt 0x%08x even " "though no command operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); @@ -2241,14 +2118,12 @@ static void sdhci_show_adma_error(struct sdhci_host *host) { } static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { - u32 command; BUG_ON(intmask == 0); /* CMD19 generates _only_ Buffer Read Ready interrupt */ if (intmask & SDHCI_INT_DATA_AVAIL) { - command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)); - if (command == MMC_SEND_TUNING_BLOCK || - command == MMC_SEND_TUNING_BLOCK_HS200) { + if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) == + MMC_SEND_TUNING_BLOCK) { host->tuning_done = 1; wake_up(&host->buf_ready_int); return; @@ -2268,7 +2143,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } } - pr_err("%s: Got data interrupt 0x%08x even " + printk(KERN_ERR "%s: Got data interrupt 0x%08x even " "though no data operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); @@ -2285,11 +2160,9 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) != MMC_BUS_TEST_R) host->data->error = -EILSEQ; else if (intmask & SDHCI_INT_ADMA_ERROR) { - pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); + printk(KERN_ERR "%s: ADMA error\n", mmc_hostname(host->mmc)); sdhci_show_adma_error(host); host->data->error = -EIO; - if (host->ops->adma_workaround) - host->ops->adma_workaround(host, intmask); } if (host->data->error) @@ -2343,19 +2216,12 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) static irqreturn_t sdhci_irq(int irq, void *dev_id) { irqreturn_t result; - struct sdhci_host *host = dev_id; - u32 intmask, unexpected = 0; - int cardint = 0, max_loops = 16; + struct sdhci_host* host = dev_id; + u32 intmask; + int cardint = 0; spin_lock(&host->lock); - if (host->runtime_suspended) { - spin_unlock(&host->lock); - pr_warning("%s: got irq while runtime suspended\n", - mmc_hostname(host->mmc)); - return IRQ_HANDLED; - } - intmask = sdhci_readl(host, SDHCI_INT_STATUS); if (!intmask || intmask == 0xffffffff) { @@ -2363,7 +2229,6 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) goto out; } -again: DBG("*** %s got interrupt: 0x%08x\n", mmc_hostname(host->mmc), intmask); @@ -2409,7 +2274,7 @@ again: intmask &= ~SDHCI_INT_ERROR; if (intmask & SDHCI_INT_BUS_POWER) { - pr_err("%s: Card is consuming too much power!\n", + printk(KERN_ERR "%s: Card is consuming too much power!\n", mmc_hostname(host->mmc)); sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS); } @@ -2422,23 +2287,19 @@ again: intmask &= ~SDHCI_INT_CARD_INT; if (intmask) { - unexpected |= intmask; + printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", + mmc_hostname(host->mmc), intmask); + sdhci_dumpregs(host); + sdhci_writel(host, intmask, SDHCI_INT_STATUS); } result = IRQ_HANDLED; - intmask = sdhci_readl(host, SDHCI_INT_STATUS); - if (intmask && --max_loops) - goto again; + mmiowb(); out: spin_unlock(&host->lock); - if (unexpected) { - pr_err("%s: Unexpected interrupt 0x%08x.\n", - mmc_hostname(host->mmc), unexpected); - sdhci_dumpregs(host); - } /* * We have to delay this as it calls back into the driver. */ @@ -2456,35 +2317,35 @@ out: #ifdef CONFIG_PM -int sdhci_suspend_host(struct sdhci_host *host) +int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) { - int ret; - - if (host->ops->platform_suspend) - host->ops->platform_suspend(host); + int ret = 0; + struct mmc_host *mmc = host->mmc; sdhci_disable_card_detection(host); /* Disable tuning since we are suspending */ - if (host->flags & SDHCI_USING_RETUNING_TIMER) { - del_timer_sync(&host->tuning_timer); + if (host->version >= SDHCI_SPEC_300 && host->tuning_count && + host->tuning_mode == SDHCI_TUNING_MODE_1) { host->flags &= ~SDHCI_NEEDS_RETUNING; + mod_timer(&host->tuning_timer, jiffies + + host->tuning_count * HZ); } - ret = mmc_suspend_host(host->mmc); - if (ret) { - if (host->flags & SDHCI_USING_RETUNING_TIMER) { - host->flags |= SDHCI_NEEDS_RETUNING; - mod_timer(&host->tuning_timer, jiffies + - host->tuning_count * HZ); - } + if (mmc->card) + ret = mmc_suspend_host(host->mmc); - sdhci_enable_card_detection(host); + if (mmc->pm_flags & MMC_PM_KEEP_POWER) + host->card_int_set = sdhci_readl(host, SDHCI_INT_ENABLE) & + SDHCI_INT_CARD_INT; - return ret; - } + sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); - free_irq(host->irq, host); + if (host->vmmc) + ret = regulator_disable(host->vmmc); + + if (host->irq) + disable_irq(host->irq); return ret; } @@ -2493,38 +2354,41 @@ EXPORT_SYMBOL_GPL(sdhci_suspend_host); int sdhci_resume_host(struct sdhci_host *host) { - int ret; + int ret = 0; + struct mmc_host *mmc = host->mmc; + + if (host->vmmc) { + int ret = regulator_enable(host->vmmc); + if (ret) + return ret; + } + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) host->ops->enable_dma(host); } - ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, - mmc_hostname(host->mmc), host); - if (ret) - return ret; + if (host->irq) + enable_irq(host->irq); - if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) && - (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) { - /* Card keeps power but host controller does not */ - sdhci_init(host, 0); - host->pwr = 0; - host->clock = 0; - sdhci_do_set_ios(host, &host->mmc->ios); - } else { - sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); - mmiowb(); + sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); + mmiowb(); + + if (mmc->card) { + ret = mmc_resume_host(host->mmc); + /* Enable card interrupt as it is overwritten in sdhci_init */ + if ((mmc->caps & MMC_CAP_SDIO_IRQ) && + (mmc->pm_flags & MMC_PM_KEEP_POWER)) + if (host->card_int_set) + mmc->ops->enable_sdio_irq(mmc, true); } - ret = mmc_resume_host(host->mmc); sdhci_enable_card_detection(host); - if (host->ops->platform_resume) - host->ops->platform_resume(host); - /* Set the re-tuning expiration flag */ - if (host->flags & SDHCI_USING_RETUNING_TIMER) + if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && + (host->tuning_mode == SDHCI_TUNING_MODE_1)) host->flags |= SDHCI_NEEDS_RETUNING; return ret; @@ -2544,88 +2408,6 @@ EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); #endif /* CONFIG_PM */ -#ifdef CONFIG_PM_RUNTIME - -static int sdhci_runtime_pm_get(struct sdhci_host *host) -{ - return pm_runtime_get_sync(host->mmc->parent); -} - -static int sdhci_runtime_pm_put(struct sdhci_host *host) -{ - pm_runtime_mark_last_busy(host->mmc->parent); - return pm_runtime_put_autosuspend(host->mmc->parent); -} - -int sdhci_runtime_suspend_host(struct sdhci_host *host) -{ - unsigned long flags; - int ret = 0; - - /* Disable tuning since we are suspending */ - if (host->flags & SDHCI_USING_RETUNING_TIMER) { - del_timer_sync(&host->tuning_timer); - host->flags &= ~SDHCI_NEEDS_RETUNING; - } - - spin_lock_irqsave(&host->lock, flags); - sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); - spin_unlock_irqrestore(&host->lock, flags); - - synchronize_irq(host->irq); - - spin_lock_irqsave(&host->lock, flags); - host->runtime_suspended = true; - spin_unlock_irqrestore(&host->lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host); - -int sdhci_runtime_resume_host(struct sdhci_host *host) -{ - unsigned long flags; - int ret = 0, host_flags = host->flags; - - if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { - if (host->ops->enable_dma) - host->ops->enable_dma(host); - } - - sdhci_init(host, 0); - - /* Force clock and power re-program */ - host->pwr = 0; - host->clock = 0; - sdhci_do_set_ios(host, &host->mmc->ios); - - sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); - if (host_flags & SDHCI_PV_ENABLED) - sdhci_do_enable_preset_value(host, true); - - /* Set the re-tuning expiration flag */ - if (host->flags & SDHCI_USING_RETUNING_TIMER) - host->flags |= SDHCI_NEEDS_RETUNING; - - spin_lock_irqsave(&host->lock, flags); - - host->runtime_suspended = false; - - /* Enable SDIO IRQ */ - if ((host->flags & SDHCI_SDIO_IRQ_ENABLED)) - sdhci_enable_sdio_irq_nolock(host, true); - - /* Enable Card Detection */ - sdhci_enable_card_detection(host); - - spin_unlock_irqrestore(&host->lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host); - -#endif - /*****************************************************************************\ * * * Device allocation/registration * @@ -2655,7 +2437,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host); int sdhci_add_host(struct sdhci_host *host) { struct mmc_host *mmc; - u32 caps[2] = {0, 0}; + u32 caps[2]; u32 max_current_caps; unsigned int ocr_avail; int ret; @@ -2668,8 +2450,6 @@ int sdhci_add_host(struct sdhci_host *host) if (debug_quirks) host->quirks = debug_quirks; - if (debug_quirks2) - host->quirks2 = debug_quirks2; sdhci_reset(host, SDHCI_RESET_ALL); @@ -2677,7 +2457,7 @@ int sdhci_add_host(struct sdhci_host *host) host->version = (host->version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; if (host->version > SDHCI_SPEC_300) { - pr_err("%s: Unknown controller version (%d). " + printk(KERN_ERR "%s: Unknown controller version (%d). " "You may experience problems.\n", mmc_hostname(mmc), host->version); } @@ -2685,10 +2465,8 @@ int sdhci_add_host(struct sdhci_host *host) caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps : sdhci_readl(host, SDHCI_CAPABILITIES); - if (host->version >= SDHCI_SPEC_300) - caps[1] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? - host->caps1 : - sdhci_readl(host, SDHCI_CAPABILITIES_1); + caps[1] = (host->version >= SDHCI_SPEC_300) ? + sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0; if (host->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_SDMA; @@ -2716,7 +2494,7 @@ int sdhci_add_host(struct sdhci_host *host) if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) { if (host->ops->enable_dma(host)) { - pr_warning("%s: No suitable DMA " + printk(KERN_WARNING "%s: No suitable DMA " "available. Falling back to PIO.\n", mmc_hostname(mmc)); host->flags &= @@ -2736,7 +2514,7 @@ int sdhci_add_host(struct sdhci_host *host) if (!host->adma_desc || !host->align_buffer) { kfree(host->adma_desc); kfree(host->align_buffer); - pr_warning("%s: Unable to allocate ADMA " + printk(KERN_WARNING "%s: Unable to allocate ADMA " "buffers. Falling back to standard DMA.\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; @@ -2764,7 +2542,8 @@ int sdhci_add_host(struct sdhci_host *host) if (host->max_clk == 0 || host->quirks & SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) { if (!host->ops->get_max_clock) { - pr_err("%s: Hardware doesn't specify base clock " + printk(KERN_ERR + "%s: Hardware doesn't specify base clock " "frequency.\n", mmc_hostname(mmc)); return -ENODEV; } @@ -2810,7 +2589,8 @@ int sdhci_add_host(struct sdhci_host *host) host->timeout_clk = host->ops->get_timeout_clock(host); } else if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) { - pr_err("%s: Hardware doesn't specify timeout clock " + printk(KERN_ERR + "%s: Hardware doesn't specify timeout clock " "frequency.\n", mmc_hostname(mmc)); return -ENODEV; } @@ -2821,9 +2601,8 @@ int sdhci_add_host(struct sdhci_host *host) if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) host->timeout_clk = mmc->f_max / 1000; - mmc->max_discard_to = (1 << 27) / host->timeout_clk; - - mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; + if (!(host->quirks & SDHCI_QUIRK_NO_CALC_MAX_DISCARD_TO)) + mmc->max_discard_to = (1 << 27) / host->timeout_clk; if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) host->flags |= SDHCI_AUTO_CMD12; @@ -2848,40 +2627,15 @@ int sdhci_add_host(struct sdhci_host *host) if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) mmc->caps |= MMC_CAP_4_BIT_DATA; - if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23) - mmc->caps &= ~MMC_CAP_CMD23; - if (caps[0] & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && - !(host->mmc->caps & MMC_CAP_NONREMOVABLE)) + mmc_card_is_removable(mmc) && !(host->ops->get_cd)) mmc->caps |= MMC_CAP_NEEDS_POLL; - /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ - host->vqmmc = regulator_get(mmc_dev(mmc), "vqmmc"); - if (IS_ERR_OR_NULL(host->vqmmc)) { - if (PTR_ERR(host->vqmmc) < 0) { - pr_info("%s: no vqmmc regulator found\n", - mmc_hostname(mmc)); - host->vqmmc = NULL; - } - } else { - regulator_enable(host->vqmmc); - if (!regulator_is_supported_voltage(host->vqmmc, 1700000, - 1950000)) - caps[1] &= ~(SDHCI_SUPPORT_SDR104 | - SDHCI_SUPPORT_SDR50 | - SDHCI_SUPPORT_DDR50); - } - - if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) - caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | - SDHCI_SUPPORT_DDR50); - - /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ - if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | - SDHCI_SUPPORT_DDR50)) + /* UHS-I mode(s) supported by the host controller. */ + if (host->version >= SDHCI_SPEC_300) mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; /* SDR104 supports also implies SDR50 support */ @@ -2893,14 +2647,10 @@ int sdhci_add_host(struct sdhci_host *host) if (caps[1] & SDHCI_SUPPORT_DDR50) mmc->caps |= MMC_CAP_UHS_DDR50; - /* Does the host need tuning for SDR50? */ + /* Does the host needs tuning for SDR50? */ if (caps[1] & SDHCI_USE_SDR50_TUNING) host->flags |= SDHCI_SDR50_NEEDS_TUNING; - /* Does the host need tuning for HS200? */ - if (mmc->caps2 & MMC_CAP2_HS200) - host->flags |= SDHCI_HS200_NEEDS_TUNING; - /* Driver Type(s) (A, C, D) supported by the host */ if (caps[1] & SDHCI_DRIVER_TYPE_A) mmc->caps |= MMC_CAP_DRIVER_TYPE_A; @@ -2925,31 +2675,6 @@ int sdhci_add_host(struct sdhci_host *host) SDHCI_RETUNING_MODE_SHIFT; ocr_avail = 0; - - host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); - if (IS_ERR_OR_NULL(host->vmmc)) { - if (PTR_ERR(host->vmmc) < 0) { - pr_info("%s: no vmmc regulator found\n", - mmc_hostname(mmc)); - host->vmmc = NULL; - } - } - -#ifdef CONFIG_REGULATOR - if (host->vmmc) { - ret = regulator_is_supported_voltage(host->vmmc, 2700000, - 3600000); - if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330))) - caps[0] &= ~SDHCI_CAN_VDD_330; - if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300))) - caps[0] &= ~SDHCI_CAN_VDD_300; - ret = regulator_is_supported_voltage(host->vmmc, 1700000, - 1950000); - if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180))) - caps[0] &= ~SDHCI_CAN_VDD_180; - } -#endif /* CONFIG_REGULATOR */ - /* * According to SD Host Controller spec v3.00, if the Host System * can afford more than 150mA, Host Driver should set XPC to 1. Also @@ -2958,45 +2683,55 @@ int sdhci_add_host(struct sdhci_host *host) * value. */ max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT); - if (!max_current_caps && host->vmmc) { - u32 curr = regulator_get_current_limit(host->vmmc); - if (curr > 0) { - - /* convert to SDHCI_MAX_CURRENT format */ - curr = curr/1000; /* convert to mA */ - curr = curr/SDHCI_MAX_CURRENT_MULTIPLIER; - - curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT); - max_current_caps = - (curr << SDHCI_MAX_CURRENT_330_SHIFT) | - (curr << SDHCI_MAX_CURRENT_300_SHIFT) | - (curr << SDHCI_MAX_CURRENT_180_SHIFT); - } - } if (caps[0] & SDHCI_CAN_VDD_330) { + int max_current_330; + ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->max_current_330 = ((max_current_caps & + max_current_330 = ((max_current_caps & SDHCI_MAX_CURRENT_330_MASK) >> SDHCI_MAX_CURRENT_330_SHIFT) * SDHCI_MAX_CURRENT_MULTIPLIER; + + if (max_current_330 > 150) + mmc->caps |= MMC_CAP_SET_XPC_330; } if (caps[0] & SDHCI_CAN_VDD_300) { + int max_current_300; + ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31; - mmc->max_current_300 = ((max_current_caps & + max_current_300 = ((max_current_caps & SDHCI_MAX_CURRENT_300_MASK) >> SDHCI_MAX_CURRENT_300_SHIFT) * SDHCI_MAX_CURRENT_MULTIPLIER; + + if (max_current_300 > 150) + mmc->caps |= MMC_CAP_SET_XPC_300; } if (caps[0] & SDHCI_CAN_VDD_180) { + int max_current_180; + ocr_avail |= MMC_VDD_165_195; - mmc->max_current_180 = ((max_current_caps & + max_current_180 = ((max_current_caps & SDHCI_MAX_CURRENT_180_MASK) >> SDHCI_MAX_CURRENT_180_SHIFT) * SDHCI_MAX_CURRENT_MULTIPLIER; + + if (max_current_180 > 150) + mmc->caps |= MMC_CAP_SET_XPC_180; + + /* Maximum current capabilities of the host at 1.8V */ + if (max_current_180 >= 800) + mmc->caps |= MMC_CAP_MAX_CURRENT_800; + else if (max_current_180 >= 600) + mmc->caps |= MMC_CAP_MAX_CURRENT_600; + else if (max_current_180 >= 400) + mmc->caps |= MMC_CAP_MAX_CURRENT_400; + else + mmc->caps |= MMC_CAP_MAX_CURRENT_200; } mmc->ocr_avail = ocr_avail; @@ -3013,7 +2748,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->ocr_avail_mmc &= host->ocr_avail_mmc; if (mmc->ocr_avail == 0) { - pr_err("%s: Hardware doesn't report any " + printk(KERN_ERR "%s: Hardware doesn't report any " "support voltages.\n", mmc_hostname(mmc)); return -ENODEV; } @@ -3061,7 +2796,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; if (mmc->max_blk_size >= 3) { - pr_warning("%s: Invalid maximum block size, " + printk(KERN_WARNING "%s: Invalid maximum block size, " "assuming 512 bytes\n", mmc_hostname(mmc)); mmc->max_blk_size = 0; } @@ -3095,10 +2830,15 @@ int sdhci_add_host(struct sdhci_host *host) ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, mmc_hostname(mmc), host); - if (ret) { - pr_err("%s: Failed to request IRQ %d: %d\n", - mmc_hostname(mmc), host->irq, ret); + if (ret) goto untasklet; + + host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); + if (IS_ERR(host->vmmc)) { + printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); + host->vmmc = NULL; + } else { + regulator_enable(host->vmmc); } sdhci_init(host, 0); @@ -3116,18 +2856,15 @@ int sdhci_add_host(struct sdhci_host *host) host->led.brightness_set = sdhci_led_control; ret = led_classdev_register(mmc_dev(mmc), &host->led); - if (ret) { - pr_err("%s: Failed to register LED device: %d\n", - mmc_hostname(mmc), ret); + if (ret) goto reset; - } #endif mmiowb(); mmc_add_host(mmc); - pr_info("%s: SDHCI controller on %s [%s] using %s\n", + printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s\n", mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), (host->flags & SDHCI_USE_ADMA) ? "ADMA" : (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); @@ -3160,7 +2897,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) host->flags |= SDHCI_DEVICE_DEAD; if (host->mrq) { - pr_err("%s: Controller removed during " + printk(KERN_ERR "%s: Controller removed during " " transfer!\n", mmc_hostname(host->mmc)); host->mrq->cmd->error = -ENOMEDIUM; @@ -3184,6 +2921,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) free_irq(host->irq, host); del_timer_sync(&host->timer); + if (host->version >= SDHCI_SPEC_300) + del_timer_sync(&host->tuning_timer); tasklet_kill(&host->card_tasklet); tasklet_kill(&host->finish_tasklet); @@ -3193,11 +2932,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) regulator_put(host->vmmc); } - if (host->vqmmc) { - regulator_disable(host->vqmmc); - regulator_put(host->vqmmc); - } - kfree(host->adma_desc); kfree(host->align_buffer); @@ -3222,9 +2956,9 @@ EXPORT_SYMBOL_GPL(sdhci_free_host); static int __init sdhci_drv_init(void) { - pr_info(DRIVER_NAME + printk(KERN_INFO DRIVER_NAME ": Secure Digital Host Controller Interface driver\n"); - pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); + printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); return 0; } @@ -3237,11 +2971,9 @@ module_init(sdhci_drv_init); module_exit(sdhci_drv_exit); module_param(debug_quirks, uint, 0444); -module_param(debug_quirks2, uint, 0444); MODULE_AUTHOR("Pierre Ossman "); MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); MODULE_LICENSE("GPL"); MODULE_PARM_DESC(debug_quirks, "Force certain quirks."); -MODULE_PARM_DESC(debug_quirks2, "Force certain other quirks."); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index a6d69b7bdea..c00833de19d 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -120,7 +120,6 @@ #define SDHCI_SIGNAL_ENABLE 0x38 #define SDHCI_INT_RESPONSE 0x00000001 #define SDHCI_INT_DATA_END 0x00000002 -#define SDHCI_INT_BLK_GAP 0x00000004 #define SDHCI_INT_DMA_END 0x00000008 #define SDHCI_INT_SPACE_AVAIL 0x00000010 #define SDHCI_INT_DATA_AVAIL 0x00000020 @@ -147,8 +146,7 @@ #define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ - SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \ - SDHCI_INT_BLK_GAP) + SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR) #define SDHCI_INT_ALL_MASK ((unsigned int)-1) #define SDHCI_ACMD12_ERR 0x3C @@ -160,7 +158,6 @@ #define SDHCI_CTRL_UHS_SDR50 0x0002 #define SDHCI_CTRL_UHS_SDR104 0x0003 #define SDHCI_CTRL_UHS_DDR50 0x0004 -#define SDHCI_CTRL_HS_SDR200 0x0005 /* reserved value in SDIO spec */ #define SDHCI_CTRL_VDD_180 0x0008 #define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 #define SDHCI_CTRL_DRV_TYPE_B 0x0000 @@ -207,7 +204,6 @@ #define SDHCI_CAPABILITIES_1 0x44 #define SDHCI_MAX_CURRENT 0x48 -#define SDHCI_MAX_CURRENT_LIMIT 0xFF #define SDHCI_MAX_CURRENT_330_MASK 0x0000FF #define SDHCI_MAX_CURRENT_330_SHIFT 0 #define SDHCI_MAX_CURRENT_300_MASK 0x00FF00 @@ -274,14 +270,15 @@ struct sdhci_ops { void (*platform_send_init_74_clocks)(struct sdhci_host *host, u8 power_mode); unsigned int (*get_ro)(struct sdhci_host *host); + unsigned int (*get_cd)(struct sdhci_host *host); void (*platform_reset_enter)(struct sdhci_host *host, u8 mask); void (*platform_reset_exit)(struct sdhci_host *host, u8 mask); int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); - void (*hw_reset)(struct sdhci_host *host); - void (*platform_suspend)(struct sdhci_host *host); - void (*platform_resume)(struct sdhci_host *host); - void (*adma_workaround)(struct sdhci_host *host, u32 intmask); - void (*platform_init)(struct sdhci_host *host); + int (*suspend)(struct sdhci_host *host, pm_message_t state); + int (*resume)(struct sdhci_host *host); + int (*switch_signal_voltage)(struct sdhci_host *host, + unsigned int signal_voltage); + int (*execute_freq_tuning)(struct sdhci_host *sdhci); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS @@ -382,14 +379,9 @@ extern int sdhci_add_host(struct sdhci_host *host); extern void sdhci_remove_host(struct sdhci_host *host, int dead); #ifdef CONFIG_PM -extern int sdhci_suspend_host(struct sdhci_host *host); +extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state); extern int sdhci_resume_host(struct sdhci_host *host); extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); #endif -#ifdef CONFIG_PM_RUNTIME -extern int sdhci_runtime_suspend_host(struct sdhci_host *host); -extern int sdhci_runtime_resume_host(struct sdhci_host *host); -#endif - #endif /* __SDHCI_HW_H */ diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 7009f17ad6c..496b7efbc6b 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -26,7 +26,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 9a4c151067d..557886bee9c 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -16,33 +16,6 @@ * */ -/* - * The MMCIF driver is now processing MMC requests asynchronously, according - * to the Linux MMC API requirement. - * - * The MMCIF driver processes MMC requests in up to 3 stages: command, optional - * data, and optional stop. To achieve asynchronous processing each of these - * stages is split into two halves: a top and a bottom half. The top half - * initialises the hardware, installs a timeout handler to handle completion - * timeouts, and returns. In case of the command stage this immediately returns - * control to the caller, leaving all further processing to run asynchronously. - * All further request processing is performed by the bottom halves. - * - * The bottom half further consists of a "hard" IRQ handler, an IRQ handler - * thread, a DMA completion callback, if DMA is used, a timeout work, and - * request- and stage-specific handler methods. - * - * Each bottom half run begins with either a hardware interrupt, a DMA callback - * invocation, or a timeout work run. In case of an error or a successful - * processing completion, the MMC core is informed and the request processing is - * finished. In case processing has to continue, i.e., if data has to be read - * from or written to the card, or if a stop command has to be sent, the next - * top half is called, which performs the necessary hardware handling and - * reschedules the timeout work. This returns the driver state machine into the - * bottom half waiting state. - */ - -#include #include #include #include @@ -54,14 +27,10 @@ #include #include #include -#include -#include #include #include -#include #include #include -#include #define DRIVER_NAME "sh_mmcif" #define DRIVER_VERSION "2010-04-28" @@ -153,11 +122,6 @@ #define MASK_MRBSYTO (1 << 1) #define MASK_MRSPTO (1 << 0) -#define MASK_START_CMD (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \ - MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \ - MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | \ - MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO) - /* CE_HOST_STS1 */ #define STS1_CMDSEQ (1 << 31) @@ -197,37 +161,19 @@ enum mmcif_state { STATE_IOS, }; -enum mmcif_wait_for { - MMCIF_WAIT_FOR_REQUEST, - MMCIF_WAIT_FOR_CMD, - MMCIF_WAIT_FOR_MREAD, - MMCIF_WAIT_FOR_MWRITE, - MMCIF_WAIT_FOR_READ, - MMCIF_WAIT_FOR_WRITE, - MMCIF_WAIT_FOR_READ_END, - MMCIF_WAIT_FOR_WRITE_END, - MMCIF_WAIT_FOR_STOP, -}; - struct sh_mmcif_host { struct mmc_host *mmc; - struct mmc_request *mrq; + struct mmc_data *data; struct platform_device *pd; struct clk *hclk; unsigned int clk; int bus_width; bool sd_error; - bool dying; long timeout; void __iomem *addr; - u32 *pio_ptr; - spinlock_t lock; /* protect sh_mmcif_host::state */ + struct completion intr_wait; enum mmcif_state state; - enum mmcif_wait_for wait_for; - struct delayed_work timeout_work; - size_t blocksize; - int sg_idx; - int sg_blkidx; + spinlock_t lock; bool power; bool card_present; @@ -253,21 +199,19 @@ static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host, static void mmcif_dma_complete(void *arg) { struct sh_mmcif_host *host = arg; - struct mmc_data *data = host->mrq->data; - dev_dbg(&host->pd->dev, "Command completed\n"); - if (WARN(!data, "%s: NULL data in DMA completion!\n", + if (WARN(!host->data, "%s: NULL data in DMA completion!\n", dev_name(&host->pd->dev))) return; - if (data->flags & MMC_DATA_READ) + if (host->data->flags & MMC_DATA_READ) dma_unmap_sg(host->chan_rx->device->dev, - data->sg, data->sg_len, + host->data->sg, host->data->sg_len, DMA_FROM_DEVICE); else dma_unmap_sg(host->chan_tx->device->dev, - data->sg, data->sg_len, + host->data->sg, host->data->sg_len, DMA_TO_DEVICE); complete(&host->dma_complete); @@ -275,19 +219,18 @@ static void mmcif_dma_complete(void *arg) static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) { - struct mmc_data *data = host->mrq->data; - struct scatterlist *sg = data->sg; + struct scatterlist *sg = host->data->sg; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; dma_cookie_t cookie = -EINVAL; int ret; - ret = dma_map_sg(chan->device->dev, sg, data->sg_len, + ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len, DMA_FROM_DEVICE); if (ret > 0) { host->dma_active = true; - desc = dmaengine_prep_slave_sg(chan, sg, ret, - DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + desc = chan->device->device_prep_slave_sg(chan, sg, ret, + DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } if (desc) { @@ -298,7 +241,7 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) dma_async_issue_pending(chan); } dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", - __func__, data->sg_len, ret, cookie); + __func__, host->data->sg_len, ret, cookie); if (!desc) { /* DMA failed, fall back to PIO */ @@ -319,24 +262,23 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) } dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, - desc, cookie, data->sg_len); + desc, cookie, host->data->sg_len); } static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) { - struct mmc_data *data = host->mrq->data; - struct scatterlist *sg = data->sg; + struct scatterlist *sg = host->data->sg; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; dma_cookie_t cookie = -EINVAL; int ret; - ret = dma_map_sg(chan->device->dev, sg, data->sg_len, + ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len, DMA_TO_DEVICE); if (ret > 0) { host->dma_active = true; - desc = dmaengine_prep_slave_sg(chan, sg, ret, - DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + desc = chan->device->device_prep_slave_sg(chan, sg, ret, + DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } if (desc) { @@ -347,7 +289,7 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) dma_async_issue_pending(chan); } dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", - __func__, data->sg_len, ret, cookie); + __func__, host->data->sg_len, ret, cookie); if (!desc) { /* DMA failed, fall back to PIO */ @@ -371,69 +313,46 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) desc, cookie); } +static bool sh_mmcif_filter(struct dma_chan *chan, void *arg) +{ + dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg); + chan->private = arg; + return true; +} + static void sh_mmcif_request_dma(struct sh_mmcif_host *host, struct sh_mmcif_plat_data *pdata) { - struct resource *res = platform_get_resource(host->pd, IORESOURCE_MEM, 0); - struct dma_slave_config cfg; - dma_cap_mask_t mask; - int ret; - host->dma_active = false; - if (!pdata) - return; - - if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0) - return; - /* We can only either use DMA for both Tx and Rx or not use it at all */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + if (pdata->dma) { + dma_cap_mask_t mask; - host->chan_tx = dma_request_channel(mask, shdma_chan_filter, - (void *)pdata->slave_id_tx); - dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__, - host->chan_tx); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); - if (!host->chan_tx) - return; - - cfg.slave_id = pdata->slave_id_tx; - cfg.direction = DMA_MEM_TO_DEV; - cfg.dst_addr = res->start + MMCIF_CE_DATA; - cfg.src_addr = 0; - ret = dmaengine_slave_config(host->chan_tx, &cfg); - if (ret < 0) - goto ecfgtx; - - host->chan_rx = dma_request_channel(mask, shdma_chan_filter, - (void *)pdata->slave_id_rx); - dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__, - host->chan_rx); - - if (!host->chan_rx) - goto erqrx; + host->chan_tx = dma_request_channel(mask, sh_mmcif_filter, + &pdata->dma->chan_priv_tx); + dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__, + host->chan_tx); - cfg.slave_id = pdata->slave_id_rx; - cfg.direction = DMA_DEV_TO_MEM; - cfg.dst_addr = 0; - cfg.src_addr = res->start + MMCIF_CE_DATA; - ret = dmaengine_slave_config(host->chan_rx, &cfg); - if (ret < 0) - goto ecfgrx; + if (!host->chan_tx) + return; - init_completion(&host->dma_complete); + host->chan_rx = dma_request_channel(mask, sh_mmcif_filter, + &pdata->dma->chan_priv_rx); + dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__, + host->chan_rx); - return; + if (!host->chan_rx) { + dma_release_channel(host->chan_tx); + host->chan_tx = NULL; + return; + } -ecfgrx: - dma_release_channel(host->chan_rx); - host->chan_rx = NULL; -erqrx: -ecfgtx: - dma_release_channel(host->chan_tx); - host->chan_tx = NULL; + init_completion(&host->dma_complete); + } } static void sh_mmcif_release_dma(struct sh_mmcif_host *host) @@ -457,19 +376,17 @@ static void sh_mmcif_release_dma(struct sh_mmcif_host *host) static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) { struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; - bool sup_pclk = p ? p->sup_pclk : false; sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR); if (!clk) return; - if (sup_pclk && clk == host->clk) + if (p->sup_pclk && clk == host->clk) sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); else sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & - ((fls(DIV_ROUND_UP(host->clk, - clk) - 1) - 1) << 16)); + (ilog2(__rounddown_pow_of_two(host->clk / clk)) << 16)); sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); } @@ -491,7 +408,7 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) static int sh_mmcif_error_manage(struct sh_mmcif_host *host) { u32 state1, state2; - int ret, timeout; + int ret, timeout = 10000000; host->sd_error = false; @@ -503,212 +420,155 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) if (state1 & STS1_CMDSEQ) { sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK); - for (timeout = 10000000; timeout; timeout--) { + while (1) { + timeout--; + if (timeout < 0) { + dev_err(&host->pd->dev, + "Forceed end of command sequence timeout err\n"); + return -EIO; + } if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) - & STS1_CMDSEQ)) + & STS1_CMDSEQ)) break; mdelay(1); } - if (!timeout) { - dev_err(&host->pd->dev, - "Forced end of command sequence timeout err\n"); - return -EIO; - } sh_mmcif_sync_reset(host); dev_dbg(&host->pd->dev, "Forced end of command sequence\n"); return -EIO; } if (state2 & STS2_CRC_ERR) { - dev_dbg(&host->pd->dev, ": CRC error\n"); + dev_dbg(&host->pd->dev, ": Happened CRC error\n"); ret = -EIO; } else if (state2 & STS2_TIMEOUT_ERR) { - dev_dbg(&host->pd->dev, ": Timeout\n"); + dev_dbg(&host->pd->dev, ": Happened Timeout error\n"); ret = -ETIMEDOUT; } else { - dev_dbg(&host->pd->dev, ": End/Index error\n"); + dev_dbg(&host->pd->dev, ": Happened End/Index error\n"); ret = -EIO; } return ret; } -static bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p) -{ - struct mmc_data *data = host->mrq->data; - - host->sg_blkidx += host->blocksize; - - /* data->sg->length must be a multiple of host->blocksize? */ - BUG_ON(host->sg_blkidx > data->sg->length); - - if (host->sg_blkidx == data->sg->length) { - host->sg_blkidx = 0; - if (++host->sg_idx < data->sg_len) - host->pio_ptr = sg_virt(++data->sg); - } else { - host->pio_ptr = p; - } - - if (host->sg_idx == data->sg_len) - return false; - - return true; -} - -static void sh_mmcif_single_read(struct sh_mmcif_host *host, - struct mmc_request *mrq) +static int sh_mmcif_single_read(struct sh_mmcif_host *host, + struct mmc_request *mrq) { - host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & - BLOCK_SIZE_MASK) + 3; - - host->wait_for = MMCIF_WAIT_FOR_READ; - schedule_delayed_work(&host->timeout_work, host->timeout); + struct mmc_data *data = mrq->data; + long time; + u32 blocksize, i, *p = sg_virt(data->sg); /* buf read enable */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); -} - -static bool sh_mmcif_read_block(struct sh_mmcif_host *host) -{ - struct mmc_data *data = host->mrq->data; - u32 *p = sg_virt(data->sg); - int i; - - if (host->sd_error) { - data->error = sh_mmcif_error_manage(host); - return false; - } - - for (i = 0; i < host->blocksize / 4; i++) + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0 || host->sd_error) + return sh_mmcif_error_manage(host); + + blocksize = (BLOCK_SIZE_MASK & + sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; + for (i = 0; i < blocksize / 4; i++) *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); /* buffer read end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); - host->wait_for = MMCIF_WAIT_FOR_READ_END; + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0 || host->sd_error) + return sh_mmcif_error_manage(host); - return true; + return 0; } -static void sh_mmcif_multi_read(struct sh_mmcif_host *host, - struct mmc_request *mrq) +static int sh_mmcif_multi_read(struct sh_mmcif_host *host, + struct mmc_request *mrq) { struct mmc_data *data = mrq->data; - - if (!data->sg_len || !data->sg->length) - return; - - host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & - BLOCK_SIZE_MASK; - - host->wait_for = MMCIF_WAIT_FOR_MREAD; - host->sg_idx = 0; - host->sg_blkidx = 0; - host->pio_ptr = sg_virt(data->sg); - schedule_delayed_work(&host->timeout_work, host->timeout); - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); -} - -static bool sh_mmcif_mread_block(struct sh_mmcif_host *host) -{ - struct mmc_data *data = host->mrq->data; - u32 *p = host->pio_ptr; - int i; - - if (host->sd_error) { - data->error = sh_mmcif_error_manage(host); - return false; + long time; + u32 blocksize, i, j, sec, *p; + + blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, + MMCIF_CE_BLOCK_SET); + for (j = 0; j < data->sg_len; j++) { + p = sg_virt(data->sg); + for (sec = 0; sec < data->sg->length / blocksize; sec++) { + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); + /* buf read enable */ + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + + if (time <= 0 || host->sd_error) + return sh_mmcif_error_manage(host); + + for (i = 0; i < blocksize / 4; i++) + *p++ = sh_mmcif_readl(host->addr, + MMCIF_CE_DATA); + } + if (j < data->sg_len - 1) + data->sg++; } - - BUG_ON(!data->sg->length); - - for (i = 0; i < host->blocksize / 4; i++) - *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); - - if (!sh_mmcif_next_block(host, p)) - return false; - - schedule_delayed_work(&host->timeout_work, host->timeout); - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); - - return true; + return 0; } -static void sh_mmcif_single_write(struct sh_mmcif_host *host, +static int sh_mmcif_single_write(struct sh_mmcif_host *host, struct mmc_request *mrq) { - host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & - BLOCK_SIZE_MASK) + 3; - - host->wait_for = MMCIF_WAIT_FOR_WRITE; - schedule_delayed_work(&host->timeout_work, host->timeout); + struct mmc_data *data = mrq->data; + long time; + u32 blocksize, i, *p = sg_virt(data->sg); - /* buf write enable */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); -} - -static bool sh_mmcif_write_block(struct sh_mmcif_host *host) -{ - struct mmc_data *data = host->mrq->data; - u32 *p = sg_virt(data->sg); - int i; - - if (host->sd_error) { - data->error = sh_mmcif_error_manage(host); - return false; - } - for (i = 0; i < host->blocksize / 4; i++) + /* buf write enable */ + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0 || host->sd_error) + return sh_mmcif_error_manage(host); + + blocksize = (BLOCK_SIZE_MASK & + sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; + for (i = 0; i < blocksize / 4; i++) sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); /* buffer write end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); - host->wait_for = MMCIF_WAIT_FOR_WRITE_END; - return true; + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0 || host->sd_error) + return sh_mmcif_error_manage(host); + + return 0; } -static void sh_mmcif_multi_write(struct sh_mmcif_host *host, - struct mmc_request *mrq) +static int sh_mmcif_multi_write(struct sh_mmcif_host *host, + struct mmc_request *mrq) { struct mmc_data *data = mrq->data; + long time; + u32 i, sec, j, blocksize, *p; - if (!data->sg_len || !data->sg->length) - return; - - host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & - BLOCK_SIZE_MASK; + blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, + MMCIF_CE_BLOCK_SET); - host->wait_for = MMCIF_WAIT_FOR_MWRITE; - host->sg_idx = 0; - host->sg_blkidx = 0; - host->pio_ptr = sg_virt(data->sg); - schedule_delayed_work(&host->timeout_work, host->timeout); - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); -} + for (j = 0; j < data->sg_len; j++) { + p = sg_virt(data->sg); + for (sec = 0; sec < data->sg->length / blocksize; sec++) { + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); + /* buf write enable*/ + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); -static bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host) -{ - struct mmc_data *data = host->mrq->data; - u32 *p = host->pio_ptr; - int i; + if (time <= 0 || host->sd_error) + return sh_mmcif_error_manage(host); - if (host->sd_error) { - data->error = sh_mmcif_error_manage(host); - return false; + for (i = 0; i < blocksize / 4; i++) + sh_mmcif_writel(host->addr, + MMCIF_CE_DATA, *p++); + } + if (j < data->sg_len - 1) + data->sg++; } - - BUG_ON(!data->sg->length); - - for (i = 0; i < host->blocksize / 4; i++) - sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); - - if (!sh_mmcif_next_block(host, p)) - return false; - - schedule_delayed_work(&host->timeout_work, host->timeout); - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); - - return true; + return 0; } static void sh_mmcif_get_response(struct sh_mmcif_host *host, @@ -730,11 +590,8 @@ static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, } static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq) + struct mmc_request *mrq, struct mmc_command *cmd, u32 opc) { - struct mmc_data *data = mrq->data; - struct mmc_command *cmd = mrq->cmd; - u32 opc = cmd->opcode; u32 tmp = 0; /* Response Type check */ @@ -761,11 +618,12 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, case MMC_SET_WRITE_PROT: case MMC_CLR_WRITE_PROT: case MMC_ERASE: + case MMC_GEN_CMD: tmp |= CMD_SET_RBSY; break; } /* WDAT / DATW */ - if (data) { + if (host->data) { tmp |= CMD_SET_WDAT; switch (host->bus_width) { case MMC_BUS_WIDTH_1: @@ -789,7 +647,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) { tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET, - data->blocks << 16); + mrq->data->blocks << 16); } /* RIDXC[1:0] check bits */ if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID || @@ -803,59 +661,68 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, opc == MMC_SEND_CSD || opc == MMC_SEND_CID) tmp |= CMD_SET_CRC7C_INTERNAL; - return (opc << 24) | tmp; + return opc = ((opc << 24) | tmp); } static int sh_mmcif_data_trans(struct sh_mmcif_host *host, - struct mmc_request *mrq, u32 opc) + struct mmc_request *mrq, u32 opc) { + int ret; + switch (opc) { case MMC_READ_MULTIPLE_BLOCK: - sh_mmcif_multi_read(host, mrq); - return 0; + ret = sh_mmcif_multi_read(host, mrq); + break; case MMC_WRITE_MULTIPLE_BLOCK: - sh_mmcif_multi_write(host, mrq); - return 0; + ret = sh_mmcif_multi_write(host, mrq); + break; case MMC_WRITE_BLOCK: - sh_mmcif_single_write(host, mrq); - return 0; + ret = sh_mmcif_single_write(host, mrq); + break; case MMC_READ_SINGLE_BLOCK: case MMC_SEND_EXT_CSD: - sh_mmcif_single_read(host, mrq); - return 0; + ret = sh_mmcif_single_read(host, mrq); + break; default: dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc); - return -EINVAL; + ret = -EINVAL; + break; } + return ret; } static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq) + struct mmc_request *mrq, struct mmc_command *cmd) { - struct mmc_command *cmd = mrq->cmd; + long time; + int ret = 0, mask = 0; u32 opc = cmd->opcode; - u32 mask; switch (opc) { - /* response busy check */ + /* respons busy check */ case MMC_SWITCH: case MMC_STOP_TRANSMISSION: case MMC_SET_WRITE_PROT: case MMC_CLR_WRITE_PROT: case MMC_ERASE: - mask = MASK_START_CMD | MASK_MRBSYE; + case MMC_GEN_CMD: + mask = MASK_MRBSYE; break; default: - mask = MASK_START_CMD | MASK_MCRSPE; + mask = MASK_MCRSPE; break; } + mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | + MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | + MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | + MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; - if (mrq->data) { + if (host->data) { sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0); sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, mrq->data->blksz); } - opc = sh_mmcif_set_cmd(host, mrq); + opc = sh_mmcif_set_cmd(host, mrq, cmd, opc); sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask); @@ -864,28 +731,80 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, /* set cmd */ sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc); - host->wait_for = MMCIF_WAIT_FOR_CMD; - schedule_delayed_work(&host->timeout_work, host->timeout); + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0) { + cmd->error = sh_mmcif_error_manage(host); + return; + } + if (host->sd_error) { + switch (cmd->opcode) { + case MMC_ALL_SEND_CID: + case MMC_SELECT_CARD: + case MMC_APP_CMD: + cmd->error = -ETIMEDOUT; + break; + default: + dev_dbg(&host->pd->dev, "Cmd(d'%d) err\n", + cmd->opcode); + cmd->error = sh_mmcif_error_manage(host); + break; + } + host->sd_error = false; + return; + } + if (!(cmd->flags & MMC_RSP_PRESENT)) { + cmd->error = 0; + return; + } + sh_mmcif_get_response(host, cmd); + if (host->data) { + if (!host->dma_active) { + ret = sh_mmcif_data_trans(host, mrq, cmd->opcode); + } else { + long time = + wait_for_completion_interruptible_timeout(&host->dma_complete, + host->timeout); + if (!time) + ret = -ETIMEDOUT; + else if (time < 0) + ret = time; + sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, + BUF_ACC_DMAREN | BUF_ACC_DMAWEN); + host->dma_active = false; + } + if (ret < 0) + mrq->data->bytes_xfered = 0; + else + mrq->data->bytes_xfered = + mrq->data->blocks * mrq->data->blksz; + } + cmd->error = ret; } static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq) + struct mmc_request *mrq, struct mmc_command *cmd) { - switch (mrq->cmd->opcode) { - case MMC_READ_MULTIPLE_BLOCK: + long time; + + if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK) sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); - break; - case MMC_WRITE_MULTIPLE_BLOCK: + else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); - break; - default: + else { dev_err(&host->pd->dev, "unsupported stop cmd\n"); - mrq->stop->error = sh_mmcif_error_manage(host); + cmd->error = sh_mmcif_error_manage(host); return; } - host->wait_for = MMCIF_WAIT_FOR_STOP; - schedule_delayed_work(&host->timeout_work, host->timeout); + time = wait_for_completion_interruptible_timeout(&host->intr_wait, + host->timeout); + if (time <= 0 || host->sd_error) { + cmd->error = sh_mmcif_error_manage(host); + return; + } + sh_mmcif_get_cmd12response(host, cmd); + cmd->error = 0; } static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) @@ -906,53 +825,47 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) switch (mrq->cmd->opcode) { /* MMCIF does not support SD/SDIO command */ - case MMC_SLEEP_AWAKE: /* = SD_IO_SEND_OP_COND (5) */ - case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ - if ((mrq->cmd->flags & MMC_CMD_MASK) != MMC_CMD_BCR) - break; + case SD_IO_SEND_OP_COND: case MMC_APP_CMD: host->state = STATE_IDLE; mrq->cmd->error = -ETIMEDOUT; mmc_request_done(mmc, mrq); return; + case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ + if (!mrq->data) { + /* send_if_cond cmd (not support) */ + host->state = STATE_IDLE; + mrq->cmd->error = -ETIMEDOUT; + mmc_request_done(mmc, mrq); + return; + } + break; default: break; } - - host->mrq = mrq; - - sh_mmcif_start_cmd(host, mrq); -} - -static int sh_mmcif_clk_update(struct sh_mmcif_host *host) -{ - int ret = clk_enable(host->hclk); - - if (!ret) { - host->clk = clk_get_rate(host->hclk); - host->mmc->f_max = host->clk / 2; - host->mmc->f_min = host->clk / 512; + host->data = mrq->data; + if (mrq->data) { + if (mrq->data->flags & MMC_DATA_READ) { + if (host->chan_rx) + sh_mmcif_start_dma_rx(host); + } else { + if (host->chan_tx) + sh_mmcif_start_dma_tx(host); + } } + sh_mmcif_start_cmd(host, mrq, mrq->cmd); + host->data = NULL; - return ret; -} - -static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios) -{ - struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data; - struct mmc_host *mmc = host->mmc; - - if (pd && pd->set_pwr) - pd->set_pwr(host->pd, ios->power_mode != MMC_POWER_OFF); - if (!IS_ERR(mmc->supply.vmmc)) - /* Errors ignored... */ - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, - ios->power_mode ? ios->vdd : 0); + if (!mrq->cmd->error && mrq->stop) + sh_mmcif_stop_cmd(host, mrq, mrq->stop); + host->state = STATE_IDLE; + mmc_request_done(mmc, mrq); } static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct sh_mmcif_host *host = mmc_priv(mmc); + struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; unsigned long flags; spin_lock_irqsave(&host->lock, flags); @@ -970,7 +883,6 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sh_mmcif_request_dma(host, host->pd->dev.platform_data); host->card_present = true; } - sh_mmcif_set_power(host, ios); } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { /* clock stop */ sh_mmcif_clock_control(host, 0); @@ -982,10 +894,9 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } if (host->power) { pm_runtime_put(&host->pd->dev); - clk_disable(host->hclk); host->power = false; - if (ios->power_mode == MMC_POWER_OFF) - sh_mmcif_set_power(host, ios); + if (p->down_pwr) + p->down_pwr(host->pd); } host->state = STATE_IDLE; return; @@ -993,7 +904,8 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->clock) { if (!host->power) { - sh_mmcif_clk_update(host); + if (p->set_pwr) + p->set_pwr(host->pd, ios->power_mode); pm_runtime_get_sync(&host->pd->dev); host->power = true; sh_mmcif_sync_reset(host); @@ -1009,12 +921,8 @@ static int sh_mmcif_get_cd(struct mmc_host *mmc) { struct sh_mmcif_host *host = mmc_priv(mmc); struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; - int ret = mmc_gpio_get_cd(mmc); - if (ret >= 0) - return ret; - - if (!p || !p->get_cd) + if (!p->get_cd) return -ENOSYS; else return p->get_cd(host->pd); @@ -1026,156 +934,9 @@ static struct mmc_host_ops sh_mmcif_ops = { .get_cd = sh_mmcif_get_cd, }; -static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) +static void sh_mmcif_detect(struct mmc_host *mmc) { - struct mmc_command *cmd = host->mrq->cmd; - struct mmc_data *data = host->mrq->data; - long time; - - if (host->sd_error) { - switch (cmd->opcode) { - case MMC_ALL_SEND_CID: - case MMC_SELECT_CARD: - case MMC_APP_CMD: - cmd->error = -ETIMEDOUT; - host->sd_error = false; - break; - default: - cmd->error = sh_mmcif_error_manage(host); - dev_dbg(&host->pd->dev, "Cmd(d'%d) error %d\n", - cmd->opcode, cmd->error); - break; - } - return false; - } - if (!(cmd->flags & MMC_RSP_PRESENT)) { - cmd->error = 0; - return false; - } - - sh_mmcif_get_response(host, cmd); - - if (!data) - return false; - - if (data->flags & MMC_DATA_READ) { - if (host->chan_rx) - sh_mmcif_start_dma_rx(host); - } else { - if (host->chan_tx) - sh_mmcif_start_dma_tx(host); - } - - if (!host->dma_active) { - data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode); - if (!data->error) - return true; - return false; - } - - /* Running in the IRQ thread, can sleep */ - time = wait_for_completion_interruptible_timeout(&host->dma_complete, - host->timeout); - if (host->sd_error) { - dev_err(host->mmc->parent, - "Error IRQ while waiting for DMA completion!\n"); - /* Woken up by an error IRQ: abort DMA */ - if (data->flags & MMC_DATA_READ) - dmaengine_terminate_all(host->chan_rx); - else - dmaengine_terminate_all(host->chan_tx); - data->error = sh_mmcif_error_manage(host); - } else if (!time) { - data->error = -ETIMEDOUT; - } else if (time < 0) { - data->error = time; - } - sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, - BUF_ACC_DMAREN | BUF_ACC_DMAWEN); - host->dma_active = false; - - if (data->error) - data->bytes_xfered = 0; - - return false; -} - -static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) -{ - struct sh_mmcif_host *host = dev_id; - struct mmc_request *mrq = host->mrq; - - cancel_delayed_work_sync(&host->timeout_work); - - /* - * All handlers return true, if processing continues, and false, if the - * request has to be completed - successfully or not - */ - switch (host->wait_for) { - case MMCIF_WAIT_FOR_REQUEST: - /* We're too late, the timeout has already kicked in */ - return IRQ_HANDLED; - case MMCIF_WAIT_FOR_CMD: - if (sh_mmcif_end_cmd(host)) - /* Wait for data */ - return IRQ_HANDLED; - break; - case MMCIF_WAIT_FOR_MREAD: - if (sh_mmcif_mread_block(host)) - /* Wait for more data */ - return IRQ_HANDLED; - break; - case MMCIF_WAIT_FOR_READ: - if (sh_mmcif_read_block(host)) - /* Wait for data end */ - return IRQ_HANDLED; - break; - case MMCIF_WAIT_FOR_MWRITE: - if (sh_mmcif_mwrite_block(host)) - /* Wait data to write */ - return IRQ_HANDLED; - break; - case MMCIF_WAIT_FOR_WRITE: - if (sh_mmcif_write_block(host)) - /* Wait for data end */ - return IRQ_HANDLED; - break; - case MMCIF_WAIT_FOR_STOP: - if (host->sd_error) { - mrq->stop->error = sh_mmcif_error_manage(host); - break; - } - sh_mmcif_get_cmd12response(host, mrq->stop); - mrq->stop->error = 0; - break; - case MMCIF_WAIT_FOR_READ_END: - case MMCIF_WAIT_FOR_WRITE_END: - if (host->sd_error) - mrq->data->error = sh_mmcif_error_manage(host); - break; - default: - BUG(); - } - - if (host->wait_for != MMCIF_WAIT_FOR_STOP) { - struct mmc_data *data = mrq->data; - if (!mrq->cmd->error && data && !data->error) - data->bytes_xfered = - data->blocks * data->blksz; - - if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) { - sh_mmcif_stop_cmd(host, mrq); - if (!mrq->stop->error) - return IRQ_HANDLED; - } - } - - host->wait_for = MMCIF_WAIT_FOR_REQUEST; - host->state = STATE_IDLE; - host->mrq = NULL; - mmc_request_done(host->mmc, mrq); - - return IRQ_HANDLED; + mmc_detect_change(mmc, 0); } static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) @@ -1186,12 +947,7 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); - if (state & INT_ERR_STS) { - /* error interrupts - process first */ - sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); - err = 1; - } else if (state & INT_RBSYE) { + if (state & INT_RBSYE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_RBSYE | INT_CRSPE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE); @@ -1213,14 +969,17 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFRE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); } else if (state & INT_DTRANE) { - sh_mmcif_writel(host->addr, MMCIF_CE_INT, - ~(INT_CMD12DRE | INT_CMD12RBE | - INT_CMD12CRE | INT_DTRANE)); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_DTRANE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); } else if (state & INT_CMD12RBE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12RBE | INT_CMD12CRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); + } else if (state & INT_ERR_STS) { + /* err interrupts */ + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); + sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); + err = 1; } else { dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state); sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); @@ -1231,81 +990,23 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) host->sd_error = true; dev_dbg(&host->pd->dev, "int err state = %08x\n", state); } - if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) { - if (!host->dma_active) - return IRQ_WAKE_THREAD; - else if (host->sd_error) - mmcif_dma_complete(host); - } else { + if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) + complete(&host->intr_wait); + else dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state); - } return IRQ_HANDLED; } -static void mmcif_timeout_work(struct work_struct *work) -{ - struct delayed_work *d = container_of(work, struct delayed_work, work); - struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work); - struct mmc_request *mrq = host->mrq; - - if (host->dying) - /* Don't run after mmc_remove_host() */ - return; - - /* - * Handle races with cancel_delayed_work(), unless - * cancel_delayed_work_sync() is used - */ - switch (host->wait_for) { - case MMCIF_WAIT_FOR_CMD: - mrq->cmd->error = sh_mmcif_error_manage(host); - break; - case MMCIF_WAIT_FOR_STOP: - mrq->stop->error = sh_mmcif_error_manage(host); - break; - case MMCIF_WAIT_FOR_MREAD: - case MMCIF_WAIT_FOR_MWRITE: - case MMCIF_WAIT_FOR_READ: - case MMCIF_WAIT_FOR_WRITE: - case MMCIF_WAIT_FOR_READ_END: - case MMCIF_WAIT_FOR_WRITE_END: - mrq->data->error = sh_mmcif_error_manage(host); - break; - default: - BUG(); - } - - host->state = STATE_IDLE; - host->wait_for = MMCIF_WAIT_FOR_REQUEST; - host->mrq = NULL; - mmc_request_done(host->mmc, mrq); -} - -static void sh_mmcif_init_ocr(struct sh_mmcif_host *host) -{ - struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data; - struct mmc_host *mmc = host->mmc; - - mmc_regulator_get_supply(mmc); - - if (!pd) - return; - - if (!mmc->ocr_avail) - mmc->ocr_avail = pd->ocr; - else if (pd->ocr) - dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); -} - -static int sh_mmcif_probe(struct platform_device *pdev) +static int __devinit sh_mmcif_probe(struct platform_device *pdev) { int ret = 0, irq[2]; struct mmc_host *mmc; struct sh_mmcif_host *host; - struct sh_mmcif_plat_data *pd = pdev->dev.platform_data; + struct sh_mmcif_plat_data *pd; struct resource *res; void __iomem *reg; + char clk_name[8]; irq[0] = platform_get_irq(pdev, 0); irq[1] = platform_get_irq(pdev, 1); @@ -1323,26 +1024,49 @@ static int sh_mmcif_probe(struct platform_device *pdev) dev_err(&pdev->dev, "ioremap error.\n"); return -ENOMEM; } - + pd = pdev->dev.platform_data; + if (!pd) { + dev_err(&pdev->dev, "sh_mmcif plat data error.\n"); + ret = -ENXIO; + goto clean_up; + } mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; - goto ealloch; + goto clean_up; } host = mmc_priv(mmc); host->mmc = mmc; host->addr = reg; host->timeout = 1000; + snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id); + host->hclk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(host->hclk)) { + dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); + ret = PTR_ERR(host->hclk); + goto clean_up1; + } + clk_enable(host->hclk); + host->clk = clk_get_rate(host->hclk); host->pd = pdev; + init_completion(&host->intr_wait); spin_lock_init(&host->lock); mmc->ops = &sh_mmcif_ops; - sh_mmcif_init_ocr(host); - + mmc->f_max = host->clk; + /* close to 400KHz */ + if (mmc->f_max < 51200000) + mmc->f_min = mmc->f_max / 128; + else if (mmc->f_max < 102400000) + mmc->f_min = mmc->f_max / 256; + else + mmc->f_min = mmc->f_max / 512; + if (pd->ocr) + mmc->ocr_avail = pd->ocr; mmc->caps = MMC_CAP_MMC_HIGHSPEED; - if (pd && pd->caps) + if (pd->caps) mmc->caps |= pd->caps; mmc->max_segs = 32; mmc->max_blk_size = 512; @@ -1350,105 +1074,63 @@ static int sh_mmcif_probe(struct platform_device *pdev) mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size; mmc->max_seg_size = mmc->max_req_size; + sh_mmcif_sync_reset(host); platform_set_drvdata(pdev, host); pm_runtime_enable(&pdev->dev); host->power = false; - host->hclk = clk_get(&pdev->dev, NULL); - if (IS_ERR(host->hclk)) { - ret = PTR_ERR(host->hclk); - dev_err(&pdev->dev, "cannot get clock: %d\n", ret); - goto eclkget; - } - ret = sh_mmcif_clk_update(host); - if (ret < 0) - goto eclkupdate; - ret = pm_runtime_resume(&pdev->dev); if (ret < 0) - goto eresume; + goto clean_up2; - INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work); + mmc_add_host(mmc); - sh_mmcif_sync_reset(host); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); - ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host); + ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host); if (ret) { dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n"); - goto ereqirq0; + goto clean_up3; } - ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host); + ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host); if (ret) { + free_irq(irq[0], host); dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n"); - goto ereqirq1; + goto clean_up3; } - if (pd && pd->use_cd_gpio) { - ret = mmc_gpio_request_cd(mmc, pd->cd_gpio); - if (ret < 0) - goto erqcd; - } - - clk_disable(host->hclk); - ret = mmc_add_host(mmc); - if (ret < 0) - goto emmcaddh; - - dev_pm_qos_expose_latency_limit(&pdev->dev, 100); + sh_mmcif_detect(host->mmc); dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); dev_dbg(&pdev->dev, "chip ver H'%04x\n", sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); return ret; -emmcaddh: - if (pd && pd->use_cd_gpio) - mmc_gpio_free_cd(mmc); -erqcd: - free_irq(irq[1], host); -ereqirq1: - free_irq(irq[0], host); -ereqirq0: +clean_up3: + mmc_remove_host(mmc); pm_runtime_suspend(&pdev->dev); -eresume: - clk_disable(host->hclk); -eclkupdate: - clk_put(host->hclk); -eclkget: +clean_up2: pm_runtime_disable(&pdev->dev); + clk_disable(host->hclk); +clean_up1: mmc_free_host(mmc); -ealloch: - iounmap(reg); +clean_up: + if (reg) + iounmap(reg); return ret; } -static int sh_mmcif_remove(struct platform_device *pdev) +static int __devexit sh_mmcif_remove(struct platform_device *pdev) { struct sh_mmcif_host *host = platform_get_drvdata(pdev); - struct sh_mmcif_plat_data *pd = pdev->dev.platform_data; int irq[2]; - host->dying = true; - clk_enable(host->hclk); pm_runtime_get_sync(&pdev->dev); - dev_pm_qos_hide_latency_limit(&pdev->dev); - - if (pd && pd->use_cd_gpio) - mmc_gpio_free_cd(host->mmc); - mmc_remove_host(host->mmc); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); - /* - * FIXME: cancel_delayed_work(_sync)() and free_irq() race with the - * mmc_remove_host() call above. But swapping order doesn't help either - * (a query on the linux-mmc mailing list didn't bring any replies). - */ - cancel_delayed_work_sync(&host->timeout_work); - if (host->addr) iounmap(host->addr); @@ -1471,18 +1153,24 @@ static int sh_mmcif_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int sh_mmcif_suspend(struct device *dev) { - struct sh_mmcif_host *host = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct sh_mmcif_host *host = platform_get_drvdata(pdev); int ret = mmc_suspend_host(host->mmc); - if (!ret) + if (!ret) { sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); + clk_disable(host->hclk); + } return ret; } static int sh_mmcif_resume(struct device *dev) { - struct sh_mmcif_host *host = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct sh_mmcif_host *host = platform_get_drvdata(pdev); + + clk_enable(host->hclk); return mmc_resume_host(host->mmc); } @@ -1491,12 +1179,6 @@ static int sh_mmcif_resume(struct device *dev) #define sh_mmcif_resume NULL #endif /* CONFIG_PM */ -static const struct of_device_id mmcif_of_match[] = { - { .compatible = "renesas,sh-mmcif" }, - { } -}; -MODULE_DEVICE_TABLE(of, mmcif_of_match); - static const struct dev_pm_ops sh_mmcif_dev_pm_ops = { .suspend = sh_mmcif_suspend, .resume = sh_mmcif_resume, @@ -1508,12 +1190,22 @@ static struct platform_driver sh_mmcif_driver = { .driver = { .name = DRIVER_NAME, .pm = &sh_mmcif_dev_pm_ops, - .owner = THIS_MODULE, - .of_match_table = mmcif_of_match, }, }; -module_platform_driver(sh_mmcif_driver); +static int __init sh_mmcif_init(void) +{ + return platform_driver_register(&sh_mmcif_driver); +} + +static void __exit sh_mmcif_exit(void) +{ + platform_driver_unregister(&sh_mmcif_driver); +} + +module_init(sh_mmcif_init); +module_exit(sh_mmcif_exit); + MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 524a7f77382..0c4a672f5db 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -21,8 +21,6 @@ #include #include #include -#include -#include #include #include #include @@ -40,39 +38,22 @@ struct sh_mobile_sdhi { struct tmio_mmc_dma dma_priv; }; -static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f) -{ - struct mmc_host *mmc = dev_get_drvdata(&pdev->dev); - struct tmio_mmc_host *host = mmc_priv(mmc); - struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); - int ret = clk_enable(priv->clk); - if (ret < 0) - return ret; - - *f = clk_get_rate(priv->clk); - return 0; -} - -static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev) -{ - struct mmc_host *mmc = dev_get_drvdata(&pdev->dev); - struct tmio_mmc_host *host = mmc_priv(mmc); - struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); - clk_disable(priv->clk); -} - static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state) { struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - p->set_pwr(pdev, state); + if (p && p->set_pwr) + p->set_pwr(pdev, state); } static int sh_mobile_sdhi_get_cd(struct platform_device *pdev) { struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - return p->get_cd(pdev); + if (p && p->get_cd) + return p->get_cd(pdev); + else + return -ENOSYS; } static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) @@ -108,23 +89,14 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) return 0; } -static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev) -{ - mmc_detect_change(dev_get_drvdata(&pdev->dev), msecs_to_jiffies(100)); -} - -static const struct sh_mobile_sdhi_ops sdhi_ops = { - .cd_wakeup = sh_mobile_sdhi_cd_wakeup, -}; - -static int sh_mobile_sdhi_probe(struct platform_device *pdev) +static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) { struct sh_mobile_sdhi *priv; struct tmio_mmc_data *mmc_data; struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct tmio_mmc_host *host; - int irq, ret, i = 0; - bool multiplexed_isr = true; + char clk_name[8]; + int i, irq, ret; priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); if (priv == NULL) { @@ -133,25 +105,21 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) } mmc_data = &priv->mmc_data; + p->pdata = mmc_data; - if (p) { - p->pdata = mmc_data; - if (p->init) { - ret = p->init(pdev, &sdhi_ops); - if (ret) - goto einit; - } - } - - priv->clk = clk_get(&pdev->dev, NULL); + snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id); + priv->clk = clk_get(&pdev->dev, clk_name); if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); ret = PTR_ERR(priv->clk); - dev_err(&pdev->dev, "cannot get clock: %d\n", ret); goto eclkget; } - mmc_data->clk_enable = sh_mobile_sdhi_clk_enable; - mmc_data->clk_disable = sh_mobile_sdhi_clk_disable; + clk_enable(priv->clk); + + mmc_data->hclk = clk_get_rate(priv->clk); + mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; + mmc_data->get_cd = sh_mobile_sdhi_get_cd; mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; if (p) { mmc_data->flags = p->tmio_flags; @@ -159,18 +127,12 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data->write16_hook = sh_mobile_sdhi_write16_hook; mmc_data->ocr_mask = p->tmio_ocr_mask; mmc_data->capabilities |= p->tmio_caps; - mmc_data->capabilities2 |= p->tmio_caps2; - mmc_data->cd_gpio = p->cd_gpio; - if (p->set_pwr) - mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; - if (p->get_cd) - mmc_data->get_cd = sh_mobile_sdhi_get_cd; if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) { - priv->param_tx.shdma_slave.slave_id = p->dma_slave_tx; - priv->param_rx.shdma_slave.slave_id = p->dma_slave_rx; - priv->dma_priv.chan_priv_tx = &priv->param_tx.shdma_slave; - priv->dma_priv.chan_priv_rx = &priv->param_rx.shdma_slave; + priv->param_tx.slave_id = p->dma_slave_tx; + priv->param_rx.slave_id = p->dma_slave_rx; + priv->dma_priv.chan_priv_tx = &priv->param_tx; + priv->dma_priv.chan_priv_rx = &priv->param_rx; priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */ mmc_data->dma = &priv->dma_priv; } @@ -191,88 +153,40 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) if (ret < 0) goto eprobe; - /* - * Allow one or more specific (named) ISRs or - * one or more multiplexed (un-named) ISRs. - */ - - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT); - if (irq >= 0) { - multiplexed_isr = false; - ret = request_irq(irq, tmio_mmc_card_detect_irq, 0, - dev_name(&pdev->dev), host); - if (ret) - goto eirq_card_detect; - } - - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO); - if (irq >= 0) { - multiplexed_isr = false; - ret = request_irq(irq, tmio_mmc_sdio_irq, 0, - dev_name(&pdev->dev), host); - if (ret) - goto eirq_sdio; - } - - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDCARD); - if (irq >= 0) { - multiplexed_isr = false; - ret = request_irq(irq, tmio_mmc_sdcard_irq, 0, + for (i = 0; i < 3; i++) { + irq = platform_get_irq(pdev, i); + if (irq < 0) { + if (i) { + continue; + } else { + ret = irq; + goto eirq; + } + } + ret = request_irq(irq, tmio_mmc_irq, 0, dev_name(&pdev->dev), host); - if (ret) - goto eirq_sdcard; - } else if (!multiplexed_isr) { - dev_err(&pdev->dev, - "Principal SD-card IRQ is missing among named interrupts\n"); - ret = irq; - goto eirq_sdcard; - } - - if (multiplexed_isr) { - while (1) { - irq = platform_get_irq(pdev, i); - if (irq < 0) - break; - i++; - ret = request_irq(irq, tmio_mmc_irq, 0, - dev_name(&pdev->dev), host); - if (ret) - goto eirq_multiplexed; + if (ret) { + while (i--) { + irq = platform_get_irq(pdev, i); + if (irq >= 0) + free_irq(irq, host); + } + goto eirq; } - - /* There must be at least one IRQ source */ - if (!i) - goto eirq_multiplexed; } - dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n", mmc_hostname(host->mmc), (unsigned long) - (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), - host->mmc->f_max / 1000000); + (platform_get_resource(pdev,IORESOURCE_MEM, 0)->start), + mmc_data->hclk / 1000000); return ret; -eirq_multiplexed: - while (i--) { - irq = platform_get_irq(pdev, i); - free_irq(irq, host); - } -eirq_sdcard: - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO); - if (irq >= 0) - free_irq(irq, host); -eirq_sdio: - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT); - if (irq >= 0) - free_irq(irq, host); -eirq_card_detect: +eirq: tmio_mmc_host_remove(host); eprobe: + clk_disable(priv->clk); clk_put(priv->clk); eclkget: - if (p && p->cleanup) - p->cleanup(pdev); -einit: kfree(priv); return ret; } @@ -283,25 +197,20 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) struct tmio_mmc_host *host = mmc_priv(mmc); struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - int i = 0, irq; + int i, irq; - if (p) - p->pdata = NULL; + p->pdata = NULL; tmio_mmc_host_remove(host); - while (1) { - irq = platform_get_irq(pdev, i++); - if (irq < 0) - break; - free_irq(irq, host); + for (i = 0; i < 3; i++) { + irq = platform_get_irq(pdev, i); + if (irq >= 0) + free_irq(irq, host); } + clk_disable(priv->clk); clk_put(priv->clk); - - if (p && p->cleanup) - p->cleanup(pdev); - kfree(priv); return 0; @@ -314,24 +223,28 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { .runtime_resume = tmio_mmc_host_runtime_resume, }; -static const struct of_device_id sh_mobile_sdhi_of_match[] = { - { .compatible = "renesas,shmobile-sdhi" }, - { } -}; -MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); - static struct platform_driver sh_mobile_sdhi_driver = { .driver = { .name = "sh_mobile_sdhi", .owner = THIS_MODULE, .pm = &tmio_mmc_dev_pm_ops, - .of_match_table = sh_mobile_sdhi_of_match, }, .probe = sh_mobile_sdhi_probe, - .remove = sh_mobile_sdhi_remove, + .remove = __devexit_p(sh_mobile_sdhi_remove), }; -module_platform_driver(sh_mobile_sdhi_driver); +static int __init sh_mobile_sdhi_init(void) +{ + return platform_driver_register(&sh_mobile_sdhi_driver); +} + +static void __exit sh_mobile_sdhi_exit(void) +{ + platform_driver_unregister(&sh_mobile_sdhi_driver); +} + +module_init(sh_mobile_sdhi_init); +module_exit(sh_mobile_sdhi_exit); MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); MODULE_AUTHOR("Magnus Damm"); diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 43d962829f8..457c26ea09d 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -16,14 +16,13 @@ #include #include #include -#include #include #define DRIVER_NAME "tifm_sd" #define DRIVER_VERSION "0.8" -static bool no_dma = 0; -static bool fixed_timeout = 0; +static int no_dma = 0; +static int fixed_timeout = 0; module_param(no_dma, bool, 0644); module_param(fixed_timeout, bool, 0644); @@ -118,7 +117,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg) + off; + buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off; if (host->cmd_flags & DATA_CARRY) { buf[pos++] = host->bounce_buf_data[0]; host->cmd_flags &= ~DATA_CARRY; @@ -134,7 +133,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, } buf[pos++] = (val >> 8) & 0xff; } - kunmap_atomic(buf - off); + kunmap_atomic(buf - off, KM_BIO_DST_IRQ); } static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, @@ -144,7 +143,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg) + off; + buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off; if (host->cmd_flags & DATA_CARRY) { val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00); writel(val, sock->addr + SOCK_MMCSD_DATA); @@ -161,7 +160,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, val |= (buf[pos++] << 8) & 0xff00; writel(val, sock->addr + SOCK_MMCSD_DATA); } - kunmap_atomic(buf - off); + kunmap_atomic(buf - off, KM_BIO_SRC_IRQ); } static void tifm_sd_transfer_data(struct tifm_sd *host) @@ -212,13 +211,13 @@ static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off, struct page *src, unsigned int src_off, unsigned int count) { - unsigned char *src_buf = kmap_atomic(src) + src_off; - unsigned char *dst_buf = kmap_atomic(dst) + dst_off; + unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off; + unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off; memcpy(dst_buf, src_buf, count); - kunmap_atomic(dst_buf - dst_off); - kunmap_atomic(src_buf - src_off); + kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ); + kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ); } static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data) @@ -632,7 +631,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) } if (host->req) { - pr_err("%s : unfinished request detected\n", + printk(KERN_ERR "%s : unfinished request detected\n", dev_name(&sock->dev)); mrq->cmd->error = -ETIMEDOUT; goto err_out; @@ -672,7 +671,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) r_data->flags & MMC_DATA_WRITE ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE)) { - pr_err("%s : scatterlist map failed\n", + printk(KERN_ERR "%s : scatterlist map failed\n", dev_name(&sock->dev)); mrq->cmd->error = -ENOMEM; goto err_out; @@ -684,7 +683,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); if (host->sg_len < 1) { - pr_err("%s : scatterlist map failed\n", + printk(KERN_ERR "%s : scatterlist map failed\n", dev_name(&sock->dev)); tifm_unmap_sg(sock, &host->bounce_buf, 1, r_data->flags & MMC_DATA_WRITE @@ -748,7 +747,7 @@ static void tifm_sd_end_cmd(unsigned long data) host->req = NULL; if (!mrq) { - pr_err(" %s : no request to complete?\n", + printk(KERN_ERR " %s : no request to complete?\n", dev_name(&sock->dev)); spin_unlock_irqrestore(&sock->lock, flags); return; @@ -787,7 +786,8 @@ static void tifm_sd_abort(unsigned long data) { struct tifm_sd *host = (struct tifm_sd*)data; - pr_err("%s : card failed to respond for a long period of time " + printk(KERN_ERR + "%s : card failed to respond for a long period of time " "(%x, %x)\n", dev_name(&host->dev->dev), host->req->cmd->opcode, host->cmd_flags); @@ -905,7 +905,7 @@ static int tifm_sd_initialize_host(struct tifm_sd *host) } if (rc) { - pr_err("%s : controller failed to reset\n", + printk(KERN_ERR "%s : controller failed to reset\n", dev_name(&sock->dev)); return -ENODEV; } @@ -931,7 +931,8 @@ static int tifm_sd_initialize_host(struct tifm_sd *host) } if (rc) { - pr_err("%s : card not ready - probe failed on initialization\n", + printk(KERN_ERR + "%s : card not ready - probe failed on initialization\n", dev_name(&sock->dev)); return -ENODEV; } @@ -952,7 +953,7 @@ static int tifm_sd_probe(struct tifm_dev *sock) if (!(TIFM_SOCK_STATE_OCCUPIED & readl(sock->addr + SOCK_PRESENT_STATE))) { - pr_warning("%s : card gone, unexpectedly\n", + printk(KERN_WARNING "%s : card gone, unexpectedly\n", dev_name(&sock->dev)); return rc; } diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 139212e79cd..44a9668c4b7 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -57,7 +57,7 @@ static int tmio_mmc_resume(struct platform_device *dev) #define tmio_mmc_resume NULL #endif -static int tmio_mmc_probe(struct platform_device *pdev) +static int __devinit tmio_mmc_probe(struct platform_device *pdev) { const struct mfd_cell *cell = mfd_get_cell(pdev); struct tmio_mmc_data *pdata; @@ -88,8 +88,8 @@ static int tmio_mmc_probe(struct platform_device *pdev) if (ret) goto cell_disable; - ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING, - dev_name(&pdev->dev), host); + ret = request_irq(irq, tmio_mmc_irq, IRQF_DISABLED | + IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host); if (ret) goto host_remove; @@ -107,7 +107,7 @@ out: return ret; } -static int tmio_mmc_remove(struct platform_device *pdev) +static int __devexit tmio_mmc_remove(struct platform_device *pdev) { const struct mfd_cell *cell = mfd_get_cell(pdev); struct mmc_host *mmc = platform_get_drvdata(pdev); @@ -133,12 +133,24 @@ static struct platform_driver tmio_mmc_driver = { .owner = THIS_MODULE, }, .probe = tmio_mmc_probe, - .remove = tmio_mmc_remove, + .remove = __devexit_p(tmio_mmc_remove), .suspend = tmio_mmc_suspend, .resume = tmio_mmc_resume, }; -module_platform_driver(tmio_mmc_driver); + +static int __init tmio_mmc_init(void) +{ + return platform_driver_register(&tmio_mmc_driver); +} + +static void __exit tmio_mmc_exit(void) +{ + platform_driver_unregister(&tmio_mmc_driver); +} + +module_init(tmio_mmc_init); +module_exit(tmio_mmc_exit); MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver"); MODULE_AUTHOR("Ian Molton "); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index d857f5c6e7d..eeaf64391fb 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -20,8 +20,8 @@ #include #include #include -#include #include +#include /* Definitions for values the CTRL_SDIO_STATUS register can take. */ #define TMIO_SDIO_STAT_IOIRQ 0x0001 @@ -47,14 +47,16 @@ struct tmio_mmc_host { struct mmc_request *mrq; struct mmc_data *data; struct mmc_host *mmc; - - /* Controller power state */ - bool power; + unsigned int sdio_irq_enabled; /* Callbacks for clock / power control */ void (*set_pwr)(struct platform_device *host, int state); void (*set_clk_div)(struct platform_device *host, int state); + int pm_error; + /* recognise system-wide suspend in runtime PM methods */ + bool pm_global; + /* pio related stuff */ struct scatterlist *sg_ptr; struct scatterlist *sg_orig; @@ -77,14 +79,9 @@ struct tmio_mmc_host { struct delayed_work delayed_reset_work; struct work_struct done; - /* Cache IRQ mask */ - u32 sdcard_irq_mask; - u32 sdio_irq_mask; - spinlock_t lock; /* protect host private data */ unsigned long last_req_ts; struct mutex ios_lock; /* protect set_ios() context */ - bool native_hotplug; }; int tmio_mmc_host_probe(struct tmio_mmc_host **host, @@ -96,21 +93,18 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); irqreturn_t tmio_mmc_irq(int irq, void *devid); -irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid); -irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid); -irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid); static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { local_irq_save(*flags); - return kmap_atomic(sg_page(sg)) + sg->offset; + return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; } static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, unsigned long *flags, void *virt) { - kunmap_atomic(virt - sg->offset); + kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ); local_irq_restore(*flags); } @@ -119,7 +113,6 @@ void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data); void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable); void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); void tmio_mmc_release_dma(struct tmio_mmc_host *host); -void tmio_mmc_abort_dma(struct tmio_mmc_host *host); #else static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data) @@ -140,10 +133,6 @@ static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host, static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host) { } - -static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host) -{ -} #endif #ifdef CONFIG_PM diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index fff92860485..86f259cdfcb 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -34,18 +34,6 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) #endif } -void tmio_mmc_abort_dma(struct tmio_mmc_host *host) -{ - tmio_mmc_enable_dma(host, false); - - if (host->chan_rx) - dmaengine_terminate_all(host->chan_rx); - if (host->chan_tx) - dmaengine_terminate_all(host->chan_tx); - - tmio_mmc_enable_dma(host, true); -} - static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) { struct scatterlist *sg = host->sg_ptr, *sg_tmp; @@ -88,8 +76,8 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); if (ret > 0) - desc = dmaengine_prep_slave_sg(chan, sg, ret, - DMA_DEV_TO_MEM, DMA_CTRL_ACK); + desc = chan->device->device_prep_slave_sg(chan, sg, ret, + DMA_FROM_DEVICE, DMA_CTRL_ACK); if (desc) { cookie = dmaengine_submit(desc); @@ -169,8 +157,8 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); if (ret > 0) - desc = dmaengine_prep_slave_sg(chan, sg, ret, - DMA_MEM_TO_DEV, DMA_CTRL_ACK); + desc = chan->device->device_prep_slave_sg(chan, sg, ret, + DMA_TO_DEVICE, DMA_CTRL_ACK); if (desc) { cookie = dmaengine_submit(desc); diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 50bf495a988..1f16357e730 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -35,30 +35,27 @@ #include #include #include -#include -#include #include #include #include #include -#include #include #include -#include #include +#include #include "tmio_mmc.h" void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i) { - host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ); - sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask); + u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) & ~(i & TMIO_MASK_IRQ); + sd_ctrl_write32(host, CTL_IRQ_MASK, mask); } void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i) { - host->sdcard_irq_mask |= (i & TMIO_MASK_IRQ); - sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask); + u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) | (i & TMIO_MASK_IRQ); + sd_ctrl_write32(host, CTL_IRQ_MASK, mask); } static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i) @@ -95,7 +92,7 @@ static int tmio_mmc_next_sg(struct tmio_mmc_host *host) static void pr_debug_status(u32 status) { int i = 0; - pr_debug("status: %08x = ", status); + printk(KERN_DEBUG "status: %08x = ", status); STATUS_TO_TEXT(CARD_REMOVE, status, i); STATUS_TO_TEXT(CARD_INSERT, status, i); STATUS_TO_TEXT(SIGSTATE, status, i); @@ -129,14 +126,14 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) struct tmio_mmc_host *host = mmc_priv(mmc); if (enable) { - host->sdio_irq_mask = TMIO_SDIO_MASK_ALL & - ~TMIO_SDIO_STAT_IOIRQ; + host->sdio_irq_enabled = 1; sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); - sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, + (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ)); } else { - host->sdio_irq_mask = TMIO_SDIO_MASK_ALL; - sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL); sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); + host->sdio_irq_enabled = 0; } } @@ -247,7 +244,6 @@ static void tmio_mmc_reset_work(struct work_struct *work) /* Ready for new calls */ host->mrq = NULL; - tmio_mmc_abort_dma(host); mmc_request_done(host->mmc, mrq); } @@ -274,9 +270,6 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host) host->mrq = NULL; spin_unlock_irqrestore(&host->lock, flags); - if (mrq->cmd->error || (mrq->data && mrq->data->error)) - tmio_mmc_abort_dma(host); - mmc_request_done(host->mmc, mrq); } @@ -304,10 +297,9 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command { struct mmc_data *data = host->data; int c = cmd->opcode; - u32 irq_mask = TMIO_MASK_CMD; - /* CMD12 is handled by hardware */ - if (cmd->opcode == MMC_STOP_TRANSMISSION && !cmd->arg) { + /* Command 12 is handled by hardware */ + if (cmd->opcode == 12 && !cmd->arg) { sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001); return 0; } @@ -340,9 +332,7 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command c |= TRANSFER_READ; } - if (!host->native_hotplug) - irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); - tmio_mmc_enable_mmc_irqs(host, irq_mask); + tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_CMD); /* Fire off the command */ sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg); @@ -450,7 +440,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) } if (stop) { - if (stop->opcode == MMC_STOP_TRANSMISSION && !stop->arg) + if (stop->opcode == 12 && !stop->arg) sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000); else BUG(); @@ -553,20 +543,45 @@ out: spin_unlock(&host->lock); } -static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host, - int *ireg, int *status) +irqreturn_t tmio_mmc_irq(int irq, void *devid) { - *status = sd_ctrl_read32(host, CTL_STATUS); - *ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; + struct tmio_mmc_host *host = devid; + struct mmc_host *mmc = host->mmc; + struct tmio_mmc_data *pdata = host->pdata; + unsigned int ireg, irq_mask, status; + unsigned int sdio_ireg, sdio_irq_mask, sdio_status; - pr_debug_status(*status); - pr_debug_status(*ireg); -} + pr_debug("MMC IRQ begin\n"); -static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host, - int ireg, int status) -{ - struct mmc_host *mmc = host->mmc; + status = sd_ctrl_read32(host, CTL_STATUS); + irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); + ireg = status & TMIO_MASK_IRQ & ~irq_mask; + + sdio_ireg = 0; + if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { + sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); + sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK); + sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask; + + sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL); + + if (sdio_ireg && !host->sdio_irq_enabled) { + pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", + sdio_status, sdio_irq_mask, sdio_ireg); + tmio_mmc_enable_sdio_irq(mmc, 0); + goto out; + } + + if (mmc->caps & MMC_CAP_SDIO_IRQ && + sdio_ireg & TMIO_SDIO_STAT_IOIRQ) + mmc_signal_sdio_irq(mmc); + + if (sdio_ireg) + goto out; + } + + pr_debug_status(status); + pr_debug_status(ireg); /* Card insert / remove attempts */ if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { @@ -576,102 +591,43 @@ static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host, ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) && !work_pending(&mmc->detect.work)) mmc_detect_change(host->mmc, msecs_to_jiffies(100)); - return true; + goto out; } - return false; -} - -irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid) -{ - unsigned int ireg, status; - struct tmio_mmc_host *host = devid; - - tmio_mmc_card_irq_status(host, &ireg, &status); - __tmio_mmc_card_detect_irq(host, ireg, status); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL(tmio_mmc_card_detect_irq); + /* CRC and other errors */ +/* if (ireg & TMIO_STAT_ERR_IRQ) + * handled |= tmio_error_irq(host, irq, stat); + */ -static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, - int ireg, int status) -{ /* Command completion */ if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) { tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT); tmio_mmc_cmd_irq(host, status); - return true; + goto out; } /* Data transfer */ if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); tmio_mmc_pio_irq(host); - return true; + goto out; } /* Data transfer completion */ if (ireg & TMIO_STAT_DATAEND) { tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND); tmio_mmc_data_irq(host); - return true; + goto out; } - return false; -} - -irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid) -{ - unsigned int ireg, status; - struct tmio_mmc_host *host = devid; - - tmio_mmc_card_irq_status(host, &ireg, &status); - __tmio_mmc_sdcard_irq(host, ireg, status); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL(tmio_mmc_sdcard_irq); - -irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid) -{ - struct tmio_mmc_host *host = devid; - struct mmc_host *mmc = host->mmc; - struct tmio_mmc_data *pdata = host->pdata; - unsigned int ireg, status; - - if (!(pdata->flags & TMIO_MMC_SDIO_IRQ)) - return IRQ_HANDLED; - - status = sd_ctrl_read16(host, CTL_SDIO_STATUS); - ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask; - - sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL); - - if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ) - mmc_signal_sdio_irq(mmc); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL(tmio_mmc_sdio_irq); - -irqreturn_t tmio_mmc_irq(int irq, void *devid) -{ - struct tmio_mmc_host *host = devid; - unsigned int ireg, status; - - pr_debug("MMC IRQ begin\n"); - - tmio_mmc_card_irq_status(host, &ireg, &status); - if (__tmio_mmc_card_detect_irq(host, ireg, status)) - return IRQ_HANDLED; - if (__tmio_mmc_sdcard_irq(host, ireg, status)) - return IRQ_HANDLED; - - tmio_mmc_sdio_irq(irq, devid); + pr_warning("tmio_mmc: Spurious irq, disabling! " + "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); + pr_debug_status(status); + tmio_mmc_disable_mmc_irqs(host, status & ~irq_mask); +out: return IRQ_HANDLED; } EXPORT_SYMBOL(tmio_mmc_irq); @@ -752,34 +708,6 @@ fail: mmc_request_done(mmc, mrq); } -static int tmio_mmc_clk_update(struct mmc_host *mmc) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - struct tmio_mmc_data *pdata = host->pdata; - int ret; - - if (!pdata->clk_enable) - return -ENOTSUPP; - - ret = pdata->clk_enable(host->pdev, &mmc->f_max); - if (!ret) - mmc->f_min = mmc->f_max / 512; - - return ret; -} - -static void tmio_mmc_set_power(struct tmio_mmc_host *host, struct mmc_ios *ios) -{ - struct mmc_host *mmc = host->mmc; - - if (host->set_pwr) - host->set_pwr(host->pdev, ios->power_mode != MMC_POWER_OFF); - if (!IS_ERR(mmc->supply.vmmc)) - /* Errors ignored... */ - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, - ios->power_mode ? ios->vdd : 0); -} - /* Set MMC clock / power. * Note: This controller uses a simple divider scheme therefore it cannot * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as @@ -789,7 +717,7 @@ static void tmio_mmc_set_power(struct tmio_mmc_host *host, struct mmc_ios *ios) static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct tmio_mmc_host *host = mmc_priv(mmc); - struct device *dev = &host->pdev->dev; + struct tmio_mmc_data *pdata = host->pdata; unsigned long flags; mutex_lock(&host->ios_lock); @@ -797,13 +725,13 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_irqsave(&host->lock, flags); if (host->mrq) { if (IS_ERR(host->mrq)) { - dev_dbg(dev, + dev_dbg(&host->pdev->dev, "%s.%d: concurrent .set_ios(), clk %u, mode %u\n", current->comm, task_pid_nr(current), ios->clock, ios->power_mode); host->mrq = ERR_PTR(-EINTR); } else { - dev_dbg(dev, + dev_dbg(&host->pdev->dev, "%s.%d: CMD%u active since %lu, now %lu!\n", current->comm, task_pid_nr(current), host->mrq->cmd->opcode, host->last_req_ts, jiffies); @@ -819,44 +747,38 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_unlock_irqrestore(&host->lock, flags); /* - * host->power toggles between false and true in both cases - either - * or not the controller can be runtime-suspended during inactivity. - * But if the controller has to be kept on, the runtime-pm usage_count - * is kept positive, so no suspending actually takes place. + * pdata->power == false only if COLD_CD is available, otherwise only + * in short time intervals during probing or resuming */ if (ios->power_mode == MMC_POWER_ON && ios->clock) { - if (!host->power) { - tmio_mmc_clk_update(mmc); - pm_runtime_get_sync(dev); - host->power = true; + if (!pdata->power) { + pm_runtime_get_sync(&host->pdev->dev); + pdata->power = true; } tmio_mmc_set_clock(host, ios->clock); /* power up SD bus */ - tmio_mmc_set_power(host, ios); + if (host->set_pwr) + host->set_pwr(host->pdev, 1); /* start bus clock */ tmio_mmc_clk_start(host); } else if (ios->power_mode != MMC_POWER_UP) { - if (ios->power_mode == MMC_POWER_OFF) - tmio_mmc_set_power(host, ios); - if (host->power) { - struct tmio_mmc_data *pdata = host->pdata; - tmio_mmc_clk_stop(host); - host->power = false; - pm_runtime_put(dev); - if (pdata->clk_disable) - pdata->clk_disable(host->pdev); + if (host->set_pwr) + host->set_pwr(host->pdev, 0); + if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && + pdata->power) { + pdata->power = false; + pm_runtime_put(&host->pdev->dev); } + tmio_mmc_clk_stop(host); } - if (host->power) { - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); - break; - case MMC_BUS_WIDTH_4: - sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); - break; - } + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); + break; + case MMC_BUS_WIDTH_4: + sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); + break; } /* Let things settle. delay taken from winCE driver */ @@ -875,9 +797,6 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); struct tmio_mmc_data *pdata = host->pdata; - int ret = mmc_gpio_get_ro(mmc); - if (ret >= 0) - return ret; return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); @@ -887,9 +806,6 @@ static int tmio_mmc_get_cd(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); struct tmio_mmc_data *pdata = host->pdata; - int ret = mmc_gpio_get_cd(mmc); - if (ret >= 0) - return ret; if (!pdata->get_cd) return -ENOSYS; @@ -905,20 +821,7 @@ static const struct mmc_host_ops tmio_mmc_ops = { .enable_sdio_irq = tmio_mmc_enable_sdio_irq, }; -static void tmio_mmc_init_ocr(struct tmio_mmc_host *host) -{ - struct tmio_mmc_data *pdata = host->pdata; - struct mmc_host *mmc = host->mmc; - - mmc_regulator_get_supply(mmc); - - if (!mmc->ocr_avail) - mmc->ocr_avail = pdata->ocr_mask ? : MMC_VDD_32_33 | MMC_VDD_33_34; - else if (pdata->ocr_mask) - dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); -} - -int tmio_mmc_host_probe(struct tmio_mmc_host **host, +int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, struct platform_device *pdev, struct tmio_mmc_data *pdata) { @@ -957,61 +860,29 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, mmc->ops = &tmio_mmc_ops; mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities; - mmc->caps2 = pdata->capabilities2; + mmc->f_max = pdata->hclk; + mmc->f_min = mmc->f_max / 512; mmc->max_segs = 32; mmc->max_blk_size = 512; mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) * mmc->max_segs; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; - tmio_mmc_init_ocr(_host); - - _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD || - mmc->caps & MMC_CAP_NEEDS_POLL || - mmc->caps & MMC_CAP_NONREMOVABLE); + if (pdata->ocr_mask) + mmc->ocr_avail = pdata->ocr_mask; + else + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - _host->power = false; + pdata->power = false; pm_runtime_enable(&pdev->dev); ret = pm_runtime_resume(&pdev->dev); if (ret < 0) goto pm_disable; - if (tmio_mmc_clk_update(mmc) < 0) { - mmc->f_max = pdata->hclk; - mmc->f_min = mmc->f_max / 512; - } - - /* - * There are 4 different scenarios for the card detection: - * 1) an external gpio irq handles the cd (best for power savings) - * 2) internal sdhi irq handles the cd - * 3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL - * 4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE - * - * While we increment the runtime PM counter for all scenarios when - * the mmc core activates us by calling an appropriate set_ios(), we - * must additionally ensure that in case 2) the tmio mmc hardware stays - * powered on during runtime for the card detection to work. - */ - if (_host->native_hotplug) - pm_runtime_get_noresume(&pdev->dev); - tmio_mmc_clk_stop(_host); tmio_mmc_reset(_host); - _host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK); tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); - - /* Unmask the IRQs we want to know about */ - if (!_host->chan_rx) - irq_mask |= TMIO_MASK_READOP; - if (!_host->chan_tx) - irq_mask |= TMIO_MASK_WRITEOP; - if (!_host->native_hotplug) - irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); - - _host->sdcard_irq_mask &= ~irq_mask; - if (pdata->flags & TMIO_MMC_SDIO_IRQ) tmio_mmc_enable_sdio_irq(mmc, 0); @@ -1025,23 +896,21 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, /* See if we also get DMA */ tmio_mmc_request_dma(_host, pdata); - ret = mmc_add_host(mmc); - if (pdata->clk_disable) - pdata->clk_disable(pdev); - if (ret < 0) { - tmio_mmc_host_remove(_host); - return ret; + /* We have to keep the device powered for its card detection to work */ + if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD)) { + pdata->power = true; + pm_runtime_get_noresume(&pdev->dev); } - dev_pm_qos_expose_latency_limit(&pdev->dev, 100); + mmc_add_host(mmc); - if (pdata->flags & TMIO_MMC_USE_GPIO_CD) { - ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio); - if (ret < 0) { - tmio_mmc_host_remove(_host); - return ret; - } - } + /* Unmask the IRQs we want to know about */ + if (!_host->chan_rx) + irq_mask |= TMIO_MASK_READOP; + if (!_host->chan_tx) + irq_mask |= TMIO_MASK_WRITEOP; + + tmio_mmc_enable_mmc_irqs(_host, irq_mask); *host = _host; @@ -1060,22 +929,18 @@ EXPORT_SYMBOL(tmio_mmc_host_probe); void tmio_mmc_host_remove(struct tmio_mmc_host *host) { struct platform_device *pdev = host->pdev; - struct tmio_mmc_data *pdata = host->pdata; - struct mmc_host *mmc = host->mmc; - if (pdata->flags & TMIO_MMC_USE_GPIO_CD) - /* - * This means we can miss a card-eject, but this is anyway - * possible, because of delayed processing of hotplug events. - */ - mmc_gpio_free_cd(mmc); - - if (!host->native_hotplug) + /* + * We don't have to manipulate pdata->power here: if there is a card in + * the slot, the runtime PM is active and our .runtime_resume() will not + * be run. If there is no card in the slot and the platform can suspend + * the controller, the runtime PM is suspended and pdata->power == false, + * so, our .runtime_resume() will not try to detect a card in the slot. + */ + if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD) pm_runtime_get_sync(&pdev->dev); - dev_pm_qos_hide_latency_limit(&pdev->dev); - - mmc_remove_host(mmc); + mmc_remove_host(host->mmc); cancel_work_sync(&host->done); cancel_delayed_work_sync(&host->delayed_reset_work); tmio_mmc_release_dma(host); @@ -1084,7 +949,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) pm_runtime_disable(&pdev->dev); iounmap(host->ctl); - mmc_free_host(mmc); + mmc_free_host(host->mmc); } EXPORT_SYMBOL(tmio_mmc_host_remove); @@ -1098,6 +963,8 @@ int tmio_mmc_host_suspend(struct device *dev) if (!ret) tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL); + host->pm_error = pm_runtime_put_sync(dev); + return ret; } EXPORT_SYMBOL(tmio_mmc_host_suspend); @@ -1107,10 +974,20 @@ int tmio_mmc_host_resume(struct device *dev) struct mmc_host *mmc = dev_get_drvdata(dev); struct tmio_mmc_host *host = mmc_priv(mmc); - tmio_mmc_reset(host); - tmio_mmc_enable_dma(host, true); - /* The MMC core will perform the complete set up */ + host->pdata->power = false; + + host->pm_global = true; + if (!host->pm_error) + pm_runtime_get_sync(dev); + + if (host->pm_global) { + /* Runtime PM resume callback didn't run */ + tmio_mmc_reset(host); + tmio_mmc_enable_dma(host, true); + host->pm_global = false; + } + return mmc_resume_host(mmc); } EXPORT_SYMBOL(tmio_mmc_host_resume); @@ -1127,10 +1004,19 @@ int tmio_mmc_host_runtime_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct tmio_mmc_host *host = mmc_priv(mmc); + struct tmio_mmc_data *pdata = host->pdata; tmio_mmc_reset(host); tmio_mmc_enable_dma(host, true); + if (pdata->power) { + /* Only entered after a card-insert interrupt */ + if (!mmc->card) + tmio_mmc_set_ios(mmc, &mmc->ios); + mmc_detect_change(mmc, msecs_to_jiffies(100)); + } + host->pm_global = false; + return 0; } EXPORT_SYMBOL(tmio_mmc_host_runtime_resume); diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c index c0105a2e269..f08f944ac53 100644 --- a/drivers/mmc/host/ushc.c +++ b/drivers/mmc/host/ushc.c @@ -562,7 +562,17 @@ static struct usb_driver ushc_driver = { .disconnect = ushc_disconnect, }; -module_usb_driver(ushc_driver); +static int __init ushc_init(void) +{ + return usb_register(&ushc_driver); +} +module_init(ushc_init); + +static void __exit ushc_exit(void) +{ + usb_deregister(&ushc_driver); +} +module_exit(ushc_exit); MODULE_DESCRIPTION("USB SD Host Controller driver"); MODULE_AUTHOR("David Vrabel "); diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 4f84586c6e9..4dfe2c02ea9 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -1082,7 +1081,7 @@ static void via_init_mmc_host(struct via_crdr_mmc_host *host) msleep(1); } -static int via_sd_probe(struct pci_dev *pcidev, +static int __devinit via_sd_probe(struct pci_dev *pcidev, const struct pci_device_id *id) { struct mmc_host *mmc; @@ -1176,7 +1175,7 @@ disable: return ret; } -static void via_sd_remove(struct pci_dev *pcidev) +static void __devexit via_sd_remove(struct pci_dev *pcidev) { struct via_crdr_mmc_host *sdhost = pci_get_drvdata(pcidev); unsigned long flags; @@ -1192,7 +1191,7 @@ static void via_sd_remove(struct pci_dev *pcidev) mmiowb(); if (sdhost->mrq) { - pr_err("%s: Controller removed during " + printk(KERN_ERR "%s: Controller removed during " "transfer\n", mmc_hostname(sdhost->mmc)); /* make sure all DMA is stopped */ @@ -1332,12 +1331,26 @@ static struct pci_driver via_sd_driver = { .name = DRV_NAME, .id_table = via_ids, .probe = via_sd_probe, - .remove = via_sd_remove, + .remove = __devexit_p(via_sd_remove), .suspend = via_sd_suspend, .resume = via_sd_resume, }; -module_pci_driver(via_sd_driver); +static int __init via_sd_drv_init(void) +{ + pr_info(DRV_NAME ": VIA SD/MMC Card Reader driver " + "(C) 2008 VIA Technologies, Inc.\n"); + + return pci_register_driver(&via_sd_driver); +} + +static void __exit via_sd_drv_exit(void) +{ + pci_unregister_driver(&via_sd_driver); +} + +module_init(via_sd_drv_init); +module_exit(via_sd_drv_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("VIA Technologies Inc."); diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index cb9f361c03a..2ec978bc32b 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -223,25 +223,25 @@ enum SD_RESPONSE_TYPE { #define FUN(c) (0x000007 & (c->arg>>28)) #define REG(c) (0x01FFFF & (c->arg>>9)) -static bool limit_speed_to_24_MHz; +static int limit_speed_to_24_MHz; module_param(limit_speed_to_24_MHz, bool, 0644); MODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz"); -static bool pad_input_to_usb_pkt; +static int pad_input_to_usb_pkt; module_param(pad_input_to_usb_pkt, bool, 0644); MODULE_PARM_DESC(pad_input_to_usb_pkt, "Pad USB data input transfers to whole USB Packet"); -static bool disable_offload_processing; +static int disable_offload_processing; module_param(disable_offload_processing, bool, 0644); MODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing"); -static bool force_1_bit_data_xfers; +static int force_1_bit_data_xfers; module_param(force_1_bit_data_xfers, bool, 0644); MODULE_PARM_DESC(force_1_bit_data_xfers, "Force SDIO Data Transfers to 1-bit Mode"); -static bool force_polling_for_irqs; +static int force_polling_for_irqs; module_param(force_polling_for_irqs, bool, 0644); MODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts"); @@ -806,7 +806,7 @@ static void command_res_completed(struct urb *urb) * we suspect a buggy USB host controller */ } else if (!vub300->data) { - /* this means that the command (typically CMD52) succeeded */ + /* this means that the command (typically CMD52) suceeded */ } else if (vub300->resp.common.header_type != 0x02) { /* * this is an error response from the VUB300 chip @@ -2358,11 +2358,10 @@ error5: * which is contained at the end of struct mmc */ error4: - usb_free_urb(command_res_urb); -error1: usb_free_urb(command_out_urb); +error1: + usb_free_urb(command_res_urb); error0: - usb_put_dev(udev); return retval; } diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index e954b775887..62e5a4d171e 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -194,7 +194,7 @@ static void wbsd_reset(struct wbsd_host *host) { u8 setup; - pr_err("%s: Resetting chip\n", mmc_hostname(host->mmc)); + printk(KERN_ERR "%s: Resetting chip\n", mmc_hostname(host->mmc)); /* * Soft reset of chip (SD/MMC part). @@ -721,7 +721,7 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) * Any leftover data? */ if (count) { - pr_err("%s: Incomplete DMA transfer. " + printk(KERN_ERR "%s: Incomplete DMA transfer. " "%d bytes left.\n", mmc_hostname(host->mmc), count); @@ -803,7 +803,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) default: #ifdef CONFIG_MMC_DEBUG - pr_warning("%s: Data command %d is not " + printk(KERN_WARNING "%s: Data command %d is not " "supported by this controller.\n", mmc_hostname(host->mmc), cmd->opcode); #endif @@ -1029,7 +1029,7 @@ static void wbsd_tasklet_card(unsigned long param) host->flags &= ~WBSD_FCARD_PRESENT; if (host->mrq) { - pr_err("%s: Card removed during transfer!\n", + printk(KERN_ERR "%s: Card removed during transfer!\n", mmc_hostname(host->mmc)); wbsd_reset(host); @@ -1196,7 +1196,7 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id) * Allocate/free MMC structure. */ -static int wbsd_alloc_mmc(struct device *dev) +static int __devinit wbsd_alloc_mmc(struct device *dev) { struct mmc_host *mmc; struct wbsd_host *host; @@ -1288,7 +1288,7 @@ static void wbsd_free_mmc(struct device *dev) * Scan for known chip id:s */ -static int wbsd_scan(struct wbsd_host *host) +static int __devinit wbsd_scan(struct wbsd_host *host) { int i, j, k; int id; @@ -1344,7 +1344,7 @@ static int wbsd_scan(struct wbsd_host *host) * Allocate/free io port ranges */ -static int wbsd_request_region(struct wbsd_host *host, int base) +static int __devinit wbsd_request_region(struct wbsd_host *host, int base) { if (base & 0x7) return -EINVAL; @@ -1374,7 +1374,7 @@ static void wbsd_release_regions(struct wbsd_host *host) * Allocate/free DMA port and buffer */ -static void wbsd_request_dma(struct wbsd_host *host, int dma) +static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma) { if (dma < 0) return; @@ -1429,7 +1429,7 @@ free: free_dma(dma); err: - pr_warning(DRIVER_NAME ": Unable to allocate DMA %d. " + printk(KERN_WARNING DRIVER_NAME ": Unable to allocate DMA %d. " "Falling back on FIFO.\n", dma); } @@ -1452,7 +1452,7 @@ static void wbsd_release_dma(struct wbsd_host *host) * Allocate/free IRQ. */ -static int wbsd_request_irq(struct wbsd_host *host, int irq) +static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq) { int ret; @@ -1502,7 +1502,7 @@ static void wbsd_release_irq(struct wbsd_host *host) * Allocate all resources for the host. */ -static int wbsd_request_resources(struct wbsd_host *host, +static int __devinit wbsd_request_resources(struct wbsd_host *host, int base, int irq, int dma) { int ret; @@ -1644,7 +1644,7 @@ static void wbsd_chip_poweroff(struct wbsd_host *host) * * \*****************************************************************************/ -static int wbsd_init(struct device *dev, int base, int irq, int dma, +static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, int pnp) { struct wbsd_host *host = NULL; @@ -1664,7 +1664,7 @@ static int wbsd_init(struct device *dev, int base, int irq, int dma, ret = wbsd_scan(host); if (ret) { if (pnp && (ret == -ENODEV)) { - pr_warning(DRIVER_NAME + printk(KERN_WARNING DRIVER_NAME ": Unable to confirm device presence. You may " "experience lock-ups.\n"); } else { @@ -1688,7 +1688,7 @@ static int wbsd_init(struct device *dev, int base, int irq, int dma, */ if (pnp) { if ((host->config != 0) && !wbsd_chip_validate(host)) { - pr_warning(DRIVER_NAME + printk(KERN_WARNING DRIVER_NAME ": PnP active but chip not configured! " "You probably have a buggy BIOS. " "Configuring chip manually.\n"); @@ -1720,7 +1720,7 @@ static int wbsd_init(struct device *dev, int base, int irq, int dma, mmc_add_host(mmc); - pr_info("%s: W83L51xD", mmc_hostname(mmc)); + printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc)); if (host->chip_id != 0) printk(" id %x", (int)host->chip_id); printk(" at 0x%x irq %d", (int)host->base, (int)host->irq); @@ -1735,7 +1735,7 @@ static int wbsd_init(struct device *dev, int base, int irq, int dma, return 0; } -static void wbsd_shutdown(struct device *dev, int pnp) +static void __devexit wbsd_shutdown(struct device *dev, int pnp) { struct mmc_host *mmc = dev_get_drvdata(dev); struct wbsd_host *host; @@ -1762,13 +1762,13 @@ static void wbsd_shutdown(struct device *dev, int pnp) * Non-PnP */ -static int wbsd_probe(struct platform_device *dev) +static int __devinit wbsd_probe(struct platform_device *dev) { /* Use the module parameters for resources */ return wbsd_init(&dev->dev, param_io, param_irq, param_dma, 0); } -static int wbsd_remove(struct platform_device *dev) +static int __devexit wbsd_remove(struct platform_device *dev) { wbsd_shutdown(&dev->dev, 0); @@ -1781,7 +1781,7 @@ static int wbsd_remove(struct platform_device *dev) #ifdef CONFIG_PNP -static int +static int __devinit wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id) { int io, irq, dma; @@ -1801,7 +1801,7 @@ wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id) return wbsd_init(&pnpdev->dev, io, irq, dma, 1); } -static void wbsd_pnp_remove(struct pnp_dev *dev) +static void __devexit wbsd_pnp_remove(struct pnp_dev *dev) { wbsd_shutdown(&dev->dev, 1); } @@ -1909,7 +1909,7 @@ static int wbsd_pnp_resume(struct pnp_dev *pnp_dev) */ if (host->config != 0) { if (!wbsd_chip_validate(host)) { - pr_warning(DRIVER_NAME + printk(KERN_WARNING DRIVER_NAME ": PnP active but chip not configured! " "You probably have a buggy BIOS. " "Configuring chip manually.\n"); @@ -1941,7 +1941,7 @@ static struct platform_device *wbsd_device; static struct platform_driver wbsd_driver = { .probe = wbsd_probe, - .remove = wbsd_remove, + .remove = __devexit_p(wbsd_remove), .suspend = wbsd_platform_suspend, .resume = wbsd_platform_resume, @@ -1957,7 +1957,7 @@ static struct pnp_driver wbsd_pnp_driver = { .name = DRIVER_NAME, .id_table = pnp_dev_table, .probe = wbsd_pnp_probe, - .remove = wbsd_pnp_remove, + .remove = __devexit_p(wbsd_pnp_remove), .suspend = wbsd_pnp_suspend, .resume = wbsd_pnp_resume, @@ -1973,9 +1973,9 @@ static int __init wbsd_drv_init(void) { int result; - pr_info(DRIVER_NAME + printk(KERN_INFO DRIVER_NAME ": Winbond W83L51xD SD/MMC card interface driver\n"); - pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); + printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); #ifdef CONFIG_PNP diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c deleted file mode 100644 index 154f0e8e931..00000000000 --- a/drivers/mmc/host/wmt-sdmmc.c +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * WM8505/WM8650 SD/MMC Host Controller - * - * Copyright (C) 2010 Tony Prisk - * Copyright (C) 2008 WonderMedia Technologies, Inc. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include - - -#define DRIVER_NAME "wmt-sdhc" - - -/* MMC/SD controller registers */ -#define SDMMC_CTLR 0x00 -#define SDMMC_CMD 0x01 -#define SDMMC_RSPTYPE 0x02 -#define SDMMC_ARG 0x04 -#define SDMMC_BUSMODE 0x08 -#define SDMMC_BLKLEN 0x0C -#define SDMMC_BLKCNT 0x0E -#define SDMMC_RSP 0x10 -#define SDMMC_CBCR 0x20 -#define SDMMC_INTMASK0 0x24 -#define SDMMC_INTMASK1 0x25 -#define SDMMC_STS0 0x28 -#define SDMMC_STS1 0x29 -#define SDMMC_STS2 0x2A -#define SDMMC_STS3 0x2B -#define SDMMC_RSPTIMEOUT 0x2C -#define SDMMC_CLK 0x30 /* VT8500 only */ -#define SDMMC_EXTCTRL 0x34 -#define SDMMC_SBLKLEN 0x38 -#define SDMMC_DMATIMEOUT 0x3C - - -/* SDMMC_CTLR bit fields */ -#define CTLR_CMD_START 0x01 -#define CTLR_CMD_WRITE 0x04 -#define CTLR_FIFO_RESET 0x08 - -/* SDMMC_BUSMODE bit fields */ -#define BM_SPI_MODE 0x01 -#define BM_FOURBIT_MODE 0x02 -#define BM_EIGHTBIT_MODE 0x04 -#define BM_SD_OFF 0x10 -#define BM_SPI_CS 0x20 -#define BM_SD_POWER 0x40 -#define BM_SOFT_RESET 0x80 -#define BM_ONEBIT_MASK 0xFD - -/* SDMMC_BLKLEN bit fields */ -#define BLKL_CRCERR_ABORT 0x0800 -#define BLKL_CD_POL_HIGH 0x1000 -#define BLKL_GPI_CD 0x2000 -#define BLKL_DATA3_CD 0x4000 -#define BLKL_INT_ENABLE 0x8000 - -/* SDMMC_INTMASK0 bit fields */ -#define INT0_MBLK_TRAN_DONE_INT_EN 0x10 -#define INT0_BLK_TRAN_DONE_INT_EN 0x20 -#define INT0_CD_INT_EN 0x40 -#define INT0_DI_INT_EN 0x80 - -/* SDMMC_INTMASK1 bit fields */ -#define INT1_CMD_RES_TRAN_DONE_INT_EN 0x02 -#define INT1_CMD_RES_TOUT_INT_EN 0x04 -#define INT1_MBLK_AUTO_STOP_INT_EN 0x08 -#define INT1_DATA_TOUT_INT_EN 0x10 -#define INT1_RESCRC_ERR_INT_EN 0x20 -#define INT1_RCRC_ERR_INT_EN 0x40 -#define INT1_WCRC_ERR_INT_EN 0x80 - -/* SDMMC_STS0 bit fields */ -#define STS0_WRITE_PROTECT 0x02 -#define STS0_CD_DATA3 0x04 -#define STS0_CD_GPI 0x08 -#define STS0_MBLK_DONE 0x10 -#define STS0_BLK_DONE 0x20 -#define STS0_CARD_DETECT 0x40 -#define STS0_DEVICE_INS 0x80 - -/* SDMMC_STS1 bit fields */ -#define STS1_SDIO_INT 0x01 -#define STS1_CMDRSP_DONE 0x02 -#define STS1_RSP_TIMEOUT 0x04 -#define STS1_AUTOSTOP_DONE 0x08 -#define STS1_DATA_TIMEOUT 0x10 -#define STS1_RSP_CRC_ERR 0x20 -#define STS1_RCRC_ERR 0x40 -#define STS1_WCRC_ERR 0x80 - -/* SDMMC_STS2 bit fields */ -#define STS2_CMD_RES_BUSY 0x10 -#define STS2_DATARSP_BUSY 0x20 -#define STS2_DIS_FORCECLK 0x80 - - -/* MMC/SD DMA Controller Registers */ -#define SDDMA_GCR 0x100 -#define SDDMA_IER 0x104 -#define SDDMA_ISR 0x108 -#define SDDMA_DESPR 0x10C -#define SDDMA_RBR 0x110 -#define SDDMA_DAR 0x114 -#define SDDMA_BAR 0x118 -#define SDDMA_CPR 0x11C -#define SDDMA_CCR 0x120 - - -/* SDDMA_GCR bit fields */ -#define DMA_GCR_DMA_EN 0x00000001 -#define DMA_GCR_SOFT_RESET 0x00000100 - -/* SDDMA_IER bit fields */ -#define DMA_IER_INT_EN 0x00000001 - -/* SDDMA_ISR bit fields */ -#define DMA_ISR_INT_STS 0x00000001 - -/* SDDMA_RBR bit fields */ -#define DMA_RBR_FORMAT 0x40000000 -#define DMA_RBR_END 0x80000000 - -/* SDDMA_CCR bit fields */ -#define DMA_CCR_RUN 0x00000080 -#define DMA_CCR_IF_TO_PERIPHERAL 0x00000000 -#define DMA_CCR_PERIPHERAL_TO_IF 0x00400000 - -/* SDDMA_CCR event status */ -#define DMA_CCR_EVT_NO_STATUS 0x00000000 -#define DMA_CCR_EVT_UNDERRUN 0x00000001 -#define DMA_CCR_EVT_OVERRUN 0x00000002 -#define DMA_CCR_EVT_DESP_READ 0x00000003 -#define DMA_CCR_EVT_DATA_RW 0x00000004 -#define DMA_CCR_EVT_EARLY_END 0x00000005 -#define DMA_CCR_EVT_SUCCESS 0x0000000F - -#define PDMA_READ 0x00 -#define PDMA_WRITE 0x01 - -#define WMT_SD_POWER_OFF 0 -#define WMT_SD_POWER_ON 1 - -struct wmt_dma_descriptor { - u32 flags; - u32 data_buffer_addr; - u32 branch_addr; - u32 reserved1; -}; - -struct wmt_mci_caps { - unsigned int f_min; - unsigned int f_max; - u32 ocr_avail; - u32 caps; - u32 max_seg_size; - u32 max_segs; - u32 max_blk_size; -}; - -struct wmt_mci_priv { - struct mmc_host *mmc; - void __iomem *sdmmc_base; - - int irq_regular; - int irq_dma; - - void *dma_desc_buffer; - dma_addr_t dma_desc_device_addr; - - struct completion cmdcomp; - struct completion datacomp; - - struct completion *comp_cmd; - struct completion *comp_dma; - - struct mmc_request *req; - struct mmc_command *cmd; - - struct clk *clk_sdmmc; - struct device *dev; - - u8 power_inverted; - u8 cd_inverted; -}; - -static void wmt_set_sd_power(struct wmt_mci_priv *priv, int enable) -{ - u32 reg_tmp; - if (enable) { - if (priv->power_inverted) { - reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); - writeb(reg_tmp | BM_SD_OFF, - priv->sdmmc_base + SDMMC_BUSMODE); - } else { - reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); - writeb(reg_tmp & (~BM_SD_OFF), - priv->sdmmc_base + SDMMC_BUSMODE); - } - } else { - if (priv->power_inverted) { - reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); - writeb(reg_tmp & (~BM_SD_OFF), - priv->sdmmc_base + SDMMC_BUSMODE); - } else { - reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); - writeb(reg_tmp | BM_SD_OFF, - priv->sdmmc_base + SDMMC_BUSMODE); - } - } -} - -static void wmt_mci_read_response(struct mmc_host *mmc) -{ - struct wmt_mci_priv *priv; - int idx1, idx2; - u8 tmp_resp; - u32 response; - - priv = mmc_priv(mmc); - - for (idx1 = 0; idx1 < 4; idx1++) { - response = 0; - for (idx2 = 0; idx2 < 4; idx2++) { - if ((idx1 == 3) && (idx2 == 3)) - tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP); - else - tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP + - (idx1*4) + idx2 + 1); - response |= (tmp_resp << (idx2 * 8)); - } - priv->cmd->resp[idx1] = cpu_to_be32(response); - } -} - -static void wmt_mci_start_command(struct wmt_mci_priv *priv) -{ - u32 reg_tmp; - - reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); - writeb(reg_tmp | CTLR_CMD_START, priv->sdmmc_base + SDMMC_CTLR); -} - -static int wmt_mci_send_command(struct mmc_host *mmc, u8 command, u8 cmdtype, - u32 arg, u8 rsptype) -{ - struct wmt_mci_priv *priv; - u32 reg_tmp; - - priv = mmc_priv(mmc); - - /* write command, arg, resptype registers */ - writeb(command, priv->sdmmc_base + SDMMC_CMD); - writel(arg, priv->sdmmc_base + SDMMC_ARG); - writeb(rsptype, priv->sdmmc_base + SDMMC_RSPTYPE); - - /* reset response FIFO */ - reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); - writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR); - - /* ensure clock enabled - VT3465 */ - wmt_set_sd_power(priv, WMT_SD_POWER_ON); - - /* clear status bits */ - writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); - writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); - writeb(0xFF, priv->sdmmc_base + SDMMC_STS2); - writeb(0xFF, priv->sdmmc_base + SDMMC_STS3); - - /* set command type */ - reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); - writeb((reg_tmp & 0x0F) | (cmdtype << 4), - priv->sdmmc_base + SDMMC_CTLR); - - return 0; -} - -static void wmt_mci_disable_dma(struct wmt_mci_priv *priv) -{ - writel(DMA_ISR_INT_STS, priv->sdmmc_base + SDDMA_ISR); - writel(0, priv->sdmmc_base + SDDMA_IER); -} - -static void wmt_complete_data_request(struct wmt_mci_priv *priv) -{ - struct mmc_request *req; - req = priv->req; - - req->data->bytes_xfered = req->data->blksz * req->data->blocks; - - /* unmap the DMA pages used for write data */ - if (req->data->flags & MMC_DATA_WRITE) - dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg, - req->data->sg_len, DMA_TO_DEVICE); - else - dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg, - req->data->sg_len, DMA_FROM_DEVICE); - - /* Check if the DMA ISR returned a data error */ - if ((req->cmd->error) || (req->data->error)) - mmc_request_done(priv->mmc, req); - else { - wmt_mci_read_response(priv->mmc); - if (!req->data->stop) { - /* single-block read/write requests end here */ - mmc_request_done(priv->mmc, req); - } else { - /* - * we change the priv->cmd variable so the response is - * stored in the stop struct rather than the original - * calling command struct - */ - priv->comp_cmd = &priv->cmdcomp; - init_completion(priv->comp_cmd); - priv->cmd = req->data->stop; - wmt_mci_send_command(priv->mmc, req->data->stop->opcode, - 7, req->data->stop->arg, 9); - wmt_mci_start_command(priv); - } - } -} - -static irqreturn_t wmt_mci_dma_isr(int irq_num, void *data) -{ - struct mmc_host *mmc; - struct wmt_mci_priv *priv; - - int status; - - priv = (struct wmt_mci_priv *)data; - mmc = priv->mmc; - - status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F; - - if (status != DMA_CCR_EVT_SUCCESS) { - dev_err(priv->dev, "DMA Error: Status = %d\n", status); - priv->req->data->error = -ETIMEDOUT; - complete(priv->comp_dma); - return IRQ_HANDLED; - } - - priv->req->data->error = 0; - - wmt_mci_disable_dma(priv); - - complete(priv->comp_dma); - - if (priv->comp_cmd) { - if (completion_done(priv->comp_cmd)) { - /* - * if the command (regular) interrupt has already - * completed, finish off the request otherwise we wait - * for the command interrupt and finish from there. - */ - wmt_complete_data_request(priv); - } - } - - return IRQ_HANDLED; -} - -static irqreturn_t wmt_mci_regular_isr(int irq_num, void *data) -{ - struct wmt_mci_priv *priv; - u32 status0; - u32 status1; - u32 status2; - u32 reg_tmp; - int cmd_done; - - priv = (struct wmt_mci_priv *)data; - cmd_done = 0; - status0 = readb(priv->sdmmc_base + SDMMC_STS0); - status1 = readb(priv->sdmmc_base + SDMMC_STS1); - status2 = readb(priv->sdmmc_base + SDMMC_STS2); - - /* Check for card insertion */ - reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0); - if ((reg_tmp & INT0_DI_INT_EN) && (status0 & STS0_DEVICE_INS)) { - mmc_detect_change(priv->mmc, 0); - if (priv->cmd) - priv->cmd->error = -ETIMEDOUT; - if (priv->comp_cmd) - complete(priv->comp_cmd); - if (priv->comp_dma) { - wmt_mci_disable_dma(priv); - complete(priv->comp_dma); - } - writeb(STS0_DEVICE_INS, priv->sdmmc_base + SDMMC_STS0); - return IRQ_HANDLED; - } - - if ((!priv->req->data) || - ((priv->req->data->stop) && (priv->cmd == priv->req->data->stop))) { - /* handle non-data & stop_transmission requests */ - if (status1 & STS1_CMDRSP_DONE) { - priv->cmd->error = 0; - cmd_done = 1; - } else if ((status1 & STS1_RSP_TIMEOUT) || - (status1 & STS1_DATA_TIMEOUT)) { - priv->cmd->error = -ETIMEDOUT; - cmd_done = 1; - } - - if (cmd_done) { - priv->comp_cmd = NULL; - - if (!priv->cmd->error) - wmt_mci_read_response(priv->mmc); - - priv->cmd = NULL; - - mmc_request_done(priv->mmc, priv->req); - } - } else { - /* handle data requests */ - if (status1 & STS1_CMDRSP_DONE) { - if (priv->cmd) - priv->cmd->error = 0; - if (priv->comp_cmd) - complete(priv->comp_cmd); - } - - if ((status1 & STS1_RSP_TIMEOUT) || - (status1 & STS1_DATA_TIMEOUT)) { - if (priv->cmd) - priv->cmd->error = -ETIMEDOUT; - if (priv->comp_cmd) - complete(priv->comp_cmd); - if (priv->comp_dma) { - wmt_mci_disable_dma(priv); - complete(priv->comp_dma); - } - } - - if (priv->comp_dma) { - /* - * If the dma interrupt has already completed, finish - * off the request; otherwise we wait for the DMA - * interrupt and finish from there. - */ - if (completion_done(priv->comp_dma)) - wmt_complete_data_request(priv); - } - } - - writeb(status0, priv->sdmmc_base + SDMMC_STS0); - writeb(status1, priv->sdmmc_base + SDMMC_STS1); - writeb(status2, priv->sdmmc_base + SDMMC_STS2); - - return IRQ_HANDLED; -} - -static void wmt_reset_hardware(struct mmc_host *mmc) -{ - struct wmt_mci_priv *priv; - u32 reg_tmp; - - priv = mmc_priv(mmc); - - /* reset controller */ - reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); - writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE); - - /* reset response FIFO */ - reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); - writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR); - - /* enable GPI pin to detect card */ - writew(BLKL_INT_ENABLE | BLKL_GPI_CD, priv->sdmmc_base + SDMMC_BLKLEN); - - /* clear interrupt status */ - writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); - writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); - - /* setup interrupts */ - writeb(INT0_CD_INT_EN | INT0_DI_INT_EN, priv->sdmmc_base + - SDMMC_INTMASK0); - writeb(INT1_DATA_TOUT_INT_EN | INT1_CMD_RES_TRAN_DONE_INT_EN | - INT1_CMD_RES_TOUT_INT_EN, priv->sdmmc_base + SDMMC_INTMASK1); - - /* set the DMA timeout */ - writew(8191, priv->sdmmc_base + SDMMC_DMATIMEOUT); - - /* auto clock freezing enable */ - reg_tmp = readb(priv->sdmmc_base + SDMMC_STS2); - writeb(reg_tmp | STS2_DIS_FORCECLK, priv->sdmmc_base + SDMMC_STS2); - - /* set a default clock speed of 400Khz */ - clk_set_rate(priv->clk_sdmmc, 400000); -} - -static int wmt_dma_init(struct mmc_host *mmc) -{ - struct wmt_mci_priv *priv; - - priv = mmc_priv(mmc); - - writel(DMA_GCR_SOFT_RESET, priv->sdmmc_base + SDDMA_GCR); - writel(DMA_GCR_DMA_EN, priv->sdmmc_base + SDDMA_GCR); - if ((readl(priv->sdmmc_base + SDDMA_GCR) & DMA_GCR_DMA_EN) != 0) - return 0; - else - return 1; -} - -static void wmt_dma_init_descriptor(struct wmt_dma_descriptor *desc, - u16 req_count, u32 buffer_addr, u32 branch_addr, int end) -{ - desc->flags = 0x40000000 | req_count; - if (end) - desc->flags |= 0x80000000; - desc->data_buffer_addr = buffer_addr; - desc->branch_addr = branch_addr; -} - -static void wmt_dma_config(struct mmc_host *mmc, u32 descaddr, u8 dir) -{ - struct wmt_mci_priv *priv; - u32 reg_tmp; - - priv = mmc_priv(mmc); - - /* Enable DMA Interrupts */ - writel(DMA_IER_INT_EN, priv->sdmmc_base + SDDMA_IER); - - /* Write DMA Descriptor Pointer Register */ - writel(descaddr, priv->sdmmc_base + SDDMA_DESPR); - - writel(0x00, priv->sdmmc_base + SDDMA_CCR); - - if (dir == PDMA_WRITE) { - reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); - writel(reg_tmp & DMA_CCR_IF_TO_PERIPHERAL, priv->sdmmc_base + - SDDMA_CCR); - } else { - reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); - writel(reg_tmp | DMA_CCR_PERIPHERAL_TO_IF, priv->sdmmc_base + - SDDMA_CCR); - } -} - -static void wmt_dma_start(struct wmt_mci_priv *priv) -{ - u32 reg_tmp; - - reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); - writel(reg_tmp | DMA_CCR_RUN, priv->sdmmc_base + SDDMA_CCR); -} - -static void wmt_mci_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct wmt_mci_priv *priv; - struct wmt_dma_descriptor *desc; - u8 command; - u8 cmdtype; - u32 arg; - u8 rsptype; - u32 reg_tmp; - - struct scatterlist *sg; - int i; - int sg_cnt; - int offset; - u32 dma_address; - int desc_cnt; - - priv = mmc_priv(mmc); - priv->req = req; - - /* - * Use the cmd variable to pass a pointer to the resp[] structure - * This is required on multi-block requests to pass the pointer to the - * stop command - */ - priv->cmd = req->cmd; - - command = req->cmd->opcode; - arg = req->cmd->arg; - rsptype = mmc_resp_type(req->cmd); - cmdtype = 0; - - /* rsptype=7 only valid for SPI commands - should be =2 for SD */ - if (rsptype == 7) - rsptype = 2; - /* rsptype=21 is R1B, convert for controller */ - if (rsptype == 21) - rsptype = 9; - - if (!req->data) { - wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype); - wmt_mci_start_command(priv); - /* completion is now handled in the regular_isr() */ - } - if (req->data) { - priv->comp_cmd = &priv->cmdcomp; - init_completion(priv->comp_cmd); - - wmt_dma_init(mmc); - - /* set controller data length */ - reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); - writew((reg_tmp & 0xF800) | (req->data->blksz - 1), - priv->sdmmc_base + SDMMC_BLKLEN); - - /* set controller block count */ - writew(req->data->blocks, priv->sdmmc_base + SDMMC_BLKCNT); - - desc = (struct wmt_dma_descriptor *)priv->dma_desc_buffer; - - if (req->data->flags & MMC_DATA_WRITE) { - sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg, - req->data->sg_len, DMA_TO_DEVICE); - cmdtype = 1; - if (req->data->blocks > 1) - cmdtype = 3; - } else { - sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg, - req->data->sg_len, DMA_FROM_DEVICE); - cmdtype = 2; - if (req->data->blocks > 1) - cmdtype = 4; - } - - dma_address = priv->dma_desc_device_addr + 16; - desc_cnt = 0; - - for_each_sg(req->data->sg, sg, sg_cnt, i) { - offset = 0; - while (offset < sg_dma_len(sg)) { - wmt_dma_init_descriptor(desc, req->data->blksz, - sg_dma_address(sg)+offset, - dma_address, 0); - desc++; - desc_cnt++; - offset += req->data->blksz; - dma_address += 16; - if (desc_cnt == req->data->blocks) - break; - } - } - desc--; - desc->flags |= 0x80000000; - - if (req->data->flags & MMC_DATA_WRITE) - wmt_dma_config(mmc, priv->dma_desc_device_addr, - PDMA_WRITE); - else - wmt_dma_config(mmc, priv->dma_desc_device_addr, - PDMA_READ); - - wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype); - - priv->comp_dma = &priv->datacomp; - init_completion(priv->comp_dma); - - wmt_dma_start(priv); - wmt_mci_start_command(priv); - } -} - -static void wmt_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct wmt_mci_priv *priv; - u32 reg_tmp; - - priv = mmc_priv(mmc); - - if (ios->power_mode == MMC_POWER_UP) { - wmt_reset_hardware(mmc); - - wmt_set_sd_power(priv, WMT_SD_POWER_ON); - } - if (ios->power_mode == MMC_POWER_OFF) - wmt_set_sd_power(priv, WMT_SD_POWER_OFF); - - if (ios->clock != 0) - clk_set_rate(priv->clk_sdmmc, ios->clock); - - switch (ios->bus_width) { - case MMC_BUS_WIDTH_8: - reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); - writeb(reg_tmp | 0x04, priv->sdmmc_base + SDMMC_EXTCTRL); - break; - case MMC_BUS_WIDTH_4: - reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); - writeb(reg_tmp | BM_FOURBIT_MODE, priv->sdmmc_base + - SDMMC_BUSMODE); - - reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); - writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL); - break; - case MMC_BUS_WIDTH_1: - reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); - writeb(reg_tmp & BM_ONEBIT_MASK, priv->sdmmc_base + - SDMMC_BUSMODE); - - reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); - writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL); - break; - } -} - -static int wmt_mci_get_ro(struct mmc_host *mmc) -{ - struct wmt_mci_priv *priv = mmc_priv(mmc); - - return !(readb(priv->sdmmc_base + SDMMC_STS0) & STS0_WRITE_PROTECT); -} - -static int wmt_mci_get_cd(struct mmc_host *mmc) -{ - struct wmt_mci_priv *priv = mmc_priv(mmc); - u32 cd = (readb(priv->sdmmc_base + SDMMC_STS0) & STS0_CD_GPI) >> 3; - - return !(cd ^ priv->cd_inverted); -} - -static struct mmc_host_ops wmt_mci_ops = { - .request = wmt_mci_request, - .set_ios = wmt_mci_set_ios, - .get_ro = wmt_mci_get_ro, - .get_cd = wmt_mci_get_cd, -}; - -/* Controller capabilities */ -static struct wmt_mci_caps wm8505_caps = { - .f_min = 390425, - .f_max = 50000000, - .ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34, - .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_SD_HIGHSPEED, - .max_seg_size = 65024, - .max_segs = 128, - .max_blk_size = 2048, -}; - -static struct of_device_id wmt_mci_dt_ids[] = { - { .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps }, - { /* Sentinel */ }, -}; - -static int wmt_mci_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct wmt_mci_priv *priv; - struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id = - of_match_device(wmt_mci_dt_ids, &pdev->dev); - const struct wmt_mci_caps *wmt_caps = of_id->data; - int ret; - int regular_irq, dma_irq; - - if (!of_id || !of_id->data) { - dev_err(&pdev->dev, "Controller capabilities data missing\n"); - return -EFAULT; - } - - if (!np) { - dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n"); - return -EFAULT; - } - - regular_irq = irq_of_parse_and_map(np, 0); - dma_irq = irq_of_parse_and_map(np, 1); - - if (!regular_irq || !dma_irq) { - dev_err(&pdev->dev, "Getting IRQs failed!\n"); - ret = -ENXIO; - goto fail1; - } - - mmc = mmc_alloc_host(sizeof(struct wmt_mci_priv), &pdev->dev); - if (!mmc) { - dev_err(&pdev->dev, "Failed to allocate mmc_host\n"); - ret = -ENOMEM; - goto fail1; - } - - mmc->ops = &wmt_mci_ops; - mmc->f_min = wmt_caps->f_min; - mmc->f_max = wmt_caps->f_max; - mmc->ocr_avail = wmt_caps->ocr_avail; - mmc->caps = wmt_caps->caps; - - mmc->max_seg_size = wmt_caps->max_seg_size; - mmc->max_segs = wmt_caps->max_segs; - mmc->max_blk_size = wmt_caps->max_blk_size; - - mmc->max_req_size = (16*512*mmc->max_segs); - mmc->max_blk_count = mmc->max_req_size / 512; - - priv = mmc_priv(mmc); - priv->mmc = mmc; - priv->dev = &pdev->dev; - - priv->power_inverted = 0; - priv->cd_inverted = 0; - - if (of_get_property(np, "sdon-inverted", NULL)) - priv->power_inverted = 1; - if (of_get_property(np, "cd-inverted", NULL)) - priv->cd_inverted = 1; - - priv->sdmmc_base = of_iomap(np, 0); - if (!priv->sdmmc_base) { - dev_err(&pdev->dev, "Failed to map IO space\n"); - ret = -ENOMEM; - goto fail2; - } - - priv->irq_regular = regular_irq; - priv->irq_dma = dma_irq; - - ret = request_irq(regular_irq, wmt_mci_regular_isr, 0, "sdmmc", priv); - if (ret) { - dev_err(&pdev->dev, "Register regular IRQ fail\n"); - goto fail3; - } - - ret = request_irq(dma_irq, wmt_mci_dma_isr, 32, "sdmmc", priv); - if (ret) { - dev_err(&pdev->dev, "Register DMA IRQ fail\n"); - goto fail4; - } - - /* alloc some DMA buffers for descriptors/transfers */ - priv->dma_desc_buffer = dma_alloc_coherent(&pdev->dev, - mmc->max_blk_count * 16, - &priv->dma_desc_device_addr, - 208); - if (!priv->dma_desc_buffer) { - dev_err(&pdev->dev, "DMA alloc fail\n"); - ret = -EPERM; - goto fail5; - } - - platform_set_drvdata(pdev, mmc); - - priv->clk_sdmmc = of_clk_get(np, 0); - if (IS_ERR(priv->clk_sdmmc)) { - dev_err(&pdev->dev, "Error getting clock\n"); - ret = PTR_ERR(priv->clk_sdmmc); - goto fail5; - } - - clk_prepare_enable(priv->clk_sdmmc); - - /* configure the controller to a known 'ready' state */ - wmt_reset_hardware(mmc); - - mmc_add_host(mmc); - - dev_info(&pdev->dev, "WMT SDHC Controller initialized\n"); - - return 0; -fail5: - free_irq(dma_irq, priv); -fail4: - free_irq(regular_irq, priv); -fail3: - iounmap(priv->sdmmc_base); -fail2: - mmc_free_host(mmc); -fail1: - return ret; -} - -static int wmt_mci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct wmt_mci_priv *priv; - struct resource *res; - u32 reg_tmp; - - mmc = platform_get_drvdata(pdev); - priv = mmc_priv(mmc); - - /* reset SD controller */ - reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); - writel(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE); - reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); - writew(reg_tmp & ~(0xA000), priv->sdmmc_base + SDMMC_BLKLEN); - writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); - writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); - - /* release the dma buffers */ - dma_free_coherent(&pdev->dev, priv->mmc->max_blk_count * 16, - priv->dma_desc_buffer, priv->dma_desc_device_addr); - - mmc_remove_host(mmc); - - free_irq(priv->irq_regular, priv); - free_irq(priv->irq_dma, priv); - - iounmap(priv->sdmmc_base); - - clk_disable_unprepare(priv->clk_sdmmc); - clk_put(priv->clk_sdmmc); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); - - mmc_free_host(mmc); - - platform_set_drvdata(pdev, NULL); - - dev_info(&pdev->dev, "WMT MCI device removed\n"); - - return 0; -} - -#ifdef CONFIG_PM -static int wmt_mci_suspend(struct device *dev) -{ - u32 reg_tmp; - struct platform_device *pdev = to_platform_device(dev); - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct wmt_mci_priv *priv; - int ret; - - if (!mmc) - return 0; - - priv = mmc_priv(mmc); - ret = mmc_suspend_host(mmc); - - if (!ret) { - reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); - writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + - SDMMC_BUSMODE); - - reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); - writew(reg_tmp & 0x5FFF, priv->sdmmc_base + SDMMC_BLKLEN); - - writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); - writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); - - clk_disable(priv->clk_sdmmc); - } - return ret; -} - -static int wmt_mci_resume(struct device *dev) -{ - u32 reg_tmp; - struct platform_device *pdev = to_platform_device(dev); - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct wmt_mci_priv *priv; - int ret = 0; - - if (mmc) { - priv = mmc_priv(mmc); - clk_enable(priv->clk_sdmmc); - - reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); - writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + - SDMMC_BUSMODE); - - reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); - writew(reg_tmp | (BLKL_GPI_CD | BLKL_INT_ENABLE), - priv->sdmmc_base + SDMMC_BLKLEN); - - reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0); - writeb(reg_tmp | INT0_DI_INT_EN, priv->sdmmc_base + - SDMMC_INTMASK0); - - ret = mmc_resume_host(mmc); - } - - return ret; -} - -static const struct dev_pm_ops wmt_mci_pm = { - .suspend = wmt_mci_suspend, - .resume = wmt_mci_resume, -}; - -#define wmt_mci_pm_ops (&wmt_mci_pm) - -#else /* !CONFIG_PM */ - -#define wmt_mci_pm_ops NULL - -#endif - -static struct platform_driver wmt_mci_driver = { - .probe = wmt_mci_probe, - .remove = __exit_p(wmt_mci_remove), - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .pm = wmt_mci_pm_ops, - .of_match_table = wmt_mci_dt_ids, - }, -}; - -module_platform_driver(wmt_mci_driver); - -MODULE_DESCRIPTION("Wondermedia MMC/SD Driver"); -MODULE_AUTHOR("Tony Prisk"); -MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(of, wmt_mci_dt_ids); -- cgit v1.2.2