diff options
Diffstat (limited to 'drivers/mmc/host')
86 files changed, 1492 insertions, 370 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 9c89a5b780e8..f0cb7aeabbc4 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -178,7 +178,7 @@ config MMC_SDHCI_OF_AT91 config MMC_SDHCI_OF_ESDHC tristate "SDHCI OF support for the Freescale eSDHC controller" depends on MMC_SDHCI_PLTFM - depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE + depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE || COMPILE_TEST select MMC_SDHCI_IO_ACCESSORS select FSL_GUTS help @@ -213,6 +213,18 @@ config MMC_SDHCI_OF_DWCMSHC If you have a controller with this interface, say Y or M here. If unsure, say N. +config MMC_SDHCI_OF_SPARX5 + tristate "SDHCI OF support for the MCHP Sparx5 SoC" + depends on MMC_SDHCI_PLTFM + depends on ARCH_SPARX5 || COMPILE_TEST + help + This selects the Secure Digital Host Controller Interface (SDHCI) + found in the MCHP Sparx5 SoC. + + If you have a Sparx5 SoC with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_CADENCE tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller" depends on MMC_SDHCI_PLTFM @@ -226,7 +238,7 @@ config MMC_SDHCI_CADENCE config MMC_SDHCI_CNS3XXX tristate "SDHCI support on the Cavium Networks CNS3xxx SoC" - depends on ARCH_CNS3XXX + depends on ARCH_CNS3XXX || COMPILE_TEST depends on MMC_SDHCI_PLTFM help This selects the SDHCI support for CNS3xxx System-on-Chip devices. @@ -250,7 +262,7 @@ config MMC_SDHCI_ESDHC_MCF config MMC_SDHCI_ESDHC_IMX tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" - depends on ARCH_MXC + depends on ARCH_MXC || COMPILE_TEST depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS select MMC_CQHCI @@ -264,7 +276,7 @@ config MMC_SDHCI_ESDHC_IMX config MMC_SDHCI_DOVE tristate "SDHCI support on Marvell's Dove SoC" - depends on ARCH_DOVE || MACH_DOVE + depends on ARCH_DOVE || MACH_DOVE || COMPILE_TEST depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS help @@ -277,7 +289,7 @@ config MMC_SDHCI_DOVE config MMC_SDHCI_TEGRA tristate "SDHCI platform support for the Tegra SD/MMC Controller" - depends on ARCH_TEGRA + depends on ARCH_TEGRA || COMPILE_TEST depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS select MMC_CQHCI @@ -289,7 +301,8 @@ config MMC_SDHCI_TEGRA config MMC_SDHCI_S3C tristate "SDHCI support on Samsung S3C SoC" - depends on MMC_SDHCI && PLAT_SAMSUNG + depends on MMC_SDHCI + depends on PLAT_SAMSUNG || COMPILE_TEST help This selects the Secure Digital Host Controller Interface (SDHCI) often referrered to as the HSMMC block in some of the Samsung S3C @@ -301,7 +314,7 @@ config MMC_SDHCI_S3C config MMC_SDHCI_SIRF tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs" - depends on ARCH_SIRF + depends on ARCH_SIRF || COMPILE_TEST depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS help @@ -339,7 +352,8 @@ config MMC_SDHCI_PXAV2 config MMC_SDHCI_SPEAR tristate "SDHCI support on ST SPEAr platform" - depends on MMC_SDHCI && PLAT_SPEAR + depends on MMC_SDHCI + depends on PLAT_SPEAR || COMPILE_TEST depends on OF help This selects the Secure Digital Host Controller Interface (SDHCI) @@ -362,7 +376,7 @@ config MMC_SDHCI_S3C_DMA config MMC_SDHCI_BCM_KONA tristate "SDHCI support on Broadcom KONA platform" - depends on ARCH_BCM_MOBILE + depends on ARCH_BCM_MOBILE || COMPILE_TEST depends on MMC_SDHCI_PLTFM help This selects the Broadcom Kona Secure Digital Host Controller @@ -410,7 +424,8 @@ config MMC_SDHCI_IPROC config MMC_MESON_GX tristate "Amlogic S905/GX*/AXG SD/MMC Host Controller support" - depends on ARCH_MESON && MMC + depends on ARCH_MESON|| COMPILE_TEST + depends on COMMON_CLK help This selects support for the Amlogic SD/MMC Host Controller found on the S905/GX*/AXG family of SoCs. This controller is @@ -446,7 +461,7 @@ config MMC_MESON_MX_SDIO config MMC_MOXART tristate "MOXART SD/MMC Host Controller support" - depends on ARCH_MOXART && MMC + depends on ARCH_MOXART || COMPILE_TEST help This selects support for the MOXART SD/MMC Host Controller. MOXA provides one multi-functional card reader which can @@ -455,7 +470,7 @@ config MMC_MOXART config MMC_SDHCI_ST tristate "SDHCI support on STMicroelectronics SoC" - depends on ARCH_STI || FSP2 + depends on ARCH_STI || FSP2 || COMPILE_TEST depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS help @@ -525,7 +540,7 @@ config MMC_ATMELMCI config MMC_SDHCI_MSM tristate "Qualcomm SDHCI Controller Support" - depends on ARCH_QCOM || (ARM && COMPILE_TEST) + depends on ARCH_QCOM || COMPILE_TEST depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS select MMC_CQHCI @@ -575,7 +590,7 @@ config MMC_TIFM_SD config MMC_MVSDIO tristate "Marvell MMC/SD/SDIO host driver" - depends on PLAT_ORION + depends on PLAT_ORION || (COMPILE_TEST && ARM) depends on OF help This selects the Marvell SDIO host driver. @@ -587,7 +602,7 @@ config MMC_MVSDIO config MMC_DAVINCI tristate "TI DAVINCI Multimedia Card Interface support" - depends on ARCH_DAVINCI + depends on ARCH_DAVINCI || COMPILE_TEST help This selects the TI DAVINCI Multimedia card Interface. If you have an DAVINCI board with a Multimedia Card slot, @@ -602,7 +617,7 @@ config MMC_GOLDFISH config MMC_SPI tristate "MMC/SD/SDIO over SPI" - depends on SPI_MASTER && HAS_DMA + depends on SPI_MASTER select CRC7 select CRC_ITU_T help @@ -669,7 +684,7 @@ config MMC_SDRICOH_CS config MMC_SDHCI_SPRD tristate "Spreadtrum SDIO host Controller" - depends on ARCH_SPRD + depends on ARCH_SPRD || COMPILE_TEST depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS select MMC_HSQ @@ -686,7 +701,7 @@ config MMC_TMIO_CORE config MMC_TMIO tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" - depends on MFD_TMIO || MFD_ASIC3 + depends on MFD_TMIO || MFD_ASIC3 || COMPILE_TEST select MMC_TMIO_CORE help This provides support for the SD/MMC cell found in TC6393XB, @@ -777,7 +792,7 @@ config MMC_CAVIUM_THUNDERX config MMC_DW tristate "Synopsys DesignWare Memory Card Interface" - depends on ARC || ARM || ARM64 || MIPS || COMPILE_TEST + depends on ARC || ARM || ARM64 || MIPS || RISCV || CSKY || COMPILE_TEST help This selects support for the Synopsys DesignWare Mobile Storage IP block, this provides host support for SD and MMC interfaces, in both @@ -959,7 +974,7 @@ config MMC_REALTEK_USB config MMC_SUNXI tristate "Allwinner sunxi SD/MMC Host Controller support" - depends on ARCH_SUNXI + depends on ARCH_SUNXI || COMPILE_TEST help This selects support for the SD/MMC Host Controller on Allwinner sunxi SoCs. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 4d5bcb0144a0..451c25fc2c69 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -94,6 +94,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o +obj-$(CONFIG_MMC_SDHCI_OF_SPARX5) += sdhci-of-sparx5.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c index 026ca9194ce5..bfb8efeb7eb8 100644 --- a/drivers/mmc/host/alcor.c +++ b/drivers/mmc/host/alcor.c @@ -1178,6 +1178,7 @@ static struct platform_driver alcor_pci_sdmmc_driver = { .id_table = alcor_pci_sdmmc_ids, .driver = { .name = DRV_NAME_ALCOR_PCI_SDMMC, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &alcor_mmc_pm_ops }, }; diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c index ceb4924e02d0..e878fdf8f20a 100644 --- a/drivers/mmc/host/android-goldfish.c +++ b/drivers/mmc/host/android-goldfish.c @@ -537,6 +537,7 @@ static struct platform_driver goldfish_mmc_driver = { .remove = goldfish_mmc_remove, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 300901415aa2..444bd3a0a922 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2418,7 +2418,7 @@ static void atmci_get_cap(struct atmel_mci *host) case 0x600: case 0x500: host->caps.has_odd_clk_div = 1; - /* Fall through */ + fallthrough; case 0x400: case 0x300: host->caps.has_dma_conf_reg = 1; @@ -2426,16 +2426,16 @@ static void atmci_get_cap(struct atmel_mci *host) host->caps.has_cfg_reg = 1; host->caps.has_cstor_reg = 1; host->caps.has_highspeed = 1; - /* Fall through */ + fallthrough; case 0x200: host->caps.has_rwproof = 1; host->caps.need_blksz_mul_4 = 0; host->caps.need_notbusy_for_read_ops = 1; - /* Fall through */ + fallthrough; case 0x100: host->caps.has_bad_data_ordering = 0; host->caps.need_reset_after_xfer = 0; - /* Fall through */ + fallthrough; case 0x0: break; default: @@ -2668,6 +2668,7 @@ static struct platform_driver atmci_driver = { .remove = atmci_remove, .driver = { .name = "atmel_mci", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(atmci_dt_ids), .pm = &atmci_dev_pm_ops, }, diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 9bb1910268ca..bd00515fbaba 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -1189,6 +1189,7 @@ static struct platform_driver au1xmmc_driver = { .resume = au1xmmc_resume, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index a0767790a826..8c2361e66277 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1406,9 +1406,7 @@ static int bcm2835_probe(struct platform_device *pdev) clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "could not get clk: %d\n", ret); + ret = dev_err_probe(dev, PTR_ERR(clk), "could not get clk\n"); goto err; } @@ -1476,6 +1474,7 @@ static struct platform_driver bcm2835_driver = { .remove = bcm2835_remove, .driver = { .name = "sdhost-bcm2835", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = bcm2835_match, }, }; diff --git a/drivers/mmc/host/cavium-octeon.c b/drivers/mmc/host/cavium-octeon.c index e299cdd1e619..2c4b2df52adb 100644 --- a/drivers/mmc/host/cavium-octeon.c +++ b/drivers/mmc/host/cavium-octeon.c @@ -327,6 +327,7 @@ static struct platform_driver octeon_mmc_driver = { .remove = octeon_mmc_remove, .driver = { .name = KBUILD_MODNAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = octeon_mmc_match, }, }; diff --git a/drivers/mmc/host/cqhci.c b/drivers/mmc/host/cqhci.c index cfa87dfa73d8..697fe40756bf 100644 --- a/drivers/mmc/host/cqhci.c +++ b/drivers/mmc/host/cqhci.c @@ -376,6 +376,9 @@ static void cqhci_off(struct mmc_host *mmc) else pr_debug("%s: cqhci: CQE off\n", mmc_hostname(mmc)); + if (cq_host->ops->post_disable) + cq_host->ops->post_disable(mmc); + mmc->cqe_on = false; } @@ -580,6 +583,9 @@ static int cqhci_request(struct mmc_host *mmc, struct mmc_request *mrq) __cqhci_enable(cq_host); if (!mmc->cqe_on) { + if (cq_host->ops->pre_enable) + cq_host->ops->pre_enable(mmc); + cqhci_writel(cq_host, 0, CQHCI_CTL); mmc->cqe_on = true; pr_debug("%s: cqhci: CQE on\n", mmc_hostname(mmc)); diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h index 437700179de4..89bf6adbce8c 100644 --- a/drivers/mmc/host/cqhci.h +++ b/drivers/mmc/host/cqhci.h @@ -206,6 +206,8 @@ struct cqhci_host_ops { void (*disable)(struct mmc_host *mmc, bool recovery); void (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq, u64 *data); + void (*pre_enable)(struct mmc_host *mmc); + void (*post_disable)(struct mmc_host *mmc); }; static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index f01fecd75833..90cd179625fc 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -300,7 +300,7 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host, * then it's harmless for us to allow it. */ cmd_reg |= MMCCMD_BSYEXP; - /* FALLTHROUGH */ + fallthrough; case MMC_RSP_R1: /* 48 bits, CRC */ cmd_reg |= MMCCMD_RSPFMT_R1456; break; @@ -996,7 +996,7 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) if (qstatus & MMCST0_RSPDNE) { /* End of command phase */ - end_command = (int) host->cmd; + end_command = host->cmd ? 1 : 0; } if (end_command) @@ -1240,9 +1240,8 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) pdev->id_entry = match->data; ret = mmc_of_parse(mmc); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "could not parse of data: %d\n", ret); + dev_err_probe(&pdev->dev, ret, + "could not parse of data\n"); goto parse_fail; } } else { @@ -1396,6 +1395,7 @@ static const struct dev_pm_ops davinci_mmcsd_pm = { static struct platform_driver davinci_mmcsd_driver = { .driver = { .name = "davinci_mmc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = davinci_mmcsd_pm_ops, .of_match_table = davinci_mmc_dt_ids, }, diff --git a/drivers/mmc/host/dw_mmc-bluefield.c b/drivers/mmc/host/dw_mmc-bluefield.c index aa38b1a8017e..10baf122bc15 100644 --- a/drivers/mmc/host/dw_mmc-bluefield.c +++ b/drivers/mmc/host/dw_mmc-bluefield.c @@ -55,6 +55,7 @@ static struct platform_driver dw_mci_bluefield_pltfm_driver = { .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_bluefield", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = dw_mci_bluefield_match, .pm = &dw_mci_pltfm_pmops, }, diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 95adeee07217..0c75810812a0 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -592,6 +592,7 @@ static struct platform_driver dw_mci_exynos_pltfm_driver = { .remove = dw_mci_exynos_remove, .driver = { .name = "dwmmc_exynos", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = dw_mci_exynos_match, .pm = &dw_mci_exynos_pmops, }, diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c index 83e1bad0a008..39794f93826f 100644 --- a/drivers/mmc/host/dw_mmc-hi3798cv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c @@ -200,6 +200,7 @@ static struct platform_driver dw_mci_hi3798cv200_driver = { .remove = dw_mci_hi3798cv200_remove, .driver = { .name = "dwmmc_hi3798cv200", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = dw_mci_hi3798cv200_match, }, }; diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c index 50977ff18074..29d2494eb27a 100644 --- a/drivers/mmc/host/dw_mmc-k3.c +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -238,7 +238,7 @@ static void dw_mci_hs_set_timing(struct dw_mci *host, int timing, if (smpl_phase >= USE_DLY_MIN_SMPL && smpl_phase <= USE_DLY_MAX_SMPL) use_smpl_dly = 1; - /* fallthrough */ + fallthrough; case MMC_TIMING_UHS_SDR50: if (smpl_phase >= ENABLE_SHIFT_MIN_SMPL && smpl_phase <= ENABLE_SHIFT_MAX_SMPL) @@ -473,6 +473,7 @@ static struct platform_driver dw_mci_k3_pltfm_driver = { .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_k3", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = dw_mci_k3_match, .pm = &dw_mci_k3_dev_pm_ops, }, diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 7de37f524a96..73731cd3ba23 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -98,6 +98,7 @@ static struct platform_driver dw_mci_pltfm_driver = { .remove = dw_mci_pltfm_remove, .driver = { .name = "dw_mmc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = dw_mci_pltfm_match, .pm = &dw_mci_pltfm_pmops, }, diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index d4d02134848c..753502ce3c85 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -383,6 +383,7 @@ static struct platform_driver dw_mci_rockchip_pltfm_driver = { .remove = dw_mci_rockchip_remove, .driver = { .name = "dwmmc_rockchip", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = dw_mci_rockchip_match, .pm = &dw_mci_rockchip_dev_pm_ops, }, diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c index eada648b27ec..51bcc6332f3a 100644 --- a/drivers/mmc/host/dw_mmc-zx.c +++ b/drivers/mmc/host/dw_mmc-zx.c @@ -155,7 +155,6 @@ static int dw_mci_zx_parse_dt(struct dw_mci *host) struct device_node *node; struct dw_mci_zx_priv_data *priv; struct regmap *sysc_base; - int ret; /* syscon is needed only by emmc */ node = of_parse_phandle(np, "zte,aon-syscon", 0); @@ -163,13 +162,9 @@ static int dw_mci_zx_parse_dt(struct dw_mci *host) sysc_base = syscon_node_to_regmap(node); of_node_put(node); - if (IS_ERR(sysc_base)) { - ret = PTR_ERR(sysc_base); - if (ret != -EPROBE_DEFER) - dev_err(host->dev, "Can't get syscon: %d\n", - ret); - return ret; - } + if (IS_ERR(sysc_base)) + return dev_err_probe(host->dev, PTR_ERR(sysc_base), + "Can't get syscon\n"); } else { return 0; } @@ -227,6 +222,7 @@ static struct platform_driver dw_mci_zx_pltfm_driver = { .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_zx", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = dw_mci_zx_match, .pm = &dw_mci_zx_dev_pm_ops, }, diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 35ae5737c622..43c5795691fb 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2030,7 +2030,7 @@ static void dw_mci_tasklet_func(unsigned long priv) } prev_state = state = STATE_SENDING_DATA; - /* fall through */ + fallthrough; case STATE_SENDING_DATA: /* @@ -2088,7 +2088,7 @@ static void dw_mci_tasklet_func(unsigned long priv) } prev_state = state = STATE_DATA_BUSY; - /* fall through */ + fallthrough; case STATE_DATA_BUSY: if (!dw_mci_clear_pending_data_complete(host)) { @@ -2141,7 +2141,7 @@ static void dw_mci_tasklet_func(unsigned long priv) */ prev_state = state = STATE_SENDING_STOP; - /* fall through */ + fallthrough; case STATE_SENDING_STOP: if (!dw_mci_clear_pending_cmd_complete(host)) @@ -3161,12 +3161,9 @@ int dw_mci_probe(struct dw_mci *host) if (!host->pdata) { host->pdata = dw_mci_parse_dt(host); - if (PTR_ERR(host->pdata) == -EPROBE_DEFER) { - return -EPROBE_DEFER; - } else if (IS_ERR(host->pdata)) { - dev_err(host->dev, "platform data not available\n"); - return -EINVAL; - } + if (IS_ERR(host->pdata)) + return dev_err_probe(host->dev, PTR_ERR(host->pdata), + "platform data not available\n"); } host->biu_clk = devm_clk_get(host->dev, "biu"); diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 447552ac25c4..a1f92fed2a55 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -739,7 +739,7 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid) break; jz_mmc_prepare_data_transfer(host); - /* fall through */ + fallthrough; case JZ4740_MMC_STATE_TRANSFER_DATA: if (host->use_dma) { @@ -774,7 +774,7 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid) break; } jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_DATA_TRAN_DONE); - /* fall through */ + fallthrough; case JZ4740_MMC_STATE_SEND_STOP: if (!req->stop) @@ -991,9 +991,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev) ret = mmc_of_parse(mmc); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "could not parse device properties: %d\n", ret); + dev_err_probe(&pdev->dev, ret, "could not parse device properties\n"); goto err_free_host; } @@ -1126,6 +1124,7 @@ static struct platform_driver jz4740_mmc_driver = { .remove = jz4740_mmc_remove, .driver = { .name = "jz4740-mmc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(jz4740_mmc_of_match), .pm = pm_ptr(&jz4740_mmc_pm_ops), }, diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 08a3b1c05acb..4ec41579940a 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -426,11 +426,9 @@ static int meson_mmc_clk_init(struct meson_host *host) snprintf(name, sizeof(name), "clkin%d", i); clk = devm_clk_get(host->dev, name); - if (IS_ERR(clk)) { - if (clk != ERR_PTR(-EPROBE_DEFER)) - dev_err(host->dev, "Missing clock %s\n", name); - return PTR_ERR(clk); - } + if (IS_ERR(clk)) + return dev_err_probe(host->dev, PTR_ERR(clk), + "Missing clock %s\n", name); mux_parent_names[i] = __clk_get_name(clk); } @@ -521,7 +519,7 @@ static int meson_mmc_resampling_tuning(struct mmc_host *mmc, u32 opcode) val |= ADJUST_ADJ_EN; writel(val, host->regs + host->data->adjust); - if (mmc->doing_retune) + if (mmc_doing_retune(mmc)) dly = FIELD_GET(ADJUST_ADJ_DELAY_MASK, val) + 1; else dly = 0; @@ -1077,12 +1075,8 @@ static int meson_mmc_probe(struct platform_device *pdev) } ret = device_reset_optional(&pdev->dev); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "device reset failed: %d\n", ret); - - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "device reset failed\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->regs = devm_ioremap_resource(&pdev->dev, res); @@ -1270,6 +1264,7 @@ static struct platform_driver meson_mmc_driver = { .remove = meson_mmc_remove, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(meson_mmc_of_match), }, }; diff --git a/drivers/mmc/host/meson-mx-sdhc-mmc.c b/drivers/mmc/host/meson-mx-sdhc-mmc.c index 53e3f6a4245a..7cd9c0ec2fcf 100644 --- a/drivers/mmc/host/meson-mx-sdhc-mmc.c +++ b/drivers/mmc/host/meson-mx-sdhc-mmc.c @@ -903,6 +903,7 @@ static struct platform_driver meson_mx_sdhc_driver = { .remove = meson_mx_sdhc_remove, .driver = { .name = "meson-mx-sdhc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(meson_mx_sdhc_of_match), }, }; diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c index 9b2cf7afc246..1c5299cd0cbe 100644 --- a/drivers/mmc/host/meson-mx-sdio.c +++ b/drivers/mmc/host/meson-mx-sdio.c @@ -294,7 +294,7 @@ static void meson_mx_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_OFF: vdd = 0; - /* fall through */ + fallthrough; case MMC_POWER_UP: if (!IS_ERR(mmc->supply.vmmc)) { host->error = mmc_regulator_set_ocr(mmc, @@ -755,6 +755,7 @@ static struct platform_driver meson_mx_mmc_driver = { .remove = meson_mx_mmc_remove, .driver = { .name = "meson-mx-sdio", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(meson_mx_mmc_of_match), }, }; diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 39bb1e30c2d7..02f4fd26e76a 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -882,9 +882,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, else clock_rate = spi->max_speed_hz; - timeout = data->timeout_ns + + timeout = data->timeout_ns / 1000 + data->timeout_clks * 1000000 / clock_rate; - timeout = usecs_to_jiffies((unsigned int)(timeout / 1000)) + 1; + timeout = usecs_to_jiffies((unsigned int)timeout) + 1; /* Handle scatterlist segments one at a time, with synch for * each 512-byte block @@ -1278,6 +1278,52 @@ mmc_spi_detect_irq(int irq, void *mmc) return IRQ_HANDLED; } +#ifdef CONFIG_HAS_DMA +static int mmc_spi_dma_alloc(struct mmc_spi_host *host) +{ + struct spi_device *spi = host->spi; + struct device *dev; + + if (!spi->master->dev.parent->dma_mask) + return 0; + + dev = spi->master->dev.parent; + + host->ones_dma = dma_map_single(dev, host->ones, MMC_SPI_BLOCKSIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, host->ones_dma)) + return -ENOMEM; + + host->data_dma = dma_map_single(dev, host->data, sizeof(*host->data), + DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, host->data_dma)) { + dma_unmap_single(dev, host->ones_dma, MMC_SPI_BLOCKSIZE, + DMA_TO_DEVICE); + return -ENOMEM; + } + + dma_sync_single_for_cpu(dev, host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); + + host->dma_dev = dev; + return 0; +} + +static void mmc_spi_dma_free(struct mmc_spi_host *host) +{ + if (!host->dma_dev) + return; + + dma_unmap_single(host->dma_dev, host->ones_dma, MMC_SPI_BLOCKSIZE, + DMA_TO_DEVICE); + dma_unmap_single(host->dma_dev, host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); +} +#else +static inline int mmc_spi_dma_alloc(struct mmc_spi_host *host) { return 0; } +static inline void mmc_spi_dma_free(struct mmc_spi_host *host) {} +#endif + static int mmc_spi_probe(struct spi_device *spi) { void *ones; @@ -1374,23 +1420,9 @@ static int mmc_spi_probe(struct spi_device *spi) if (!host->data) goto fail_nobuf1; - if (spi->master->dev.parent->dma_mask) { - struct device *dev = spi->master->dev.parent; - - host->dma_dev = dev; - host->ones_dma = dma_map_single(dev, ones, - MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); - if (dma_mapping_error(dev, host->ones_dma)) - goto fail_ones_dma; - host->data_dma = dma_map_single(dev, host->data, - sizeof(*host->data), DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, host->data_dma)) - goto fail_data_dma; - - dma_sync_single_for_cpu(host->dma_dev, - host->data_dma, sizeof(*host->data), - DMA_BIDIRECTIONAL); - } + status = mmc_spi_dma_alloc(host); + if (status) + goto fail_dma; /* setup message for status/busy readback */ spi_message_init(&host->readback); @@ -1458,20 +1490,12 @@ static int mmc_spi_probe(struct spi_device *spi) fail_add_host: mmc_remove_host(mmc); fail_glue_init: - if (host->dma_dev) - dma_unmap_single(host->dma_dev, host->data_dma, - sizeof(*host->data), DMA_BIDIRECTIONAL); -fail_data_dma: - if (host->dma_dev) - dma_unmap_single(host->dma_dev, host->ones_dma, - MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); -fail_ones_dma: + mmc_spi_dma_free(host); +fail_dma: kfree(host->data); - fail_nobuf1: mmc_free_host(mmc); mmc_spi_put_pdata(spi); - nomem: kfree(ones); return status; @@ -1489,13 +1513,7 @@ static int mmc_spi_remove(struct spi_device *spi) mmc_remove_host(mmc); - if (host->dma_dev) { - dma_unmap_single(host->dma_dev, host->ones_dma, - MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); - dma_unmap_single(host->dma_dev, host->data_dma, - sizeof(*host->data), DMA_BIDIRECTIONAL); - } - + mmc_spi_dma_free(host); kfree(host->data); kfree(host->ones); diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index fc6b9cf27d0b..f25079ba3bca 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -689,19 +689,18 @@ static int moxart_remove(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, NULL); - if (mmc) { - if (!IS_ERR(host->dma_chan_tx)) - dma_release_channel(host->dma_chan_tx); - if (!IS_ERR(host->dma_chan_rx)) - dma_release_channel(host->dma_chan_rx); - mmc_remove_host(mmc); - mmc_free_host(mmc); + if (!IS_ERR(host->dma_chan_tx)) + dma_release_channel(host->dma_chan_tx); + if (!IS_ERR(host->dma_chan_rx)) + dma_release_channel(host->dma_chan_rx); + mmc_remove_host(mmc); + mmc_free_host(mmc); + + writel(0, host->base + REG_INTERRUPT_MASK); + writel(0, host->base + REG_POWER_CONTROL); + writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF, + host->base + REG_CLOCK_CONTROL); - writel(0, host->base + REG_INTERRUPT_MASK); - writel(0, host->base + REG_POWER_CONTROL); - writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF, - host->base + REG_CLOCK_CONTROL); - } return 0; } @@ -717,6 +716,7 @@ static struct platform_driver moxart_mmc_driver = { .remove = moxart_remove, .driver = { .name = "mmc-moxart", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = moxart_mmc_match, }, }; diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 4e2583f69a63..a704745e5882 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/interrupt.h> +#include <linux/reset.h> #include <linux/mmc/card.h> #include <linux/mmc/core.h> @@ -396,7 +397,6 @@ struct msdc_delay_phase { struct msdc_host { struct device *dev; const struct mtk_mmc_compatible *dev_comp; - struct mmc_host *mmc; /* mmc structure */ int cmd_rsp; spinlock_t lock; @@ -419,6 +419,7 @@ struct msdc_host { struct pinctrl_state *pins_uhs; struct delayed_work req_timeout; int irq; /* host interrupt */ + struct reset_control *reset; struct clk *src_clk; /* msdc source clock */ struct clk *h_clk; /* msdc h_clk */ @@ -732,14 +733,15 @@ static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq) static u64 msdc_timeout_cal(struct msdc_host *host, u64 ns, u64 clks) { + struct mmc_host *mmc = mmc_from_priv(host); u64 timeout, clk_ns; u32 mode = 0; - if (host->mmc->actual_clock == 0) { + if (mmc->actual_clock == 0) { timeout = 0; } else { clk_ns = 1000000000ULL; - do_div(clk_ns, host->mmc->actual_clock); + do_div(clk_ns, mmc->actual_clock); timeout = ns + clk_ns - 1; do_div(timeout, clk_ns); timeout += clks; @@ -800,6 +802,7 @@ static void msdc_ungate_clock(struct msdc_host *host) static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) { + struct mmc_host *mmc = mmc_from_priv(host); u32 mode; u32 flags; u32 div; @@ -809,7 +812,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) if (!hz) { dev_dbg(host->dev, "set mclk to 0\n"); host->mclk = 0; - host->mmc->actual_clock = 0; + mmc->actual_clock = 0; sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); return; } @@ -888,7 +891,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) cpu_relax(); sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); - host->mmc->actual_clock = sclk; + mmc->actual_clock = sclk; host->mclk = hz; host->timing = timing; /* need because clk changed. */ @@ -899,7 +902,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) * mmc_select_hs400() will drop to 50Mhz and High speed mode, * tune result of hs200/200Mhz is not suitable for 50Mhz */ - if (host->mmc->actual_clock <= 52000000) { + if (mmc->actual_clock <= 52000000) { writel(host->def_tune_para.iocon, host->base + MSDC_IOCON); if (host->top_base) { writel(host->def_tune_para.emmc_top_control, @@ -930,7 +933,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRRDLY, host->hs400_cmd_int_delay); - dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->mmc->actual_clock, + dev_dbg(host->dev, "sclk: %d, timing: %d\n", mmc->actual_clock, timing); } @@ -965,6 +968,7 @@ static inline u32 msdc_cmd_find_resp(struct msdc_host *host, static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, struct mmc_request *mrq, struct mmc_command *cmd) { + struct mmc_host *mmc = mmc_from_priv(host); /* rawcmd : * vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 | * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode @@ -991,7 +995,7 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, struct mmc_data *data = cmd->data; if (mmc_op_multi(opcode)) { - if (mmc_card_mmc(host->mmc->card) && mrq->sbc && + if (mmc_card_mmc(mmc->card) && mrq->sbc && !(mrq->sbc->arg & 0xFFFF0000)) rawcmd |= 0x2 << 28; /* AutoCMD23 */ } @@ -1068,9 +1072,10 @@ static int msdc_auto_cmd_done(struct msdc_host *host, int events, */ static void msdc_recheck_sdio_irq(struct msdc_host *host) { + struct mmc_host *mmc = mmc_from_priv(host); u32 reg_int, reg_inten, reg_ps; - if (host->mmc->caps & MMC_CAP_SDIO_IRQ) { + if (mmc->caps & MMC_CAP_SDIO_IRQ) { reg_inten = readl(host->base + MSDC_INTEN); if (reg_inten & MSDC_INTEN_SDIOIRQ) { reg_int = readl(host->base + MSDC_INT); @@ -1078,7 +1083,7 @@ static void msdc_recheck_sdio_irq(struct msdc_host *host) if (!(reg_int & MSDC_INT_SDIOIRQ || reg_ps & MSDC_PS_DATA1)) { __msdc_enable_sdio_irq(host, 0); - sdio_signal_irq(host->mmc); + sdio_signal_irq(mmc); } } } @@ -1111,7 +1116,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) msdc_unprepare_data(host, mrq); if (host->error) msdc_reset_hw(host); - mmc_request_done(host->mmc, mrq); + mmc_request_done(mmc_from_priv(host), mrq); if (host->dev_comp->recheck_sdio_irq) msdc_recheck_sdio_irq(host); } @@ -1498,6 +1503,7 @@ static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts) { + struct mmc_host *mmc = mmc_from_priv(host); int cmd_err = 0, dat_err = 0; if (intsts & MSDC_INT_RSPCRCERR) { @@ -1521,12 +1527,13 @@ static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts) cmd_err, dat_err, intsts); } - return cqhci_irq(host->mmc, 0, cmd_err, dat_err); + return cqhci_irq(mmc, 0, cmd_err, dat_err); } static irqreturn_t msdc_irq(int irq, void *dev_id) { struct msdc_host *host = (struct msdc_host *) dev_id; + struct mmc_host *mmc = mmc_from_priv(host); while (true) { unsigned long flags; @@ -1549,18 +1556,18 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) spin_unlock_irqrestore(&host->lock, flags); if ((events & event_mask) & MSDC_INT_SDIOIRQ) - sdio_signal_irq(host->mmc); + sdio_signal_irq(mmc); if ((events & event_mask) & MSDC_INT_CDSC) { if (host->internal_cd) - mmc_detect_change(host->mmc, msecs_to_jiffies(20)); + mmc_detect_change(mmc, msecs_to_jiffies(20)); events &= ~MSDC_INT_CDSC; } if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ))) break; - if ((host->mmc->caps2 & MMC_CAP2_CQE) && + if ((mmc->caps2 & MMC_CAP2_CQE) && (events & MSDC_INT_CMDQ)) { msdc_cmdq_irq(host, events); /* clear interrupts */ @@ -1592,6 +1599,12 @@ static void msdc_init_hw(struct msdc_host *host) u32 val; u32 tune_reg = host->dev_comp->pad_tune_reg; + if (host->reset) { + reset_control_assert(host->reset); + usleep_range(10, 50); + reset_control_deassert(host->reset); + } + /* Configure to MMC/SD mode, clock free running */ sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN); @@ -2282,6 +2295,26 @@ static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery) } } +static void msdc_cqe_pre_enable(struct mmc_host *mmc) +{ + struct cqhci_host *cq_host = mmc->cqe_private; + u32 reg; + + reg = cqhci_readl(cq_host, CQHCI_CFG); + reg |= CQHCI_ENABLE; + cqhci_writel(cq_host, reg, CQHCI_CFG); +} + +static void msdc_cqe_post_disable(struct mmc_host *mmc) +{ + struct cqhci_host *cq_host = mmc->cqe_private; + u32 reg; + + reg = cqhci_readl(cq_host, CQHCI_CFG); + reg &= ~CQHCI_ENABLE; + cqhci_writel(cq_host, reg, CQHCI_CFG); +} + static const struct mmc_host_ops mt_msdc_ops = { .post_req = msdc_post_req, .pre_req = msdc_pre_req, @@ -2301,6 +2334,8 @@ static const struct mmc_host_ops mt_msdc_ops = { static const struct cqhci_host_ops msdc_cmdq_ops = { .enable = msdc_cqe_enable, .disable = msdc_cqe_disable, + .pre_enable = msdc_cqe_pre_enable, + .post_disable = msdc_cqe_post_disable, }; static void msdc_of_property_parse(struct platform_device *pdev, @@ -2390,6 +2425,11 @@ static int msdc_drv_probe(struct platform_device *pdev) if (IS_ERR(host->src_clk_cg)) host->src_clk_cg = NULL; + host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev, + "hrst"); + if (IS_ERR(host->reset)) + return PTR_ERR(host->reset); + host->irq = platform_get_irq(pdev, 0); if (host->irq < 0) { ret = -EINVAL; @@ -2421,7 +2461,6 @@ static int msdc_drv_probe(struct platform_device *pdev) host->dev = &pdev->dev; host->dev_comp = of_device_get_match_data(&pdev->dev); - host->mmc = mmc; host->src_clk_freq = clk_get_rate(host->src_clk); /* Set host parameters to mmc */ mmc->ops = &mt_msdc_ops; @@ -2462,7 +2501,7 @@ static int msdc_drv_probe(struct platform_device *pdev) mmc_dev(mmc)->dma_mask = &host->dma_mask; if (mmc->caps2 & MMC_CAP2_CQE) { - host->cq_host = devm_kzalloc(host->mmc->parent, + host->cq_host = devm_kzalloc(mmc->parent, sizeof(*host->cq_host), GFP_KERNEL); if (!host->cq_host) { @@ -2547,7 +2586,7 @@ static int msdc_drv_remove(struct platform_device *pdev) pm_runtime_get_sync(host->dev); platform_set_drvdata(pdev, NULL); - mmc_remove_host(host->mmc); + mmc_remove_host(mmc); msdc_deinit_hw(host); msdc_gate_clock(host); @@ -2559,7 +2598,7 @@ static int msdc_drv_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc), host->dma.bd, host->dma.bd_addr); - mmc_free_host(host->mmc); + mmc_free_host(mmc); return 0; } @@ -2594,6 +2633,7 @@ static void msdc_save_reg(struct msdc_host *host) static void msdc_restore_reg(struct msdc_host *host) { + struct mmc_host *mmc = mmc_from_priv(host); u32 tune_reg = host->dev_comp->pad_tune_reg; writel(host->save_para.msdc_cfg, host->base + MSDC_CFG); @@ -2618,7 +2658,7 @@ static void msdc_restore_reg(struct msdc_host *host) writel(host->save_para.pad_tune, host->base + tune_reg); } - if (sdio_irq_claimed(host->mmc)) + if (sdio_irq_claimed(mmc)) __msdc_enable_sdio_irq(host, 1); } @@ -2654,6 +2694,7 @@ static struct platform_driver mt_msdc_driver = { .remove = msdc_drv_remove, .driver = { .name = "mtk-msdc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = msdc_of_ids, .pm = &msdc_dev_pm_ops, }, diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index cc0752a9df6d..629efbe639c4 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -824,6 +824,7 @@ static struct platform_driver mvsd_driver = { .remove = mvsd_remove, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = mvsdio_dt_ids, }, }; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index b3d654c688e5..12ee07285980 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -1244,6 +1244,7 @@ static struct platform_driver mxcmci_driver = { .id_table = mxcmci_devtype, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &mxcmci_pm_ops, .of_match_table = mxcmci_of_match, } diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index b1820def36c0..75007f61df97 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -726,6 +726,7 @@ static struct platform_driver mxs_mmc_driver = { .id_table = mxs_ssp_ids, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &mxs_mmc_pm_ops, .of_match_table = mxs_mmc_dt_ids, }, diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 33d7af7c7762..6aa0537f1f84 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1504,6 +1504,7 @@ static struct platform_driver mmc_omap_driver = { .remove = mmc_omap_remove, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(mmc_omap_match), }, }; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 37b8740513f5..aa9cc49206d1 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1114,8 +1114,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) int ret; /* Disable the clocks */ - if (host->dbclk) - clk_disable_unprepare(host->dbclk); + clk_disable_unprepare(host->dbclk); /* Turn the power off */ ret = omap_hsmmc_set_power(host, 0); @@ -1123,8 +1122,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) /* Turn the power ON with given VDD 1.8 or 3.0v */ if (!ret) ret = omap_hsmmc_set_power(host, 1); - if (host->dbclk) - clk_prepare_enable(host->dbclk); + clk_prepare_enable(host->dbclk); if (ret != 0) goto err; @@ -2014,8 +2012,7 @@ err_irq: pm_runtime_dont_use_autosuspend(host->dev); pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); - if (host->dbclk) - clk_disable_unprepare(host->dbclk); + clk_disable_unprepare(host->dbclk); err1: mmc_free_host(mmc); err: @@ -2037,8 +2034,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev) pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); device_init_wakeup(&pdev->dev, false); - if (host->dbclk) - clk_disable_unprepare(host->dbclk); + clk_disable_unprepare(host->dbclk); mmc_free_host(host->mmc); @@ -2063,8 +2059,7 @@ static int omap_hsmmc_suspend(struct device *dev) OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); } - if (host->dbclk) - clk_disable_unprepare(host->dbclk); + clk_disable_unprepare(host->dbclk); pm_runtime_put_sync(host->dev); return 0; @@ -2080,8 +2075,7 @@ static int omap_hsmmc_resume(struct device *dev) pm_runtime_get_sync(host->dev); - if (host->dbclk) - clk_prepare_enable(host->dbclk); + clk_prepare_enable(host->dbclk); if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) omap_hsmmc_conf_bus_power(host); @@ -2171,6 +2165,7 @@ static struct platform_driver omap_hsmmc_driver = { .remove = omap_hsmmc_remove, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &omap_hsmmc_dev_pm_ops, .of_match_table = of_match_ptr(omap_mmc_of_match), }, diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c index df43f42855e2..ccf214a89eda 100644 --- a/drivers/mmc/host/owl-mmc.c +++ b/drivers/mmc/host/owl-mmc.c @@ -689,6 +689,7 @@ MODULE_DEVICE_TABLE(of, owl_mmc_of_match); static struct platform_driver owl_mmc_driver = { .driver = { .name = "owl_mmc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = owl_mmc_of_match, }, .probe = owl_mmc_probe, diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 3a9333475a2b..29f6180a0036 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -811,6 +811,7 @@ static struct platform_driver pxamci_driver = { .remove = pxamci_remove, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(pxa_mmc_dt_ids), }, }; diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index 14c64caefc64..cb962c7883dc 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -33,10 +33,13 @@ struct renesas_sdhi_of_data { unsigned short max_segs; }; +#define SDHI_CALIB_TABLE_MAX 32 + struct renesas_sdhi_quirks { bool hs400_disabled; bool hs400_4taps; u32 hs400_bad_taps; + const u8 (*hs400_calib_table)[SDHI_CALIB_TABLE_MAX]; }; struct tmio_mmc_dma { @@ -58,7 +61,8 @@ struct renesas_sdhi { void __iomem *scc_ctl; u32 scc_tappos; u32 scc_tappos_hs400; - bool doing_tune; + const u8 *adjust_hs400_calib_table; + bool needs_adjust_hs400; /* Tuning values: 1 for success, 0 for failure */ DECLARE_BITMAP(taps, BITS_PER_LONG); diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 15e21894bd44..414314151d0a 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -26,6 +26,7 @@ #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> #include <linux/mmc/slot-gpio.h> #include <linux/mfd/tmio.h> #include <linux/sh_dma.h> @@ -47,6 +48,8 @@ #define SDHI_VER_GEN3_SD 0xcc10 #define SDHI_VER_GEN3_SDMMC 0xcd10 +#define SDHI_GEN3_MMC0_ADDR 0xee140000 + static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) { u32 val; @@ -117,8 +120,12 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, unsigned int freq, diff, best_freq = 0, diff_min = ~0; int i; - /* tested only on R-Car Gen2+ currently; may work for others */ - if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) + /* + * We simply return the current rate if a) we are not on a R-Car Gen2+ + * SoC (may work for others, but untested) or b) if the SCC needs its + * clock during tuning, so we don't change the external clock setup. + */ + if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2) || mmc_doing_tune(host->mmc)) return clk_get_rate(priv->clk); /* @@ -247,6 +254,11 @@ static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, #define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A #define SH_MOBILE_SDHI_SCC_SMPCMP 0x00C #define SH_MOBILE_SDHI_SCC_TMPPORT2 0x00E +#define SH_MOBILE_SDHI_SCC_TMPPORT3 0x014 +#define SH_MOBILE_SDHI_SCC_TMPPORT4 0x016 +#define SH_MOBILE_SDHI_SCC_TMPPORT5 0x018 +#define SH_MOBILE_SDHI_SCC_TMPPORT6 0x01A +#define SH_MOBILE_SDHI_SCC_TMPPORT7 0x01C #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0) #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16 @@ -267,6 +279,40 @@ static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, #define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4) #define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN BIT(31) +/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT4 register */ +#define SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START BIT(0) + +/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT5 register */ +#define SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_R BIT(8) +#define SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_W (0 << 8) +#define SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_ADR_MASK 0x3F + +/* Definitions for values the SH_MOBILE_SDHI_SCC register */ +#define SH_MOBILE_SDHI_SCC_TMPPORT_DISABLE_WP_CODE 0xa5000000 +#define SH_MOBILE_SDHI_SCC_TMPPORT_CALIB_CODE_MASK 0x1f +#define SH_MOBILE_SDHI_SCC_TMPPORT_MANUAL_MODE BIT(7) + +static const u8 r8a7796_es13_calib_table[2][SDHI_CALIB_TABLE_MAX] = { + { 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15, + 16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 }, + { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 8, 11, + 12, 17, 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, 22, 23, 25, 25 } +}; + +static const u8 r8a77965_calib_table[2][SDHI_CALIB_TABLE_MAX] = { + { 1, 2, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 26, 27, 28, 29, 30, 31 }, + { 2, 3, 4, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 17, 17, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 31, 31, 31 } +}; + +static const u8 r8a77990_calib_table[2][SDHI_CALIB_TABLE_MAX] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 1, 2, 3, 3, 4, 4, 4, 5, 5, 6, 8, 9, 10, + 11, 12, 13, 15, 16, 17, 17, 18, 18, 19, 20, 22, 24, 25, 26, 26 } +}; + static inline u32 sd_scc_read32(struct tmio_mmc_host *host, struct renesas_sdhi *priv, int addr) { @@ -373,6 +419,9 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc) sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); + + if (priv->adjust_hs400_calib_table) + priv->needs_adjust_hs400 = true; } static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host, @@ -403,6 +452,74 @@ static void renesas_sdhi_disable_scc(struct mmc_host *mmc) sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); } +static u32 sd_scc_tmpport_read32(struct tmio_mmc_host *host, + struct renesas_sdhi *priv, u32 addr) +{ + /* read mode */ + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT5, + SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_R | + (SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_ADR_MASK & addr)); + + /* access start and stop */ + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4, + SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START); + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4, 0); + + return sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT7); +} + +static void sd_scc_tmpport_write32(struct tmio_mmc_host *host, + struct renesas_sdhi *priv, u32 addr, u32 val) +{ + /* write mode */ + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT5, + SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_W | + (SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_ADR_MASK & addr)); + + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT6, val); + + /* access start and stop */ + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4, + SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START); + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4, 0); +} + +static void renesas_sdhi_adjust_hs400_mode_enable(struct tmio_mmc_host *host) +{ + struct renesas_sdhi *priv = host_to_priv(host); + u32 calib_code; + + /* disable write protect */ + sd_scc_tmpport_write32(host, priv, 0x00, + SH_MOBILE_SDHI_SCC_TMPPORT_DISABLE_WP_CODE); + /* read calibration code and adjust */ + calib_code = sd_scc_tmpport_read32(host, priv, 0x26); + calib_code &= SH_MOBILE_SDHI_SCC_TMPPORT_CALIB_CODE_MASK; + + sd_scc_tmpport_write32(host, priv, 0x22, + SH_MOBILE_SDHI_SCC_TMPPORT_MANUAL_MODE | + priv->adjust_hs400_calib_table[calib_code]); + + /* set offset value to TMPPORT3, hardcoded to OFFSET0 (= 0x3) for now */ + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT3, 0x3); + + /* adjustment done, clear flag */ + priv->needs_adjust_hs400 = false; +} + +static void renesas_sdhi_adjust_hs400_mode_disable(struct tmio_mmc_host *host) +{ + struct renesas_sdhi *priv = host_to_priv(host); + + /* disable write protect */ + sd_scc_tmpport_write32(host, priv, 0x00, + SH_MOBILE_SDHI_SCC_TMPPORT_DISABLE_WP_CODE); + /* disable manual calibration */ + sd_scc_tmpport_write32(host, priv, 0x22, 0); + /* clear offset value of TMPPORT3 */ + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT3, 0); +} + static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host, struct renesas_sdhi *priv) { @@ -420,6 +537,9 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host, SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) & sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2)); + if (priv->adjust_hs400_calib_table) + renesas_sdhi_adjust_hs400_mode_disable(host); + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); } @@ -432,6 +552,37 @@ static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_io return 0; } +static void renesas_sdhi_reset(struct tmio_mmc_host *host) +{ + struct renesas_sdhi *priv = host_to_priv(host); + + renesas_sdhi_reset_scc(host, priv); + renesas_sdhi_reset_hs400_mode(host, priv); + priv->needs_adjust_hs400 = false; + + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); + + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, + ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); + + if (host->pdata->flags & TMIO_MMC_MIN_RCAR2) + sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, + TMIO_MASK_INIT_RCAR2); +} + +/* + * This is a temporary workaround! This driver used 'hw_reset' wrongly and the + * fix for that showed a regression. So, we mimic the old behaviour until the + * proper solution is found. + */ +static void renesas_sdhi_hw_reset(struct mmc_host *mmc) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + renesas_sdhi_reset(host); +} + #define SH_MOBILE_SDHI_MIN_TAP_ROW 3 static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) @@ -441,7 +592,6 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) unsigned int taps_size = priv->tap_num * 2, min_tap_row; unsigned long *bitmap; - priv->doing_tune = false; sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); /* @@ -500,10 +650,11 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) return 0; } -static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode) +static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode) { + struct tmio_mmc_host *host = mmc_priv(mmc); struct renesas_sdhi *priv = host_to_priv(host); - int i; + int i, ret; priv->tap_num = renesas_sdhi_init_tuning(host); if (!priv->tap_num) @@ -515,7 +666,6 @@ static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode) return -EINVAL; } - priv->doing_tune = true; bitmap_zero(priv->taps, priv->tap_num * 2); bitmap_zero(priv->smpcmp, priv->tap_num * 2); @@ -524,14 +674,17 @@ static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode) /* Set sampling clock position */ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, i % priv->tap_num); - if (mmc_send_tuning(host->mmc, opcode, NULL) == 0) + if (mmc_send_tuning(mmc, opcode, NULL) == 0) set_bit(i, priv->taps); if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) == 0) set_bit(i, priv->smpcmp); } - return renesas_sdhi_select_tuning(host); + ret = renesas_sdhi_select_tuning(host); + if (ret < 0) + renesas_sdhi_reset(host); + return ret; } static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap) @@ -621,7 +774,7 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host) !(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && !use_4tap)) return false; - if (mmc_doing_retune(host->mmc) || priv->doing_tune) + if (mmc_doing_tune(host->mmc)) return false; if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & @@ -631,27 +784,6 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host) return renesas_sdhi_manual_correction(host, use_4tap); } -static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host) -{ - struct renesas_sdhi *priv; - - priv = host_to_priv(host); - - renesas_sdhi_reset_scc(host, priv); - renesas_sdhi_reset_hs400_mode(host, priv); - - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - - sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, - ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & - sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); - - if (host->pdata->flags & TMIO_MMC_MIN_RCAR2) - sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, - TMIO_MASK_INIT_RCAR2); -} - static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit) { int timeout = 1000; @@ -685,7 +817,7 @@ static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) case HOST_MODE: if (host->pdata->flags & TMIO_MMC_HAVE_CBSY) bit = TMIO_STAT_CMD_BUSY; - /* fallthrough */ + fallthrough; case CTL_SD_CARD_CLK_CTL: return renesas_sdhi_wait_idle(host, bit); } @@ -711,6 +843,13 @@ static int renesas_sdhi_multi_io_quirk(struct mmc_card *card, return blk_size; } +static void renesas_sdhi_fixup_request(struct tmio_mmc_host *host, struct mmc_request *mrq) +{ + struct renesas_sdhi *priv = host_to_priv(host); + + if (priv->needs_adjust_hs400 && mrq->cmd->opcode == MMC_SEND_STATUS) + renesas_sdhi_adjust_hs400_mode_enable(host); +} static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) { /* Iff regs are 8 byte apart, sdbuf is 64 bit. Otherwise always 32. */ @@ -742,6 +881,21 @@ static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps2367 = { .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), }; +static const struct renesas_sdhi_quirks sdhi_quirks_r8a7796_es13 = { + .hs400_4taps = true, + .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), + .hs400_calib_table = r8a7796_es13_calib_table, +}; + +static const struct renesas_sdhi_quirks sdhi_quirks_r8a77965 = { + .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), + .hs400_calib_table = r8a77965_calib_table, +}; + +static const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = { + .hs400_calib_table = r8a77990_calib_table, +}; + /* * Note for r8a7796 / r8a774a1: we can't distinguish ES1.1 and 1.2 as of now. * So, we want to treat them equally and only have a match for ES1.2 to enforce @@ -753,10 +907,11 @@ static const struct soc_device_attribute sdhi_quirks_match[] = { { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap }, { .soc_id = "r8a7795", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps2367 }, { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, - { .soc_id = "r8a7796", .revision = "ES1.*", .data = &sdhi_quirks_4tap }, + { .soc_id = "r8a7796", .revision = "ES1.*", .data = &sdhi_quirks_r8a7796_es13 }, { .soc_id = "r8a7796", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps1357 }, - { .soc_id = "r8a77965", .data = &sdhi_quirks_bad_taps2367 }, + { .soc_id = "r8a77965", .data = &sdhi_quirks_r8a77965 }, { .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 }, + { .soc_id = "r8a77990", .data = &sdhi_quirks_r8a77990 }, { /* Sentinel. */ }, }; @@ -862,11 +1017,11 @@ int renesas_sdhi_probe(struct platform_device *pdev, renesas_sdhi_start_signal_voltage_switch; host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27; - /* SDR and HS200/400 registers requires HW reset */ if (of_data && of_data->scc_offset) { priv->scc_ctl = host->ctl + of_data->scc_offset; + host->reset = renesas_sdhi_reset; + host->ops.hw_reset = renesas_sdhi_hw_reset; host->mmc->caps |= MMC_CAP_HW_RESET; - host->hw_reset = renesas_sdhi_hw_reset; } } @@ -915,6 +1070,14 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (ver == SDHI_VER_GEN2_SDR50) mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY; + if (ver == SDHI_VER_GEN3_SDMMC && quirks && quirks->hs400_calib_table) { + host->fixup_request = renesas_sdhi_fixup_request; + priv->adjust_hs400_calib_table = *( + res->start == SDHI_GEN3_MMC0_ADDR ? + quirks->hs400_calib_table : + quirks->hs400_calib_table + 1); + } + ret = tmio_mmc_host_probe(host); if (ret < 0) goto edisclk; @@ -943,8 +1106,8 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (!hit) dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n"); - host->execute_tuning = renesas_sdhi_execute_tuning; host->check_retune = renesas_sdhi_check_scc_error; + host->ops.execute_tuning = renesas_sdhi_execute_tuning; host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning; host->ops.hs400_downgrade = renesas_sdhi_disable_scc; host->ops.hs400_complete = renesas_sdhi_hs400_complete; diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 32ab991544ef..fe13e1ea22dc 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -336,10 +336,6 @@ static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev) if (soc) global_flags |= (unsigned long)soc->data; - dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); - if (!dev->dma_parms) - return -ENOMEM; - /* value is max of SD_SECCNT. Confirmed by HW engineers */ dma_set_max_seg_size(dev, 0xffffffff); @@ -357,6 +353,7 @@ static const struct dev_pm_ops renesas_sdhi_internal_dmac_dev_pm_ops = { static struct platform_driver renesas_internal_dmac_sdhi_driver = { .driver = { .name = "renesas_sdhi_internal_dmac", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &renesas_sdhi_internal_dmac_dev_pm_ops, .of_match_table = renesas_sdhi_internal_dmac_of_match, }, diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 13ff023fbee9..c5f789675302 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -463,6 +463,7 @@ static const struct dev_pm_ops renesas_sdhi_sys_dmac_dev_pm_ops = { static struct platform_driver renesas_sys_dmac_sdhi_driver = { .driver = { .name = "sh_mobile_sdhi", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &renesas_sdhi_sys_dmac_dev_pm_ops, .of_match_table = renesas_sdhi_sys_dmac_of_match, }, diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 2763a376b054..eb395e144207 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1471,6 +1471,7 @@ static struct platform_driver rtsx_pci_sdmmc_driver = { .id_table = rtsx_pci_sdmmc_ids, .driver = { .name = DRV_NAME_RTSX_PCI_SDMMC, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; module_platform_driver(rtsx_pci_sdmmc_driver); diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index 7225d9312af8..5fe4528e296e 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -579,7 +579,6 @@ static void sd_normal_rw(struct rtsx_usb_sdmmc *host, static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx) { struct rtsx_ucr *ucr = host->ucr; - int err; dev_dbg(sdmmc_dev(host), "%s: %s sample_point = %d\n", __func__, tx ? "TX" : "RX", sample_point); @@ -601,11 +600,7 @@ static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx) rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0); rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_RST, 0); - err = rtsx_usb_send_cmd(ucr, MODE_C, 100); - if (err) - return err; - - return 0; + return rtsx_usb_send_cmd(ucr, MODE_C, 100); } static inline u32 get_phase_point(u32 phase_map, unsigned int idx) @@ -1458,6 +1453,7 @@ static struct platform_driver rtsx_usb_sdmmc_driver = { .id_table = rtsx_usb_sdmmc_ids, .driver = { .name = "rtsx_usb_sdmmc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &rtsx_usb_sdmmc_dev_pm_ops, }, }; diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 444b2769ae2c..e3698aba8dd3 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -150,8 +150,8 @@ static void s3cmci_reset(struct s3cmci_host *host); static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) { - u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize; - u32 datcon, datcnt, datsta, fsta, imask; + u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer; + u32 datcon, datcnt, datsta, fsta; con = readl(host->base + S3C2410_SDICON); pre = readl(host->base + S3C2410_SDIPRE); @@ -163,12 +163,10 @@ static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) r2 = readl(host->base + S3C2410_SDIRSP2); r3 = readl(host->base + S3C2410_SDIRSP3); timer = readl(host->base + S3C2410_SDITIMER); - bsize = readl(host->base + S3C2410_SDIBSIZE); datcon = readl(host->base + S3C2410_SDIDCON); datcnt = readl(host->base + S3C2410_SDIDCNT); datsta = readl(host->base + S3C2410_SDIDSTA); fsta = readl(host->base + S3C2410_SDIFSTA); - imask = readl(host->base + host->sdiimsk); dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n", prefix, con, pre, timer); @@ -396,9 +394,6 @@ static void s3cmci_enable_irq(struct s3cmci_host *host, bool more) local_irq_restore(flags); } -/** - * - */ static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer) { unsigned long flags; @@ -1379,7 +1374,7 @@ static int s3cmci_state_show(struct seq_file *seq, void *v) { struct s3cmci_host *host = seq->private; - seq_printf(seq, "Register base = 0x%08x\n", (u32)host->base); + seq_printf(seq, "Register base = 0x%p\n", host->base); seq_printf(seq, "Clock rate = %ld\n", host->clk_rate); seq_printf(seq, "Prescale = %d\n", host->prescaler); seq_printf(seq, "is2440 = %d\n", host->is2440); @@ -1522,7 +1517,7 @@ static int s3cmci_probe_dt(struct s3cmci_host *host) struct mmc_host *mmc = host->mmc; int ret; - host->is2440 = (int) of_device_get_match_data(&pdev->dev); + host->is2440 = (long) of_device_get_match_data(&pdev->dev); ret = mmc_of_parse(mmc); if (ret) @@ -1809,6 +1804,7 @@ MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids); static struct platform_driver s3cmci_driver = { .driver = { .name = "s3c-sdi", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = s3cmci_dt_match, }, .id_table = s3cmci_driver_ids, diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 48ecbd0b180d..54205e3be9e8 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -535,6 +535,11 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = { .caps = MMC_CAP_NONREMOVABLE, }; +struct amd_sdhci_host { + bool tuned_clock; + bool dll_enabled; +}; + /* AMD sdhci reset dll register. */ #define SDHCI_AMD_RESET_DLL_REGISTER 0x908 @@ -546,39 +551,96 @@ static int amd_select_drive_strength(struct mmc_card *card, return MMC_SET_DRIVER_TYPE_A; } -static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host) +static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host, bool enable) { + struct sdhci_acpi_host *acpi_host = sdhci_priv(host); + struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host); + /* AMD Platform requires dll setting */ sdhci_writel(host, 0x40003210, SDHCI_AMD_RESET_DLL_REGISTER); usleep_range(10, 20); - sdhci_writel(host, 0x40033210, SDHCI_AMD_RESET_DLL_REGISTER); + if (enable) + sdhci_writel(host, 0x40033210, SDHCI_AMD_RESET_DLL_REGISTER); + + amd_host->dll_enabled = enable; } /* - * For AMD Platform it is required to disable the tuning - * bit first controller to bring to HS Mode from HS200 - * mode, later enable to tune to HS400 mode. + * The initialization sequence for HS400 is: + * HS->HS200->Perform Tuning->HS->HS400 + * + * The re-tuning sequence is: + * HS400->DDR52->HS->HS200->Perform Tuning->HS->HS400 + * + * The AMD eMMC Controller can only use the tuned clock while in HS200 and HS400 + * mode. If we switch to a different mode, we need to disable the tuned clock. + * If we have previously performed tuning and switch back to HS200 or + * HS400, we can re-enable the tuned clock. + * */ static void amd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_acpi_host *acpi_host = sdhci_priv(host); + struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host); unsigned int old_timing = host->timing; + u16 val; sdhci_set_ios(mmc, ios); - if (old_timing == MMC_TIMING_MMC_HS200 && - ios->timing == MMC_TIMING_MMC_HS) - sdhci_writew(host, 0x9, SDHCI_HOST_CONTROL2); - if (old_timing != MMC_TIMING_MMC_HS400 && - ios->timing == MMC_TIMING_MMC_HS400) { - sdhci_writew(host, 0x80, SDHCI_HOST_CONTROL2); - sdhci_acpi_amd_hs400_dll(host); + + if (old_timing != host->timing && amd_host->tuned_clock) { + if (host->timing == MMC_TIMING_MMC_HS400 || + host->timing == MMC_TIMING_MMC_HS200) { + val = sdhci_readw(host, SDHCI_HOST_CONTROL2); + val |= SDHCI_CTRL_TUNED_CLK; + sdhci_writew(host, val, SDHCI_HOST_CONTROL2); + } else { + val = sdhci_readw(host, SDHCI_HOST_CONTROL2); + val &= ~SDHCI_CTRL_TUNED_CLK; + sdhci_writew(host, val, SDHCI_HOST_CONTROL2); + } + + /* DLL is only required for HS400 */ + if (host->timing == MMC_TIMING_MMC_HS400 && + !amd_host->dll_enabled) + sdhci_acpi_amd_hs400_dll(host, true); } } +static int amd_sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + int err; + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_acpi_host *acpi_host = sdhci_priv(host); + struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host); + + amd_host->tuned_clock = false; + + err = sdhci_execute_tuning(mmc, opcode); + + if (!err && !host->tuning_err) + amd_host->tuned_clock = true; + + return err; +} + +static void amd_sdhci_reset(struct sdhci_host *host, u8 mask) +{ + struct sdhci_acpi_host *acpi_host = sdhci_priv(host); + struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host); + + if (mask & SDHCI_RESET_ALL) { + amd_host->tuned_clock = false; + sdhci_acpi_amd_hs400_dll(host, false); + } + + sdhci_reset(host, mask); +} + static const struct sdhci_ops sdhci_acpi_ops_amd = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, - .reset = sdhci_reset, + .reset = amd_sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, }; @@ -600,8 +662,46 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev, (host->mmc->caps & MMC_CAP_1_8V_DDR)) host->mmc->caps2 = MMC_CAP2_HS400_1_8V; + /* + * There are two types of presets out in the wild: + * 1) Default/broken presets. + * These presets have two sets of problems: + * a) The clock divisor for SDR12, SDR25, and SDR50 is too small. + * This results in clock frequencies that are 2x higher than + * acceptable. i.e., SDR12 = 25 MHz, SDR25 = 50 MHz, SDR50 = + * 100 MHz.x + * b) The HS200 and HS400 driver strengths don't match. + * By default, the SDR104 preset register has a driver strength of + * A, but the (internal) HS400 preset register has a driver + * strength of B. As part of initializing HS400, HS200 tuning + * needs to be performed. Having different driver strengths + * between tuning and operation is wrong. It results in different + * rise/fall times that lead to incorrect sampling. + * 2) Firmware with properly initialized presets. + * These presets have proper clock divisors. i.e., SDR12 => 12MHz, + * SDR25 => 25 MHz, SDR50 => 50 MHz. Additionally the HS200 and + * HS400 preset driver strengths match. + * + * Enabling presets for HS400 doesn't work for the following reasons: + * 1) sdhci_set_ios has a hard coded list of timings that are used + * to determine if presets should be enabled. + * 2) sdhci_get_preset_value is using a non-standard register to + * read out HS400 presets. The AMD controller doesn't support this + * non-standard register. In fact, it doesn't expose the HS400 + * preset register anywhere in the SDHCI memory map. This results + * in reading a garbage value and using the wrong presets. + * + * Since HS400 and HS200 presets must be identical, we could + * instead use the the SDR104 preset register. + * + * If the above issues are resolved we could remove this quirk for + * firmware that that has valid presets (i.e., SDR12 <= 12 MHz). + */ + host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; + host->mmc_host_ops.select_drive_strength = amd_select_drive_strength; host->mmc_host_ops.set_ios = amd_set_ios; + host->mmc_host_ops.execute_tuning = amd_sdhci_execute_tuning; return 0; } @@ -613,6 +713,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_amd_emmc = { SDHCI_QUIRK_32BIT_ADMA_SIZE, .quirks2 = SDHCI_QUIRK2_BROKEN_64_BIT_DMA, .probe_slot = sdhci_acpi_emmc_amd_probe_slot, + .priv_size = sizeof(struct amd_sdhci_host), }; struct sdhci_acpi_uid_slot { @@ -963,6 +1064,7 @@ static const struct dev_pm_ops sdhci_acpi_pm_ops = { static struct platform_driver sdhci_acpi_driver = { .driver = { .name = "sdhci-acpi", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .acpi_match_table = sdhci_acpi_ids, .pm = &sdhci_acpi_pm_ops, }, diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index a6c2bd202b45..4d4aac85cc7a 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -324,6 +324,7 @@ err_pltfm_free: static struct platform_driver sdhci_bcm_kona_driver = { .driver = { .name = "sdhci-kona", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &sdhci_pltfm_pmops, .of_match_table = sdhci_bcm_kona_of_match, }, diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c index ad01f6451a95..bbf3496f4495 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -235,13 +235,11 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probe found match for %s\n", match->compatible); - clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - if (PTR_ERR(clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - dev_err(&pdev->dev, "Clock not found in Device Tree\n"); - clk = NULL; - } + clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk), + "Failed to get clock from Device Tree\n"); + res = clk_prepare_enable(clk); if (res) return res; @@ -328,6 +326,7 @@ MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match); static struct platform_driver sdhci_brcmstb_driver = { .driver = { .name = "sdhci-brcmstb", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &sdhci_pltfm_pmops, .of_match_table = of_match_ptr(sdhci_brcm_of_match), }, diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index 4d9f7681817c..6f2de54a5987 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -463,6 +463,7 @@ MODULE_DEVICE_TABLE(of, sdhci_cdns_match); static struct platform_driver sdhci_cdns_driver = { .driver = { .name = "sdhci-cdns", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &sdhci_cdns_pm_ops, .of_match_table = sdhci_cdns_match, }, diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index 811eab1b8964..2a29c7a4f308 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -98,6 +98,7 @@ static int sdhci_cns3xxx_probe(struct platform_device *pdev) static struct platform_driver sdhci_cns3xxx_driver = { .driver = { .name = "sdhci-cns3xxx", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_cns3xxx_probe, diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index fe9da3122fe9..5e5bf82e5976 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table); static struct platform_driver sdhci_dove_driver = { .driver = { .name = "sdhci-dove", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &sdhci_pltfm_pmops, .of_match_table = sdhci_dove_of_match_table, }, diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index a76b4513fbec..fce8fa7e6b30 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -987,10 +987,20 @@ static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) { u32 reg; + u8 sw_rst; + int ret; /* FIXME: delay a bit for card to be ready for next tuning due to errors */ mdelay(1); + /* IC suggest to reset USDHC before every tuning command */ + esdhc_clrset_le(host, 0xff, SDHCI_RESET_ALL, SDHCI_SOFTWARE_RESET); + ret = readb_poll_timeout(host->ioaddr + SDHCI_SOFTWARE_RESET, sw_rst, + !(sw_rst & SDHCI_RESET_ALL), 10, 100); + if (ret == -ETIMEDOUT) + dev_warn(mmc_dev(host->mmc), + "warning! RESET_ALL never complete before sending tuning command\n"); + reg = readl(host->ioaddr + ESDHC_MIX_CTRL); reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | ESDHC_MIX_CTRL_FBCLK_SEL; @@ -1367,7 +1377,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) * response, block the tuning procedure or the first command * after the whole tuning procedure always can't get any response. */ - tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; + tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { /* @@ -1556,7 +1566,7 @@ static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev, "failed to request card-detect gpio!\n"); return err; } - /* fall through */ + fallthrough; case ESDHC_CD_CONTROLLER: /* we have a working card_detect back */ @@ -1643,10 +1653,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) goto disable_ipg_clk; imx_data->pinctrl = devm_pinctrl_get(&pdev->dev); - if (IS_ERR(imx_data->pinctrl)) { - err = PTR_ERR(imx_data->pinctrl); + if (IS_ERR(imx_data->pinctrl)) dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n"); - } if (esdhc_is_usdhc(imx_data)) { host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; @@ -1917,6 +1925,7 @@ static const struct dev_pm_ops sdhci_esdhc_pmops = { static struct platform_driver sdhci_esdhc_imx_driver = { .driver = { .name = "sdhci-esdhc-imx", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = imx_esdhc_dt_ids, .pm = &sdhci_esdhc_pmops, }, diff --git a/drivers/mmc/host/sdhci-esdhc-mcf.c b/drivers/mmc/host/sdhci-esdhc-mcf.c index 71bf086a9812..ca7a1690b2a8 100644 --- a/drivers/mmc/host/sdhci-esdhc-mcf.c +++ b/drivers/mmc/host/sdhci-esdhc-mcf.c @@ -509,6 +509,7 @@ static int sdhci_esdhc_mcf_remove(struct platform_device *pdev) static struct platform_driver sdhci_esdhc_mcf_driver = { .driver = { .name = "sdhci-esdhc-mcf", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = sdhci_esdhc_mcf_probe, .remove = sdhci_esdhc_mcf_remove, diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index e2d8dfe90077..c9434b461aab 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -283,6 +283,7 @@ static const struct sdhci_pltfm_data sdhci_bcm2711_pltfm_data = { static const struct sdhci_iproc_data bcm2711_data = { .pdata = &sdhci_bcm2711_pltfm_data, + .mmc_caps = MMC_CAP_3_3V_DDR, }; static const struct of_device_id sdhci_iproc_of_match[] = { @@ -368,6 +369,7 @@ err: static struct platform_driver sdhci_iproc_driver = { .driver = { .name = "sdhci-iproc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_iproc_of_match, .acpi_match_table = ACPI_PTR(sdhci_iproc_acpi_ids), .pm = &sdhci_pltfm_pmops, diff --git a/drivers/mmc/host/sdhci-milbeaut.c b/drivers/mmc/host/sdhci-milbeaut.c index 4e7cc0680f94..148b37ac6564 100644 --- a/drivers/mmc/host/sdhci-milbeaut.c +++ b/drivers/mmc/host/sdhci-milbeaut.c @@ -333,6 +333,7 @@ static int sdhci_milbeaut_remove(struct platform_device *pdev) static struct platform_driver sdhci_milbeaut_driver = { .driver = { .name = "sdhci-milbeaut", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(mlb_dt_ids), }, .probe = sdhci_milbeaut_probe, diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 5a33389037cd..3451eb325513 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -263,7 +263,6 @@ struct sdhci_msm_host { unsigned long clk_rate; struct mmc_host *mmc; struct opp_table *opp_table; - bool has_opp_table; bool use_14lpp_dll_reset; bool tuning_done; bool calibration_done; @@ -1166,7 +1165,7 @@ static void sdhci_msm_set_cdr(struct sdhci_host *host, bool enable) static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host = mmc_priv(mmc); - int tuning_seq_cnt = 3; + int tuning_seq_cnt = 10; u8 phase, tuned_phases[16], tuned_phase_cnt = 0; int rc; struct mmc_ios ios = host->mmc->ios; @@ -1222,6 +1221,22 @@ retry: } while (++phase < ARRAY_SIZE(tuned_phases)); if (tuned_phase_cnt) { + if (tuned_phase_cnt == ARRAY_SIZE(tuned_phases)) { + /* + * All phases valid is _almost_ as bad as no phases + * valid. Probably all phases are not really reliable + * but we didn't detect where the unreliable place is. + * That means we'll essentially be guessing and hoping + * we get a good phase. Better to try a few times. + */ + dev_dbg(mmc_dev(mmc), "%s: All phases valid; try again\n", + mmc_hostname(mmc)); + if (--tuning_seq_cnt) { + tuned_phase_cnt = 0; + goto retry; + } + } + rc = msm_find_most_appropriate_phase(host, tuned_phases, tuned_phase_cnt); if (rc < 0) @@ -2151,6 +2166,7 @@ static const struct of_device_id sdhci_msm_dt_match[] = { {.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var}, {.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var}, {.compatible = "qcom,sm8250-sdhci", .data = &sm8250_sdhci_var}, + {.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var}, {}, }; @@ -2285,11 +2301,9 @@ static int sdhci_msm_probe(struct platform_device *pdev) /* OPP table is optional */ ret = dev_pm_opp_of_add_table(&pdev->dev); - if (!ret) { - msm_host->has_opp_table = true; - } else if (ret != -ENODEV) { + if (ret && ret != -ENODEV) { dev_err(&pdev->dev, "Invalid OPP table in Device tree\n"); - goto opp_cleanup; + goto opp_put_clkname; } /* Vote for maximum clock rate for maximum performance */ @@ -2453,8 +2467,8 @@ clk_disable: clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); opp_cleanup: - if (msm_host->has_opp_table) - dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_of_remove_table(&pdev->dev); +opp_put_clkname: dev_pm_opp_put_clkname(msm_host->opp_table); bus_clk_disable: if (!IS_ERR(msm_host->bus_clk)) @@ -2474,8 +2488,7 @@ static int sdhci_msm_remove(struct platform_device *pdev) sdhci_remove_host(host, dead); - if (msm_host->has_opp_table) - dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_of_remove_table(&pdev->dev); dev_pm_opp_put_clkname(msm_host->opp_table); pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -2541,6 +2554,7 @@ static struct platform_driver sdhci_msm_driver = { .name = "sdhci_msm", .of_match_table = sdhci_msm_dt_match, .pm = &sdhci_msm_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index f186fbd016b1..829ccef87426 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -1543,10 +1543,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev) of_node_put(node); if (IS_ERR(sdhci_arasan->soc_ctl_base)) { - ret = PTR_ERR(sdhci_arasan->soc_ctl_base); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Can't get syscon: %d\n", - ret); + ret = dev_err_probe(&pdev->dev, + PTR_ERR(sdhci_arasan->soc_ctl_base), + "Can't get syscon\n"); goto err_pltfm_free; } } @@ -1694,6 +1693,7 @@ static int sdhci_arasan_remove(struct platform_device *pdev) static struct platform_driver sdhci_arasan_driver = { .driver = { .name = "sdhci-arasan", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_arasan_of_match, .pm = &sdhci_arasan_dev_pm_ops, }, diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c index a1bcc0f4ba9e..4f008ba3280e 100644 --- a/drivers/mmc/host/sdhci-of-aspeed.c +++ b/drivers/mmc/host/sdhci-of-aspeed.c @@ -240,6 +240,7 @@ static const struct of_device_id aspeed_sdhci_of_match[] = { static struct platform_driver aspeed_sdhci_driver = { .driver = { .name = "sdhci-aspeed", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = aspeed_sdhci_of_match, }, .probe = aspeed_sdhci_probe, @@ -318,6 +319,7 @@ MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match); static struct platform_driver aspeed_sdc_driver = { .driver = { .name = "sd-controller-aspeed", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &sdhci_pltfm_pmops, .of_match_table = aspeed_sdc_of_match, }, diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 1ece2c50042c..5564d7b23e7c 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -465,6 +465,7 @@ static int sdhci_at91_remove(struct platform_device *pdev) static struct platform_driver sdhci_at91_driver = { .driver = { .name = "sdhci-at91", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_at91_dt_match, .pm = &sdhci_at91_dev_pm_ops, }, diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index 64ac0dbee95c..4b673792b5a4 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -214,6 +214,7 @@ MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); static struct platform_driver sdhci_dwcmshc_driver = { .driver = { .name = "sdhci-dwcmshc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_dwcmshc_dt_ids, .pm = &dwcmshc_pmops, }, diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 7c73d243dc6c..0b45eff6fed4 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -81,6 +81,7 @@ struct sdhci_esdhc { bool quirk_tuning_erratum_type2; bool quirk_ignore_data_inhibit; bool quirk_delay_before_data_reset; + bool quirk_trans_complete_erratum; bool in_sw_tuning; unsigned int peripheral_clock; const struct esdhc_clk_fixup *clk_fixup; @@ -1177,10 +1178,11 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, static u32 esdhc_irq(struct sdhci_host *host, u32 intmask) { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); u32 command; - if (of_find_compatible_node(NULL, NULL, - "fsl,p2020-esdhc")) { + if (esdhc->quirk_trans_complete_erratum) { command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)); if (command == MMC_WRITE_MULTIPLE_BLOCK && @@ -1334,8 +1336,10 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) esdhc->clk_fixup = match->data; np = pdev->dev.of_node; - if (of_device_is_compatible(np, "fsl,p2020-esdhc")) + if (of_device_is_compatible(np, "fsl,p2020-esdhc")) { esdhc->quirk_delay_before_data_reset = true; + esdhc->quirk_trans_complete_erratum = true; + } clk = of_clk_get(np, 0); if (!IS_ERR(clk)) { @@ -1356,13 +1360,19 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) clk_put(clk); } - if (esdhc->peripheral_clock) { - esdhc_clock_enable(host, false); - val = sdhci_readl(host, ESDHC_DMA_SYSCTL); + esdhc_clock_enable(host, false); + val = sdhci_readl(host, ESDHC_DMA_SYSCTL); + /* + * This bit is not able to be reset by SDHCI_RESET_ALL. Need to + * initialize it as 1 or 0 once, to override the different value + * which may be configured in bootloader. + */ + if (esdhc->peripheral_clock) val |= ESDHC_PERIPHERAL_CLK_SEL; - sdhci_writel(host, val, ESDHC_DMA_SYSCTL); - esdhc_clock_enable(host, true); - } + else + val &= ~ESDHC_PERIPHERAL_CLK_SEL; + sdhci_writel(host, val, ESDHC_DMA_SYSCTL); + esdhc_clock_enable(host, true); } static int esdhc_hs400_prepare_ddr(struct mmc_host *mmc) @@ -1464,6 +1474,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) static struct platform_driver sdhci_esdhc_driver = { .driver = { .name = "sdhci-esdhc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_esdhc_of_match, .pm = &esdhc_of_dev_pm_ops, }, diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index da844a39af6e..12675797b296 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -80,6 +80,7 @@ MODULE_DEVICE_TABLE(of, sdhci_hlwd_of_match); static struct platform_driver sdhci_hlwd_driver = { .driver = { .name = "sdhci-hlwd", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_hlwd_of_match, .pm = &sdhci_pltfm_pmops, }, diff --git a/drivers/mmc/host/sdhci-of-sparx5.c b/drivers/mmc/host/sdhci-of-sparx5.c new file mode 100644 index 000000000000..28e4ee69e100 --- /dev/null +++ b/drivers/mmc/host/sdhci-of-sparx5.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * drivers/mmc/host/sdhci-of-sparx5.c + * + * MCHP Sparx5 SoC Secure Digital Host Controller Interface. + * + * Copyright (c) 2019 Microchip Inc. + * + * Author: Lars Povlsen <lars.povlsen@microchip.com> + */ + +#include <linux/sizes.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/of_device.h> +#include <linux/mfd/syscon.h> +#include <linux/dma-mapping.h> + +#include "sdhci-pltfm.h" + +#define CPU_REGS_GENERAL_CTRL (0x22 * 4) +#define MSHC_DLY_CC_MASK GENMASK(16, 13) +#define MSHC_DLY_CC_SHIFT 13 +#define MSHC_DLY_CC_MAX 15 + +#define CPU_REGS_PROC_CTRL (0x2C * 4) +#define ACP_CACHE_FORCE_ENA BIT(4) +#define ACP_AWCACHE BIT(3) +#define ACP_ARCACHE BIT(2) +#define ACP_CACHE_MASK (ACP_CACHE_FORCE_ENA|ACP_AWCACHE|ACP_ARCACHE) + +#define MSHC2_VERSION 0x500 /* Off 0x140, reg 0x0 */ +#define MSHC2_TYPE 0x504 /* Off 0x140, reg 0x1 */ +#define MSHC2_EMMC_CTRL 0x52c /* Off 0x140, reg 0xB */ +#define MSHC2_EMMC_CTRL_EMMC_RST_N BIT(2) +#define MSHC2_EMMC_CTRL_IS_EMMC BIT(0) + +struct sdhci_sparx5_data { + struct sdhci_host *host; + struct regmap *cpu_ctrl; + int delay_clock; +}; + +#define BOUNDARY_OK(addr, len) \ + ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) + +/* + * If DMA addr spans 128MB boundary, we split the DMA transfer into two + * so that each DMA transfer doesn't exceed the boundary. + */ +static void sdhci_sparx5_adma_write_desc(struct sdhci_host *host, void **desc, + dma_addr_t addr, int len, + unsigned int cmd) +{ + int tmplen, offset; + + if (likely(!len || BOUNDARY_OK(addr, len))) { + sdhci_adma_write_desc(host, desc, addr, len, cmd); + return; + } + + pr_debug("%s: write_desc: splitting dma len %d, offset %pad\n", + mmc_hostname(host->mmc), len, &addr); + + offset = addr & (SZ_128M - 1); + tmplen = SZ_128M - offset; + sdhci_adma_write_desc(host, desc, addr, tmplen, cmd); + + addr += tmplen; + len -= tmplen; + sdhci_adma_write_desc(host, desc, addr, len, cmd); +} + +static void sparx5_set_cacheable(struct sdhci_host *host, u32 value) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host); + + pr_debug("%s: Set Cacheable = 0x%x\n", mmc_hostname(host->mmc), value); + + /* Update ACP caching attributes in HW */ + regmap_update_bits(sdhci_sparx5->cpu_ctrl, + CPU_REGS_PROC_CTRL, ACP_CACHE_MASK, value); +} + +static void sparx5_set_delay(struct sdhci_host *host, u8 value) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host); + + pr_debug("%s: Set DLY_CC = %u\n", mmc_hostname(host->mmc), value); + + /* Update DLY_CC in HW */ + regmap_update_bits(sdhci_sparx5->cpu_ctrl, + CPU_REGS_GENERAL_CTRL, + MSHC_DLY_CC_MASK, + (value << MSHC_DLY_CC_SHIFT)); +} + +static void sdhci_sparx5_set_emmc(struct sdhci_host *host) +{ + if (!mmc_card_is_removable(host->mmc)) { + u8 value; + + value = sdhci_readb(host, MSHC2_EMMC_CTRL); + if (!(value & MSHC2_EMMC_CTRL_IS_EMMC)) { + value |= MSHC2_EMMC_CTRL_IS_EMMC; + pr_debug("%s: Set EMMC_CTRL: 0x%08x\n", + mmc_hostname(host->mmc), value); + sdhci_writeb(host, value, MSHC2_EMMC_CTRL); + } + } +} + +static void sdhci_sparx5_reset_emmc(struct sdhci_host *host) +{ + u8 value; + + pr_debug("%s: Toggle EMMC_CTRL.EMMC_RST_N\n", mmc_hostname(host->mmc)); + value = sdhci_readb(host, MSHC2_EMMC_CTRL) & + ~MSHC2_EMMC_CTRL_EMMC_RST_N; + sdhci_writeb(host, value, MSHC2_EMMC_CTRL); + /* For eMMC, minimum is 1us but give it 10us for good measure */ + usleep_range(10, 20); + sdhci_writeb(host, value | MSHC2_EMMC_CTRL_EMMC_RST_N, + MSHC2_EMMC_CTRL); + /* For eMMC, minimum is 200us but give it 300us for good measure */ + usleep_range(300, 400); +} + +static void sdhci_sparx5_reset(struct sdhci_host *host, u8 mask) +{ + pr_debug("%s: *** RESET: mask %d\n", mmc_hostname(host->mmc), mask); + + sdhci_reset(host, mask); + + /* Be sure CARD_IS_EMMC stays set */ + sdhci_sparx5_set_emmc(host); +} + +static const struct sdhci_ops sdhci_sparx5_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .reset = sdhci_sparx5_reset, + .adma_write_desc = sdhci_sparx5_adma_write_desc, +}; + +static const struct sdhci_pltfm_data sdhci_sparx5_pdata = { + .quirks = 0, + .quirks2 = SDHCI_QUIRK2_HOST_NO_CMD23 | /* Controller issue */ + SDHCI_QUIRK2_NO_1_8_V, /* No sdr104, ddr50, etc */ + .ops = &sdhci_sparx5_ops, +}; + +static int sdhci_sparx5_probe(struct platform_device *pdev) +{ + int ret; + const char *syscon = "microchip,sparx5-cpu-syscon"; + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_sparx5_data *sdhci_sparx5; + struct device_node *np = pdev->dev.of_node; + u32 value; + u32 extra; + + host = sdhci_pltfm_init(pdev, &sdhci_sparx5_pdata, + sizeof(*sdhci_sparx5)); + + if (IS_ERR(host)) + return PTR_ERR(host); + + /* + * extra adma table cnt for cross 128M boundary handling. + */ + extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M); + if (extra > SDHCI_MAX_SEGS) + extra = SDHCI_MAX_SEGS; + host->adma_table_cnt += extra; + + pltfm_host = sdhci_priv(host); + sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host); + sdhci_sparx5->host = host; + + pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(pltfm_host->clk)) { + ret = PTR_ERR(pltfm_host->clk); + dev_err(&pdev->dev, "failed to get core clk: %d\n", ret); + goto free_pltfm; + } + ret = clk_prepare_enable(pltfm_host->clk); + if (ret) + goto free_pltfm; + + if (!of_property_read_u32(np, "microchip,clock-delay", &value) && + (value > 0 && value <= MSHC_DLY_CC_MAX)) + sdhci_sparx5->delay_clock = value; + + sdhci_get_of_property(pdev); + + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_clk; + + sdhci_sparx5->cpu_ctrl = syscon_regmap_lookup_by_compatible(syscon); + if (IS_ERR(sdhci_sparx5->cpu_ctrl)) { + dev_err(&pdev->dev, "No CPU syscon regmap !\n"); + ret = PTR_ERR(sdhci_sparx5->cpu_ctrl); + goto err_clk; + } + + if (sdhci_sparx5->delay_clock >= 0) + sparx5_set_delay(host, sdhci_sparx5->delay_clock); + + if (!mmc_card_is_removable(host->mmc)) { + /* Do a HW reset of eMMC card */ + sdhci_sparx5_reset_emmc(host); + /* Update EMMC_CTRL */ + sdhci_sparx5_set_emmc(host); + /* If eMMC, disable SD and SDIO */ + host->mmc->caps2 |= (MMC_CAP2_NO_SDIO|MMC_CAP2_NO_SD); + } + + ret = sdhci_add_host(host); + if (ret) + goto err_clk; + + /* Set AXI bus master to use un-cached access (for DMA) */ + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA) && + IS_ENABLED(CONFIG_DMA_DECLARE_COHERENT)) + sparx5_set_cacheable(host, ACP_CACHE_FORCE_ENA); + + pr_debug("%s: SDHC version: 0x%08x\n", + mmc_hostname(host->mmc), sdhci_readl(host, MSHC2_VERSION)); + pr_debug("%s: SDHC type: 0x%08x\n", + mmc_hostname(host->mmc), sdhci_readl(host, MSHC2_TYPE)); + + return ret; + +err_clk: + clk_disable_unprepare(pltfm_host->clk); +free_pltfm: + sdhci_pltfm_free(pdev); + return ret; +} + +static const struct of_device_id sdhci_sparx5_of_match[] = { + { .compatible = "microchip,dw-sparx5-sdhci" }, + { } +}; +MODULE_DEVICE_TABLE(of, sdhci_sparx5_of_match); + +static struct platform_driver sdhci_sparx5_driver = { + .driver = { + .name = "sdhci-sparx5", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = sdhci_sparx5_of_match, + .pm = &sdhci_pltfm_pmops, + }, + .probe = sdhci_sparx5_probe, + .remove = sdhci_pltfm_unregister, +}; + +module_platform_driver(sdhci_sparx5_driver); + +MODULE_DESCRIPTION("Sparx5 SDHCI OF driver"); +MODULE_AUTHOR("Lars Povlsen <lars.povlsen@microchip.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 1ec74c2d5c17..7893fd3599b6 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -1297,6 +1297,7 @@ static struct platform_driver sdhci_omap_driver = { .remove = sdhci_omap_remove, .driver = { .name = "sdhci-omap", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &sdhci_omap_dev_pm_ops, .of_match_table = omap_sdhci_match, }, diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index bb6802448b2f..23da7f7fe093 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -24,6 +24,8 @@ #include <linux/iopoll.h> #include <linux/gpio.h> #include <linux/pm_runtime.h> +#include <linux/pm_qos.h> +#include <linux/debugfs.h> #include <linux/mmc/slot-gpio.h> #include <linux/mmc/sdhci-pci-data.h> #include <linux/acpi.h> @@ -232,6 +234,14 @@ static void sdhci_pci_dumpregs(struct mmc_host *mmc) sdhci_dumpregs(mmc_priv(mmc)); } +static void sdhci_cqhci_reset(struct sdhci_host *host, u8 mask) +{ + if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && + host->mmc->cqe_private) + cqhci_deactivate(host->mmc); + sdhci_reset(host, mask); +} + /*****************************************************************************\ * * * Hardware specific quirk handling * @@ -508,6 +518,8 @@ struct intel_host { bool rpm_retune_ok; u32 glk_rx_ctrl1; u32 glk_tun_val; + u32 active_ltr; + u32 idle_ltr; }; static const guid_t intel_dsm_guid = @@ -718,7 +730,7 @@ static const struct sdhci_ops sdhci_intel_glk_ops = { .set_power = sdhci_intel_set_power, .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_set_bus_width, - .reset = sdhci_reset, + .reset = sdhci_cqhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, .hw_reset = sdhci_pci_hw_reset, .irq = sdhci_cqhci_irq, @@ -752,6 +764,108 @@ static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode) return 0; } +#define INTEL_ACTIVELTR 0x804 +#define INTEL_IDLELTR 0x808 + +#define INTEL_LTR_REQ BIT(15) +#define INTEL_LTR_SCALE_MASK GENMASK(11, 10) +#define INTEL_LTR_SCALE_1US (2 << 10) +#define INTEL_LTR_SCALE_32US (3 << 10) +#define INTEL_LTR_VALUE_MASK GENMASK(9, 0) + +static void intel_cache_ltr(struct sdhci_pci_slot *slot) +{ + struct intel_host *intel_host = sdhci_pci_priv(slot); + struct sdhci_host *host = slot->host; + + intel_host->active_ltr = readl(host->ioaddr + INTEL_ACTIVELTR); + intel_host->idle_ltr = readl(host->ioaddr + INTEL_IDLELTR); +} + +static void intel_ltr_set(struct device *dev, s32 val) +{ + struct sdhci_pci_chip *chip = dev_get_drvdata(dev); + struct sdhci_pci_slot *slot = chip->slots[0]; + struct intel_host *intel_host = sdhci_pci_priv(slot); + struct sdhci_host *host = slot->host; + u32 ltr; + + pm_runtime_get_sync(dev); + + /* + * Program latency tolerance (LTR) accordingly what has been asked + * by the PM QoS layer or disable it in case we were passed + * negative value or PM_QOS_LATENCY_ANY. + */ + ltr = readl(host->ioaddr + INTEL_ACTIVELTR); + + if (val == PM_QOS_LATENCY_ANY || val < 0) { + ltr &= ~INTEL_LTR_REQ; + } else { + ltr |= INTEL_LTR_REQ; + ltr &= ~INTEL_LTR_SCALE_MASK; + ltr &= ~INTEL_LTR_VALUE_MASK; + + if (val > INTEL_LTR_VALUE_MASK) { + val >>= 5; + if (val > INTEL_LTR_VALUE_MASK) + val = INTEL_LTR_VALUE_MASK; + ltr |= INTEL_LTR_SCALE_32US | val; + } else { + ltr |= INTEL_LTR_SCALE_1US | val; + } + } + + if (ltr == intel_host->active_ltr) + goto out; + + writel(ltr, host->ioaddr + INTEL_ACTIVELTR); + writel(ltr, host->ioaddr + INTEL_IDLELTR); + + /* Cache the values into lpss structure */ + intel_cache_ltr(slot); +out: + pm_runtime_put_autosuspend(dev); +} + +static bool intel_use_ltr(struct sdhci_pci_chip *chip) +{ + switch (chip->pdev->device) { + case PCI_DEVICE_ID_INTEL_BYT_EMMC: + case PCI_DEVICE_ID_INTEL_BYT_EMMC2: + case PCI_DEVICE_ID_INTEL_BYT_SDIO: + case PCI_DEVICE_ID_INTEL_BYT_SD: + case PCI_DEVICE_ID_INTEL_BSW_EMMC: + case PCI_DEVICE_ID_INTEL_BSW_SDIO: + case PCI_DEVICE_ID_INTEL_BSW_SD: + return false; + default: + return true; + } +} + +static void intel_ltr_expose(struct sdhci_pci_chip *chip) +{ + struct device *dev = &chip->pdev->dev; + + if (!intel_use_ltr(chip)) + return; + + dev->power.set_latency_tolerance = intel_ltr_set; + dev_pm_qos_expose_latency_tolerance(dev); +} + +static void intel_ltr_hide(struct sdhci_pci_chip *chip) +{ + struct device *dev = &chip->pdev->dev; + + if (!intel_use_ltr(chip)) + return; + + dev_pm_qos_hide_latency_tolerance(dev); + dev->power.set_latency_tolerance = NULL; +} + static void byt_probe_slot(struct sdhci_pci_slot *slot) { struct mmc_host_ops *ops = &slot->host->mmc_host_ops; @@ -766,6 +880,43 @@ static void byt_probe_slot(struct sdhci_pci_slot *slot) ops->start_signal_voltage_switch = intel_start_signal_voltage_switch; device_property_read_u32(dev, "max-frequency", &mmc->f_max); + + if (!mmc->slotno) { + slot->chip->slots[mmc->slotno] = slot; + intel_ltr_expose(slot->chip); + } +} + +static void byt_add_debugfs(struct sdhci_pci_slot *slot) +{ + struct intel_host *intel_host = sdhci_pci_priv(slot); + struct mmc_host *mmc = slot->host->mmc; + struct dentry *dir = mmc->debugfs_root; + + if (!intel_use_ltr(slot->chip)) + return; + + debugfs_create_x32("active_ltr", 0444, dir, &intel_host->active_ltr); + debugfs_create_x32("idle_ltr", 0444, dir, &intel_host->idle_ltr); + + intel_cache_ltr(slot); +} + +static int byt_add_host(struct sdhci_pci_slot *slot) +{ + int ret = sdhci_add_host(slot->host); + + if (!ret) + byt_add_debugfs(slot); + return ret; +} + +static void byt_remove_slot(struct sdhci_pci_slot *slot, int dead) +{ + struct mmc_host *mmc = slot->host->mmc; + + if (!mmc->slotno) + intel_ltr_hide(slot->chip); } static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) @@ -786,7 +937,8 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) static bool glk_broken_cqhci(struct sdhci_pci_slot *slot) { return slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC && - dmi_match(DMI_BIOS_VENDOR, "LENOVO"); + (dmi_match(DMI_BIOS_VENDOR, "LENOVO") || + dmi_match(DMI_SYS_VENDOR, "IRBIS")); } static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot) @@ -846,6 +998,8 @@ static int glk_emmc_add_host(struct sdhci_pci_slot *slot) if (ret) goto cleanup; + byt_add_debugfs(slot); + return 0; cleanup: @@ -1023,6 +1177,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { #endif .allow_runtime_pm = true, .probe_slot = byt_emmc_probe_slot, + .add_host = byt_add_host, + .remove_slot = byt_remove_slot, .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | SDHCI_QUIRK_NO_LED, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | @@ -1036,6 +1192,7 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = { .allow_runtime_pm = true, .probe_slot = glk_emmc_probe_slot, .add_host = glk_emmc_add_host, + .remove_slot = byt_remove_slot, #ifdef CONFIG_PM_SLEEP .suspend = sdhci_cqhci_suspend, .resume = sdhci_cqhci_resume, @@ -1066,6 +1223,8 @@ static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = { SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .allow_runtime_pm = true, .probe_slot = ni_byt_sdio_probe_slot, + .add_host = byt_add_host, + .remove_slot = byt_remove_slot, .ops = &sdhci_intel_byt_ops, .priv_size = sizeof(struct intel_host), }; @@ -1083,6 +1242,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .allow_runtime_pm = true, .probe_slot = byt_sdio_probe_slot, + .add_host = byt_add_host, + .remove_slot = byt_remove_slot, .ops = &sdhci_intel_byt_ops, .priv_size = sizeof(struct intel_host), }; @@ -1102,6 +1263,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { .allow_runtime_pm = true, .own_cd_for_runtime_pm = true, .probe_slot = byt_sd_probe_slot, + .add_host = byt_add_host, + .remove_slot = byt_remove_slot, .ops = &sdhci_intel_byt_ops, .priv_size = sizeof(struct intel_host), }; diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 5da2b06d84ae..9887485a4134 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -14,6 +14,7 @@ #include <linux/delay.h> #include "sdhci.h" #include "sdhci-pci.h" +#include "cqhci.h" /* Genesys Logic extra registers */ #define SDHCI_GLI_9750_WT 0x800 @@ -81,9 +82,16 @@ #define GLI_9763E_VHS_REV_R 0x0 #define GLI_9763E_VHS_REV_M 0x1 #define GLI_9763E_VHS_REV_W 0x2 +#define PCIE_GLI_9763E_MB 0x888 +#define GLI_9763E_MB_CMDQ_OFF BIT(19) #define PCIE_GLI_9763E_SCR 0x8E0 #define GLI_9763E_SCR_AXI_REQ BIT(9) +#define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200 +#define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \ + SDHCI_TRNS_BLK_CNT_EN | \ + SDHCI_TRNS_DMA) + #define PCI_GLI_9755_WT 0x800 #define PCI_GLI_9755_WT_EN BIT(0) #define GLI_9755_WT_EN_ON 0x1 @@ -578,6 +586,30 @@ static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip) return sdhci_pci_resume_host(chip); } + +static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip) +{ + struct sdhci_pci_slot *slot = chip->slots[0]; + int ret; + + ret = sdhci_pci_gli_resume(chip); + if (ret) + return ret; + + return cqhci_resume(slot->host->mmc); +} + +static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip) +{ + struct sdhci_pci_slot *slot = chip->slots[0]; + int ret; + + ret = cqhci_suspend(slot->host->mmc); + if (ret) + return ret; + + return sdhci_suspend_host(slot->host); +} #endif static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc, @@ -614,6 +646,110 @@ static void sdhci_set_gl9763e_signaling(struct sdhci_host *host, sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); } +static void sdhci_gl9763e_dumpregs(struct mmc_host *mmc) +{ + sdhci_dumpregs(mmc_priv(mmc)); +} + +static void sdhci_gl9763e_cqe_pre_enable(struct mmc_host *mmc) +{ + struct cqhci_host *cq_host = mmc->cqe_private; + u32 value; + + value = cqhci_readl(cq_host, CQHCI_CFG); + value |= CQHCI_ENABLE; + cqhci_writel(cq_host, value, CQHCI_CFG); +} + +static void sdhci_gl9763e_cqe_enable(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_writew(host, GLI_9763E_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); + sdhci_cqe_enable(mmc); +} + +static u32 sdhci_gl9763e_cqhci_irq(struct sdhci_host *host, u32 intmask) +{ + int cmd_error = 0; + int data_error = 0; + + if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) + return intmask; + + cqhci_irq(host->mmc, intmask, cmd_error, data_error); + + return 0; +} + +static void sdhci_gl9763e_cqe_post_disable(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct cqhci_host *cq_host = mmc->cqe_private; + u32 value; + + value = cqhci_readl(cq_host, CQHCI_CFG); + value &= ~CQHCI_ENABLE; + cqhci_writel(cq_host, value, CQHCI_CFG); + sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); +} + +static const struct cqhci_host_ops sdhci_gl9763e_cqhci_ops = { + .enable = sdhci_gl9763e_cqe_enable, + .disable = sdhci_cqe_disable, + .dumpregs = sdhci_gl9763e_dumpregs, + .pre_enable = sdhci_gl9763e_cqe_pre_enable, + .post_disable = sdhci_gl9763e_cqe_post_disable, +}; + +static int gl9763e_add_host(struct sdhci_pci_slot *slot) +{ + struct device *dev = &slot->chip->pdev->dev; + struct sdhci_host *host = slot->host; + struct cqhci_host *cq_host; + bool dma64; + int ret; + + ret = sdhci_setup_host(host); + if (ret) + return ret; + + cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL); + if (!cq_host) { + ret = -ENOMEM; + goto cleanup; + } + + cq_host->mmio = host->ioaddr + SDHCI_GLI_9763E_CQE_BASE_ADDR; + cq_host->ops = &sdhci_gl9763e_cqhci_ops; + + dma64 = host->flags & SDHCI_USE_64_BIT_DMA; + if (dma64) + cq_host->caps |= CQHCI_TASK_DESC_SZ_128; + + ret = cqhci_init(cq_host, host->mmc, dma64); + if (ret) + goto cleanup; + + ret = __sdhci_add_host(host); + if (ret) + goto cleanup; + + return 0; + +cleanup: + sdhci_cleanup_host(host); + return ret; +} + +static void sdhci_gl9763e_reset(struct sdhci_host *host, u8 mask) +{ + if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && + host->mmc->cqe_private) + cqhci_deactivate(host->mmc); + sdhci_reset(host, mask); +} + static void gli_set_gl9763e(struct sdhci_pci_slot *slot) { struct pci_dev *pdev = slot->chip->pdev; @@ -636,7 +772,9 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot) static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) { + struct pci_dev *pdev = slot->chip->pdev; struct sdhci_host *host = slot->host; + u32 value; host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_1_8V_DDR | @@ -646,6 +784,11 @@ static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) MMC_CAP2_HS400_ES | MMC_CAP2_NO_SDIO | MMC_CAP2_NO_SD; + + pci_read_config_dword(pdev, PCIE_GLI_9763E_MB, &value); + if (!(value & GLI_9763E_MB_CMDQ_OFF)) + host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; + gli_pcie_enable_msi(slot); host->mmc_host_ops.hs400_enhanced_strobe = gl9763e_hs400_enhanced_strobe; @@ -699,9 +842,10 @@ static const struct sdhci_ops sdhci_gl9763e_ops = { .set_clock = sdhci_set_clock, .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_set_bus_width, - .reset = sdhci_reset, + .reset = sdhci_gl9763e_reset, .set_uhs_signaling = sdhci_set_gl9763e_signaling, .voltage_switch = sdhci_gli_voltage_switch, + .irq = sdhci_gl9763e_cqhci_irq, }; const struct sdhci_pci_fixes sdhci_gl9763e = { @@ -709,6 +853,8 @@ const struct sdhci_pci_fixes sdhci_gl9763e = { .probe_slot = gli_probe_slot_gl9763e, .ops = &sdhci_gl9763e_ops, #ifdef CONFIG_PM_SLEEP - .resume = sdhci_pci_gli_resume, + .resume = sdhci_cqhci_gli_resume, + .suspend = sdhci_cqhci_gli_suspend, #endif + .add_host = gl9763e_add_host, }; diff --git a/drivers/mmc/host/sdhci-pic32.c b/drivers/mmc/host/sdhci-pic32.c index a11e6397d4ff..6ce1519ae177 100644 --- a/drivers/mmc/host/sdhci-pic32.c +++ b/drivers/mmc/host/sdhci-pic32.c @@ -241,6 +241,7 @@ MODULE_DEVICE_TABLE(of, pic32_sdhci_id_table); static struct platform_driver pic32_sdhci_driver = { .driver = { .name = "pic32-sdhci", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(pic32_sdhci_id_table), }, .probe = pic32_sdhci_probe, diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 9282bc4b8c41..f18906b5575f 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -226,6 +226,7 @@ free: static struct platform_driver sdhci_pxav2_driver = { .driver = { .name = "sdhci-pxav2", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(sdhci_pxav2_of_match), .pm = &sdhci_pltfm_pmops, }, diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index e55037ceda73..a6d89a3f1946 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -567,6 +567,7 @@ static const struct dev_pm_ops sdhci_pxav3_pmops = { static struct platform_driver sdhci_pxav3_driver = { .driver = { .name = "sdhci-pxav3", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(sdhci_pxav3_of_match), .pm = &sdhci_pxav3_pmops, }, diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 9194bb73e601..f48a788a9d3d 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -461,7 +461,9 @@ static int sdhci_s3c_parse_dt(struct device *dev, } #endif +#ifdef CONFIG_OF static const struct of_device_id sdhci_s3c_dt_match[]; +#endif static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data( struct platform_device *pdev) @@ -609,7 +611,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) switch (pdata->max_width) { case 8: host->mmc->caps |= MMC_CAP_8_BIT_DATA; - /* Fall through */ + fallthrough; case 4: host->mmc->caps |= MMC_CAP_4_BIT_DATA; break; @@ -784,6 +786,7 @@ static struct platform_driver sdhci_s3c_driver = { .id_table = sdhci_s3c_driver_ids, .driver = { .name = "s3c-sdhci", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(sdhci_s3c_dt_match), .pm = &sdhci_s3c_pmops, }, diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c index f4b05dd6c20a..e9b347b3af7e 100644 --- a/drivers/mmc/host/sdhci-sirf.c +++ b/drivers/mmc/host/sdhci-sirf.c @@ -220,6 +220,7 @@ MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match); static struct platform_driver sdhci_sirf_driver = { .driver = { .name = "sdhci-sirf", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_sirf_of_match, .pm = &sdhci_pltfm_pmops, }, diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index b4b63089a4e2..d463e2fd5b1a 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -181,6 +181,7 @@ MODULE_DEVICE_TABLE(of, sdhci_spear_id_table); static struct platform_driver sdhci_driver = { .driver = { .name = "sdhci", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &sdhci_pm_ops, .of_match_table = of_match_ptr(sdhci_spear_id_table), }, diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index a910cb461ed7..58109c5b53e2 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -387,7 +387,7 @@ static void sdhci_sprd_request_done(struct sdhci_host *host, if (mmc_hsq_finalize_request(host->mmc, mrq)) return; - mmc_request_done(host->mmc, mrq); + mmc_request_done(host->mmc, mrq); } static struct sdhci_ops sdhci_sprd_ops = { @@ -433,7 +433,7 @@ static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq) } static int sdhci_sprd_request_atomic(struct mmc_host *mmc, - struct mmc_request *mrq) + struct mmc_request *mrq) { sdhci_sprd_check_auto_cmd23(mmc, mrq); @@ -470,7 +470,7 @@ static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) break; default: - /* fall-through */ + fallthrough; case MMC_SIGNAL_VOLTAGE_330: ret = pinctrl_select_state(sprd_host->pinctrl, sprd_host->pins_default); @@ -787,6 +787,7 @@ static struct platform_driver sdhci_sprd_driver = { .remove = sdhci_sprd_remove, .driver = { .name = "sdhci_sprd_r11", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(sdhci_sprd_of_match), .pm = &sdhci_sprd_pm_ops, }, diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c index 1301cebfc3ea..4e9ff3e828ba 100644 --- a/drivers/mmc/host/sdhci-st.c +++ b/drivers/mmc/host/sdhci-st.c @@ -521,6 +521,7 @@ static struct platform_driver sdhci_st_driver = { .remove = sdhci_st_remove, .driver = { .name = "sdhci-st", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &sdhci_st_pmops, .of_match_table = of_match_ptr(st_sdhci_match), }, diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 0a3f9d024f2a..ed12aacb1c73 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -110,6 +110,12 @@ #define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8) #define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING BIT(9) +/* + * NVQUIRK_HAS_TMCLK is for SoC's having separate timeout clock for Tegra + * SDMMC hardware data timeout. + */ +#define NVQUIRK_HAS_TMCLK BIT(10) + /* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */ #define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000 @@ -140,6 +146,7 @@ struct sdhci_tegra_autocal_offsets { struct sdhci_tegra { const struct sdhci_tegra_soc_data *soc_data; struct gpio_desc *power_gpio; + struct clk *tmclk; bool ddr_signaling; bool pad_calib_required; bool pad_control_available; @@ -1418,7 +1425,6 @@ static const struct sdhci_ops tegra210_sdhci_ops = { static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | @@ -1434,7 +1440,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = { NVQUIRK_HAS_PADCALIB | NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_ENABLE_SDR50 | - NVQUIRK_ENABLE_SDR104, + NVQUIRK_ENABLE_SDR104 | + NVQUIRK_HAS_TMCLK, .min_tap_delay = 106, .max_tap_delay = 185, }; @@ -1456,7 +1463,6 @@ static const struct sdhci_ops tegra186_sdhci_ops = { static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | @@ -1473,6 +1479,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra186 = { NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_SDR104 | + NVQUIRK_HAS_TMCLK | NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING, .min_tap_delay = 84, .max_tap_delay = 136, @@ -1485,7 +1492,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra194 = { NVQUIRK_HAS_PADCALIB | NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_ENABLE_SDR50 | - NVQUIRK_ENABLE_SDR104, + NVQUIRK_ENABLE_SDR104 | + NVQUIRK_HAS_TMCLK, .min_tap_delay = 96, .max_tap_delay = 139, }; @@ -1613,13 +1621,47 @@ static int sdhci_tegra_probe(struct platform_device *pdev) goto err_power_req; } - clk = devm_clk_get(mmc_dev(host->mmc), NULL); - if (IS_ERR(clk)) { - rc = PTR_ERR(clk); + /* + * Tegra210 has a separate SDMMC_LEGACY_TM clock used for host + * timeout clock and SW can choose TMCLK or SDCLK for hardware + * data timeout through the bit USE_TMCLK_FOR_DATA_TIMEOUT of + * the register SDHCI_TEGRA_VENDOR_SYS_SW_CTRL. + * + * USE_TMCLK_FOR_DATA_TIMEOUT bit default is set to 1 and SDMMC uses + * 12Mhz TMCLK which is advertised in host capability register. + * With TMCLK of 12Mhz provides maximum data timeout period that can + * be achieved is 11s better than using SDCLK for data timeout. + * + * So, TMCLK is set to 12Mhz and kept enabled all the time on SoC's + * supporting separate TMCLK. + */ + + if (soc_data->nvquirks & NVQUIRK_HAS_TMCLK) { + clk = devm_clk_get(&pdev->dev, "tmclk"); + if (IS_ERR(clk)) { + rc = PTR_ERR(clk); + if (rc == -EPROBE_DEFER) + goto err_power_req; + + dev_warn(&pdev->dev, "failed to get tmclk: %d\n", rc); + clk = NULL; + } - if (rc != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get clock: %d\n", rc); + clk_set_rate(clk, 12000000); + rc = clk_prepare_enable(clk); + if (rc) { + dev_err(&pdev->dev, + "failed to enable tmclk: %d\n", rc); + goto err_power_req; + } + + tegra_host->tmclk = clk; + } + clk = devm_clk_get(mmc_dev(host->mmc), NULL); + if (IS_ERR(clk)) { + rc = dev_err_probe(&pdev->dev, PTR_ERR(clk), + "failed to get clock\n"); goto err_clk_get; } clk_prepare_enable(clk); @@ -1656,6 +1698,7 @@ err_add_host: err_rst_get: clk_disable_unprepare(pltfm_host->clk); err_clk_get: + clk_disable_unprepare(tegra_host->tmclk); err_power_req: err_parse_dt: sdhci_pltfm_free(pdev); @@ -1673,6 +1716,7 @@ static int sdhci_tegra_remove(struct platform_device *pdev) reset_control_assert(tegra_host->rst); usleep_range(2000, 4000); clk_disable_unprepare(pltfm_host->clk); + clk_disable_unprepare(tegra_host->tmclk); sdhci_pltfm_free(pdev); @@ -1738,6 +1782,7 @@ static SIMPLE_DEV_PM_OPS(sdhci_tegra_dev_pm_ops, sdhci_tegra_suspend, static struct platform_driver sdhci_tegra_driver = { .driver = { .name = "sdhci-tegra", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_tegra_dt_match, .pm = &sdhci_tegra_dev_pm_ops, }, diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c index e6e9e286cc34..03ce57ef4585 100644 --- a/drivers/mmc/host/sdhci-xenon-phy.c +++ b/drivers/mmc/host/sdhci-xenon-phy.c @@ -527,7 +527,7 @@ static bool xenon_emmc_phy_slow_mode(struct sdhci_host *host, ret = true; break; } - /* fall through */ + fallthrough; default: reg &= ~XENON_TIMING_ADJUST_SLOW_MODE; ret = false; diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c index 4703cd540c7f..24c978de2a3f 100644 --- a/drivers/mmc/host/sdhci-xenon.c +++ b/drivers/mmc/host/sdhci-xenon.c @@ -677,6 +677,7 @@ MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); static struct platform_driver sdhci_xenon_driver = { .driver = { .name = "xenon-sdhci", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_xenon_dt_ids, .pm = &sdhci_xenon_dev_pm_ops, }, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 3ad394b40eb1..592a55a34b58 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2825,7 +2825,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) case MMC_TIMING_UHS_SDR50: if (host->flags & SDHCI_SDR50_NEEDS_TUNING) break; - /* FALLTHROUGH */ + fallthrough; default: goto out; diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index f9d24af12396..a64ea143d185 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -2,10 +2,11 @@ /* * sdhci_am654.c - SDHCI driver for TI's AM654 SOCs * - * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com * */ #include <linux/clk.h> +#include <linux/iopoll.h> #include <linux/of.h> #include <linux/module.h> #include <linux/pm_runtime.h> @@ -18,9 +19,11 @@ /* CTL_CFG Registers */ #define CTL_CFG_2 0x14 +#define CTL_CFG_3 0x18 #define SLOTTYPE_MASK GENMASK(31, 30) #define SLOTTYPE_EMBEDDED BIT(30) +#define TUNINGFORSDR50_MASK BIT(13) /* PHY Registers */ #define PHY_CTRL1 0x100 @@ -65,6 +68,14 @@ #define RETRIM_MASK BIT(RETRIM_SHIFT) #define SELDLYTXCLK_SHIFT 17 #define SELDLYTXCLK_MASK BIT(SELDLYTXCLK_SHIFT) +#define SELDLYRXCLK_SHIFT 16 +#define SELDLYRXCLK_MASK BIT(SELDLYRXCLK_SHIFT) +#define ITAPDLYSEL_SHIFT 0 +#define ITAPDLYSEL_MASK GENMASK(4, 0) +#define ITAPDLYENA_SHIFT 8 +#define ITAPDLYENA_MASK BIT(ITAPDLYENA_SHIFT) +#define ITAPCHGWIN_SHIFT 9 +#define ITAPCHGWIN_MASK BIT(ITAPCHGWIN_SHIFT) #define DRIVER_STRENGTH_50_OHM 0x0 #define DRIVER_STRENGTH_33_OHM 0x1 @@ -72,7 +83,7 @@ #define DRIVER_STRENGTH_100_OHM 0x3 #define DRIVER_STRENGTH_40_OHM 0x4 -#define CLOCK_TOO_SLOW_HZ 400000 +#define CLOCK_TOO_SLOW_HZ 50000000 /* Command Queue Host Controller Interface Base address */ #define SDHCI_AM654_CQE_BASE_ADDR 0x200 @@ -84,14 +95,56 @@ static struct regmap_config sdhci_am654_regmap_config = { .fast_io = true, }; +struct timing_data { + const char *otap_binding; + const char *itap_binding; + u32 capability; +}; + +static const struct timing_data td[] = { + [MMC_TIMING_LEGACY] = {"ti,otap-del-sel-legacy", + "ti,itap-del-sel-legacy", + 0}, + [MMC_TIMING_MMC_HS] = {"ti,otap-del-sel-mmc-hs", + "ti,itap-del-sel-mmc-hs", + MMC_CAP_MMC_HIGHSPEED}, + [MMC_TIMING_SD_HS] = {"ti,otap-del-sel-sd-hs", + "ti,itap-del-sel-sd-hs", + MMC_CAP_SD_HIGHSPEED}, + [MMC_TIMING_UHS_SDR12] = {"ti,otap-del-sel-sdr12", + "ti,itap-del-sel-sdr12", + MMC_CAP_UHS_SDR12}, + [MMC_TIMING_UHS_SDR25] = {"ti,otap-del-sel-sdr25", + "ti,itap-del-sel-sdr25", + MMC_CAP_UHS_SDR25}, + [MMC_TIMING_UHS_SDR50] = {"ti,otap-del-sel-sdr50", + NULL, + MMC_CAP_UHS_SDR50}, + [MMC_TIMING_UHS_SDR104] = {"ti,otap-del-sel-sdr104", + NULL, + MMC_CAP_UHS_SDR104}, + [MMC_TIMING_UHS_DDR50] = {"ti,otap-del-sel-ddr50", + NULL, + MMC_CAP_UHS_DDR50}, + [MMC_TIMING_MMC_DDR52] = {"ti,otap-del-sel-ddr52", + "ti,itap-del-sel-ddr52", + MMC_CAP_DDR}, + [MMC_TIMING_MMC_HS200] = {"ti,otap-del-sel-hs200", + NULL, + MMC_CAP2_HS200}, + [MMC_TIMING_MMC_HS400] = {"ti,otap-del-sel-hs400", + NULL, + MMC_CAP2_HS400}, +}; + struct sdhci_am654_data { struct regmap *base; bool legacy_otapdly; - int otap_del_sel[11]; + int otap_del_sel[ARRAY_SIZE(td)]; + int itap_del_sel[ARRAY_SIZE(td)]; int clkbuf_sel; int trm_icp; int drv_strength; - bool dll_on; int strb_sel; u32 flags; }; @@ -106,26 +159,6 @@ struct sdhci_am654_driver_data { #define DLL_CALIB (1 << 4) }; -struct timing_data { - const char *binding; - u32 capability; -}; - -static const struct timing_data td[] = { - [MMC_TIMING_LEGACY] = {"ti,otap-del-sel-legacy", 0}, - [MMC_TIMING_MMC_HS] = {"ti,otap-del-sel-mmc-hs", MMC_CAP_MMC_HIGHSPEED}, - [MMC_TIMING_SD_HS] = {"ti,otap-del-sel-sd-hs", MMC_CAP_SD_HIGHSPEED}, - [MMC_TIMING_UHS_SDR12] = {"ti,otap-del-sel-sdr12", MMC_CAP_UHS_SDR12}, - [MMC_TIMING_UHS_SDR25] = {"ti,otap-del-sel-sdr25", MMC_CAP_UHS_SDR25}, - [MMC_TIMING_UHS_SDR50] = {"ti,otap-del-sel-sdr50", MMC_CAP_UHS_SDR50}, - [MMC_TIMING_UHS_SDR104] = {"ti,otap-del-sel-sdr104", - MMC_CAP_UHS_SDR104}, - [MMC_TIMING_UHS_DDR50] = {"ti,otap-del-sel-ddr50", MMC_CAP_UHS_DDR50}, - [MMC_TIMING_MMC_DDR52] = {"ti,otap-del-sel-ddr52", MMC_CAP_DDR}, - [MMC_TIMING_MMC_HS200] = {"ti,otap-del-sel-hs200", MMC_CAP2_HS200}, - [MMC_TIMING_MMC_HS400] = {"ti,otap-del-sel-hs400", MMC_CAP2_HS400}, -}; - static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -134,6 +167,10 @@ static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock) u32 mask, val; int ret; + /* Disable delay chain mode */ + regmap_update_bits(sdhci_am654->base, PHY_CTRL5, + SELDLYTXCLK_MASK | SELDLYRXCLK_MASK, 0); + if (sdhci_am654->flags & FREQSEL_2_BIT) { switch (clock) { case 200000000: @@ -188,8 +225,32 @@ static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock) dev_err(mmc_dev(host->mmc), "DLL failed to relock\n"); return; } +} + +static void sdhci_am654_write_itapdly(struct sdhci_am654_data *sdhci_am654, + u32 itapdly) +{ + /* Set ITAPCHGWIN before writing to ITAPDLY */ + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, + 1 << ITAPCHGWIN_SHIFT); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYSEL_MASK, + itapdly << ITAPDLYSEL_SHIFT); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); +} + +static void sdhci_am654_setup_delay_chain(struct sdhci_am654_data *sdhci_am654, + unsigned char timing) +{ + u32 mask, val; + + regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0); + + val = 1 << SELDLYTXCLK_SHIFT | 1 << SELDLYRXCLK_SHIFT; + mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK; + regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask, val); - sdhci_am654->dll_on = true; + sdhci_am654_write_itapdly(sdhci_am654, + sdhci_am654->itap_del_sel[timing]); } static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) @@ -201,11 +262,7 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) u32 otap_del_ena; u32 mask, val; - if (sdhci_am654->dll_on) { - regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0); - - sdhci_am654->dll_on = false; - } + regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0); sdhci_set_clock(host, clock); @@ -233,14 +290,10 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); - if (timing > MMC_TIMING_UHS_SDR25 && clock > CLOCK_TOO_SLOW_HZ) { - regmap_update_bits(sdhci_am654->base, PHY_CTRL5, - SELDLYTXCLK_MASK, 0); + if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) sdhci_am654_setup_dll(host, clock); - } else { - regmap_update_bits(sdhci_am654->base, PHY_CTRL5, - SELDLYTXCLK_MASK, 1 << SELDLYTXCLK_SHIFT); - } + else + sdhci_am654_setup_delay_chain(sdhci_am654, timing); regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, sdhci_am654->clkbuf_sel); @@ -272,9 +325,19 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, sdhci_set_clock(host, clock); } +static u8 sdhci_am654_write_power_on(struct sdhci_host *host, u8 val, int reg) +{ + writeb(val, host->ioaddr + reg); + usleep_range(1000, 10000); + return readb(host->ioaddr + reg); +} + +#define MAX_POWER_ON_TIMEOUT 1500000 /* us */ static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg) { unsigned char timing = host->mmc->ios.timing; + u8 pwr; + int ret; if (reg == SDHCI_HOST_CONTROL) { switch (timing) { @@ -291,6 +354,19 @@ static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg) } writeb(val, host->ioaddr + reg); + if (reg == SDHCI_POWER_CONTROL && (val & SDHCI_POWER_ON)) { + /* + * Power on will not happen until the card detect debounce + * timer expires. Wait at least 1.5 seconds for the power on + * bit to be set + */ + ret = read_poll_timeout(sdhci_am654_write_power_on, pwr, + pwr & SDHCI_POWER_ON, 0, + MAX_POWER_ON_TIMEOUT, false, host, val, + reg); + if (ret) + dev_warn(mmc_dev(host->mmc), "Power on failed\n"); + } } static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode) @@ -322,7 +398,46 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask) return 0; } +#define ITAP_MAX 32 +static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, + u32 opcode) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); + int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len; + u32 itap; + + /* Enable ITAPDLY */ + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK, + 1 << ITAPDLYENA_SHIFT); + + for (itap = 0; itap < ITAP_MAX; itap++) { + sdhci_am654_write_itapdly(sdhci_am654, itap); + + cur_val = !mmc_send_tuning(host->mmc, opcode, NULL); + if (cur_val && !prev_val) + pass_window = itap; + + if (!cur_val) + fail_len++; + + prev_val = cur_val; + } + /* + * Having determined the length of the failing window and start of + * the passing window calculate the length of the passing window and + * set the final value halfway through it considering the range as a + * circular buffer + */ + pass_len = ITAP_MAX - fail_len; + itap = (pass_window + (pass_len >> 1)) % ITAP_MAX; + sdhci_am654_write_itapdly(sdhci_am654, itap); + + return 0; +} + static struct sdhci_ops sdhci_am654_ops = { + .platform_execute_tuning = sdhci_am654_platform_execute_tuning, .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, @@ -352,6 +467,7 @@ static const struct sdhci_am654_driver_data sdhci_am654_drvdata = { }; static struct sdhci_ops sdhci_j721e_8bit_ops = { + .platform_execute_tuning = sdhci_am654_platform_execute_tuning, .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, @@ -375,6 +491,7 @@ static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = { }; static struct sdhci_ops sdhci_j721e_4bit_ops = { + .platform_execute_tuning = sdhci_am654_platform_execute_tuning, .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, @@ -445,7 +562,7 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host, int i; int ret; - ret = device_property_read_u32(dev, td[MMC_TIMING_LEGACY].binding, + ret = device_property_read_u32(dev, td[MMC_TIMING_LEGACY].otap_binding, &sdhci_am654->otap_del_sel[MMC_TIMING_LEGACY]); if (ret) { /* @@ -468,11 +585,11 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host, for (i = MMC_TIMING_MMC_HS; i <= MMC_TIMING_MMC_HS400; i++) { - ret = device_property_read_u32(dev, td[i].binding, + ret = device_property_read_u32(dev, td[i].otap_binding, &sdhci_am654->otap_del_sel[i]); if (ret) { dev_dbg(dev, "Couldn't find %s\n", - td[i].binding); + td[i].otap_binding); /* * Remove the corresponding capability * if an otap-del-sel value is not found @@ -482,6 +599,10 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host, else host->mmc->caps2 &= ~td[i].capability; } + + if (td[i].itap_binding) + device_property_read_u32(dev, td[i].itap_binding, + &sdhci_am654->itap_del_sel[i]); } return 0; @@ -527,6 +648,10 @@ static int sdhci_am654_init(struct sdhci_host *host) regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2); + /* Enable tuning for SDR50 */ + regmap_update_bits(sdhci_am654->base, CTL_CFG_3, TUNINGFORSDR50_MASK, + TUNINGFORSDR50_MASK); + ret = sdhci_setup_host(host); if (ret) return ret; @@ -614,6 +739,7 @@ static const struct of_device_id sdhci_am654_of_match[] = { }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, sdhci_am654_of_match); static int sdhci_am654_probe(struct platform_device *pdev) { @@ -721,6 +847,7 @@ static int sdhci_am654_remove(struct platform_device *pdev) static struct platform_driver sdhci_am654_driver = { .driver = { .name = "sdhci-am654", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_am654_of_match, }, .probe = sdhci_am654_probe, diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index 4625cc071b61..3f5977979cf2 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -219,6 +219,7 @@ MODULE_DEVICE_TABLE(acpi, f_sdh30_acpi_ids); static struct platform_driver sdhci_f_sdh30_driver = { .driver = { .name = "f_sdh30", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(f_sdh30_dt_ids), .acpi_match_table = ACPI_PTR(f_sdh30_acpi_ids), .pm = &sdhci_pltfm_pmops, diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 9f53634aa411..e5e457037235 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1562,6 +1562,7 @@ static struct platform_driver sh_mmcif_driver = { .remove = sh_mmcif_remove, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &sh_mmcif_dev_pm_ops, .of_match_table = sh_mmcif_of_match, }, diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 5e95bbc51644..fc62773602ec 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -1514,6 +1514,7 @@ static const struct dev_pm_ops sunxi_mmc_pm_ops = { static struct platform_driver sunxi_mmc_driver = { .driver = { .name = "sunxi-mmc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(sunxi_mmc_of_match), .pm = &sunxi_mmc_pm_ops, }, diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 5987656e0474..fd8b72d3e02c 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -335,7 +335,7 @@ static unsigned int tifm_sd_op_flags(struct mmc_command *cmd) break; case MMC_RSP_R1B: rc |= TIFM_MMCSD_RSP_BUSY; - /* fall-through */ + fallthrough; case MMC_RSP_R1: rc |= TIFM_MMCSD_RSP_R1; break; diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 93e83ad25976..d2d3b8df1bbe 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -77,18 +77,10 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, static void tmio_mmc_reset(struct tmio_mmc_host *host) { - /* FIXME - should we set stop clock reg here */ - sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); usleep_range(10000, 11000); - sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); usleep_range(10000, 11000); - - if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) { - sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); - sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); - } } #ifdef CONFIG_PM_SLEEP @@ -221,6 +213,7 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { static struct platform_driver tmio_mmc_driver = { .driver = { .name = "tmio-mmc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &tmio_mmc_dev_pm_ops, }, .probe = tmio_mmc_probe, diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 0a4f36500add..9546e542619c 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -178,14 +178,8 @@ struct tmio_mmc_host { unsigned int direction, int blk_size); int (*write16_hook)(struct tmio_mmc_host *host, int addr); void (*reset)(struct tmio_mmc_host *host); - void (*hw_reset)(struct tmio_mmc_host *host); bool (*check_retune)(struct tmio_mmc_host *host); - - /* - * Mandatory callback for tuning to occur which is optional for SDR50 - * and mandatory for SDR104. - */ - int (*execute_tuning)(struct tmio_mmc_host *host, u32 opcode); + void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq); void (*prepare_hs400_tuning)(struct tmio_mmc_host *host); void (*hs400_downgrade)(struct tmio_mmc_host *host); diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 946fb013c610..2fce0518632d 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -172,24 +172,15 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host) sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); usleep_range(10000, 11000); + if (host->reset) + host->reset(host); + if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) { sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); } } -static void tmio_mmc_hw_reset(struct mmc_host *mmc) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - - host->reset(host); - - tmio_mmc_abort_dma(host); - - if (host->hw_reset) - host->hw_reset(host); -} - static void tmio_mmc_reset_work(struct work_struct *work) { struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, @@ -228,11 +219,12 @@ static void tmio_mmc_reset_work(struct work_struct *work) spin_unlock_irqrestore(&host->lock, flags); - tmio_mmc_hw_reset(host->mmc); + tmio_mmc_reset(host); /* Ready for new calls */ host->mrq = NULL; + tmio_mmc_abort_dma(host); mmc_request_done(host->mmc, mrq); } @@ -720,24 +712,6 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host, return 0; } -static int tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - int ret; - - if (!host->execute_tuning) - return 0; - - ret = host->execute_tuning(host, opcode); - - if (ret < 0) { - dev_warn(&host->pdev->dev, "Tuning procedure failed\n"); - tmio_mmc_hw_reset(mmc); - } - - return ret; -} - static void tmio_process_mrq(struct tmio_mmc_host *host, struct mmc_request *mrq) { @@ -835,6 +809,9 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host) return; } + if (host->fixup_request) + host->fixup_request(host, mrq); + mmc_request_done(host->mmc, mrq); } @@ -1011,8 +988,6 @@ static struct mmc_host_ops tmio_mmc_ops = { .get_cd = tmio_mmc_get_cd, .enable_sdio_irq = tmio_mmc_enable_sdio_irq, .multi_io_quirk = tmio_multi_io_quirk, - .hw_reset = tmio_mmc_hw_reset, - .execute_tuning = tmio_mmc_execute_tuning, }; static int tmio_mmc_init_ocr(struct tmio_mmc_host *host) @@ -1156,9 +1131,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) mmc->caps & MMC_CAP_NEEDS_POLL || !mmc_card_is_removable(mmc)); - if (!_host->reset) - _host->reset = tmio_mmc_reset; - /* * On Gen2+, eMMC with NONREMOVABLE currently fails because native * hotplug gets disabled. It seems RuntimePM related yet we need further @@ -1180,7 +1152,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) _host->sdio_irq_mask = TMIO_SDIO_MASK_ALL; _host->set_clock(_host, 0); - tmio_mmc_hw_reset(mmc); + tmio_mmc_reset(_host); _host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK); tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); @@ -1283,7 +1255,7 @@ int tmio_mmc_host_runtime_resume(struct device *dev) struct tmio_mmc_host *host = dev_get_drvdata(dev); tmio_mmc_clk_enable(host); - tmio_mmc_hw_reset(host->mmc); + tmio_mmc_reset(host); if (host->clk_cache) host->set_clock(host, host->clk_cache); diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c index f82baf99fd69..3092466a99ab 100644 --- a/drivers/mmc/host/uniphier-sd.c +++ b/drivers/mmc/host/uniphier-sd.c @@ -409,8 +409,9 @@ static void uniphier_sd_clk_disable(struct tmio_mmc_host *host) clk_disable_unprepare(priv->clk); } -static void uniphier_sd_hw_reset(struct tmio_mmc_host *host) +static void uniphier_sd_hw_reset(struct mmc_host *mmc) { + struct tmio_mmc_host *host = mmc_priv(mmc); struct uniphier_sd_priv *priv = uniphier_sd_priv(host); reset_control_assert(priv->rst_hw); @@ -597,7 +598,7 @@ static int uniphier_sd_probe(struct platform_device *pdev) ret = PTR_ERR(priv->rst_hw); goto free_host; } - host->hw_reset = uniphier_sd_hw_reset; + host->ops.hw_reset = uniphier_sd_hw_reset; } if (host->mmc->caps & MMC_CAP_UHS) { @@ -684,6 +685,7 @@ static struct platform_driver uniphier_sd_driver = { .remove = uniphier_sd_remove, .driver = { .name = "uniphier-sd", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = uniphier_sd_match, }, }; diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 369b8dee2e3d..e2d5112d809d 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1343,7 +1343,7 @@ static int usdhi6_stop_cmd(struct usdhi6_host *host) host->wait = USDHI6_WAIT_FOR_STOP; return 0; } - /* fall through - Unsupported STOP command. */ + fallthrough; /* Unsupported STOP command */ default: dev_err(mmc_dev(host->mmc), "unsupported stop CMD%d for CMD%d\n", @@ -1691,7 +1691,7 @@ static void usdhi6_timeout_work(struct work_struct *work) switch (host->wait) { default: dev_err(mmc_dev(host->mmc), "Invalid state %u\n", host->wait); - /* fall through - mrq can be NULL, but is impossible. */ + fallthrough; /* mrq can be NULL, but is impossible */ case USDHI6_WAIT_FOR_CMD: usdhi6_error_code(host); if (mrq) @@ -1713,7 +1713,7 @@ static void usdhi6_timeout_work(struct work_struct *work) host->offset, data->blocks, data->blksz, data->sg_len, sg_dma_len(sg), sg->offset); usdhi6_sg_unmap(host, true); - /* fall through - page unmapped in USDHI6_WAIT_FOR_DATA_END. */ + fallthrough; /* page unmapped in USDHI6_WAIT_FOR_DATA_END */ case USDHI6_WAIT_FOR_DATA_END: usdhi6_error_code(host); data->error = -ETIMEDOUT; @@ -1890,6 +1890,7 @@ static struct platform_driver usdhi6_driver = { .remove = usdhi6_remove, .driver = { .name = "usdhi6rol0", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = usdhi6_of_match, }, }; diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 49dab9f42b6d..9b755ea0fa03 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -1257,11 +1257,14 @@ static void __maybe_unused via_init_sdc_pm(struct via_crdr_mmc_host *host) static int __maybe_unused via_sd_suspend(struct device *dev) { struct via_crdr_mmc_host *host; + unsigned long flags; host = dev_get_drvdata(dev); + spin_lock_irqsave(&host->lock, flags); via_save_pcictrlreg(host); via_save_sdcreg(host); + spin_unlock_irqrestore(&host->lock, flags); device_wakeup_enable(dev); diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 67f917d6ecd3..cd63ea865b77 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1905,6 +1905,7 @@ static struct platform_driver wbsd_driver = { .resume = wbsd_platform_resume, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 2c4ba1fa4bbf..cf10949fb0ac 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -990,6 +990,7 @@ static struct platform_driver wmt_mci_driver = { .remove = wmt_mci_remove, .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = wmt_mci_pm_ops, .of_match_table = wmt_mci_dt_ids, }, |