diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/core/debugfs.c | 56 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc_test.c | 10 | ||||
| -rw-r--r-- | drivers/mmc/host/android-goldfish.c | 31 | ||||
| -rw-r--r-- | drivers/mmc/host/atmel-mci.c | 38 | ||||
| -rw-r--r-- | drivers/mmc/host/dw_mmc.c | 36 | ||||
| -rw-r--r-- | drivers/mmc/host/meson-gx-mmc.c | 85 | ||||
| -rw-r--r-- | drivers/mmc/host/renesas_sdhi_core.c | 19 | ||||
| -rw-r--r-- | drivers/mmc/host/s3cmci.c | 27 | ||||
| -rw-r--r-- | drivers/mmc/host/s3cmci.h | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-of-esdhc.c | 17 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-pci-core.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-sprd.c | 171 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci_am654.c | 292 | ||||
| -rw-r--r-- | drivers/mmc/host/tmio_mmc.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/host/tmio_mmc_core.c | 11 | ||||
| -rw-r--r-- | drivers/mmc/host/uniphier-sd.c | 3 |
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 |
