summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-12 04:11:21 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-12 04:11:21 +0300
commit8931084c0d017314ad025f19353f7c5c1d3782d8 (patch)
treee5ae4dcaba8353cad27744b0150dd0b6513413fc /drivers/mmc
parent17a20acaf171124017f43bc70bb4d7ca88070659 (diff)
parent59592cc1f5937ced72e11e681c3e358a0375f7ae (diff)
downloadlinux-8931084c0d017314ad025f19353f7c5c1d3782d8.tar.xz
Merge tag 'mmc-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson: "MMC core: - Let the dma map ops deal with bouncing and drop dma_max_pfn() from the dma-mapping interface for ARM - Convert the generic MMC DT doc to YAML schemas - Drop questionable support for powered-on re-init of SDIO cards at runtime resume and for SDIO HW reset - Prevent questionable re-init of powered-on removable SDIO cards at system resume - Cleanup and clarify some SDIO core code MMC host: - tmio: Make runtime PM enablement more flexible for variants - tmio/renesas_sdhi: Rename DT doc tmio_mmc.txt to renesas,sdhi.txt to clarify - sdhci-pci: Add support for Intel EHL - sdhci-pci-o2micro: Enable support for 8-bit bus - sdhci-msm: Prevent acquiring a mutex while holding a spin_lock - sdhci-of-esdhc: Improve clock management and tuning - sdhci_am654: Enable support for 4 and 8-bit bus on J721E - sdhci-sprd: Use pinctrl for a proper signal voltage switch - sdhci-sprd: Add support for HS400 enhanced strobe mode - sdhci-sprd: Enable PHY DLL and allow delay config to stabilize the clock - sdhci-sprd: Add support for optional gate clock - sunxi-mmc: Convert DT doc to YAML schemas - meson-gx: Add support for broken DRAM access for DMA MEMSTICK core: - Fixup error path of memstick_init()" * tag 'mmc-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (52 commits) mmc: sdhci_am654: Add dependency on MMC_SDHCI_AM654 mmc: alcor: remove a redundant greater or equal to zero comparison mmc: sdhci-msm: fix mutex while in spinlock mmc: sdhci_am654: Make some symbols static dma-mapping: remove dma_max_pfn mmc: core: let the dma map ops handle bouncing dt-binding: mmc: rename tmio_mmc.txt to renesas,sdhi.txt mmc: sdhci-sprd: Add pin control support for voltage switch dt-bindings: mmc: sprd: Add pinctrl support mmc: sdhci-sprd: Add start_signal_voltage_switch ops mmc: sdhci-pci: Add support for Intel EHL mmc: tmio: Use dma_max_mapping_size() instead of a workaround mmc: sdio: Drop unused in-parameter from mmc_sdio_init_card() mmc: sdio: Drop unused in-parameter to mmc_sdio_reinit_card() mmc: sdio: Don't re-initialize powered-on removable SDIO cards at resume mmc: sdio: Drop powered-on re-init at runtime resume and HW reset mmc: sdio: Move comment about re-initialization to mmc_sdio_reinit_card() mmc: sdio: Drop mmc_claim|release_host() in mmc_sdio_power_restore() mmc: sdio: Turn sdio_run_irqs() into static mmc: sdhci: Fix indenting on SDHCI_CTRL_8BITBUS ...
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/debugfs.c56
-rw-r--r--drivers/mmc/core/mmc_test.c10
-rw-r--r--drivers/mmc/core/queue.c7
-rw-r--r--drivers/mmc/core/sdio.c92
-rw-r--r--drivers/mmc/core/sdio_irq.c3
-rw-r--r--drivers/mmc/host/Kconfig2
-rw-r--r--drivers/mmc/host/alcor.c2
-rw-r--r--drivers/mmc/host/android-goldfish.c31
-rw-r--r--drivers/mmc/host/atmel-mci.c38
-rw-r--r--drivers/mmc/host/dw_mmc.c36
-rw-r--r--drivers/mmc/host/meson-gx-mmc.c70
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c19
-rw-r--r--drivers/mmc/host/s3cmci.c27
-rw-r--r--drivers/mmc/host/s3cmci.h2
-rw-r--r--drivers/mmc/host/sdhci-msm.c9
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c17
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c4
-rw-r--r--drivers/mmc/host/sdhci-pci-o2micro.c12
-rw-r--r--drivers/mmc/host/sdhci-pci.h2
-rw-r--r--drivers/mmc/host/sdhci-sprd.c249
-rw-r--r--drivers/mmc/host/sdhci-tegra.c5
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/mmc/host/sdhci_am654.c293
-rw-r--r--drivers/mmc/host/tmio_mmc.c5
-rw-r--r--drivers/mmc/host/tmio_mmc_core.c29
-rw-r--r--drivers/mmc/host/uniphier-sd.c3
26 files changed, 666 insertions, 359 deletions
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 2797771a5fa8..09e0c7659469 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -227,45 +227,21 @@ void mmc_add_host_debugfs(struct mmc_host *host)
struct dentry *root;
root = debugfs_create_dir(mmc_hostname(host), NULL);
- if (IS_ERR(root))
- /* Don't complain -- debugfs just isn't enabled */
- return;
- if (!root)
- /* Complain -- debugfs is enabled, but it failed to
- * create the directory. */
- goto err_root;
-
host->debugfs_root = root;
- if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
- goto err_node;
-
- if (!debugfs_create_x32("caps", S_IRUSR, root, &host->caps))
- goto err_node;
-
- if (!debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2))
- goto err_node;
-
- if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
- &mmc_clock_fops))
- goto err_node;
+ debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops);
+ debugfs_create_x32("caps", S_IRUSR, root, &host->caps);
+ debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2);
+ debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
+ &mmc_clock_fops);
#ifdef CONFIG_FAIL_MMC_REQUEST
if (fail_request)
setup_fault_attr(&fail_default_attr, fail_request);
host->fail_mmc_request = fail_default_attr;
- if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
- root,
- &host->fail_mmc_request)))
- goto err_node;
+ fault_create_debugfs_attr("fail_mmc_request", root,
+ &host->fail_mmc_request);
#endif
- return;
-
-err_node:
- debugfs_remove_recursive(root);
- host->debugfs_root = NULL;
-err_root:
- dev_err(&host->class_dev, "failed to initialize debugfs\n");
}
void mmc_remove_host_debugfs(struct mmc_host *host)
@@ -282,25 +258,9 @@ void mmc_add_card_debugfs(struct mmc_card *card)
return;
root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
- if (IS_ERR(root))
- /* Don't complain -- debugfs just isn't enabled */
- return;
- if (!root)
- /* Complain -- debugfs is enabled, but it failed to
- * create the directory. */
- goto err;
-
card->debugfs_root = root;
- if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
- goto err;
-
- return;
-
-err:
- debugfs_remove_recursive(root);
- card->debugfs_root = NULL;
- dev_err(&card->dev, "failed to initialize debugfs\n");
+ debugfs_create_x32("state", S_IRUSR, root, &card->state);
}
void mmc_remove_card_debugfs(struct mmc_card *card)
diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c
index b27df2d2b5ae..492dd4596314 100644
--- a/drivers/mmc/core/mmc_test.c
+++ b/drivers/mmc/core/mmc_test.c
@@ -3167,15 +3167,7 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
struct mmc_test_dbgfs_file *df;
if (card->debugfs_root)
- file = debugfs_create_file(name, mode, card->debugfs_root,
- card, fops);
-
- if (IS_ERR_OR_NULL(file)) {
- dev_err(&card->dev,
- "Can't create %s. Perhaps debugfs is disabled.\n",
- name);
- return -ENODEV;
- }
+ debugfs_create_file(name, mode, card->debugfs_root, card, fops);
df = kmalloc(sizeof(*df), GFP_KERNEL);
if (!df) {
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index 3557d5c51141..e327f80ebe70 100644
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -350,18 +350,15 @@ static const struct blk_mq_ops mmc_mq_ops = {
static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
{
struct mmc_host *host = card->host;
- u64 limit = BLK_BOUNCE_HIGH;
unsigned block_size = 512;
- if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
- limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
-
blk_queue_flag_set(QUEUE_FLAG_NONROT, mq->queue);
blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, mq->queue);
if (mmc_can_erase(card))
mmc_queue_setup_discard(mq->queue, card);
- blk_queue_bounce_limit(mq->queue, limit);
+ if (!mmc_dev(host)->dma_mask || !*mmc_dev(host)->dma_mask)
+ blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH);
blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_segments(mq->queue, host->max_segs);
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 712a7742765e..8dd8fc32ecca 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -559,7 +559,7 @@ static void mmc_sdio_resend_if_cond(struct mmc_host *host,
* we're trying to reinitialise.
*/
static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
- struct mmc_card *oldcard, int powered_resume)
+ struct mmc_card *oldcard)
{
struct mmc_card *card;
int err;
@@ -582,11 +582,9 @@ try_again:
/*
* Inform the card of the voltage
*/
- if (!powered_resume) {
- err = mmc_send_io_op_cond(host, ocr, &rocr);
- if (err)
- goto err;
- }
+ err = mmc_send_io_op_cond(host, ocr, &rocr);
+ if (err)
+ goto err;
/*
* For SPI, enable CRC as appropriate.
@@ -645,7 +643,7 @@ try_again:
* try to init uhs card. sdio_read_cccr will take over this task
* to make sure which speed mode should work.
*/
- if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
+ if (rocr & ocr & R4_18V_PRESENT) {
err = mmc_set_uhs_voltage(host, ocr_card);
if (err == -EAGAIN) {
mmc_sdio_resend_if_cond(host, card);
@@ -659,7 +657,7 @@ try_again:
/*
* For native busses: set card RCA and quit open drain mode.
*/
- if (!powered_resume && !mmc_host_is_spi(host)) {
+ if (!mmc_host_is_spi(host)) {
err = mmc_send_relative_addr(host, &card->rca);
if (err)
goto remove;
@@ -687,7 +685,7 @@ try_again:
/*
* Select card, as all following commands rely on that.
*/
- if (!powered_resume && !mmc_host_is_spi(host)) {
+ if (!mmc_host_is_spi(host)) {
err = mmc_select_card(card);
if (err)
goto remove;
@@ -816,10 +814,27 @@ err:
return err;
}
-static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
+static int mmc_sdio_reinit_card(struct mmc_host *host)
{
int ret;
+ /*
+ * Reset the card by performing the same steps that are taken by
+ * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
+ *
+ * sdio_reset() is technically not needed. Having just powered up the
+ * hardware, it should already be in reset state. However, some
+ * platforms (such as SD8686 on OLPC) do not instantly cut power,
+ * meaning that a reset is required when restoring power soon after
+ * powering off. It is harmless in other cases.
+ *
+ * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
+ * is not necessary for non-removable cards. However, it is required
+ * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
+ * harmless in other situations.
+ *
+ */
+
sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->card->ocr);
@@ -828,8 +843,7 @@ static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
if (ret)
return ret;
- return mmc_sdio_init_card(host, host->card->ocr, host->card,
- powered_resume);
+ return mmc_sdio_init_card(host, host->card->ocr, host->card);
}
/*
@@ -965,7 +979,11 @@ static int mmc_sdio_resume(struct mmc_host *host)
/* Basic card reinitialization. */
mmc_claim_host(host);
- /* Restore power if needed */
+ /*
+ * Restore power and reinitialize the card when needed. Note that a
+ * removable card is checked from a detect work later on in the resume
+ * process.
+ */
if (!mmc_card_keep_power(host)) {
mmc_power_up(host, host->card->ocr);
/*
@@ -979,12 +997,8 @@ static int mmc_sdio_resume(struct mmc_host *host)
pm_runtime_set_active(&host->card->dev);
pm_runtime_enable(&host->card->dev);
}
- }
-
- /* No need to reinitialize powered-resumed nonremovable cards */
- if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
- err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
- } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
+ err = mmc_sdio_reinit_card(host);
+ } else if (mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host->card);
}
@@ -1009,38 +1023,6 @@ out:
return err;
}
-static int mmc_sdio_power_restore(struct mmc_host *host)
-{
- int ret;
-
- /*
- * Reset the card by performing the same steps that are taken by
- * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
- *
- * sdio_reset() is technically not needed. Having just powered up the
- * hardware, it should already be in reset state. However, some
- * platforms (such as SD8686 on OLPC) do not instantly cut power,
- * meaning that a reset is required when restoring power soon after
- * powering off. It is harmless in other cases.
- *
- * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
- * is not necessary for non-removable cards. However, it is required
- * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
- * harmless in other situations.
- *
- */
-
- mmc_claim_host(host);
-
- ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
- if (!ret && host->sdio_irqs)
- mmc_signal_sdio_irq(host);
-
- mmc_release_host(host);
-
- return ret;
-}
-
static int mmc_sdio_runtime_suspend(struct mmc_host *host)
{
/* No references to the card, cut the power to it. */
@@ -1058,7 +1040,7 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
/* Restore power and re-initialize. */
mmc_claim_host(host);
mmc_power_up(host, host->card->ocr);
- ret = mmc_sdio_power_restore(host);
+ ret = mmc_sdio_reinit_card(host);
mmc_release_host(host);
return ret;
@@ -1067,7 +1049,7 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
static int mmc_sdio_hw_reset(struct mmc_host *host)
{
mmc_power_cycle(host, host->card->ocr);
- return mmc_sdio_power_restore(host);
+ return mmc_sdio_reinit_card(host);
}
static int mmc_sdio_sw_reset(struct mmc_host *host)
@@ -1079,7 +1061,7 @@ static int mmc_sdio_sw_reset(struct mmc_host *host)
mmc_set_initial_state(host);
mmc_set_initial_signal_voltage(host);
- return mmc_sdio_reinit_card(host, 0);
+ return mmc_sdio_reinit_card(host);
}
static const struct mmc_bus_ops mmc_sdio_ops = {
@@ -1129,7 +1111,7 @@ int mmc_attach_sdio(struct mmc_host *host)
/*
* Detect and init the card.
*/
- err = mmc_sdio_init_card(host, rocr, NULL, 0);
+ err = mmc_sdio_init_card(host, rocr, NULL);
if (err)
goto err;
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 9f54a259a1b3..0bcc5e83bd1a 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -92,7 +92,7 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
return ret;
}
-void sdio_run_irqs(struct mmc_host *host)
+static void sdio_run_irqs(struct mmc_host *host)
{
mmc_claim_host(host);
if (host->sdio_irqs) {
@@ -103,7 +103,6 @@ void sdio_run_irqs(struct mmc_host *host)
}
mmc_release_host(host);
}
-EXPORT_SYMBOL_GPL(sdio_run_irqs);
void sdio_irq_work(struct work_struct *work)
{
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 931770f17087..14d89a108edd 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -996,7 +996,7 @@ config MMC_SDHCI_OMAP
config MMC_SDHCI_AM654
tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
- depends on MMC_SDHCI_PLTFM && OF
+ depends on MMC_SDHCI_PLTFM && OF && REGMAP_MMIO
select MMC_SDHCI_IO_ACCESSORS
help
This selects the Secure Digital Host Controller Interface (SDHCI)
diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c
index e481535cba2b..1aee485d56d4 100644
--- a/drivers/mmc/host/alcor.c
+++ b/drivers/mmc/host/alcor.c
@@ -672,7 +672,7 @@ static void alcor_set_clock(struct alcor_sdmmc_host *host, unsigned int clock)
tmp_clock = DIV_ROUND_UP(cfg->clk_src_freq, tmp_div);
tmp_diff = abs(clock - tmp_clock);
- if (tmp_diff >= 0 && tmp_diff < diff) {
+ if (tmp_diff < diff) {
diff = tmp_diff;
clk_src = cfg->clk_src_reg;
clk_div = tmp_div;
diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c
index 11a208cfba04..914e17bab3be 100644
--- a/drivers/mmc/host/android-goldfish.c
+++ b/drivers/mmc/host/android-goldfish.c
@@ -110,7 +110,6 @@ struct goldfish_mmc_host {
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
- struct mmc_host *mmc;
struct device *dev;
unsigned char id; /* 16xx chips have 2 MMC blocks */
void *virt_base;
@@ -172,7 +171,7 @@ goldfish_mmc_start_command(struct goldfish_mmc_host *host, struct mmc_command *c
resptype = 3;
break;
default:
- dev_err(mmc_dev(host->mmc),
+ dev_err(mmc_dev(mmc_from_priv(host)),
"Invalid response type: %04x\n", mmc_resp_type(cmd));
break;
}
@@ -218,8 +217,8 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
data->sg->length);
}
host->data->bytes_xfered += data->sg->length;
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
- dma_data_dir);
+ dma_unmap_sg(mmc_dev(mmc_from_priv(host)), data->sg,
+ host->sg_len, dma_data_dir);
}
host->data = NULL;
@@ -233,7 +232,7 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
if (!data->stop) {
host->mrq = NULL;
- mmc_request_done(host->mmc, data->mrq);
+ mmc_request_done(mmc_from_priv(host), data->mrq);
return;
}
@@ -275,7 +274,7 @@ static void goldfish_mmc_cmd_done(struct goldfish_mmc_host *host,
if (host->data == NULL || cmd->error) {
host->mrq = NULL;
- mmc_request_done(host->mmc, cmd->mrq);
+ mmc_request_done(mmc_from_priv(host), cmd->mrq);
}
}
@@ -310,7 +309,7 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
struct mmc_request *mrq = host->mrq;
mrq->cmd->error = -ETIMEDOUT;
host->mrq = NULL;
- mmc_request_done(host->mmc, mrq);
+ mmc_request_done(mmc_from_priv(host), mrq);
}
if (end_command)
@@ -336,12 +335,13 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
u32 state = GOLDFISH_MMC_READ(host, MMC_STATE);
pr_info("%s: Card detect now %d\n", __func__,
(state & MMC_STATE_INSERTED));
- mmc_detect_change(host->mmc, 0);
+ mmc_detect_change(mmc_from_priv(host), 0);
}
if (!end_command && !end_transfer && !state_changed && !cmd_timeout) {
status = GOLDFISH_MMC_READ(host, MMC_INT_STATUS);
- dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
+ dev_info(mmc_dev(mmc_from_priv(host)), "spurious irq 0x%04x\n",
+ status);
if (status != 0) {
GOLDFISH_MMC_WRITE(host, MMC_INT_STATUS, status);
GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE, 0);
@@ -380,7 +380,7 @@ static void goldfish_mmc_prepare_data(struct goldfish_mmc_host *host,
dma_data_dir = mmc_get_dma_dir(data);
- host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ host->sg_len = dma_map_sg(mmc_dev(mmc_from_priv(host)), data->sg,
sg_len, dma_data_dir);
host->dma_done = 0;
host->dma_in_use = 1;
@@ -458,7 +458,6 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
}
host = mmc_priv(mmc);
- host->mmc = mmc;
pr_err("mmc: Mapping %lX to %lX\n", (long)res->start, (long)res->end);
host->reg_base = ioremap(res->start, resource_size(res));
@@ -505,8 +504,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
ret = device_create_file(&pdev->dev, &dev_attr_cover_switch);
if (ret)
- dev_warn(mmc_dev(host->mmc),
- "Unable to create sysfs attributes\n");
+ dev_warn(mmc_dev(mmc), "Unable to create sysfs attributes\n");
GOLDFISH_MMC_WRITE(host, MMC_SET_BUFFER, host->phys_base);
GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE,
@@ -522,7 +520,7 @@ err_request_irq_failed:
dma_alloc_failed:
iounmap(host->reg_base);
ioremap_failed:
- mmc_free_host(host->mmc);
+ mmc_free_host(mmc);
err_alloc_host_failed:
return ret;
}
@@ -530,14 +528,15 @@ err_alloc_host_failed:
static int goldfish_mmc_remove(struct platform_device *pdev)
{
struct goldfish_mmc_host *host = platform_get_drvdata(pdev);
+ struct mmc_host *mmc = mmc_from_priv(host);
BUG_ON(host == NULL);
- mmc_remove_host(host->mmc);
+ mmc_remove_host(mmc);
free_irq(host->irq, host);
dma_free_coherent(&pdev->dev, BUFFER_SIZE, host->virt_base, host->phys_base);
iounmap(host->reg_base);
- mmc_free_host(host->mmc);
+ mmc_free_host(mmc);
return 0;
}
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 392a1f87c638..9ee0bc0ce6d0 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -576,42 +576,18 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
struct mmc_host *mmc = slot->mmc;
struct atmel_mci *host = slot->host;
struct dentry *root;
- struct dentry *node;
root = mmc->debugfs_root;
if (!root)
return;
- node = debugfs_create_file("regs", S_IRUSR, root, host,
- &atmci_regs_fops);
- if (IS_ERR(node))
- return;
- if (!node)
- goto err;
-
- node = debugfs_create_file("req", S_IRUSR, root, slot,
- &atmci_req_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("pending_events", S_IRUSR, root,
- (u32 *)&host->pending_events);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("completed_events", S_IRUSR, root,
- (u32 *)&host->completed_events);
- if (!node)
- goto err;
-
- return;
-
-err:
- dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+ debugfs_create_file("regs", S_IRUSR, root, host, &atmci_regs_fops);
+ debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
+ debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
+ debugfs_create_x32("pending_events", S_IRUSR, root,
+ (u32 *)&host->pending_events);
+ debugfs_create_x32("completed_events", S_IRUSR, root,
+ (u32 *)&host->completed_events);
}
#if defined(CONFIG_OF)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b53b6b7d4dd4..faaaf52a46d2 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -169,40 +169,18 @@ static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
struct mmc_host *mmc = slot->mmc;
struct dw_mci *host = slot->host;
struct dentry *root;
- struct dentry *node;
root = mmc->debugfs_root;
if (!root)
return;
- node = debugfs_create_file("regs", S_IRUSR, root, host,
- &dw_mci_regs_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_file("req", S_IRUSR, root, slot,
- &dw_mci_req_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("pending_events", S_IRUSR, root,
- (u32 *)&host->pending_events);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("completed_events", S_IRUSR, root,
- (u32 *)&host->completed_events);
- if (!node)
- goto err;
-
- return;
-
-err:
- dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+ debugfs_create_file("regs", S_IRUSR, root, host, &dw_mci_regs_fops);
+ debugfs_create_file("req", S_IRUSR, root, slot, &dw_mci_req_fops);
+ debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
+ debugfs_create_x32("pending_events", S_IRUSR, root,
+ (u32 *)&host->pending_events);
+ debugfs_create_x32("completed_events", S_IRUSR, root,
+ (u32 *)&host->completed_events);
}
#endif /* defined(CONFIG_DEBUG_FS) */
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index fb842255de49..037311db3551 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -116,6 +116,9 @@
#define SD_EMMC_TXD 0x94
#define SD_EMMC_LAST_REG SD_EMMC_TXD
+#define SD_EMMC_SRAM_DATA_BUF_LEN 1536
+#define SD_EMMC_SRAM_DATA_BUF_OFF 0x200
+
#define SD_EMMC_CFG_BLK_SIZE 512 /* internal buffer max: 512 bytes */
#define SD_EMMC_CFG_RESP_TIMEOUT 256 /* in clock cycles */
#define SD_EMMC_CMD_TIMEOUT 1024 /* in ms */
@@ -155,6 +158,8 @@ struct meson_host {
unsigned long req_rate;
bool ddr;
+ bool dram_access_quirk;
+
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_clk_gate;
@@ -219,12 +224,21 @@ static struct mmc_command *meson_mmc_get_next_command(struct mmc_command *cmd)
static void meson_mmc_get_transfer_mode(struct mmc_host *mmc,
struct mmc_request *mrq)
{
+ struct meson_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
struct scatterlist *sg;
int i;
bool use_desc_chain_mode = true;
/*
+ * When Controller DMA cannot directly access DDR memory, disable
+ * support for Chain Mode to directly use the internal SRAM using
+ * the bounce buffer mode.
+ */
+ if (host->dram_access_quirk)
+ return;
+
+ /*
* Broken SDIO with AP6255-based WiFi on Khadas VIM Pro has been
* reported. For some strange reason this occurs in descriptor
* chain mode only. So let's fall back to bounce buffer mode
@@ -1036,6 +1050,10 @@ static int meson_mmc_probe(struct platform_device *pdev)
host->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, host);
+ /* The G12A SDIO Controller needs an SRAM bounce buffer */
+ host->dram_access_quirk = device_property_read_bool(&pdev->dev,
+ "amlogic,dram-access-quirk");
+
/* Get regulators and the supported OCR mask */
host->vqmmc_enabled = false;
ret = mmc_regulator_get_supply(mmc);
@@ -1133,9 +1151,16 @@ static int meson_mmc_probe(struct platform_device *pdev)
goto err_init_clk;
mmc->caps |= MMC_CAP_CMD23;
- mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
+ if (host->dram_access_quirk) {
+ /* Limit to the available sram memory */
+ mmc->max_segs = SD_EMMC_SRAM_DATA_BUF_LEN / mmc->max_blk_size;
+ mmc->max_blk_count = mmc->max_segs;
+ } else {
+ mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
+ mmc->max_segs = SD_EMMC_DESC_BUF_LEN /
+ sizeof(struct sd_emmc_desc);
+ }
mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
- mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc);
mmc->max_seg_size = mmc->max_req_size;
/*
@@ -1145,15 +1170,27 @@ static int meson_mmc_probe(struct platform_device *pdev)
*/
mmc->caps2 &= ~MMC_CAP2_HS400;
- /* data bounce buffer */
- host->bounce_buf_size = mmc->max_req_size;
- host->bounce_buf =
- dma_alloc_coherent(host->dev, host->bounce_buf_size,
- &host->bounce_dma_addr, GFP_KERNEL);
- if (host->bounce_buf == NULL) {
- dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
- ret = -ENOMEM;
- goto err_free_irq;
+ if (host->dram_access_quirk) {
+ /*
+ * The MMC Controller embeds 1,5KiB of internal SRAM
+ * that can be used to be used as bounce buffer.
+ * In the case of the G12A SDIO controller, use these
+ * instead of the DDR memory
+ */
+ host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN;
+ host->bounce_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF;
+ host->bounce_dma_addr = res->start + SD_EMMC_SRAM_DATA_BUF_OFF;
+ } else {
+ /* data bounce buffer */
+ host->bounce_buf_size = mmc->max_req_size;
+ host->bounce_buf =
+ dma_alloc_coherent(host->dev, host->bounce_buf_size,
+ &host->bounce_dma_addr, GFP_KERNEL);
+ if (host->bounce_buf == NULL) {
+ dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
+ ret = -ENOMEM;
+ goto err_free_irq;
+ }
}
host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
@@ -1170,8 +1207,9 @@ static int meson_mmc_probe(struct platform_device *pdev)
return 0;
err_bounce_buf:
- dma_free_coherent(host->dev, host->bounce_buf_size,
- host->bounce_buf, host->bounce_dma_addr);
+ if (!host->dram_access_quirk)
+ dma_free_coherent(host->dev, host->bounce_buf_size,
+ host->bounce_buf, host->bounce_dma_addr);
err_free_irq:
free_irq(host->irq, host);
err_init_clk:
@@ -1195,8 +1233,10 @@ static int meson_mmc_remove(struct platform_device *pdev)
dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
host->descs, host->descs_dma_addr);
- dma_free_coherent(host->dev, host->bounce_buf_size,
- host->bounce_buf, host->bounce_dma_addr);
+
+ if (!host->dram_access_quirk)
+ dma_free_coherent(host->dev, host->bounce_buf_size,
+ host->bounce_buf, host->bounce_dma_addr);
clk_disable_unprepare(host->mmc_clk);
clk_disable_unprepare(host->core_clk);
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 5f8d57ac084f..64d3b5fb7fe5 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -610,13 +610,12 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
renesas_sdhi_sdbuf_width(host, enable ? width : 16);
}
-static const struct renesas_sdhi_quirks sdhi_quirks_h3_m3w_es1 = {
+static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400 = {
.hs400_disabled = true,
.hs400_4taps = true,
};
-static const struct renesas_sdhi_quirks sdhi_quirks_h3_es2 = {
- .hs400_disabled = false,
+static const struct renesas_sdhi_quirks sdhi_quirks_4tap = {
.hs400_4taps = true,
};
@@ -625,10 +624,10 @@ static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = {
};
static const struct soc_device_attribute sdhi_quirks_match[] = {
- { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_h3_m3w_es1 },
- { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_h3_es2 },
- { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_h3_m3w_es1 },
- { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_h3_m3w_es1 },
+ { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_4tap_nohs400 },
+ { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap },
+ { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
+ { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
{ .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 },
{ /* Sentinel. */ },
};
@@ -775,6 +774,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
/* All SDHI have SDIO status bits which must be 1 */
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
+ pm_runtime_enable(&pdev->dev);
+
ret = renesas_sdhi_clk_enable(host);
if (ret)
goto efree;
@@ -855,6 +856,8 @@ edisclk:
efree:
tmio_mmc_host_free(host);
+ pm_runtime_disable(&pdev->dev);
+
return ret;
}
EXPORT_SYMBOL_GPL(renesas_sdhi_probe);
@@ -866,6 +869,8 @@ int renesas_sdhi_remove(struct platform_device *pdev)
tmio_mmc_host_remove(host);
renesas_sdhi_clk_disable(host);
+ pm_runtime_disable(&pdev->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index b1d3f8288732..ccc5f095775f 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -1449,33 +1449,18 @@ DEFINE_SHOW_ATTRIBUTE(s3cmci_regs);
static void s3cmci_debugfs_attach(struct s3cmci_host *host)
{
struct device *dev = &host->pdev->dev;
+ struct dentry *root;
- host->debug_root = debugfs_create_dir(dev_name(dev), NULL);
- if (IS_ERR(host->debug_root)) {
- dev_err(dev, "failed to create debugfs root\n");
- return;
- }
-
- host->debug_state = debugfs_create_file("state", 0444,
- host->debug_root, host,
- &s3cmci_state_fops);
-
- if (IS_ERR(host->debug_state))
- dev_err(dev, "failed to create debug state file\n");
-
- host->debug_regs = debugfs_create_file("regs", 0444,
- host->debug_root, host,
- &s3cmci_regs_fops);
+ root = debugfs_create_dir(dev_name(dev), NULL);
+ host->debug_root = root;
- if (IS_ERR(host->debug_regs))
- dev_err(dev, "failed to create debug regs file\n");
+ debugfs_create_file("state", 0444, root, host, &s3cmci_state_fops);
+ debugfs_create_file("regs", 0444, root, host, &s3cmci_regs_fops);
}
static void s3cmci_debugfs_remove(struct s3cmci_host *host)
{
- debugfs_remove(host->debug_regs);
- debugfs_remove(host->debug_state);
- debugfs_remove(host->debug_root);
+ debugfs_remove_recursive(host->debug_root);
}
#else
diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h
index 7ca1d9d639c4..8b65d7ad9f97 100644
--- a/drivers/mmc/host/s3cmci.h
+++ b/drivers/mmc/host/s3cmci.h
@@ -67,8 +67,6 @@ struct s3cmci_host {
#ifdef CONFIG_DEBUG_FS
struct dentry *debug_root;
- struct dentry *debug_state;
- struct dentry *debug_regs;
#endif
#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 5fc76a1993d0..9cf14b359c14 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -575,11 +575,14 @@ static int msm_init_cm_dll(struct sdhci_host *host)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
int wait_cnt = 50;
- unsigned long flags;
+ unsigned long flags, xo_clk = 0;
u32 config;
const struct sdhci_msm_offset *msm_offset =
msm_host->offset;
+ if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk))
+ xo_clk = clk_get_rate(msm_host->xo_clk);
+
spin_lock_irqsave(&host->lock, flags);
/*
@@ -627,10 +630,10 @@ static int msm_init_cm_dll(struct sdhci_host *host)
config &= CORE_FLL_CYCLE_CNT;
if (config)
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
- clk_get_rate(msm_host->xo_clk));
+ xo_clk);
else
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
- clk_get_rate(msm_host->xo_clk));
+ xo_clk);
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config_2);
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 68c5866f5c85..4dd43b1adf2c 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -830,9 +830,17 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
bool hs400_tuning;
+ unsigned int clk;
u32 val;
int ret;
+ /* For tuning mode, the sd clock divisor value
+ * must be larger than 3 according to reference manual.
+ */
+ clk = esdhc->peripheral_clock / 3;
+ if (host->clock > clk)
+ esdhc_of_set_clock(host, clk);
+
if (esdhc->quirk_limited_clk_division &&
host->flags & SDHCI_HS400_TUNING)
esdhc_of_set_clock(host, host->clock);
@@ -1040,11 +1048,12 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
/*
* esdhc->peripheral_clock would be assigned with a value
* which is eSDHC base clock when use periperal clock.
- * For ls1046a, the clock value got by common clk API is
- * peripheral clock while the eSDHC base clock is 1/2
- * peripheral clock.
+ * For some platforms, the clock value got by common clk
+ * API is peripheral clock while the eSDHC base clock is
+ * 1/2 peripheral clock.
*/
- if (of_device_is_compatible(np, "fsl,ls1046a-esdhc"))
+ if (of_device_is_compatible(np, "fsl,ls1046a-esdhc") ||
+ of_device_is_compatible(np, "fsl,ls1028a-esdhc"))
esdhc->peripheral_clock = clk_get_rate(clk) / 2;
else
esdhc->peripheral_clock = clk_get_rate(clk);
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 4154ee11b47d..4041878eb0f3 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1668,6 +1668,8 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(INTEL, ICP_EMMC, intel_glk_emmc),
SDHCI_PCI_DEVICE(INTEL, ICP_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(INTEL, EHL_EMMC, intel_glk_emmc),
+ SDHCI_PCI_DEVICE(INTEL, EHL_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(INTEL, CML_EMMC, intel_glk_emmc),
SDHCI_PCI_DEVICE(INTEL, CML_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(O2, 8120, o2),
@@ -2040,8 +2042,6 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
- if (slots == 0)
- return -ENODEV;
BUG_ON(slots > MAX_SLOTS);
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c
index dd21315922c8..9dc4548271b4 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -395,11 +395,21 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
{
struct sdhci_pci_chip *chip;
struct sdhci_host *host;
- u32 reg;
+ u32 reg, caps;
int ret;
chip = slot->chip;
host = slot->host;
+
+ caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+
+ /*
+ * mmc_select_bus_width() will test the bus to determine the actual bus
+ * width.
+ */
+ if (caps & SDHCI_CAN_DO_8BIT)
+ host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+
switch (chip->pdev->device) {
case PCI_DEVICE_ID_O2_SDS0:
case PCI_DEVICE_ID_O2_SEABIRD0:
diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
index e5dc6e44c7a4..cdd15f357d01 100644
--- a/drivers/mmc/host/sdhci-pci.h
+++ b/drivers/mmc/host/sdhci-pci.h
@@ -50,6 +50,8 @@
#define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375
#define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4
#define PCI_DEVICE_ID_INTEL_ICP_SD 0x34f8
+#define PCI_DEVICE_ID_INTEL_EHL_EMMC 0x4b47
+#define PCI_DEVICE_ID_INTEL_EHL_SD 0x4b48
#define PCI_DEVICE_ID_INTEL_CML_EMMC 0x02c4
#define PCI_DEVICE_ID_INTEL_CML_SD 0x02f5
diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c
index 9a822e2e9f0b..6ee340a3fb3a 100644
--- a/drivers/mmc/host/sdhci-sprd.c
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -12,6 +12,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -22,6 +23,15 @@
/* SDHCI_ARGUMENT2 register high 16bit */
#define SDHCI_SPRD_ARG2_STUFF GENMASK(31, 16)
+#define SDHCI_SPRD_REG_32_DLL_CFG 0x200
+#define SDHCI_SPRD_DLL_ALL_CPST_EN (BIT(18) | BIT(24) | BIT(25) | BIT(26) | BIT(27))
+#define SDHCI_SPRD_DLL_EN BIT(21)
+#define SDHCI_SPRD_DLL_SEARCH_MODE BIT(16)
+#define SDHCI_SPRD_DLL_INIT_COUNT 0xc00
+#define SDHCI_SPRD_DLL_PHASE_INTERNAL 0x3
+
+#define SDHCI_SPRD_REG_32_DLL_DLY 0x204
+
#define SDHCI_SPRD_REG_32_DLL_DLY_OFFSET 0x208
#define SDHCIBSPRD_IT_WR_DLY_INV BIT(5)
#define SDHCI_SPRD_BIT_CMD_DLY_INV BIT(13)
@@ -41,6 +51,7 @@
/* SDHCI_HOST_CONTROL2 */
#define SDHCI_SPRD_CTRL_HS200 0x0005
#define SDHCI_SPRD_CTRL_HS400 0x0006
+#define SDHCI_SPRD_CTRL_HS400ES 0x0007
/*
* According to the standard specification, BIT(3) of SDHCI_SOFTWARE_RESET is
@@ -55,13 +66,36 @@
#define SDHCI_SPRD_CLK_MAX_DIV 1023
#define SDHCI_SPRD_CLK_DEF_RATE 26000000
+#define SDHCI_SPRD_PHY_DLL_CLK 52000000
struct sdhci_sprd_host {
u32 version;
struct clk *clk_sdio;
struct clk *clk_enable;
+ struct clk *clk_2x_enable;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_uhs;
+ struct pinctrl_state *pins_default;
u32 base_rate;
int flags; /* backup of host attribute */
+ u32 phy_delay[MMC_TIMING_MMC_HS400 + 2];
+};
+
+struct sdhci_sprd_phy_cfg {
+ const char *property;
+ u8 timing;
+};
+
+static const struct sdhci_sprd_phy_cfg sdhci_sprd_phy_cfgs[] = {
+ { "sprd,phy-delay-legacy", MMC_TIMING_LEGACY, },
+ { "sprd,phy-delay-sd-highspeed", MMC_TIMING_SD_HS, },
+ { "sprd,phy-delay-sd-uhs-sdr50", MMC_TIMING_UHS_SDR50, },
+ { "sprd,phy-delay-sd-uhs-sdr104", MMC_TIMING_UHS_SDR104, },
+ { "sprd,phy-delay-mmc-highspeed", MMC_TIMING_MMC_HS, },
+ { "sprd,phy-delay-mmc-ddr52", MMC_TIMING_MMC_DDR52, },
+ { "sprd,phy-delay-mmc-hs200", MMC_TIMING_MMC_HS200, },
+ { "sprd,phy-delay-mmc-hs400", MMC_TIMING_MMC_HS400, },
+ { "sprd,phy-delay-mmc-hs400es", MMC_TIMING_MMC_HS400 + 1, },
};
#define TO_SPRD_HOST(host) sdhci_pltfm_priv(sdhci_priv(host))
@@ -131,6 +165,15 @@ static inline void sdhci_sprd_sd_clk_off(struct sdhci_host *host)
sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
}
+static inline void sdhci_sprd_sd_clk_on(struct sdhci_host *host)
+{
+ u16 ctrl;
+
+ ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ ctrl |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
+}
+
static inline void
sdhci_sprd_set_dll_invert(struct sdhci_host *host, u32 mask, bool en)
{
@@ -189,9 +232,33 @@ static inline void _sdhci_sprd_set_clock(struct sdhci_host *host,
}
}
+static void sdhci_sprd_enable_phy_dll(struct sdhci_host *host)
+{
+ u32 tmp;
+
+ tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
+ tmp &= ~(SDHCI_SPRD_DLL_EN | SDHCI_SPRD_DLL_ALL_CPST_EN);
+ sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
+ /* wait 1ms */
+ usleep_range(1000, 1250);
+
+ tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
+ tmp |= SDHCI_SPRD_DLL_ALL_CPST_EN | SDHCI_SPRD_DLL_SEARCH_MODE |
+ SDHCI_SPRD_DLL_INIT_COUNT | SDHCI_SPRD_DLL_PHASE_INTERNAL;
+ sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
+ /* wait 1ms */
+ usleep_range(1000, 1250);
+
+ tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
+ tmp |= SDHCI_SPRD_DLL_EN;
+ sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
+ /* wait 1ms */
+ usleep_range(1000, 1250);
+}
+
static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
{
- bool en = false;
+ bool en = false, clk_changed = false;
if (clock == 0) {
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
@@ -203,9 +270,19 @@ static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
en = true;
sdhci_sprd_set_dll_invert(host, SDHCI_SPRD_BIT_CMD_DLY_INV |
SDHCI_SPRD_BIT_POSRD_DLY_INV, en);
+ clk_changed = true;
} else {
_sdhci_sprd_set_clock(host, clock);
}
+
+ /*
+ * According to the Spreadtrum SD host specification, when we changed
+ * the clock to be more than 52M, we should enable the PHY DLL which
+ * is used to track the clock frequency to make the clock work more
+ * stable. Otherwise deviation may occur of the higher clock.
+ */
+ if (clk_changed && clock > SDHCI_SPRD_PHY_DLL_CLK)
+ sdhci_sprd_enable_phy_dll(host);
}
static unsigned int sdhci_sprd_get_max_clock(struct sdhci_host *host)
@@ -223,6 +300,9 @@ static unsigned int sdhci_sprd_get_min_clock(struct sdhci_host *host)
static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
unsigned int timing)
{
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ struct mmc_host *mmc = host->mmc;
+ u32 *p = sprd_host->phy_delay;
u16 ctrl_2;
if (timing == host->timing)
@@ -261,6 +341,9 @@ static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
}
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+ if (!mmc->ios.enhanced_strobe)
+ sdhci_writel(host, p[timing], SDHCI_SPRD_REG_32_DLL_DLY);
}
static void sdhci_sprd_hw_reset(struct sdhci_host *host)
@@ -284,6 +367,12 @@ static void sdhci_sprd_hw_reset(struct sdhci_host *host)
usleep_range(300, 500);
}
+static unsigned int sdhci_sprd_get_max_timeout_count(struct sdhci_host *host)
+{
+ /* The Spredtrum controller actual maximum timeout count is 1 << 31 */
+ return 1 << 31;
+}
+
static struct sdhci_ops sdhci_sprd_ops = {
.read_l = sdhci_sprd_readl,
.write_l = sdhci_sprd_writel,
@@ -295,6 +384,7 @@ static struct sdhci_ops sdhci_sprd_ops = {
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_sprd_set_uhs_signaling,
.hw_reset = sdhci_sprd_hw_reset,
+ .get_max_timeout_count = sdhci_sprd_get_max_timeout_count,
};
static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -317,6 +407,99 @@ static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
sdhci_request(mmc, mrq);
}
+static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ int ret;
+
+ if (!IS_ERR(mmc->supply.vqmmc)) {
+ ret = mmc_regulator_set_vqmmc(mmc, ios);
+ if (ret) {
+ pr_err("%s: Switching signalling voltage failed\n",
+ mmc_hostname(mmc));
+ return ret;
+ }
+ }
+
+ if (IS_ERR(sprd_host->pinctrl))
+ return 0;
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_180:
+ ret = pinctrl_select_state(sprd_host->pinctrl,
+ sprd_host->pins_uhs);
+ if (ret) {
+ pr_err("%s: failed to select uhs pin state\n",
+ mmc_hostname(mmc));
+ return ret;
+ }
+ break;
+
+ default:
+ /* fall-through */
+ case MMC_SIGNAL_VOLTAGE_330:
+ ret = pinctrl_select_state(sprd_host->pinctrl,
+ sprd_host->pins_default);
+ if (ret) {
+ pr_err("%s: failed to select default pin state\n",
+ mmc_hostname(mmc));
+ return ret;
+ }
+ break;
+ }
+
+ /* Wait for 300 ~ 500 us for pin state stable */
+ usleep_range(300, 500);
+ sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+ return 0;
+}
+
+static void sdhci_sprd_hs400_enhanced_strobe(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ u32 *p = sprd_host->phy_delay;
+ u16 ctrl_2;
+
+ if (!ios->enhanced_strobe)
+ return;
+
+ sdhci_sprd_sd_clk_off(host);
+
+ /* Set HS400 enhanced strobe mode */
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+ ctrl_2 |= SDHCI_SPRD_CTRL_HS400ES;
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+ sdhci_sprd_sd_clk_on(host);
+
+ /* Set the PHY DLL delay value for HS400 enhanced strobe mode */
+ sdhci_writel(host, p[MMC_TIMING_MMC_HS400 + 1],
+ SDHCI_SPRD_REG_32_DLL_DLY);
+}
+
+static void sdhci_sprd_phy_param_parse(struct sdhci_sprd_host *sprd_host,
+ struct device_node *np)
+{
+ u32 *p = sprd_host->phy_delay;
+ int ret, i, index;
+ u32 val[4];
+
+ for (i = 0; i < ARRAY_SIZE(sdhci_sprd_phy_cfgs); i++) {
+ ret = of_property_read_u32_array(np,
+ sdhci_sprd_phy_cfgs[i].property, val, 4);
+ if (ret)
+ continue;
+
+ index = sdhci_sprd_phy_cfgs[i].timing;
+ p[index] = val[0] | (val[1] << 8) | (val[2] << 16) | (val[3] << 24);
+ }
+}
+
static const struct sdhci_pltfm_data sdhci_sprd_pdata = {
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
.quirks2 = SDHCI_QUIRK2_BROKEN_HS200 |
@@ -338,6 +521,16 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
host->dma_mask = DMA_BIT_MASK(64);
pdev->dev.dma_mask = &host->dma_mask;
host->mmc_host_ops.request = sdhci_sprd_request;
+ host->mmc_host_ops.hs400_enhanced_strobe =
+ sdhci_sprd_hs400_enhanced_strobe;
+ /*
+ * We can not use the standard ops to change and detect the voltage
+ * signal for Spreadtrum SD host controller, since our voltage regulator
+ * for I/O is fixed in hardware, that means we do not need control
+ * the standard SD host controller to change the I/O voltage.
+ */
+ host->mmc_host_ops.start_signal_voltage_switch =
+ sdhci_sprd_voltage_switch;
host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_ERASE | MMC_CAP_CMD23;
@@ -346,6 +539,24 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
goto pltfm_free;
sprd_host = TO_SPRD_HOST(host);
+ sdhci_sprd_phy_param_parse(sprd_host, pdev->dev.of_node);
+
+ sprd_host->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (!IS_ERR(sprd_host->pinctrl)) {
+ sprd_host->pins_uhs =
+ pinctrl_lookup_state(sprd_host->pinctrl, "state_uhs");
+ if (IS_ERR(sprd_host->pins_uhs)) {
+ ret = PTR_ERR(sprd_host->pins_uhs);
+ goto pltfm_free;
+ }
+
+ sprd_host->pins_default =
+ pinctrl_lookup_state(sprd_host->pinctrl, "default");
+ if (IS_ERR(sprd_host->pins_default)) {
+ ret = PTR_ERR(sprd_host->pins_default);
+ goto pltfm_free;
+ }
+ }
clk = devm_clk_get(&pdev->dev, "sdio");
if (IS_ERR(clk)) {
@@ -364,14 +575,22 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
}
sprd_host->clk_enable = clk;
+ clk = devm_clk_get(&pdev->dev, "2x_enable");
+ if (!IS_ERR(clk))
+ sprd_host->clk_2x_enable = clk;
+
ret = clk_prepare_enable(sprd_host->clk_sdio);
if (ret)
goto pltfm_free;
- clk_prepare_enable(sprd_host->clk_enable);
+ ret = clk_prepare_enable(sprd_host->clk_enable);
if (ret)
goto clk_disable;
+ ret = clk_prepare_enable(sprd_host->clk_2x_enable);
+ if (ret)
+ goto clk_disable2;
+
sdhci_sprd_init_config(host);
host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
sprd_host->version = ((host->version & SDHCI_VENDOR_VER_MASK) >>
@@ -408,6 +627,9 @@ pm_runtime_disable:
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+ clk_disable_unprepare(sprd_host->clk_2x_enable);
+
+clk_disable2:
clk_disable_unprepare(sprd_host->clk_enable);
clk_disable:
@@ -427,6 +649,7 @@ static int sdhci_sprd_remove(struct platform_device *pdev)
mmc_remove_host(mmc);
clk_disable_unprepare(sprd_host->clk_sdio);
clk_disable_unprepare(sprd_host->clk_enable);
+ clk_disable_unprepare(sprd_host->clk_2x_enable);
mmc_free_host(mmc);
@@ -449,6 +672,7 @@ static int sdhci_sprd_runtime_suspend(struct device *dev)
clk_disable_unprepare(sprd_host->clk_sdio);
clk_disable_unprepare(sprd_host->clk_enable);
+ clk_disable_unprepare(sprd_host->clk_2x_enable);
return 0;
}
@@ -459,19 +683,28 @@ static int sdhci_sprd_runtime_resume(struct device *dev)
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
int ret;
- ret = clk_prepare_enable(sprd_host->clk_enable);
+ ret = clk_prepare_enable(sprd_host->clk_2x_enable);
if (ret)
return ret;
+ ret = clk_prepare_enable(sprd_host->clk_enable);
+ if (ret)
+ goto clk_2x_disable;
+
ret = clk_prepare_enable(sprd_host->clk_sdio);
- if (ret) {
- clk_disable_unprepare(sprd_host->clk_enable);
- return ret;
- }
+ if (ret)
+ goto clk_disable;
sdhci_runtime_resume_host(host);
-
return 0;
+
+clk_disable:
+ clk_disable_unprepare(sprd_host->clk_enable);
+
+clk_2x_disable:
+ clk_disable_unprepare(sprd_host->clk_2x_enable);
+
+ return ret;
}
#endif
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 781a3e106d9a..f4d4761cf20a 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -1541,8 +1541,11 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
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);
+
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "failed to get clock: %d\n", rc);
+
goto err_clk_get;
}
clk_prepare_enable(clk);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 199712e7adbb..89fd96596a1f 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -89,7 +89,7 @@
#define SDHCI_CTRL_ADMA32 0x10
#define SDHCI_CTRL_ADMA64 0x18
#define SDHCI_CTRL_ADMA3 0x18
-#define SDHCI_CTRL_8BITBUS 0x20
+#define SDHCI_CTRL_8BITBUS 0x20
#define SDHCI_CTRL_CDTEST_INS 0x40
#define SDHCI_CTRL_CDTEST_EN 0x80
diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index 3222ea4d584d..bb90757ecace 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -6,6 +6,7 @@
*
*/
#include <linux/clk.h>
+#include <linux/of.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -36,11 +37,14 @@
#define OTAPDLYSEL_SHIFT 12
#define OTAPDLYSEL_MASK GENMASK(15, 12)
#define STRBSEL_SHIFT 24
-#define STRBSEL_MASK GENMASK(27, 24)
+#define STRBSEL_4BIT_MASK GENMASK(27, 24)
+#define STRBSEL_8BIT_MASK GENMASK(31, 24)
#define SEL50_SHIFT 8
#define SEL50_MASK BIT(SEL50_SHIFT)
#define SEL100_SHIFT 9
#define SEL100_MASK BIT(SEL100_SHIFT)
+#define FREQSEL_SHIFT 8
+#define FREQSEL_MASK GENMASK(10, 8)
#define DLL_TRIM_ICP_SHIFT 4
#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
#define DR_TY_SHIFT 20
@@ -77,19 +81,29 @@ struct sdhci_am654_data {
int trm_icp;
int drv_strength;
bool dll_on;
+ int strb_sel;
+ u32 flags;
+};
+
+struct sdhci_am654_driver_data {
+ const struct sdhci_pltfm_data *pdata;
+ u32 flags;
+#define IOMUX_PRESENT (1 << 0)
+#define FREQSEL_2_BIT (1 << 1)
+#define STRBSEL_4_BIT (1 << 2)
+#define DLL_PRESENT (1 << 3)
};
static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
- int sel50, sel100;
+ int sel50, sel100, freqsel;
u32 mask, val;
int ret;
if (sdhci_am654->dll_on) {
- regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
- ENDLL_MASK, 0);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
sdhci_am654->dll_on = false;
}
@@ -101,27 +115,53 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
val = (1 << OTAPDLYENA_SHIFT) |
(sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
- regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
- mask, val);
- switch (clock) {
- case 200000000:
- sel50 = 0;
- sel100 = 0;
- break;
- case 100000000:
- sel50 = 0;
- sel100 = 1;
- break;
- default:
- sel50 = 1;
- sel100 = 0;
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
+ /* Write to STRBSEL for HS400 speed mode */
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
+ if (sdhci_am654->flags & STRBSEL_4_BIT)
+ mask = STRBSEL_4BIT_MASK;
+ else
+ mask = STRBSEL_8BIT_MASK;
+
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask,
+ sdhci_am654->strb_sel <<
+ STRBSEL_SHIFT);
+ }
+
+ if (sdhci_am654->flags & FREQSEL_2_BIT) {
+ switch (clock) {
+ case 200000000:
+ sel50 = 0;
+ sel100 = 0;
+ break;
+ case 100000000:
+ sel50 = 0;
+ sel100 = 1;
+ break;
+ default:
+ sel50 = 1;
+ sel100 = 0;
+ }
+
+ /* Configure PHY DLL frequency */
+ mask = SEL50_MASK | SEL100_MASK;
+ val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask,
+ val);
+ } else {
+ switch (clock) {
+ case 200000000:
+ freqsel = 0x0;
+ break;
+ default:
+ freqsel = 0x4;
+ }
+
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
+ FREQSEL_MASK,
+ freqsel << FREQSEL_SHIFT);
}
- /* Configure PHY DLL frequency */
- mask = SEL50_MASK | SEL100_MASK;
- val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
- regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
- mask, val);
/* Configure DLL TRIM */
mask = DLL_TRIM_ICP_MASK;
val = sdhci_am654->trm_icp << DLL_TRIM_ICP_SHIFT;
@@ -129,24 +169,41 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
/* Configure DLL driver strength */
mask |= DR_TY_MASK;
val |= sdhci_am654->drv_strength << DR_TY_SHIFT;
- regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
- mask, val);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1, mask, val);
/* Enable DLL */
- regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
- ENDLL_MASK, 0x1 << ENDLL_SHIFT);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK,
+ 0x1 << ENDLL_SHIFT);
/*
* Poll for DLL ready. Use a one second timeout.
* Works in all experiments done so far
*/
- ret = regmap_read_poll_timeout(sdhci_am654->base,
- PHY_STAT1, val,
- val & DLLRDY_MASK,
- 1000, 1000000);
+ ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
+ val, val & DLLRDY_MASK, 1000,
+ 1000000);
+ if (ret) {
+ dev_err(mmc_dev(host->mmc), "DLL failed to relock\n");
+ return;
+ }
sdhci_am654->dll_on = true;
}
}
+static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
+ unsigned int clock)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
+ int val, mask;
+
+ mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
+ val = (1 << OTAPDLYENA_SHIFT) |
+ (sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
+
+ sdhci_set_clock(host, clock);
+}
+
static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode,
unsigned short vdd)
{
@@ -197,6 +254,56 @@ static const struct sdhci_pltfm_data sdhci_am654_pdata = {
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
};
+static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
+ .pdata = &sdhci_am654_pdata,
+ .flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT,
+};
+
+static struct sdhci_ops sdhci_j721e_8bit_ops = {
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+ .set_bus_width = sdhci_set_bus_width,
+ .set_power = sdhci_am654_set_power,
+ .set_clock = sdhci_am654_set_clock,
+ .write_b = sdhci_am654_write_b,
+ .reset = sdhci_reset,
+};
+
+static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = {
+ .ops = &sdhci_j721e_8bit_ops,
+ .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
+ SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
+static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = {
+ .pdata = &sdhci_j721e_8bit_pdata,
+ .flags = DLL_PRESENT,
+};
+
+static struct sdhci_ops sdhci_j721e_4bit_ops = {
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+ .set_bus_width = sdhci_set_bus_width,
+ .set_power = sdhci_am654_set_power,
+ .set_clock = sdhci_j721e_4bit_set_clock,
+ .write_b = sdhci_am654_write_b,
+ .reset = sdhci_reset,
+};
+
+static const struct sdhci_pltfm_data sdhci_j721e_4bit_pdata = {
+ .ops = &sdhci_j721e_4bit_ops,
+ .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
+ SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
+static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = {
+ .pdata = &sdhci_j721e_4bit_pdata,
+ .flags = IOMUX_PRESENT,
+};
static int sdhci_am654_init(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -208,30 +315,34 @@ static int sdhci_am654_init(struct sdhci_host *host)
/* Reset OTAP to default value */
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
- regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
- mask, 0x0);
-
- regmap_read(sdhci_am654->base, PHY_STAT1, &val);
- if (~val & CALDONE_MASK) {
- /* Calibrate IO lines */
- regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
- PDB_MASK, PDB_MASK);
- ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
- val, val & CALDONE_MASK, 1, 20);
- if (ret)
- return ret;
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, 0x0);
+
+ if (sdhci_am654->flags & DLL_PRESENT) {
+ regmap_read(sdhci_am654->base, PHY_STAT1, &val);
+ if (~val & CALDONE_MASK) {
+ /* Calibrate IO lines */
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+ PDB_MASK, PDB_MASK);
+ ret = regmap_read_poll_timeout(sdhci_am654->base,
+ PHY_STAT1, val,
+ val & CALDONE_MASK,
+ 1, 20);
+ if (ret)
+ return ret;
+ }
}
/* Enable pins by setting IO mux to 0 */
- regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
- IOMUX_ENABLE_MASK, 0);
+ if (sdhci_am654->flags & IOMUX_PRESENT)
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+ IOMUX_ENABLE_MASK, 0);
/* Set slot type based on SD or eMMC */
if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
ctl_cfg_2 = SLOTTYPE_EMBEDDED;
- regmap_update_bits(sdhci_am654->base, CTL_CFG_2,
- SLOTTYPE_MASK, ctl_cfg_2);
+ regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK,
+ ctl_cfg_2);
return sdhci_add_host(host);
}
@@ -243,51 +354,73 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev,
int drv_strength;
int ret;
- ret = device_property_read_u32(dev, "ti,trm-icp",
- &sdhci_am654->trm_icp);
- if (ret)
- return ret;
-
ret = device_property_read_u32(dev, "ti,otap-del-sel",
&sdhci_am654->otap_del_sel);
if (ret)
return ret;
- ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
- &drv_strength);
- if (ret)
- return ret;
+ if (sdhci_am654->flags & DLL_PRESENT) {
+ ret = device_property_read_u32(dev, "ti,trm-icp",
+ &sdhci_am654->trm_icp);
+ if (ret)
+ return ret;
- switch (drv_strength) {
- case 50:
- sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
- break;
- case 33:
- sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
- break;
- case 66:
- sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
- break;
- case 100:
- sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
- break;
- case 40:
- sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
- break;
- default:
- dev_err(dev, "Invalid driver strength\n");
- return -EINVAL;
+ ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
+ &drv_strength);
+ if (ret)
+ return ret;
+
+ switch (drv_strength) {
+ case 50:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
+ break;
+ case 33:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
+ break;
+ case 66:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
+ break;
+ case 100:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
+ break;
+ case 40:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
+ break;
+ default:
+ dev_err(dev, "Invalid driver strength\n");
+ return -EINVAL;
+ }
}
+ device_property_read_u32(dev, "ti,strobe-sel", &sdhci_am654->strb_sel);
+
sdhci_get_of_property(pdev);
return 0;
}
+static const struct of_device_id sdhci_am654_of_match[] = {
+ {
+ .compatible = "ti,am654-sdhci-5.1",
+ .data = &sdhci_am654_drvdata,
+ },
+ {
+ .compatible = "ti,j721e-sdhci-8bit",
+ .data = &sdhci_j721e_8bit_drvdata,
+ },
+ {
+ .compatible = "ti,j721e-sdhci-4bit",
+ .data = &sdhci_j721e_4bit_drvdata,
+ },
+ { /* sentinel */ }
+};
+
static int sdhci_am654_probe(struct platform_device *pdev)
{
+ const struct sdhci_am654_driver_data *drvdata;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_am654_data *sdhci_am654;
+ const struct of_device_id *match;
struct sdhci_host *host;
struct resource *res;
struct clk *clk_xin;
@@ -295,12 +428,15 @@ static int sdhci_am654_probe(struct platform_device *pdev)
void __iomem *base;
int ret;
- host = sdhci_pltfm_init(pdev, &sdhci_am654_pdata, sizeof(*sdhci_am654));
+ match = of_match_node(sdhci_am654_of_match, pdev->dev.of_node);
+ drvdata = match->data;
+ host = sdhci_pltfm_init(pdev, drvdata->pdata, sizeof(*sdhci_am654));
if (IS_ERR(host))
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
+ sdhci_am654->flags = drvdata->flags;
clk_xin = devm_clk_get(dev, "clk_xin");
if (IS_ERR(clk_xin)) {
@@ -375,11 +511,6 @@ static int sdhci_am654_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id sdhci_am654_of_match[] = {
- { .compatible = "ti,am654-sdhci-5.1" },
- { /* sentinel */ }
-};
-
static struct platform_driver sdhci_am654_driver = {
.driver = {
.name = "sdhci-am654",
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 93e83ad25976..8539e10784b4 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -172,6 +172,8 @@ static int tmio_mmc_probe(struct platform_device *pdev)
host->mmc->f_max = pdata->hclk;
host->mmc->f_min = pdata->hclk / 512;
+ pm_runtime_enable(&pdev->dev);
+
ret = tmio_mmc_host_probe(host);
if (ret)
goto host_free;
@@ -191,6 +193,7 @@ host_remove:
tmio_mmc_host_remove(host);
host_free:
tmio_mmc_host_free(host);
+ pm_runtime_disable(&pdev->dev);
cell_disable:
if (cell->disable)
cell->disable(pdev);
@@ -207,6 +210,8 @@ static int tmio_mmc_remove(struct platform_device *pdev)
if (cell->disable)
cell->disable(pdev);
+ pm_runtime_disable(&pdev->dev);
+
return 0;
}
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 84cb7d2aacdf..2cb3f951c3e2 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/dma-mapping.h>
#include <linux/highmem.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -45,7 +46,6 @@
#include <linux/scatterlist.h>
#include <linux/sizes.h>
#include <linux/spinlock.h>
-#include <linux/swiotlb.h>
#include <linux/workqueue.h>
#include "tmio_mmc.h"
@@ -1153,6 +1153,15 @@ void tmio_mmc_host_free(struct tmio_mmc_host *host)
}
EXPORT_SYMBOL_GPL(tmio_mmc_host_free);
+/**
+ * tmio_mmc_host_probe() - Common probe for all implementations
+ * @_host: Host to probe
+ *
+ * Perform tasks common to all implementations probe functions.
+ *
+ * The caller should have called pm_runtime_enable() prior to calling
+ * the common probe function.
+ */
int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
{
struct platform_device *pdev = _host->pdev;
@@ -1190,19 +1199,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
mmc->max_blk_size = TMIO_MAX_BLK_SIZE;
mmc->max_blk_count = pdata->max_blk_count ? :
(PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;
- mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
- /*
- * Since swiotlb has memory size limitation, this will calculate
- * the maximum size locally (because we don't have any APIs for it now)
- * and check the current max_req_size. And then, this will update
- * the max_req_size if needed as a workaround.
- */
- if (swiotlb_max_segment()) {
- unsigned int max_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE;
-
- if (mmc->max_req_size > max_size)
- mmc->max_req_size = max_size;
- }
+ mmc->max_req_size = min_t(size_t,
+ mmc->max_blk_size * mmc->max_blk_count,
+ dma_max_mapping_size(&pdev->dev));
mmc->max_seg_size = mmc->max_req_size;
if (mmc_can_gpio_ro(mmc))
@@ -1261,7 +1260,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
ret = mmc_add_host(mmc);
if (ret)
@@ -1297,7 +1295,6 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
}
EXPORT_SYMBOL_GPL(tmio_mmc_host_remove);
diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c
index 91a2be41edf6..49aad9a79c18 100644
--- a/drivers/mmc/host/uniphier-sd.c
+++ b/drivers/mmc/host/uniphier-sd.c
@@ -631,6 +631,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
host->clk_disable = uniphier_sd_clk_disable;
host->set_clock = uniphier_sd_set_clock;
+ pm_runtime_enable(&pdev->dev);
ret = uniphier_sd_clk_enable(host);
if (ret)
goto free_host;
@@ -652,6 +653,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
free_host:
tmio_mmc_host_free(host);
+ pm_runtime_disable(&pdev->dev);
return ret;
}
@@ -662,6 +664,7 @@ static int uniphier_sd_remove(struct platform_device *pdev)
tmio_mmc_host_remove(host);
uniphier_sd_clk_disable(host);
+ pm_runtime_disable(&pdev->dev);
return 0;
}