summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
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/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.c85
-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-of-esdhc.c17
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c2
-rw-r--r--drivers/mmc/host/sdhci-sprd.c171
-rw-r--r--drivers/mmc/host/sdhci-tegra.c5
-rw-r--r--drivers/mmc/host/sdhci_am654.c292
-rw-r--r--drivers/mmc/host/tmio_mmc.c5
-rw-r--r--drivers/mmc/host/tmio_mmc_core.c11
-rw-r--r--drivers/mmc/host/uniphier-sd.c3
17 files changed, 520 insertions, 290 deletions
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index d2275c5a2311..cc3be259bc42 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -230,45 +230,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)
@@ -285,25 +261,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/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c
index 61e4e2a213c9..f6334c2a75bb 100644
--- a/drivers/mmc/host/android-goldfish.c
+++ b/drivers/mmc/host/android-goldfish.c
@@ -113,7 +113,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;
@@ -175,7 +174,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;
}
@@ -221,8 +220,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;
@@ -236,7 +235,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;
}
@@ -278,7 +277,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);
}
}
@@ -313,7 +312,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)
@@ -339,12 +338,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);
@@ -383,7 +383,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;
@@ -461,7 +461,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));
@@ -508,8 +507,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,
@@ -525,7 +523,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;
}
@@ -533,14 +531,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 735aa5871358..e1f10c3fa144 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -579,42 +579,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 5582561586b4..26f33431120e 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Amlogic SD/eMMC driver for the GX/S905 family SoCs
*
* Copyright (c) 2016 BayLibre, SAS.
* Author: Kevin Hilman <khilman@baylibre.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -129,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 */
@@ -168,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;
@@ -232,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
@@ -1049,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);
@@ -1146,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;
/*
@@ -1158,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,
@@ -1183,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:
@@ -1208,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 f31333e831a7..6a91db7ca5f1 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -1452,33 +1452,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 30c2c0dd1bc8..62cae53b4271 100644
--- a/drivers/mmc/host/s3cmci.h
+++ b/drivers/mmc/host/s3cmci.h
@@ -70,8 +70,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-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..fa6a8fa560c3 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -2040,8 +2040,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-sprd.c b/drivers/mmc/host/sdhci-sprd.c
index 9a822e2e9f0b..024c3c5fa979 100644
--- a/drivers/mmc/host/sdhci-sprd.c
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -22,6 +22,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 +50,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 +65,33 @@
#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;
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 +161,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 +228,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 +266,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 +296,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 +337,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 +363,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 +380,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 +403,50 @@ static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
sdhci_request(mmc, mrq);
}
+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 s