From fdc4e755f6c516e526dd9396b6eb05712c44fb65 Mon Sep 17 00:00:00 2001 From: Kamlesh Gurudasani Date: Wed, 8 May 2019 01:22:29 +0530 Subject: mmc: android-goldfish: Drop pointer to mmc_host from goldfish_mmc_host The driver for android-goldfish uses a pointer to get from the private goldfish_mmc_host structure to the generic mmc_host structure. However the latter is always immediately preceding the former in memory, so compute its address with a subtraction (which is cheaper than a dereference) and drop the superfluous pointer. No functional change intended. Signed-off-by: Kamlesh Gurudasani Signed-off-by: Ulf Hansson --- drivers/mmc/host/android-goldfish.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/mmc') 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; } -- cgit v1.2.3-70-g09d2 From 7ff213193310ef8d0ee5f04f79d791210787ac2c Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Thu, 11 Apr 2019 00:22:40 +0200 Subject: mmc: tmio: move runtime PM enablement to the driver implementations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both the Renesas and Uniphier implementations perform actions which affect runtime PM before calling into the core tmio_mmc_host_probe() which enabled runtime PM. Move pm_runtime_enable() from the core and tmio_mmc_host_probe() into each drivers probe() so it can be called before any clocks or other resources are switched on. Reported-by: Geert Uytterhoeven Signed-off-by: Niklas Söderlund Acked-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 6 ++++++ drivers/mmc/host/tmio_mmc.c | 5 +++++ drivers/mmc/host/tmio_mmc_core.c | 11 +++++++++-- drivers/mmc/host/uniphier-sd.c | 3 +++ 4 files changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 5e9e36ed2107..db73f9f1b186 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -770,6 +770,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; @@ -850,6 +852,8 @@ edisclk: efree: tmio_mmc_host_free(host); + pm_runtime_disable(&pdev->dev); + return ret; } EXPORT_SYMBOL_GPL(renesas_sdhi_probe); @@ -861,6 +865,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/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..83fd94341113 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -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; @@ -1261,7 +1270,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 +1305,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; } -- cgit v1.2.3-70-g09d2 From 754aee559160fe6a9d7debe9f1ad07d060e6ae93 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 20 May 2019 16:36:46 +0200 Subject: mmc: meson-gx-mmc: update with SPDX Licence identifier Signed-off-by: Neil Armstrong Acked-by: Kevin Hilman Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 5582561586b4..747d92daf9d7 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 - * - * 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 . - * The full GNU General Public License is included in this distribution - * in the file called COPYING. */ #include #include -- cgit v1.2.3-70-g09d2 From acdc8e71d9bb0bdef66b002f8baf8af3147df00c Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 27 May 2019 14:43:06 +0200 Subject: mmc: meson-gx: add dram-access-quirk On the Amlogic G12A SoC family, (only) the SDIO controller fails to access the data from DRAM, leading to a broken controller. But each MMC controller has 1,5KiB of SRAM after the registers, that can be used as bounce buffer to avoid direct DRAM access from the integrated DMAs (this SRAM may be used by the boot ROM when DRAM is not yet initialized). The quirk is to disable the chained descriptor for this controller, and use this SRAM memory zone as buffer for the bounce buffer fallback mode. The performance hit hasn't been evaluated, but the fix has been tested using a WiFi AP6398S SDIO module, and the iperf3 Bandwidth measurement gave 55.2 Mbits/sec over a 63 Hours long test, with the SDIO ios set as High-Speed at 50MHz clock. It gave 170 Mbits/sec as SDR104 and 200MHz clock. Reviewed-by: Kevin Hilman Tested-by: Guillaume La Roque Signed-off-by: Neil Armstrong Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 70 ++++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 15 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 747d92daf9d7..26f33431120e 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,11 +224,20 @@ 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 @@ -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); -- cgit v1.2.3-70-g09d2 From 8023cf2634b051ff53739a035a0c1bef3cbb389c Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Tue, 28 May 2019 15:29:27 +0530 Subject: mmc: sdhci_am654: Improve whitespace utilisation with regmap_*() calls Line wrapping with the regmap_*() functions is way more conservative than required by the 80 character rule. Expand the function calls out to use less number of lines. Signed-off-by: Faiz Abbas Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_am654.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 3222ea4d584d..3c32d9fb6e1e 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -88,8 +88,7 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) 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,8 +100,7 @@ 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); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); switch (clock) { case 200000000: sel50 = 0; @@ -120,8 +118,7 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) /* 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); + 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,20 +126,17 @@ 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); sdhci_am654->dll_on = true; } } @@ -208,8 +202,7 @@ 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_update_bits(sdhci_am654->base, PHY_CTRL4, mask, 0x0); regmap_read(sdhci_am654->base, PHY_STAT1, &val); if (~val & CALDONE_MASK) { @@ -223,15 +216,14 @@ static int sdhci_am654_init(struct sdhci_host *host) } /* Enable pins by setting IO mux to 0 */ - regmap_update_bits(sdhci_am654->base, PHY_CTRL1, - IOMUX_ENABLE_MASK, 0); + 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); } -- cgit v1.2.3-70-g09d2 From 7e24e28b79b3df4fb1db40f26c46e0a3480eede4 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Tue, 28 May 2019 15:29:28 +0530 Subject: mmc: sdhci_am654: Print error message if the DLL fails to lock Print an error message and return if DLL fails to lock. Signed-off-by: Faiz Abbas Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_am654.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 3c32d9fb6e1e..d0b20780dd0f 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -137,6 +137,11 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) 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; } } -- cgit v1.2.3-70-g09d2 From 90298dc353bc1327d59da30d4b1e4d50d5513033 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 31 May 2019 12:32:23 +0100 Subject: mmc: sdhci-pci: remove redundant check of slots == 0 The calculation of slots results in a value in the range 1..8 and so slots can never be zero. The check for slots == 0 is always going to be false, hence it is redundant and can be removed. Addresses-Coverity: ("Logically dead code") Signed-off-by: Colin Ian King Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mmc') 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); -- cgit v1.2.3-70-g09d2 From 1d94717ddcc7bca9482b8a2f22cd2cac7ce2ca50 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 4 Jun 2019 16:14:21 +0800 Subject: mmc: sdhci-sprd: Check the enable clock's return value correctly Missed to check the enable clock's return value, fix it. Signed-off-by: Baolin Wang Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index 9a822e2e9f0b..e7414918e100 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -368,7 +368,7 @@ static int sdhci_sprd_probe(struct platform_device *pdev) 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; -- cgit v1.2.3-70-g09d2 From ebd88a38dbf91c496ec1167c1d9a4eaf095dd704 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 4 Jun 2019 16:14:23 +0800 Subject: mmc: sdhci-sprd: Add optional gate clock support For the Spreadtrum SC9860 platform, we should enable another gate clock '2x_enable' to make the SD host controller work well. Signed-off-by: Baolin Wang Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index e7414918e100..31ba7d65369f 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -60,6 +60,7 @@ 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 */ }; @@ -364,6 +365,10 @@ 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; @@ -372,6 +377,10 @@ static int sdhci_sprd_probe(struct platform_device *pdev) 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 +417,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 +439,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 +462,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 +473,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 -- cgit v1.2.3-70-g09d2 From 7486831d7d6aebcf851f9a4bbe65080351d5c9fb Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 4 Jun 2019 16:14:24 +0800 Subject: mmc: sdhci-sprd: Implement the get_max_timeout_count() interface Implement the get_max_timeout_count() interface to set the Spredtrum SD host controller actual maximum timeout count. Signed-off-by: Baolin Wang Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index 31ba7d65369f..d91281d02cdb 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -285,6 +285,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, @@ -296,6 +302,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) -- cgit v1.2.3-70-g09d2 From 494c11e1a5366d3f5adb2cb2b677b5b0bcf08e3b Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 4 Jun 2019 16:14:25 +0800 Subject: mmc: sdhci-sprd: Add HS400 enhanced strobe mode Add HS400 enhanced strobe mode support for Spreadtrum SD host controller. Signed-off-by: Baolin Wang Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index d91281d02cdb..edec19755ecd 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -41,6 +41,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 @@ -132,6 +133,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) { @@ -325,6 +335,26 @@ 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); + 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); +} + static const struct sdhci_pltfm_data sdhci_sprd_pdata = { .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, .quirks2 = SDHCI_QUIRK2_BROKEN_HS200 | @@ -346,6 +376,8 @@ 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; host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_ERASE | MMC_CAP_CMD23; -- cgit v1.2.3-70-g09d2 From 87a395c27bfab5048413ea18287f0f9453e3e31a Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 4 Jun 2019 16:14:26 +0800 Subject: mmc: sdhci-sprd: Enable PHY DLL to make clock stable For the Spreadtrum SD host controller, 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. Signed-off-by: Baolin Wang Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 44 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index edec19755ecd..e6eda13e34ea 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -22,6 +22,13 @@ /* 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_OFFSET 0x208 #define SDHCIBSPRD_IT_WR_DLY_INV BIT(5) #define SDHCI_SPRD_BIT_CMD_DLY_INV BIT(13) @@ -56,6 +63,7 @@ #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; @@ -200,9 +208,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); @@ -214,9 +246,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) -- cgit v1.2.3-70-g09d2 From 5f2f4e0da2b5d4f4a188480c13f40c848a5f7d15 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 4 Jun 2019 16:14:28 +0800 Subject: mmc: sdhci-sprd: Add PHY DLL delay configuration Set the PHY DLL delay for each timing mode, which is used to sample the clock accurately and make the clock more stable. Signed-off-by: Baolin Wang Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index e6eda13e34ea..024c3c5fa979 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -29,6 +29,8 @@ #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) @@ -72,6 +74,24 @@ struct sdhci_sprd_host { 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)) @@ -276,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) @@ -314,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) @@ -381,6 +407,8 @@ 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) @@ -395,6 +423,28 @@ static void sdhci_sprd_hs400_enhanced_strobe(struct mmc_host *mmc, 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 = { @@ -428,6 +478,7 @@ 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); clk = devm_clk_get(&pdev->dev, "sdio"); if (IS_ERR(clk)) { -- cgit v1.2.3-70-g09d2 From 00a9584eadf39b12dac7495250dc508c6b106f81 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 4 Jun 2019 17:34:46 +0200 Subject: sdhci: tegra: Do not log error message on deferred probe Recent changes have made it much more likely that clocks are not available, when the SDHCI driver is first probed. However, that is a situation that the driver can cope with just fine. To avoid confusion, don't output an error when this happens. Signed-off-by: Thierry Reding Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') 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); -- cgit v1.2.3-70-g09d2 From 6a6869869a37e61ec0521653bacc8f39dfaae0e2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 6 Jun 2019 13:35:36 +0200 Subject: mmc: sdhi: improve quirk descriptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quirks show up in new SoCs as well, so the naming should be generic. Describe them by what they do. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 683c449a2f94..24857ced9f2e 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -610,12 +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 = { +static const struct renesas_sdhi_quirks sdhi_quirks_4tap = { .hs400_disabled = false, .hs400_4taps = true, }; @@ -625,10 +625,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. */ }, }; -- cgit v1.2.3-70-g09d2 From ef4a8d90b7f495a5b32375e33d5d2fd763a6a18c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 6 Jun 2019 13:35:37 +0200 Subject: mmc: sdhi: remove unneeded initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bools are initialized to 'false' by default. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 24857ced9f2e..64d3b5fb7fe5 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -616,7 +616,6 @@ static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400 = { }; static const struct renesas_sdhi_quirks sdhi_quirks_4tap = { - .hs400_disabled = false, .hs400_4taps = true, }; -- cgit v1.2.3-70-g09d2 From 99909b55f2982e548f594e8c8e2310b50d3254ce Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Tue, 4 Jun 2019 11:39:12 +0530 Subject: mmc: sdhci_am654: Add Support for 8 bit IP on J721E The 8 bit IP on the TI's J721E device departs from the AM654x IP in some ways which require special handling. Create a driver_data structure which holds the pltfm_data and a flags field which is used to indicate these differences. These are the following: 1. The pins are not muxed with anything else inside the SoC and hence the IOMUX_ENABLE field does not exist. Add a flag which is used to indicate the presence of the field. 2. The register field used to select DLL frequency is 3 bit wide as compared to 2 bits in AM65x. Add another flag which differentiates between 3 bit and 2 bit fields. 3. The strobe select field is 8 bit wide as compared to 4 bits for AM65x. Add yet another flag to indicate this difference. Strobe select is used only for HS400 speed mode, support for which has not yet been added in AM65x. Signed-off-by: Faiz Abbas Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_am654.c | 135 +++++++++++++++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 25 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index d0b20780dd0f..4575aeb435ec 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -6,6 +6,7 @@ * */ #include +#include #include #include #include @@ -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,13 +81,23 @@ 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) }; 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; @@ -101,24 +115,52 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) 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; + /* 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; @@ -196,6 +238,33 @@ 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, +}; + +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, +}; + static int sdhci_am654_init(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -221,7 +290,9 @@ static int sdhci_am654_init(struct sdhci_host *host) } /* 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) @@ -276,15 +347,31 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev, 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, + }, + { /* 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; @@ -292,12 +379,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)) { @@ -372,11 +462,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", -- cgit v1.2.3-70-g09d2 From 1accbced1c3273ead1d30de14339c4a39062bee0 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Tue, 4 Jun 2019 11:39:13 +0530 Subject: mmc: sdhci_am654: Add Support for 4 bit IP on J721E Add support for 4 bit instances on TI's J721E devices. Because these instances have no DLL, introduce a DLL_PRESENT flag and make sure DLL related registers are only accessed when it is present. Also add a separate set_clock callback for this compatible. Signed-off-by: Faiz Abbas Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_am654.c | 124 ++++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 38 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 4575aeb435ec..3b3948144591 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -91,6 +91,7 @@ struct sdhci_am654_driver_data { #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) @@ -188,6 +189,20 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) } } +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) { @@ -240,7 +255,7 @@ static const struct sdhci_pltfm_data sdhci_am654_pdata = { static const struct sdhci_am654_driver_data sdhci_am654_drvdata = { .pdata = &sdhci_am654_pdata, - .flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT, + .flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT, }; struct sdhci_ops sdhci_j721e_8bit_ops = { @@ -263,8 +278,31 @@ static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = { static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = { .pdata = &sdhci_j721e_8bit_pdata, + .flags = DLL_PRESENT, +}; + +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); @@ -278,15 +316,19 @@ static int sdhci_am654_init(struct sdhci_host *host) 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; + 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 */ @@ -311,40 +353,42 @@ 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; + + 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; + 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); @@ -363,6 +407,10 @@ static const struct of_device_id sdhci_am654_of_match[] = { .compatible = "ti,j721e-sdhci-8bit", .data = &sdhci_j721e_8bit_drvdata, }, + { + .compatible = "ti,j721e-sdhci-4bit", + .data = &sdhci_j721e_4bit_drvdata, + }, { /* sentinel */ } }; -- cgit v1.2.3-70-g09d2 From a04c50aaa916f8c5704ef8292928095ccb4469b6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Jun 2019 10:25:28 +0200 Subject: mmc: core: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Ulf Hansson --- drivers/mmc/core/debugfs.c | 56 +++++++-------------------------------------- drivers/mmc/core/mmc_test.c | 10 +------- 2 files changed, 9 insertions(+), 57 deletions(-) (limited to 'drivers/mmc') 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) { -- cgit v1.2.3-70-g09d2 From 091eb12f62b06bcf7e7cf4e4ae55e1d5ab2c25e3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Jun 2019 10:25:29 +0200 Subject: mmc: host: atmel-mci: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Cc: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman Acked-by: Alexandre Belloni Acked-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) (limited to 'drivers/mmc') 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) -- cgit v1.2.3-70-g09d2 From fcac152782e302a553c6d197d5fb38224b50023e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Jun 2019 10:25:30 +0200 Subject: mmc: host: dw_mmc: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this Cc: Jaehoon Chung Signed-off-by: Greg Kroah-Hartman Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) (limited to 'drivers/mmc') 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) */ -- cgit v1.2.3-70-g09d2 From 5928d8929d8cc3ba89f0af57ddeecaa004aa2340 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Jun 2019 10:25:31 +0200 Subject: mmc: host: s3cmci: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Also, because there is no need to save the file dentries, remove them from the host-specific structure and just recursively delete the directory that the driver created, when shutting down. Cc: Ben Dooks Signed-off-by: Greg Kroah-Hartman Signed-off-by: Ulf Hansson --- drivers/mmc/host/s3cmci.c | 27 ++++++--------------------- drivers/mmc/host/s3cmci.h | 2 -- 2 files changed, 6 insertions(+), 23 deletions(-) (limited to 'drivers/mmc') 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 -- cgit v1.2.3-70-g09d2 From 04509d77097914ae1bd351f4cec751d011844ca3 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Fri, 14 Jun 2019 16:29:53 +0800 Subject: mmc: sdhci-of-esdhc: set the sd clock divisor value above 3 This patch is to set the sd clock divisor value above 3 in tuning mode Signed-off-by: Yinbo Zhu Signed-off-by: Yangbo Lu Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-esdhc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 68c5866f5c85..c56c7d413a09 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); -- cgit v1.2.3-70-g09d2 From 791463ba1ae90a7457ddcb07c6c5a1a64738e354 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Fri, 14 Jun 2019 16:29:54 +0800 Subject: mmc: sdhci-of-esdhc: use 1/2 periperhal clock for ls1028a LS1028A used 1/2 periperhal clock as one reference clock. Signed-off-by: Yangbo Lu Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-esdhc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index c56c7d413a09..4dd43b1adf2c 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -1048,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); -- cgit v1.2.3-70-g09d2 From de23f0b757766d9fae59df97da6e8bdc5b231351 Mon Sep 17 00:00:00 2001 From: Raul E Rangel Date: Mon, 17 Jun 2019 14:10:13 -0600 Subject: mmc: sdhci: sdhci-pci-o2micro: Check if controller supports 8-bit width The O2 controller supports 8-bit EMMC access. JESD84-B51 section A.6.3.a defines the bus testing procedure that `mmc_select_bus_width()` implements. This is used to determine the actual bus width of the eMMC. Signed-off-by: Raul E Rangel Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-o2micro.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') 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: -- cgit v1.2.3-70-g09d2 From 6e8e1acda6aab9638c15c085dbef1dc429c1e87e Mon Sep 17 00:00:00 2001 From: Raul E Rangel Date: Mon, 17 Jun 2019 14:10:14 -0600 Subject: mmc: sdhci: Fix indenting on SDHCI_CTRL_8BITBUS Remove whitespace in front of SDHCI_CTRL_8BITBUS. The value is not part of SDHCI_CTRL_DMA_MASK. Signed-off-by: Raul E Rangel Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') 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 -- cgit v1.2.3-70-g09d2 From cf4b20ecfa4edc4a0e55d52bc0a735f60bdfe7eb Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 18 Jun 2019 17:34:42 +0200 Subject: mmc: sdio: Turn sdio_run_irqs() into static All external users of sdio_run_irqs() have converted into using the preferred sdio_signal_irq() interface, thus not calling the function directly any more. Avoid further new users of it, by turning it into static. Suggested-by: Douglas Anderson Signed-off-by: Ulf Hansson Reviewed-by: Douglas Anderson Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio_irq.c | 3 +-- include/linux/mmc/host.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mmc') 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/include/linux/mmc/host.h b/include/linux/mmc/host.h index ecb7972e2423..a9b12322c775 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -504,7 +504,6 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host) wake_up_process(host->sdio_irq_thread); } -void sdio_run_irqs(struct mmc_host *host); void sdio_signal_irq(struct mmc_host *host); #ifdef CONFIG_REGULATOR -- cgit v1.2.3-70-g09d2 From cd23042d05468ab2e66e0298b46ee90a5f8d9a74 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 11 Jun 2019 17:44:32 +0200 Subject: mmc: sdio: Drop mmc_claim|release_host() in mmc_sdio_power_restore() The function mmc_sdio_power_restore() is called either from mmc_sdio_runtime_resume() or from mmc_sdio_hw_reset(). Both callers either claims/releases the host or require its callers to do so. Therefore let's drop the redundant calls to mmc_claim|release_host() in mmc_sdio_power_restore(). Signed-off-by: Ulf Hansson Reviewed-by: Douglas Anderson Tested-by: Douglas Anderson --- drivers/mmc/core/sdio.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 712a7742765e..b3303b7d9956 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1030,14 +1030,10 @@ static int mmc_sdio_power_restore(struct mmc_host *host) * */ - 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; } -- cgit v1.2.3-70-g09d2 From ee550947a0d696f7ddfe88b204d4eae7f879b583 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 17 Jun 2019 23:41:15 +0200 Subject: mmc: sdio: Move comment about re-initialization to mmc_sdio_reinit_card() The comment in mmc_sdio_power_restore() belongs in mmc_sdio_reinit_card(), which was created during a previous commit that re-factored some code. Fix this by moving the comment into mmc_sdio_reinit_card(). Signed-off-by: Ulf Hansson Reviewed-by: Douglas Anderson --- drivers/mmc/core/sdio.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index b3303b7d9956..29f86c1e9923 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -820,6 +820,23 @@ static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume) { 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); @@ -1013,23 +1030,6 @@ 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. - * - */ - ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host)); if (!ret && host->sdio_irqs) mmc_signal_sdio_irq(host); -- cgit v1.2.3-70-g09d2 From 7fbbe725378d62c30a076742a60a7e1812a2515a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 17 Jun 2019 23:51:31 +0200 Subject: mmc: sdio: Drop powered-on re-init at runtime resume and HW reset To use the so called powered-on re-initialization of an SDIO card, the power to the card must obviously have stayed on. If not, the initialization will simply fail. In the runtime suspend case, the card is always powered off. Hence, let's drop the support for powered-on re-initialization during runtime resume, as it doesn't make sense. Moreover, during a HW reset, the point is to cut the power to the card and then do fresh re-initialization. Therefore drop the support for powered-on re-initialization during HW reset. Signed-off-by: Ulf Hansson Fixes: ca8971ca5753 ("mmc: dw_mmc: Prevent runtime PM suspend when SDIO IRQs are enabled") Tested-by: Douglas Anderson --- drivers/mmc/core/sdio.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 29f86c1e9923..a9bfcae8db5b 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1028,13 +1028,7 @@ out: static int mmc_sdio_power_restore(struct mmc_host *host) { - int ret; - - ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host)); - if (!ret && host->sdio_irqs) - mmc_signal_sdio_irq(host); - - return ret; + return mmc_sdio_reinit_card(host, 0); } static int mmc_sdio_runtime_suspend(struct mmc_host *host) -- cgit v1.2.3-70-g09d2 From 6ebc581c3f9e6fd11a1c9da492a5e05bbe96885a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 18 Jun 2019 00:52:59 +0200 Subject: mmc: sdio: Don't re-initialize powered-on removable SDIO cards at resume It looks like the original idea behind always doing a re-initialization of a removable SDIO card during system resume in mmc_sdio_resume(), is to try to play safe to detect whether the card has been removed. However, this seems like a really a bad idea as it will most likely screw things up, especially when the card is expected to remain powered on during system suspend by the SDIO func driver. Let's fix this, simply by trusting that the detect work checks if the card is alive and inserted, which is being scheduled at the PM_POST_SUSPEND notification anyway. Signed-off-by: Ulf Hansson Tested-by: Douglas Anderson Reviewed-by: Douglas Anderson --- drivers/mmc/core/sdio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index a9bfcae8db5b..945416c53b56 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -982,7 +982,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); /* @@ -996,12 +1000,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, 0); + } 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); } -- cgit v1.2.3-70-g09d2 From 3c30e73977e5d1a14a2969cfebcca2655a29b40a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 18 Jun 2019 01:13:02 +0200 Subject: mmc: sdio: Drop unused in-parameter to mmc_sdio_reinit_card() The "powered_resume" in-parameter to mmc_sdio_reinit_card() has now become redundant as all callers set it to 0. Therefore let's just drop it. Signed-off-by: Ulf Hansson Reviewed-by: Douglas Anderson Tested-by: Douglas Anderson --- drivers/mmc/core/sdio.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 945416c53b56..0bf603670f61 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -816,7 +816,7 @@ 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; @@ -845,8 +845,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, 0); } /* @@ -1000,7 +999,7 @@ static int mmc_sdio_resume(struct mmc_host *host) pm_runtime_set_active(&host->card->dev); pm_runtime_enable(&host->card->dev); } - err = mmc_sdio_reinit_card(host, 0); + 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); @@ -1026,11 +1025,6 @@ out: return err; } -static int mmc_sdio_power_restore(struct mmc_host *host) -{ - return mmc_sdio_reinit_card(host, 0); -} - static int mmc_sdio_runtime_suspend(struct mmc_host *host) { /* No references to the card, cut the power to it. */ @@ -1048,7 +1042,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; @@ -1057,7 +1051,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) @@ -1069,7 +1063,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 = { -- cgit v1.2.3-70-g09d2 From 4aaaf3ab150947557345aedc178dac4f5c10cc87 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 18 Jun 2019 01:20:50 +0200 Subject: mmc: sdio: Drop unused in-parameter from mmc_sdio_init_card() The "powered_resume" in-parameter to mmc_sdio_init_card() has now become redundant as all callers set it to 0. Therefore let's just drop it. Signed-off-by: Ulf Hansson Reviewed-by: Douglas Anderson Tested-by: Douglas Anderson --- drivers/mmc/core/sdio.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 0bf603670f61..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; @@ -845,7 +843,7 @@ static int mmc_sdio_reinit_card(struct mmc_host *host) if (ret) return ret; - return mmc_sdio_init_card(host, host->card->ocr, host->card, 0); + return mmc_sdio_init_card(host, host->card->ocr, host->card); } /* @@ -1113,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; -- cgit v1.2.3-70-g09d2 From 63624d13b24d00fa3783181efdfdb9d5afaa7363 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 19 Jun 2019 13:55:30 +0900 Subject: mmc: tmio: Use dma_max_mapping_size() instead of a workaround Since the commit 133d624b1cee ("dma: Introduce dma_max_mapping_size()") provides a helper function to get the max mapping size, we can use the function instead of the workaround code for swiotlb. Signed-off-by: Yoshihiro Shimoda Acked-by: Wolfram Sang Reviewed-by: Christoph Hellwig Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc_core.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 83fd94341113..2cb3f951c3e2 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -45,7 +46,6 @@ #include #include #include -#include #include #include "tmio_mmc.h" @@ -1199,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)) -- cgit v1.2.3-70-g09d2 From cb3a7d4a0aec4e56043d6433724e0606d6b6efba Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 20 Jun 2019 12:49:01 +0300 Subject: mmc: sdhci-pci: Add support for Intel EHL Add PCI Ids for Intel EHL. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 2 ++ drivers/mmc/host/sdhci-pci.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index fa6a8fa560c3..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), 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 -- cgit v1.2.3-70-g09d2 From eef9e0a60e78be6873b515e85466cac2f25581ed Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Fri, 21 Jun 2019 14:12:31 +0800 Subject: mmc: sdhci-sprd: Add start_signal_voltage_switch ops For Spreadtrum SD host controller, we can not use standard SD registers to change and detect the I/O voltage signals, since our voltage regulator for I/O is fixed in hardware, and no signals were connected to the SD controller. Thus add Spreadtrum specific voltage switch ops to change voltage instead of using standard SD host registers. Signed-off-by: Baolin Wang Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index 024c3c5fa979..8b23c8838fb9 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -403,6 +403,22 @@ 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) +{ + 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; + } + } + + return 0; +} + static void sdhci_sprd_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -470,6 +486,14 @@ static int sdhci_sprd_probe(struct platform_device *pdev) 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; -- cgit v1.2.3-70-g09d2 From 29ca763fc26f382444887951b3443da0fa47e5fc Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Fri, 21 Jun 2019 14:12:33 +0800 Subject: mmc: sdhci-sprd: Add pin control support for voltage switch For Spreadtrum SD card voltage switching, besides regulator setting, it also need switch related pin's state to output corresponding voltage. This patch adds pin control operation to support voltage switch. Signed-off-by: Baolin Wang Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 54 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index 8b23c8838fb9..6ee340a3fb3a 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,9 @@ struct sdhci_sprd_host { 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]; @@ -405,6 +409,8 @@ static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *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)) { @@ -416,6 +422,37 @@ static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) } } + 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; } @@ -504,6 +541,23 @@ static int sdhci_sprd_probe(struct platform_device *pdev) 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)) { ret = PTR_ERR(clk); -- cgit v1.2.3-70-g09d2 From 7559d612dff0389aba5b49664e3bc94a150e45f2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 25 Jun 2019 11:20:41 +0200 Subject: mmc: core: let the dma map ops handle bouncing Just like we do for all other block drivers. Especially as the limit imposed at the moment might be way to pessimistic for iommus. This also means we are not going to set a bounce limit for the queue, in case we have a dma mask. On most architectures it was never needed, the major hold out was x86-32 with PAE, but that has been fixed by now. Signed-off-by: Christoph Hellwig Signed-off-by: Ulf Hansson --- drivers/mmc/core/queue.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 92900a095796..4bf9cd881bd0 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -354,18 +354,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); -- cgit v1.2.3-70-g09d2 From 8751c8bd8b91abb0887ab971651a1ac72d3b9398 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 28 Jun 2019 12:07:51 +0800 Subject: mmc: sdhci_am654: Make some symbols static Fix sparse warnings: drivers/mmc/host/sdhci_am654.c:192:6: warning: symbol 'sdhci_j721e_4bit_set_clock' was not declared. Should it be static? drivers/mmc/host/sdhci_am654.c:261:18: warning: symbol 'sdhci_j721e_8bit_ops' was not declared. Should it be static? drivers/mmc/host/sdhci_am654.c:284:18: warning: symbol 'sdhci_j721e_4bit_ops' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_am654.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 3b3948144591..bb90757ecace 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -189,7 +189,8 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) } } -void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, unsigned int clock) +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); @@ -258,7 +259,7 @@ static const struct sdhci_am654_driver_data sdhci_am654_drvdata = { .flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT, }; -struct sdhci_ops sdhci_j721e_8bit_ops = { +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, @@ -281,7 +282,7 @@ static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = { .flags = DLL_PRESENT, }; -struct sdhci_ops sdhci_j721e_4bit_ops = { +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, -- cgit v1.2.3-70-g09d2 From 5e6b6651d22de109ebf48ca00d0373bc2c0cc080 Mon Sep 17 00:00:00 2001 From: Jorge Ramirez-Ortiz Date: Mon, 1 Jul 2019 17:01:25 +0200 Subject: mmc: sdhci-msm: fix mutex while in spinlock mutexes can sleep and therefore should not be taken while holding a spinlock. move clk_get_rate (can sleep) outside the spinlock protected region. Fixes: 83736352e0ca ("mmc: sdhci-msm: Update DLL reset sequence") Cc: stable@vger.kernel.org Signed-off-by: Jorge Ramirez-Ortiz Reviewed-by: Bjorn Andersson Reviewed-by: Vinod Koul Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') 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); -- cgit v1.2.3-70-g09d2 From 42248a918d7c18a535b08f05badb988b140298f6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 1 Jul 2019 18:52:46 +0100 Subject: mmc: alcor: remove a redundant greater or equal to zero comparison A greater or equal comparison on the unsigned int variable tmp_diff is always true as unsigned ints are never negative. Hence the comparison is redundant and can be removed. Addresses-Coverity: ("Unsigned compared against 0") Signed-off-by: Colin Ian King Signed-off-by: Ulf Hansson --- drivers/mmc/host/alcor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') 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; -- cgit v1.2.3-70-g09d2 From 59592cc1f5937ced72e11e681c3e358a0375f7ae Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 2 Jul 2019 21:36:31 +0800 Subject: mmc: sdhci_am654: Add dependency on MMC_SDHCI_AM654 Fix build error: drivers/mmc/host/sdhci_am654.o: In function `sdhci_am654_probe': drivers/mmc/host/sdhci_am654.c:464: undefined reference to `__devm_regmap_init_mmio_clk' drivers/mmc/host/sdhci_am654.o:(.debug_addr+0x3f8): undefined reference to `__devm_regmap_init_mmio_clk' Reported-by: Hulk Robot Fixes: aff88ff23512 ("mmc: sdhci_am654: Add Initial Support for AM654 SDHCI driver") Signed-off-by: YueHaibing Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') 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) -- cgit v1.2.3-70-g09d2