diff options
Diffstat (limited to 'drivers/mmc')
80 files changed, 5635 insertions, 2634 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 1fa4c80ff886..c69afb5e264e 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -78,13 +78,16 @@ static int perdev_minors = CONFIG_MMC_BLOCK_MINORS; /* * We've only got one major, so number of mmcblk devices is - * limited to 256 / number of minors per device. + * limited to (1 << 20) / number of minors per device. It is also + * currently limited by the size of the static bitmaps below. */ static int max_devices; -/* 256 minors, so at most 256 separate devices */ -static DECLARE_BITMAP(dev_use, 256); -static DECLARE_BITMAP(name_use, 256); +#define MAX_DEVICES 256 + +/* TODO: Replace these with struct ida */ +static DECLARE_BITMAP(dev_use, MAX_DEVICES); +static DECLARE_BITMAP(name_use, MAX_DEVICES); /* * There is one mmc_blk_data per slot. @@ -112,7 +115,7 @@ struct mmc_blk_data { /* * Only set in main mmc_blk_data associated - * with mmc_card with mmc_set_drvdata, and keeps + * with mmc_card with dev_set_drvdata, and keeps * track of the current selected device partition. */ unsigned int part_curr; @@ -260,7 +263,7 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, int ret; struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); - ret = snprintf(buf, PAGE_SIZE, "%d", + ret = snprintf(buf, PAGE_SIZE, "%d\n", get_disk_ro(dev_to_disk(dev)) ^ md->read_only); mmc_blk_put(md); @@ -642,7 +645,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, struct mmc_blk_data *md) { int ret; - struct mmc_blk_data *main_md = mmc_get_drvdata(card); + struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev); if (main_md->part_curr == md->part_type) return 0; @@ -1004,7 +1007,8 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, 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); + struct mmc_blk_data *main_md = + dev_get_drvdata(&host->card->dev); int part_err; main_md->part_curr = main_md->part_type; @@ -1308,19 +1312,11 @@ static int mmc_blk_packed_err_check(struct mmc_card *card, } if (status & R1_EXCEPTION_EVENT) { - ext_csd = kzalloc(512, GFP_KERNEL); - if (!ext_csd) { - pr_err("%s: unable to allocate buffer for ext_csd\n", - req->rq_disk->disk_name); - return -ENOMEM; - } - - err = mmc_send_ext_csd(card, ext_csd); + err = mmc_get_ext_csd(card, &ext_csd); if (err) { pr_err("%s: error %d sending ext_csd\n", req->rq_disk->disk_name, err); - check = MMC_BLK_ABORT; - goto free; + return MMC_BLK_ABORT; } if ((ext_csd[EXT_CSD_EXP_EVENTS_STATUS] & @@ -1338,7 +1334,6 @@ static int mmc_blk_packed_err_check(struct mmc_card *card, req->rq_disk->disk_name, packed->nr_entries, packed->blocks, packed->idx_failure); } -free: kfree(ext_csd); } @@ -2093,7 +2088,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, /* * !subname implies we are creating main mmc_blk_data that will be - * associated with mmc_card with mmc_set_drvdata. Due to device + * associated with mmc_card with dev_set_drvdata. Due to device * partitions, devidx will not coincide with a per-physical card * index anymore so we keep track of a name index. */ @@ -2152,7 +2147,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 : ""); + "mmcblk%u%s", md->name_idx, subname ? subname : ""); if (mmc_card_mmc(card)) blk_queue_logical_block_size(md->queue.queue, @@ -2198,7 +2193,6 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) { sector_t size; - struct mmc_blk_data *md; if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { /* @@ -2214,9 +2208,8 @@ 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, + return mmc_blk_alloc_req(card, &card->dev, size, false, NULL, MMC_BLK_DATA_AREA_MAIN); - return md; } static int mmc_blk_alloc_part(struct mmc_card *card, @@ -2425,8 +2418,9 @@ static const struct mmc_fixup blk_fixups[] = END_FIXUP }; -static int mmc_blk_probe(struct mmc_card *card) +static int mmc_blk_probe(struct device *dev) { + struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_blk_data *md, *part_md; char cap_str[10]; @@ -2451,7 +2445,7 @@ static int mmc_blk_probe(struct mmc_card *card) if (mmc_blk_alloc_parts(card, md)) goto out; - mmc_set_drvdata(card, md); + dev_set_drvdata(dev, md); if (mmc_add_disk(md)) goto out; @@ -2481,9 +2475,10 @@ static int mmc_blk_probe(struct mmc_card *card) return 0; } -static void mmc_blk_remove(struct mmc_card *card) +static int mmc_blk_remove(struct device *dev) { - struct mmc_blk_data *md = mmc_get_drvdata(card); + struct mmc_card *card = mmc_dev_to_card(dev); + struct mmc_blk_data *md = dev_get_drvdata(dev); mmc_blk_remove_parts(card, md); pm_runtime_get_sync(&card->dev); @@ -2494,13 +2489,15 @@ static void mmc_blk_remove(struct mmc_card *card) pm_runtime_disable(&card->dev); pm_runtime_put_noidle(&card->dev); mmc_blk_remove_req(md); - mmc_set_drvdata(card, NULL); + dev_set_drvdata(dev, NULL); + + return 0; } -static int _mmc_blk_suspend(struct mmc_card *card) +static int _mmc_blk_suspend(struct device *dev) { struct mmc_blk_data *part_md; - struct mmc_blk_data *md = mmc_get_drvdata(card); + struct mmc_blk_data *md = dev_get_drvdata(dev); if (md) { mmc_queue_suspend(&md->queue); @@ -2511,21 +2508,21 @@ static int _mmc_blk_suspend(struct mmc_card *card) return 0; } -static void mmc_blk_shutdown(struct mmc_card *card) +static void mmc_blk_shutdown(struct device *dev) { - _mmc_blk_suspend(card); + _mmc_blk_suspend(dev); } -#ifdef CONFIG_PM -static int mmc_blk_suspend(struct mmc_card *card) +#ifdef CONFIG_PM_SLEEP +static int mmc_blk_suspend(struct device *dev) { - return _mmc_blk_suspend(card); + return _mmc_blk_suspend(dev); } -static int mmc_blk_resume(struct mmc_card *card) +static int mmc_blk_resume(struct device *dev) { struct mmc_blk_data *part_md; - struct mmc_blk_data *md = mmc_get_drvdata(card); + struct mmc_blk_data *md = dev_get_drvdata(dev); if (md) { /* @@ -2540,19 +2537,15 @@ static int mmc_blk_resume(struct mmc_card *card) } return 0; } -#else -#define mmc_blk_suspend NULL -#define mmc_blk_resume NULL #endif -static struct mmc_driver mmc_driver = { - .drv = { - .name = "mmcblk", - }, +static SIMPLE_DEV_PM_OPS(mmc_blk_pm_ops, mmc_blk_suspend, mmc_blk_resume); + +static struct device_driver mmc_driver = { + .name = "mmcblk", + .pm = &mmc_blk_pm_ops, .probe = mmc_blk_probe, .remove = mmc_blk_remove, - .suspend = mmc_blk_suspend, - .resume = mmc_blk_resume, .shutdown = mmc_blk_shutdown, }; @@ -2563,7 +2556,7 @@ static int __init mmc_blk_init(void) if (perdev_minors != CONFIG_MMC_BLOCK_MINORS) pr_info("mmcblk: using %d minors per device\n", perdev_minors); - max_devices = 256 / perdev_minors; + max_devices = min(MAX_DEVICES, (1 << MINORBITS) / perdev_minors); res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); if (res) diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 0c0fc52d42c5..7dac4695163b 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -14,6 +14,7 @@ #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/slab.h> +#include <linux/device.h> #include <linux/scatterlist.h> #include <linux/swap.h> /* For nr_free_buffer_pages() */ @@ -32,6 +33,8 @@ #define BUFFER_ORDER 2 #define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER) +#define TEST_ALIGN_END 8 + /* * Limit the test area size to the maximum MMC HC erase group size. Note that * the maximum SD allocation unit size is just 4MiB. @@ -1174,7 +1177,7 @@ static int mmc_test_align_write(struct mmc_test_card *test) int ret, i; struct scatterlist sg; - for (i = 1;i < 4;i++) { + for (i = 1; i < TEST_ALIGN_END; i++) { sg_init_one(&sg, test->buffer + i, 512); ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1); if (ret) @@ -1189,7 +1192,7 @@ static int mmc_test_align_read(struct mmc_test_card *test) int ret, i; struct scatterlist sg; - for (i = 1;i < 4;i++) { + for (i = 1; i < TEST_ALIGN_END; i++) { sg_init_one(&sg, test->buffer + i, 512); ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0); if (ret) @@ -1216,7 +1219,7 @@ static int mmc_test_align_multi_write(struct mmc_test_card *test) if (size < 1024) return RESULT_UNSUP_HOST; - for (i = 1;i < 4;i++) { + for (i = 1; i < TEST_ALIGN_END; i++) { sg_init_one(&sg, test->buffer + i, size); ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1); if (ret) @@ -1243,7 +1246,7 @@ static int mmc_test_align_multi_read(struct mmc_test_card *test) if (size < 1024) return RESULT_UNSUP_HOST; - for (i = 1;i < 4;i++) { + for (i = 1; i < TEST_ALIGN_END; i++) { sg_init_one(&sg, test->buffer + i, size); ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0); if (ret) @@ -2339,20 +2342,16 @@ static int mmc_test_hw_reset(struct mmc_test_card *test) struct mmc_host *host = card->host; int err; - err = mmc_hw_reset_check(host); + if (!mmc_card_mmc(card) || !mmc_can_reset(card)) + return RESULT_UNSUP_CARD; + + err = mmc_hw_reset(host); if (!err) return RESULT_OK; + else if (err == -EOPNOTSUPP) + return RESULT_UNSUP_HOST; - if (err == -ENOSYS) - return RESULT_FAIL; - - if (err != -EOPNOTSUPP) - return err; - - if (!mmc_can_reset(card)) - return RESULT_UNSUP_CARD; - - return RESULT_UNSUP_HOST; + return RESULT_FAIL; } static const struct mmc_test_case mmc_test_cases[] = { @@ -2997,8 +2996,9 @@ err: return ret; } -static int mmc_test_probe(struct mmc_card *card) +static int mmc_test_probe(struct device *dev) { + struct mmc_card *card = mmc_dev_to_card(dev); int ret; if (!mmc_card_mmc(card) && !mmc_card_sd(card)) @@ -3013,20 +3013,22 @@ static int mmc_test_probe(struct mmc_card *card) return 0; } -static void mmc_test_remove(struct mmc_card *card) +static int mmc_test_remove(struct device *dev) { + struct mmc_card *card = mmc_dev_to_card(dev); + mmc_test_free_result(card); mmc_test_free_dbgfs_file(card); + + return 0; } -static void mmc_test_shutdown(struct mmc_card *card) +static void mmc_test_shutdown(struct device *dev) { } -static struct mmc_driver mmc_driver = { - .drv = { - .name = "mmc_test", - }, +static struct device_driver mmc_driver = { + .name = "mmc_test", .probe = mmc_test_probe, .remove = mmc_test_remove, .shutdown = mmc_test_shutdown, diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index cfa6110632c3..236d194c2883 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -232,13 +232,15 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, if (!mqrq_cur->bounce_buf) { pr_warn("%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_warn("%s: unable to allocate bounce prev buffer\n", - mmc_card_name(card)); - kfree(mqrq_cur->bounce_buf); - mqrq_cur->bounce_buf = NULL; + } else { + mqrq_prev->bounce_buf = + kmalloc(bouncesz, GFP_KERNEL); + if (!mqrq_prev->bounce_buf) { + pr_warn("%s: unable to allocate bounce prev buffer\n", + mmc_card_name(card)); + kfree(mqrq_cur->bounce_buf); + mqrq_cur->bounce_buf = NULL; + } } } diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 38ed210ce2f3..2c25138f28b7 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -8,5 +8,5 @@ mmc_core-y := core.o bus.o host.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o \ quirks.o slot-gpio.o - +mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 8a1f1240e058..c5ef10065a4a 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/stat.h> +#include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/mmc/card.h> @@ -25,8 +26,6 @@ #include "sdio_cis.h" #include "bus.h" -#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) - static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -106,33 +105,14 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } -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); - - return drv->probe(card); -} - -static int mmc_bus_remove(struct device *dev) -{ - struct mmc_driver *drv = to_mmc_driver(dev->driver); - struct mmc_card *card = mmc_dev_to_card(dev); - - drv->remove(card); - - return 0; -} - static void mmc_bus_shutdown(struct device *dev) { - struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; int ret; - if (dev->driver && drv->shutdown) - drv->shutdown(card); + if (dev->driver && dev->driver->shutdown) + dev->driver->shutdown(dev); if (host->bus_ops->shutdown) { ret = host->bus_ops->shutdown(host); @@ -145,16 +125,13 @@ static void mmc_bus_shutdown(struct device *dev) #ifdef CONFIG_PM_SLEEP static int mmc_bus_suspend(struct device *dev) { - struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; int ret; - if (dev->driver && drv->suspend) { - ret = drv->suspend(card); - if (ret) - return ret; - } + ret = pm_generic_suspend(dev); + if (ret) + return ret; ret = host->bus_ops->suspend(host); return ret; @@ -162,7 +139,6 @@ static int mmc_bus_suspend(struct device *dev) static int mmc_bus_resume(struct device *dev) { - struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; int ret; @@ -172,14 +148,12 @@ static int mmc_bus_resume(struct device *dev) pr_warn("%s: error %d during resume (card was removed?)\n", mmc_hostname(host), ret); - if (dev->driver && drv->resume) - ret = drv->resume(card); - + ret = pm_generic_resume(dev); return ret; } #endif -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int mmc_runtime_suspend(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); @@ -195,7 +169,7 @@ static int mmc_runtime_resume(struct device *dev) return host->bus_ops->runtime_resume(host); } -#endif /* !CONFIG_PM_RUNTIME */ +#endif /* !CONFIG_PM */ static const struct dev_pm_ops mmc_bus_pm_ops = { SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, NULL) @@ -207,8 +181,6 @@ static struct bus_type mmc_bus_type = { .dev_groups = mmc_dev_groups, .match = mmc_bus_match, .uevent = mmc_bus_uevent, - .probe = mmc_bus_probe, - .remove = mmc_bus_remove, .shutdown = mmc_bus_shutdown, .pm = &mmc_bus_pm_ops, }; @@ -227,24 +199,22 @@ void mmc_unregister_bus(void) * mmc_register_driver - register a media driver * @drv: MMC media driver */ -int mmc_register_driver(struct mmc_driver *drv) +int mmc_register_driver(struct device_driver *drv) { - drv->drv.bus = &mmc_bus_type; - return driver_register(&drv->drv); + drv->bus = &mmc_bus_type; + return driver_register(drv); } - EXPORT_SYMBOL(mmc_register_driver); /** * mmc_unregister_driver - unregister a media driver * @drv: MMC media driver */ -void mmc_unregister_driver(struct mmc_driver *drv) +void mmc_unregister_driver(struct device_driver *drv) { - drv->drv.bus = &mmc_bus_type; - driver_unregister(&drv->drv); + drv->bus = &mmc_bus_type; + driver_unregister(drv); } - EXPORT_SYMBOL(mmc_unregister_driver); static void mmc_release_card(struct device *dev) @@ -352,6 +322,8 @@ int mmc_add_card(struct mmc_card *card) #endif mmc_init_context_info(card->host); + card->dev.of_node = mmc_of_find_child_device(card->host, 0); + ret = device_add(&card->dev); if (ret) return ret; @@ -380,6 +352,7 @@ void mmc_remove_card(struct mmc_card *card) mmc_hostname(card->host), card->rca); } device_del(&card->dev); + of_node_put(card->dev.of_node); } put_device(&card->dev); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f26a5f1d926d..c296bc098fe2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -40,6 +40,7 @@ #include "bus.h" #include "host.h" #include "sdio_bus.h" +#include "pwrseq.h" #include "mmc_ops.h" #include "sd_ops.h" @@ -149,6 +150,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) led_trigger_event(host->led, LED_OFF); + if (mrq->sbc) { + pr_debug("%s: req done <CMD%u>: %d: %08x %08x %08x %08x\n", + mmc_hostname(host), mrq->sbc->opcode, + mrq->sbc->error, + mrq->sbc->resp[0], mrq->sbc->resp[1], + mrq->sbc->resp[2], mrq->sbc->resp[3]); + } + pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", mmc_hostname(host), cmd->opcode, err, cmd->resp[0], cmd->resp[1], @@ -177,13 +186,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) EXPORT_SYMBOL(mmc_request_done); -static void -mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) +static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { #ifdef CONFIG_MMC_DEBUG unsigned int i, sz; struct scatterlist *sg; #endif + if (mmc_card_removed(host->card)) + return -ENOMEDIUM; if (mrq->sbc) { pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", @@ -214,6 +224,10 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mrq->cmd->error = 0; mrq->cmd->mrq = mrq; + if (mrq->sbc) { + mrq->sbc->error = 0; + mrq->sbc->mrq = mrq; + } if (mrq->data) { BUG_ON(mrq->data->blksz > host->max_blk_size); BUG_ON(mrq->data->blocks > host->max_blk_count); @@ -239,6 +253,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mmc_host_clk_hold(host); led_trigger_event(host->led, LED_FULL); host->ops->request(host, mrq); + + return 0; } /** @@ -259,7 +275,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) BUG_ON(!card); - if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card)) + if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card)) return; err = mmc_read_bkops_status(card); @@ -333,29 +349,34 @@ static void mmc_wait_done(struct mmc_request *mrq) */ static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq) { + int err; + mrq->done = mmc_wait_data_done; mrq->host = host; - if (mmc_card_removed(host->card)) { - mrq->cmd->error = -ENOMEDIUM; + + err = mmc_start_request(host, mrq); + if (err) { + mrq->cmd->error = err; mmc_wait_data_done(mrq); - return -ENOMEDIUM; } - mmc_start_request(host, mrq); - return 0; + return err; } static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) { + int err; + init_completion(&mrq->completion); mrq->done = mmc_wait_done; - if (mmc_card_removed(host->card)) { - mrq->cmd->error = -ENOMEDIUM; + + err = mmc_start_request(host, mrq); + if (err) { + mrq->cmd->error = err; complete(&mrq->completion); - return -ENOMEDIUM; } - mmc_start_request(host, mrq); - return 0; + + return err; } /* @@ -538,8 +559,18 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, 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)) + (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) { + + /* Cancel the prepared request */ + if (areq) + mmc_post_req(host, areq->mrq, -EINVAL); + mmc_start_bkops(host->card, true); + + /* prepare the request again */ + if (areq) + mmc_pre_req(host, areq->mrq, !host->areq); + } } if (!err && areq) @@ -709,27 +740,16 @@ 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); + err = mmc_get_ext_csd(card, &ext_csd); mmc_release_host(card->host); if (err) - goto out; + return err; 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; + return 0; } EXPORT_SYMBOL(mmc_read_bkops_status); @@ -877,6 +897,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) DECLARE_WAITQUEUE(wait, current); unsigned long flags; int stop; + bool pm = false; might_sleep(); @@ -896,15 +917,18 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) host->claimed = 1; host->claimer = current; host->claim_cnt += 1; + if (host->claim_cnt == 1) + pm = true; } else 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 (pm) + pm_runtime_get_sync(mmc_dev(host)); + return stop; } - EXPORT_SYMBOL(__mmc_claim_host); /** @@ -920,9 +944,6 @@ void mmc_release_host(struct mmc_host *host) 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 */ @@ -932,6 +953,8 @@ void mmc_release_host(struct mmc_host *host) host->claimer = NULL; spin_unlock_irqrestore(&host->lock, flags); wake_up(&host->wq); + pm_runtime_mark_last_busy(mmc_dev(host)); + pm_runtime_put_autosuspend(mmc_dev(host)); } } EXPORT_SYMBOL(mmc_release_host); @@ -1066,6 +1089,30 @@ void mmc_set_ungated(struct mmc_host *host) } #endif +int mmc_execute_tuning(struct mmc_card *card) +{ + struct mmc_host *host = card->host; + u32 opcode; + int err; + + if (!host->ops->execute_tuning) + return 0; + + if (mmc_card_mmc(card)) + opcode = MMC_SEND_TUNING_BLOCK_HS200; + else + opcode = MMC_SEND_TUNING_BLOCK; + + mmc_host_clk_hold(host); + err = host->ops->execute_tuning(host, opcode); + mmc_host_clk_release(host); + + if (err) + pr_err("%s: tuning execution failed\n", mmc_hostname(host)); + + return err; +} + /* * Change the bus mode (open drain/push-pull) of a host. */ @@ -1088,6 +1135,22 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width) mmc_host_clk_release(host); } +/* + * Set initial state after a power cycle or a hw_reset. + */ +void mmc_set_initial_state(struct mmc_host *host) +{ + if (mmc_host_is_spi(host)) + host->ios.chip_select = MMC_CS_HIGH; + else + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; + + mmc_set_ios(host); +} + /** * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number * @vdd: voltage (mV) @@ -1205,6 +1268,34 @@ EXPORT_SYMBOL(mmc_of_parse_voltage); #endif /* CONFIG_OF */ +static int mmc_of_get_func_num(struct device_node *node) +{ + u32 reg; + int ret; + + ret = of_property_read_u32(node, "reg", ®); + if (ret < 0) + return ret; + + return reg; +} + +struct device_node *mmc_of_find_child_device(struct mmc_host *host, + unsigned func_num) +{ + struct device_node *node; + + if (!host->parent || !host->parent->of_node) + return NULL; + + for_each_child_of_node(host->parent->of_node, node) { + if (mmc_of_get_func_num(node) == func_num) + return node; + } + + return NULL; +} + #ifdef CONFIG_REGULATOR /** @@ -1420,18 +1511,20 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) pr_warn("%s: cannot verify signal voltage switch\n", mmc_hostname(host)); + mmc_host_clk_hold(host); + cmd.opcode = SD_SWITCH_VOLTAGE; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(host, &cmd, 0); if (err) - return err; - - if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) - return -EIO; + goto err_command; - mmc_host_clk_hold(host); + if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) { + err = -EIO; + goto err_command; + } /* * The card should drive cmd and dat[0:3] low immediately * after the response of cmd11, but wait 1 ms to be sure @@ -1480,6 +1573,7 @@ power_cycle: mmc_power_cycle(host, ocr); } +err_command: mmc_host_clk_release(host); return err; @@ -1525,16 +1619,12 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) mmc_host_clk_hold(host); + mmc_pwrseq_pre_power_on(host); + host->ios.vdd = fls(ocr) - 1; - if (mmc_host_is_spi(host)) - host->ios.chip_select = MMC_CS_HIGH; - else - host->ios.chip_select = MMC_CS_DONTCARE; - host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; 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 initial state and call mmc_set_ios */ + mmc_set_initial_state(host); /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */ if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330) == 0) @@ -1550,6 +1640,8 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) */ mmc_delay(10); + mmc_pwrseq_post_power_on(host); + host->ios.clock = host->f_init; host->ios.power_mode = MMC_POWER_ON; @@ -1571,17 +1663,14 @@ void mmc_power_off(struct mmc_host *host) mmc_host_clk_hold(host); + mmc_pwrseq_power_off(host); + host->ios.clock = 0; host->ios.vdd = 0; - if (!mmc_host_is_spi(host)) { - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; - } host->ios.power_mode = MMC_POWER_OFF; - host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ios.timing = MMC_TIMING_LEGACY; - mmc_set_ios(host); + /* Set initial state and call mmc_set_ios */ + mmc_set_initial_state(host); /* * Some configurations, such as the 802.11 SDIO card in the OLPC @@ -2226,81 +2315,28 @@ static void mmc_hw_reset_for_init(struct mmc_host *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) +int mmc_hw_reset(struct mmc_host *host) { - struct mmc_card *card = host->card; - - if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) - return -EOPNOTSUPP; + int ret; - if (!card) + if (!host->card) return -EINVAL; - if (!mmc_can_reset(card)) + mmc_bus_get(host); + if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) { + mmc_bus_put(host); 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; - } } - 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); + ret = host->bus_ops->reset(host); + mmc_bus_put(host); - return host->bus_ops->power_restore(host); -} + pr_warn("%s: tried to reset card\n", mmc_hostname(host)); -int mmc_hw_reset(struct mmc_host *host) -{ - return mmc_do_hw_reset(host, 0); + return ret; } 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; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 443a584660f0..cfba3c05aab1 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -27,11 +27,15 @@ struct mmc_bus_ops { int (*power_restore)(struct mmc_host *); int (*alive)(struct mmc_host *); int (*shutdown)(struct mmc_host *); + int (*reset)(struct mmc_host *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); void mmc_detach_bus(struct mmc_host *host); +struct device_node *mmc_of_find_child_device(struct mmc_host *host, + unsigned func_num); + void mmc_init_erase(struct mmc_card *card); void mmc_set_chip_select(struct mmc_host *host, int mode); @@ -49,6 +53,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); void mmc_power_up(struct mmc_host *host, u32 ocr); void mmc_power_off(struct mmc_host *host); void mmc_power_cycle(struct mmc_host *host, u32 ocr); +void mmc_set_initial_state(struct mmc_host *host); static inline void mmc_delay(unsigned int ms) { @@ -81,5 +86,8 @@ void mmc_add_card_debugfs(struct mmc_card *card); void mmc_remove_card_debugfs(struct mmc_card *card); void mmc_init_context_info(struct mmc_host *host); + +int mmc_execute_tuning(struct mmc_card *card); + #endif diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 91eb16223246..e9142108a6c6 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -291,14 +291,8 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) if (!buf) return -ENOMEM; - ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) { - err = -ENOMEM; - goto out_free; - } - mmc_get_card(card); - err = mmc_send_ext_csd(card, ext_csd); + err = mmc_get_ext_csd(card, &ext_csd); mmc_put_card(card); if (err) goto out_free; @@ -314,7 +308,6 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) out_free: kfree(buf); - kfree(ext_csd); return err; } diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 270d58a4c43d..8be0df758e68 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -29,13 +29,20 @@ #include "core.h" #include "host.h" +#include "slot-gpio.h" +#include "pwrseq.h" #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) +static DEFINE_IDR(mmc_host_idr); +static DEFINE_SPINLOCK(mmc_host_lock); + static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); - mutex_destroy(&host->slot.lock); + spin_lock(&mmc_host_lock); + idr_remove(&mmc_host_idr, host->index); + spin_unlock(&mmc_host_lock); kfree(host); } @@ -54,9 +61,6 @@ void mmc_unregister_host_class(void) class_unregister(&mmc_host_class); } -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) @@ -367,16 +371,10 @@ int mmc_of_parse(struct mmc_host *host) ret = mmc_gpiod_request_cd(host, "cd", 0, true, 0, &cd_gpio_invert); - if (ret) { - if (ret == -EPROBE_DEFER) - return ret; - if (ret != -ENOENT) { - dev_err(host->parent, - "Failed to request CD GPIO: %d\n", - ret); - } - } else + if (!ret) dev_info(host->parent, "Got CD GPIO\n"); + else if (ret != -ENOENT) + return ret; /* * There are two ways to flag that the CD line is inverted: @@ -397,16 +395,10 @@ int mmc_of_parse(struct mmc_host *host) ro_cap_invert = of_property_read_bool(np, "wp-inverted"); ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert); - if (ret) { - if (ret == -EPROBE_DEFER) - goto out; - if (ret != -ENOENT) { - dev_err(host->parent, - "Failed to request WP GPIO: %d\n", - ret); - } - } else + if (!ret) dev_info(host->parent, "Got WP GPIO\n"); + else if (ret != -ENOENT) + return ret; /* See the comment on CD inversion above */ if (ro_cap_invert ^ ro_gpio_invert) @@ -457,11 +449,7 @@ int mmc_of_parse(struct mmc_host *host) host->dsr_req = 0; } - return 0; - -out: - mmc_gpio_free_cd(host); - return ret; + return mmc_pwrseq_alloc(host); } EXPORT_SYMBOL(mmc_of_parse); @@ -491,8 +479,10 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->index = err; spin_unlock(&mmc_host_lock); idr_preload_end(); - if (err < 0) - goto free; + if (err < 0) { + kfree(host); + return NULL; + } dev_set_name(&host->class_dev, "mmc%d", host->index); @@ -501,10 +491,12 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->class_dev.class = &mmc_host_class; device_initialize(&host->class_dev); - mmc_host_clk_init(host); + if (mmc_gpio_alloc(host)) { + put_device(&host->class_dev); + return NULL; + } - mutex_init(&host->slot.lock); - host->slot.cd_irq = -EINVAL; + mmc_host_clk_init(host); spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); @@ -525,10 +517,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->max_blk_count = PAGE_CACHE_SIZE / 512; return host; - -free: - kfree(host); - return NULL; } EXPORT_SYMBOL(mmc_alloc_host); @@ -601,10 +589,7 @@ EXPORT_SYMBOL(mmc_remove_host); */ 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); - + mmc_pwrseq_free(host); put_device(&host->class_dev); } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b212239750af..f36c76f8b232 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -11,6 +11,7 @@ */ #include <linux/err.h> +#include <linux/of.h> #include <linux/slab.h> #include <linux/stat.h> #include <linux/pm_runtime.h> @@ -177,65 +178,6 @@ static int mmc_decode_csd(struct mmc_card *card) return 0; } -/* - * Read extended CSD. - */ -static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) -{ - int err; - u8 *ext_csd; - - BUG_ON(!card); - BUG_ON(!new_ext_csd); - - *new_ext_csd = NULL; - - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) - return 0; - - /* - * As the ext_csd is so large and mostly unused, we don't store the - * raw block in mmc_card. - */ - ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) { - pr_err("%s: could not allocate a buffer to " - "receive the ext_csd.\n", mmc_hostname(card->host)); - return -ENOMEM; - } - - err = mmc_send_ext_csd(card, ext_csd); - if (err) { - kfree(ext_csd); - *new_ext_csd = NULL; - - /* If the host or the card can't do the switch, - * fail more gracefully. */ - if ((err != -EINVAL) - && (err != -ENOSYS) - && (err != -EFAULT)) - return err; - - /* - * High capacity cards should have this "magic" size - * stored in their CSD. - */ - if (card->csd.capacity == (4096 * 512)) { - pr_err("%s: unable to read EXT_CSD " - "on a possible high capacity card. " - "Card will be ignored.\n", - mmc_hostname(card->host)); - } else { - pr_warn("%s: unable to read EXT_CSD, performance might suffer\n", - mmc_hostname(card->host)); - err = 0; - } - } else - *new_ext_csd = ext_csd; - - return err; -} - static void mmc_select_card_type(struct mmc_card *card) { struct mmc_host *host = card->host; @@ -391,15 +333,12 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) /* * Decode extended CSD. */ -static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) +static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) { int err = 0, idx; unsigned int part_size; - - BUG_ON(!card); - - if (!ext_csd) - return 0; + struct device_node *np; + bool broken_hpi = false; /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; @@ -413,6 +352,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } } + np = mmc_of_find_child_device(card->host, 0); + if (np && of_device_is_compatible(np, "mmc-card")) + broken_hpi = of_property_read_bool(np, "broken-hpi"); + of_node_put(np); + /* * The EXT_CSD format is meant to be forward compatible. As long * as CSD_STRUCTURE does not change, all values for EXT_CSD_REV @@ -547,16 +491,18 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) /* 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.man_bkops_en = + (ext_csd[EXT_CSD_BKOPS_EN] & + EXT_CSD_MANUAL_BKOPS_MASK); 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", + if (!card->ext_csd.man_bkops_en) + pr_info("%s: MAN_BKOPS_EN bit is not set\n", mmc_hostname(card->host)); } /* check whether the eMMC card supports HPI */ - if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { + if (!broken_hpi && (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; @@ -628,16 +574,56 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.data_sector_size = 512; } + /* eMMC v5 or later */ + if (card->ext_csd.rev >= 7) { + memcpy(card->ext_csd.fwrev, &ext_csd[EXT_CSD_FIRMWARE_VERSION], + MMC_FIRMWARE_LEN); + card->ext_csd.ffu_capable = + (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) && + !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1); + } out: return err; } -static inline void mmc_free_ext_csd(u8 *ext_csd) +static int mmc_read_ext_csd(struct mmc_card *card) { + u8 *ext_csd; + int err; + + if (!mmc_can_ext_csd(card)) + return 0; + + err = mmc_get_ext_csd(card, &ext_csd); + if (err) { + /* If the host or the card can't do the switch, + * fail more gracefully. */ + if ((err != -EINVAL) + && (err != -ENOSYS) + && (err != -EFAULT)) + return err; + + /* + * High capacity cards should have this "magic" size + * stored in their CSD. + */ + if (card->csd.capacity == (4096 * 512)) { + pr_err("%s: unable to read EXT_CSD on a possible high capacity card. Card will be ignored.\n", + mmc_hostname(card->host)); + } else { + pr_warn("%s: unable to read EXT_CSD, performance might suffer\n", + mmc_hostname(card->host)); + err = 0; + } + + return err; + } + + err = mmc_decode_ext_csd(card, ext_csd); kfree(ext_csd); + return err; } - static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) { u8 *bw_ext_csd; @@ -647,11 +633,8 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) return 0; err = mmc_get_ext_csd(card, &bw_ext_csd); - - if (err || bw_ext_csd == NULL) { - err = -EINVAL; - goto out; - } + if (err) + return err; /* only compare read only fields */ err = !((card->ext_csd.raw_partition_support == @@ -710,8 +693,7 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) if (err) err = -EINVAL; -out: - mmc_free_ext_csd(bw_ext_csd); + kfree(bw_ext_csd); return err; } @@ -722,7 +704,7 @@ MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year); MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9); MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9); -MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev); +MMC_DEV_ATTR(ffu_capable, "%d\n", card->ext_csd.ffu_capable); MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev); MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); @@ -735,6 +717,22 @@ 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 ssize_t mmc_fwrev_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mmc_card *card = mmc_dev_to_card(dev); + + if (card->ext_csd.rev < 7) { + return sprintf(buf, "0x%x\n", card->cid.fwrev); + } else { + return sprintf(buf, "0x%*phN\n", MMC_FIRMWARE_LEN, + card->ext_csd.fwrev); + } +} + +static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL); + static struct attribute *mmc_std_attrs[] = { &dev_attr_cid.attr, &dev_attr_csd.attr, @@ -742,6 +740,7 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_erase_size.attr, &dev_attr_preferred_erase_size.attr, &dev_attr_fwrev.attr, + &dev_attr_ffu_capable.attr, &dev_attr_hwrev.attr, &dev_attr_manfid.attr, &dev_attr_name.attr, @@ -774,14 +773,6 @@ static int __mmc_select_powerclass(struct mmc_card *card, unsigned int pwrclass_val = 0; int err = 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 <= MMC_HIGH_26_MAX_DTR) @@ -844,7 +835,7 @@ static int mmc_select_powerclass(struct mmc_card *card) int err, ddr; /* Power class selection is supported for versions >= 4.0 */ - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + if (!mmc_can_ext_csd(card)) return 0; bus_width = host->ios.bus_width; @@ -905,7 +896,7 @@ static int mmc_select_bus_width(struct mmc_card *card) unsigned idx, bus_width = 0; int err = 0; - if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) && + if (!mmc_can_ext_csd(card) || !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) return 0; @@ -998,7 +989,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card) ext_csd_bits, card->ext_csd.generic_cmd6_time); if (err) { - pr_warn("%s: switch to bus width %d ddr failed\n", + pr_err("%s: switch to bus width %d ddr failed\n", mmc_hostname(host), 1 << bus_width); return err; } @@ -1069,7 +1060,7 @@ static int mmc_select_hs400(struct mmc_card *card) card->ext_csd.generic_cmd6_time, true, true, true); if (err) { - pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n", + pr_err("%s: switch to high-speed from hs200 failed, err:%d\n", mmc_hostname(host), err); return err; } @@ -1079,7 +1070,7 @@ static int mmc_select_hs400(struct mmc_card *card) EXT_CSD_DDR_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time); if (err) { - pr_warn("%s: switch to bus width for hs400 failed, err:%d\n", + pr_err("%s: switch to bus width for hs400 failed, err:%d\n", mmc_hostname(host), err); return err; } @@ -1089,7 +1080,7 @@ static int mmc_select_hs400(struct mmc_card *card) card->ext_csd.generic_cmd6_time, true, true, true); if (err) { - pr_warn("%s: switch to hs400 failed, err:%d\n", + pr_err("%s: switch to hs400 failed, err:%d\n", mmc_hostname(host), err); return err; } @@ -1146,8 +1137,7 @@ static int mmc_select_timing(struct mmc_card *card) { int err = 0; - if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 && - card->ext_csd.hs_max_dtr == 0)) + if (!mmc_can_ext_csd(card)) goto bus_speed; if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) @@ -1175,38 +1165,6 @@ bus_speed: return err; } -const u8 tuning_blk_pattern_4bit[MMC_TUNING_BLK_PATTERN_4BIT_SIZE] = { - 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, - 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, - 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, - 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, - 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, - 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, - 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, - 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, -}; -EXPORT_SYMBOL(tuning_blk_pattern_4bit); - -const u8 tuning_blk_pattern_8bit[MMC_TUNING_BLK_PATTERN_8BIT_SIZE] = { - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, - 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, - 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, - 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, - 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, - 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, - 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, - 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, - 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, - 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, - 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, - 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, - 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, - 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, -}; -EXPORT_SYMBOL(tuning_blk_pattern_8bit); - /* * Execute tuning sequence to seek the proper bus operating * conditions for HS200 and HS400, which sends CMD21 to the device. @@ -1214,7 +1172,6 @@ EXPORT_SYMBOL(tuning_blk_pattern_8bit); static int mmc_hs200_tuning(struct mmc_card *card) { struct mmc_host *host = card->host; - int err = 0; /* * Timing should be adjusted to the HS400 target @@ -1225,18 +1182,7 @@ static int mmc_hs200_tuning(struct mmc_card *card) if (host->ops->prepare_hs400_tuning) host->ops->prepare_hs400_tuning(host, &host->ios); - if (host->ops->execute_tuning) { - mmc_host_clk_hold(host); - err = host->ops->execute_tuning(host, - MMC_SEND_TUNING_BLOCK_HS200); - mmc_host_clk_release(host); - - if (err) - pr_warn("%s: tuning execution failed\n", - mmc_hostname(host)); - } - - return err; + return mmc_execute_tuning(card); } /* @@ -1252,7 +1198,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, int err; u32 cid[4]; u32 rocr; - u8 *ext_csd = NULL; BUG_ON(!host); WARN_ON(!host->claimed); @@ -1318,6 +1263,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } /* + * Call the optional HC's init_card function to handle quirks. + */ + if (host->ops->init_card) + host->ops->init_card(host, card); + + /* * For native busses: set card RCA and quit open drain mode. */ if (!mmc_host_is_spi(host)) { @@ -1361,14 +1312,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } if (!oldcard) { - /* - * Fetch and process extended CSD. - */ - - err = mmc_get_ext_csd(card, &ext_csd); - if (err) - goto free_card; - err = mmc_read_ext_csd(card, ext_csd); + /* Read extended CSD. */ + err = mmc_read_ext_csd(card); if (err) goto free_card; @@ -1458,18 +1403,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (mmc_card_hs200(card)) { err = mmc_hs200_tuning(card); if (err) - goto err; + goto free_card; err = mmc_select_hs400(card); if (err) - goto err; + goto free_card; } else if (mmc_card_hs(card)) { /* Select the desired bus width optionally */ err = mmc_select_bus_width(card); if (!IS_ERR_VALUE(err)) { err = mmc_select_hs_ddr(card); if (err) - goto err; + goto free_card; } } @@ -1545,15 +1490,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; - mmc_free_ext_csd(ext_csd); return 0; free_card: if (!oldcard) mmc_remove_card(card); err: - mmc_free_ext_csd(ext_csd); - return err; } @@ -1851,6 +1793,46 @@ static int mmc_power_restore(struct mmc_host *host) return ret; } +int mmc_can_reset(struct mmc_card *card) +{ + u8 rst_n_function; + + 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_reset(struct mmc_host *host) +{ + struct mmc_card *card = host->card; + u32 status; + + if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) + return -EOPNOTSUPP; + + 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 (!mmc_send_status(card, &status)) { + mmc_host_clk_release(host); + return -ENOSYS; + } + + /* Set initial state and call mmc_set_ios */ + mmc_set_initial_state(host); + mmc_host_clk_release(host); + + return mmc_power_restore(host); +} + static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect, @@ -1861,6 +1843,7 @@ static const struct mmc_bus_ops mmc_ops = { .power_restore = mmc_power_restore, .alive = mmc_alive, .shutdown = mmc_shutdown, + .reset = mmc_reset, }; /* diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 7911e0510a1d..0ea042dc7443 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -23,6 +23,36 @@ #define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ +static const u8 tuning_blk_pattern_4bit[] = { + 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, + 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, + 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, + 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, + 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, + 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, + 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, + 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, +}; + +static const u8 tuning_blk_pattern_8bit[] = { + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, + 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, + 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, + 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, + 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, + 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, + 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, + 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, + 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, + 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, + 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, + 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, + 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, +}; + static inline int __mmc_send_status(struct mmc_card *card, u32 *status, bool ignore_crc) { @@ -264,20 +294,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, 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; mrq.cmd = &cmd; mrq.data = &data; @@ -298,7 +314,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, data_buf, len); + sg_init_one(&sg, buf, len); if (opcode == MMC_SEND_CSD || opcode == MMC_SEND_CID) { /* @@ -312,11 +328,6 @@ 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); - } - if (cmd.error) return cmd.error; if (data.error) @@ -334,7 +345,7 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd) return mmc_send_cxd_native(card->host, card->rca << 16, csd, MMC_SEND_CSD); - csd_tmp = kmalloc(16, GFP_KERNEL); + csd_tmp = kzalloc(16, GFP_KERNEL); if (!csd_tmp) return -ENOMEM; @@ -362,7 +373,7 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid) cid, MMC_SEND_CID); } - cid_tmp = kmalloc(16, GFP_KERNEL); + cid_tmp = kzalloc(16, GFP_KERNEL); if (!cid_tmp) return -ENOMEM; @@ -378,12 +389,35 @@ err: return ret; } -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) { - return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, - ext_csd, 512); + int err; + u8 *ext_csd; + + if (!card || !new_ext_csd) + return -EINVAL; + + if (!mmc_can_ext_csd(card)) + return -EOPNOTSUPP; + + /* + * As the ext_csd is so large and mostly unused, we don't store the + * raw block in mmc_card. + */ + ext_csd = kzalloc(512, GFP_KERNEL); + if (!ext_csd) + return -ENOMEM; + + err = mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, ext_csd, + 512); + if (err) + kfree(ext_csd); + else + *new_ext_csd = ext_csd; + + return err; } -EXPORT_SYMBOL_GPL(mmc_send_ext_csd); +EXPORT_SYMBOL_GPL(mmc_get_ext_csd); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) { @@ -543,6 +577,75 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, } EXPORT_SYMBOL_GPL(mmc_switch); +int mmc_send_tuning(struct mmc_host *host) +{ + struct mmc_request mrq = {NULL}; + struct mmc_command cmd = {0}; + struct mmc_data data = {0}; + struct scatterlist sg; + struct mmc_ios *ios = &host->ios; + const u8 *tuning_block_pattern; + int size, err = 0; + u8 *data_buf; + u32 opcode; + + if (ios->bus_width == MMC_BUS_WIDTH_8) { + tuning_block_pattern = tuning_blk_pattern_8bit; + size = sizeof(tuning_blk_pattern_8bit); + opcode = MMC_SEND_TUNING_BLOCK_HS200; + } else if (ios->bus_width == MMC_BUS_WIDTH_4) { + tuning_block_pattern = tuning_blk_pattern_4bit; + size = sizeof(tuning_blk_pattern_4bit); + opcode = MMC_SEND_TUNING_BLOCK; + } else + return -EINVAL; + + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) + return -ENOMEM; + + mrq.cmd = &cmd; + mrq.data = &data; + + cmd.opcode = opcode; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = size; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + /* + * According to the tuning specs, Tuning process + * is normally shorter 40 executions of CMD19, + * and timeout value should be shorter than 150 ms + */ + data.timeout_ns = 150 * NSEC_PER_MSEC; + + data.sg = &sg; + data.sg_len = 1; + sg_init_one(&sg, data_buf, size); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error) { + err = cmd.error; + goto out; + } + + if (data.error) { + err = data.error; + goto out; + } + + if (memcmp(data_buf, tuning_block_pattern, size)) + err = -EIO; + +out: + kfree(data_buf); + return err; +} +EXPORT_SYMBOL_GPL(mmc_send_tuning); + static int mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, u8 len) @@ -675,3 +778,8 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) return 0; } + +int mmc_can_ext_csd(struct mmc_card *card) +{ + return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3); +} diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 390dac665b2a..6f4b00ed93de 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -20,13 +20,13 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_all_send_cid(struct mmc_host *host, u32 *cid); int mmc_set_relative_addr(struct mmc_card *card); int mmc_send_csd(struct mmc_card *card, u32 *csd); -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); int mmc_send_status(struct mmc_card *card, u32 *status); int mmc_send_cid(struct mmc_host *host, u32 *cid); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); +int mmc_can_ext_csd(struct mmc_card *card); #endif diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c new file mode 100644 index 000000000000..ab2129781161 --- /dev/null +++ b/drivers/mmc/core/pwrseq.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2014 Linaro Ltd + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + * + * MMC power sequence management + */ +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_platform.h> + +#include <linux/mmc/host.h> + +#include "pwrseq.h" + +struct mmc_pwrseq_match { + const char *compatible; + struct mmc_pwrseq *(*alloc)(struct mmc_host *host, struct device *dev); +}; + +static struct mmc_pwrseq_match pwrseq_match[] = { + { + .compatible = "mmc-pwrseq-simple", + .alloc = mmc_pwrseq_simple_alloc, + }, { + .compatible = "mmc-pwrseq-emmc", + .alloc = mmc_pwrseq_emmc_alloc, + }, +}; + +static struct mmc_pwrseq_match *mmc_pwrseq_find(struct device_node *np) +{ + struct mmc_pwrseq_match *match = ERR_PTR(-ENODEV); + int i; + + for (i = 0; i < ARRAY_SIZE(pwrseq_match); i++) { + if (of_device_is_compatible(np, pwrseq_match[i].compatible)) { + match = &pwrseq_match[i]; + break; + } + } + + return match; +} + +int mmc_pwrseq_alloc(struct mmc_host *host) +{ + struct platform_device *pdev; + struct device_node *np; + struct mmc_pwrseq_match *match; + struct mmc_pwrseq *pwrseq; + int ret = 0; + + np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0); + if (!np) + return 0; + + pdev = of_find_device_by_node(np); + if (!pdev) { + ret = -ENODEV; + goto err; + } + + match = mmc_pwrseq_find(np); + if (IS_ERR(match)) { + ret = PTR_ERR(match); + goto err; + } + + pwrseq = match->alloc(host, &pdev->dev); + if (IS_ERR(pwrseq)) { + ret = PTR_ERR(host->pwrseq); + goto err; + } + + host->pwrseq = pwrseq; + dev_info(host->parent, "allocated mmc-pwrseq\n"); + +err: + of_node_put(np); + return ret; +} + +void mmc_pwrseq_pre_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops && pwrseq->ops->pre_power_on) + pwrseq->ops->pre_power_on(host); +} + +void mmc_pwrseq_post_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops && pwrseq->ops->post_power_on) + pwrseq->ops->post_power_on(host); +} + +void mmc_pwrseq_power_off(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops && pwrseq->ops->power_off) + pwrseq->ops->power_off(host); +} + +void mmc_pwrseq_free(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops && pwrseq->ops->free) + pwrseq->ops->free(host); + + host->pwrseq = NULL; +} diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h new file mode 100644 index 000000000000..096da48c6a7e --- /dev/null +++ b/drivers/mmc/core/pwrseq.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014 Linaro Ltd + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef _MMC_CORE_PWRSEQ_H +#define _MMC_CORE_PWRSEQ_H + +struct mmc_pwrseq_ops { + void (*pre_power_on)(struct mmc_host *host); + void (*post_power_on)(struct mmc_host *host); + void (*power_off)(struct mmc_host *host); + void (*free)(struct mmc_host *host); +}; + +struct mmc_pwrseq { + struct mmc_pwrseq_ops *ops; +}; + +#ifdef CONFIG_OF + +int mmc_pwrseq_alloc(struct mmc_host *host); +void mmc_pwrseq_pre_power_on(struct mmc_host *host); +void mmc_pwrseq_post_power_on(struct mmc_host *host); +void mmc_pwrseq_power_off(struct mmc_host *host); +void mmc_pwrseq_free(struct mmc_host *host); + +struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host, + struct device *dev); +struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host, + struct device *dev); + +#else + +static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; } +static inline void mmc_pwrseq_pre_power_on(struct mmc_host *host) {} +static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {} +static inline void mmc_pwrseq_power_off(struct mmc_host *host) {} +static inline void mmc_pwrseq_free(struct mmc_host *host) {} + +#endif + +#endif diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c new file mode 100644 index 000000000000..9d6d2fb21796 --- /dev/null +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2015, Samsung Electronics Co., Ltd. + * + * Author: Marek Szyprowski <m.szyprowski@samsung.com> + * + * License terms: GNU General Public License (GPL) version 2 + * + * Simple eMMC hardware reset provider + */ +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/reboot.h> + +#include <linux/mmc/host.h> + +#include "pwrseq.h" + +struct mmc_pwrseq_emmc { + struct mmc_pwrseq pwrseq; + struct notifier_block reset_nb; + struct gpio_desc *reset_gpio; +}; + +static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) +{ + gpiod_set_value(pwrseq->reset_gpio, 1); + udelay(1); + gpiod_set_value(pwrseq->reset_gpio, 0); + udelay(200); +} + +static void mmc_pwrseq_emmc_reset(struct mmc_host *host) +{ + struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_emmc, pwrseq); + + __mmc_pwrseq_emmc_reset(pwrseq); +} + +static void mmc_pwrseq_emmc_free(struct mmc_host *host) +{ + struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_emmc, pwrseq); + + unregister_restart_handler(&pwrseq->reset_nb); + gpiod_put(pwrseq->reset_gpio); + kfree(pwrseq); +} + +static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { + .post_power_on = mmc_pwrseq_emmc_reset, + .free = mmc_pwrseq_emmc_free, +}; + +static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct mmc_pwrseq_emmc *pwrseq = container_of(this, + struct mmc_pwrseq_emmc, reset_nb); + + __mmc_pwrseq_emmc_reset(pwrseq); + return NOTIFY_DONE; +} + +struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host, + struct device *dev) +{ + struct mmc_pwrseq_emmc *pwrseq; + int ret = 0; + + pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL); + if (!pwrseq) + return ERR_PTR(-ENOMEM); + + pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW); + if (IS_ERR(pwrseq->reset_gpio)) { + ret = PTR_ERR(pwrseq->reset_gpio); + goto free; + } + + /* + * register reset handler to ensure emmc reset also from + * emergency_reboot(), priority 129 schedules it just before + * system reboot + */ + pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; + pwrseq->reset_nb.priority = 129; + register_restart_handler(&pwrseq->reset_nb); + + pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; + + return &pwrseq->pwrseq; +free: + kfree(pwrseq); + return ERR_PTR(ret); +} diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c new file mode 100644 index 000000000000..0b14b83a53d6 --- /dev/null +++ b/drivers/mmc/core/pwrseq_simple.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2014 Linaro Ltd + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + * + * Simple MMC power sequence management + */ +#include <linux/clk.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> + +#include <linux/mmc/host.h> + +#include "pwrseq.h" + +struct mmc_pwrseq_simple { + struct mmc_pwrseq pwrseq; + bool clk_enabled; + struct clk *ext_clk; + int nr_gpios; + struct gpio_desc *reset_gpios[0]; +}; + +static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, + int value) +{ + int i; + + for (i = 0; i < pwrseq->nr_gpios; i++) + if (!IS_ERR(pwrseq->reset_gpios[i])) + gpiod_set_value_cansleep(pwrseq->reset_gpios[i], value); +} + +static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_simple, pwrseq); + + if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) { + clk_prepare_enable(pwrseq->ext_clk); + pwrseq->clk_enabled = true; + } + + mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); +} + +static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_simple, pwrseq); + + mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); +} + +static void mmc_pwrseq_simple_power_off(struct mmc_host *host) +{ + struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_simple, pwrseq); + + mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); + + if (!IS_ERR(pwrseq->ext_clk) && pwrseq->clk_enabled) { + clk_disable_unprepare(pwrseq->ext_clk); + pwrseq->clk_enabled = false; + } +} + +static void mmc_pwrseq_simple_free(struct mmc_host *host) +{ + struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_simple, pwrseq); + int i; + + for (i = 0; i < pwrseq->nr_gpios; i++) + if (!IS_ERR(pwrseq->reset_gpios[i])) + gpiod_put(pwrseq->reset_gpios[i]); + + if (!IS_ERR(pwrseq->ext_clk)) + clk_put(pwrseq->ext_clk); + + kfree(pwrseq); +} + +static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { + .pre_power_on = mmc_pwrseq_simple_pre_power_on, + .post_power_on = mmc_pwrseq_simple_post_power_on, + .power_off = mmc_pwrseq_simple_power_off, + .free = mmc_pwrseq_simple_free, +}; + +struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host, + struct device *dev) +{ + struct mmc_pwrseq_simple *pwrseq; + int i, nr_gpios, ret = 0; + + nr_gpios = of_gpio_named_count(dev->of_node, "reset-gpios"); + if (nr_gpios < 0) + nr_gpios = 0; + + pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple) + nr_gpios * + sizeof(struct gpio_desc *), GFP_KERNEL); + if (!pwrseq) + return ERR_PTR(-ENOMEM); + + pwrseq->ext_clk = clk_get(dev, "ext_clock"); + if (IS_ERR(pwrseq->ext_clk) && + PTR_ERR(pwrseq->ext_clk) != -ENOENT) { + ret = PTR_ERR(pwrseq->ext_clk); + goto free; + } + + for (i = 0; i < nr_gpios; i++) { + pwrseq->reset_gpios[i] = gpiod_get_index(dev, "reset", i, + GPIOD_OUT_HIGH); + if (IS_ERR(pwrseq->reset_gpios[i]) && + PTR_ERR(pwrseq->reset_gpios[i]) != -ENOENT && + PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) { + ret = PTR_ERR(pwrseq->reset_gpios[i]); + + while (i--) + gpiod_put(pwrseq->reset_gpios[i]); + + goto clk_put; + } + } + + pwrseq->nr_gpios = nr_gpios; + pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops; + + return &pwrseq->pwrseq; +clk_put: + if (!IS_ERR(pwrseq->ext_clk)) + clk_put(pwrseq->ext_clk); +free: + kfree(pwrseq); + return ERR_PTR(ret); +} diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index c2cddfd99c7c..31a9ef256d06 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -660,15 +660,10 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. */ - if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning && - (card->sd_bus_speed == UHS_SDR50_BUS_SPEED || - card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) { - 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->sd_bus_speed == UHS_SDR50_BUS_SPEED || + card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) + err = mmc_execute_tuning(card); out: kfree(status); @@ -933,6 +928,12 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, } /* + * Call the optional HC's init_card function to handle quirks. + */ + if (host->ops->init_card) + host->ops->init_card(host, card); + + /* * For native busses: get card RCA and quit open drain mode. */ if (!mmc_host_is_spi(host)) { @@ -1191,6 +1192,12 @@ static int mmc_sd_power_restore(struct mmc_host *host) return ret; } +static int mmc_sd_reset(struct mmc_host *host) +{ + mmc_power_cycle(host, host->card->ocr); + return mmc_sd_power_restore(host); +} + static const struct mmc_bus_ops mmc_sd_ops = { .remove = mmc_sd_remove, .detect = mmc_sd_detect, @@ -1201,6 +1208,7 @@ static const struct mmc_bus_ops mmc_sd_ops = { .power_restore = mmc_sd_power_restore, .alive = mmc_sd_alive, .shutdown = mmc_sd_suspend, + .reset = mmc_sd_reset, }; /* @@ -1271,4 +1279,3 @@ err: return err; } - diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2439e717655b..5bc6c7dbbd60 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -293,19 +293,22 @@ static int sdio_enable_4bit_bus(struct mmc_card *card) int err; if (card->type == MMC_TYPE_SDIO) - return sdio_enable_wide(card); - - if ((card->host->caps & MMC_CAP_4_BIT_DATA) && - (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + err = sdio_enable_wide(card); + else if ((card->host->caps & MMC_CAP_4_BIT_DATA) && + (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); if (err) return err; + err = sdio_enable_wide(card); + if (err <= 0) + mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1); } else return 0; - err = sdio_enable_wide(card); - if (err <= 0) - mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1); + if (err > 0) { + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); + err = 0; + } return err; } @@ -547,13 +550,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) /* * Switch to wider bus (if supported). */ - if (card->host->caps & MMC_CAP_4_BIT_DATA) { + if (card->host->caps & MMC_CAP_4_BIT_DATA) err = sdio_enable_4bit_bus(card); - if (err > 0) { - mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); - err = 0; - } - } /* Set the driver strength for the card */ sdio_select_driver_type(card); @@ -567,17 +565,11 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. */ - if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning && - ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) || - (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) { - 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->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) || + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) + err = mmc_execute_tuning(card); out: - return err; } @@ -809,9 +801,7 @@ try_again: * Switch to wider bus (if supported). */ err = sdio_enable_4bit_bus(card); - if (err > 0) - mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); - else if (err) + if (err) goto remove; } finish: @@ -980,15 +970,15 @@ static int mmc_sdio_resume(struct mmc_host *host) if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) { sdio_reset(host); mmc_go_idle(host); - err = mmc_sdio_init_card(host, host->card->ocr, host->card, - mmc_card_keep_power(host)); + mmc_send_if_cond(host, host->card->ocr); + err = mmc_send_io_op_cond(host, 0, NULL); + if (!err) + err = mmc_sdio_init_card(host, host->card->ocr, + host->card, + mmc_card_keep_power(host)); } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { /* We may have switched to 1-bit mode during suspend */ err = sdio_enable_4bit_bus(host->card); - if (err > 0) { - mmc_set_bus_width(host, MMC_BUS_WIDTH_4); - err = 0; - } } if (!err && host->sdio_irqs) { @@ -1035,7 +1025,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host) sdio_reset(host); mmc_go_idle(host); - mmc_send_if_cond(host, host->ocr_avail); + mmc_send_if_cond(host, host->card->ocr); ret = mmc_send_io_op_cond(host, 0, NULL); if (ret) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 6da97b170563..bee02e644d62 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -22,10 +22,14 @@ #include <linux/mmc/card.h> #include <linux/mmc/host.h> #include <linux/mmc/sdio_func.h> +#include <linux/of.h> +#include "core.h" #include "sdio_cis.h" #include "sdio_bus.h" +#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) + /* show configuration fields */ #define sdio_config_attr(field, format_string) \ static ssize_t \ @@ -196,8 +200,6 @@ static int sdio_bus_remove(struct device *dev) return ret; } -#ifdef CONFIG_PM - static const struct dev_pm_ops sdio_bus_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume) SET_RUNTIME_PM_OPS( @@ -207,14 +209,6 @@ static const struct dev_pm_ops sdio_bus_pm_ops = { ) }; -#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops) - -#else /* !CONFIG_PM */ - -#define SDIO_PM_OPS_PTR NULL - -#endif /* !CONFIG_PM */ - static struct bus_type sdio_bus_type = { .name = "sdio", .dev_groups = sdio_dev_groups, @@ -222,7 +216,7 @@ static struct bus_type sdio_bus_type = { .uevent = sdio_bus_uevent, .probe = sdio_bus_probe, .remove = sdio_bus_remove, - .pm = SDIO_PM_OPS_PTR, + .pm = &sdio_bus_pm_ops, }; int sdio_register_bus(void) @@ -295,7 +289,7 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) static void sdio_acpi_set_handle(struct sdio_func *func) { struct mmc_host *host = func->card->host; - u64 addr = (host->slotno << 16) | func->num; + u64 addr = ((u64)host->slotno << 16) | func->num; acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr); } @@ -303,6 +297,13 @@ static void sdio_acpi_set_handle(struct sdio_func *func) static inline void sdio_acpi_set_handle(struct sdio_func *func) {} #endif +static void sdio_set_of_node(struct sdio_func *func) +{ + struct mmc_host *host = func->card->host; + + func->dev.of_node = mmc_of_find_child_device(host, func->num); +} + /* * Register a new SDIO function with the driver model. */ @@ -312,6 +313,7 @@ int sdio_add_func(struct sdio_func *func) dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num); + sdio_set_of_node(func); sdio_acpi_set_handle(func); ret = device_add(&func->dev); if (ret == 0) { @@ -335,6 +337,7 @@ void sdio_remove_func(struct sdio_func *func) dev_pm_domain_detach(&func->dev, false); device_del(&func->dev); + of_node_put(func->dev.of_node); put_device(&func->dev); } diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 69bbf2adb329..27117ba47073 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -18,11 +18,14 @@ #include <linux/module.h> #include <linux/slab.h> +#include "slot-gpio.h" + struct mmc_gpio { struct gpio_desc *ro_gpio; struct gpio_desc *cd_gpio; bool override_ro_active_level; bool override_cd_active_level; + irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id); char *ro_label; char cd_label[0]; }; @@ -38,32 +41,20 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) return IRQ_HANDLED; } -static int mmc_gpio_alloc(struct mmc_host *host) +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)); - host->slot.handler_priv = ctx; - } + struct mmc_gpio *ctx = devm_kzalloc(host->parent, + 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)); + host->slot.handler_priv = ctx; + host->slot.cd_irq = -EINVAL; } - mutex_unlock(&host->slot.lock); - return ctx ? 0 : -ENOMEM; } @@ -103,29 +94,19 @@ EXPORT_SYMBOL(mmc_gpio_get_cd); * @gpio: gpio number requested * * As devm_* managed functions are used in mmc_gpio_request_ro(), client - * drivers do not need to explicitly call mmc_gpio_free_ro() for freeing up, - * if the requesting and freeing are only needed at probing and unbinding time - * for once. However, if client drivers do something special like runtime - * switching for write-protection, they are responsible for calling - * mmc_gpio_request_ro() and mmc_gpio_free_ro() as a pair on their own. + * drivers do not need to worry about freeing up memory. * * Returns zero on success, else an error. */ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) { - struct mmc_gpio *ctx; + struct mmc_gpio *ctx = host->slot.handler_priv; 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 = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN, + ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN, ctx->ro_label); if (ret < 0) return ret; @@ -156,8 +137,10 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host) irq = -EINVAL; if (irq >= 0) { - ret = devm_request_threaded_irq(&host->class_dev, irq, - NULL, mmc_gpio_cd_irqt, + if (!ctx->cd_gpio_isr) + ctx->cd_gpio_isr = mmc_gpio_cd_irqt; + ret = devm_request_threaded_irq(host->parent, irq, + NULL, ctx->cd_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ctx->cd_label, host); if (ret < 0) @@ -171,6 +154,19 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host) } EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); +/* Register an alternate interrupt service routine for + * the card-detect GPIO. + */ +void mmc_gpio_set_cd_isr(struct mmc_host *host, + irqreturn_t (*isr)(int irq, void *dev_id)) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + WARN_ON(ctx->cd_gpio_isr); + ctx->cd_gpio_isr = isr; +} +EXPORT_SYMBOL(mmc_gpio_set_cd_isr); + /** * mmc_gpio_request_cd - request a gpio for card-detection * @host: mmc host @@ -178,11 +174,7 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); * @debounce: debounce time in microseconds * * As devm_* managed functions are used in mmc_gpio_request_cd(), client - * drivers do not need to explicitly call mmc_gpio_free_cd() for freeing up, - * if the requesting and freeing are only needed at probing and unbinding time - * for once. However, if client drivers do something special like runtime - * switching for card-detection, they are responsible for calling - * mmc_gpio_request_cd() and mmc_gpio_free_cd() as a pair on their own. + * drivers do not need to worry about freeing up memory. * * If GPIO debouncing is desired, set the debounce parameter to a non-zero * value. The caller is responsible for ensuring that the GPIO driver associated @@ -193,16 +185,10 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, unsigned int debounce) { - struct mmc_gpio *ctx; + struct mmc_gpio *ctx = host->slot.handler_priv; int ret; - ret = mmc_gpio_alloc(host); - if (ret < 0) - return ret; - - ctx = host->slot.handler_priv; - - ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN, + ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN, ctx->cd_label); if (ret < 0) /* @@ -226,55 +212,6 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, EXPORT_SYMBOL(mmc_gpio_request_cd); /** - * mmc_gpio_free_ro - free the write-protection gpio - * @host: mmc host - * - * It's provided only for cases that client drivers need to manually free - * up the write-protection gpio requested by mmc_gpio_request_ro(). - */ -void mmc_gpio_free_ro(struct mmc_host *host) -{ - struct mmc_gpio *ctx = host->slot.handler_priv; - int gpio; - - if (!ctx || !ctx->ro_gpio) - return; - - gpio = desc_to_gpio(ctx->ro_gpio); - ctx->ro_gpio = NULL; - - devm_gpio_free(&host->class_dev, gpio); -} -EXPORT_SYMBOL(mmc_gpio_free_ro); - -/** - * mmc_gpio_free_cd - free the card-detection gpio - * @host: mmc host - * - * It's provided only for cases that client drivers need to manually free - * up the card-detection gpio requested by mmc_gpio_request_cd(). - */ -void mmc_gpio_free_cd(struct mmc_host *host) -{ - struct mmc_gpio *ctx = host->slot.handler_priv; - int gpio; - - if (!ctx || !ctx->cd_gpio) - return; - - if (host->slot.cd_irq >= 0) { - devm_free_irq(&host->class_dev, host->slot.cd_irq, host); - host->slot.cd_irq = -EINVAL; - } - - gpio = desc_to_gpio(ctx->cd_gpio); - ctx->cd_gpio = NULL; - - devm_gpio_free(&host->class_dev, gpio); -} -EXPORT_SYMBOL(mmc_gpio_free_cd); - -/** * mmc_gpiod_request_cd - request a gpio descriptor for card-detection * @host: mmc host * @con_id: function within the GPIO consumer @@ -285,8 +222,7 @@ EXPORT_SYMBOL(mmc_gpio_free_cd); * to NULL to ignore * * Use this function in place of mmc_gpio_request_cd() to use the GPIO - * descriptor API. Note that it is paired with mmc_gpiod_free_cd() not - * mmc_gpio_free_cd(). Note also that it must be called prior to mmc_add_host() + * descriptor API. Note that it must be called prior to mmc_add_host() * otherwise the caller must also call mmc_gpiod_request_cd_irq(). * * Returns zero on success, else an error. @@ -295,16 +231,10 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, unsigned int idx, bool override_active_level, unsigned int debounce, bool *gpio_invert) { - struct mmc_gpio *ctx; + struct mmc_gpio *ctx = host->slot.handler_priv; struct gpio_desc *desc; int ret; - ret = mmc_gpio_alloc(host); - if (ret < 0) - return ret; - - ctx = host->slot.handler_priv; - if (!con_id) con_id = ctx->cd_label; @@ -339,8 +269,7 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd); * set to NULL to ignore * * Use this function in place of mmc_gpio_request_ro() to use the GPIO - * descriptor API. Note that it is paired with mmc_gpiod_free_ro() not - * mmc_gpio_free_ro(). + * descriptor API. * * Returns zero on success, else an error. */ @@ -348,16 +277,10 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, unsigned int idx, bool override_active_level, unsigned int debounce, bool *gpio_invert) { - struct mmc_gpio *ctx; + struct mmc_gpio *ctx = host->slot.handler_priv; struct gpio_desc *desc; int ret; - ret = mmc_gpio_alloc(host); - if (ret < 0) - return ret; - - ctx = host->slot.handler_priv; - if (!con_id) con_id = ctx->ro_label; @@ -380,28 +303,3 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, return 0; } EXPORT_SYMBOL(mmc_gpiod_request_ro); - -/** - * mmc_gpiod_free_cd - free the card-detection gpio descriptor - * @host: mmc host - * - * It's provided only for cases that client drivers need to manually free - * up the card-detection gpio requested by mmc_gpiod_request_cd(). - */ -void mmc_gpiod_free_cd(struct mmc_host *host) -{ - struct mmc_gpio *ctx = host->slot.handler_priv; - - if (!ctx || !ctx->cd_gpio) - return; - - if (host->slot.cd_irq >= 0) { - devm_free_irq(&host->class_dev, host->slot.cd_irq, host); - host->slot.cd_irq = -EINVAL; - } - - devm_gpiod_put(host->parent, ctx->cd_gpio); - - ctx->cd_gpio = NULL; -} -EXPORT_SYMBOL(mmc_gpiod_free_cd); diff --git a/drivers/mmc/core/slot-gpio.h b/drivers/mmc/core/slot-gpio.h new file mode 100644 index 000000000000..8c1854dc5d58 --- /dev/null +++ b/drivers/mmc/core/slot-gpio.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2014 Linaro Ltd + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef _MMC_CORE_SLOTGPIO_H +#define _MMC_CORE_SLOTGPIO_H + +int mmc_gpio_alloc(struct mmc_host *host); + +#endif diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 13860656104b..7f4db908f89b 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -57,6 +57,7 @@ config MMC_SDHCI_IO_ACCESSORS config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER bool + depends on MMC_SDHCI select MMC_SDHCI_IO_ACCESSORS help This option is selected by drivers running on big endian hosts @@ -82,6 +83,7 @@ config MMC_SDHCI_PCI config MMC_RICOH_MMC bool "Ricoh MMC Controller Disabler" depends on MMC_SDHCI_PCI + default y help This adds a pci quirk to disable Ricoh MMC Controller. This proprietary controller is unnecessary because the SDHCI driver @@ -130,7 +132,7 @@ config MMC_SDHCI_OF_ARASAN config MMC_SDHCI_OF_ESDHC tristate "SDHCI OF support for the Freescale eSDHC controller" depends on MMC_SDHCI_PLTFM - depends on PPC_OF + depends on PPC select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER help This selects the Freescale eSDHC controller support. @@ -142,7 +144,7 @@ config MMC_SDHCI_OF_ESDHC config MMC_SDHCI_OF_HLWD tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers" depends on MMC_SDHCI_PLTFM - depends on PPC_OF + depends on PPC select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER help This selects the Secure Digital Host Controller Interface (SDHCI) @@ -228,6 +230,7 @@ config MMC_SDHCI_PXAV3 tristate "Marvell MMP2 SD Host Controller support (PXAV3)" depends on CLKDEV_LOOKUP depends on MMC_SDHCI_PLTFM + depends on ARCH_BERLIN || ARCH_MMP || ARCH_MVEBU || COMPILE_TEST default CPU_MMP2 help This selects the Marvell(R) PXAV3 SD Host Controller. @@ -240,6 +243,7 @@ config MMC_SDHCI_PXAV2 tristate "Marvell PXA9XX SD Host Controller support (PXAV2)" depends on CLKDEV_LOOKUP depends on MMC_SDHCI_PLTFM + depends on ARCH_MMP || COMPILE_TEST default CPU_PXA910 help This selects the Marvell(R) PXAV2 SD Host Controller. @@ -251,6 +255,7 @@ config MMC_SDHCI_PXAV2 config MMC_SDHCI_SPEAR tristate "SDHCI support on ST SPEAr platform" depends on MMC_SDHCI && PLAT_SPEAR + depends on OF help This selects the Secure Digital Host Controller Interface (SDHCI) often referrered to as the HSMMC block in some of the ST SPEAR range @@ -292,6 +297,31 @@ config MMC_SDHCI_BCM2835 If unsure, say N. +config MMC_SDHCI_F_SDH30 + tristate "SDHCI support for Fujitsu Semiconductor F_SDH30" + depends on MMC_SDHCI_PLTFM + depends on OF + help + This selects the Secure Digital Host Controller Interface (SDHCI) + Needed by some Fujitsu SoC for MMC / SD / SDIO support. + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + +config MMC_SDHCI_IPROC + tristate "SDHCI platform support for the iProc SD/MMC Controller" + depends on ARCH_BCM_IPROC || COMPILE_TEST + depends on MMC_SDHCI_PLTFM + default ARCH_BCM_IPROC + select MMC_SDHCI_IO_ACCESSORS + help + This selects the iProc SD/MMC controller. + + If you have an IPROC platform with SD or MMC devices, + say Y or M here. + + If unsure, say N. + config MMC_MOXART tristate "MOXART SD/MMC Host Controller support" depends on ARCH_MOXART && MMC @@ -580,7 +610,7 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND config MMC_DW tristate "Synopsys DesignWare Memory Card Interface" depends on HAS_DMA - depends on ARC || ARM || MIPS || COMPILE_TEST + depends on ARC || ARM || ARM64 || MIPS || COMPILE_TEST help This selects support for the Synopsys DesignWare Mobile Storage IP block, this provides host support for SD and MMC interfaces, in both @@ -748,3 +778,8 @@ config MMC_SUNXI help This selects support for the SD/MMC Host Controller on Allwinner sunxi SoCs. + +config MMC_TOSHIBA_PCI + tristate "Toshiba Type A SD/MMC Card Interface Driver" + depends on PCI + help diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index b09ecfb88269..711e913450f5 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o +obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o @@ -55,6 +56,7 @@ obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o +obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o @@ -69,6 +71,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o +obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index c97001e15227..0aa44e679df4 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -135,10 +135,17 @@ #define ATMCI_REGS_SIZE 0x100 /* Register access macros */ -#define atmci_readl(port,reg) \ +#ifdef CONFIG_AVR32 +#define atmci_readl(port, reg) \ __raw_readl((port)->regs + reg) -#define atmci_writel(port,reg,value) \ +#define atmci_writel(port, reg, value) \ __raw_writel((value), (port)->regs + reg) +#else +#define atmci_readl(port, reg) \ + readl_relaxed((port)->regs + reg) +#define atmci_writel(port, reg, value) \ + writel_relaxed((value), (port)->regs + reg) +#endif /* On AVR chips the Peripheral DMA Controller is not connected to MCI. */ #ifdef CONFIG_AVR32 diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 77250d4b1979..03d7c7521d97 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -30,13 +30,16 @@ #include <linux/stat.h> #include <linux/types.h> #include <linux/platform_data/atmel.h> +#include <linux/platform_data/mmc-atmel-mci.h> #include <linux/mmc/host.h> #include <linux/mmc/sdio.h> -#include <mach/atmel-mci.h> #include <linux/atmel-mci.h> #include <linux/atmel_pdc.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/pinctrl/consumer.h> #include <asm/cacheflush.h> #include <asm/io.h> @@ -44,6 +47,8 @@ #include "atmel-mci-regs.h" +#define AUTOSUSPEND_DELAY 50 + #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) #define ATMCI_DMA_THRESHOLD 16 @@ -386,20 +391,19 @@ static int atmci_regs_show(struct seq_file *s, void *v) if (!buf) return -ENOMEM; + pm_runtime_get_sync(&host->pdev->dev); + /* * Grab a more or less consistent snapshot. Note that we're * not disabling interrupts, so IMR and SR may not be * consistent. */ - ret = clk_prepare_enable(host->mck); - if (ret) - goto out; - spin_lock_bh(&host->lock); memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); spin_unlock_bh(&host->lock); - clk_disable_unprepare(host->mck); + pm_runtime_mark_last_busy(&host->pdev->dev); + pm_runtime_put_autosuspend(&host->pdev->dev); seq_printf(s, "MR:\t0x%08x%s%s ", buf[ATMCI_MR / 4], @@ -449,7 +453,6 @@ static int atmci_regs_show(struct seq_file *s, void *v) val & ATMCI_CFG_LSYNC ? " LSYNC" : ""); } -out: kfree(buf); return ret; @@ -560,6 +563,9 @@ atmci_of_init(struct platform_device *pdev) pdata->slot[slot_id].detect_is_active_high = of_property_read_bool(cnp, "cd-inverted"); + pdata->slot[slot_id].non_removable = + of_property_read_bool(cnp, "non-removable"); + pdata->slot[slot_id].wp_pin = of_get_named_gpio(cnp, "wp-gpios", 0); } @@ -1252,6 +1258,8 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(slot->mrq); dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode); + pm_runtime_get_sync(&host->pdev->dev); + /* * We may "know" the card is gone even though there's still an * electrical connection. If so, we really need to communicate @@ -1281,7 +1289,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct atmel_mci_slot *slot = mmc_priv(mmc); struct atmel_mci *host = slot->host; unsigned int i; - bool unprepare_clk; + + pm_runtime_get_sync(&host->pdev->dev); slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; switch (ios->bus_width) { @@ -1297,13 +1306,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) unsigned int clock_min = ~0U; u32 clkdiv; - clk_prepare(host->mck); - unprepare_clk = true; - spin_lock_bh(&host->lock); if (!host->mode_reg) { - clk_enable(host->mck); - unprepare_clk = false; atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); if (host->caps.has_cfg_reg) @@ -1371,8 +1375,6 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } else { bool any_slot_active = false; - unprepare_clk = false; - spin_lock_bh(&host->lock); slot->clock = 0; for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { @@ -1385,17 +1387,12 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); if (host->mode_reg) { atmci_readl(host, ATMCI_MR); - clk_disable(host->mck); - unprepare_clk = true; } host->mode_reg = 0; } spin_unlock_bh(&host->lock); } - if (unprepare_clk) - clk_unprepare(host->mck); - switch (ios->power_mode) { case MMC_POWER_OFF: if (!IS_ERR(mmc->supply.vmmc)) @@ -1421,6 +1418,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) */ break; } + + pm_runtime_mark_last_busy(&host->pdev->dev); + pm_runtime_put_autosuspend(&host->pdev->dev); } static int atmci_get_ro(struct mmc_host *mmc) @@ -1512,6 +1512,9 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) spin_unlock(&host->lock); mmc_request_done(prev_mmc, mrq); spin_lock(&host->lock); + + pm_runtime_mark_last_busy(&host->pdev->dev); + pm_runtime_put_autosuspend(&host->pdev->dev); } static void atmci_command_complete(struct atmel_mci *host, @@ -2137,7 +2140,7 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init atmci_init_slot(struct atmel_mci *host, +static int atmci_init_slot(struct atmel_mci *host, struct mci_slot_pdata *slot_data, unsigned int id, u32 sdc_reg, u32 sdio_irq) { @@ -2206,8 +2209,12 @@ static int __init atmci_init_slot(struct atmel_mci *host, } } - if (!gpio_is_valid(slot->detect_pin)) - mmc->caps |= MMC_CAP_NEEDS_POLL; + if (!gpio_is_valid(slot->detect_pin)) { + if (slot_data->non_removable) + mmc->caps |= MMC_CAP_NONREMOVABLE; + else + mmc->caps |= MMC_CAP_NEEDS_POLL; + } if (gpio_is_valid(slot->wp_pin)) { if (devm_gpio_request(&host->pdev->dev, slot->wp_pin, @@ -2265,55 +2272,25 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot, mmc_free_host(slot->mmc); } -static bool atmci_filter(struct dma_chan *chan, void *pdata) +static int atmci_configure_dma(struct atmel_mci *host) { - struct mci_platform_data *sl_pdata = pdata; - struct mci_dma_data *sl; - - if (!sl_pdata) - return false; + host->dma.chan = dma_request_slave_channel_reason(&host->pdev->dev, + "rxtx"); + if (IS_ERR(host->dma.chan)) + return PTR_ERR(host->dma.chan); + + dev_info(&host->pdev->dev, "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; - sl = sl_pdata->dma_slave; - if (sl && find_slave_dev(sl) == chan->device->dev) { - chan->private = slave_data_ptr(sl); - return true; - } else { - return false; - } -} - -static bool atmci_configure_dma(struct atmel_mci *host) -{ - struct mci_platform_data *pdata; - dma_cap_mask_t mask; - - if (host == NULL) - return false; - - pdata = host->pdev->dev.platform_data; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata, - &host->pdev->dev, "rxtx"); - if (!host->dma.chan) { - dev_warn(&host->pdev->dev, "no DMA channel available\n"); - return false; - } else { - dev_info(&host->pdev->dev, - "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; - } + return 0; } /* @@ -2321,7 +2298,7 @@ static bool atmci_configure_dma(struct atmel_mci *host) * HSMCI provides DMA support and a new config register but no more supports * PDC. */ -static void __init atmci_get_cap(struct atmel_mci *host) +static void atmci_get_cap(struct atmel_mci *host) { unsigned int version; @@ -2370,7 +2347,7 @@ static void __init atmci_get_cap(struct atmel_mci *host) } } -static int __init atmci_probe(struct platform_device *pdev) +static int atmci_probe(struct platform_device *pdev) { struct mci_platform_data *pdata; struct atmel_mci *host; @@ -2417,19 +2394,23 @@ static int __init atmci_probe(struct platform_device *pdev) atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); host->bus_hz = clk_get_rate(host->mck); - clk_disable_unprepare(host->mck); host->mapbase = regs->start; tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host); ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host); - if (ret) + if (ret) { + clk_disable_unprepare(host->mck); return ret; + } /* Get MCI capabilities and set operations according to it */ atmci_get_cap(host); - if (atmci_configure_dma(host)) { + ret = atmci_configure_dma(host); + if (ret == -EPROBE_DEFER) + goto err_dma_probe_defer; + if (ret == 0) { host->prepare_data = &atmci_prepare_data_dma; host->submit_data = &atmci_submit_data_dma; host->stop_transfer = &atmci_stop_transfer_dma; @@ -2449,6 +2430,12 @@ static int __init atmci_probe(struct platform_device *pdev) setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + /* We need at least one slot to succeed */ nr_slots = 0; ret = -ENODEV; @@ -2491,6 +2478,9 @@ static int __init atmci_probe(struct platform_device *pdev) "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", host->mapbase, irq, nr_slots); + pm_runtime_mark_last_busy(&host->pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + return 0; err_dma_alloc: @@ -2499,18 +2489,26 @@ err_dma_alloc: atmci_cleanup_slot(host->slot[i], i); } err_init_slot: + clk_disable_unprepare(host->mck); + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + del_timer_sync(&host->timer); - if (host->dma.chan) + if (!IS_ERR(host->dma.chan)) dma_release_channel(host->dma.chan); +err_dma_probe_defer: free_irq(irq, host); return ret; } -static int __exit atmci_remove(struct platform_device *pdev) +static int atmci_remove(struct platform_device *pdev) { struct atmel_mci *host = platform_get_drvdata(pdev); unsigned int i; + pm_runtime_get_sync(&pdev->dev); + if (host->buffer) dma_free_coherent(&pdev->dev, host->buf_size, host->buffer, host->buf_phys_addr); @@ -2520,41 +2518,62 @@ static int __exit atmci_remove(struct platform_device *pdev) atmci_cleanup_slot(host->slot[i], i); } - clk_prepare_enable(host->mck); atmci_writel(host, ATMCI_IDR, ~0UL); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); atmci_readl(host, ATMCI_SR); - clk_disable_unprepare(host->mck); del_timer_sync(&host->timer); - if (host->dma.chan) + if (!IS_ERR(host->dma.chan)) dma_release_channel(host->dma.chan); free_irq(platform_get_irq(pdev, 0), host); + clk_disable_unprepare(host->mck); + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + return 0; } -static struct platform_driver atmci_driver = { - .remove = __exit_p(atmci_remove), - .driver = { - .name = "atmel_mci", - .of_match_table = of_match_ptr(atmci_dt_ids), - }, -}; - -static int __init atmci_init(void) +#ifdef CONFIG_PM +static int atmci_runtime_suspend(struct device *dev) { - return platform_driver_probe(&atmci_driver, atmci_probe); + struct atmel_mci *host = dev_get_drvdata(dev); + + clk_disable_unprepare(host->mck); + + pinctrl_pm_select_sleep_state(dev); + + return 0; } -static void __exit atmci_exit(void) +static int atmci_runtime_resume(struct device *dev) { - platform_driver_unregister(&atmci_driver); + struct atmel_mci *host = dev_get_drvdata(dev); + + pinctrl_pm_select_default_state(dev); + + return clk_prepare_enable(host->mck); } +#endif -late_initcall(atmci_init); /* try to load after dma driver when built-in */ -module_exit(atmci_exit); +static const struct dev_pm_ops atmci_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(atmci_runtime_suspend, atmci_runtime_resume, NULL) +}; + +static struct platform_driver atmci_driver = { + .probe = atmci_probe, + .remove = atmci_remove, + .driver = { + .name = "atmel_mci", + .of_match_table = of_match_ptr(atmci_dt_ids), + .pm = &atmci_dev_pm_ops, + }, +}; +module_platform_driver(atmci_driver); MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 725f6a6fd89b..ed77fbfa4774 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -1206,7 +1206,6 @@ static struct platform_driver au1xmmc_driver = { .resume = au1xmmc_resume, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, }, }; diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 5d4c5e0fba2f..1625f908dc70 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1466,7 +1466,6 @@ static const struct dev_pm_ops davinci_mmcsd_pm = { static struct platform_driver davinci_mmcsd_driver = { .driver = { .name = "davinci_mmc", - .owner = THIS_MODULE, .pm = davinci_mmcsd_pm_ops, .of_match_table = davinci_mmc_dt_ids, }, diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 0fbc53ac7eae..e761eb1b1441 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -21,42 +21,7 @@ #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_CLKSEL_WAKEUP_INT BIT(11) - -#define EXYNOS4210_FIXED_CIU_CLK_DIV 2 -#define EXYNOS4412_FIXED_CIU_CLK_DIV 4 - -/* Block number in eMMC */ -#define DWMCI_BLOCK_NUM 0xFFFFFFFF - -#define SDMMC_EMMCP_BASE 0x1000 -#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010) -#define SDMMC_MPSBEGIN0 (SDMMC_EMMCP_BASE + 0x0200) -#define SDMMC_MPSEND0 (SDMMC_EMMCP_BASE + 0x0204) -#define SDMMC_MPSCTRL0 (SDMMC_EMMCP_BASE + 0x020C) - -/* SMU control bits */ -#define DWMCI_MPSCTRL_SECURE_READ_BIT BIT(7) -#define DWMCI_MPSCTRL_SECURE_WRITE_BIT BIT(6) -#define DWMCI_MPSCTRL_NON_SECURE_READ_BIT BIT(5) -#define DWMCI_MPSCTRL_NON_SECURE_WRITE_BIT BIT(4) -#define DWMCI_MPSCTRL_USE_FUSE_KEY BIT(3) -#define DWMCI_MPSCTRL_ECB_MODE BIT(2) -#define DWMCI_MPSCTRL_ENCRYPTION BIT(1) -#define DWMCI_MPSCTRL_VALID BIT(0) - -#define EXYNOS_CCLKIN_MIN 50000000 /* unit: HZ */ +#include "dw_mmc-exynos.h" /* Variations in Exynos specific dw-mshc controller */ enum dw_mci_exynos_type { @@ -65,6 +30,8 @@ enum dw_mci_exynos_type { DW_MCI_TYPE_EXYNOS5250, DW_MCI_TYPE_EXYNOS5420, DW_MCI_TYPE_EXYNOS5420_SMU, + DW_MCI_TYPE_EXYNOS7, + DW_MCI_TYPE_EXYNOS7_SMU, }; /* Exynos implementation specific driver private data */ @@ -73,7 +40,12 @@ struct dw_mci_exynos_priv_data { u8 ciu_div; u32 sdr_timing; u32 ddr_timing; + u32 hs400_timing; + u32 tuned_sample; u32 cur_speed; + u32 dqs_delay; + u32 saved_dqs_en; + u32 saved_strobe_ctrl; }; static struct dw_mci_exynos_compatible { @@ -95,20 +67,52 @@ static struct dw_mci_exynos_compatible { }, { .compatible = "samsung,exynos5420-dw-mshc-smu", .ctrl_type = DW_MCI_TYPE_EXYNOS5420_SMU, + }, { + .compatible = "samsung,exynos7-dw-mshc", + .ctrl_type = DW_MCI_TYPE_EXYNOS7, + }, { + .compatible = "samsung,exynos7-dw-mshc-smu", + .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU, }, }; +static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412) + return EXYNOS4412_FIXED_CIU_CLK_DIV; + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) + return EXYNOS4210_FIXED_CIU_CLK_DIV; + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1; + else + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1; +} + static int dw_mci_exynos_priv_init(struct dw_mci *host) { struct dw_mci_exynos_priv_data *priv = host->priv; - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU) { + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { mci_writel(host, MPSBEGIN0, 0); - mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM); - mci_writel(host, MPSCTRL0, DWMCI_MPSCTRL_SECURE_WRITE_BIT | - DWMCI_MPSCTRL_NON_SECURE_READ_BIT | - DWMCI_MPSCTRL_VALID | - DWMCI_MPSCTRL_NON_SECURE_WRITE_BIT); + mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX); + mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT | + SDMMC_MPSCTRL_NON_SECURE_READ_BIT | + SDMMC_MPSCTRL_VALID | + SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT); + } + + if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) { + priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL); + priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN); + priv->saved_dqs_en |= AXI_NON_BLOCKING_WR; + mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en); + if (!priv->dqs_delay) + priv->dqs_delay = + DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl); } return 0; @@ -117,12 +121,32 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) static int dw_mci_exynos_setup_clock(struct dw_mci *host) { struct dw_mci_exynos_priv_data *priv = host->priv; - unsigned long rate = clk_get_rate(host->ciu_clk); - host->bus_hz = rate / (priv->ciu_div + 1); + host->bus_hz /= (priv->ciu_div + 1); + return 0; } +static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + u32 clksel; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); + + clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); +} + #ifdef CONFIG_PM_SLEEP static int dw_mci_exynos_suspend(struct device *dev) { @@ -153,11 +177,22 @@ static int dw_mci_exynos_resume(struct device *dev) static int dw_mci_exynos_resume_noirq(struct device *dev) { struct dw_mci *host = dev_get_drvdata(dev); + struct dw_mci_exynos_priv_data *priv = host->priv; u32 clksel; - clksel = mci_readl(host, CLKSEL); - if (clksel & SDMMC_CLKSEL_WAKEUP_INT) - mci_writel(host, CLKSEL, clksel); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); + + if (clksel & SDMMC_CLKSEL_WAKEUP_INT) { + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); + } return 0; } @@ -169,6 +204,7 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) { + struct dw_mci_exynos_priv_data *priv = host->priv; /* * Exynos4412 and Exynos5250 extends the use of CMD register with the * use of bit 29 (which is reserved on standard MSHC controllers) for @@ -176,45 +212,105 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) * 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; + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { + if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL64))) + *cmdr |= SDMMC_CMD_USE_HOLD_REG; + } else { + 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) +static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) { struct dw_mci_exynos_priv_data *priv = host->priv; - unsigned int wanted = ios->clock; - unsigned long actual; - u8 div = priv->ciu_div + 1; + u32 dqs, strobe; - if (ios->timing == MMC_TIMING_MMC_DDR52) { - mci_writel(host, CLKSEL, priv->ddr_timing); - /* Should be double rate for DDR mode */ - if (ios->bus_width == MMC_BUS_WIDTH_8) - wanted <<= 1; + /* + * Not supported to configure register + * related to HS400 + */ + if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) + return; + + dqs = priv->saved_dqs_en; + strobe = priv->saved_strobe_ctrl; + + if (timing == MMC_TIMING_MMC_HS400) { + dqs |= DATA_STROBE_EN; + strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay); } else { - mci_writel(host, CLKSEL, priv->sdr_timing); + dqs &= ~DATA_STROBE_EN; } - /* Don't care if wanted clock is zero */ - if (!wanted) + mci_writel(host, HS400_DQS_EN, dqs); + mci_writel(host, HS400_DLINE_CTRL, strobe); +} + +static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + unsigned long actual; + u8 div; + int ret; + /* + * Don't care if wanted clock is zero or + * ciu clock is unavailable + */ + if (!wanted || IS_ERR(host->ciu_clk)) return; /* Guaranteed minimum frequency for cclkin */ if (wanted < EXYNOS_CCLKIN_MIN) wanted = EXYNOS_CCLKIN_MIN; - if (wanted != priv->cur_speed) { - int ret = clk_set_rate(host->ciu_clk, wanted * div); - if (ret) - dev_warn(host->dev, - "failed to set clk-rate %u error: %d\n", - wanted * div, ret); - actual = clk_get_rate(host->ciu_clk); - host->bus_hz = actual / div; - priv->cur_speed = wanted; - host->current_speed = 0; + if (wanted == priv->cur_speed) + return; + + div = dw_mci_exynos_get_ciu_div(host); + ret = clk_set_rate(host->ciu_clk, wanted * div); + if (ret) + dev_warn(host->dev, + "failed to set clk-rate %u error: %d\n", + wanted * div, ret); + actual = clk_get_rate(host->ciu_clk); + host->bus_hz = actual / div; + priv->cur_speed = wanted; + host->current_speed = 0; +} + +static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + unsigned int wanted = ios->clock; + u32 timing = ios->timing, clksel; + + switch (timing) { + case MMC_TIMING_MMC_HS400: + /* Update tuned sample timing */ + clksel = SDMMC_CLKSEL_UP_SAMPLE( + priv->hs400_timing, priv->tuned_sample); + wanted <<= 1; + break; + case MMC_TIMING_MMC_DDR52: + clksel = priv->ddr_timing; + /* Should be double rate for DDR mode */ + if (ios->bus_width == MMC_BUS_WIDTH_8) + wanted <<= 1; + break; + default: + clksel = priv->sdr_timing; } + + /* Set clock timing for the requested speed mode*/ + dw_mci_exynos_set_clksel_timing(host, clksel); + + /* Configure setting for HS400 */ + dw_mci_exynos_config_hs400(host, timing); + + /* Configure clock rate */ + dw_mci_exynos_adjust_clock(host, wanted); } static int dw_mci_exynos_parse_dt(struct dw_mci *host) @@ -227,10 +323,8 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) int ret; priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(host->dev, "mem alloc failed for private data\n"); + if (!priv) return -ENOMEM; - } for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) { if (of_device_is_compatible(np, exynos_compat[idx].compatible)) @@ -259,32 +353,70 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) return ret; priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); + + ret = of_property_read_u32_array(np, + "samsung,dw-mshc-hs400-timing", timing, 2); + if (!ret && of_property_read_u32(np, + "samsung,read-strobe-delay", &priv->dqs_delay)) + dev_dbg(host->dev, + "read-strobe-delay is not found, assuming usage of default value\n"); + + priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], + HS400_FIXED_CIU_CLK_DIV); host->priv = priv; return 0; } static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host) { - return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); + struct dw_mci_exynos_priv_data *priv = host->priv; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64)); + else + return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); } static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) { u32 clksel; - clksel = mci_readl(host, CLKSEL); - clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample); - mci_writel(host, CLKSEL, clksel); + struct dw_mci_exynos_priv_data *priv = host->priv; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); } static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) { + struct dw_mci_exynos_priv_data *priv = host->priv; u32 clksel; u8 sample; - clksel = mci_readl(host, CLKSEL); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); + sample = (clksel + 1) & 0x7; - clksel = (clksel & ~0x7) | sample; - mci_writel(host, CLKSEL, clksel); + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); + return sample; } @@ -314,76 +446,48 @@ out: return loc; } -static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode, - struct dw_mci_tuning_data *tuning_data) +static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot) { struct dw_mci *host = slot->host; + struct dw_mci_exynos_priv_data *priv = host->priv; struct mmc_host *mmc = slot->mmc; - const u8 *blk_pattern = tuning_data->blk_pattern; - u8 *blk_test; - unsigned int blksz = tuning_data->blksz; u8 start_smpl, smpl, candiates = 0; s8 found = -1; int ret = 0; - blk_test = kmalloc(blksz, GFP_KERNEL); - if (!blk_test) - return -ENOMEM; - start_smpl = dw_mci_exynos_get_clksmpl(host); do { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_command stop = {0}; - struct mmc_data data = {0}; - struct scatterlist sg; - - cmd.opcode = opcode; - cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - - stop.opcode = MMC_STOP_TRANSMISSION; - stop.arg = 0; - stop.flags = MMC_RSP_R1B | MMC_CMD_AC; - - data.blksz = blksz; - data.blocks = 1; - data.flags = MMC_DATA_READ; - data.sg = &sg; - data.sg_len = 1; - - sg_init_one(&sg, blk_test, blksz); - mrq.cmd = &cmd; - mrq.stop = &stop; - mrq.data = &data; - host->mrq = &mrq; - mci_writel(host, TMOUT, ~0); smpl = dw_mci_exynos_move_next_clksmpl(host); - mmc_wait_for_req(mmc, &mrq); + if (!mmc_send_tuning(mmc)) + candiates |= (1 << smpl); - if (!cmd.error && !data.error) { - if (!memcmp(blk_pattern, blk_test, blksz)) - candiates |= (1 << smpl); - } else { - dev_dbg(host->dev, - "Tuning error: cmd.error:%d, data.error:%d\n", - cmd.error, data.error); - } } while (start_smpl != smpl); found = dw_mci_exynos_get_best_clksmpl(candiates); - if (found >= 0) + if (found >= 0) { dw_mci_exynos_set_clksmpl(host, found); - else + priv->tuned_sample = found; + } else { ret = -EIO; + } - kfree(blk_test); return ret; } +static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host, + struct mmc_ios *ios) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + + dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing); + dw_mci_exynos_adjust_clock(host, (ios->clock) << 1); + + return 0; +} + /* Common capabilities of Exynos4/Exynos5 SoC */ static unsigned long exynos_dwmmc_caps[4] = { MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, @@ -400,6 +504,7 @@ static const struct dw_mci_drv_data exynos_drv_data = { .set_ios = dw_mci_exynos_set_ios, .parse_dt = dw_mci_exynos_parse_dt, .execute_tuning = dw_mci_exynos_execute_tuning, + .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning, }; static const struct of_device_id dw_mci_exynos_match[] = { @@ -411,6 +516,10 @@ static const struct of_device_id dw_mci_exynos_match[] = { .data = &exynos_drv_data, }, { .compatible = "samsung,exynos5420-dw-mshc-smu", .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos7-dw-mshc", + .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos7-dw-mshc-smu", + .data = &exynos_drv_data, }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); @@ -434,7 +543,7 @@ static const struct dev_pm_ops dw_mci_exynos_pmops = { static struct platform_driver dw_mci_exynos_pltfm_driver = { .probe = dw_mci_exynos_probe, - .remove = __exit_p(dw_mci_pltfm_remove), + .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_exynos", .of_match_table = dw_mci_exynos_match, diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h new file mode 100644 index 000000000000..595c934e6166 --- /dev/null +++ b/drivers/mmc/host/dw_mmc-exynos.h @@ -0,0 +1,73 @@ +/* + * Exynos Specific Extensions for Synopsys DW Multimedia Card Interface driver + * + * Copyright (C) 2012-2014 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_EXYNOS_H_ +#define _DW_MMC_EXYNOS_H_ + +#define SDMMC_CLKSEL 0x09C +#define SDMMC_CLKSEL64 0x0A8 + +/* Extended Register's Offset */ +#define SDMMC_HS400_DQS_EN 0x180 +#define SDMMC_HS400_ASYNC_FIFO_CTRL 0x184 +#define SDMMC_HS400_DLINE_CTRL 0x188 + +/* CLKSEL register defines */ +#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_GET_DIV(x) (((x) >> 24) & 0x7) +#define SDMMC_CLKSEL_UP_SAMPLE(x, y) (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\ + SDMMC_CLKSEL_CCLK_SAMPLE(y)) +#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \ + SDMMC_CLKSEL_CCLK_DRIVE(y) | \ + SDMMC_CLKSEL_CCLK_DIVIDER(z)) +#define SDMMC_CLKSEL_TIMING_MASK SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7) +#define SDMMC_CLKSEL_WAKEUP_INT BIT(11) + +/* RCLK_EN register defines */ +#define DATA_STROBE_EN BIT(0) +#define AXI_NON_BLOCKING_WR BIT(7) + +/* DLINE_CTRL register defines */ +#define DQS_CTRL_RD_DELAY(x, y) (((x) & ~0x3FF) | ((y) & 0x3FF)) +#define DQS_CTRL_GET_RD_DELAY(x) ((x) & 0x3FF) + +/* Protector Register */ +#define SDMMC_EMMCP_BASE 0x1000 +#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010) +#define SDMMC_MPSBEGIN0 (SDMMC_EMMCP_BASE + 0x0200) +#define SDMMC_MPSEND0 (SDMMC_EMMCP_BASE + 0x0204) +#define SDMMC_MPSCTRL0 (SDMMC_EMMCP_BASE + 0x020C) + +/* SMU control defines */ +#define SDMMC_MPSCTRL_SECURE_READ_BIT BIT(7) +#define SDMMC_MPSCTRL_SECURE_WRITE_BIT BIT(6) +#define SDMMC_MPSCTRL_NON_SECURE_READ_BIT BIT(5) +#define SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT BIT(4) +#define SDMMC_MPSCTRL_USE_FUSE_KEY BIT(3) +#define SDMMC_MPSCTRL_ECB_MODE BIT(2) +#define SDMMC_MPSCTRL_ENCRYPTION BIT(1) +#define SDMMC_MPSCTRL_VALID BIT(0) + +/* Maximum number of Ending sector */ +#define SDMMC_ENDING_SEC_NR_MAX 0xFFFFFFFF + +/* Fixed clock divider */ +#define EXYNOS4210_FIXED_CIU_CLK_DIV 2 +#define EXYNOS4412_FIXED_CIU_CLK_DIV 4 +#define HS400_FIXED_CIU_CLK_DIV 1 + +/* Minimal required clock frequency for cclkin, unit: HZ */ +#define EXYNOS_CCLKIN_MIN 50000000 + +#endif /* _DW_MMC_EXYNOS_H_ */ diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 8b6572162ed9..ec6dbcdec693 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -35,6 +35,10 @@ static const struct dw_mci_drv_data socfpga_drv_data = { .prepare_command = dw_mci_pltfm_prepare_command, }; +static const struct dw_mci_drv_data pistachio_drv_data = { + .prepare_command = dw_mci_pltfm_prepare_command, +}; + int dw_mci_pltfm_register(struct platform_device *pdev, const struct dw_mci_drv_data *drv_data) { @@ -90,6 +94,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = { { .compatible = "snps,dw-mshc", }, { .compatible = "altr,socfpga-dw-mshc", .data = &socfpga_drv_data }, + { .compatible = "img,pistachio-dw-mshc", + .data = &pistachio_drv_data }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match); diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index f0c2cb1a210d..dbf166f94f1b 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -37,6 +37,9 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) unsigned int cclkin; u32 bus_hz; + if (ios->clock == 0) + return; + /* * cclkin: source clock of mmc controller * bus_hz: card interface clock generated by CLKGEN @@ -65,14 +68,32 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) } } +static int dw_mci_rockchip_init(struct dw_mci *host) +{ + /* It is slot 8 on Rockchip SoCs */ + host->sdio_id0 = 8; + + return 0; +} + +/* Common capabilities of RK3288 SoC */ +static unsigned long dw_mci_rk3288_dwmmc_caps[4] = { + MMC_CAP_RUNTIME_RESUME, /* emmc */ + MMC_CAP_RUNTIME_RESUME, /* sdmmc */ + MMC_CAP_RUNTIME_RESUME, /* sdio0 */ + MMC_CAP_RUNTIME_RESUME, /* sdio1 */ +}; static const struct dw_mci_drv_data rk2928_drv_data = { .prepare_command = dw_mci_rockchip_prepare_command, + .init = dw_mci_rockchip_init, }; static const struct dw_mci_drv_data rk3288_drv_data = { + .caps = dw_mci_rk3288_dwmmc_caps, .prepare_command = dw_mci_rockchip_prepare_command, .set_ios = dw_mci_rk3288_set_ios, .setup_clock = dw_mci_rk3288_setup_clock, + .init = dw_mci_rockchip_init, }; static const struct of_device_id dw_mci_rockchip_match[] = { @@ -120,7 +141,7 @@ static SIMPLE_DEV_PM_OPS(dw_mci_rockchip_pmops, static struct platform_driver dw_mci_rockchip_pltfm_driver = { .probe = dw_mci_rockchip_probe, - .remove = __exit_p(dw_mci_pltfm_remove), + .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_rockchip", .of_match_table = dw_mci_rockchip_match, diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 69f0cc68d5b2..38b29265cc7c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -27,6 +27,7 @@ #include <linux/stat.h> #include <linux/delay.h> #include <linux/irq.h> +#include <linux/mmc/card.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> @@ -34,7 +35,6 @@ #include <linux/mmc/dw_mmc.h> #include <linux/bitops.h> #include <linux/regulator/consumer.h> -#include <linux/workqueue.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/mmc/slot-gpio.h> @@ -62,8 +62,27 @@ SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ SDMMC_IDMAC_INT_TI) -struct idmac_desc { +struct idmac_desc_64addr { u32 des0; /* Control Descriptor */ + + u32 des1; /* Reserved */ + + u32 des2; /*Buffer sizes */ +#define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \ + ((d)->des2 = ((d)->des2 & cpu_to_le32(0x03ffe000)) | \ + ((cpu_to_le32(s)) & cpu_to_le32(0x1fff))) + + u32 des3; /* Reserved */ + + u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/ + u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/ + + u32 des6; /* Lower 32-bits of Next Descriptor Address */ + u32 des7; /* Upper 32-bits of Next Descriptor Address */ +}; + +struct idmac_desc { + __le32 des0; /* Control Descriptor */ #define IDMAC_DES0_DIC BIT(1) #define IDMAC_DES0_LD BIT(2) #define IDMAC_DES0_FD BIT(3) @@ -72,17 +91,19 @@ struct idmac_desc { #define IDMAC_DES0_CES BIT(30) #define IDMAC_DES0_OWN BIT(31) - u32 des1; /* Buffer sizes */ + __le32 des1; /* Buffer sizes */ #define IDMAC_SET_BUFFER1_SIZE(d, s) \ ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff)) - u32 des2; /* buffer 1 physical address */ + __le32 des2; /* buffer 1 physical address */ - u32 des3; /* buffer 2 physical address */ + __le32 des3; /* buffer 2 physical address */ }; #endif /* CONFIG_MMC_DW_IDMAC */ static bool dw_mci_reset(struct dw_mci *host); +static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); +static int dw_mci_card_busy(struct mmc_host *mmc); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -295,7 +316,9 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) if (cmdr == MMC_READ_SINGLE_BLOCK || cmdr == MMC_READ_MULTIPLE_BLOCK || cmdr == MMC_WRITE_BLOCK || - cmdr == MMC_WRITE_MULTIPLE_BLOCK) { + cmdr == MMC_WRITE_MULTIPLE_BLOCK || + cmdr == MMC_SEND_TUNING_BLOCK || + cmdr == MMC_SEND_TUNING_BLOCK_HS200) { stop->opcode = MMC_STOP_TRANSMISSION; stop->arg = 0; stop->flags = MMC_RSP_R1B | MMC_CMD_AC; @@ -314,6 +337,31 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) return cmdr; } +static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(500); + + /* + * Databook says that before issuing a new data transfer command + * we need to check to see if the card is busy. Data transfer commands + * all have SDMMC_CMD_PRV_DAT_WAIT set, so we'll key off that. + * + * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is + * expected. + */ + if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) && + !(cmd_flags & SDMMC_CMD_VOLT_SWITCH)) { + while (mci_readl(host, STATUS) & SDMMC_STATUS_BUSY) { + if (time_after(jiffies, timeout)) { + /* Command will fail; we'll pass error then */ + dev_err(host->dev, "Busy; trying anyway\n"); + break; + } + udelay(10); + } + } +} + static void dw_mci_start_command(struct dw_mci *host, struct mmc_command *cmd, u32 cmd_flags) { @@ -324,6 +372,7 @@ static void dw_mci_start_command(struct dw_mci *host, mci_writel(host, CMDARG, cmd->arg); wmb(); + dw_mci_wait_while_busy(host, cmd_flags); mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); } @@ -414,30 +463,66 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, unsigned int sg_len) { int i; - struct idmac_desc *desc = host->sg_cpu; + if (host->dma_64bit_address == 1) { + struct idmac_desc_64addr *desc = host->sg_cpu; + + for (i = 0; i < sg_len; i++, desc++) { + unsigned int length = sg_dma_len(&data->sg[i]); + u64 mem_addr = sg_dma_address(&data->sg[i]); - for (i = 0; i < sg_len; i++, desc++) { - unsigned int length = sg_dma_len(&data->sg[i]); - u32 mem_addr = sg_dma_address(&data->sg[i]); + /* + * Set the OWN bit and disable interrupts for this + * descriptor + */ + desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | + IDMAC_DES0_CH; + /* Buffer length */ + IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length); + + /* Physical address to DMA to/from */ + desc->des4 = mem_addr & 0xffffffff; + desc->des5 = mem_addr >> 32; + } - /* Set the OWN bit and disable interrupts for this descriptor */ - desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH; + /* Set first descriptor */ + desc = host->sg_cpu; + desc->des0 |= IDMAC_DES0_FD; - /* Buffer length */ - IDMAC_SET_BUFFER1_SIZE(desc, length); + /* Set last descriptor */ + desc = host->sg_cpu + (i - 1) * + sizeof(struct idmac_desc_64addr); + desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); + desc->des0 |= IDMAC_DES0_LD; - /* Physical address to DMA to/from */ - desc->des2 = mem_addr; - } + } else { + struct idmac_desc *desc = host->sg_cpu; - /* Set first descriptor */ - desc = host->sg_cpu; - desc->des0 |= IDMAC_DES0_FD; + for (i = 0; i < sg_len; i++, desc++) { + unsigned int length = sg_dma_len(&data->sg[i]); + u32 mem_addr = sg_dma_address(&data->sg[i]); - /* Set last descriptor */ - desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); - desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); - desc->des0 |= IDMAC_DES0_LD; + /* + * Set the OWN bit and disable interrupts for this + * descriptor + */ + desc->des0 = cpu_to_le32(IDMAC_DES0_OWN | + IDMAC_DES0_DIC | IDMAC_DES0_CH); + /* Buffer length */ + IDMAC_SET_BUFFER1_SIZE(desc, length); + + /* Physical address to DMA to/from */ + desc->des2 = cpu_to_le32(mem_addr); + } + + /* Set first descriptor */ + desc = host->sg_cpu; + desc->des0 |= cpu_to_le32(IDMAC_DES0_FD); + + /* Set last descriptor */ + desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); + desc->des0 &= cpu_to_le32(~(IDMAC_DES0_CH | IDMAC_DES0_DIC)); + desc->des0 |= cpu_to_le32(IDMAC_DES0_LD); + } wmb(); } @@ -448,6 +533,10 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) dw_mci_translate_sglist(host, host->data, sg_len); + /* Make sure to reset DMA in case we did PIO before this */ + dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET); + dw_mci_idmac_reset(host); + /* Select IDMAC interface */ temp = mci_readl(host, CTRL); temp |= SDMMC_CTRL_USE_IDMAC; @@ -466,29 +555,71 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) static int dw_mci_idmac_init(struct dw_mci *host) { - struct idmac_desc *p; int i; - /* Number of descriptors in the ring buffer */ - host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); + if (host->dma_64bit_address == 1) { + struct idmac_desc_64addr *p; + /* Number of descriptors in the ring buffer */ + host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr); + + /* Forward link the descriptor list */ + for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; + i++, p++) { + p->des6 = (host->sg_dma + + (sizeof(struct idmac_desc_64addr) * + (i + 1))) & 0xffffffff; + + p->des7 = (u64)(host->sg_dma + + (sizeof(struct idmac_desc_64addr) * + (i + 1))) >> 32; + /* Initialize reserved and buffer size fields to "0" */ + p->des1 = 0; + p->des2 = 0; + p->des3 = 0; + } + + /* Set the last descriptor as the end-of-ring descriptor */ + p->des6 = host->sg_dma & 0xffffffff; + p->des7 = (u64)host->sg_dma >> 32; + p->des0 = IDMAC_DES0_ER; - /* Forward link the descriptor list */ - for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) - p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1)); + } else { + struct idmac_desc *p; + /* Number of descriptors in the ring buffer */ + host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); - /* Set the last descriptor as the end-of-ring descriptor */ - p->des3 = host->sg_dma; - p->des0 = IDMAC_DES0_ER; + /* Forward link the descriptor list */ + for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) + p->des3 = cpu_to_le32(host->sg_dma + + (sizeof(struct idmac_desc) * (i + 1))); + + /* Set the last descriptor as the end-of-ring descriptor */ + p->des3 = cpu_to_le32(host->sg_dma); + p->des0 = cpu_to_le32(IDMAC_DES0_ER); + } dw_mci_idmac_reset(host); - /* Mask out interrupts - get Tx & Rx complete only */ - mci_writel(host, IDSTS, IDMAC_INT_CLR); - mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | - SDMMC_IDMAC_INT_TI); + if (host->dma_64bit_address == 1) { + /* Mask out interrupts - get Tx & Rx complete only */ + mci_writel(host, IDSTS64, IDMAC_INT_CLR); + mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI | + SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); + + /* Set the descriptor base address */ + mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff); + mci_writel(host, DBADDRU, (u64)host->sg_dma >> 32); + + } else { + /* Mask out interrupts - get Tx & Rx complete only */ + mci_writel(host, IDSTS, IDMAC_INT_CLR); + mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | + SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); + + /* Set the descriptor base address */ + mci_writel(host, DBADDR, host->sg_dma); + } - /* Set the descriptor base address */ - mci_writel(host, DBADDR, host->sg_dma); return 0; } @@ -626,7 +757,15 @@ static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data) WARN_ON(!(data->flags & MMC_DATA_READ)); + /* + * CDTHRCTL doesn't exist prior to 240A (in fact that register offset is + * in the FIFO region, so we really shouldn't access it). + */ + if (host->verid < DW_MMC_240A) + return; + if (host->timing != MMC_TIMING_MMC_HS200 && + host->timing != MMC_TIMING_MMC_HS400 && host->timing != MMC_TIMING_UHS_SDR104) goto disable; @@ -651,6 +790,7 @@ disable: static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) { + unsigned long irqflags; int sg_len; u32 temp; @@ -687,9 +827,11 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) mci_writel(host, CTRL, temp); /* Disable RX/TX IRQs, let DMA handle it */ + spin_lock_irqsave(&host->irq_lock, irqflags); temp = mci_readl(host, INTMASK); temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); mci_writel(host, INTMASK, temp); + spin_unlock_irqrestore(&host->irq_lock, irqflags); host->dma_ops->start(host, sg_len); @@ -698,6 +840,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) { + unsigned long irqflags; u32 temp; data->error = -EINPROGRESS; @@ -726,9 +869,12 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) host->part_buf_count = 0; mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); + + spin_lock_irqsave(&host->irq_lock, irqflags); temp = mci_readl(host, INTMASK); temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; mci_writel(host, INTMASK, temp); + spin_unlock_irqrestore(&host->irq_lock, irqflags); temp = mci_readl(host, CTRL); temp &= ~SDMMC_CTRL_DMA_ENABLE; @@ -759,6 +905,7 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) mci_writel(host, CMDARG, arg); wmb(); + dw_mci_wait_while_busy(host, cmd); mci_writel(host, CMD, SDMMC_CMD_START | cmd); while (time_before(jiffies, timeout)) { @@ -819,7 +966,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) /* 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))) + if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; mci_writel(host, CLKENA, clk_en_a); @@ -875,6 +1022,26 @@ static void __dw_mci_start_request(struct dw_mci *host, dw_mci_start_command(host, cmd, cmdflags); + if (cmd->opcode == SD_SWITCH_VOLTAGE) { + unsigned long irqflags; + + /* + * Databook says to fail after 2ms w/ no response, but evidence + * shows that sometimes the cmd11 interrupt takes over 130ms. + * We'll set to 500ms, plus an extra jiffy just in case jiffies + * is just about to roll over. + * + * We do this whole thing under spinlock and only if the + * command hasn't already completed (indicating the the irq + * already ran so we don't want the timeout). + */ + spin_lock_irqsave(&host->irq_lock, irqflags); + if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) + mod_timer(&host->cmd11_timer, + jiffies + msecs_to_jiffies(500) + 1); + spin_unlock_irqrestore(&host->irq_lock, irqflags); + } + if (mrq->stop) host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); else @@ -967,7 +1134,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) regs = mci_readl(slot->host, UHS_REG); /* DDR mode set */ - if (ios->timing == MMC_TIMING_MMC_DDR52) + if (ios->timing == MMC_TIMING_MMC_DDR52 || + ios->timing == MMC_TIMING_MMC_HS400) regs |= ((0x1 << slot->id) << 16); else regs &= ~((0x1 << slot->id) << 16); @@ -984,12 +1152,6 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 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); - - if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) - slot->host->state = STATE_IDLE; - switch (ios->power_mode) { case MMC_POWER_UP: if (!IS_ERR(mmc->supply.vmmc)) { @@ -1002,27 +1164,45 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) return; } } - if (!IS_ERR(mmc->supply.vqmmc) && !slot->host->vqmmc_enabled) { - ret = regulator_enable(mmc->supply.vqmmc); - if (ret < 0) - dev_err(slot->host->dev, - "failed to enable vqmmc regulator\n"); - else - slot->host->vqmmc_enabled = true; - } set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); regs = mci_readl(slot->host, PWREN); regs |= (1 << slot->id); mci_writel(slot->host, PWREN, regs); break; + case MMC_POWER_ON: + if (!slot->host->vqmmc_enabled) { + if (!IS_ERR(mmc->supply.vqmmc)) { + ret = regulator_enable(mmc->supply.vqmmc); + if (ret < 0) + dev_err(slot->host->dev, + "failed to enable vqmmc\n"); + else + slot->host->vqmmc_enabled = true; + + } else { + /* Keep track so we don't reset again */ + slot->host->vqmmc_enabled = true; + } + + /* Reset our state machine after powering on */ + dw_mci_ctrl_reset(slot->host, + SDMMC_CTRL_ALL_RESET_FLAGS); + } + + /* Adjust clock / bus width after power is up */ + dw_mci_setup_bus(slot, false); + + break; case MMC_POWER_OFF: + /* Turn clock off before power goes down */ + dw_mci_setup_bus(slot, false); + if (!IS_ERR(mmc->supply.vmmc)) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); - if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) { + if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); - slot->host->vqmmc_enabled = false; - } + slot->host->vqmmc_enabled = false; regs = mci_readl(slot->host, PWREN); regs &= ~(1 << slot->id); @@ -1031,6 +1211,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) default: break; } + + if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) + slot->host->state = STATE_IDLE; } static int dw_mci_card_busy(struct mmc_host *mmc) @@ -1075,7 +1258,7 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); if (ret) { - dev_err(&mmc->class_dev, + dev_dbg(&mmc->class_dev, "Regulator set error %d: %d - %d\n", ret, min_uv, max_uv); return ret; @@ -1138,27 +1321,37 @@ 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) +static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) { + struct dw_mci_slot *slot = mmc_priv(mmc); 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); + /* + * 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. + */ + if (mmc->caps & MMC_CAP_SDIO_IRQ) { + const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; + u32 clk_en_a_old; + u32 clk_en_a; + + clk_en_a_old = 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); + if (card->type == MMC_TYPE_SDIO || + card->type == MMC_TYPE_SD_COMBO) { + set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); + clk_en_a = clk_en_a_old & ~clken_low_pwr; + } else { + clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); + clk_en_a = clk_en_a_old | clken_low_pwr; + } + + if (clk_en_a != clk_en_a_old) { + mci_writel(host, CLKENA, clk_en_a); + mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | + SDMMC_CMD_PRV_DAT_WAIT, 0); + } } } @@ -1166,25 +1359,20 @@ 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; + unsigned long irqflags; u32 int_mask; + spin_lock_irqsave(&host->irq_lock, irqflags); + /* 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); + if (enb) + int_mask |= SDMMC_INT_SDIO(slot->sdio_id); + else + int_mask &= ~SDMMC_INT_SDIO(slot->sdio_id); + mci_writel(host, INTMASK, int_mask); - mci_writel(host, INTMASK, - (int_mask | SDMMC_INT_SDIO(slot->id))); - } else { - mci_writel(host, INTMASK, - (int_mask & ~SDMMC_INT_SDIO(slot->id))); - } + spin_unlock_irqrestore(&host->irq_lock, irqflags); } static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) @@ -1192,33 +1380,25 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; const struct dw_mci_drv_data *drv_data = host->drv_data; - struct dw_mci_tuning_data tuning_data; int err = -ENOSYS; - if (opcode == MMC_SEND_TUNING_BLOCK_HS200) { - if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { - tuning_data.blk_pattern = tuning_blk_pattern_8bit; - tuning_data.blksz = sizeof(tuning_blk_pattern_8bit); - } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) { - tuning_data.blk_pattern = tuning_blk_pattern_4bit; - tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); - } else { - return -EINVAL; - } - } else if (opcode == MMC_SEND_TUNING_BLOCK) { - tuning_data.blk_pattern = tuning_blk_pattern_4bit; - tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); - } else { - dev_err(host->dev, - "Undefined command(%d) for tuning\n", opcode); - return -EINVAL; - } - if (drv_data && drv_data->execute_tuning) - err = drv_data->execute_tuning(slot, opcode, &tuning_data); + err = drv_data->execute_tuning(slot); return err; } +static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci *host = slot->host; + const struct dw_mci_drv_data *drv_data = host->drv_data; + + if (drv_data && drv_data->prepare_hs400_tuning) + return drv_data->prepare_hs400_tuning(host, ios); + + return 0; +} + static const struct mmc_host_ops dw_mci_ops = { .request = dw_mci_request, .pre_req = dw_mci_pre_req, @@ -1230,7 +1410,8 @@ static const struct mmc_host_ops dw_mci_ops = { .execute_tuning = dw_mci_execute_tuning, .card_busy = dw_mci_card_busy, .start_signal_voltage_switch = dw_mci_switch_voltage, - + .init_card = dw_mci_init_card, + .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning, }; static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) @@ -1416,7 +1597,10 @@ static void dw_mci_tasklet_func(unsigned long priv) if (test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)) { dw_mci_stop_dma(host); - send_stop_abort(host, data); + if (data->stop || + !(host->data_status & (SDMMC_INT_DRTO | + SDMMC_INT_EBE))) + send_stop_abort(host, data); state = STATE_DATA_ERROR; break; } @@ -1443,7 +1627,10 @@ static void dw_mci_tasklet_func(unsigned long priv) if (test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)) { dw_mci_stop_dma(host); - send_stop_abort(host, data); + if (data->stop || + !(host->data_status & (SDMMC_INT_DRTO | + SDMMC_INT_EBE))) + send_stop_abort(host, data); state = STATE_DATA_ERROR; break; } @@ -1581,8 +1768,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (host->part_buf_count == 2) { - mci_writew(host, DATA(host->data_offset), - host->part_buf16); + mci_fifo_writew(host->fifo_reg, host->part_buf16); host->part_buf_count = 0; } } @@ -1599,15 +1785,14 @@ 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_fifo_writew(host->fifo_reg, aligned_buf[i]); } } else #endif { u16 *pdata = buf; for (; cnt >= 2; cnt -= 2) - mci_writew(host, DATA(host->data_offset), *pdata++); + mci_fifo_writew(host->fifo_reg, *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ @@ -1616,8 +1801,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) /* Push data if we have reached the expected data length */ if ((data->bytes_xfered + init_cnt) == (data->blksz * data->blocks)) - mci_writew(host, DATA(host->data_offset), - host->part_buf16); + mci_fifo_writew(host->fifo_reg, host->part_buf16); } } @@ -1632,8 +1816,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_fifo_readw(host->fifo_reg); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1644,11 +1827,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_fifo_readw(host->fifo_reg); buf = pdata; } if (cnt) { - host->part_buf16 = mci_readw(host, DATA(host->data_offset)); + host->part_buf16 = mci_fifo_readw(host->fifo_reg); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1664,8 +1847,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (host->part_buf_count == 4) { - mci_writel(host, DATA(host->data_offset), - host->part_buf32); + mci_fifo_writel(host->fifo_reg, host->part_buf32); host->part_buf_count = 0; } } @@ -1682,15 +1864,14 @@ 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_fifo_writel(host->fifo_reg, aligned_buf[i]); } } else #endif { u32 *pdata = buf; for (; cnt >= 4; cnt -= 4) - mci_writel(host, DATA(host->data_offset), *pdata++); + mci_fifo_writel(host->fifo_reg, *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ @@ -1699,8 +1880,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) /* Push data if we have reached the expected data length */ if ((data->bytes_xfered + init_cnt) == (data->blksz * data->blocks)) - mci_writel(host, DATA(host->data_offset), - host->part_buf32); + mci_fifo_writel(host->fifo_reg, host->part_buf32); } } @@ -1715,8 +1895,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_fifo_readl(host->fifo_reg); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1727,11 +1906,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_fifo_readl(host->fifo_reg); buf = pdata; } if (cnt) { - host->part_buf32 = mci_readl(host, DATA(host->data_offset)); + host->part_buf32 = mci_fifo_readl(host->fifo_reg); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1748,8 +1927,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) cnt -= len; if (host->part_buf_count == 8) { - mci_writeq(host, DATA(host->data_offset), - host->part_buf); + mci_fifo_writeq(host->fifo_reg, host->part_buf); host->part_buf_count = 0; } } @@ -1766,15 +1944,14 @@ 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_fifo_writeq(host->fifo_reg, aligned_buf[i]); } } else #endif { u64 *pdata = buf; for (; cnt >= 8; cnt -= 8) - mci_writeq(host, DATA(host->data_offset), *pdata++); + mci_fifo_writeq(host->fifo_reg, *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ @@ -1783,8 +1960,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) /* Push data if we have reached the expected data length */ if ((data->bytes_xfered + init_cnt) == (data->blksz * data->blocks)) - mci_writeq(host, DATA(host->data_offset), - host->part_buf); + mci_fifo_writeq(host->fifo_reg, host->part_buf); } } @@ -1799,8 +1975,8 @@ 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_fifo_readq(host->fifo_reg); + /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1811,11 +1987,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_fifo_readq(host->fifo_reg); buf = pdata; } if (cnt) { - host->part_buf = mci_readq(host, DATA(host->data_offset)); + host->part_buf = mci_fifo_readq(host->fifo_reg); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1954,6 +2130,23 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) tasklet_schedule(&host->tasklet); } +static void dw_mci_handle_cd(struct dw_mci *host) +{ + int i; + + for (i = 0; i < host->num_slots; i++) { + struct dw_mci_slot *slot = host->slot[i]; + + if (!slot) + continue; + + if (slot->mmc->ops->card_event) + slot->mmc->ops->card_event(slot->mmc); + mmc_detect_change(slot->mmc, + msecs_to_jiffies(host->pdata->detect_delay_ms)); + } +} + static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) { struct dw_mci *host = dev_id; @@ -1976,9 +2169,20 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) /* Check volt switch first, since it can look like an error */ if ((host->state == STATE_SENDING_CMD11) && (pending & SDMMC_INT_VOLT_SWITCH)) { + unsigned long irqflags; + mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH); pending &= ~SDMMC_INT_VOLT_SWITCH; + + /* + * Hold the lock; we know cmd11_timer can't be kicked + * off after the lock is released, so safe to delete. + */ + spin_lock_irqsave(&host->irq_lock, irqflags); dw_mci_cmd_interrupt(host, pending); + spin_unlock_irqrestore(&host->irq_lock, irqflags); + + del_timer(&host->cmd11_timer); } if (pending & DW_MCI_CMD_ERROR_FLAGS) { @@ -2029,14 +2233,19 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & SDMMC_INT_CD) { mci_writel(host, RINTSTS, SDMMC_INT_CD); - queue_work(host->card_workqueue, &host->card_work); + dw_mci_handle_cd(host); } /* 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)); + + if (!slot) + continue; + + if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { + mci_writel(host, RINTSTS, + SDMMC_INT_SDIO(slot->sdio_id)); mmc_signal_sdio_irq(slot->mmc); } } @@ -2045,99 +2254,28 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) #ifdef CONFIG_MMC_DW_IDMAC /* Handle DMA interrupts */ - pending = mci_readl(host, IDSTS); - 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); - host->dma_ops->complete(host); + if (host->dma_64bit_address == 1) { + pending = mci_readl(host, IDSTS64); + if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { + mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI | + SDMMC_IDMAC_INT_RI); + mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI); + host->dma_ops->complete(host); + } + } else { + pending = mci_readl(host, IDSTS); + 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); + host->dma_ops->complete(host); + } } #endif return IRQ_HANDLED; } -static void dw_mci_work_routine_card(struct work_struct *work) -{ - struct dw_mci *host = container_of(work, struct dw_mci, card_work); - int i; - - for (i = 0; i < host->num_slots; i++) { - struct dw_mci_slot *slot = host->slot[i]; - struct mmc_host *mmc = slot->mmc; - struct mmc_request *mrq; - int present; - - present = dw_mci_get_cd(mmc); - while (present != slot->last_detect_state) { - dev_dbg(&slot->mmc->class_dev, "card %s\n", - present ? "inserted" : "removed"); - - spin_lock_bh(&host->lock); - - /* Card change detected */ - slot->last_detect_state = present; - - /* Clean up queue if present */ - mrq = slot->mrq; - if (mrq) { - if (mrq == host->mrq) { - host->data = NULL; - host->cmd = NULL; - - switch (host->state) { - case STATE_IDLE: - case STATE_WAITING_CMD11_DONE: - break; - case STATE_SENDING_CMD11: - case STATE_SENDING_CMD: - mrq->cmd->error = -ENOMEDIUM; - if (!mrq->data) - break; - /* fall through */ - case STATE_SENDING_DATA: - mrq->data->error = -ENOMEDIUM; - dw_mci_stop_dma(host); - break; - case STATE_DATA_BUSY: - case STATE_DATA_ERROR: - if (mrq->data->error == -EINPROGRESS) - mrq->data->error = -ENOMEDIUM; - /* fall through */ - case STATE_SENDING_STOP: - if (mrq->stop) - mrq->stop->error = -ENOMEDIUM; - break; - } - - dw_mci_request_end(host, mrq); - } else { - list_del(&slot->queue_node); - mrq->cmd->error = -ENOMEDIUM; - if (mrq->data) - mrq->data->error = -ENOMEDIUM; - if (mrq->stop) - mrq->stop->error = -ENOMEDIUM; - - spin_unlock(&host->lock); - mmc_request_done(slot->mmc, mrq); - spin_lock(&host->lock); - } - } - - /* Power down slot */ - if (present == 0) - dw_mci_reset(host); - - spin_unlock_bh(&host->lock); - - present = dw_mci_get_cd(mmc); - } - - mmc_detect_change(slot->mmc, - msecs_to_jiffies(host->pdata->detect_delay_ms)); - } -} - #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) @@ -2206,6 +2344,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) slot = mmc_priv(mmc); slot->id = id; + slot->sdio_id = host->sdio_id0 + id; slot->mmc = mmc; slot->host = host; host->slot[id] = slot; @@ -2264,9 +2403,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) #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; + mmc->max_req_size = mmc->max_seg_size * host->ring_size; + mmc->max_blk_count = mmc->max_req_size / 512; #else mmc->max_segs = 64; mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ @@ -2289,9 +2428,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) dw_mci_init_debugfs(slot); #endif - /* Card initially undetected */ - slot->last_detect_state = 0; - return 0; err_host_allocated: @@ -2309,6 +2445,22 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) static void dw_mci_init_dma(struct dw_mci *host) { + int addr_config; + /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */ + addr_config = (mci_readl(host, HCON) >> 27) & 0x01; + + if (addr_config == 1) { + /* host supports IDMAC in 64-bit address mode */ + host->dma_64bit_address = 1; + dev_info(host->dev, "IDMAC supports 64-bit address mode.\n"); + if (!dma_set_mask(host->dev, DMA_BIT_MASK(64))) + dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64)); + } else { + /* host supports IDMAC in 32-bit address mode */ + host->dma_64bit_address = 0; + dev_info(host->dev, "IDMAC supports 32-bit address mode.\n"); + } + /* Alloc memory for sg translation */ host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); @@ -2441,6 +2593,20 @@ ciu_out: return ret; } +static void dw_mci_cmd11_timer(unsigned long arg) +{ + struct dw_mci *host = (struct dw_mci *)arg; + + if (host->state != STATE_SENDING_CMD11) { + dev_warn(host->dev, "Unexpected CMD11 timeout\n"); + return; + } + + host->cmd_status = SDMMC_INT_RTO; + set_bit(EVENT_CMD_COMPLETE, &host->pending_events); + tasklet_schedule(&host->tasklet); +} + #ifdef CONFIG_OF static struct dw_mci_of_quirks { char *quirk; @@ -2465,10 +2631,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) u32 clock_frequency; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(dev, "could not allocate memory for pdata\n"); + if (!pdata) return ERR_PTR(-ENOMEM); - } /* find out number of slots supported */ if (of_property_read_u32(dev->of_node, "num-slots", @@ -2511,6 +2675,34 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) } #endif /* CONFIG_OF */ +static void dw_mci_enable_cd(struct dw_mci *host) +{ + struct dw_mci_board *brd = host->pdata; + unsigned long irqflags; + u32 temp; + int i; + + /* No need for CD if broken card detection */ + if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) + return; + + /* No need for CD if all slots have a non-error GPIO */ + for (i = 0; i < host->num_slots; i++) { + struct dw_mci_slot *slot = host->slot[i]; + + if (IS_ERR_VALUE(mmc_gpio_get_cd(slot->mmc))) + break; + } + if (i == host->num_slots) + return; + + spin_lock_irqsave(&host->irq_lock, irqflags); + temp = mci_readl(host, INTMASK); + temp |= SDMMC_INT_CD; + mci_writel(host, INTMASK, temp); + spin_unlock_irqrestore(&host->irq_lock, irqflags); +} + int dw_mci_probe(struct dw_mci *host) { const struct dw_mci_drv_data *drv_data = host->drv_data; @@ -2589,9 +2781,13 @@ int dw_mci_probe(struct dw_mci *host) } } + setup_timer(&host->cmd11_timer, + dw_mci_cmd11_timer, (unsigned long)host); + host->quirks = host->pdata->quirks; spin_lock_init(&host->lock); + spin_lock_init(&host->irq_lock); INIT_LIST_HEAD(&host->queue); /* @@ -2667,22 +2863,15 @@ int dw_mci_probe(struct dw_mci *host) dev_info(host->dev, "Version ID is %04x\n", host->verid); if (host->verid < DW_MMC_240A) - host->data_offset = DATA_OFFSET; + host->fifo_reg = host->regs + DATA_OFFSET; else - host->data_offset = DATA_240A_OFFSET; + host->fifo_reg = host->regs + DATA_240A_OFFSET; tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); - host->card_workqueue = alloc_workqueue("dw-mci-card", - WQ_MEM_RECLAIM, 1); - if (!host->card_workqueue) { - ret = -ENOMEM; - 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); if (ret) - goto err_workqueue; + goto err_dmaunmap; if (host->pdata->num_slots) host->num_slots = host->pdata->num_slots; @@ -2690,13 +2879,13 @@ int dw_mci_probe(struct dw_mci *host) host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; /* - * Enable interrupts for command done, data over, data empty, card det, + * Enable interrupts for command done, data over, data empty, * receive ready and error such as transmit, receive timeout, crc error */ mci_writel(host, RINTSTS, 0xFFFFFFFF); mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | SDMMC_INT_TXDR | SDMMC_INT_RXDR | - DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); + DW_MCI_ERROR_FLAGS); mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ dev_info(host->dev, "DW MMC controller at irq %d, " @@ -2718,17 +2907,17 @@ int dw_mci_probe(struct dw_mci *host) } else { dev_dbg(host->dev, "attempted to initialize %d slots, " "but failed on all\n", host->num_slots); - goto err_workqueue; + goto err_dmaunmap; } + /* Now that slots are all setup, we can enable card detect */ + dw_mci_enable_cd(host); + if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); return 0; -err_workqueue: - destroy_workqueue(host->card_workqueue); - err_dmaunmap: if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); @@ -2762,8 +2951,6 @@ void dw_mci_remove(struct dw_mci *host) mci_writel(host, CLKENA, 0); mci_writel(host, CLKSRC, 0); - destroy_workqueue(host->card_workqueue); - if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); @@ -2812,7 +2999,7 @@ int dw_mci_resume(struct dw_mci *host) mci_writel(host, RINTSTS, 0xFFFFFFFF); mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | SDMMC_INT_TXDR | SDMMC_INT_RXDR | - DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); + DW_MCI_ERROR_FLAGS); mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); for (i = 0; i < host->num_slots; i++) { @@ -2824,6 +3011,10 @@ int dw_mci_resume(struct dw_mci *host) dw_mci_setup_bus(slot, true); } } + + /* Now that slots are all setup, we can enable card detect */ + dw_mci_enable_cd(host); + return 0; } EXPORT_SYMBOL(dw_mci_resume); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 01b99e8a9190..f45ab91de339 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -55,6 +55,17 @@ #define SDMMC_BUFADDR 0x098 #define SDMMC_CDTHRCTL 0x100 #define SDMMC_DATA(x) (x) +/* +* Registers to support idmac 64-bit address mode +*/ +#define SDMMC_DBADDRL 0x088 +#define SDMMC_DBADDRU 0x08c +#define SDMMC_IDSTS64 0x090 +#define SDMMC_IDINTEN64 0x094 +#define SDMMC_DSCADDRL 0x098 +#define SDMMC_DSCADDRU 0x09c +#define SDMMC_BUFADDRL 0x0A0 +#define SDMMC_BUFADDRU 0x0A4 /* * Data offset is difference according to Version @@ -158,24 +169,34 @@ #define SDMMC_CTRL_ALL_RESET_FLAGS \ (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) +/* FIFO register access macros. These should not change the data endian-ness + * as they are written to memory to be dealt with by the upper layers */ +#define mci_fifo_readw(__reg) __raw_readw(__reg) +#define mci_fifo_readl(__reg) __raw_readl(__reg) +#define mci_fifo_readq(__reg) __raw_readq(__reg) + +#define mci_fifo_writew(__value, __reg) __raw_writew(__reg, __value) +#define mci_fifo_writel(__value, __reg) __raw_writel(__reg, __value) +#define mci_fifo_writeq(__value, __reg) __raw_writeq(__reg, __value) + /* Register access macros */ #define mci_readl(dev, reg) \ - __raw_readl((dev)->regs + SDMMC_##reg) + readl_relaxed((dev)->regs + SDMMC_##reg) #define mci_writel(dev, reg, value) \ - __raw_writel((value), (dev)->regs + SDMMC_##reg) + writel_relaxed((value), (dev)->regs + SDMMC_##reg) /* 16-bit FIFO access macros */ #define mci_readw(dev, reg) \ - __raw_readw((dev)->regs + SDMMC_##reg) + readw_relaxed((dev)->regs + SDMMC_##reg) #define mci_writew(dev, reg, value) \ - __raw_writew((value), (dev)->regs + SDMMC_##reg) + writew_relaxed((value), (dev)->regs + SDMMC_##reg) /* 64-bit FIFO access macros */ #ifdef readq #define mci_readq(dev, reg) \ - __raw_readq((dev)->regs + SDMMC_##reg) + readq_relaxed((dev)->regs + SDMMC_##reg) #define mci_writeq(dev, reg, value) \ - __raw_writeq((value), (dev)->regs + SDMMC_##reg) + writeq_relaxed((value), (dev)->regs + SDMMC_##reg) #else /* * Dummy readq implementation for architectures that don't define it. @@ -189,6 +210,10 @@ (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg)) #define mci_writeq(dev, reg, value) \ (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value)) + +#define __raw_writeq(__value, __reg) \ + (*(volatile u64 __force *)(__reg) = (__value)) +#define __raw_readq(__reg) (*(volatile u64 __force *)(__reg)) #endif extern int dw_mci_probe(struct dw_mci *host); @@ -214,7 +239,7 @@ extern int dw_mci_resume(struct dw_mci *host); * with CONFIG_MMC_CLKGATE. * @flags: Random state bits associated with the slot. * @id: Number of this slot. - * @last_detect_state: Most recently observed card detect state. + * @sdio_id: Number of this slot in the SDIO interrupt registers. */ struct dw_mci_slot { struct mmc_host *mmc; @@ -233,13 +258,9 @@ struct dw_mci_slot { unsigned long flags; #define DW_MMC_CARD_PRESENT 0 #define DW_MMC_CARD_NEED_INIT 1 +#define DW_MMC_CARD_NO_LOW_PWR 2 int id; - int last_detect_state; -}; - -struct dw_mci_tuning_data { - const u8 *blk_pattern; - unsigned int blksz; + int sdio_id; }; /** @@ -263,7 +284,8 @@ struct dw_mci_drv_data { 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 (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode, - struct dw_mci_tuning_data *tuning_data); + int (*execute_tuning)(struct dw_mci_slot *slot); + int (*prepare_hs400_tuning)(struct dw_mci *host, + struct mmc_ios *ios); }; #endif /* _DW_MMC_H_ */ diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index e4a07546f8b6..ae19d83bb9de 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1507,7 +1507,7 @@ static int mmc_spi_remove(struct spi_device *spi) return 0; } -static struct of_device_id mmc_spi_of_match_table[] = { +static const struct of_device_id mmc_spi_of_match_table[] = { { .compatible = "mmc-spi-slot", }, {}, }; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 43af791e2e45..fb266745f824 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -430,7 +430,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) static void mmci_dma_setup(struct mmci_host *host) { const char *rxname, *txname; - dma_cap_mask_t mask; struct variant_data *variant = host->variant; host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); @@ -439,10 +438,6 @@ static void mmci_dma_setup(struct mmci_host *host) /* initialize pre request cookie */ host->next_data.cookie = 1; - /* Try to acquire a generic DMA engine slave channel */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - /* * If only an RX channel is specified, the driver will * attempt to use it bidirectionally, however if it is @@ -736,8 +731,15 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, chan = host->dma_tx_channel; dmaengine_terminate_all(chan); + if (host->dma_desc_current == next->dma_desc) + host->dma_desc_current = NULL; + + if (host->dma_current == next->dma_chan) + host->dma_current = NULL; + next->dma_desc = NULL; next->dma_chan = NULL; + data->host_cookie = 0; } } @@ -1611,7 +1613,10 @@ static int mmci_probe(struct amba_device *dev, dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); /* Get regulators and the supported OCR mask */ - mmc_regulator_get_supply(mmc); + ret = mmc_regulator_get_supply(mmc); + if (ret == -EPROBE_DEFER) + goto clk_disable; + if (!mmc->ocr_avail) mmc->ocr_avail = plat->ocr_mask; else if (plat->ocr_mask) @@ -1732,10 +1737,10 @@ static int mmci_probe(struct amba_device *dev, pm_runtime_set_autosuspend_delay(&dev->dev, 50); pm_runtime_use_autosuspend(&dev->dev); - pm_runtime_put(&dev->dev); mmc_add_host(mmc); + pm_runtime_put(&dev->dev); return 0; clk_disable: @@ -1843,7 +1848,7 @@ static int mmci_runtime_resume(struct device *dev) static const struct dev_pm_ops mmci_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) - SET_PM_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL) + SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL) }; static struct amba_id mmci_ids[] = { diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index f3e18d08e852..006f1862444b 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/delay.h> +#include <linux/errno.h> #include <linux/interrupt.h> #include <linux/blkdev.h> #include <linux/dma-mapping.h> @@ -562,7 +563,6 @@ static int moxart_probe(struct platform_device *pdev) struct dma_slave_config cfg; struct clk *clk; void __iomem *reg_mmc; - dma_cap_mask_t mask; int irq, ret; u32 i; @@ -586,9 +586,8 @@ static int moxart_probe(struct platform_device *pdev) goto out; } - clk = of_clk_get(node, 0); + clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) { - dev_err(dev, "of_clk_get failed\n"); ret = PTR_ERR(clk); goto out; } @@ -599,10 +598,9 @@ static int moxart_probe(struct platform_device *pdev) goto out; } - mmc_of_parse(mmc); - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + ret = mmc_of_parse(mmc); + if (ret) + goto out; host = mmc_priv(mmc); host->mmc = mmc; @@ -611,8 +609,8 @@ static int moxart_probe(struct platform_device *pdev) host->timeout = msecs_to_jiffies(1000); host->sysclk = clk_get_rate(clk); host->fifo_width = readl(host->base + REG_FEATURE) << 2; - host->dma_chan_tx = of_dma_request_slave_channel(node, "tx"); - host->dma_chan_rx = of_dma_request_slave_channel(node, "rx"); + host->dma_chan_tx = dma_request_slave_channel_reason(dev, "tx"); + host->dma_chan_rx = dma_request_slave_channel_reason(dev, "rx"); spin_lock_init(&host->lock); @@ -622,6 +620,11 @@ static int moxart_probe(struct platform_device *pdev) mmc->ocr_avail = 0xffff00; /* Support 2.0v - 3.6v power. */ if (IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) { + if (PTR_ERR(host->dma_chan_tx) == -EPROBE_DEFER || + PTR_ERR(host->dma_chan_rx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto out; + } dev_dbg(dev, "PIO mode transfer enabled\n"); host->have_dma = false; } else { @@ -700,9 +703,6 @@ static int moxart_remove(struct platform_device *pdev) writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF, host->base + REG_CLOCK_CONTROL); } - - kfree(host); - return 0; } diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 9405ecdaf6cf..90c60fd4ff6e 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1360,7 +1360,7 @@ msmsdcc_probe(struct platform_device *pdev) if (ret) goto cmd_irq_free; - mmc_set_drvdata(pdev, mmc); + platform_set_drvdata(pdev, mmc); mmc_add_host(mmc); pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n", @@ -1419,7 +1419,7 @@ ioremap_free: static int msmsdcc_suspend(struct platform_device *dev, pm_message_t state) { - struct mmc_host *mmc = mmc_get_drvdata(dev); + struct mmc_host *mmc = platform_get_drvdata(dev); if (mmc) { struct msmsdcc_host *host = mmc_priv(mmc); @@ -1437,7 +1437,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) static int msmsdcc_resume(struct platform_device *dev) { - struct mmc_host *mmc = mmc_get_drvdata(dev); + struct mmc_host *mmc = platform_get_drvdata(dev); if (mmc) { struct msmsdcc_host *host = mmc_priv(mmc); diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 6b4c5ad3b393..a448498e3af2 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -25,7 +25,6 @@ #include <linux/of_irq.h> #include <linux/mmc/host.h> #include <linux/mmc/slot-gpio.h> -#include <linux/pinctrl/consumer.h> #include <asm/sizes.h> #include <asm/unaligned.h> @@ -111,10 +110,15 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) mvsd_write(MVSD_BLK_COUNT, data->blocks); mvsd_write(MVSD_BLK_SIZE, data->blksz); - if (nodma || (data->blksz | data->sg->offset) & 3) { + if (nodma || (data->blksz | data->sg->offset) & 3 || + ((!(data->flags & MMC_DATA_READ) && data->sg->offset & 0x3f))) { /* * We cannot do DMA on a buffer which offset or size * is not aligned on a 4-byte boundary. + * + * It also appears the host to card DMA can corrupt + * data when the buffer is not aligned on a 64 byte + * boundary. */ host->pio_size = data->blocks * data->blksz; host->pio_ptr = sg_virt(data->sg); @@ -699,7 +703,6 @@ static int mvsd_probe(struct platform_device *pdev) const struct mbus_dram_target_info *dram; struct resource *r; int ret, irq; - struct pinctrl *pinctrl; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); @@ -716,10 +719,6 @@ static int mvsd_probe(struct platform_device *pdev) host->mmc = mmc; host->dev = &pdev->dev; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - dev_warn(&pdev->dev, "no pins associated\n"); - /* * Some non-DT platforms do not pass a clock, and the clock * frequency is passed through platform_data. On DT platforms, @@ -823,8 +822,6 @@ static int mvsd_probe(struct platform_device *pdev) out: if (mmc) { - mmc_gpio_free_cd(mmc); - mmc_gpio_free_ro(mmc); if (!IS_ERR(host->clk)) clk_disable_unprepare(host->clk); mmc_free_host(mmc); @@ -839,8 +836,6 @@ static int mvsd_remove(struct platform_device *pdev) struct mvsd_host *host = mmc_priv(mmc); - mmc_gpio_free_cd(mmc); - mmc_gpio_free_ro(mmc); mmc_remove_host(mmc); del_timer_sync(&host->timer); mvsd_power_down(host); diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index ad111422ad55..5316d9b9e7b4 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -373,13 +373,9 @@ static void mxcmci_dma_callback(void *data) del_timer(&host->watchdog); stat = mxcmci_readl(host, MMC_REG_STATUS); - mxcmci_writel(host, stat & ~STATUS_DATA_TRANS_DONE, MMC_REG_STATUS); dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); - if (stat & STATUS_READ_OP_DONE) - mxcmci_writel(host, STATUS_READ_OP_DONE, MMC_REG_STATUS); - mxcmci_data_done(host, stat); } @@ -743,10 +739,8 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio; spin_unlock_irqrestore(&host->lock, flags); - if (mxcmci_use_dma(host) && - (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE))) - mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, - MMC_REG_STATUS); + if (mxcmci_use_dma(host) && (stat & (STATUS_WRITE_OP_DONE))) + mxcmci_writel(host, STATUS_WRITE_OP_DONE, MMC_REG_STATUS); if (sdio_irq) { mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS); @@ -756,8 +750,7 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) if (stat & STATUS_END_CMD_RESP) mxcmci_cmd_done(host, stat); - if (mxcmci_use_dma(host) && - (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) { + if (mxcmci_use_dma(host) && (stat & STATUS_WRITE_OP_DONE)) { del_timer(&host->watchdog); mxcmci_data_done(host, stat); } @@ -1084,12 +1077,14 @@ static int mxcmci_probe(struct platform_device *pdev) dat3_card_detect = true; ret = mmc_regulator_get_supply(mmc); - if (ret) { - if (pdata && ret != -EPROBE_DEFER) - mmc->ocr_avail = pdata->ocr_avail ? : - MMC_VDD_32_33 | MMC_VDD_33_34; + if (ret == -EPROBE_DEFER) + goto out_free; + + if (!mmc->ocr_avail) { + if (pdata && pdata->ocr_avail) + mmc->ocr_avail = pdata->ocr_avail; else - goto out_free; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; } if (dat3_card_detect) diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index cd74e5143c36..a82411a2c024 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -581,10 +581,9 @@ static int mxs_mmc_probe(struct platform_device *pdev) struct regulator *reg_vmmc; struct mxs_ssp *ssp; - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq_err = platform_get_irq(pdev, 0); - if (!iores || irq_err < 0) - return -EINVAL; + if (irq_err < 0) + return irq_err; mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); if (!mmc) @@ -593,6 +592,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) host = mmc_priv(mmc); ssp = &host->ssp; ssp->dev = &pdev->dev; + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); ssp->base = devm_ioremap_resource(&pdev->dev, iores); if (IS_ERR(ssp->base)) { ret = PTR_ERR(ssp->base); @@ -619,7 +619,9 @@ static int mxs_mmc_probe(struct platform_device *pdev) ret = PTR_ERR(ssp->clk); goto out_mmc_free; } - clk_prepare_enable(ssp->clk); + ret = clk_prepare_enable(ssp->clk); + if (ret) + goto out_mmc_free; ret = mxs_mmc_reset(host); if (ret) { @@ -660,7 +662,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mmc); ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0, - DRIVER_NAME, host); + dev_name(&pdev->dev), host); if (ret) goto out_free_dma; @@ -675,8 +677,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) return 0; out_free_dma: - if (ssp->dmach) - dma_release_channel(ssp->dmach); + dma_release_channel(ssp->dmach); out_clk_disable: clk_disable_unprepare(ssp->clk); out_mmc_free: @@ -702,7 +703,7 @@ static int mxs_mmc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int mxs_mmc_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); @@ -719,25 +720,19 @@ static int mxs_mmc_resume(struct device *dev) struct mxs_mmc_host *host = mmc_priv(mmc); struct mxs_ssp *ssp = &host->ssp; - clk_prepare_enable(ssp->clk); - return 0; + return clk_prepare_enable(ssp->clk); } - -static const struct dev_pm_ops mxs_mmc_pm_ops = { - .suspend = mxs_mmc_suspend, - .resume = mxs_mmc_resume, -}; #endif +static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume); + static struct platform_driver mxs_mmc_driver = { .probe = mxs_mmc_probe, .remove = mxs_mmc_remove, .id_table = mxs_ssp_ids, .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM .pm = &mxs_mmc_pm_ops, -#endif .of_match_table = mxs_mmc_dt_ids, }, }; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index df27bb4fc098..9df2b6801f76 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -36,13 +36,14 @@ #include <linux/mmc/host.h> #include <linux/mmc/core.h> #include <linux/mmc/mmc.h> +#include <linux/mmc/slot-gpio.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> -#include <linux/platform_data/mmc-omap.h> +#include <linux/platform_data/hsmmc-omap.h> /* OMAP HSMMC Host Controller Registers */ #define OMAP_HSMMC_SYSSTATUS 0x0014 @@ -155,7 +156,7 @@ * omap.c controller driver. Luckily this is not currently done on any known * omap_hsmmc.c device. */ -#define mmc_slot(host) (host->pdata->slots[host->slot_id]) +#define mmc_pdata(host) host->pdata /* * MMC Host controller read/write API's @@ -207,7 +208,6 @@ struct omap_hsmmc_host { int use_dma, dma_ch; struct dma_chan *tx_chan; struct dma_chan *rx_chan; - int slot_id; int response_busy; int context_loss; int protect_card; @@ -220,7 +220,17 @@ struct omap_hsmmc_host { #define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */ #define HSMMC_WAKE_IRQ_ENABLED (1 << 2) struct omap_hsmmc_next next_data; - struct omap_mmc_platform_data *pdata; + struct omap_hsmmc_platform_data *pdata; + + /* return MMC cover switch state, can be NULL if not supported. + * + * possible return values: + * 0 - closed + * 1 - open + */ + int (*get_cover_state)(struct device *dev); + + int (*card_detect)(struct device *dev); }; struct omap_mmc_of_data { @@ -230,64 +240,23 @@ struct omap_mmc_of_data { static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host); -static int omap_hsmmc_card_detect(struct device *dev, int slot) +static int omap_hsmmc_card_detect(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; - /* NOTE: assumes card detect signal is active-low */ - return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); + return mmc_gpio_get_cd(host->mmc); } -static int omap_hsmmc_get_wp(struct device *dev, int slot) +static int omap_hsmmc_get_cover_state(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; - /* NOTE: assumes write protect signal is active-high */ - return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); + return mmc_gpio_get_cd(host->mmc); } -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; - - /* NOTE: assumes card detect signal is active-low */ - return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); -} - -#ifdef CONFIG_PM - -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; - - disable_irq(mmc->slots[0].card_detect_irq); - return 0; -} - -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; - - enable_irq(mmc->slots[0].card_detect_irq); - return 0; -} - -#else - -#define omap_hsmmc_suspend_cdirq NULL -#define omap_hsmmc_resume_cdirq NULL - -#endif - #ifdef CONFIG_REGULATOR -static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, - int vdd) +static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) { struct omap_hsmmc_host *host = platform_get_drvdata(to_platform_device(dev)); @@ -300,8 +269,8 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, if (!host->vcc) return 0; - if (mmc_slot(host).before_set_reg) - mmc_slot(host).before_set_reg(dev, slot, power_on, vdd); + if (mmc_pdata(host)->before_set_reg) + mmc_pdata(host)->before_set_reg(dev, power_on, vdd); if (host->pbias) { if (host->pbias_enabled == 1) { @@ -363,8 +332,8 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, } } - if (mmc_slot(host).after_set_reg) - mmc_slot(host).after_set_reg(dev, slot, power_on, vdd); + if (mmc_pdata(host)->after_set_reg) + mmc_pdata(host)->after_set_reg(dev, power_on, vdd); error_set_power: return ret; @@ -383,18 +352,18 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) } else { host->vcc = reg; ocr_value = mmc_regulator_get_ocrmask(reg); - if (!mmc_slot(host).ocr_mask) { - mmc_slot(host).ocr_mask = ocr_value; + if (!mmc_pdata(host)->ocr_mask) { + mmc_pdata(host)->ocr_mask = ocr_value; } else { - if (!(mmc_slot(host).ocr_mask & ocr_value)) { + if (!(mmc_pdata(host)->ocr_mask & ocr_value)) { dev_err(host->dev, "ocrmask %x is not supported\n", - mmc_slot(host).ocr_mask); - mmc_slot(host).ocr_mask = 0; + mmc_pdata(host)->ocr_mask); + mmc_pdata(host)->ocr_mask = 0; return -EINVAL; } } } - mmc_slot(host).set_power = omap_hsmmc_set_power; + mmc_pdata(host)->set_power = omap_hsmmc_set_power; /* Allow an aux regulator */ reg = devm_regulator_get_optional(host->dev, "vmmc_aux"); @@ -404,7 +373,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) host->pbias = IS_ERR(reg) ? NULL : reg; /* For eMMC do not power off when not in sleep state */ - if (mmc_slot(host).no_regulator_off_init) + if (mmc_pdata(host)->no_regulator_off_init) return 0; /* * To disable boot_on regulator, enable regulator @@ -412,10 +381,10 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) */ if ((host->vcc && regulator_is_enabled(host->vcc) > 0) || (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { - int vdd = ffs(mmc_slot(host).ocr_mask) - 1; + int vdd = ffs(mmc_pdata(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); + mmc_pdata(host)->set_power(host->dev, 1, vdd); + mmc_pdata(host)->set_power(host->dev, 0, 0); } return 0; @@ -423,7 +392,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) { - mmc_slot(host).set_power = NULL; + mmc_pdata(host)->set_power = NULL; } static inline int omap_hsmmc_have_reg(void) @@ -449,55 +418,36 @@ static inline int omap_hsmmc_have_reg(void) #endif -static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata) +static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id); + +static int omap_hsmmc_gpio_init(struct mmc_host *mmc, + struct omap_hsmmc_host *host, + struct omap_hsmmc_platform_data *pdata) { int ret; - if (gpio_is_valid(pdata->slots[0].switch_pin)) { - if (pdata->slots[0].cover) - pdata->slots[0].get_cover_state = - omap_hsmmc_get_cover_state; - else - pdata->slots[0].card_detect = omap_hsmmc_card_detect; - pdata->slots[0].card_detect_irq = - gpio_to_irq(pdata->slots[0].switch_pin); - ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd"); + if (gpio_is_valid(pdata->gpio_cod)) { + ret = mmc_gpio_request_cd(mmc, pdata->gpio_cod, 0); if (ret) return ret; - ret = gpio_direction_input(pdata->slots[0].switch_pin); - if (ret) - goto err_free_sp; - } else - pdata->slots[0].switch_pin = -EINVAL; - if (gpio_is_valid(pdata->slots[0].gpio_wp)) { - pdata->slots[0].get_ro = omap_hsmmc_get_wp; - ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp"); - if (ret) - goto err_free_cd; - ret = gpio_direction_input(pdata->slots[0].gpio_wp); + host->get_cover_state = omap_hsmmc_get_cover_state; + mmc_gpio_set_cd_isr(mmc, omap_hsmmc_cover_irq); + } else if (gpio_is_valid(pdata->gpio_cd)) { + ret = mmc_gpio_request_cd(mmc, pdata->gpio_cd, 0); if (ret) - goto err_free_wp; - } else - pdata->slots[0].gpio_wp = -EINVAL; + return ret; - return 0; + host->card_detect = omap_hsmmc_card_detect; + } -err_free_wp: - gpio_free(pdata->slots[0].gpio_wp); -err_free_cd: - if (gpio_is_valid(pdata->slots[0].switch_pin)) -err_free_sp: - gpio_free(pdata->slots[0].switch_pin); - return ret; -} + if (gpio_is_valid(pdata->gpio_wp)) { + ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp); + if (ret) + return ret; + } -static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata) -{ - if (gpio_is_valid(pdata->slots[0].gpio_wp)) - gpio_free(pdata->slots[0].gpio_wp); - if (gpio_is_valid(pdata->slots[0].switch_pin)) - gpio_free(pdata->slots[0].switch_pin); + return 0; } /* @@ -607,8 +557,9 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) * in capabilities register * - MMC/SD clock coming out of controller > 25MHz */ - if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) && + if ((mmc_pdata(host)->features & HSMMC_HAS_HSPE_SUPPORT) && (ios->timing != MMC_TIMING_MMC_DDR52) && + (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) @@ -628,7 +579,8 @@ 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_MMC_DDR52) + if (ios->timing == MMC_TIMING_MMC_DDR52 || + ios->timing == MMC_TIMING_UHS_DDR50) con |= DDR; /* configure in DDR mode */ else con &= ~DDR; @@ -791,8 +743,8 @@ int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host) { int r = 1; - if (mmc_slot(host).get_cover_state) - r = mmc_slot(host).get_cover_state(host->dev, host->slot_id); + if (host->get_cover_state) + r = host->get_cover_state(host->dev); return r; } @@ -816,7 +768,7 @@ omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr, struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); struct omap_hsmmc_host *host = mmc_priv(mmc); - return sprintf(buf, "%s\n", mmc_slot(host).name); + return sprintf(buf, "%s\n", mmc_pdata(host)->name); } static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL); @@ -910,6 +862,8 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req return; host->mrq = NULL; mmc_request_done(host->mmc, mrq); + pm_runtime_mark_last_busy(host->dev); + pm_runtime_put_autosuspend(host->dev); } /* @@ -1061,7 +1015,7 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, * OMAP4 ES2 and greater has an updated reset logic. * Monitor a 0->1 transition first */ - if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) { + if (mmc_pdata(host)->features & HSMMC_HAS_UPDATED_RESET) { while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit)) && (i++ < limit)) udelay(1); @@ -1210,12 +1164,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) clk_disable_unprepare(host->dbclk); /* Turn the power off */ - ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); + ret = mmc_pdata(host)->set_power(host->dev, 0, 0); /* Turn the power ON with given VDD 1.8 or 3.0v */ if (!ret) - ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, - vdd); + ret = mmc_pdata(host)->set_power(host->dev, 1, vdd); pm_runtime_get_sync(host->dev); if (host->dbclk) clk_prepare_enable(host->dbclk); @@ -1259,11 +1212,11 @@ err: /* Protect the card while the cover is open */ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) { - if (!mmc_slot(host).get_cover_state) + if (!host->get_cover_state) return; host->reqs_blocked = 0; - if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) { + if (host->get_cover_state(host->dev)) { if (host->protect_card) { dev_info(host->dev, "%s: cover is closed, " "card is now accessible\n", @@ -1281,27 +1234,16 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) } /* - * irq handler to notify the core about card insertion/removal + * irq handler when (cell-phone) cover is mounted/removed */ -static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) +static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id) { struct omap_hsmmc_host *host = dev_id; - struct omap_mmc_slot_data *slot = &mmc_slot(host); - int carddetect; sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); - if (slot->card_detect) - carddetect = slot->card_detect(host->dev, host->slot_id); - else { - omap_hsmmc_protect_card(host); - carddetect = -ENOSYS; - } - - if (carddetect) - mmc_detect_change(host->mmc, (HZ * 200) / 1000); - else - mmc_detect_change(host->mmc, (HZ * 50) / 1000); + omap_hsmmc_protect_card(host); + mmc_detect_change(host->mmc, (HZ * 200) / 1000); return IRQ_HANDLED; } @@ -1335,6 +1277,8 @@ static void omap_hsmmc_dma_callback(void *param) host->mrq = NULL; mmc_request_done(host->mmc, mrq); + pm_runtime_mark_last_busy(host->dev); + pm_runtime_put_autosuspend(host->dev); } } @@ -1567,6 +1511,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) BUG_ON(host->req_in_progress); BUG_ON(host->dma_ch != -1); + pm_runtime_get_sync(host->dev); if (host->protect_card) { if (host->reqs_blocked < 3) { /* @@ -1583,6 +1528,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) req->data->error = -EBADF; req->cmd->retries = 0; mmc_request_done(mmc, req); + pm_runtime_mark_last_busy(host->dev); + pm_runtime_put_autosuspend(host->dev); return; } else if (host->reqs_blocked) host->reqs_blocked = 0; @@ -1596,6 +1543,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) req->data->error = err; host->mrq = NULL; mmc_request_done(mmc, req); + pm_runtime_mark_last_busy(host->dev); + pm_runtime_put_autosuspend(host->dev); return; } if (req->sbc && !(host->flags & AUTO_CMD23)) { @@ -1618,12 +1567,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->power_mode != host->power_mode) { switch (ios->power_mode) { case MMC_POWER_OFF: - mmc_slot(host).set_power(host->dev, host->slot_id, - 0, 0); + mmc_pdata(host)->set_power(host->dev, 0, 0); break; case MMC_POWER_UP: - mmc_slot(host).set_power(host->dev, host->slot_id, - 1, ios->vdd); + mmc_pdata(host)->set_power(host->dev, 1, ios->vdd); break; case MMC_POWER_ON: do_send_init_stream = 1; @@ -1668,26 +1615,17 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc) { struct omap_hsmmc_host *host = mmc_priv(mmc); - if (!mmc_slot(host).card_detect) - return -ENOSYS; - return mmc_slot(host).card_detect(host->dev, host->slot_id); -} - -static int omap_hsmmc_get_ro(struct mmc_host *mmc) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - if (!mmc_slot(host).get_ro) + if (!host->card_detect) return -ENOSYS; - return mmc_slot(host).get_ro(host->dev, 0); + return host->card_detect(host->dev); } static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) { struct omap_hsmmc_host *host = mmc_priv(mmc); - if (mmc_slot(host).init_card) - mmc_slot(host).init_card(card); + if (mmc_pdata(host)->init_card) + mmc_pdata(host)->init_card(card); } static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) @@ -1810,25 +1748,6 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) set_sd_bus_power(host); } -static int omap_hsmmc_enable_fclk(struct mmc_host *mmc) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - pm_runtime_get_sync(host->dev); - - return 0; -} - -static int omap_hsmmc_disable_fclk(struct mmc_host *mmc) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); - - return 0; -} - static int omap_hsmmc_multi_io_quirk(struct mmc_card *card, unsigned int direction, int blk_size) { @@ -1840,14 +1759,12 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card *card, } static struct mmc_host_ops omap_hsmmc_ops = { - .enable = omap_hsmmc_enable_fclk, - .disable = omap_hsmmc_disable_fclk, .post_req = omap_hsmmc_post_req, .pre_req = omap_hsmmc_pre_req, .request = omap_hsmmc_request, .set_ios = omap_hsmmc_set_ios, .get_cd = omap_hsmmc_get_cd, - .get_ro = omap_hsmmc_get_ro, + .get_ro = mmc_gpio_get_ro, .init_card = omap_hsmmc_init_card, .enable_sdio_irq = omap_hsmmc_enable_sdio_irq, }; @@ -1957,17 +1874,10 @@ static const struct of_device_id omap_mmc_of_match[] = { }; MODULE_DEVICE_TABLE(of, omap_mmc_of_match); -static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) +static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) { - struct omap_mmc_platform_data *pdata; + struct omap_hsmmc_platform_data *pdata; struct device_node *np = dev->of_node; - u32 bus_width, max_freq; - int cd_gpio, wp_gpio; - - cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); - wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); - if (cd_gpio == -EPROBE_DEFER || wp_gpio == -EPROBE_DEFER) - return ERR_PTR(-EPROBE_DEFER); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -1976,40 +1886,25 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) 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 = cd_gpio; - pdata->slots[0].gpio_wp = wp_gpio; + pdata->gpio_cd = -EINVAL; + pdata->gpio_cod = -EINVAL; + pdata->gpio_wp = -EINVAL; if (of_find_property(np, "ti,non-removable", NULL)) { - pdata->slots[0].nonremovable = true; - pdata->slots[0].no_regulator_off_init = true; + pdata->nonremovable = true; + pdata->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; + pdata->features |= HSMMC_HAS_UPDATED_RESET; if (of_find_property(np, "ti,needs-special-hs-handling", NULL)) - pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT; - - if (of_find_property(np, "keep-power-in-suspend", NULL)) - pdata->slots[0].pm_caps |= MMC_PM_KEEP_POWER; - - if (of_find_property(np, "enable-sdio-wakeup", NULL)) - pdata->slots[0].pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + pdata->features |= HSMMC_HAS_HSPE_SUPPORT; return pdata; } #else -static inline struct omap_mmc_platform_data +static inline struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) { return ERR_PTR(-EINVAL); @@ -2018,7 +1913,7 @@ static inline struct omap_mmc_platform_data static int omap_hsmmc_probe(struct platform_device *pdev) { - struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; + struct omap_hsmmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_host *mmc; struct omap_hsmmc_host *host = NULL; struct resource *res; @@ -2048,11 +1943,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) return -ENXIO; } - if (pdata->nr_slots == 0) { - dev_err(&pdev->dev, "No Slots\n"); - return -ENXIO; - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (res == NULL || irq < 0) @@ -2062,16 +1952,16 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - ret = omap_hsmmc_gpio_init(pdata); - if (ret) - goto err; - mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; - goto err_alloc; + goto err; } + ret = mmc_of_parse(mmc); + if (ret) + goto err1; + host = mmc_priv(mmc); host->mmc = mmc; host->pdata = pdata; @@ -2079,13 +1969,16 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->use_dma = 1; host->dma_ch = -1; host->irq = irq; - host->slot_id = 0; host->mapbase = res->start + pdata->reg_offset; host->base = base + pdata->reg_offset; host->power_mode = MMC_POWER_OFF; host->next_data.cookie = 1; host->pbias_enabled = 0; + ret = omap_hsmmc_gpio_init(mmc, host, pdata); + if (ret) + goto err_gpio; + platform_set_drvdata(pdev, host); if (pdev->dev.of_node) @@ -2097,7 +1990,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (pdata->max_freq > 0) mmc->f_max = pdata->max_freq; - else + else if (mmc->f_max == 0) mmc->f_max = OMAP_MMC_MAX_CLOCK; spin_lock_init(&host->irq_lock); @@ -2144,14 +2037,14 @@ static int omap_hsmmc_probe(struct platform_device *pdev) mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE; - mmc->caps |= mmc_slot(host).caps; + mmc->caps |= mmc_pdata(host)->caps; if (mmc->caps & MMC_CAP_8_BIT_DATA) mmc->caps |= MMC_CAP_4_BIT_DATA; - if (mmc_slot(host).nonremovable) + if (mmc_pdata(host)->nonremovable) mmc->caps |= MMC_CAP_NONREMOVABLE; - mmc->pm_caps = mmc_slot(host).pm_caps; + mmc->pm_caps |= mmc_pdata(host)->pm_caps; omap_hsmmc_conf_bus_power(host); @@ -2204,38 +2097,14 @@ static int omap_hsmmc_probe(struct platform_device *pdev) goto err_irq; } - if (pdata->init != NULL) { - if (pdata->init(&pdev->dev) != 0) { - dev_err(mmc_dev(host->mmc), - "Unable to configure MMC IRQs\n"); - goto err_irq; - } - } - - if (omap_hsmmc_have_reg() && !mmc_slot(host).set_power) { + if (omap_hsmmc_have_reg() && !mmc_pdata(host)->set_power) { ret = omap_hsmmc_reg_get(host); if (ret) - goto err_reg; + goto err_irq; host->use_reg = 1; } - mmc->ocr_avail = mmc_slot(host).ocr_mask; - - /* Request IRQ for card detect */ - if ((mmc_slot(host).card_detect_irq)) { - ret = devm_request_threaded_irq(&pdev->dev, - mmc_slot(host).card_detect_irq, - NULL, omap_hsmmc_detect, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - mmc_hostname(mmc), host); - if (ret) { - dev_err(mmc_dev(host->mmc), - "Unable to grab MMC CD IRQ\n"); - goto err_irq_cd; - } - pdata->suspend = omap_hsmmc_suspend_cdirq; - pdata->resume = omap_hsmmc_resume_cdirq; - } + mmc->ocr_avail = mmc_pdata(host)->ocr_mask; omap_hsmmc_disable_irq(host); @@ -2255,14 +2124,14 @@ static int omap_hsmmc_probe(struct platform_device *pdev) mmc_add_host(mmc); - if (mmc_slot(host).name != NULL) { + if (mmc_pdata(host)->name != NULL) { ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name); if (ret < 0) goto err_slot_name; } - if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) { + if (host->get_cover_state) { ret = device_create_file(&mmc->class_dev, - &dev_attr_cover_switch); + &dev_attr_cover_switch); if (ret < 0) goto err_slot_name; } @@ -2275,12 +2144,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev) err_slot_name: mmc_remove_host(mmc); -err_irq_cd: if (host->use_reg) omap_hsmmc_reg_put(host); -err_reg: - if (host->pdata->cleanup) - host->pdata->cleanup(&pdev->dev); err_irq: if (host->tx_chan) dma_release_channel(host->tx_chan); @@ -2291,9 +2156,8 @@ err_irq: if (host->dbclk) clk_disable_unprepare(host->dbclk); err1: +err_gpio: mmc_free_host(mmc); -err_alloc: - omap_hsmmc_gpio_free(pdata); err: return ret; } @@ -2306,8 +2170,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev) mmc_remove_host(host->mmc); if (host->use_reg) omap_hsmmc_reg_put(host); - if (host->pdata->cleanup) - host->pdata->cleanup(&pdev->dev); if (host->tx_chan) dma_release_channel(host->tx_chan); @@ -2319,32 +2181,12 @@ static int omap_hsmmc_remove(struct platform_device *pdev) if (host->dbclk) clk_disable_unprepare(host->dbclk); - omap_hsmmc_gpio_free(host->pdata); mmc_free_host(host->mmc); return 0; } -#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); - -} - +#ifdef CONFIG_PM_SLEEP static int omap_hsmmc_suspend(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); @@ -2400,12 +2242,6 @@ static int omap_hsmmc_resume(struct device *dev) pm_runtime_put_autosuspend(host->dev); return 0; } - -#else -#define omap_hsmmc_prepare NULL -#define omap_hsmmc_complete NULL -#define omap_hsmmc_suspend NULL -#define omap_hsmmc_resume NULL #endif static int omap_hsmmc_runtime_suspend(struct device *dev) @@ -2486,10 +2322,7 @@ 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, + SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume) .runtime_suspend = omap_hsmmc_runtime_suspend, .runtime_resume = omap_hsmmc_runtime_resume, }; diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index c70b602f8f1e..1d3d6c4bfdc6 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -28,6 +28,7 @@ #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> +#include <linux/mmc/sdio.h> #include <linux/mmc/card.h> #include <linux/mfd/rtsx_pci.h> #include <asm/unaligned.h> @@ -53,9 +54,9 @@ struct realtek_pci_sdmmc { #define SDMMC_POWER_ON 1 #define SDMMC_POWER_OFF 0 - unsigned int sg_count; + int sg_count; s32 cookie; - unsigned int cookie_sg_count; + int cookie_sg_count; bool using_cookie; }; @@ -71,30 +72,83 @@ static inline void sd_clear_error(struct realtek_pci_sdmmc *host) } #ifdef DEBUG -static void sd_print_debug_regs(struct realtek_pci_sdmmc *host) +static void dump_reg_range(struct realtek_pci_sdmmc *host, u16 start, u16 end) { - struct rtsx_pcr *pcr = host->pcr; - u16 i; - u8 *ptr; + u16 len = end - start + 1; + int i; + u8 data[8]; + + for (i = 0; i < len; i += 8) { + int j; + int n = min(8, len - i); + + memset(&data, 0, sizeof(data)); + for (j = 0; j < n; j++) + rtsx_pci_read_register(host->pcr, start + i + j, + data + j); + dev_dbg(sdmmc_dev(host), "0x%04X(%d): %8ph\n", + start + i, n, data); + } +} - /* 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++)); +static void sd_print_debug_regs(struct realtek_pci_sdmmc *host) +{ + dump_reg_range(host, 0xFDA0, 0xFDB3); + dump_reg_range(host, 0xFD52, 0xFD69); } #else #define sd_print_debug_regs(host) #endif /* DEBUG */ +static inline int sd_get_cd_int(struct realtek_pci_sdmmc *host) +{ + return rtsx_pci_readl(host->pcr, RTSX_BIPR) & SD_EXIST; +} + +static void sd_cmd_set_sd_cmd(struct rtsx_pcr *pcr, struct mmc_command *cmd) +{ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF, + SD_CMD_START | cmd->opcode); + rtsx_pci_write_be32(pcr, SD_CMD1, cmd->arg); +} + +static void sd_cmd_set_data_len(struct rtsx_pcr *pcr, u16 blocks, u16 blksz) +{ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, blocks); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, blocks >> 8); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, blksz); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, blksz >> 8); +} + +static int sd_response_type(struct mmc_command *cmd) +{ + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + return SD_RSP_TYPE_R0; + case MMC_RSP_R1: + return SD_RSP_TYPE_R1; + case MMC_RSP_R1 & ~MMC_RSP_CRC: + return SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7; + case MMC_RSP_R1B: + return SD_RSP_TYPE_R1b; + case MMC_RSP_R2: + return SD_RSP_TYPE_R2; + case MMC_RSP_R3: + return SD_RSP_TYPE_R3; + default: + return -EINVAL; + } +} + +static int sd_status_index(int resp_type) +{ + if (resp_type == SD_RSP_TYPE_R0) + return 0; + else if (resp_type == SD_RSP_TYPE_R2) + return 16; + + return 5; +} /* * sd_pre_dma_transfer - do dma_map_sg() or using cookie * @@ -166,123 +220,6 @@ static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, data->host_cookie = 0; } -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) { @@ -293,47 +230,18 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, int timeout = 100; int i; u8 *ptr; - int stat_idx = 0; - u8 rsp_type; - int rsp_len = 5; + int rsp_type; + int stat_idx; bool clock_toggled = false; 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_R1 & ~MMC_RSP_CRC: - rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7; - 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; + rsp_type = sd_response_type(cmd); + if (rsp_type < 0) goto out; - } + + stat_idx = sd_status_index(rsp_type); if (rsp_type == SD_RSP_TYPE_R1b) timeout = 3000; @@ -348,13 +256,7 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, } 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); - + sd_cmd_set_sd_cmd(pcr, cmd); 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); @@ -368,12 +270,10 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, /* 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); @@ -438,71 +338,213 @@ out: SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); } -static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) +static int sd_read_data(struct realtek_pci_sdmmc *host, struct mmc_command *cmd, + u16 byte_cnt, u8 *buf, int buf_len, int timeout) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + u8 trans_mode; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd->opcode, cmd->arg); + + if (!buf) + buf_len = 0; + + if (cmd->opcode == MMC_SEND_TUNING_BLOCK) + trans_mode = SD_TM_AUTO_TUNING; + else + trans_mode = SD_TM_NORMAL_READ; + + rtsx_pci_init_cmd(pcr); + sd_cmd_set_sd_cmd(pcr, cmd); + sd_cmd_set_data_len(pcr, 1, byte_cnt); + 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, + struct mmc_command *cmd, u16 byte_cnt, u8 *buf, int buf_len, + int timeout) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd->opcode, cmd->arg); + + if (!buf) + buf_len = 0; + + sd_send_cmd_get_rsp(host, cmd); + if (cmd->error) + return cmd->error; + + 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; + } + } + + rtsx_pci_init_cmd(pcr); + sd_cmd_set_data_len(pcr, 1, byte_cnt); + 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_0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + SD_TRANSFER_START | SD_TM_AUTO_WRITE_3); + 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 int sd_read_long_data(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_command *cmd = mrq->cmd; struct mmc_data *data = mrq->data; int uhs = mmc_card_uhs(card); - int read = (data->flags & MMC_DATA_READ) ? 1 : 0; - u8 cfg2, trans_mode; + u8 cfg2 = 0; int err; + int resp_type; 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; - } + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd->opcode, cmd->arg); + + resp_type = sd_response_type(cmd); + if (resp_type < 0) + return resp_type; 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)); - + sd_cmd_set_sd_cmd(pcr, cmd); + sd_cmd_set_data_len(pcr, data->blocks, data->blksz); 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)); + 0xFF, (u8)(data_len >> 24)); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, - 0xFF, (u8)(data_len >> 16)); + 0xFF, (u8)(data_len >> 16)); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, - 0xFF, (u8)(data_len >> 8)); + 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, DMACTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_FROM_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 | resp_type); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + SD_TRANSFER_START | SD_TM_AUTO_READ_2); + 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_dma_transfer(pcr, data->sg, host->sg_count, 1, 10000); + if (err < 0) { + sd_print_debug_regs(host); + sd_clear_error(host); + return err; } + return 0; +} + +static int sd_write_long_data(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_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + int uhs = mmc_card_uhs(card); + u8 cfg2; + int err; + size_t data_len = data->blksz * data->blocks; + + sd_send_cmd_get_rsp(host, cmd); + if (cmd->error) + return cmd->error; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd->opcode, cmd->arg); + + cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; + + if (!uhs) + cfg2 |= SD_NO_CHECK_WAIT_CRC_TO; + + rtsx_pci_init_cmd(pcr); + sd_cmd_set_data_len(pcr, data->blocks, data->blksz); + 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); + 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); + SD_TRANSFER_START | SD_TM_AUTO_WRITE_3); 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_dma_transfer(pcr, data->sg, host->sg_count, read, 10000); + err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, 0, 10000); if (err < 0) { sd_clear_error(host); return err; @@ -511,6 +553,23 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) return 0; } +static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) +{ + struct mmc_data *data = mrq->data; + + if (host->sg_count < 0) { + data->error = host->sg_count; + dev_dbg(sdmmc_dev(host), "%s: sg_count = %d is invalid\n", + __func__, host->sg_count); + return data->error; + } + + if (data->flags & MMC_DATA_READ) + return sd_read_long_data(host, mrq); + + return sd_write_long_data(host, mrq); +} + static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host) { rtsx_pci_write_register(host->pcr, SD_CFG1, @@ -528,10 +587,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host, { 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])); + u8 *buf; buf = kzalloc(data->blksz, GFP_NOIO); if (!buf) { @@ -543,7 +599,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host, if (host->initial_mode) sd_disable_initial_mode(host); - cmd->error = sd_read_data(host, _cmd, (u16)data->blksz, buf, + cmd->error = sd_read_data(host, cmd, (u16)data->blksz, buf, data->blksz, 200); if (host->initial_mode) @@ -553,7 +609,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host, } else { sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz); - cmd->error = sd_write_data(host, _cmd, (u16)data->blksz, buf, + cmd->error = sd_write_data(host, cmd, (u16)data->blksz, buf, data->blksz, 200); } @@ -653,14 +709,14 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, u8 opcode, u8 sample_point) { int err; - u8 cmd[5] = {0}; + struct mmc_command cmd = {0}; err = sd_change_phase(host, sample_point, true); if (err < 0) return err; - cmd[0] = 0x40 | opcode; - err = sd_read_data(host, cmd, 0x40, NULL, 0, 100); + cmd.opcode = opcode; + err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100); if (err < 0) { /* Wait till SD DATA IDLE */ sd_wait_data_idle(host); @@ -727,6 +783,12 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode) return 0; } +static inline int sdio_extblock_cmd(struct mmc_command *cmd, + struct mmc_data *data) +{ + return (cmd->opcode == SD_IO_RW_EXTENDED) && (data->blksz == 512); +} + static inline int sd_rw_cmd(struct mmc_command *cmd) { return mmc_op_multi(cmd->opcode) || @@ -748,7 +810,7 @@ static void sd_request(struct work_struct *work) unsigned int data_size = 0; int err; - if (host->eject) { + if (host->eject || !sd_get_cd_int(host)) { cmd->error = -ENOMEDIUM; goto finish; } @@ -776,17 +838,15 @@ static void sd_request(struct work_struct *work) if (mrq->data) data_size = data->blocks * data->blksz; - if (!data_size || sd_rw_cmd(cmd)) { + if (!data_size) { sd_send_cmd_get_rsp(host, cmd); + } else if (sd_rw_cmd(cmd) || sdio_extblock_cmd(cmd, data)) { + cmd->error = sd_rw_multi(host, mrq); + if (!host->using_cookie) + sdmmc_post_req(host->mmc, host->mrq, 0); - if (!cmd->error && data_size) { - sd_rw_multi(host, mrq); - if (!host->using_cookie) - sdmmc_post_req(host->mmc, host->mrq, 0); - - if (mmc_op_multi(cmd->opcode) && mrq->stop) - sd_send_cmd_get_rsp(host, mrq->stop); - } + if (mmc_op_multi(cmd->opcode) && mrq->stop) + sd_send_cmd_get_rsp(host, mrq->stop); } else { sd_normal_rw(host, mrq); } @@ -801,8 +861,10 @@ static void sd_request(struct work_struct *work) mutex_unlock(&pcr->pcr_mutex); finish: - if (cmd->error) - dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error); + if (cmd->error) { + dev_dbg(sdmmc_dev(host), "CMD %d 0x%08x error(%d)\n", + cmd->opcode, cmd->arg, cmd->error); + } mutex_lock(&host->host_mutex); host->mrq = NULL; @@ -820,7 +882,7 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; mutex_unlock(&host->host_mutex); - if (sd_rw_cmd(mrq->cmd)) + if (sd_rw_cmd(mrq->cmd) || sdio_extblock_cmd(mrq->cmd, data)) host->using_cookie = sd_pre_dma_transfer(host, data, false); queue_work(host->workq, &host->work); @@ -1066,7 +1128,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc) u32 val; if (host->eject) - return -ENOMEDIUM; + return cd; mutex_lock(&pcr->pcr_mutex); @@ -1317,6 +1379,7 @@ static void rtsx_pci_sdmmc_card_event(struct platform_device *pdev) { struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); + host->cookie = -1; mmc_detect_change(host->mmc, 0); } @@ -1349,6 +1412,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) host->pcr = pcr; host->mmc = mmc; host->pdev = pdev; + host->cookie = -1; host->power_state = SDMMC_POWER_OFF; INIT_WORK(&host->work, sd_request); platform_set_drvdata(pdev, host); diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 9cccc0e89b04..22d929fa3371 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -40,7 +40,6 @@ #include <linux/mmc/host.h> #include <linux/mmc/pm.h> #include <linux/mmc/slot-gpio.h> -#include <linux/mmc/sdhci.h> #include "sdhci.h" @@ -76,6 +75,7 @@ struct sdhci_acpi_host { const struct sdhci_acpi_slot *slot; struct platform_device *pdev; bool use_runtime_pm; + bool dma_setup; }; static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) @@ -85,7 +85,29 @@ static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) static int sdhci_acpi_enable_dma(struct sdhci_host *host) { - return 0; + struct sdhci_acpi_host *c = sdhci_priv(host); + struct device *dev = &c->pdev->dev; + int err = -1; + + if (c->dma_setup) + return 0; + + if (host->flags & SDHCI_USE_64_BIT_DMA) { + if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) { + host->flags &= ~SDHCI_USE_64_BIT_DMA; + } else { + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (err) + dev_warn(dev, "Failed to set 64-bit DMA mask\n"); + } + } + + if (err) + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + + c->dma_setup = !err; + + return err; } static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) @@ -135,7 +157,7 @@ static int sdhci_acpi_emmc_probe_slot(struct platform_device *pdev, host = c->host; - /* Platform specific code during emmc proble slot goes here */ + /* Platform specific code during emmc probe slot goes here */ if (hid && uid && !strcmp(hid, "80860F14") && !strcmp(uid, "1") && sdhci_readl(host, SDHCI_CAPABILITIES) == 0x446cc8b2 && @@ -156,7 +178,7 @@ static int sdhci_acpi_sdio_probe_slot(struct platform_device *pdev, host = c->host; - /* Platform specific code during emmc proble slot goes here */ + /* Platform specific code during sdio probe slot goes here */ return 0; } @@ -172,7 +194,7 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev, host = c->host; - /* Platform specific code during emmc proble slot goes here */ + /* Platform specific code during sd probe slot goes here */ return 0; } @@ -180,17 +202,21 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev, static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = { .chip = &sdhci_acpi_chip_int, .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | - MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR, + MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | + MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY, .caps2 = MMC_CAP2_HC_ERASE_SZ, .flags = SDHCI_ACPI_RUNTIME_PM, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC, .probe_slot = sdhci_acpi_emmc_probe_slot, }; static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { - .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, + .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, - .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD, + .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD | + MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY, .flags = SDHCI_ACPI_RUNTIME_PM, .pm_caps = MMC_PM_KEEP_POWER, .probe_slot = sdhci_acpi_sdio_probe_slot, @@ -199,8 +225,10 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { .flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL | SDHCI_ACPI_RUNTIME_PM, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | SDHCI_QUIRK2_STOP_WITH_TC, + .caps = MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY, .probe_slot = sdhci_acpi_sd_probe_slot, }; @@ -218,6 +246,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { { "INT33BB" , "3" , &sdhci_acpi_slot_int_sd }, { "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio }, { "INT3436" , NULL, &sdhci_acpi_slot_int_sdio }, + { "INT344D" , NULL, &sdhci_acpi_slot_int_sdio }, { "PNP0D40" }, { }, }; @@ -228,6 +257,7 @@ static const struct acpi_device_id sdhci_acpi_ids[] = { { "INT33BB" }, { "INT33C6" }, { "INT3436" }, + { "INT344D" }, { "PNP0D40" }, { }, }; @@ -305,21 +335,6 @@ static int sdhci_acpi_probe(struct platform_device *pdev) 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); - } - - err = dma_coerce_mask_and_coherent(dev, dma_mask); - if (err) - goto err_free; - } - if (c->slot) { if (c->slot->probe_slot) { err = c->slot->probe_slot(pdev, hid, uid); @@ -416,7 +431,7 @@ static int sdhci_acpi_resume(struct device *dev) #endif -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int sdhci_acpi_runtime_suspend(struct device *dev) { @@ -432,24 +447,18 @@ static int sdhci_acpi_runtime_resume(struct device *dev) return sdhci_runtime_resume_host(c->host); } -static int sdhci_acpi_runtime_idle(struct device *dev) -{ - return 0; -} - #endif static const struct dev_pm_ops sdhci_acpi_pm_ops = { .suspend = sdhci_acpi_suspend, .resume = sdhci_acpi_resume, SET_RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend, - sdhci_acpi_runtime_resume, sdhci_acpi_runtime_idle) + sdhci_acpi_runtime_resume, NULL) }; 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, }, diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index e7e4fbdcbfe0..2bd90fb35c75 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -54,7 +54,6 @@ struct sdhci_bcm_kona_dev { struct mutex write_lock; /* protect back to back writes */ - struct clk *external_clk; }; @@ -175,24 +174,6 @@ static void sdhci_bcm_kona_card_event(struct sdhci_host *host) } } -/* - * Get the base clock. Use central clock source for now. Not sure if different - * clock speed to each dev is allowed - */ -static unsigned int sdhci_bcm_kona_get_max_clk(struct sdhci_host *host) -{ - struct sdhci_bcm_kona_dev *kona_dev; - struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); - kona_dev = sdhci_pltfm_priv(pltfm_priv); - - return host->mmc->f_max; -} - -static unsigned int sdhci_bcm_kona_get_timeout_clock(struct sdhci_host *host) -{ - return sdhci_bcm_kona_get_max_clk(host); -} - static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host, u8 power_mode) { @@ -207,8 +188,8 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host, static struct sdhci_ops sdhci_bcm_kona_ops = { .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_bcm_kona_get_max_clk, - .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, @@ -254,7 +235,9 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) kona_dev = sdhci_pltfm_priv(pltfm_priv); mutex_init(&kona_dev->write_lock); - mmc_of_parse(host->mmc); + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_pltfm_free; if (!host->mmc->f_max) { dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n"); @@ -262,21 +245,21 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) goto err_pltfm_free; } - /* Get and enable the external clock */ - kona_dev->external_clk = devm_clk_get(dev, NULL); - if (IS_ERR(kona_dev->external_clk)) { - dev_err(dev, "Failed to get external clock\n"); - ret = PTR_ERR(kona_dev->external_clk); + /* Get and enable the core clock */ + pltfm_priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(pltfm_priv->clk)) { + dev_err(dev, "Failed to get core clock\n"); + ret = PTR_ERR(pltfm_priv->clk); goto err_pltfm_free; } - if (clk_set_rate(kona_dev->external_clk, host->mmc->f_max) != 0) { - dev_err(dev, "Failed to set rate external clock\n"); + if (clk_set_rate(pltfm_priv->clk, host->mmc->f_max) != 0) { + dev_err(dev, "Failed to set rate core clock\n"); goto err_pltfm_free; } - if (clk_prepare_enable(kona_dev->external_clk) != 0) { - dev_err(dev, "Failed to enable external clock\n"); + if (clk_prepare_enable(pltfm_priv->clk) != 0) { + dev_err(dev, "Failed to enable core clock\n"); goto err_pltfm_free; } @@ -331,7 +314,7 @@ err_reset: sdhci_bcm_kona_sd_reset(host); err_clk_disable: - clk_disable_unprepare(kona_dev->external_clk); + clk_disable_unprepare(pltfm_priv->clk); err_pltfm_free: sdhci_pltfm_free(pdev); @@ -340,22 +323,6 @@ err_pltfm_free: return ret; } -static int sdhci_bcm_kona_remove(struct platform_device *pdev) -{ - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); - struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv); - int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - - sdhci_remove_host(host, dead); - - clk_disable_unprepare(kona_dev->external_clk); - - sdhci_pltfm_free(pdev); - - return 0; -} - static struct platform_driver sdhci_bcm_kona_driver = { .driver = { .name = "sdhci-kona", @@ -363,7 +330,7 @@ static struct platform_driver sdhci_bcm_kona_driver = { .of_match_table = sdhci_bcm_kona_of_match, }, .probe = sdhci_bcm_kona_probe, - .remove = sdhci_bcm_kona_remove, + .remove = sdhci_pltfm_unregister, }; module_platform_driver(sdhci_bcm_kona_driver); diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c index 439d259fdf1d..0ef0343c603a 100644 --- a/drivers/mmc/host/sdhci-bcm2835.c +++ b/drivers/mmc/host/sdhci-bcm2835.c @@ -180,11 +180,6 @@ err: return ret; } -static int bcm2835_sdhci_remove(struct platform_device *pdev) -{ - return sdhci_pltfm_unregister(pdev); -} - static const struct of_device_id bcm2835_sdhci_of_match[] = { { .compatible = "brcm,bcm2835-sdhci" }, { } @@ -198,7 +193,7 @@ static struct platform_driver bcm2835_sdhci_driver = { .pm = SDHCI_PLTFM_PMOPS, }, .probe = bcm2835_sdhci_probe, - .remove = bcm2835_sdhci_remove, + .remove = sdhci_pltfm_unregister, }; module_platform_driver(bcm2835_sdhci_driver); diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index a7935a8d0922..59f2923f8054 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -98,18 +98,13 @@ static int sdhci_cns3xxx_probe(struct platform_device *pdev) return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata, 0); } -static int sdhci_cns3xxx_remove(struct platform_device *pdev) -{ - return sdhci_pltfm_unregister(pdev); -} - static struct platform_driver sdhci_cns3xxx_driver = { .driver = { .name = "sdhci-cns3xxx", .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_cns3xxx_probe, - .remove = sdhci_cns3xxx_remove, + .remove = sdhci_pltfm_unregister, }; module_platform_driver(sdhci_cns3xxx_driver); diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index ca969d271a27..407c21f152b2 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -28,10 +28,6 @@ #include "sdhci-pltfm.h" -struct sdhci_dove_priv { - struct clk *clk; -}; - static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) { u16 ret; @@ -84,27 +80,17 @@ static int 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); - host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata, 0); if (IS_ERR(host)) return PTR_ERR(host); pltfm_host = sdhci_priv(host); - pltfm_host->priv = priv; + pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); - if (!IS_ERR(priv->clk)) - clk_prepare_enable(priv->clk); + if (!IS_ERR(pltfm_host->clk)) + clk_prepare_enable(pltfm_host->clk); ret = mmc_of_parse(host->mmc); if (ret) @@ -117,26 +103,11 @@ static int sdhci_dove_probe(struct platform_device *pdev) return 0; err_sdhci_add: - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(pltfm_host->clk); sdhci_pltfm_free(pdev); return ret; } -static int 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 (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); - - return 0; -} - static const struct of_device_id sdhci_dove_of_match_table[] = { { .compatible = "marvell,dove-sdhci", }, {} @@ -150,7 +121,7 @@ static struct platform_driver sdhci_dove_driver = { .of_match_table = sdhci_dove_of_match_table, }, .probe = sdhci_dove_probe, - .remove = sdhci_dove_remove, + .remove = sdhci_pltfm_unregister, }; module_platform_driver(sdhci_dove_driver); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 587ee0edeb57..82f512d87cb8 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -65,8 +65,6 @@ /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ #define ESDHC_TUNING_START_TAP 0x1 -#define ESDHC_TUNING_BLOCK_PATTERN_LEN 64 - /* pinctrl state */ #define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz" #define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz" @@ -418,7 +416,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; else new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; - writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); + writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); return; case SDHCI_HOST_CONTROL2: new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); @@ -692,8 +690,6 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) /* FIXME: delay a bit for card to be ready for next tuning due to errors */ mdelay(1); - /* This is balanced by the runtime put in sdhci_tasklet_finish */ - pm_runtime_get_sync(host->mmc->parent); reg = readl(host->ioaddr + ESDHC_MIX_CTRL); reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | ESDHC_MIX_CTRL_FBCLK_SEL; @@ -704,54 +700,6 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); } -static void esdhc_request_done(struct mmc_request *mrq) -{ - complete(&mrq->completion); -} - -static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode, - struct scatterlist *sg) -{ - struct mmc_command cmd = {0}; - struct mmc_request mrq = {NULL}; - struct mmc_data data = {0}; - - cmd.opcode = opcode; - cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - - data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN; - data.blocks = 1; - data.flags = MMC_DATA_READ; - data.sg = sg; - data.sg_len = 1; - - mrq.cmd = &cmd; - mrq.cmd->mrq = &mrq; - mrq.data = &data; - mrq.data->mrq = &mrq; - mrq.cmd->data = mrq.data; - - mrq.done = esdhc_request_done; - init_completion(&(mrq.completion)); - - spin_lock_irq(&host->lock); - host->mrq = &mrq; - - sdhci_send_command(host, mrq.cmd); - - spin_unlock_irq(&host->lock); - - wait_for_completion(&mrq.completion); - - if (cmd.error) - return cmd.error; - if (data.error) - return data.error; - - return 0; -} - static void esdhc_post_tuning(struct sdhci_host *host) { u32 reg; @@ -763,21 +711,13 @@ static void esdhc_post_tuning(struct sdhci_host *host) static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) { - struct scatterlist sg; - char *tuning_pattern; int min, max, avg, ret; - tuning_pattern = kmalloc(ESDHC_TUNING_BLOCK_PATTERN_LEN, GFP_KERNEL); - if (!tuning_pattern) - return -ENOMEM; - - sg_init_one(&sg, tuning_pattern, ESDHC_TUNING_BLOCK_PATTERN_LEN); - /* find the mininum delay first which can pass tuning */ min = ESDHC_TUNE_CTRL_MIN; while (min < ESDHC_TUNE_CTRL_MAX) { esdhc_prepare_tuning(host, min); - if (!esdhc_send_tuning_cmd(host, opcode, &sg)) + if (!mmc_send_tuning(host->mmc)) break; min += ESDHC_TUNE_CTRL_STEP; } @@ -786,7 +726,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) max = min + ESDHC_TUNE_CTRL_STEP; while (max < ESDHC_TUNE_CTRL_MAX) { esdhc_prepare_tuning(host, max); - if (esdhc_send_tuning_cmd(host, opcode, &sg)) { + if (mmc_send_tuning(host->mmc)) { max -= ESDHC_TUNE_CTRL_STEP; break; } @@ -796,11 +736,9 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) /* use average delay to get the best timing */ avg = (min + max) / 2; esdhc_prepare_tuning(host, avg); - ret = esdhc_send_tuning_cmd(host, opcode, &sg); + ret = mmc_send_tuning(host->mmc); esdhc_post_tuning(host); - kfree(tuning_pattern); - dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n", ret ? "failed" : "passed", avg, ret); @@ -926,6 +864,7 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { #ifdef CONFIG_OF static int sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, + struct sdhci_host *host, struct esdhc_platform_data *boarddata) { struct device_node *np = pdev->dev.of_node; @@ -962,11 +901,14 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line)) boarddata->delay_line = 0; + mmc_of_parse_voltage(np, &host->ocr_mask); + return 0; } #else static inline int sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, + struct sdhci_host *host, struct esdhc_platform_data *boarddata) { return -ENODEV; @@ -1031,11 +973,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl, PINCTRL_STATE_DEFAULT); - if (IS_ERR(imx_data->pins_default)) { - err = PTR_ERR(imx_data->pins_default); - dev_err(mmc_dev(host->mmc), "could not get default state\n"); - goto disable_clk; - } + if (IS_ERR(imx_data->pins_default)) + dev_warn(mmc_dev(host->mmc), "could not get default state\n"); host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; @@ -1064,7 +1003,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) host->ioaddr + ESDHC_TUNING_CTRL); boarddata = &imx_data->boarddata; - if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { + if (sdhci_esdhc_imx_probe_dt(pdev, host, boarddata) < 0) { if (!host->mmc->parent->platform_data) { dev_err(mmc_dev(host->mmc), "no board data!\n"); err = -EINVAL; @@ -1074,40 +1013,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) host->mmc->parent->platform_data); } - /* write_protect */ - if (boarddata->wp_type == ESDHC_WP_GPIO) { - err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio); - if (err) { - dev_err(mmc_dev(host->mmc), - "failed to request write-protect gpio!\n"); - goto disable_clk; - } - host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; - } - /* card_detect */ - switch (boarddata->cd_type) { - case ESDHC_CD_GPIO: - err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0); - if (err) { - dev_err(mmc_dev(host->mmc), - "failed to request card-detect gpio!\n"); - goto disable_clk; - } - /* fall through */ - - case ESDHC_CD_CONTROLLER: - /* we have a working card_detect back */ + if (boarddata->cd_type == ESDHC_CD_CONTROLLER) host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; - break; - - case ESDHC_CD_PERMANENT: - host->mmc->caps |= MMC_CAP_NONREMOVABLE; - break; - - case ESDHC_CD_NONE: - break; - } switch (boarddata->max_bus_width) { case 8: @@ -1123,7 +1031,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) } /* sdr50 and sdr104 needs work on 1.8v signal voltage */ - if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data)) { + if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) && + !IS_ERR(imx_data->pins_default)) { imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl, ESDHC_PINCTRL_STATE_100MHZ); imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl, @@ -1139,15 +1048,20 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; } + /* call to generic mmc_of_parse to support additional capabilities */ + err = mmc_of_parse(host->mmc); + if (err) + goto disable_clk; + err = sdhci_add_host(host); if (err) goto disable_clk; pm_runtime_set_active(&pdev->dev); - 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); + pm_runtime_enable(&pdev->dev); return 0; @@ -1167,23 +1081,22 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev) struct pltfm_imx_data *imx_data = pltfm_host->priv; int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - sdhci_remove_host(host, dead); - - pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); - if (!IS_ENABLED(CONFIG_PM_RUNTIME)) { - clk_disable_unprepare(imx_data->clk_per); - clk_disable_unprepare(imx_data->clk_ipg); - clk_disable_unprepare(imx_data->clk_ahb); - } + 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); sdhci_pltfm_free(pdev); return 0; } -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int sdhci_esdhc_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c new file mode 100644 index 000000000000..3b423b0ad8e7 --- /dev/null +++ b/drivers/mmc/host/sdhci-iproc.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * iProc SDHCI platform driver + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/mmc/host.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include "sdhci-pltfm.h" + +struct sdhci_iproc_data { + const struct sdhci_pltfm_data *pdata; + u32 caps; + u32 caps1; +}; + +struct sdhci_iproc_host { + const struct sdhci_iproc_data *data; + u32 shadow_cmd; + u32 shadow_blk; +}; + +#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) + +static inline u32 sdhci_iproc_readl(struct sdhci_host *host, int reg) +{ + u32 val = readl(host->ioaddr + reg); + + pr_debug("%s: readl [0x%02x] 0x%08x\n", + mmc_hostname(host->mmc), reg, val); + return val; +} + +static u16 sdhci_iproc_readw(struct sdhci_host *host, int reg) +{ + u32 val = sdhci_iproc_readl(host, (reg & ~3)); + u16 word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; + return word; +} + +static u8 sdhci_iproc_readb(struct sdhci_host *host, int reg) +{ + u32 val = sdhci_iproc_readl(host, (reg & ~3)); + u8 byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff; + return byte; +} + +static inline void sdhci_iproc_writel(struct sdhci_host *host, u32 val, int reg) +{ + pr_debug("%s: writel [0x%02x] 0x%08x\n", + mmc_hostname(host->mmc), reg, val); + + writel(val, host->ioaddr + reg); + + if (host->clock <= 400000) { + /* Round up to micro-second four SD clock delay */ + if (host->clock) + udelay((4 * 1000000 + host->clock - 1) / host->clock); + else + udelay(10); + } +} + +/* + * The Arasan has a bugette whereby it may lose the content of successive + * writes to the same register that are within two SD-card clock cycles of + * each other (a clock domain crossing problem). The data + * register does not have this problem, which is just as well - otherwise we'd + * have to nobble the DMA engine too. + * + * This wouldn't be a problem with the code except that we can only write the + * controller with 32-bit writes. So two different 16-bit registers are + * written back to back creates the problem. + * + * In reality, this only happens when SDHCI_BLOCK_SIZE and SDHCI_BLOCK_COUNT + * are written followed by SDHCI_TRANSFER_MODE and SDHCI_COMMAND. + * The BLOCK_SIZE and BLOCK_COUNT are meaningless until a command issued so + * the work around can be further optimized. We can keep shadow values of + * BLOCK_SIZE, BLOCK_COUNT, and TRANSFER_MODE until a COMMAND is issued. + * Then, write the BLOCK_SIZE+BLOCK_COUNT in a single 32-bit write followed + * by the TRANSFER+COMMAND in another 32-bit write. + */ +static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host); + u32 word_shift = REG_OFFSET_IN_BITS(reg); + u32 mask = 0xffff << word_shift; + u32 oldval, newval; + + if (reg == SDHCI_COMMAND) { + /* Write the block now as we are issuing a command */ + if (iproc_host->shadow_blk != 0) { + sdhci_iproc_writel(host, iproc_host->shadow_blk, + SDHCI_BLOCK_SIZE); + iproc_host->shadow_blk = 0; + } + oldval = iproc_host->shadow_cmd; + } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { + /* Block size and count are stored in shadow reg */ + oldval = iproc_host->shadow_blk; + } else { + /* Read reg, all other registers are not shadowed */ + oldval = sdhci_iproc_readl(host, (reg & ~3)); + } + newval = (oldval & ~mask) | (val << word_shift); + + if (reg == SDHCI_TRANSFER_MODE) { + /* Save the transfer mode until the command is issued */ + iproc_host->shadow_cmd = newval; + } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { + /* Save the block info until the command is issued */ + iproc_host->shadow_blk = newval; + } else { + /* Command or other regular 32-bit write */ + sdhci_iproc_writel(host, newval, reg & ~3); + } +} + +static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg) +{ + u32 oldval = sdhci_iproc_readl(host, (reg & ~3)); + u32 byte_shift = REG_OFFSET_IN_BITS(reg); + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + + sdhci_iproc_writel(host, newval, reg & ~3); +} + +static const struct sdhci_ops sdhci_iproc_ops = { + .read_l = sdhci_iproc_readl, + .read_w = sdhci_iproc_readw, + .read_b = sdhci_iproc_readb, + .write_l = sdhci_iproc_writel, + .write_w = sdhci_iproc_writew, + .write_b = sdhci_iproc_writeb, + .set_clock = sdhci_set_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = { + .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, + .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN, + .ops = &sdhci_iproc_ops, +}; + +static const struct sdhci_iproc_data iproc_data = { + .pdata = &sdhci_iproc_pltfm_data, + .caps = 0x05E90000, + .caps1 = 0x00000064, +}; + +static const struct of_device_id sdhci_iproc_of_match[] = { + { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_data }, + { } +}; +MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match); + +static int sdhci_iproc_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + const struct sdhci_iproc_data *iproc_data; + struct sdhci_host *host; + struct sdhci_iproc_host *iproc_host; + struct sdhci_pltfm_host *pltfm_host; + int ret; + + match = of_match_device(sdhci_iproc_of_match, &pdev->dev); + if (!match) + return -EINVAL; + iproc_data = match->data; + + host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host)); + if (IS_ERR(host)) + return PTR_ERR(host); + + pltfm_host = sdhci_priv(host); + iproc_host = sdhci_pltfm_priv(pltfm_host); + + iproc_host->data = iproc_data; + + mmc_of_parse(host->mmc); + sdhci_get_of_property(pdev); + + /* Enable EMMC 1/8V DDR capable */ + host->mmc->caps |= MMC_CAP_1_8V_DDR; + + pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pltfm_host->clk)) { + ret = PTR_ERR(pltfm_host->clk); + goto err; + } + + if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) { + host->caps = iproc_host->data->caps; + host->caps1 = iproc_host->data->caps1; + } + + return sdhci_add_host(host); + +err: + sdhci_pltfm_free(pdev); + return ret; +} + +static int sdhci_iproc_remove(struct platform_device *pdev) +{ + return sdhci_pltfm_unregister(pdev); +} + +static struct platform_driver sdhci_iproc_driver = { + .driver = { + .name = "sdhci-iproc", + .of_match_table = sdhci_iproc_of_match, + .pm = SDHCI_PLTFM_PMOPS, + }, + .probe = sdhci_iproc_probe, + .remove = sdhci_iproc_remove, +}; +module_platform_driver(sdhci_iproc_driver); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("IPROC SDHCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 30804385af6d..4a09f7608c66 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -22,6 +22,11 @@ #include "sdhci-pltfm.h" +#define CORE_MCI_VERSION 0x50 +#define CORE_VERSION_MAJOR_SHIFT 28 +#define CORE_VERSION_MAJOR_MASK (0xf << CORE_VERSION_MAJOR_SHIFT) +#define CORE_VERSION_MINOR_MASK 0xff + #define CORE_HC_MODE 0x78 #define HC_MODE_EN 0x1 #define CORE_POWER 0x0 @@ -41,6 +46,8 @@ #define CORE_VENDOR_SPEC 0x10c #define CORE_CLK_PWRSAVE BIT(1) +#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c + #define CDR_SELEXT_SHIFT 20 #define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT) #define CMUX_SHIFT_PHASE_SHIFT 24 @@ -339,9 +346,7 @@ static int msm_init_cm_dll(struct sdhci_host *host) static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) { int tuning_seq_cnt = 3; - u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0; - const u8 *tuning_block_pattern = tuning_blk_pattern_4bit; - int size = sizeof(tuning_blk_pattern_4bit); + u8 phase, tuned_phases[16], tuned_phase_cnt = 0; int rc; struct mmc_host *mmc = host->mmc; struct mmc_ios ios = host->mmc->ios; @@ -355,53 +360,21 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) (ios.timing == MMC_TIMING_UHS_SDR104))) return 0; - if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) && - (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) { - tuning_block_pattern = tuning_blk_pattern_8bit; - size = sizeof(tuning_blk_pattern_8bit); - } - - data_buf = kmalloc(size, GFP_KERNEL); - if (!data_buf) - return -ENOMEM; - retry: /* First of all reset the tuning block */ rc = msm_init_cm_dll(host); if (rc) - goto out; + return rc; phase = 0; do { - struct mmc_command cmd = { 0 }; - struct mmc_data data = { 0 }; - struct mmc_request mrq = { - .cmd = &cmd, - .data = &data - }; - struct scatterlist sg; - /* Set the phase in delay line hw block */ rc = msm_config_cm_dll_phase(host, phase); if (rc) - goto out; - - cmd.opcode = opcode; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + return rc; - data.blksz = size; - data.blocks = 1; - data.flags = MMC_DATA_READ; - data.timeout_ns = NSEC_PER_SEC; /* 1 second */ - - data.sg = &sg; - data.sg_len = 1; - sg_init_one(&sg, data_buf, size); - memset(data_buf, 0, size); - mmc_wait_for_req(mmc, &mrq); - - if (!cmd.error && !data.error && - !memcmp(data_buf, tuning_block_pattern, size)) { + rc = mmc_send_tuning(mmc); + if (!rc) { /* Tuning is successful at this tuning point */ tuned_phases[tuned_phase_cnt++] = phase; dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", @@ -413,7 +386,7 @@ retry: rc = msm_find_most_appropriate_phase(host, tuned_phases, tuned_phase_cnt); if (rc < 0) - goto out; + return rc; else phase = rc; @@ -423,7 +396,7 @@ retry: */ rc = msm_config_cm_dll_phase(host, phase); if (rc) - goto out; + return rc; dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", mmc_hostname(mmc), phase); } else { @@ -435,8 +408,6 @@ retry: rc = -EIO; } -out: - kfree(data_buf); return rc; } @@ -462,7 +433,9 @@ static int sdhci_msm_probe(struct platform_device *pdev) struct sdhci_msm_host *msm_host; struct resource *core_memres; int ret; - u16 host_version; + u16 host_version, core_minor; + u32 core_version, caps; + u8 core_major; msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL); if (!msm_host) @@ -552,6 +525,24 @@ static int sdhci_msm_probe(struct platform_device *pdev) host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT)); + core_version = readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION); + core_major = (core_version & CORE_VERSION_MAJOR_MASK) >> + CORE_VERSION_MAJOR_SHIFT; + core_minor = core_version & CORE_VERSION_MINOR_MASK; + dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n", + core_version, core_major, core_minor); + + /* + * Support for some capabilities is not advertised by newer + * controller versions and must be explicitly enabled. + */ + if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) { + caps = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES); + caps |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT; + writel_relaxed(caps, host->ioaddr + + CORE_VENDOR_SPEC_CAPABILITIES0); + } + ret = sdhci_add_host(host); if (ret) goto clk_disable; diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 981d66e5c023..6287d426c96b 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -165,7 +165,6 @@ static int sdhci_arasan_probe(struct platform_device *pdev) host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, 0); if (IS_ERR(host)) { ret = PTR_ERR(host); - dev_err(&pdev->dev, "platform init failed (%u)\n", ret); goto clk_disable_all; } @@ -174,12 +173,16 @@ static int sdhci_arasan_probe(struct platform_device *pdev) pltfm_host->priv = sdhci_arasan; pltfm_host->clk = clk_xin; - ret = sdhci_add_host(host); + ret = mmc_of_parse(host->mmc); if (ret) { - dev_err(&pdev->dev, "platform register failed (%u)\n", ret); - goto err_pltfm_free; + dev_err(&pdev->dev, "parsing dt failed (%u)\n", ret); + goto clk_disable_all; } + ret = sdhci_add_host(host); + if (ret) + goto err_pltfm_free; + return 0; err_pltfm_free: @@ -198,7 +201,6 @@ static int sdhci_arasan_remove(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; - clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(sdhci_arasan->clk_ahb); return sdhci_pltfm_unregister(pdev); diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 8872c85c63d4..22e9111b11ff 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -276,6 +276,14 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) ESDHC_CTRL_BUSWIDTH_MASK, ctrl); } +static void esdhc_reset(struct sdhci_host *host, u8 mask) +{ + sdhci_reset(host, mask); + + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); +} + static const struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl, .read_w = esdhc_readw, @@ -290,7 +298,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = { .platform_init = esdhc_of_platform_init, .adma_workaround = esdhci_of_adma_workaround, .set_bus_width = esdhc_pltfm_set_bus_width, - .reset = sdhci_reset, + .reset = esdhc_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, }; @@ -362,21 +370,22 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) } /* call to generic mmc_of_parse to support additional capabilities */ - mmc_of_parse(host->mmc); + ret = mmc_of_parse(host->mmc); + if (ret) + goto err; + mmc_of_parse_voltage(np, &host->ocr_mask); ret = sdhci_add_host(host); if (ret) - sdhci_pltfm_free(pdev); + goto err; + return 0; + err: + sdhci_pltfm_free(pdev); return ret; } -static int sdhci_esdhc_remove(struct platform_device *pdev) -{ - return sdhci_pltfm_unregister(pdev); -} - static const struct of_device_id sdhci_esdhc_of_match[] = { { .compatible = "fsl,mpc8379-esdhc" }, { .compatible = "fsl,mpc8536-esdhc" }, @@ -392,7 +401,7 @@ static struct platform_driver sdhci_esdhc_driver = { .pm = ESDHC_PMOPS, }, .probe = sdhci_esdhc_probe, - .remove = sdhci_esdhc_remove, + .remove = sdhci_pltfm_unregister, }; module_platform_driver(sdhci_esdhc_driver); diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index be479279a1d5..4079a96ad37e 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -75,11 +75,6 @@ static int sdhci_hlwd_probe(struct platform_device *pdev) return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata, 0); } -static int sdhci_hlwd_remove(struct platform_device *pdev) -{ - return sdhci_pltfm_unregister(pdev); -} - static const struct of_device_id sdhci_hlwd_of_match[] = { { .compatible = "nintendo,hollywood-sdhci" }, { } @@ -93,7 +88,7 @@ static struct platform_driver sdhci_hlwd_driver = { .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_hlwd_probe, - .remove = sdhci_hlwd_remove, + .remove = sdhci_pltfm_unregister, }; module_platform_driver(sdhci_hlwd_driver); diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index 5670e381b0cf..e2ec108dba0e 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -127,8 +127,6 @@ void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) return; scratch_32 &= ~((1 << 21) | (1 << 30)); - /* Set RTD3 function disabled */ - scratch_32 |= ((1 << 29) | (1 << 28)); pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32); /* Set L1 Entrance Timer */ diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 61192973e7cb..7a3fc16d0a6c 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -134,7 +134,7 @@ static int pch_hc_probe_slot(struct sdhci_pci_slot *slot) return 0; } -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id) { @@ -269,7 +269,9 @@ static void sdhci_pci_int_hw_reset(struct sdhci_host *host) static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) { slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | - MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR; + MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | + MMC_CAP_BUS_WIDTH_TEST | + MMC_CAP_WAIT_WHILE_BUSY; slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ; slot->hw_reset = sdhci_pci_int_hw_reset; if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC) @@ -279,12 +281,16 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) static int byt_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_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | + MMC_CAP_BUS_WIDTH_TEST | + MMC_CAP_WAIT_WHILE_BUSY; return 0; } static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) { + slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST | + MMC_CAP_WAIT_WHILE_BUSY; slot->cd_con_id = NULL; slot->cd_idx = 0; slot->cd_override_level = true; @@ -294,11 +300,13 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { .allow_runtime_pm = true, .probe_slot = byt_emmc_probe_slot, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC, }; static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .allow_runtime_pm = true, @@ -306,6 +314,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { }; static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC, @@ -641,10 +650,30 @@ static int rtsx_probe_slot(struct sdhci_pci_slot *slot) static const struct sdhci_pci_fixes sdhci_rtsx = { .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_BROKEN_64_BIT_DMA | SDHCI_QUIRK2_BROKEN_DDR50, .probe_slot = rtsx_probe_slot, }; +static int amd_probe(struct sdhci_pci_chip *chip) +{ + struct pci_dev *smbus_dev; + + smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); + + if (smbus_dev && (smbus_dev->revision < 0x51)) { + chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD; + chip->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; + } + + return 0; +} + +static const struct sdhci_pci_fixes sdhci_amd = { + .probe = amd_probe, +}; + static const struct pci_device_id pci_ids[] = { { .vendor = PCI_VENDOR_ID_RICOH, @@ -965,6 +994,31 @@ static const struct pci_device_id pci_ids[] = { .subdevice = PCI_ANY_ID, .driver_data = (kernel_ulong_t)&sdhci_intel_mrfl_mmc, }, + + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_SPT_EMMC, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, + }, + + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_SPT_SDIO, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio, + }, + + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_SPT_SD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, + }, + { .vendor = PCI_VENDOR_ID_O2, .device = PCI_DEVICE_ID_O2_8120, @@ -1044,7 +1098,15 @@ static const struct pci_device_id pci_ids[] = { .subdevice = PCI_ANY_ID, .driver_data = (kernel_ulong_t)&sdhci_o2, }, - + { + .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_ANY_ID, + .class = PCI_CLASS_SYSTEM_SDHCI << 8, + .class_mask = 0xFFFF00, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_amd, + }, { /* Generic SD host controller */ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) }, @@ -1064,7 +1126,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host) { struct sdhci_pci_slot *slot; struct pci_dev *pdev; - int ret; + int ret = -1; slot = sdhci_priv(host); pdev = slot->chip->pdev; @@ -1076,7 +1138,17 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host) "doesn't fully claim to support it.\n"); } - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (host->flags & SDHCI_USE_64_BIT_DMA) { + if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) { + host->flags &= ~SDHCI_USE_64_BIT_DMA; + } else { + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (ret) + dev_warn(&pdev->dev, "Failed to set 64-bit DMA mask\n"); + } + } + if (ret) + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) return ret; @@ -1230,15 +1302,6 @@ static int sdhci_pci_resume(struct device *dev) return 0; } -#else /* CONFIG_PM */ - -#define sdhci_pci_suspend NULL -#define sdhci_pci_resume NULL - -#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); @@ -1305,18 +1368,18 @@ static int sdhci_pci_runtime_resume(struct device *dev) return 0; } -static int sdhci_pci_runtime_idle(struct device *dev) -{ - return 0; -} +#else /* CONFIG_PM */ -#endif +#define sdhci_pci_suspend NULL +#define sdhci_pci_resume NULL + +#endif /* CONFIG_PM */ static const struct dev_pm_ops sdhci_pci_pm_ops = { .suspend = sdhci_pci_suspend, .resume = sdhci_pci_resume, SET_RUNTIME_PM_OPS(sdhci_pci_runtime_suspend, - sdhci_pci_runtime_resume, sdhci_pci_runtime_idle) + sdhci_pci_runtime_resume, NULL) }; /*****************************************************************************\ diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index d57c3d169914..1ec684d06d54 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -21,6 +21,9 @@ #define PCI_DEVICE_ID_INTEL_CLV_EMMC0 0x08e5 #define PCI_DEVICE_ID_INTEL_CLV_EMMC1 0x08e6 #define PCI_DEVICE_ID_INTEL_QRK_SD 0x08A7 +#define PCI_DEVICE_ID_INTEL_SPT_EMMC 0x9d2b +#define PCI_DEVICE_ID_INTEL_SPT_SDIO 0x9d2c +#define PCI_DEVICE_ID_INTEL_SPT_SD 0x9d2d /* * PCI registers diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index c5b01d6bb85d..a207f5aaf62f 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -75,43 +75,41 @@ void sdhci_get_of_property(struct platform_device *pdev) 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,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)) - host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; + if (of_get_property(np, "sdhci,1-bit-only", NULL) || + (of_property_read_u32(np, "bus-width", &bus_width) == 0 && + bus_width == 1)) + host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; - if (sdhci_of_wp_inverted(np)) - host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; + 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, "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_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-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,t4240-esdhc") || - of_device_is_compatible(np, "fsl,mpc8536-esdhc")) - host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; + if (of_device_is_compatible(np, "fsl,p2020-esdhc") || + of_device_is_compatible(np, "fsl,p1010-esdhc") || + of_device_is_compatible(np, "fsl,t4240-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); + 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, "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; - } + if (of_find_property(np, "enable-sdio-wakeup", NULL)) + host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; } #else void sdhci_get_of_property(struct platform_device *pdev) {} @@ -225,9 +223,11 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_register); int sdhci_pltfm_unregister(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); sdhci_remove_host(host, dead); + clk_disable_unprepare(pltfm_host->clk); sdhci_pltfm_free(pdev); return 0; diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index b4c23e983baf..f98008b5ea77 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -167,23 +167,17 @@ static int sdhci_pxav2_probe(struct platform_device *pdev) 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; - pxa = kzalloc(sizeof(struct sdhci_pxa), GFP_KERNEL); - if (!pxa) - return -ENOMEM; - host = sdhci_pltfm_init(pdev, NULL, 0); - if (IS_ERR(host)) { - kfree(pxa); + if (IS_ERR(host)) return PTR_ERR(host); - } + pltfm_host = sdhci_priv(host); - pltfm_host->priv = pxa; + pltfm_host->priv = NULL; clk = clk_get(dev, "PXA-SDHCLK"); if (IS_ERR(clk)) { @@ -238,7 +232,6 @@ err_add_host: clk_put(clk); err_clk_get: sdhci_pltfm_free(pdev); - kfree(pxa); return ret; } @@ -246,14 +239,12 @@ static int sdhci_pxav2_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; sdhci_remove_host(host, 1); clk_disable_unprepare(pltfm_host->clk); clk_put(pltfm_host->clk); sdhci_pltfm_free(pdev); - kfree(pxa); return 0; } diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 5036d7d39529..b5103a247bc1 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -58,6 +58,13 @@ #define SDCE_MISC_INT (1<<2) #define SDCE_MISC_INT_EN (1<<1) +struct sdhci_pxa { + struct clk *clk_core; + struct clk *clk_io; + u8 power_mode; + void __iomem *sdio3_conf_reg; +}; + /* * These registers are relative to the second register region, for the * MBus bridge. @@ -66,6 +73,14 @@ #define SDHCI_WINDOW_BASE(i) (0x84 + ((i) << 3)) #define SDHCI_MAX_WIN_NUM 8 +/* + * Fields below belong to SDIO3 Configuration Register (third register + * region for the Armada 38x flavor) + */ + +#define SDIO3_CONF_CLK_INV BIT(0) +#define SDIO3_CONF_SD_FB_CLK BIT(2) + static int mv_conf_mbus_windows(struct platform_device *pdev, const struct mbus_dram_target_info *dram) { @@ -112,6 +127,51 @@ static int mv_conf_mbus_windows(struct platform_device *pdev, return 0; } +static int armada_38x_quirks(struct platform_device *pdev, + struct sdhci_host *host) +{ + struct device_node *np = pdev->dev.of_node; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; + struct resource *res; + + host->quirks |= SDHCI_QUIRK_MISSING_CAPS; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "conf-sdio3"); + if (res) { + pxa->sdio3_conf_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pxa->sdio3_conf_reg)) + return PTR_ERR(pxa->sdio3_conf_reg); + } else { + /* + * According to erratum 'FE-2946959' both SDR50 and DDR50 + * modes require specific clock adjustments in SDIO3 + * Configuration register, if the adjustment is not done, + * remove them from the capabilities. + */ + host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); + host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); + + dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.\nConsider updating your dtb\n"); + } + + /* + * According to erratum 'ERR-7878951' Armada 38x SDHCI + * controller has different capabilities than the ones shown + * in its registers + */ + host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); + if (of_property_read_bool(np, "no-1-8-v")) { + host->caps &= ~SDHCI_CAN_VDD_180; + host->mmc->caps &= ~MMC_CAP_1_8V_DDR; + } else { + host->caps &= ~SDHCI_CAN_VDD_330; + } + host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_USE_SDR50_TUNING); + + return 0; +} + static void pxav3_reset(struct sdhci_host *host, u8 mask) { struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); @@ -188,6 +248,8 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; u16 ctrl_2; /* @@ -211,11 +273,30 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) case MMC_TIMING_UHS_SDR104: ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; break; + case MMC_TIMING_MMC_DDR52: case MMC_TIMING_UHS_DDR50: ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; break; } + /* + * Update SDIO3 Configuration register according to erratum + * FE-2946959 + */ + if (pxa->sdio3_conf_reg) { + u8 reg_val = readb(pxa->sdio3_conf_reg); + + if (uhs == MMC_TIMING_UHS_SDR50 || + uhs == MMC_TIMING_UHS_DDR50) { + reg_val &= ~SDIO3_CONF_CLK_INV; + reg_val |= SDIO3_CONF_SD_FB_CLK; + } else { + reg_val |= SDIO3_CONF_CLK_INV; + reg_val &= ~SDIO3_CONF_SD_FB_CLK; + } + writeb(reg_val, pxa->sdio3_conf_reg); + } + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); dev_dbg(mmc_dev(host->mmc), "%s uhs = %d, ctrl_2 = %04X\n", @@ -261,8 +342,8 @@ static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) if (!pdata) return NULL; - of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles); - if (clk_delay_cycles > 0) + if (!of_property_read_u32(np, "mrvl,clk-delay-cycles", + &clk_delay_cycles)) pdata->clk_delay_cycles = clk_delay_cycles; return pdata; @@ -283,9 +364,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) struct sdhci_host *host = NULL; struct sdhci_pxa *pxa = NULL; const struct of_device_id *match; - int ret; - struct clk *clk; pxa = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_pxa), GFP_KERNEL); if (!pxa) @@ -295,28 +374,36 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) if (IS_ERR(host)) return PTR_ERR(host); - if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) { - ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info()); - if (ret < 0) - goto err_mbus_win; - } - - pltfm_host = sdhci_priv(host); pltfm_host->priv = pxa; - clk = devm_clk_get(dev, NULL); - if (IS_ERR(clk)) { + pxa->clk_io = devm_clk_get(dev, "io"); + if (IS_ERR(pxa->clk_io)) + pxa->clk_io = devm_clk_get(dev, NULL); + if (IS_ERR(pxa->clk_io)) { dev_err(dev, "failed to get io clock\n"); - ret = PTR_ERR(clk); + ret = PTR_ERR(pxa->clk_io); goto err_clk_get; } - pltfm_host->clk = clk; - clk_prepare_enable(clk); + pltfm_host->clk = pxa->clk_io; + clk_prepare_enable(pxa->clk_io); + + pxa->clk_core = devm_clk_get(dev, "core"); + if (!IS_ERR(pxa->clk_core)) + clk_prepare_enable(pxa->clk_core); /* enable 1/8V DDR capable */ host->mmc->caps |= MMC_CAP_1_8V_DDR; + if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) { + ret = armada_38x_quirks(pdev, host); + if (ret < 0) + goto err_clk_get; + ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info()); + if (ret < 0) + goto err_mbus_win; + } + match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev); if (match) { ret = mmc_of_parse(host->mmc); @@ -355,10 +442,11 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) } } - pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, 1); ret = sdhci_add_host(host); @@ -381,13 +469,14 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) return 0; err_add_host: - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); err_of_parse: err_cd_req: - clk_disable_unprepare(clk); -err_clk_get: err_mbus_win: + clk_disable_unprepare(pxa->clk_io); + clk_disable_unprepare(pxa->clk_core); +err_clk_get: sdhci_pltfm_free(pdev); return ret; } @@ -396,12 +485,16 @@ static int 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; pm_runtime_get_sync(&pdev->dev); - sdhci_remove_host(host, 1); pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + sdhci_remove_host(host, 1); - clk_disable_unprepare(pltfm_host->clk); + clk_disable_unprepare(pxa->clk_io); + clk_disable_unprepare(pxa->clk_core); sdhci_pltfm_free(pdev); @@ -436,20 +529,21 @@ static int sdhci_pxav3_resume(struct device *dev) } #endif -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int sdhci_pxav3_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - unsigned long flags; + struct sdhci_pxa *pxa = pltfm_host->priv; + int ret; - if (pltfm_host->clk) { - spin_lock_irqsave(&host->lock, flags); - host->runtime_suspended = true; - spin_unlock_irqrestore(&host->lock, flags); + ret = sdhci_runtime_suspend_host(host); + if (ret) + return ret; - clk_disable_unprepare(pltfm_host->clk); - } + clk_disable_unprepare(pxa->clk_io); + if (!IS_ERR(pxa->clk_core)) + clk_disable_unprepare(pxa->clk_core); return 0; } @@ -458,17 +552,13 @@ static int sdhci_pxav3_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - unsigned long flags; - - if (pltfm_host->clk) { - clk_prepare_enable(pltfm_host->clk); + struct sdhci_pxa *pxa = pltfm_host->priv; - spin_lock_irqsave(&host->lock, flags); - host->runtime_suspended = false; - spin_unlock_irqrestore(&host->lock, flags); - } + clk_prepare_enable(pxa->clk_io); + if (!IS_ERR(pxa->clk_core)) + clk_prepare_enable(pxa->clk_core); - return 0; + return sdhci_runtime_resume_host(host); } #endif diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 0ce6eb17deaf..c6d2dd7317c1 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. */ +#include <linux/spinlock.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> @@ -300,6 +301,7 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) struct device *dev = &ourhost->pdev->dev; unsigned long timeout; u16 clk = 0; + int ret; host->mmc->actual_clock = 0; @@ -311,7 +313,19 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_s3c_set_clock(host, clock); - clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); + /* Reset SD Clock Enable */ + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + spin_unlock_irq(&host->lock); + ret = clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); + spin_lock_irq(&host->lock); + if (ret != 0) { + dev_err(dev, "%s: failed to set clock rate %uHz\n", + mmc_hostname(host->mmc), clock); + return; + } clk = SDHCI_CLOCK_INT_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); @@ -601,7 +615,9 @@ static int sdhci_s3c_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, 1); - mmc_of_parse(host->mmc); + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_req_regs; ret = sdhci_add_host(host); if (ret) { @@ -609,7 +625,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) goto err_req_regs; } -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) clk_disable_unprepare(sc->clk_io); #endif @@ -635,7 +651,7 @@ 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 +#ifdef CONFIG_PM if (sc->pdata->cd_type != S3C_SDHCI_CD_INTERNAL) clk_prepare_enable(sc->clk_io); #endif @@ -667,7 +683,7 @@ static int sdhci_s3c_resume(struct device *dev) } #endif -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int sdhci_s3c_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c index dd29d47c07aa..32848eb7ad80 100644 --- a/drivers/mmc/host/sdhci-sirf.c +++ b/drivers/mmc/host/sdhci-sirf.c @@ -15,20 +15,14 @@ #include <linux/mmc/slot-gpio.h> #include "sdhci-pltfm.h" +#define SDHCI_CLK_DELAY_SETTING 0x4C #define SDHCI_SIRF_8BITBUS BIT(3) +#define SIRF_TUNING_COUNT 128 struct sdhci_sirf_priv { - struct clk *clk; int gpio_cd; }; -static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host); - return clk_get_rate(priv->clk); -} - static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width) { u8 ctrl; @@ -49,9 +43,78 @@ static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } +static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + int tuning_seq_cnt = 3; + u8 phase, tuned_phases[SIRF_TUNING_COUNT]; + u8 tuned_phase_cnt = 0; + int rc = 0, longest_range = 0; + int start = -1, end = 0, tuning_value = -1, range = 0; + u16 clock_setting; + struct mmc_host *mmc = host->mmc; + + clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING); + clock_setting &= ~0x3fff; + +retry: + phase = 0; + do { + sdhci_writel(host, + clock_setting | phase, + SDHCI_CLK_DELAY_SETTING); + + if (!mmc_send_tuning(mmc)) { + /* Tuning is successful at this tuning point */ + tuned_phases[tuned_phase_cnt++] = phase; + dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", + mmc_hostname(mmc), phase); + if (start == -1) + start = phase; + end = phase; + range++; + if (phase == (SIRF_TUNING_COUNT - 1) + && range > longest_range) + tuning_value = (start + end) / 2; + } else { + dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n", + mmc_hostname(mmc), phase); + if (range > longest_range) { + tuning_value = (start + end) / 2; + longest_range = range; + } + start = -1; + end = range = 0; + } + } while (++phase < ARRAY_SIZE(tuned_phases)); + + if (tuned_phase_cnt && tuning_value > 0) { + /* + * Finally set the selected phase in delay + * line hw block. + */ + phase = tuning_value; + sdhci_writel(host, + clock_setting | phase, + SDHCI_CLK_DELAY_SETTING); + + dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", + mmc_hostname(mmc), phase); + } else { + if (--tuning_seq_cnt) + goto retry; + /* Tuning failed */ + dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", + mmc_hostname(mmc)); + rc = -EIO; + } + + return rc; +} + static struct sdhci_ops sdhci_sirf_ops = { + .platform_execute_tuning = sdhci_sirf_execute_tuning, .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_sirf_get_max_clk, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, .set_bus_width = sdhci_sirf_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, @@ -91,13 +154,13 @@ static int sdhci_sirf_probe(struct platform_device *pdev) return PTR_ERR(host); pltfm_host = sdhci_priv(host); + pltfm_host->clk = clk; priv = sdhci_pltfm_priv(pltfm_host); - priv->clk = clk; priv->gpio_cd = gpio_cd; sdhci_get_of_property(pdev); - ret = clk_prepare_enable(priv->clk); + ret = clk_prepare_enable(pltfm_host->clk); if (ret) goto err_clk_prepare; @@ -124,40 +187,24 @@ static int sdhci_sirf_probe(struct platform_device *pdev) err_request_cd: sdhci_remove_host(host, 0); err_sdhci_add: - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(pltfm_host->clk); err_clk_prepare: sdhci_pltfm_free(pdev); return ret; } -static int sdhci_sirf_remove(struct platform_device *pdev) -{ - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host); - - sdhci_pltfm_unregister(pdev); - - if (gpio_is_valid(priv->gpio_cd)) - mmc_gpio_free_cd(host->mmc); - - clk_disable_unprepare(priv->clk); - return 0; -} - #ifdef CONFIG_PM_SLEEP static int sdhci_sirf_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host); int ret; ret = sdhci_suspend_host(host); if (ret) return ret; - clk_disable(priv->clk); + clk_disable(pltfm_host->clk); return 0; } @@ -166,10 +213,9 @@ static int sdhci_sirf_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host); int ret; - ret = clk_enable(priv->clk); + ret = clk_enable(pltfm_host->clk); if (ret) { dev_dbg(dev, "Resume: Error enabling clock\n"); return ret; @@ -196,7 +242,7 @@ static struct platform_driver sdhci_sirf_driver = { #endif }, .probe = sdhci_sirf_probe, - .remove = sdhci_sirf_remove, + .remove = sdhci_pltfm_unregister, }; module_platform_driver(sdhci_sirf_driver); diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 22e58268545f..df088343d60f 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -26,14 +26,13 @@ #include <linux/pm.h> #include <linux/slab.h> #include <linux/mmc/host.h> -#include <linux/mmc/sdhci-spear.h> #include <linux/mmc/slot-gpio.h> #include <linux/io.h> #include "sdhci.h" struct spear_sdhci { struct clk *clk; - struct sdhci_plat_data *data; + int card_int_gpio; }; /* sdhci ops */ @@ -44,38 +43,20 @@ static const struct sdhci_ops sdhci_pltfm_ops = { .set_uhs_signaling = sdhci_set_uhs_signaling, }; -#ifdef CONFIG_OF -static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) +static void sdhci_probe_config_dt(struct device_node *np, + struct spear_sdhci *host) { - 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"); - else - 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); + host->card_int_gpio = cd_gpio; } -#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; @@ -124,28 +105,18 @@ static int sdhci_probe(struct platform_device *pdev) 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"); - goto disable_clk; - } - } else { - sdhci->data = dev_get_platdata(&pdev->dev); - } - + sdhci_probe_config_dt(pdev->dev.of_node, sdhci); /* * It is optional to use GPIOs for sdhci card detection. If - * sdhci->data is NULL, then use original sdhci lines otherwise + * sdhci->card_int_gpio < 0, then use original sdhci lines otherwise * GPIO lines. We use the built-in GPIO support for this. */ - if (sdhci->data && sdhci->data->card_int_gpio >= 0) { - ret = mmc_gpio_request_cd(host->mmc, - sdhci->data->card_int_gpio, 0); + if (sdhci->card_int_gpio >= 0) { + ret = mmc_gpio_request_cd(host->mmc, sdhci->card_int_gpio, 0); if (ret < 0) { dev_dbg(&pdev->dev, "failed to request card-detect gpio%d\n", - sdhci->data->card_int_gpio); + sdhci->card_int_gpio); goto disable_clk; } } diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c index 328f348c7243..682f2bb0f4bf 100644 --- a/drivers/mmc/host/sdhci-st.c +++ b/drivers/mmc/host/sdhci-st.c @@ -23,9 +23,295 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/mmc/host.h> - +#include <linux/reset.h> #include "sdhci-pltfm.h" +struct st_mmc_platform_data { + struct reset_control *rstc; + void __iomem *top_ioaddr; +}; + +/* MMCSS glue logic to setup the HC on some ST SoCs (e.g. STiH407 family) */ + +#define ST_MMC_CCONFIG_REG_1 0x400 +#define ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT BIT(24) +#define ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ BIT(12) +#define ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT BIT(8) +#define ST_MMC_CCONFIG_ASYNC_WAKEUP BIT(0) +#define ST_MMC_CCONFIG_1_DEFAULT \ + ((ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT) | \ + (ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ) | \ + (ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT)) + +#define ST_MMC_CCONFIG_REG_2 0x404 +#define ST_MMC_CCONFIG_HIGH_SPEED BIT(28) +#define ST_MMC_CCONFIG_ADMA2 BIT(24) +#define ST_MMC_CCONFIG_8BIT BIT(20) +#define ST_MMC_CCONFIG_MAX_BLK_LEN 16 +#define MAX_BLK_LEN_1024 1 +#define MAX_BLK_LEN_2048 2 +#define BASE_CLK_FREQ_200 0xc8 +#define BASE_CLK_FREQ_100 0x64 +#define BASE_CLK_FREQ_50 0x32 +#define ST_MMC_CCONFIG_2_DEFAULT \ + (ST_MMC_CCONFIG_HIGH_SPEED | ST_MMC_CCONFIG_ADMA2 | \ + ST_MMC_CCONFIG_8BIT | \ + (MAX_BLK_LEN_1024 << ST_MMC_CCONFIG_MAX_BLK_LEN)) + +#define ST_MMC_CCONFIG_REG_3 0x408 +#define ST_MMC_CCONFIG_EMMC_SLOT_TYPE BIT(28) +#define ST_MMC_CCONFIG_64BIT BIT(24) +#define ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT BIT(20) +#define ST_MMC_CCONFIG_1P8_VOLT BIT(16) +#define ST_MMC_CCONFIG_3P0_VOLT BIT(12) +#define ST_MMC_CCONFIG_3P3_VOLT BIT(8) +#define ST_MMC_CCONFIG_SUSP_RES_SUPPORT BIT(4) +#define ST_MMC_CCONFIG_SDMA BIT(0) +#define ST_MMC_CCONFIG_3_DEFAULT \ + (ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT | \ + ST_MMC_CCONFIG_3P3_VOLT | \ + ST_MMC_CCONFIG_SUSP_RES_SUPPORT | \ + ST_MMC_CCONFIG_SDMA) + +#define ST_MMC_CCONFIG_REG_4 0x40c +#define ST_MMC_CCONFIG_D_DRIVER BIT(20) +#define ST_MMC_CCONFIG_C_DRIVER BIT(16) +#define ST_MMC_CCONFIG_A_DRIVER BIT(12) +#define ST_MMC_CCONFIG_DDR50 BIT(8) +#define ST_MMC_CCONFIG_SDR104 BIT(4) +#define ST_MMC_CCONFIG_SDR50 BIT(0) +#define ST_MMC_CCONFIG_4_DEFAULT 0 + +#define ST_MMC_CCONFIG_REG_5 0x410 +#define ST_MMC_CCONFIG_TUNING_FOR_SDR50 BIT(8) +#define RETUNING_TIMER_CNT_MAX 0xf +#define ST_MMC_CCONFIG_5_DEFAULT 0 + +/* I/O configuration for Arasan IP */ +#define ST_MMC_GP_OUTPUT 0x450 +#define ST_MMC_GP_OUTPUT_CD BIT(12) + +#define ST_MMC_STATUS_R 0x460 + +#define ST_TOP_MMC_DLY_FIX_OFF(x) (x - 0x8) + +/* TOP config registers to manage static and dynamic delay */ +#define ST_TOP_MMC_TX_CLK_DLY ST_TOP_MMC_DLY_FIX_OFF(0x8) +#define ST_TOP_MMC_RX_CLK_DLY ST_TOP_MMC_DLY_FIX_OFF(0xc) +/* MMC delay control register */ +#define ST_TOP_MMC_DLY_CTRL ST_TOP_MMC_DLY_FIX_OFF(0x18) +#define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_CMD BIT(0) +#define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_PH_SEL BIT(1) +#define ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE BIT(8) +#define ST_TOP_MMC_DLY_CTRL_RX_DLL_ENABLE BIT(9) +#define ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY BIT(10) +#define ST_TOP_MMC_START_DLL_LOCK BIT(11) + +/* register to provide the phase-shift value for DLL */ +#define ST_TOP_MMC_TX_DLL_STEP_DLY ST_TOP_MMC_DLY_FIX_OFF(0x1c) +#define ST_TOP_MMC_RX_DLL_STEP_DLY ST_TOP_MMC_DLY_FIX_OFF(0x20) +#define ST_TOP_MMC_RX_CMD_STEP_DLY ST_TOP_MMC_DLY_FIX_OFF(0x24) + +/* phase shift delay on the tx clk 2.188ns */ +#define ST_TOP_MMC_TX_DLL_STEP_DLY_VALID 0x6 + +#define ST_TOP_MMC_DLY_MAX 0xf + +#define ST_TOP_MMC_DYN_DLY_CONF \ + (ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE | \ + ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY | \ + ST_TOP_MMC_START_DLL_LOCK) + +/* + * For clock speeds greater than 90MHz, we need to check that the + * DLL procedure has finished before switching to ultra-speed modes. + */ +#define CLK_TO_CHECK_DLL_LOCK 90000000 + +static inline void st_mmcss_set_static_delay(void __iomem *ioaddr) +{ + if (!ioaddr) + return; + + writel_relaxed(0x0, ioaddr + ST_TOP_MMC_DLY_CTRL); + writel_relaxed(ST_TOP_MMC_DLY_MAX, + ioaddr + ST_TOP_MMC_TX_CLK_DLY); +} + +/** + * st_mmcss_cconfig: configure the Arasan HC inside the flashSS. + * @np: dt device node. + * @host: sdhci host + * Description: this function is to configure the Arasan host controller. + * On some ST SoCs, i.e. STiH407 family, the MMC devices inside a dedicated + * flashSS sub-system which needs to be configured to be compliant to eMMC 4.5 + * or eMMC4.3. This has to be done before registering the sdhci host. + */ +static void st_mmcss_cconfig(struct device_node *np, struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct mmc_host *mhost = host->mmc; + u32 cconf2, cconf3, cconf4, cconf5; + + if (!of_device_is_compatible(np, "st,sdhci-stih407")) + return; + + cconf2 = ST_MMC_CCONFIG_2_DEFAULT; + cconf3 = ST_MMC_CCONFIG_3_DEFAULT; + cconf4 = ST_MMC_CCONFIG_4_DEFAULT; + cconf5 = ST_MMC_CCONFIG_5_DEFAULT; + + writel_relaxed(ST_MMC_CCONFIG_1_DEFAULT, + host->ioaddr + ST_MMC_CCONFIG_REG_1); + + /* Set clock frequency, default to 50MHz if max-frequency is not + * provided */ + + switch (mhost->f_max) { + case 200000000: + clk_set_rate(pltfm_host->clk, mhost->f_max); + cconf2 |= BASE_CLK_FREQ_200; + break; + case 100000000: + clk_set_rate(pltfm_host->clk, mhost->f_max); + cconf2 |= BASE_CLK_FREQ_100; + break; + default: + clk_set_rate(pltfm_host->clk, 50000000); + cconf2 |= BASE_CLK_FREQ_50; + } + + writel_relaxed(cconf2, host->ioaddr + ST_MMC_CCONFIG_REG_2); + + if (mhost->caps & MMC_CAP_NONREMOVABLE) + cconf3 |= ST_MMC_CCONFIG_EMMC_SLOT_TYPE; + else + /* CARD _D ET_CTRL */ + writel_relaxed(ST_MMC_GP_OUTPUT_CD, + host->ioaddr + ST_MMC_GP_OUTPUT); + + if (mhost->caps & MMC_CAP_UHS_SDR50) { + /* use 1.8V */ + cconf3 |= ST_MMC_CCONFIG_1P8_VOLT; + cconf4 |= ST_MMC_CCONFIG_SDR50; + /* Use tuning */ + cconf5 |= ST_MMC_CCONFIG_TUNING_FOR_SDR50; + /* Max timeout for retuning */ + cconf5 |= RETUNING_TIMER_CNT_MAX; + } + + if (mhost->caps & MMC_CAP_UHS_SDR104) { + /* + * SDR104 implies the HC can support HS200 mode, so + * it's mandatory to use 1.8V + */ + cconf3 |= ST_MMC_CCONFIG_1P8_VOLT; + cconf4 |= ST_MMC_CCONFIG_SDR104; + /* Max timeout for retuning */ + cconf5 |= RETUNING_TIMER_CNT_MAX; + } + + if (mhost->caps & MMC_CAP_UHS_DDR50) + cconf4 |= ST_MMC_CCONFIG_DDR50; + + writel_relaxed(cconf3, host->ioaddr + ST_MMC_CCONFIG_REG_3); + writel_relaxed(cconf4, host->ioaddr + ST_MMC_CCONFIG_REG_4); + writel_relaxed(cconf5, host->ioaddr + ST_MMC_CCONFIG_REG_5); +} + +static inline void st_mmcss_set_dll(void __iomem *ioaddr) +{ + if (!ioaddr) + return; + + writel_relaxed(ST_TOP_MMC_DYN_DLY_CONF, ioaddr + ST_TOP_MMC_DLY_CTRL); + writel_relaxed(ST_TOP_MMC_TX_DLL_STEP_DLY_VALID, + ioaddr + ST_TOP_MMC_TX_DLL_STEP_DLY); +} + +static int st_mmcss_lock_dll(void __iomem *ioaddr) +{ + unsigned long curr, value; + unsigned long finish = jiffies + HZ; + + /* Checks if the DLL procedure is finished */ + do { + curr = jiffies; + value = readl(ioaddr + ST_MMC_STATUS_R); + if (value & 0x1) + return 0; + + cpu_relax(); + } while (!time_after_eq(curr, finish)); + + return -EBUSY; +} + +static int sdhci_st_set_dll_for_clock(struct sdhci_host *host) +{ + int ret = 0; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct st_mmc_platform_data *pdata = pltfm_host->priv; + + if (host->clock > CLK_TO_CHECK_DLL_LOCK) { + st_mmcss_set_dll(pdata->top_ioaddr); + ret = st_mmcss_lock_dll(host->ioaddr); + } + + return ret; +} + +static void sdhci_st_set_uhs_signaling(struct sdhci_host *host, + unsigned int uhs) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct st_mmc_platform_data *pdata = pltfm_host->priv; + u16 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + int ret = 0; + + /* Select Bus Speed Mode for host */ + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + switch (uhs) { + /* + * Set V18_EN -- UHS modes do not work without this. + * does not change signaling voltage + */ + + case MMC_TIMING_UHS_SDR12: + st_mmcss_set_static_delay(pdata->top_ioaddr); + ctrl_2 |= SDHCI_CTRL_UHS_SDR12 | SDHCI_CTRL_VDD_180; + break; + case MMC_TIMING_UHS_SDR25: + st_mmcss_set_static_delay(pdata->top_ioaddr); + ctrl_2 |= SDHCI_CTRL_UHS_SDR25 | SDHCI_CTRL_VDD_180; + break; + case MMC_TIMING_UHS_SDR50: + st_mmcss_set_static_delay(pdata->top_ioaddr); + ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; + ret = sdhci_st_set_dll_for_clock(host); + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + st_mmcss_set_static_delay(pdata->top_ioaddr); + ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; + ret = sdhci_st_set_dll_for_clock(host); + break; + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + st_mmcss_set_static_delay(pdata->top_ioaddr); + ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; + break; + } + + if (ret) + dev_warn(mmc_dev(host->mmc), "Error setting dll for clock " + "(uhs %d)\n", uhs); + + dev_dbg(mmc_dev(host->mmc), "uhs %d, ctrl_2 %04X\n", uhs, ctrl_2); + + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); +} + static u32 sdhci_st_readl(struct sdhci_host *host, int reg) { u32 ret; @@ -48,22 +334,33 @@ static const struct sdhci_ops sdhci_st_ops = { .set_bus_width = sdhci_set_bus_width, .read_l = sdhci_st_readl, .reset = sdhci_reset, + .set_uhs_signaling = sdhci_st_set_uhs_signaling, }; static const struct sdhci_pltfm_data sdhci_st_pdata = { .ops = &sdhci_st_ops, .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | - SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_NO_HISPD_BIT, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_STOP_WITH_TC, }; static int sdhci_st_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct sdhci_host *host; + struct st_mmc_platform_data *pdata; struct sdhci_pltfm_host *pltfm_host; struct clk *clk; int ret = 0; u16 host_version; + struct resource *res; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; clk = devm_clk_get(&pdev->dev, "mmc"); if (IS_ERR(clk)) { @@ -71,24 +368,43 @@ static int sdhci_st_probe(struct platform_device *pdev) return PTR_ERR(clk); } + pdata->rstc = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(pdata->rstc)) + pdata->rstc = NULL; + else + reset_control_deassert(pdata->rstc); + host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, 0); if (IS_ERR(host)) { dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n"); - return PTR_ERR(host); + ret = PTR_ERR(host); + goto err_pltfm_init; } ret = mmc_of_parse(host->mmc); - if (ret) { dev_err(&pdev->dev, "Failed mmc_of_parse\n"); - return ret; + goto err_of; } clk_prepare_enable(clk); + /* Configure the FlashSS Top registers for setting eMMC TX/RX delay */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "top-mmc-delay"); + pdata->top_ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pdata->top_ioaddr)) { + dev_warn(&pdev->dev, "FlashSS Top Dly registers not available"); + pdata->top_ioaddr = NULL; + } + pltfm_host = sdhci_priv(host); + pltfm_host->priv = pdata; pltfm_host->clk = clk; + /* Configure the Arasan HC inside the flashSS */ + st_mmcss_cconfig(np, host); + ret = sdhci_add_host(host); if (ret) { dev_err(&pdev->dev, "Failed sdhci_add_host\n"); @@ -108,7 +424,11 @@ static int sdhci_st_probe(struct platform_device *pdev) err_out: clk_disable_unprepare(clk); +err_of: sdhci_pltfm_free(pdev); +err_pltfm_init: + if (pdata->rstc) + reset_control_assert(pdata->rstc); return ret; } @@ -117,10 +437,15 @@ static int sdhci_st_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct st_mmc_platform_data *pdata = pltfm_host->priv; + int ret; - clk_disable_unprepare(pltfm_host->clk); + ret = sdhci_pltfm_unregister(pdev); + + if (pdata->rstc) + reset_control_assert(pdata->rstc); - return sdhci_pltfm_unregister(pdev); + return ret; } #ifdef CONFIG_PM_SLEEP @@ -128,11 +453,15 @@ static int sdhci_st_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct st_mmc_platform_data *pdata = pltfm_host->priv; int ret = sdhci_suspend_host(host); if (ret) goto out; + if (pdata->rstc) + reset_control_assert(pdata->rstc); + clk_disable_unprepare(pltfm_host->clk); out: return ret; @@ -142,9 +471,16 @@ static int sdhci_st_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct st_mmc_platform_data *pdata = pltfm_host->priv; + struct device_node *np = dev->of_node; clk_prepare_enable(pltfm_host->clk); + if (pdata->rstc) + reset_control_deassert(pdata->rstc); + + st_mmcss_cconfig(np, host); + return sdhci_resume_host(host); } #endif diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 59797106af93..ad28b49f0203 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -20,11 +20,10 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> -#include <linux/gpio.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> #include <linux/mmc/slot-gpio.h> +#include <linux/gpio/consumer.h> #include "sdhci-pltfm.h" @@ -49,7 +48,7 @@ struct sdhci_tegra_soc_data { struct sdhci_tegra { const struct sdhci_tegra_soc_data *soc_data; - int power_gpio; + struct gpio_desc *power_gpio; }; static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) @@ -67,6 +66,27 @@ static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) return readw(host->ioaddr + reg); } +static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + switch (reg) { + case SDHCI_TRANSFER_MODE: + /* + * Postpone this write, we must do it together with a + * command write that is down below. + */ + pltfm_host->xfer_mode_shadow = val; + return; + case SDHCI_COMMAND: + writel((val << 16) | pltfm_host->xfer_mode_shadow, + host->ioaddr + SDHCI_TRANSFER_MODE); + return; + } + + writew(val, 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); @@ -187,6 +207,18 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = { NVQUIRK_DISABLE_SDR104, }; +static const struct sdhci_ops tegra114_sdhci_ops = { + .get_ro = tegra_sdhci_get_ro, + .read_w = tegra_sdhci_readw, + .write_w = tegra_sdhci_writew, + .write_l = tegra_sdhci_writel, + .set_clock = sdhci_set_clock, + .set_bus_width = tegra_sdhci_set_bus_width, + .reset = tegra_sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, +}; + static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | @@ -194,7 +226,7 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, - .ops = &tegra_sdhci_ops, + .ops = &tegra114_sdhci_ops, }; static struct sdhci_tegra_soc_data soc_data_tegra114 = { @@ -213,17 +245,6 @@ static const struct of_device_id sdhci_tegra_dt_match[] = { }; MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match); -static int sdhci_tegra_parse_dt(struct device *dev) -{ - struct device_node *np = dev->of_node; - struct sdhci_host *host = dev_get_drvdata(dev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - - tegra_host->power_gpio = of_get_named_gpio(np, "power-gpios", 0); - return mmc_of_parse(host->mmc); -} - static int sdhci_tegra_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -253,21 +274,18 @@ static int sdhci_tegra_probe(struct platform_device *pdev) tegra_host->soc_data = soc_data; pltfm_host->priv = tegra_host; - rc = sdhci_tegra_parse_dt(&pdev->dev); + rc = mmc_of_parse(host->mmc); if (rc) goto err_parse_dt; - if (gpio_is_valid(tegra_host->power_gpio)) { - rc = gpio_request(tegra_host->power_gpio, "sdhci_power"); - if (rc) { - dev_err(mmc_dev(host->mmc), - "failed to allocate power gpio\n"); - goto err_power_req; - } - gpio_direction_output(tegra_host->power_gpio, 1); + tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", + GPIOD_OUT_HIGH); + if (IS_ERR(tegra_host->power_gpio)) { + rc = PTR_ERR(tegra_host->power_gpio); + goto err_power_req; } - clk = clk_get(mmc_dev(host->mmc), NULL); + clk = devm_clk_get(mmc_dev(host->mmc), NULL); if (IS_ERR(clk)) { dev_err(mmc_dev(host->mmc), "clk err\n"); rc = PTR_ERR(clk); @@ -284,10 +302,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) err_add_host: clk_disable_unprepare(pltfm_host->clk); - clk_put(pltfm_host->clk); err_clk_get: - if (gpio_is_valid(tegra_host->power_gpio)) - gpio_free(tegra_host->power_gpio); err_power_req: err_parse_dt: err_alloc_tegra_host: @@ -295,26 +310,6 @@ err_alloc_tegra_host: return rc; } -static int 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; - int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - - sdhci_remove_host(host, dead); - - if (gpio_is_valid(tegra_host->power_gpio)) - gpio_free(tegra_host->power_gpio); - - clk_disable_unprepare(pltfm_host->clk); - clk_put(pltfm_host->clk); - - sdhci_pltfm_free(pdev); - - return 0; -} - static struct platform_driver sdhci_tegra_driver = { .driver = { .name = "sdhci-tegra", @@ -322,7 +317,7 @@ static struct platform_driver sdhci_tegra_driver = { .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_tegra_probe, - .remove = sdhci_tegra_remove, + .remove = sdhci_pltfm_unregister, }; module_platform_driver(sdhci_tegra_driver); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ada1a3ea3a87..c80287a02735 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -28,6 +28,7 @@ #include <linux/mmc/mmc.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/sdio.h> #include <linux/mmc/slot-gpio.h> #include "sdhci.h" @@ -44,8 +45,6 @@ #define MAX_TUNING_LOOP 40 -#define ADMA_SIZE ((128 * 2 + 1) * 4) - static unsigned int debug_quirks = 0; static unsigned int debug_quirks2; @@ -55,8 +54,12 @@ static void sdhci_finish_command(struct sdhci_host *); static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_tuning_timer(unsigned long data); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); +static int sdhci_pre_dma_transfer(struct sdhci_host *host, + struct mmc_data *data, + struct sdhci_host_next *next); +static int sdhci_do_get_cd(struct sdhci_host *host); -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int sdhci_runtime_pm_get(struct sdhci_host *host); static int sdhci_runtime_pm_put(struct sdhci_host *host); static void sdhci_runtime_pm_bus_on(struct sdhci_host *host); @@ -119,10 +122,17 @@ static void sdhci_dumpregs(struct sdhci_host *host) pr_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", - readl(host->ioaddr + SDHCI_ADMA_ERROR), - readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); + if (host->flags & SDHCI_USE_ADMA) { + if (host->flags & SDHCI_USE_64_BIT_DMA) + pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n", + readl(host->ioaddr + SDHCI_ADMA_ERROR), + readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI), + readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); + else + pr_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"); } @@ -254,8 +264,6 @@ static void sdhci_reinit(struct sdhci_host *host) 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); } @@ -448,18 +456,26 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) local_irq_restore(*flags); } -static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd) +static void sdhci_adma_write_desc(struct sdhci_host *host, void *desc, + dma_addr_t addr, int len, unsigned cmd) { - __le32 *dataddr = (__le32 __force *)(desc + 4); - __le16 *cmdlen = (__le16 __force *)desc; + struct sdhci_adma2_64_desc *dma_desc = desc; + + /* 32-bit and 64-bit descriptors have these members in same position */ + dma_desc->cmd = cpu_to_le16(cmd); + dma_desc->len = cpu_to_le16(len); + dma_desc->addr_lo = cpu_to_le32((u32)addr); - /* SDHCI specification says ADMA descriptors should be 4 byte - * aligned, so using 16 or 32bit operations should be safe. */ + if (host->flags & SDHCI_USE_64_BIT_DMA) + dma_desc->addr_hi = cpu_to_le32((u64)addr >> 32); +} - cmdlen[0] = cpu_to_le16(cmd); - cmdlen[1] = cpu_to_le16(len); +static void sdhci_adma_mark_end(void *desc) +{ + struct sdhci_adma2_64_desc *dma_desc = desc; - dataddr[0] = cpu_to_le32(addr); + /* 32-bit and 64-bit descriptors have 'cmd' in same position */ + dma_desc->cmd |= cpu_to_le16(ADMA2_END); } static int sdhci_adma_table_pre(struct sdhci_host *host, @@ -467,8 +483,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, { int direction; - u8 *desc; - u8 *align; + void *desc; + void *align; dma_addr_t addr; dma_addr_t align_addr; int len, offset; @@ -489,17 +505,16 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, direction = DMA_TO_DEVICE; host->align_addr = dma_map_single(mmc_dev(host->mmc), - host->align_buffer, 128 * 4, direction); + host->align_buffer, host->align_buffer_sz, direction); if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) goto fail; - BUG_ON(host->align_addr & 0x3); + BUG_ON(host->align_addr & host->align_mask); - host->sg_count = dma_map_sg(mmc_dev(host->mmc), - data->sg, data->sg_len, direction); - if (host->sg_count == 0) + host->sg_count = sdhci_pre_dma_transfer(host, data, NULL); + if (host->sg_count < 0) goto unmap_align; - desc = host->adma_desc; + desc = host->adma_table; align = host->align_buffer; align_addr = host->align_addr; @@ -515,24 +530,25 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, * the (up to three) bytes that screw up the * alignment. */ - offset = (4 - (addr & 0x3)) & 0x3; + offset = (host->align_sz - (addr & host->align_mask)) & + host->align_mask; if (offset) { if (data->flags & MMC_DATA_WRITE) { buffer = sdhci_kmap_atomic(sg, &flags); - WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); memcpy(align, buffer, offset); sdhci_kunmap_atomic(buffer, &flags); } /* tran, valid */ - sdhci_set_adma_desc(desc, align_addr, offset, 0x21); + sdhci_adma_write_desc(host, desc, align_addr, offset, + ADMA2_TRAN_VALID); BUG_ON(offset > 65536); - align += 4; - align_addr += 4; + align += host->align_sz; + align_addr += host->align_sz; - desc += 8; + desc += host->desc_sz; addr += offset; len -= offset; @@ -541,23 +557,23 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, BUG_ON(len > 65536); /* tran, valid */ - sdhci_set_adma_desc(desc, addr, len, 0x21); - desc += 8; + sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID); + desc += host->desc_sz; /* * If this triggers then we have a calculation bug * somewhere. :/ */ - WARN_ON((desc - host->adma_desc) > ADMA_SIZE); + WARN_ON((desc - host->adma_table) >= host->adma_table_sz); } if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) { /* * Mark the last descriptor as the terminating descriptor */ - if (desc != host->adma_desc) { - desc -= 8; - desc[0] |= 0x2; /* end */ + if (desc != host->adma_table) { + desc -= host->desc_sz; + sdhci_adma_mark_end(desc); } } else { /* @@ -565,7 +581,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, */ /* nop, end, valid */ - sdhci_set_adma_desc(desc, 0, 0, 0x3); + sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID); } /* @@ -573,14 +589,14 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, */ if (data->flags & MMC_DATA_WRITE) { dma_sync_single_for_device(mmc_dev(host->mmc), - host->align_addr, 128 * 4, direction); + host->align_addr, host->align_buffer_sz, direction); } return 0; unmap_align: dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - 128 * 4, direction); + host->align_buffer_sz, direction); fail: return -EINVAL; } @@ -592,7 +608,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host, struct scatterlist *sg; int i, size; - u8 *align; + void *align; char *buffer; unsigned long flags; bool has_unaligned; @@ -603,12 +619,12 @@ static void sdhci_adma_table_post(struct sdhci_host *host, direction = DMA_TO_DEVICE; dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - 128 * 4, direction); + host->align_buffer_sz, direction); /* Do a quick scan of the SG list for any unaligned mappings */ has_unaligned = false; for_each_sg(data->sg, sg, host->sg_count, i) - if (sg_dma_address(sg) & 3) { + if (sg_dma_address(sg) & host->align_mask) { has_unaligned = true; break; } @@ -620,21 +636,22 @@ static void sdhci_adma_table_post(struct sdhci_host *host, align = host->align_buffer; for_each_sg(data->sg, sg, host->sg_count, i) { - if (sg_dma_address(sg) & 0x3) { - size = 4 - (sg_dma_address(sg) & 0x3); + if (sg_dma_address(sg) & host->align_mask) { + size = host->align_sz - + (sg_dma_address(sg) & host->align_mask); buffer = sdhci_kmap_atomic(sg, &flags); - WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); memcpy(buffer, align, size); sdhci_kunmap_atomic(buffer, &flags); - align += 4; + align += host->align_sz; } } } - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); + if (!data->host_cookie) + dma_unmap_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, direction); } static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) @@ -822,15 +839,15 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) } else { sdhci_writel(host, host->adma_addr, SDHCI_ADMA_ADDRESS); + if (host->flags & SDHCI_USE_64_BIT_DMA) + sdhci_writel(host, + (u64)host->adma_addr >> 32, + SDHCI_ADMA_ADDRESS_HI); } } else { int sg_cnt; - sg_cnt = dma_map_sg(mmc_dev(host->mmc), - data->sg, data->sg_len, - (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : - DMA_TO_DEVICE); + sg_cnt = sdhci_pre_dma_transfer(host, data, NULL); if (sg_cnt == 0) { /* * This only happens when someone fed @@ -855,10 +872,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; if ((host->flags & SDHCI_REQ_USE_DMA) && - (host->flags & SDHCI_USE_ADMA)) - ctrl |= SDHCI_CTRL_ADMA32; - else + (host->flags & SDHCI_USE_ADMA)) { + if (host->flags & SDHCI_USE_64_BIT_DMA) + ctrl |= SDHCI_CTRL_ADMA64; + else + ctrl |= SDHCI_CTRL_ADMA32; + } else { ctrl |= SDHCI_CTRL_SDMA; + } sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } @@ -885,27 +906,35 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) static void sdhci_set_transfer_mode(struct sdhci_host *host, struct mmc_command *cmd) { - u16 mode; + u16 mode = 0; struct mmc_data *data = cmd->data; if (data == NULL) { + if (host->quirks2 & + SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) { + sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); + } else { /* clear Auto CMD settings for no data CMDs */ - mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); - sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 | + mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); + sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 | SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE); + } return; } WARN_ON(!host->data); - mode = SDHCI_TRNS_BLK_CNT_EN; + if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE)) + mode = SDHCI_TRNS_BLK_CNT_EN; + if (mmc_op_multi(cmd->opcode) || data->blocks > 1) { - mode |= SDHCI_TRNS_MULTI; + mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI; /* * If we are sending CMD23, CMD12 never gets sent * on successful completion (so no Auto-CMD12). */ - if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) + if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) && + (cmd->opcode != SD_IO_RW_EXTENDED)) mode |= SDHCI_TRNS_AUTO_CMD12; else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { mode |= SDHCI_TRNS_AUTO_CMD23; @@ -934,8 +963,10 @@ static void sdhci_finish_data(struct sdhci_host *host) if (host->flags & SDHCI_USE_ADMA) sdhci_adma_table_post(host, data); else { - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, (data->flags & MMC_DATA_READ) ? + if (!data->host_cookie) + dma_unmap_sg(mmc_dev(host->mmc), + data->sg, data->sg_len, + (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } } @@ -1117,6 +1148,9 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host) case MMC_TIMING_UHS_DDR50: preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50); break; + case MMC_TIMING_MMC_HS400: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400); + break; default: pr_warn("%s: Invalid UHS-I mode selected\n", mmc_hostname(host->mmc)); @@ -1239,6 +1273,12 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode, spin_unlock_irq(&host->lock); mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); spin_lock_irq(&host->lock); + + if (mode != MMC_POWER_OFF) + sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL); + else + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + return; } @@ -1319,6 +1359,9 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) sdhci_runtime_pm_get(host); + /* Firstly check card presence */ + present = sdhci_do_get_cd(host); + spin_lock_irqsave(&host->lock, flags); WARN_ON(host->mrq != NULL); @@ -1340,23 +1383,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; - /* - * Firstly check card presence from cd-gpio. The return could - * be one of the following possibilities: - * negative: cd-gpio is not available - * zero: cd-gpio is used, and card is removed - * one: cd-gpio is used, and card is present - */ - present = mmc_gpio_get_cd(host->mmc); - if (present < 0) { - /* If polling, assume that the card is always present. */ - if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) - present = 1; - else - present = sdhci_readl(host, SDHCI_PRESENT_STATE) & - SDHCI_CARD_PRESENT; - } - if (!present || host->flags & SDHCI_DEVICE_DEAD) { host->mrq->cmd->error = -ENOMEDIUM; tasklet_schedule(&host->finish_tasklet); @@ -1444,6 +1470,8 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) else if ((timing == MMC_TIMING_UHS_DDR50) || (timing == MMC_TIMING_MMC_DDR52)) ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + else if (timing == MMC_TIMING_MMC_HS400) + ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); } EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling); @@ -1515,7 +1543,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) u16 clk, ctrl_2; /* In case of UHS-I modes, set High Speed Enable */ - if ((ios->timing == MMC_TIMING_MMC_HS200) || + if ((ios->timing == MMC_TIMING_MMC_HS400) || + (ios->timing == MMC_TIMING_MMC_HS200) || (ios->timing == MMC_TIMING_MMC_DDR52) || (ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR104) || @@ -1588,7 +1617,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) * signalling timeout and CRC errors even on CMD0. Resetting * it on each ios seems to solve the problem. */ - if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) + if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); mmiowb(); @@ -1790,6 +1819,10 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, ctrl |= SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + /* Some controller need to do more when switching */ + if (host->ops->voltage_switch) + host->ops->voltage_switch(host); + /* 1.8V regulator output should be stable within 5 ms */ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); if (ctrl & SDHCI_CTRL_VDD_180) @@ -1843,6 +1876,18 @@ static int sdhci_card_busy(struct mmc_host *mmc) return !(present_state & SDHCI_DATA_LVL_MASK); } +static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host->flags |= SDHCI_HS400_TUNING; + spin_unlock_irqrestore(&host->lock, flags); + + return 0; +} + static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host = mmc_priv(mmc); @@ -1850,10 +1895,18 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) int tuning_loop_counter = MAX_TUNING_LOOP; int err = 0; unsigned long flags; + unsigned int tuning_count = 0; + bool hs400_tuning; sdhci_runtime_pm_get(host); spin_lock_irqsave(&host->lock, flags); + hs400_tuning = host->flags & SDHCI_HS400_TUNING; + host->flags &= ~SDHCI_HS400_TUNING; + + if (host->tuning_mode == SDHCI_TUNING_MODE_1) + tuning_count = host->tuning_count; + /* * The Host Controller needs tuning only in case of SDR104 mode * and for SDR50 mode when Use Tuning for SDR50 is set in the @@ -1862,7 +1915,20 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) * tuning function has to be executed. */ switch (host->timing) { + /* HS400 tuning is done in HS200 mode */ + case MMC_TIMING_MMC_HS400: + err = -EINVAL; + goto out_unlock; + case MMC_TIMING_MMC_HS200: + /* + * Periodic re-tuning for HS400 is not expected to be needed, so + * disable it here. + */ + if (hs400_tuning) + tuning_count = 0; + break; + case MMC_TIMING_UHS_SDR104: break; @@ -1873,9 +1939,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) /* FALLTHROUGH */ default: - spin_unlock_irqrestore(&host->lock, flags); - sdhci_runtime_pm_put(host); - return 0; + goto out_unlock; } if (host->ops->platform_execute_tuning) { @@ -1887,6 +1951,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ctrl |= SDHCI_CTRL_EXEC_TUNING; + if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND) + ctrl |= SDHCI_CTRL_TUNED_CLK; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); /* @@ -1999,24 +2065,11 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) } out: - /* - * If this is the very first time we are here, we start the retuning - * timer. Since only during the first time, SDHCI_NEEDS_RETUNING - * flag won't be set, we check this condition before actually starting - * the timer. - */ - if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count && - (host->tuning_mode == SDHCI_TUNING_MODE_1)) { + host->flags &= ~SDHCI_NEEDS_RETUNING; + + if (tuning_count) { 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 */ - mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size; - } else if (host->flags & SDHCI_USING_RETUNING_TIMER) { - host->flags &= ~SDHCI_NEEDS_RETUNING; - /* Reload the new initial value for timer */ - mod_timer(&host->tuning_timer, jiffies + - host->tuning_count * HZ); + mod_timer(&host->tuning_timer, jiffies + tuning_count * HZ); } /* @@ -2032,6 +2085,7 @@ out: sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); +out_unlock: spin_unlock_irqrestore(&host->lock, flags); sdhci_runtime_pm_put(host); @@ -2068,19 +2122,93 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable) } } +static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, + int err) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct mmc_data *data = mrq->data; + + if (host->flags & SDHCI_REQ_USE_DMA) { + if (data->host_cookie) + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + data->flags & MMC_DATA_WRITE ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + mrq->data->host_cookie = 0; + } +} + +static int sdhci_pre_dma_transfer(struct sdhci_host *host, + struct mmc_data *data, + struct sdhci_host_next *next) +{ + int sg_count; + + if (!next && data->host_cookie && + data->host_cookie != host->next_data.cookie) { + pr_debug(DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n", + __func__, data->host_cookie, host->next_data.cookie); + data->host_cookie = 0; + } + + /* Check if next job is already prepared */ + if (next || + (!next && data->host_cookie != host->next_data.cookie)) { + sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, + data->flags & MMC_DATA_WRITE ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + + } else { + sg_count = host->next_data.sg_count; + host->next_data.sg_count = 0; + } + + + if (sg_count == 0) + return -EINVAL; + + if (next) { + next->sg_count = sg_count; + data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie; + } else + host->sg_count = sg_count; + + return sg_count; +} + +static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, + bool is_first_req) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (mrq->data->host_cookie) { + mrq->data->host_cookie = 0; + return; + } + + if (host->flags & SDHCI_REQ_USE_DMA) + if (sdhci_pre_dma_transfer(host, + mrq->data, + &host->next_data) < 0) + mrq->data->host_cookie = 0; +} + static void sdhci_card_event(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); unsigned long flags; + int present; /* First check if client has provided their own card event */ if (host->ops->card_event) host->ops->card_event(host); + present = sdhci_do_get_cd(host); + spin_lock_irqsave(&host->lock, flags); /* Check host->mrq first in case we are runtime suspended */ - if (host->mrq && !sdhci_do_get_cd(host)) { + if (host->mrq && !present) { pr_err("%s: Card removed during transfer!\n", mmc_hostname(host->mmc)); pr_err("%s: Resetting controller.\n", @@ -2098,12 +2226,15 @@ static void sdhci_card_event(struct mmc_host *mmc) static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, + .post_req = sdhci_post_req, + .pre_req = sdhci_pre_req, .set_ios = sdhci_set_ios, .get_cd = sdhci_get_cd, .get_ro = sdhci_get_ro, .hw_reset = sdhci_hw_reset, .enable_sdio_irq = sdhci_enable_sdio_irq, .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, + .prepare_hs400_tuning = sdhci_prepare_hs400_tuning, .execute_tuning = sdhci_execute_tuning, .card_event = sdhci_card_event, .card_busy = sdhci_card_busy, @@ -2144,9 +2275,10 @@ static void sdhci_tasklet_finish(unsigned long param) */ if (!(host->flags & SDHCI_DEVICE_DEAD) && ((mrq->cmd && mrq->cmd->error) || - (mrq->data && (mrq->data->error || - (mrq->data->stop && mrq->data->stop->error))) || - (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { + (mrq->sbc && mrq->sbc->error) || + (mrq->data && ((mrq->data->error && !mrq->data->stop) || + (mrq->data->stop && mrq->data->stop->error))) || + (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { /* Some controllers need this kick or reset won't work here */ if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) @@ -2282,32 +2414,36 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) } #ifdef CONFIG_MMC_DEBUG -static void sdhci_show_adma_error(struct sdhci_host *host) +static void sdhci_adma_show_error(struct sdhci_host *host) { const char *name = mmc_hostname(host->mmc); - u8 *desc = host->adma_desc; - __le32 *dma; - __le16 *len; - u8 attr; + void *desc = host->adma_table; sdhci_dumpregs(host); while (true) { - dma = (__le32 *)(desc + 4); - len = (__le16 *)(desc + 2); - attr = *desc; - - DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", - name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr); + struct sdhci_adma2_64_desc *dma_desc = desc; + + if (host->flags & SDHCI_USE_64_BIT_DMA) + DBG("%s: %p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n", + name, desc, le32_to_cpu(dma_desc->addr_hi), + le32_to_cpu(dma_desc->addr_lo), + le16_to_cpu(dma_desc->len), + le16_to_cpu(dma_desc->cmd)); + else + DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", + name, desc, le32_to_cpu(dma_desc->addr_lo), + le16_to_cpu(dma_desc->len), + le16_to_cpu(dma_desc->cmd)); - desc += 8; + desc += host->desc_sz; - if (attr & 2) + if (dma_desc->cmd & cpu_to_le16(ADMA2_END)) break; } } #else -static void sdhci_show_adma_error(struct sdhci_host *host) { } +static void sdhci_adma_show_error(struct sdhci_host *host) { } #endif static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) @@ -2370,7 +2506,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) host->data->error = -EILSEQ; else if (intmask & SDHCI_INT_ADMA_ERROR) { pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); - sdhci_show_adma_error(host); + sdhci_adma_show_error(host); host->data->error = -EIO; if (host->ops->adma_workaround) host->ops->adma_workaround(host, intmask); @@ -2654,9 +2790,6 @@ int sdhci_resume_host(struct sdhci_host *host) } EXPORT_SYMBOL_GPL(sdhci_resume_host); -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_RUNTIME static int sdhci_runtime_pm_get(struct sdhci_host *host) { @@ -2726,9 +2859,9 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) /* Force clock and power re-program */ host->pwr = 0; host->clock = 0; + sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); sdhci_do_set_ios(host, &host->mmc->ios); - sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); if ((host_flags & SDHCI_PV_ENABLED) && !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { spin_lock_irqsave(&host->lock, flags); @@ -2757,7 +2890,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) } EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host); -#endif +#endif /* CONFIG_PM */ /*****************************************************************************\ * * @@ -2849,6 +2982,16 @@ int sdhci_add_host(struct sdhci_host *host) host->flags &= ~SDHCI_USE_ADMA; } + /* + * It is assumed that a 64-bit capable device has set a 64-bit DMA mask + * and *must* do 64-bit DMA. A driver has the opportunity to change + * that during the first call to ->enable_dma(). Similarly + * SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to + * implement. + */ + if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) + host->flags |= SDHCI_USE_64_BIT_DMA; + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) { if (host->ops->enable_dma(host)) { @@ -2860,33 +3003,56 @@ int sdhci_add_host(struct sdhci_host *host) } } + /* SDMA does not support 64-bit DMA */ + if (host->flags & SDHCI_USE_64_BIT_DMA) + host->flags &= ~SDHCI_USE_SDMA; + if (host->flags & SDHCI_USE_ADMA) { /* - * We need to allocate descriptors for all sg entries - * (128) and potentially one alignment transfer for - * each of those entries. + * The DMA descriptor table size is calculated as the maximum + * number of segments times 2, to allow for an alignment + * descriptor for each segment, plus 1 for a nop end descriptor, + * all multipled by the descriptor size. */ - host->adma_desc = dma_alloc_coherent(mmc_dev(mmc), - ADMA_SIZE, &host->adma_addr, - GFP_KERNEL); - host->align_buffer = kmalloc(128 * 4, GFP_KERNEL); - if (!host->adma_desc || !host->align_buffer) { - dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, - host->adma_desc, host->adma_addr); + if (host->flags & SDHCI_USE_64_BIT_DMA) { + host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * + SDHCI_ADMA2_64_DESC_SZ; + host->align_buffer_sz = SDHCI_MAX_SEGS * + SDHCI_ADMA2_64_ALIGN; + host->desc_sz = SDHCI_ADMA2_64_DESC_SZ; + host->align_sz = SDHCI_ADMA2_64_ALIGN; + host->align_mask = SDHCI_ADMA2_64_ALIGN - 1; + } else { + host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * + SDHCI_ADMA2_32_DESC_SZ; + host->align_buffer_sz = SDHCI_MAX_SEGS * + SDHCI_ADMA2_32_ALIGN; + host->desc_sz = SDHCI_ADMA2_32_DESC_SZ; + host->align_sz = SDHCI_ADMA2_32_ALIGN; + host->align_mask = SDHCI_ADMA2_32_ALIGN - 1; + } + host->adma_table = dma_alloc_coherent(mmc_dev(mmc), + host->adma_table_sz, + &host->adma_addr, + GFP_KERNEL); + host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL); + if (!host->adma_table || !host->align_buffer) { + dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, + host->adma_table, host->adma_addr); kfree(host->align_buffer); pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; - host->adma_desc = NULL; + host->adma_table = NULL; host->align_buffer = NULL; - } else if (host->adma_addr & 3) { + } else if (host->adma_addr & host->align_mask) { pr_warn("%s: unable to allocate aligned ADMA descriptor\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; - dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, - host->adma_desc, host->adma_addr); + dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, + host->adma_table, host->adma_addr); kfree(host->align_buffer); - host->adma_desc = NULL; + host->adma_table = NULL; host->align_buffer = NULL; } } @@ -2919,6 +3085,7 @@ int sdhci_add_host(struct sdhci_host *host) host->max_clk = host->ops->get_max_clock(host); } + host->next_data.cookie = 1; /* * In case of Host Controller v3.00, find out whether clock * multiplier is supported. @@ -2985,7 +3152,8 @@ int sdhci_add_host(struct sdhci_host *host) /* Auto-CMD23 stuff only works in ADMA or PIO. */ if ((host->version >= SDHCI_SPEC_300) && ((host->flags & SDHCI_USE_ADMA) || - !(host->flags & SDHCI_USE_SDMA))) { + !(host->flags & SDHCI_USE_SDMA)) && + !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) { host->flags |= SDHCI_AUTO_CMD23; DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc)); } else { @@ -3027,7 +3195,7 @@ int sdhci_add_host(struct sdhci_host *host) if (ret) { pr_warn("%s: Failed to enable vqmmc regulator: %d\n", mmc_hostname(mmc), ret); - mmc->supply.vqmmc = NULL; + mmc->supply.vqmmc = ERR_PTR(-EINVAL); } } @@ -3046,16 +3214,21 @@ int sdhci_add_host(struct sdhci_host *host) /* SD3.0: SDR104 is supported so (for eMMC) the caps2 * field can be promoted to support HS200. */ - if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200)) { + if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200)) mmc->caps2 |= MMC_CAP2_HS200; - if (IS_ERR(mmc->supply.vqmmc) || - !regulator_is_supported_voltage - (mmc->supply.vqmmc, 1100000, 1300000)) - mmc->caps2 &= ~MMC_CAP2_HS200_1_2V_SDR; - } } else if (caps[1] & SDHCI_SUPPORT_SDR50) mmc->caps |= MMC_CAP_UHS_SDR50; + if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 && + (caps[1] & SDHCI_SUPPORT_HS400)) + mmc->caps2 |= MMC_CAP2_HS400; + + if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) && + (IS_ERR(mmc->supply.vqmmc) || + !regulator_is_supported_voltage(mmc->supply.vqmmc, 1100000, + 1300000))) + mmc->caps2 &= ~MMC_CAP2_HSX00_1_2V; + if ((caps[1] & SDHCI_SUPPORT_DDR50) && !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50)) mmc->caps |= MMC_CAP_UHS_DDR50; @@ -3175,15 +3348,16 @@ int sdhci_add_host(struct sdhci_host *host) * can do scatter/gather or not. */ if (host->flags & SDHCI_USE_ADMA) - mmc->max_segs = 128; + mmc->max_segs = SDHCI_MAX_SEGS; else if (host->flags & SDHCI_USE_SDMA) mmc->max_segs = 1; else /* PIO */ - mmc->max_segs = 128; + mmc->max_segs = SDHCI_MAX_SEGS; /* - * Maximum number of sectors in one transfer. Limited by DMA boundary - * size (512KiB). + * Maximum number of sectors in one transfer. Limited by SDMA boundary + * size (512KiB). Note some tuning modes impose a 4MiB limit, but this + * is less anyway. */ mmc->max_req_size = 524288; @@ -3232,9 +3406,9 @@ int sdhci_add_host(struct sdhci_host *host) setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); - if (host->version >= SDHCI_SPEC_300) { - init_waitqueue_head(&host->buf_ready_int); + init_waitqueue_head(&host->buf_ready_int); + if (host->version >= SDHCI_SPEC_300) { /* Initialize re-tuning timer */ init_timer(&host->tuning_timer); host->tuning_timer.data = (unsigned long)host; @@ -3277,7 +3451,8 @@ int sdhci_add_host(struct sdhci_host *host) pr_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_ADMA) ? + (host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" : (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); sdhci_enable_card_detection(host); @@ -3339,18 +3514,15 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) tasklet_kill(&host->finish_tasklet); - if (!IS_ERR(mmc->supply.vmmc)) - regulator_disable(mmc->supply.vmmc); - if (!IS_ERR(mmc->supply.vqmmc)) regulator_disable(mmc->supply.vqmmc); - if (host->adma_desc) - dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, - host->adma_desc, host->adma_addr); + if (host->adma_table) + dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, + host->adma_table, host->adma_addr); kfree(host->align_buffer); - host->adma_desc = NULL; + host->adma_table = NULL; host->align_buffer = NULL; } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 31896a779d4e..e639b7f435e5 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -18,7 +18,7 @@ #include <linux/types.h> #include <linux/io.h> -#include <linux/mmc/sdhci.h> +#include <linux/mmc/host.h> /* * Controller registers @@ -161,7 +161,7 @@ #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_HS400 0x0005 /* Non-standard */ #define SDHCI_CTRL_VDD_180 0x0008 #define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 #define SDHCI_CTRL_DRV_TYPE_B 0x0000 @@ -204,6 +204,7 @@ #define SDHCI_RETUNING_MODE_SHIFT 14 #define SDHCI_CLOCK_MUL_MASK 0x00FF0000 #define SDHCI_CLOCK_MUL_SHIFT 16 +#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ #define SDHCI_CAPABILITIES_1 0x44 @@ -227,6 +228,7 @@ /* 55-57 reserved */ #define SDHCI_ADMA_ADDRESS 0x58 +#define SDHCI_ADMA_ADDRESS_HI 0x5C /* 60-FB reserved */ @@ -235,6 +237,7 @@ #define SDHCI_PRESET_FOR_SDR50 0x6A #define SDHCI_PRESET_FOR_SDR104 0x6C #define SDHCI_PRESET_FOR_DDR50 0x6E +#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */ #define SDHCI_PRESET_DRV_MASK 0xC000 #define SDHCI_PRESET_DRV_SHIFT 14 #define SDHCI_PRESET_CLKGEN_SEL_MASK 0x400 @@ -266,6 +269,247 @@ #define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) #define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12) +/* ADMA2 32-bit DMA descriptor size */ +#define SDHCI_ADMA2_32_DESC_SZ 8 + +/* ADMA2 32-bit DMA alignment */ +#define SDHCI_ADMA2_32_ALIGN 4 + +/* ADMA2 32-bit descriptor */ +struct sdhci_adma2_32_desc { + __le16 cmd; + __le16 len; + __le32 addr; +} __packed __aligned(SDHCI_ADMA2_32_ALIGN); + +/* ADMA2 64-bit DMA descriptor size */ +#define SDHCI_ADMA2_64_DESC_SZ 12 + +/* ADMA2 64-bit DMA alignment */ +#define SDHCI_ADMA2_64_ALIGN 8 + +/* + * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte + * aligned. + */ +struct sdhci_adma2_64_desc { + __le16 cmd; + __le16 len; + __le32 addr_lo; + __le32 addr_hi; +} __packed __aligned(4); + +#define ADMA2_TRAN_VALID 0x21 +#define ADMA2_NOP_END_VALID 0x3 +#define ADMA2_END 0x2 + +/* + * Maximum segments assuming a 512KiB maximum requisition size and a minimum + * 4KiB page size. + */ +#define SDHCI_MAX_SEGS 128 + +struct sdhci_host_next { + unsigned int sg_count; + s32 cookie; +}; + +struct sdhci_host { + /* Data set by hardware interface driver */ + const char *hw_name; /* Hardware bus name */ + + unsigned int quirks; /* Deviations from spec. */ + +/* Controller doesn't honor resets unless we touch the clock register */ +#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) +/* Controller has bad caps bits, but really supports DMA */ +#define SDHCI_QUIRK_FORCE_DMA (1<<1) +/* Controller doesn't like to be reset when there is no card inserted. */ +#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) +/* Controller doesn't like clearing the power reg before a change */ +#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) +/* Controller has flaky internal state so reset it on each ios change */ +#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) +/* Controller has an unusable DMA engine */ +#define SDHCI_QUIRK_BROKEN_DMA (1<<5) +/* Controller has an unusable ADMA engine */ +#define SDHCI_QUIRK_BROKEN_ADMA (1<<6) +/* Controller can only DMA from 32-bit aligned addresses */ +#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<7) +/* Controller can only DMA chunk sizes that are a multiple of 32 bits */ +#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<8) +/* Controller can only ADMA chunks that are a multiple of 32 bits */ +#define SDHCI_QUIRK_32BIT_ADMA_SIZE (1<<9) +/* Controller needs to be reset after each request to stay stable */ +#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<10) +/* Controller needs voltage and power writes to happen separately */ +#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11) +/* Controller provides an incorrect timeout value for transfers */ +#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12) +/* Controller has an issue with buffer bits for small transfers */ +#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13) +/* Controller does not provide transfer-complete interrupt when not busy */ +#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14) +/* Controller has unreliable card detection */ +#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15) +/* Controller reports inverted write-protect state */ +#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16) +/* Controller does not like fast PIO transfers */ +#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18) +/* Controller has to be forced to use block size of 2048 bytes */ +#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20) +/* Controller cannot do multi-block transfers */ +#define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21) +/* Controller can only handle 1-bit data transfers */ +#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22) +/* Controller needs 10ms delay between applying power and clock */ +#define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23) +/* Controller uses SDCLK instead of TMCLK for data timeouts */ +#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<24) +/* Controller reports wrong base clock capability */ +#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25) +/* Controller cannot support End Attribute in NOP ADMA descriptor */ +#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26) +/* Controller is missing device caps. Use caps provided by host */ +#define SDHCI_QUIRK_MISSING_CAPS (1<<27) +/* Controller uses Auto CMD12 command to stop the transfer */ +#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28) +/* Controller doesn't have HISPD bit field in HI-SPEED SD card */ +#define SDHCI_QUIRK_NO_HISPD_BIT (1<<29) +/* Controller treats ADMA descriptors with length 0000h incorrectly */ +#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1<<30) +/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ +#define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1<<31) + + unsigned int quirks2; /* More deviations from spec. */ + +#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0) +#define SDHCI_QUIRK2_HOST_NO_CMD23 (1<<1) +/* The system physically doesn't support 1.8v, even if the host does */ +#define SDHCI_QUIRK2_NO_1_8_V (1<<2) +#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3) +#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4) +/* Controller has a non-standard host control register */ +#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5) +/* Controller does not support HS200 */ +#define SDHCI_QUIRK2_BROKEN_HS200 (1<<6) +/* Controller does not support DDR50 */ +#define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7) +/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */ +#define SDHCI_QUIRK2_STOP_WITH_TC (1<<8) +/* Controller does not support 64-bit DMA */ +#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9) +/* need clear transfer mode register before send cmd */ +#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10) +/* Capability register bit-63 indicates HS400 support */ +#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1<<11) +/* forced tuned clock */ +#define SDHCI_QUIRK2_TUNING_WORK_AROUND (1<<12) +/* disable the block count for single block transactions */ +#define SDHCI_QUIRK2_SUPPORT_SINGLE (1<<13) +/* Controller broken with using ACMD23 */ +#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14) + + int irq; /* Device IRQ */ + void __iomem *ioaddr; /* Mapped address */ + + const struct sdhci_ops *ops; /* Low level hw interface */ + + /* Internal data */ + struct mmc_host *mmc; /* MMC structure */ + u64 dma_mask; /* custom DMA mask */ + +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) + struct led_classdev led; /* LED control */ + char led_name[32]; +#endif + + spinlock_t lock; /* Mutex */ + + int flags; /* Host attributes */ +#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */ +#define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */ +#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ +#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ +#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */ +#define SDHCI_NEEDS_RETUNING (1<<5) /* Host needs retuning */ +#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */ +#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ +#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */ +#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ +#define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */ +#define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */ +#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ +#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */ + + unsigned int version; /* SDHCI spec. version */ + + unsigned int max_clk; /* Max possible freq (MHz) */ + unsigned int timeout_clk; /* Timeout freq (KHz) */ + unsigned int clk_mul; /* Clock Muliplier value */ + + unsigned int clock; /* Current clock (MHz) */ + u8 pwr; /* Current voltage */ + + bool runtime_suspended; /* Host is runtime suspended */ + bool bus_on; /* Bus power prevents runtime suspend */ + bool preset_enabled; /* Preset is enabled */ + + struct mmc_request *mrq; /* Current request */ + struct mmc_command *cmd; /* Current command */ + struct mmc_data *data; /* Current data request */ + unsigned int data_early:1; /* Data finished before cmd */ + unsigned int busy_handle:1; /* Handling the order of Busy-end */ + + struct sg_mapping_iter sg_miter; /* SG state for PIO */ + unsigned int blocks; /* remaining PIO blocks */ + + int sg_count; /* Mapped sg entries */ + + void *adma_table; /* ADMA descriptor table */ + void *align_buffer; /* Bounce buffer */ + + size_t adma_table_sz; /* ADMA descriptor table size */ + size_t align_buffer_sz; /* Bounce buffer size */ + + dma_addr_t adma_addr; /* Mapped ADMA descr. table */ + dma_addr_t align_addr; /* Mapped bounce buffer */ + + unsigned int desc_sz; /* ADMA descriptor size */ + unsigned int align_sz; /* ADMA alignment */ + unsigned int align_mask; /* ADMA alignment mask */ + + struct tasklet_struct finish_tasklet; /* Tasklet structures */ + + struct timer_list timer; /* Timer for timeouts */ + + u32 caps; /* Alternative CAPABILITY_0 */ + u32 caps1; /* Alternative CAPABILITY_1 */ + + unsigned int ocr_avail_sdio; /* OCR bit masks */ + unsigned int ocr_avail_sd; + unsigned int ocr_avail_mmc; + u32 ocr_mask; /* available voltages */ + + unsigned timing; /* Current timing */ + + u32 thread_isr; + + /* cached registers */ + u32 ier; + + wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ + unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ + + unsigned int tuning_count; /* Timer count for re-tuning */ + unsigned int tuning_mode; /* Re-tuning mode supported by host */ +#define SDHCI_TUNING_MODE_1 0 + struct timer_list tuning_timer; /* Timer for tuning */ + + struct sdhci_host_next next_data; + unsigned long private[0] ____cacheline_aligned; +}; + struct sdhci_ops { #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS u32 (*read_l)(struct sdhci_host *host, int reg); @@ -296,6 +540,7 @@ struct sdhci_ops { void (*adma_workaround)(struct sdhci_host *host, u32 intmask); void (*platform_init)(struct sdhci_host *host); void (*card_event)(struct sdhci_host *host); + void (*voltage_switch)(struct sdhci_host *host); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS @@ -411,9 +656,6 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); extern int sdhci_suspend_host(struct sdhci_host *host); 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 diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c new file mode 100644 index 000000000000..2fe8b91481b3 --- /dev/null +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -0,0 +1,237 @@ +/* + * linux/drivers/mmc/host/sdhci_f_sdh30.c + * + * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd + * Vincent Yang <vincent.yang@tw.fujitsu.com> + * Copyright (C) 2015 Linaro Ltd Andy Green <andy.green@linaro.org> + * + * 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, version 2 of the License. + */ + +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/clk.h> + +#include "sdhci-pltfm.h" + +/* F_SDH30 extended Controller registers */ +#define F_SDH30_AHB_CONFIG 0x100 +#define F_SDH30_AHB_BIGED 0x00000040 +#define F_SDH30_BUSLOCK_DMA 0x00000020 +#define F_SDH30_BUSLOCK_EN 0x00000010 +#define F_SDH30_SIN 0x00000008 +#define F_SDH30_AHB_INCR_16 0x00000004 +#define F_SDH30_AHB_INCR_8 0x00000002 +#define F_SDH30_AHB_INCR_4 0x00000001 + +#define F_SDH30_TUNING_SETTING 0x108 +#define F_SDH30_CMD_CHK_DIS 0x00010000 + +#define F_SDH30_IO_CONTROL2 0x114 +#define F_SDH30_CRES_O_DN 0x00080000 +#define F_SDH30_MSEL_O_1_8 0x00040000 + +#define F_SDH30_ESD_CONTROL 0x124 +#define F_SDH30_EMMC_RST 0x00000002 +#define F_SDH30_EMMC_HS200 0x01000000 + +#define F_SDH30_CMD_DAT_DELAY 0x200 + +#define F_SDH30_MIN_CLOCK 400000 + +struct f_sdhost_priv { + struct clk *clk_iface; + struct clk *clk; + u32 vendor_hs200; + struct device *dev; +}; + +void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host) +{ + struct f_sdhost_priv *priv = sdhci_priv(host); + u32 ctrl = 0; + + usleep_range(2500, 3000); + ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2); + ctrl |= F_SDH30_CRES_O_DN; + sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); + ctrl |= F_SDH30_MSEL_O_1_8; + sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); + + ctrl &= ~F_SDH30_CRES_O_DN; + sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); + usleep_range(2500, 3000); + + if (priv->vendor_hs200) { + dev_info(priv->dev, "%s: setting hs200\n", __func__); + ctrl = sdhci_readl(host, F_SDH30_ESD_CONTROL); + ctrl |= priv->vendor_hs200; + sdhci_writel(host, ctrl, F_SDH30_ESD_CONTROL); + } + + ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING); + ctrl |= F_SDH30_CMD_CHK_DIS; + sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING); +} + +unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host *host) +{ + return F_SDH30_MIN_CLOCK; +} + +void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask) +{ + if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0) + sdhci_writew(host, 0xBC01, SDHCI_CLOCK_CONTROL); + + sdhci_reset(host, mask); +} + +static const struct sdhci_ops sdhci_f_sdh30_ops = { + .voltage_switch = sdhci_f_sdh30_soft_voltage_switch, + .get_min_clock = sdhci_f_sdh30_get_min_clock, + .reset = sdhci_f_sdh30_reset, + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static int sdhci_f_sdh30_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct device *dev = &pdev->dev; + struct resource *res; + int irq, ctrl = 0, ret = 0; + struct f_sdhost_priv *priv; + u32 reg = 0; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "%s: no irq specified\n", __func__); + return irq; + } + + host = sdhci_alloc_host(dev, sizeof(struct sdhci_host) + + sizeof(struct f_sdhost_priv)); + if (IS_ERR(host)) + return PTR_ERR(host); + + priv = sdhci_priv(host); + priv->dev = dev; + + host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_INVERTED_WRITE_PROTECT; + host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE | + SDHCI_QUIRK2_TUNING_WORK_AROUND; + + ret = mmc_of_parse(host->mmc); + if (ret) + goto err; + + platform_set_drvdata(pdev, host); + + sdhci_get_of_property(pdev); + host->hw_name = "f_sdh30"; + host->ops = &sdhci_f_sdh30_ops; + host->irq = irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + host->ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(host->ioaddr)) { + ret = PTR_ERR(host->ioaddr); + goto err; + } + + priv->clk_iface = devm_clk_get(&pdev->dev, "iface"); + if (IS_ERR(priv->clk_iface)) { + ret = PTR_ERR(priv->clk_iface); + goto err; + } + + ret = clk_prepare_enable(priv->clk_iface); + if (ret) + goto err; + + priv->clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(priv->clk)) { + ret = PTR_ERR(priv->clk); + goto err_clk; + } + + ret = clk_prepare_enable(priv->clk); + if (ret) + goto err_clk; + + /* init vendor specific regs */ + ctrl = sdhci_readw(host, F_SDH30_AHB_CONFIG); + ctrl |= F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 | + F_SDH30_AHB_INCR_4; + ctrl &= ~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN); + sdhci_writew(host, ctrl, F_SDH30_AHB_CONFIG); + + reg = sdhci_readl(host, F_SDH30_ESD_CONTROL); + sdhci_writel(host, reg & ~F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL); + msleep(20); + sdhci_writel(host, reg | F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL); + + reg = sdhci_readl(host, SDHCI_CAPABILITIES); + if (reg & SDHCI_CAN_DO_8BIT) + priv->vendor_hs200 = F_SDH30_EMMC_HS200; + + ret = sdhci_add_host(host); + if (ret) + goto err_add_host; + + return 0; + +err_add_host: + clk_disable_unprepare(priv->clk); +err_clk: + clk_disable_unprepare(priv->clk_iface); +err: + sdhci_free_host(host); + return ret; +} + +static int sdhci_f_sdh30_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct f_sdhost_priv *priv = sdhci_priv(host); + + sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) == + 0xffffffff); + + clk_disable_unprepare(priv->clk_iface); + clk_disable_unprepare(priv->clk); + + sdhci_free_host(host); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id f_sdh30_dt_ids[] = { + { .compatible = "fujitsu,mb86s70-sdhci-3.0" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, f_sdh30_dt_ids); + +static struct platform_driver sdhci_f_sdh30_driver = { + .driver = { + .name = "f_sdh30", + .of_match_table = f_sdh30_dt_ids, + .pm = SDHCI_PLTFM_PMOPS, + }, + .probe = sdhci_f_sdh30_probe, + .remove = sdhci_f_sdh30_remove, +}; + +module_platform_driver(sdhci_f_sdh30_driver); + +MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD."); +MODULE_ALIAS("platform:f_sdh30"); diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 7d9d6a321521..072f67066df3 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -875,6 +875,7 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, struct mmc_command *cmd = mrq->cmd; u32 opc = cmd->opcode; u32 mask; + unsigned long flags; switch (opc) { /* response busy check */ @@ -909,10 +910,12 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, /* set arg */ sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg); /* set cmd */ + spin_lock_irqsave(&host->lock, flags); 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); + spin_unlock_irqrestore(&host->lock, flags); } static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, @@ -1171,6 +1174,12 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) struct sh_mmcif_host *host = dev_id; struct mmc_request *mrq; bool wait = false; + unsigned long flags; + int wait_work; + + spin_lock_irqsave(&host->lock, flags); + wait_work = host->wait_for; + spin_unlock_irqrestore(&host->lock, flags); cancel_delayed_work_sync(&host->timeout_work); @@ -1188,7 +1197,7 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) * All handlers return true, if processing continues, and false, if the * request has to be completed - successfully or not */ - switch (host->wait_for) { + switch (wait_work) { case MMCIF_WAIT_FOR_REQUEST: /* We're too late, the timeout has already kicked in */ mutex_unlock(&host->thread_lock); @@ -1312,15 +1321,15 @@ static void mmcif_timeout_work(struct work_struct *work) /* Don't run after mmc_remove_host() */ return; - dev_err(&host->pd->dev, "Timeout waiting for %u on CMD%u\n", - host->wait_for, mrq->cmd->opcode); - spin_lock_irqsave(&host->lock, flags); if (host->state == STATE_IDLE) { spin_unlock_irqrestore(&host->lock, flags); return; } + dev_err(&host->pd->dev, "Timeout waiting for %u on CMD%u\n", + host->wait_for, mrq->cmd->opcode); + host->state = STATE_TIMEOUT; spin_unlock_irqrestore(&host->lock, flags); diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index a2e81a1ea6af..6906a905cd54 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -35,10 +35,13 @@ #define EXT_ACC 0xe4 +#define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data) + struct sh_mobile_sdhi_of_data { unsigned long tmio_flags; unsigned long capabilities; unsigned long capabilities2; + enum dma_slave_buswidth dma_buswidth; dma_addr_t dma_rx_offset; }; @@ -58,6 +61,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_CLK_ACTUAL, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, + .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_rx_offset = 0x2000, }; @@ -84,16 +88,43 @@ struct sh_mobile_sdhi { struct tmio_mmc_dma dma_priv; }; +static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) +{ + u32 val; + + /* + * see also + * sh_mobile_sdhi_of_data :: dma_buswidth + */ + switch (sd_ctrl_read16(host, CTL_VERSION)) { + case 0x490C: + val = (width == 32) ? 0x0001 : 0x0000; + break; + case 0xCB0D: + val = (width == 32) ? 0x0000 : 0x0001; + break; + default: + /* nothing to do */ + return; + } + + sd_ctrl_write16(host, EXT_ACC, val); +} + static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f) { struct mmc_host *mmc = platform_get_drvdata(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 *priv = host_to_priv(host); int ret = clk_prepare_enable(priv->clk); if (ret < 0) return ret; *f = clk_get_rate(priv->clk); + + /* enable 16bit data access on SDBUF as default */ + sh_mobile_sdhi_sdbuf_width(host, 16); + return 0; } @@ -101,7 +132,7 @@ static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(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 *priv = host_to_priv(host); clk_disable_unprepare(priv->clk); } @@ -113,7 +144,7 @@ static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) udelay(1); if (!timeout) { - dev_warn(host->pdata->dev, "timeout waiting for SD bus idle\n"); + dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n"); return -EBUSY; } @@ -156,14 +187,13 @@ static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, return blk_size; } -static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev) +static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) { - mmc_detect_change(platform_get_drvdata(pdev), msecs_to_jiffies(100)); -} + sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); -static const struct sh_mobile_sdhi_ops sdhi_ops = { - .cd_wakeup = sh_mobile_sdhi_cd_wakeup, -}; + /* enable 32bit access if DMA mode if possibile */ + sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16); +} static int sh_mobile_sdhi_probe(struct platform_device *pdev) { @@ -177,7 +207,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) int irq, ret, i = 0; bool multiplexed_isr = true; struct tmio_mmc_dma *dma_priv; - u16 ver; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -192,26 +221,31 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data = &priv->mmc_data; dma_priv = &priv->dma_priv; - if (p) { - if (p->init) { - ret = p->init(pdev, &sdhi_ops); - if (ret) - return ret; - } - } - priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { ret = PTR_ERR(priv->clk); dev_err(&pdev->dev, "cannot get clock: %d\n", ret); - goto eclkget; + goto eprobe; } - mmc_data->clk_enable = sh_mobile_sdhi_clk_enable; - mmc_data->clk_disable = sh_mobile_sdhi_clk_disable; + host = tmio_mmc_host_alloc(pdev); + if (!host) { + ret = -ENOMEM; + goto eprobe; + } + + host->dma = dma_priv; + host->write16_hook = sh_mobile_sdhi_write16_hook; + host->clk_enable = sh_mobile_sdhi_clk_enable; + host->clk_disable = sh_mobile_sdhi_clk_disable; + host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; + /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ + if (resource_size(res) > 0x100) + host->bus_shift = 1; + else + host->bus_shift = 0; + mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; - mmc_data->write16_hook = sh_mobile_sdhi_write16_hook; - mmc_data->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; if (p) { mmc_data->flags = p->tmio_flags; mmc_data->ocr_mask = p->tmio_ocr_mask; @@ -231,11 +265,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) dma_priv->slave_id_rx = p->dma_slave_rx; } } - - dma_priv->alignment_shift = 1; /* 2-byte alignment */ dma_priv->filter = shdma_chan_filter; + dma_priv->enable = sh_mobile_sdhi_enable_dma; - mmc_data->dma = dma_priv; + mmc_data->alignment_shift = 1; /* 2-byte alignment */ /* * All SDHI blocks support 2-byte and larger block sizes in 4-bit @@ -258,33 +291,18 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) */ mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK; - /* - * All SDHI have DMA control register - */ - mmc_data->flags |= TMIO_MMC_HAVE_CTL_DMA_REG; - if (of_id && of_id->data) { const struct sh_mobile_sdhi_of_data *of_data = of_id->data; mmc_data->flags |= of_data->tmio_flags; mmc_data->capabilities |= of_data->capabilities; mmc_data->capabilities2 |= of_data->capabilities2; - dma_priv->dma_rx_offset = of_data->dma_rx_offset; + mmc_data->dma_rx_offset = of_data->dma_rx_offset; + dma_priv->dma_buswidth = of_data->dma_buswidth; } - /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ - mmc_data->bus_shift = resource_size(res) >> 9; - - ret = tmio_mmc_host_probe(&host, pdev, mmc_data); + ret = tmio_mmc_host_probe(host, mmc_data); if (ret < 0) - goto eprobe; - - /* - * FIXME: - * this Workaround can be more clever method - */ - ver = sd_ctrl_read16(host, CTL_VERSION); - if (ver == 0xCB0D) - sd_ctrl_write16(host, EXT_ACC, 1); + goto efree; /* * Allow one or more specific (named) ISRs or @@ -351,10 +369,9 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) eirq: tmio_mmc_host_remove(host); +efree: + tmio_mmc_host_free(host); eprobe: -eclkget: - if (p && p->cleanup) - p->cleanup(pdev); return ret; } @@ -362,20 +379,16 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; tmio_mmc_host_remove(host); - if (p && p->cleanup) - p->cleanup(pdev); - return 0; } static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) - SET_PM_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, + SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, tmio_mmc_host_runtime_resume, NULL) }; diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index d1663b3c4143..4d3e1ffe5508 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -21,9 +21,6 @@ #include <linux/err.h> #include <linux/clk.h> -#include <linux/clk-private.h> -#include <linux/clk/sunxi.h> - #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/spinlock.h> @@ -230,6 +227,8 @@ struct sunxi_mmc_host { /* clock management */ struct clk *clk_ahb; struct clk *clk_mmc; + struct clk *clk_sample; + struct clk *clk_output; /* irq */ spinlock_t lock; @@ -253,7 +252,7 @@ static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host) unsigned long expire = jiffies + msecs_to_jiffies(250); u32 rval; - mmc_writel(host, REG_CMDR, SDXC_HARDWARE_RESET); + mmc_writel(host, REG_GCTRL, SDXC_HARDWARE_RESET); do { rval = mmc_readl(host, REG_GCTRL); } while (time_before(jiffies, expire) && (rval & SDXC_HARDWARE_RESET)); @@ -294,7 +293,7 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host, struct mmc_data *data) { struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu; - struct sunxi_idma_des *pdes_pa = (struct sunxi_idma_des *)host->sg_dma; + dma_addr_t next_desc = host->sg_dma; int i, max_len = (1 << host->idma_des_size_bits); for (i = 0; i < data->sg_len; i++) { @@ -306,12 +305,15 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host, else pdes[i].buf_size = data->sg[i].length; + next_desc += sizeof(struct sunxi_idma_des); pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]); - pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1]; + pdes[i].buf_addr_ptr2 = (u32)next_desc; } pdes[0].config |= SDXC_IDMAC_DES0_FD; - pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD; + pdes[i - 1].config |= SDXC_IDMAC_DES0_LD | SDXC_IDMAC_DES0_ER; + pdes[i - 1].config &= ~SDXC_IDMAC_DES0_DIC; + pdes[i - 1].buf_addr_ptr2 = 0; /* * Avoid the io-store starting the idmac hitting io-mem before the @@ -571,6 +573,15 @@ static irqreturn_t sunxi_mmc_handle_manual_stop(int irq, void *dev_id) } dev_err(mmc_dev(host->mmc), "data error, sending stop command\n"); + + /* + * We will never have more than one outstanding request, + * and we do not complete the request until after + * we've cleared host->manual_stop_mrq so we do not need to + * spin lock this function. + * Additionally we have wait states within this function + * so having it in a lock is a very bad idea. + */ sunxi_mmc_send_manual_stop(host, mrq); spin_lock_irqsave(&host->lock, iflags); @@ -617,7 +628,7 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, struct mmc_ios *ios) { - u32 rate, oclk_dly, rval, sclk_dly, src_clk; + u32 rate, oclk_dly, rval, sclk_dly; int ret; rate = clk_round_rate(host->clk_mmc, ios->clock); @@ -643,34 +654,31 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, /* determine delays */ if (rate <= 400000) { - oclk_dly = 0; - sclk_dly = 7; + oclk_dly = 180; + sclk_dly = 42; } else if (rate <= 25000000) { - oclk_dly = 0; - sclk_dly = 5; + oclk_dly = 180; + sclk_dly = 75; } else if (rate <= 50000000) { if (ios->timing == MMC_TIMING_UHS_DDR50) { - oclk_dly = 2; - sclk_dly = 4; + oclk_dly = 60; + sclk_dly = 120; } else { - oclk_dly = 3; - sclk_dly = 5; + oclk_dly = 90; + sclk_dly = 150; } + } else if (rate <= 100000000) { + oclk_dly = 6; + sclk_dly = 24; + } else if (rate <= 200000000) { + oclk_dly = 3; + sclk_dly = 12; } else { - /* rate > 50000000 */ - oclk_dly = 2; - sclk_dly = 4; + return -EINVAL; } - src_clk = clk_get_rate(clk_get_parent(host->clk_mmc)); - if (src_clk >= 300000000 && src_clk <= 400000000) { - if (oclk_dly) - oclk_dly--; - if (sclk_dly) - sclk_dly--; - } - - clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly); + clk_set_phase(host->clk_sample, sclk_dly); + clk_set_phase(host->clk_output, oclk_dly); return sunxi_mmc_oclk_onoff(host, 1); } @@ -767,6 +775,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) unsigned long iflags; u32 imask = SDXC_INTERRUPT_ERROR_BIT; u32 cmd_val = SDXC_START | (cmd->opcode & 0x3f); + bool wait_dma = host->wait_dma; int ret; /* Check for set_ios errors (should never happen) */ @@ -817,7 +826,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) if (cmd->data->flags & MMC_DATA_WRITE) cmd_val |= SDXC_WRITE; else - host->wait_dma = true; + wait_dma = true; } else { imask |= SDXC_COMMAND_DONE; } @@ -851,6 +860,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) } host->mrq = mrq; + host->wait_dma = wait_dma; mmc_writel(host, REG_IMASK, host->sdio_imask | imask); mmc_writel(host, REG_CARG, cmd->arg); mmc_writel(host, REG_CMDR, cmd_val); @@ -909,7 +919,21 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, return PTR_ERR(host->clk_mmc); } - host->reset = devm_reset_control_get(&pdev->dev, "ahb"); + host->clk_output = devm_clk_get(&pdev->dev, "output"); + if (IS_ERR(host->clk_output)) { + dev_err(&pdev->dev, "Could not get output clock\n"); + return PTR_ERR(host->clk_output); + } + + host->clk_sample = devm_clk_get(&pdev->dev, "sample"); + if (IS_ERR(host->clk_sample)) { + dev_err(&pdev->dev, "Could not get sample clock\n"); + return PTR_ERR(host->clk_sample); + } + + host->reset = devm_reset_control_get_optional(&pdev->dev, "ahb"); + if (PTR_ERR(host->reset) == -EPROBE_DEFER) + return PTR_ERR(host->reset); ret = clk_prepare_enable(host->clk_ahb); if (ret) { @@ -923,11 +947,23 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, goto error_disable_clk_ahb; } + ret = clk_prepare_enable(host->clk_output); + if (ret) { + dev_err(&pdev->dev, "Enable output clk err %d\n", ret); + goto error_disable_clk_mmc; + } + + ret = clk_prepare_enable(host->clk_sample); + if (ret) { + dev_err(&pdev->dev, "Enable sample clk err %d\n", ret); + goto error_disable_clk_output; + } + if (!IS_ERR(host->reset)) { ret = reset_control_deassert(host->reset); if (ret) { dev_err(&pdev->dev, "reset err %d\n", ret); - goto error_disable_clk_mmc; + goto error_disable_clk_sample; } } @@ -946,6 +982,10 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, error_assert_reset: if (!IS_ERR(host->reset)) reset_control_assert(host->reset); +error_disable_clk_sample: + clk_disable_unprepare(host->clk_sample); +error_disable_clk_output: + clk_disable_unprepare(host->clk_output); error_disable_clk_mmc: clk_disable_unprepare(host->clk_mmc); error_disable_clk_ahb: @@ -991,7 +1031,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev) mmc->f_min = 400000; mmc->f_max = 50000000; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_ERASE; + MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ; ret = mmc_of_parse(mmc); if (ret) diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 659028ddb8b1..f746df493892 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -88,14 +88,19 @@ static int tmio_mmc_probe(struct platform_device *pdev) if (!res) return -EINVAL; - /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ - pdata->bus_shift = resource_size(res) >> 10; pdata->flags |= TMIO_MMC_HAVE_HIGH_REG; - ret = tmio_mmc_host_probe(&host, pdev, pdata); - if (ret) + host = tmio_mmc_host_alloc(pdev); + if (!host) goto cell_disable; + /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ + host->bus_shift = resource_size(res) >> 10; + + ret = tmio_mmc_host_probe(host, pdata); + if (ret) + goto host_free; + ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host); if (ret) @@ -108,6 +113,8 @@ static int tmio_mmc_probe(struct platform_device *pdev) host_remove: tmio_mmc_host_remove(host); +host_free: + tmio_mmc_host_free(host); cell_disable: if (cell->disable) cell->disable(pdev); @@ -135,7 +142,7 @@ static int tmio_mmc_remove(struct platform_device *pdev) static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume) - SET_PM_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, + SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, tmio_mmc_host_runtime_resume, NULL) }; @@ -143,7 +150,6 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { static struct platform_driver tmio_mmc_driver = { .driver = { .name = "tmio-mmc", - .owner = THIS_MODULE, .pm = &tmio_mmc_dev_pm_ops, }, .probe = tmio_mmc_probe, diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index a34ecbe1c1ad..fc3805ed69d1 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -16,6 +16,7 @@ #ifndef TMIO_MMC_H #define TMIO_MMC_H +#include <linux/dmaengine.h> #include <linux/highmem.h> #include <linux/mmc/tmio.h> #include <linux/mutex.h> @@ -39,6 +40,17 @@ #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) struct tmio_mmc_data; +struct tmio_mmc_host; + +struct tmio_mmc_dma { + void *chan_priv_tx; + void *chan_priv_rx; + int slave_id_tx; + int slave_id_rx; + enum dma_slave_buswidth dma_buswidth; + bool (*filter)(struct dma_chan *chan, void *arg); + void (*enable)(struct tmio_mmc_host *host, bool enable); +}; struct tmio_mmc_host { void __iomem *ctl; @@ -56,9 +68,11 @@ struct tmio_mmc_host { struct scatterlist *sg_orig; unsigned int sg_len; unsigned int sg_off; + unsigned long bus_shift; struct platform_device *pdev; struct tmio_mmc_data *pdata; + struct tmio_mmc_dma *dma; /* DMA support */ bool force_pio; @@ -83,10 +97,17 @@ struct tmio_mmc_host { struct mutex ios_lock; /* protect set_ios() context */ bool native_hotplug; bool sdio_irq_enabled; + + int (*write16_hook)(struct tmio_mmc_host *host, int addr); + int (*clk_enable)(struct platform_device *pdev, unsigned int *f); + void (*clk_disable)(struct platform_device *pdev); + int (*multi_io_quirk)(struct mmc_card *card, + unsigned int direction, int blk_size); }; -int tmio_mmc_host_probe(struct tmio_mmc_host **host, - struct platform_device *pdev, +struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev); +void tmio_mmc_host_free(struct tmio_mmc_host *host); +int tmio_mmc_host_probe(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); void tmio_mmc_host_remove(struct tmio_mmc_host *host); void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); @@ -151,19 +172,19 @@ int tmio_mmc_host_runtime_resume(struct device *dev); static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) { - return readw(host->ctl + (addr << host->pdata->bus_shift)); + return readw(host->ctl + (addr << host->bus_shift)); } static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, u16 *buf, int count) { - readsw(host->ctl + (addr << host->pdata->bus_shift), buf, count); + readsw(host->ctl + (addr << host->bus_shift), buf, count); } static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) { - return readw(host->ctl + (addr << host->pdata->bus_shift)) | - readw(host->ctl + ((addr + 2) << host->pdata->bus_shift)) << 16; + return readw(host->ctl + (addr << host->bus_shift)) | + readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; } static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) @@ -171,21 +192,21 @@ static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val /* If there is a hook and it returns non-zero then there * is an error and the write should be skipped */ - if (host->pdata->write16_hook && host->pdata->write16_hook(host, addr)) + if (host->write16_hook && host->write16_hook(host, addr)) return; - writew(val, host->ctl + (addr << host->pdata->bus_shift)); + writew(val, host->ctl + (addr << host->bus_shift)); } static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, u16 *buf, int count) { - writesw(host->ctl + (addr << host->pdata->bus_shift), buf, count); + writesw(host->ctl + (addr << host->bus_shift), buf, count); } static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) { - writew(val, host->ctl + (addr << host->pdata->bus_shift)); - writew(val >> 16, host->ctl + ((addr + 2) << host->pdata->bus_shift)); + writew(val, host->ctl + (addr << host->bus_shift)); + writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); } diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index 7d077388b9eb..331bb618e398 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -28,8 +28,8 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) if (!host->chan_tx || !host->chan_rx) return; - if (host->pdata->flags & TMIO_MMC_HAVE_CTL_DMA_REG) - sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); + if (host->dma->enable) + host->dma->enable(host, enable); } void tmio_mmc_abort_dma(struct tmio_mmc_host *host) @@ -49,11 +49,10 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; - struct tmio_mmc_data *pdata = host->pdata; dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; - unsigned int align = (1 << pdata->dma->alignment_shift) - 1; + unsigned int align = (1 << host->pdata->alignment_shift) - 1; for_each_sg(sg, sg_tmp, host->sg_len, i) { if (sg_tmp->offset & align) @@ -126,11 +125,10 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; - struct tmio_mmc_data *pdata = host->pdata; dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; - unsigned int align = (1 << pdata->dma->alignment_shift) - 1; + unsigned int align = (1 << host->pdata->alignment_shift) - 1; for_each_sg(sg, sg_tmp, host->sg_len, i) { if (sg_tmp->offset & align) @@ -262,8 +260,8 @@ out: void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata) { /* We can only either use DMA for both Tx and Rx or not use it at all */ - if (!pdata->dma || (!host->pdev->dev.of_node && - (!pdata->dma->chan_priv_tx || !pdata->dma->chan_priv_rx))) + if (!host->dma || (!host->pdev->dev.of_node && + (!host->dma->chan_priv_tx || !host->dma->chan_priv_rx))) return; if (!host->chan_tx && !host->chan_rx) { @@ -280,7 +278,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat dma_cap_set(DMA_SLAVE, mask); host->chan_tx = dma_request_slave_channel_compat(mask, - pdata->dma->filter, pdata->dma->chan_priv_tx, + host->dma->filter, host->dma->chan_priv_tx, &host->pdev->dev, "tx"); dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, host->chan_tx); @@ -288,18 +286,20 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat if (!host->chan_tx) return; - if (pdata->dma->chan_priv_tx) - cfg.slave_id = pdata->dma->slave_id_tx; + if (host->dma->chan_priv_tx) + cfg.slave_id = host->dma->slave_id_tx; cfg.direction = DMA_MEM_TO_DEV; - cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->pdata->bus_shift); - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift); + cfg.dst_addr_width = host->dma->dma_buswidth; + if (!cfg.dst_addr_width) + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; cfg.src_addr = 0; ret = dmaengine_slave_config(host->chan_tx, &cfg); if (ret < 0) goto ecfgtx; host->chan_rx = dma_request_slave_channel_compat(mask, - pdata->dma->filter, pdata->dma->chan_priv_rx, + host->dma->filter, host->dma->chan_priv_rx, &host->pdev->dev, "rx"); dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, host->chan_rx); @@ -307,11 +307,13 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat if (!host->chan_rx) goto ereqrx; - if (pdata->dma->chan_priv_rx) - cfg.slave_id = pdata->dma->slave_id_rx; + if (host->dma->chan_priv_rx) + cfg.slave_id = host->dma->slave_id_rx; cfg.direction = DMA_DEV_TO_MEM; - cfg.src_addr = cfg.dst_addr + pdata->dma->dma_rx_offset; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset; + cfg.src_addr_width = host->dma->dma_buswidth; + if (!cfg.src_addr_width) + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; cfg.dst_addr = 0; ret = dmaengine_slave_config(host->chan_rx, &cfg); if (ret < 0) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 250bf8c9f998..dba7e1c19dd7 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -835,13 +835,12 @@ fail: static int tmio_mmc_clk_update(struct tmio_mmc_host *host) { struct mmc_host *mmc = host->mmc; - struct tmio_mmc_data *pdata = host->pdata; int ret; - if (!pdata->clk_enable) + if (!host->clk_enable) return -ENOTSUPP; - ret = pdata->clk_enable(host->pdev, &mmc->f_max); + ret = host->clk_enable(host->pdev, &mmc->f_max); if (!ret) mmc->f_min = mmc->f_max / 512; @@ -1005,10 +1004,9 @@ static int tmio_multi_io_quirk(struct mmc_card *card, unsigned int direction, int blk_size) { struct tmio_mmc_host *host = mmc_priv(card->host); - struct tmio_mmc_data *pdata = host->pdata; - if (pdata->multi_io_quirk) - return pdata->multi_io_quirk(card, direction, blk_size); + if (host->multi_io_quirk) + return host->multi_io_quirk(card, direction, blk_size); return blk_size; } @@ -1054,12 +1052,35 @@ static void tmio_mmc_of_parse(struct platform_device *pdev, pdata->flags |= TMIO_MMC_WRPROTECT_DISABLE; } -int tmio_mmc_host_probe(struct tmio_mmc_host **host, - struct platform_device *pdev, - struct tmio_mmc_data *pdata) +struct tmio_mmc_host* +tmio_mmc_host_alloc(struct platform_device *pdev) { - struct tmio_mmc_host *_host; + struct tmio_mmc_host *host; struct mmc_host *mmc; + + mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); + if (!mmc) + return NULL; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->pdev = pdev; + + return host; +} +EXPORT_SYMBOL(tmio_mmc_host_alloc); + +void tmio_mmc_host_free(struct tmio_mmc_host *host) +{ + mmc_free_host(host->mmc); +} +EXPORT_SYMBOL(tmio_mmc_host_free); + +int tmio_mmc_host_probe(struct tmio_mmc_host *_host, + struct tmio_mmc_data *pdata) +{ + struct platform_device *pdev = _host->pdev; + struct mmc_host *mmc = _host->mmc; struct resource *res_ctl; int ret; u32 irq_mask = TMIO_MASK_CMD; @@ -1067,25 +1088,17 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, tmio_mmc_of_parse(pdev, pdata); if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT)) - pdata->write16_hook = NULL; + _host->write16_hook = NULL; res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_ctl) return -EINVAL; - mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); - if (!mmc) - return -ENOMEM; - ret = mmc_of_parse(mmc); if (ret < 0) goto host_free; - pdata->dev = &pdev->dev; - _host = mmc_priv(mmc); _host->pdata = pdata; - _host->mmc = mmc; - _host->pdev = pdev; platform_set_drvdata(pdev, mmc); _host->set_pwr = pdata->set_pwr; @@ -1192,12 +1205,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, mmc_gpiod_request_cd_irq(mmc); } - *host = _host; - return 0; host_free: - mmc_free_host(mmc); return ret; } @@ -1222,7 +1232,6 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) pm_runtime_disable(&pdev->dev); iounmap(host->ctl); - mmc_free_host(mmc); } EXPORT_SYMBOL(tmio_mmc_host_remove); @@ -1237,8 +1246,8 @@ int tmio_mmc_host_runtime_suspend(struct device *dev) if (host->clk_cache) tmio_mmc_clk_stop(host); - if (host->pdata->clk_disable) - host->pdata->clk_disable(host->pdev); + if (host->clk_disable) + host->clk_disable(host->pdev); return 0; } diff --git a/drivers/mmc/host/toshsd.c b/drivers/mmc/host/toshsd.c new file mode 100644 index 000000000000..e2cdd5fb1423 --- /dev/null +++ b/drivers/mmc/host/toshsd.c @@ -0,0 +1,708 @@ +/* + * Toshiba PCI Secure Digital Host Controller Interface driver + * + * Copyright (C) 2014 Ondrej Zary + * Copyright (C) 2007 Richard Betts, All Rights Reserved. + * + * Based on asic3_mmc.c, copyright (c) 2005 SDG Systems, LLC and, + * sdhci.c, copyright (C) 2005-2006 Pierre Ossman + * + * 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 <linux/delay.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/scatterlist.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/pm.h> +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> + +#include "toshsd.h" + +#define DRIVER_NAME "toshsd" + +static const struct pci_device_id pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA, 0x0805) }, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(pci, pci_ids); + +static void toshsd_init(struct toshsd_host *host) +{ + /* enable clock */ + pci_write_config_byte(host->pdev, SD_PCICFG_CLKSTOP, + SD_PCICFG_CLKSTOP_ENABLE_ALL); + pci_write_config_byte(host->pdev, SD_PCICFG_CARDDETECT, 2); + + /* reset */ + iowrite16(0, host->ioaddr + SD_SOFTWARERESET); /* assert */ + mdelay(2); + iowrite16(1, host->ioaddr + SD_SOFTWARERESET); /* deassert */ + mdelay(2); + + /* Clear card registers */ + iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL); + iowrite32(0, host->ioaddr + SD_CARDSTATUS); + iowrite32(0, host->ioaddr + SD_ERRORSTATUS0); + iowrite16(0, host->ioaddr + SD_STOPINTERNAL); + + /* SDIO clock? */ + iowrite16(0x100, host->ioaddr + SDIO_BASE + SDIO_CLOCKNWAITCTRL); + + /* enable LED */ + pci_write_config_byte(host->pdev, SD_PCICFG_SDLED_ENABLE1, + SD_PCICFG_LED_ENABLE1_START); + pci_write_config_byte(host->pdev, SD_PCICFG_SDLED_ENABLE2, + SD_PCICFG_LED_ENABLE2_START); + + /* set interrupt masks */ + iowrite32(~(u32)(SD_CARD_RESP_END | SD_CARD_RW_END + | SD_CARD_CARD_REMOVED_0 | SD_CARD_CARD_INSERTED_0 + | SD_BUF_READ_ENABLE | SD_BUF_WRITE_ENABLE + | SD_BUF_CMD_TIMEOUT), + host->ioaddr + SD_INTMASKCARD); + + iowrite16(0x1000, host->ioaddr + SD_TRANSACTIONCTRL); +} + +/* Set MMC clock / power. + * Note: This controller uses a simple divider scheme therefore it cannot run + * SD/MMC cards at full speed (24/20MHz). HCLK (=33MHz PCI clock?) is too high + * and the next slowest is 16MHz (div=2). + */ +static void __toshsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct toshsd_host *host = mmc_priv(mmc); + + if (ios->clock) { + u16 clk; + int div = 1; + + while (ios->clock < HCLK / div) + div *= 2; + + clk = div >> 2; + + if (div == 1) { /* disable the divider */ + pci_write_config_byte(host->pdev, SD_PCICFG_CLKMODE, + SD_PCICFG_CLKMODE_DIV_DISABLE); + clk |= SD_CARDCLK_DIV_DISABLE; + } else + pci_write_config_byte(host->pdev, SD_PCICFG_CLKMODE, 0); + + clk |= SD_CARDCLK_ENABLE_CLOCK; + iowrite16(clk, host->ioaddr + SD_CARDCLOCKCTRL); + + mdelay(10); + } else + iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL); + + switch (ios->power_mode) { + case MMC_POWER_OFF: + pci_write_config_byte(host->pdev, SD_PCICFG_POWER1, + SD_PCICFG_PWR1_OFF); + mdelay(1); + break; + case MMC_POWER_UP: + break; + case MMC_POWER_ON: + pci_write_config_byte(host->pdev, SD_PCICFG_POWER1, + SD_PCICFG_PWR1_33V); + pci_write_config_byte(host->pdev, SD_PCICFG_POWER2, + SD_PCICFG_PWR2_AUTO); + mdelay(20); + break; + } + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + iowrite16(SD_CARDOPT_REQUIRED | SD_CARDOPT_DATA_RESP_TIMEOUT(14) + | SD_CARDOPT_C2_MODULE_ABSENT + | SD_CARDOPT_DATA_XFR_WIDTH_1, + host->ioaddr + SD_CARDOPTIONSETUP); + break; + case MMC_BUS_WIDTH_4: + iowrite16(SD_CARDOPT_REQUIRED | SD_CARDOPT_DATA_RESP_TIMEOUT(14) + | SD_CARDOPT_C2_MODULE_ABSENT + | SD_CARDOPT_DATA_XFR_WIDTH_4, + host->ioaddr + SD_CARDOPTIONSETUP); + break; + } +} + +static void toshsd_set_led(struct toshsd_host *host, unsigned char state) +{ + iowrite16(state, host->ioaddr + SDIO_BASE + SDIO_LEDCTRL); +} + +static void toshsd_finish_request(struct toshsd_host *host) +{ + struct mmc_request *mrq = host->mrq; + + /* Write something to end the command */ + host->mrq = NULL; + host->cmd = NULL; + host->data = NULL; + + toshsd_set_led(host, 0); + mmc_request_done(host->mmc, mrq); +} + +static irqreturn_t toshsd_thread_irq(int irq, void *dev_id) +{ + struct toshsd_host *host = dev_id; + struct mmc_data *data = host->data; + struct sg_mapping_iter *sg_miter = &host->sg_miter; + unsigned short *buf; + int count; + unsigned long flags; + + if (!data) { + dev_warn(&host->pdev->dev, "Spurious Data IRQ\n"); + if (host->cmd) { + host->cmd->error = -EIO; + toshsd_finish_request(host); + } + return IRQ_NONE; + } + spin_lock_irqsave(&host->lock, flags); + + if (!sg_miter_next(sg_miter)) + goto done; + + buf = sg_miter->addr; + + /* Ensure we dont read more than one block. The chip will interrupt us + * When the next block is available. + */ + count = sg_miter->length; + if (count > data->blksz) + count = data->blksz; + + dev_dbg(&host->pdev->dev, "count: %08x, flags %08x\n", count, + data->flags); + + /* Transfer the data */ + if (data->flags & MMC_DATA_READ) + ioread32_rep(host->ioaddr + SD_DATAPORT, buf, count >> 2); + else + iowrite32_rep(host->ioaddr + SD_DATAPORT, buf, count >> 2); + + sg_miter->consumed = count; + sg_miter_stop(sg_miter); + +done: + spin_unlock_irqrestore(&host->lock, flags); + + return IRQ_HANDLED; +} + +static void toshsd_cmd_irq(struct toshsd_host *host) +{ + struct mmc_command *cmd = host->cmd; + u8 *buf; + u16 data; + + if (!host->cmd) { + dev_warn(&host->pdev->dev, "Spurious CMD irq\n"); + return; + } + buf = (u8 *)cmd->resp; + host->cmd = NULL; + + if (cmd->flags & MMC_RSP_PRESENT && cmd->flags & MMC_RSP_136) { + /* R2 */ + buf[12] = 0xff; + data = ioread16(host->ioaddr + SD_RESPONSE0); + buf[13] = data & 0xff; + buf[14] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE1); + buf[15] = data & 0xff; + buf[8] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE2); + buf[9] = data & 0xff; + buf[10] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE3); + buf[11] = data & 0xff; + buf[4] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE4); + buf[5] = data & 0xff; + buf[6] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE5); + buf[7] = data & 0xff; + buf[0] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE6); + buf[1] = data & 0xff; + buf[2] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE7); + buf[3] = data & 0xff; + } else if (cmd->flags & MMC_RSP_PRESENT) { + /* R1, R1B, R3, R6, R7 */ + data = ioread16(host->ioaddr + SD_RESPONSE0); + buf[0] = data & 0xff; + buf[1] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE1); + buf[2] = data & 0xff; + buf[3] = data >> 8; + } + + dev_dbg(&host->pdev->dev, "Command IRQ complete %d %d %x\n", + cmd->opcode, cmd->error, cmd->flags); + + /* If there is data to handle we will + * finish the request in the mmc_data_end_irq handler.*/ + if (host->data) + return; + + toshsd_finish_request(host); +} + +static void toshsd_data_end_irq(struct toshsd_host *host) +{ + struct mmc_data *data = host->data; + + host->data = NULL; + + if (!data) { + dev_warn(&host->pdev->dev, "Spurious data end IRQ\n"); + return; + } + + if (data->error == 0) + data->bytes_xfered = data->blocks * data->blksz; + else + data->bytes_xfered = 0; + + dev_dbg(&host->pdev->dev, "Completed data request xfr=%d\n", + data->bytes_xfered); + + iowrite16(0, host->ioaddr + SD_STOPINTERNAL); + + toshsd_finish_request(host); +} + +static irqreturn_t toshsd_irq(int irq, void *dev_id) +{ + struct toshsd_host *host = dev_id; + u32 int_reg, int_mask, int_status, detail; + int error = 0, ret = IRQ_HANDLED; + + spin_lock(&host->lock); + int_status = ioread32(host->ioaddr + SD_CARDSTATUS); + int_mask = ioread32(host->ioaddr + SD_INTMASKCARD); + int_reg = int_status & ~int_mask & ~IRQ_DONT_CARE_BITS; + + dev_dbg(&host->pdev->dev, "IRQ status:%x mask:%x\n", + int_status, int_mask); + + /* nothing to do: it's not our IRQ */ + if (!int_reg) { + ret = IRQ_NONE; + goto irq_end; + } + + if (int_reg & SD_BUF_CMD_TIMEOUT) { + error = -ETIMEDOUT; + dev_dbg(&host->pdev->dev, "Timeout\n"); + } else if (int_reg & SD_BUF_CRC_ERR) { + error = -EILSEQ; + dev_err(&host->pdev->dev, "BadCRC\n"); + } else if (int_reg & (SD_BUF_ILLEGAL_ACCESS + | SD_BUF_CMD_INDEX_ERR + | SD_BUF_STOP_BIT_END_ERR + | SD_BUF_OVERFLOW + | SD_BUF_UNDERFLOW + | SD_BUF_DATA_TIMEOUT)) { + dev_err(&host->pdev->dev, "Buffer status error: { %s%s%s%s%s%s}\n", + int_reg & SD_BUF_ILLEGAL_ACCESS ? "ILLEGAL_ACC " : "", + int_reg & SD_BUF_CMD_INDEX_ERR ? "CMD_INDEX " : "", + int_reg & SD_BUF_STOP_BIT_END_ERR ? "STOPBIT_END " : "", + int_reg & SD_BUF_OVERFLOW ? "OVERFLOW " : "", + int_reg & SD_BUF_UNDERFLOW ? "UNDERFLOW " : "", + int_reg & SD_BUF_DATA_TIMEOUT ? "DATA_TIMEOUT " : ""); + + detail = ioread32(host->ioaddr + SD_ERRORSTATUS0); + dev_err(&host->pdev->dev, "detail error status { %s%s%s%s%s%s%s%s%s%s%s%s%s}\n", + detail & SD_ERR0_RESP_CMD_ERR ? "RESP_CMD " : "", + detail & SD_ERR0_RESP_NON_CMD12_END_BIT_ERR ? "RESP_END_BIT " : "", + detail & SD_ERR0_RESP_CMD12_END_BIT_ERR ? "RESP_END_BIT " : "", + detail & SD_ERR0_READ_DATA_END_BIT_ERR ? "READ_DATA_END_BIT " : "", + detail & SD_ERR0_WRITE_CRC_STATUS_END_BIT_ERR ? "WRITE_CMD_END_BIT " : "", + detail & SD_ERR0_RESP_NON_CMD12_CRC_ERR ? "RESP_CRC " : "", + detail & SD_ERR0_RESP_CMD12_CRC_ERR ? "RESP_CRC " : "", + detail & SD_ERR0_READ_DATA_CRC_ERR ? "READ_DATA_CRC " : "", + detail & SD_ERR0_WRITE_CMD_CRC_ERR ? "WRITE_CMD_CRC " : "", + detail & SD_ERR1_NO_CMD_RESP ? "NO_CMD_RESP " : "", + detail & SD_ERR1_TIMEOUT_READ_DATA ? "READ_DATA_TIMEOUT " : "", + detail & SD_ERR1_TIMEOUT_CRS_STATUS ? "CRS_STATUS_TIMEOUT " : "", + detail & SD_ERR1_TIMEOUT_CRC_BUSY ? "CRC_BUSY_TIMEOUT " : ""); + error = -EIO; + } + + if (error) { + if (host->cmd) + host->cmd->error = error; + + if (error == -ETIMEDOUT) { + iowrite32(int_status & + ~(SD_BUF_CMD_TIMEOUT | SD_CARD_RESP_END), + host->ioaddr + SD_CARDSTATUS); + } else { + toshsd_init(host); + __toshsd_set_ios(host->mmc, &host->mmc->ios); + goto irq_end; + } + } + + /* Card insert/remove. The mmc controlling code is stateless. */ + if (int_reg & (SD_CARD_CARD_INSERTED_0 | SD_CARD_CARD_REMOVED_0)) { + iowrite32(int_status & + ~(SD_CARD_CARD_REMOVED_0 | SD_CARD_CARD_INSERTED_0), + host->ioaddr + SD_CARDSTATUS); + + if (int_reg & SD_CARD_CARD_INSERTED_0) + toshsd_init(host); + + mmc_detect_change(host->mmc, 1); + } + + /* Data transfer */ + if (int_reg & (SD_BUF_READ_ENABLE | SD_BUF_WRITE_ENABLE)) { + iowrite32(int_status & + ~(SD_BUF_WRITE_ENABLE | SD_BUF_READ_ENABLE), + host->ioaddr + SD_CARDSTATUS); + + ret = IRQ_WAKE_THREAD; + goto irq_end; + } + + /* Command completion */ + if (int_reg & SD_CARD_RESP_END) { + iowrite32(int_status & ~(SD_CARD_RESP_END), + host->ioaddr + SD_CARDSTATUS); + toshsd_cmd_irq(host); + } + + /* Data transfer completion */ + if (int_reg & SD_CARD_RW_END) { + iowrite32(int_status & ~(SD_CARD_RW_END), + host->ioaddr + SD_CARDSTATUS); + toshsd_data_end_irq(host); + } +irq_end: + spin_unlock(&host->lock); + return ret; +} + +static void toshsd_start_cmd(struct toshsd_host *host, struct mmc_command *cmd) +{ + struct mmc_data *data = host->data; + int c = cmd->opcode; + + dev_dbg(&host->pdev->dev, "Command opcode: %d\n", cmd->opcode); + + if (cmd->opcode == MMC_STOP_TRANSMISSION) { + iowrite16(SD_STOPINT_ISSUE_CMD12, + host->ioaddr + SD_STOPINTERNAL); + + cmd->resp[0] = cmd->opcode; + cmd->resp[1] = 0; + cmd->resp[2] = 0; + cmd->resp[3] = 0; + + toshsd_finish_request(host); + return; + } + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + c |= SD_CMD_RESP_TYPE_NONE; + break; + + case MMC_RSP_R1: + c |= SD_CMD_RESP_TYPE_EXT_R1; + break; + case MMC_RSP_R1B: + c |= SD_CMD_RESP_TYPE_EXT_R1B; + break; + case MMC_RSP_R2: + c |= SD_CMD_RESP_TYPE_EXT_R2; + break; + case MMC_RSP_R3: + c |= SD_CMD_RESP_TYPE_EXT_R3; + break; + + default: + dev_err(&host->pdev->dev, "Unknown response type %d\n", + mmc_resp_type(cmd)); + break; + } + + host->cmd = cmd; + + if (cmd->opcode == MMC_APP_CMD) + c |= SD_CMD_TYPE_ACMD; + + if (cmd->opcode == MMC_GO_IDLE_STATE) + c |= (3 << 8); /* removed from ipaq-asic3.h for some reason */ + + if (data) { + c |= SD_CMD_DATA_PRESENT; + + if (data->blocks > 1) { + iowrite16(SD_STOPINT_AUTO_ISSUE_CMD12, + host->ioaddr + SD_STOPINTERNAL); + c |= SD_CMD_MULTI_BLOCK; + } + + if (data->flags & MMC_DATA_READ) + c |= SD_CMD_TRANSFER_READ; + + /* MMC_DATA_WRITE does not require a bit to be set */ + } + + /* Send the command */ + iowrite32(cmd->arg, host->ioaddr + SD_ARG0); + iowrite16(c, host->ioaddr + SD_CMD); +} + +static void toshsd_start_data(struct toshsd_host *host, struct mmc_data *data) +{ + unsigned int flags = SG_MITER_ATOMIC; + + dev_dbg(&host->pdev->dev, "setup data transfer: blocksize %08x nr_blocks %d, offset: %08x\n", + data->blksz, data->blocks, data->sg->offset); + + host->data = data; + + if (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); + + /* Set transfer length and blocksize */ + iowrite16(data->blocks, host->ioaddr + SD_BLOCKCOUNT); + iowrite16(data->blksz, host->ioaddr + SD_CARDXFERDATALEN); +} + +/* Process requests from the MMC layer */ +static void toshsd_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct toshsd_host *host = mmc_priv(mmc); + unsigned long flags; + + /* abort if card not present */ + if (!(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_PRESENT_0)) { + mrq->cmd->error = -ENOMEDIUM; + mmc_request_done(mmc, mrq); + return; + } + + spin_lock_irqsave(&host->lock, flags); + + WARN_ON(host->mrq != NULL); + + host->mrq = mrq; + + if (mrq->data) + toshsd_start_data(host, mrq->data); + + toshsd_set_led(host, 1); + + toshsd_start_cmd(host, mrq->cmd); + + spin_unlock_irqrestore(&host->lock, flags); +} + +static void toshsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct toshsd_host *host = mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + __toshsd_set_ios(mmc, ios); + spin_unlock_irqrestore(&host->lock, flags); +} + +static int toshsd_get_ro(struct mmc_host *mmc) +{ + struct toshsd_host *host = mmc_priv(mmc); + + /* active low */ + return !(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_WRITE_PROTECT); +} + +static int toshsd_get_cd(struct mmc_host *mmc) +{ + struct toshsd_host *host = mmc_priv(mmc); + + return !!(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_PRESENT_0); +} + +static struct mmc_host_ops toshsd_ops = { + .request = toshsd_request, + .set_ios = toshsd_set_ios, + .get_ro = toshsd_get_ro, + .get_cd = toshsd_get_cd, +}; + + +static void toshsd_powerdown(struct toshsd_host *host) +{ + /* mask all interrupts */ + iowrite32(0xffffffff, host->ioaddr + SD_INTMASKCARD); + /* disable card clock */ + iowrite16(0x000, host->ioaddr + SDIO_BASE + SDIO_CLOCKNWAITCTRL); + iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL); + /* power down card */ + pci_write_config_byte(host->pdev, SD_PCICFG_POWER1, SD_PCICFG_PWR1_OFF); + /* disable clock */ + pci_write_config_byte(host->pdev, SD_PCICFG_CLKSTOP, 0); +} + +#ifdef CONFIG_PM_SLEEP +static int toshsd_pm_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct toshsd_host *host = pci_get_drvdata(pdev); + + toshsd_powerdown(host); + + pci_save_state(pdev); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int toshsd_pm_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct toshsd_host *host = pci_get_drvdata(pdev); + int ret; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) + return ret; + + toshsd_init(host); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int ret; + struct toshsd_host *host; + struct mmc_host *mmc; + resource_size_t base; + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + mmc = mmc_alloc_host(sizeof(struct toshsd_host), &pdev->dev); + if (!mmc) { + ret = -ENOMEM; + goto err; + } + + host = mmc_priv(mmc); + host->mmc = mmc; + + host->pdev = pdev; + pci_set_drvdata(pdev, host); + + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret) + goto free; + + host->ioaddr = pci_iomap(pdev, 0, 0); + if (!host->ioaddr) { + ret = -ENOMEM; + goto release; + } + + /* Set MMC host parameters */ + mmc->ops = &toshsd_ops; + mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->ocr_avail = MMC_VDD_32_33; + + mmc->f_min = HCLK / 512; + mmc->f_max = HCLK; + + spin_lock_init(&host->lock); + + toshsd_init(host); + + ret = request_threaded_irq(pdev->irq, toshsd_irq, toshsd_thread_irq, + IRQF_SHARED, DRIVER_NAME, host); + if (ret) + goto unmap; + + mmc_add_host(mmc); + + base = pci_resource_start(pdev, 0); + dev_dbg(&pdev->dev, "MMIO %pa, IRQ %d\n", &base, pdev->irq); + + pm_suspend_ignore_children(&pdev->dev, 1); + + return 0; + +unmap: + pci_iounmap(pdev, host->ioaddr); +release: + pci_release_regions(pdev); +free: + mmc_free_host(mmc); + pci_set_drvdata(pdev, NULL); +err: + pci_disable_device(pdev); + return ret; +} + +static void toshsd_remove(struct pci_dev *pdev) +{ + struct toshsd_host *host = pci_get_drvdata(pdev); + + mmc_remove_host(host->mmc); + toshsd_powerdown(host); + free_irq(pdev->irq, host); + pci_iounmap(pdev, host->ioaddr); + pci_release_regions(pdev); + mmc_free_host(host->mmc); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); +} + +static const struct dev_pm_ops toshsd_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(toshsd_pm_suspend, toshsd_pm_resume) +}; + +static struct pci_driver toshsd_driver = { + .name = DRIVER_NAME, + .id_table = pci_ids, + .probe = toshsd_probe, + .remove = toshsd_remove, + .driver.pm = &toshsd_pm_ops, +}; + +module_pci_driver(toshsd_driver); + +MODULE_AUTHOR("Ondrej Zary, Richard Betts"); +MODULE_DESCRIPTION("Toshiba PCI Secure Digital Host Controller Interface driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/toshsd.h b/drivers/mmc/host/toshsd.h new file mode 100644 index 000000000000..b6c0d89e53a6 --- /dev/null +++ b/drivers/mmc/host/toshsd.h @@ -0,0 +1,176 @@ +/* + * Toshiba PCI Secure Digital Host Controller Interface driver + * + * Copyright (C) 2014 Ondrej Zary + * Copyright (C) 2007 Richard Betts, All Rights Reserved. + * + * Based on asic3_mmc.c Copyright (c) 2005 SDG Systems, LLC + * + * 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. + */ + +#define HCLK 33000000 /* 33 MHz (PCI clock) */ + +#define SD_PCICFG_CLKSTOP 0x40 /* 0x1f = clock controller, 0 = stop */ +#define SD_PCICFG_GATEDCLK 0x41 /* Gated clock */ +#define SD_PCICFG_CLKMODE 0x42 /* Control clock of SD controller */ +#define SD_PCICFG_PINSTATUS 0x44 /* R/O: read status of SD pins */ +#define SD_PCICFG_POWER1 0x48 +#define SD_PCICFG_POWER2 0x49 +#define SD_PCICFG_POWER3 0x4a +#define SD_PCICFG_CARDDETECT 0x4c +#define SD_PCICFG_SLOTS 0x50 /* R/O: define support slot number */ +#define SD_PCICFG_EXTGATECLK1 0xf0 /* Could be used for gated clock */ +#define SD_PCICFG_EXTGATECLK2 0xf1 /* Could be used for gated clock */ +#define SD_PCICFG_EXTGATECLK3 0xf9 /* Bit 1: double buffer/single buffer */ +#define SD_PCICFG_SDLED_ENABLE1 0xfa +#define SD_PCICFG_SDLED_ENABLE2 0xfe + +#define SD_PCICFG_CLKMODE_DIV_DISABLE BIT(0) +#define SD_PCICFG_CLKSTOP_ENABLE_ALL 0x1f +#define SD_PCICFG_LED_ENABLE1_START 0x12 +#define SD_PCICFG_LED_ENABLE2_START 0x80 + +#define SD_PCICFG_PWR1_33V 0x08 /* Set for 3.3 volts */ +#define SD_PCICFG_PWR1_OFF 0x00 /* Turn off power */ +#define SD_PCICFG_PWR2_AUTO 0x02 + +#define SD_CMD 0x00 /* also for SDIO */ +#define SD_ARG0 0x04 /* also for SDIO */ +#define SD_ARG1 0x06 /* also for SDIO */ +#define SD_STOPINTERNAL 0x08 +#define SD_BLOCKCOUNT 0x0a /* also for SDIO */ +#define SD_RESPONSE0 0x0c /* also for SDIO */ +#define SD_RESPONSE1 0x0e /* also for SDIO */ +#define SD_RESPONSE2 0x10 /* also for SDIO */ +#define SD_RESPONSE3 0x12 /* also for SDIO */ +#define SD_RESPONSE4 0x14 /* also for SDIO */ +#define SD_RESPONSE5 0x16 /* also for SDIO */ +#define SD_RESPONSE6 0x18 /* also for SDIO */ +#define SD_RESPONSE7 0x1a /* also for SDIO */ +#define SD_CARDSTATUS 0x1c /* also for SDIO */ +#define SD_BUFFERCTRL 0x1e /* also for SDIO */ +#define SD_INTMASKCARD 0x20 /* also for SDIO */ +#define SD_INTMASKBUFFER 0x22 /* also for SDIO */ +#define SD_CARDCLOCKCTRL 0x24 +#define SD_CARDXFERDATALEN 0x26 /* also for SDIO */ +#define SD_CARDOPTIONSETUP 0x28 /* also for SDIO */ +#define SD_ERRORSTATUS0 0x2c /* also for SDIO */ +#define SD_ERRORSTATUS1 0x2e /* also for SDIO */ +#define SD_DATAPORT 0x30 /* also for SDIO */ +#define SD_TRANSACTIONCTRL 0x34 /* also for SDIO */ +#define SD_SOFTWARERESET 0xe0 /* also for SDIO */ + +/* registers above marked "also for SDIO" and all SDIO registers below can be + * accessed at SDIO_BASE + reg address */ +#define SDIO_BASE 0x100 + +#define SDIO_CARDPORTSEL 0x02 +#define SDIO_CARDINTCTRL 0x36 +#define SDIO_CLOCKNWAITCTRL 0x38 +#define SDIO_HOSTINFORMATION 0x3a +#define SDIO_ERRORCTRL 0x3c +#define SDIO_LEDCTRL 0x3e + +#define SD_TRANSCTL_SET BIT(8) + +#define SD_CARDCLK_DIV_DISABLE BIT(15) +#define SD_CARDCLK_ENABLE_CLOCK BIT(8) +#define SD_CARDCLK_CLK_DIV_512 BIT(7) +#define SD_CARDCLK_CLK_DIV_256 BIT(6) +#define SD_CARDCLK_CLK_DIV_128 BIT(5) +#define SD_CARDCLK_CLK_DIV_64 BIT(4) +#define SD_CARDCLK_CLK_DIV_32 BIT(3) +#define SD_CARDCLK_CLK_DIV_16 BIT(2) +#define SD_CARDCLK_CLK_DIV_8 BIT(1) +#define SD_CARDCLK_CLK_DIV_4 BIT(0) +#define SD_CARDCLK_CLK_DIV_2 0 + +#define SD_CARDOPT_REQUIRED 0x000e +#define SD_CARDOPT_DATA_RESP_TIMEOUT(x) (((x) & 0x0f) << 4) /* 4 bits */ +#define SD_CARDOPT_C2_MODULE_ABSENT BIT(14) +#define SD_CARDOPT_DATA_XFR_WIDTH_1 (1 << 15) +#define SD_CARDOPT_DATA_XFR_WIDTH_4 (0 << 15) + +#define SD_CMD_TYPE_CMD (0 << 6) +#define SD_CMD_TYPE_ACMD (1 << 6) +#define SD_CMD_TYPE_AUTHEN (2 << 6) +#define SD_CMD_RESP_TYPE_NONE (3 << 8) +#define SD_CMD_RESP_TYPE_EXT_R1 (4 << 8) +#define SD_CMD_RESP_TYPE_EXT_R1B (5 << 8) +#define SD_CMD_RESP_TYPE_EXT_R2 (6 << 8) +#define SD_CMD_RESP_TYPE_EXT_R3 (7 << 8) +#define SD_CMD_RESP_TYPE_EXT_R6 (4 << 8) +#define SD_CMD_RESP_TYPE_EXT_R7 (4 << 8) +#define SD_CMD_DATA_PRESENT BIT(11) +#define SD_CMD_TRANSFER_READ BIT(12) +#define SD_CMD_MULTI_BLOCK BIT(13) +#define SD_CMD_SECURITY_CMD BIT(14) + +#define SD_STOPINT_ISSUE_CMD12 BIT(0) +#define SD_STOPINT_AUTO_ISSUE_CMD12 BIT(8) + +#define SD_CARD_RESP_END BIT(0) +#define SD_CARD_RW_END BIT(2) +#define SD_CARD_CARD_REMOVED_0 BIT(3) +#define SD_CARD_CARD_INSERTED_0 BIT(4) +#define SD_CARD_PRESENT_0 BIT(5) +#define SD_CARD_UNK6 BIT(6) +#define SD_CARD_WRITE_PROTECT BIT(7) +#define SD_CARD_CARD_REMOVED_3 BIT(8) +#define SD_CARD_CARD_INSERTED_3 BIT(9) +#define SD_CARD_PRESENT_3 BIT(10) + +#define SD_BUF_CMD_INDEX_ERR BIT(16) +#define SD_BUF_CRC_ERR BIT(17) +#define SD_BUF_STOP_BIT_END_ERR BIT(18) +#define SD_BUF_DATA_TIMEOUT BIT(19) +#define SD_BUF_OVERFLOW BIT(20) +#define SD_BUF_UNDERFLOW BIT(21) +#define SD_BUF_CMD_TIMEOUT BIT(22) +#define SD_BUF_UNK7 BIT(23) +#define SD_BUF_READ_ENABLE BIT(24) +#define SD_BUF_WRITE_ENABLE BIT(25) +#define SD_BUF_ILLEGAL_FUNCTION BIT(29) +#define SD_BUF_CMD_BUSY BIT(30) +#define SD_BUF_ILLEGAL_ACCESS BIT(31) + +#define SD_ERR0_RESP_CMD_ERR BIT(0) +#define SD_ERR0_RESP_NON_CMD12_END_BIT_ERR BIT(2) +#define SD_ERR0_RESP_CMD12_END_BIT_ERR BIT(3) +#define SD_ERR0_READ_DATA_END_BIT_ERR BIT(4) +#define SD_ERR0_WRITE_CRC_STATUS_END_BIT_ERR BIT(5) +#define SD_ERR0_RESP_NON_CMD12_CRC_ERR BIT(8) +#define SD_ERR0_RESP_CMD12_CRC_ERR BIT(9) +#define SD_ERR0_READ_DATA_CRC_ERR BIT(10) +#define SD_ERR0_WRITE_CMD_CRC_ERR BIT(11) + +#define SD_ERR1_NO_CMD_RESP BIT(16) +#define SD_ERR1_TIMEOUT_READ_DATA BIT(20) +#define SD_ERR1_TIMEOUT_CRS_STATUS BIT(21) +#define SD_ERR1_TIMEOUT_CRC_BUSY BIT(22) + +#define IRQ_DONT_CARE_BITS (SD_CARD_PRESENT_3 \ + | SD_CARD_WRITE_PROTECT \ + | SD_CARD_UNK6 \ + | SD_CARD_PRESENT_0 \ + | SD_BUF_UNK7 \ + | SD_BUF_CMD_BUSY) + +struct toshsd_host { + struct pci_dev *pdev; + struct mmc_host *mmc; + + spinlock_t lock; + + struct mmc_request *mrq;/* Current request */ + struct mmc_command *cmd;/* Current command */ + struct mmc_data *data; /* Current data request */ + + struct sg_mapping_iter sg_miter; /* for PIO */ + + void __iomem *ioaddr; /* mapped address */ +}; diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index f0a39eb049af..54b082b1804a 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1834,7 +1834,6 @@ static struct platform_driver usdhi6_driver = { .remove = usdhi6_remove, .driver = { .name = "usdhi6rol0", - .owner = THIS_MODULE, .of_match_table = usdhi6_of_match, }, }; diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 4262296c12fa..fbabbb82b354 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -659,7 +659,7 @@ static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300) static void __do_poll(struct vub300_mmc_host *vub300) { /* cmd_mutex is held by vub300_pollwork_thread */ - long commretval; + unsigned long commretval; mod_timer(&vub300->inactivity_timer, jiffies + HZ); init_completion(&vub300->irqpoll_complete); send_irqpoll(vub300); @@ -671,8 +671,6 @@ static void __do_poll(struct vub300_mmc_host *vub300) vub300->usb_timed_out = 1; usb_kill_urb(vub300->command_out_urb); usb_kill_urb(vub300->command_res_urb); - } else if (commretval < 0) { - vub300_queue_poll_work(vub300, 1); } else { /* commretval > 0 */ __vub300_irqpoll_response(vub300); } diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 9a6dfb0c4ecc..ca183ea767b3 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1914,7 +1914,6 @@ static struct platform_driver wbsd_driver = { .resume = wbsd_platform_resume, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, }, }; diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 54181b4f6e9e..5af00559e9d6 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -744,7 +744,7 @@ static struct wmt_mci_caps wm8505_caps = { .max_blk_size = 2048, }; -static struct of_device_id wmt_mci_dt_ids[] = { +static const struct of_device_id wmt_mci_dt_ids[] = { { .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps }, { /* Sentinel */ }, }; @@ -991,7 +991,6 @@ static struct platform_driver wmt_mci_driver = { .remove = wmt_mci_remove, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = wmt_mci_pm_ops, .of_match_table = wmt_mci_dt_ids, }, |