diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-04-26 03:29:46 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-04-26 03:29:46 +0300 |
commit | c5c06e278019892391ef4d47933796cacfec29cb (patch) | |
tree | 33291b9db7249779ec6cc3976654f47d568e4231 | |
parent | eb8322d714ea98fdc620d682fb517b50ea282aa5 (diff) | |
parent | 22a4455e75be443fb80784175bb70f40ba6d0c52 (diff) | |
download | linux-c5c06e278019892391ef4d47933796cacfec29cb.tar.xz |
Merge tag 'mmc-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Allow an invalid regulator in mmc_regulator_set_ocr()
- Log about empty non-removable slots
- Add helpers to enable/disable the vqmmc regulator
MMC host:
- mtk-sd: Add support for the mt8365 variant
- renesas_sdhi: Remove support for R-Car H3 ES1.* variants
- sdhci_am654: Add power management support
- sdhci-cadence: Add support for eMMC hardware reset
- sdhci-cadence: Add support for AMD Pensando Elba variant
- sdhci-msm: Add support for the IPQ5018 variant
- sdhci-msm: Add support for the QCM2290 variant
- sdhci-of-arasan: Skip setting clock delay for 400KHz
- sdhci-of-arasan: Add support for the Xilinx Versal Net variant
- sdhci-of-arasan: Remove Intel Thunder Bay SOC support
- sdhci-of-arasan: Add support to request the "gate" clock
- sdhci-of-dwcmshc: Properly determine max clock on Rockchip
- sdhci-of-esdhc: Fix quirk to ignore command inhibit for data
- sdhci-pci-o2micro: Fix SDR50 mode timing issue
MEMSTICK:
- r592: Fix use-after-free bug in r592_remove due to race condition"
* tag 'mmc-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (40 commits)
dt-bindings: mmc: sdhci-msm: Document the IPQ5018 compatible
mmc: vub300: remove unreachable code
mmc: sdhci-cadence: Support mmc hardware reset
mmc: sdhci-cadence: Add AMD Pensando Elba SoC support
mmc: sdhci-cadence: Support device specific init during probe
mmc: sdhci-cadence: Enable device specific override of writel()
dt-bindings: mmc: cdns: Add AMD Pensando Elba SoC
mmc: core: Remove unused macro mmc_req_rel_wr
mmc: sdhci-of-arasan: Skip setting clock delay for 400KHz
mmc: sdhci-of-arasan: Add support for eMMC5.1 on Xilinx Versal Net platform
dt-bindings: mmc: arasan,sdci: Add Xilinx Versal Net compatible
mmc: sdhci_am654: Add support for PM suspend/resume
mmc: core: remove unnecessary (void*) conversions
dt-bindings: mmc: fsl-imx-esdhc: ref sdhci-common.yaml
mmc: sdhci-of-esdhc: fix quirk to ignore command inhibit for data
mmc: core: Log about empty non-removable slots
dt-bindings: mmc: fujitsu: Add Socionext Synquacer
mmc: sdricoh_cs: remove unused sdricoh_readw function
dt-bindings: mmc: Remove bindings for Intel Thunder Bay SoC"
mmc: sdhci-of-arasan: Remove Intel Thunder Bay SOC support
...
38 files changed, 711 insertions, 205 deletions
diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml index 8296c34cfa00..a6c19a6cc99e 100644 --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml @@ -27,6 +27,7 @@ allOf: enum: - xlnx,zynqmp-8.9a - xlnx,versal-8.9a + - xlnx,versal-net-emmc then: properties: clock-output-names: @@ -62,6 +63,10 @@ properties: description: For this device it is strongly suggested to include clock-output-names and '#clock-cells'. + - const: xlnx,versal-net-emmc # Versal Net eMMC PHY + description: + For this device it is strongly suggested to include + clock-output-names and '#clock-cells'. - items: - const: intel,lgm-sdhci-5.1-emmc # Intel LGM eMMC PHY - const: arasan,sdhci-5.1 @@ -88,12 +93,6 @@ properties: description: For this device it is strongly suggested to include arasan,soc-ctl-syscon. - - items: - - const: intel,thunderbay-sdhci-5.1 # Intel Thunder Bay eMMC PHY - - const: arasan,sdhci-5.1 - description: - For this device it is strongly suggested to include - clock-output-names and '#clock-cells'. reg: maxItems: 1 @@ -309,22 +308,3 @@ examples: <&scmi_clk KEEM_BAY_PSS_SD0>; arasan,soc-ctl-syscon = <&sd0_phy_syscon>; }; - - - | - #define EMMC_XIN_CLK - #define EMMC_AXI_CLK - #define TBH_PSS_EMMC_RST_N - mmc@80420000 { - compatible = "intel,thunderbay-sdhci-5.1", "arasan,sdhci-5.1"; - interrupts = <GIC_SPI 714 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x80420000 0x400>; - clocks = <&scmi_clk EMMC_XIN_CLK>, - <&scmi_clk EMMC_AXI_CLK>; - clock-names = "clk_xin", "clk_ahb"; - phys = <&emmc_phy>; - phy-names = "phy_arasan"; - assigned-clocks = <&scmi_clk EMMC_XIN_CLK>; - clock-output-names = "emmc_cardclock"; - resets = <&rst_pss1 TBH_PSS_EMMC_RST_N>; - #clock-cells = <0x0>; - }; diff --git a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml index adacd0535c14..6c40611405a0 100644 --- a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml @@ -9,19 +9,18 @@ title: Cadence SD/SDIO/eMMC Host Controller (SD4HC) maintainers: - Masahiro Yamada <yamada.masahiro@socionext.com> -allOf: - - $ref: mmc-controller.yaml - properties: compatible: items: - enum: + - amd,pensando-elba-sd4hc - microchip,mpfs-sd4hc - socionext,uniphier-sd4hc - const: cdns,sd4hc reg: - maxItems: 1 + minItems: 1 + maxItems: 2 interrupts: maxItems: 1 @@ -120,6 +119,26 @@ required: - interrupts - clocks +allOf: + - $ref: mmc-controller.yaml + - if: + properties: + compatible: + contains: + const: amd,pensando-elba-sd4hc + then: + properties: + reg: + items: + - description: Host controller registers + - description: Elba byte-lane enable register for writes + required: + - resets + else: + properties: + reg: + maxItems: 1 + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml index 7f721fbfb009..fbfd822b9270 100644 --- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml @@ -10,7 +10,7 @@ maintainers: - Shawn Guo <shawnguo@kernel.org> allOf: - - $ref: mmc-controller.yaml + - $ref: sdhci-common.yaml# description: | The Enhanced Secure Digital Host Controller on Freescale i.MX family diff --git a/Documentation/devicetree/bindings/mmc/fujitsu,sdhci-fujitsu.yaml b/Documentation/devicetree/bindings/mmc/fujitsu,sdhci-fujitsu.yaml index 73d747e917f3..430b62899397 100644 --- a/Documentation/devicetree/bindings/mmc/fujitsu,sdhci-fujitsu.yaml +++ b/Documentation/devicetree/bindings/mmc/fujitsu,sdhci-fujitsu.yaml @@ -14,9 +14,13 @@ allOf: properties: compatible: - enum: - - fujitsu,mb86s70-sdhci-3.0 - - socionext,f-sdh30-e51-mmc + oneOf: + - items: + - const: socionext,synquacer-sdhci + - const: fujitsu,mb86s70-sdhci-3.0 + - enum: + - fujitsu,mb86s70-sdhci-3.0 + - socionext,f-sdh30-e51-mmc reg: maxItems: 1 @@ -29,6 +33,11 @@ properties: - const: iface - const: core + dma-coherent: true + + interrupts: + maxItems: 2 + resets: maxItems: 1 diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml index 7a649ebc688c..46eefdd19a2c 100644 --- a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml +++ b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml @@ -34,6 +34,7 @@ properties: - mediatek,mt8188-mmc - mediatek,mt8192-mmc - mediatek,mt8195-mmc + - mediatek,mt8365-mmc - const: mediatek,mt8183-mmc reg: diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml index 64df6919abaf..4f2d9e8127dd 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml @@ -34,8 +34,10 @@ properties: - const: qcom,sdhci-msm-v4 # for sdcc versions less than 5.0 - items: - enum: + - qcom,ipq5018-sdhci - qcom,ipq5332-sdhci - qcom,ipq9574-sdhci + - qcom,qcm2290-sdhci - qcom,qcs404-sdhci - qcom,sc7180-sdhci - qcom,sc7280-sdhci diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 1d35d147552d..42bfc46842b8 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c @@ -829,7 +829,7 @@ static void r592_remove(struct pci_dev *pdev) /* Stop the processing thread. That ensures that we won't take any more requests */ kthread_stop(dev->io_thread); - + del_timer_sync(&dev->detect_timer); r592_enable_device(dev, false); while (!error && dev->req) { diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 672ab90c4b2d..00c33edb9fb9 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -76,8 +76,6 @@ MODULE_ALIAS("mmc:block"); #define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16) #define MMC_EXTRACT_VALUE_FROM_ARG(x) ((x & 0x0000FF00) >> 8) -#define mmc_req_rel_wr(req) ((req->cmd_flags & REQ_FUA) && \ - (rq_data_dir(req) == WRITE)) static DEFINE_MUTEX(block_mutex); /* diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 426c7f66b349..3d3e0ca52614 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2257,6 +2257,11 @@ void mmc_rescan(struct work_struct *work) break; } + /* A non-removable card should have been detected by now. */ + if (!mmc_card_is_removable(host) && !host->bus_ops) + pr_info("%s: Failed to initialize a non-removable card", + mmc_hostname(host)); + /* * Ignore the command timeout errors observed during * the card init as those are excepted. diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index fe6808771bc7..2c97b94aab23 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -246,7 +246,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(mmc_err_state, mmc_err_state_get, NULL, "%llu\n"); static int mmc_err_stats_show(struct seq_file *file, void *data) { - struct mmc_host *host = (struct mmc_host *)file->private; + struct mmc_host *host = file->private; const char *desc[MMC_ERR_MAX] = { [MMC_ERR_CMD_TIMEOUT] = "Command Timeout Occurred", [MMC_ERR_CMD_CRC] = "Command CRC Errors Occurred", diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 156d34b2ed4d..0f6a563103fd 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -3045,7 +3045,7 @@ static LIST_HEAD(mmc_test_file_test); static int mtf_test_show(struct seq_file *sf, void *data) { - struct mmc_card *card = (struct mmc_card *)sf->private; + struct mmc_card *card = sf->private; struct mmc_test_general_result *gr; mutex_lock(&mmc_test_lock); @@ -3079,8 +3079,8 @@ static int mtf_test_open(struct inode *inode, struct file *file) static ssize_t mtf_test_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { - struct seq_file *sf = (struct seq_file *)file->private_data; - struct mmc_card *card = (struct mmc_card *)sf->private; + struct seq_file *sf = file->private_data; + struct mmc_card *card = sf->private; struct mmc_test_card *test; long testcase; int ret; diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c index 609201a467ef..005247a49e51 100644 --- a/drivers/mmc/core/regulator.c +++ b/drivers/mmc/core/regulator.c @@ -110,6 +110,9 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, int result = 0; int min_uV, max_uV; + if (IS_ERR(supply)) + return 0; + if (vdd_bit) { mmc_ocrbitnum_to_vdd(vdd_bit, &min_uV, &max_uV); @@ -271,3 +274,44 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) return 0; } EXPORT_SYMBOL_GPL(mmc_regulator_get_supply); + +/** + * mmc_regulator_enable_vqmmc - enable VQMMC regulator for a host + * @mmc: the host to regulate + * + * Returns 0 or errno. Enables the regulator for vqmmc. + * Keeps track of the enable status for ensuring that calls to + * regulator_enable/disable are balanced. + */ +int mmc_regulator_enable_vqmmc(struct mmc_host *mmc) +{ + int ret = 0; + + if (!IS_ERR(mmc->supply.vqmmc) && !mmc->vqmmc_enabled) { + ret = regulator_enable(mmc->supply.vqmmc); + if (ret < 0) + dev_err(mmc_dev(mmc), "enabling vqmmc regulator failed\n"); + else + mmc->vqmmc_enabled = true; + } + + return ret; +} +EXPORT_SYMBOL_GPL(mmc_regulator_enable_vqmmc); + +/** + * mmc_regulator_disable_vqmmc - disable VQMMC regulator for a host + * @mmc: the host to regulate + * + * Returns 0 or errno. Disables the regulator for vqmmc. + * Keeps track of the enable status for ensuring that calls to + * regulator_enable/disable are balanced. + */ +void mmc_regulator_disable_vqmmc(struct mmc_host *mmc) +{ + if (!IS_ERR(mmc->supply.vqmmc) && mmc->vqmmc_enabled) { + regulator_disable(mmc->supply.vqmmc); + mmc->vqmmc_enabled = false; + } +} +EXPORT_SYMBOL_GPL(mmc_regulator_disable_vqmmc); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 4745fe217ade..9f793892123c 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -255,6 +255,7 @@ config MMC_SDHCI_CADENCE tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller" depends on MMC_SDHCI_PLTFM depends on OF + select MMC_SDHCI_IO_ACCESSORS help This selects the Cadence SD/SDIO/eMMC driver. diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 13e55cff8237..48b7da2b86b3 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -46,8 +46,7 @@ int dw_mci_pltfm_register(struct platform_device *pdev, host->irq_flags = 0; host->pdata = pdev->dev.platform_data; - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->regs = devm_ioremap_resource(&pdev->dev, regs); + host->regs = devm_platform_get_and_ioremap_resource(pdev, 0, ®s); if (IS_ERR(host->regs)) return PTR_ERR(host->regs); diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 698450afa7bb..1846a05210e3 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -1079,8 +1079,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev) goto err_free_host; } - host->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->base = devm_ioremap_resource(&pdev->dev, host->mem_res); + host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &host->mem_res); if (IS_ERR(host->base)) { ret = PTR_ERR(host->base); goto err_free_host; diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 2b963a81c2ad..b8514d9d5e73 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -174,7 +174,6 @@ struct meson_host { int irq; - bool vqmmc_enabled; bool needs_pre_post_req; spinlock_t lock; @@ -604,32 +603,18 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) */ switch (ios->power_mode) { case MMC_POWER_OFF: - if (!IS_ERR(mmc->supply.vmmc)) - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); - - if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) { - regulator_disable(mmc->supply.vqmmc); - host->vqmmc_enabled = false; - } + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + mmc_regulator_disable_vqmmc(mmc); break; case MMC_POWER_UP: - if (!IS_ERR(mmc->supply.vmmc)) - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); break; case MMC_POWER_ON: - if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) { - int ret = regulator_enable(mmc->supply.vqmmc); - - if (ret < 0) - dev_err(host->dev, - "failed to enable vqmmc regulator\n"); - else - host->vqmmc_enabled = true; - } + mmc_regulator_enable_vqmmc(mmc); break; } @@ -1181,7 +1166,6 @@ static int meson_mmc_probe(struct platform_device *pdev) "amlogic,dram-access-quirk"); /* Get regulators and the supported OCR mask */ - host->vqmmc_enabled = false; ret = mmc_regulator_get_supply(mmc); if (ret) return ret; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index b9e5dfe74e5c..f2b2e8b0574e 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1962,28 +1962,28 @@ static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) if (ret) return ret; - if (of_get_property(np, "st,sig-dir-dat0", NULL)) + if (of_property_read_bool(np, "st,sig-dir-dat0")) host->pwr_reg_add |= MCI_ST_DATA0DIREN; - if (of_get_property(np, "st,sig-dir-dat2", NULL)) + if (of_property_read_bool(np, "st,sig-dir-dat2")) host->pwr_reg_add |= MCI_ST_DATA2DIREN; - if (of_get_property(np, "st,sig-dir-dat31", NULL)) + if (of_property_read_bool(np, "st,sig-dir-dat31")) host->pwr_reg_add |= MCI_ST_DATA31DIREN; - if (of_get_property(np, "st,sig-dir-dat74", NULL)) + if (of_property_read_bool(np, "st,sig-dir-dat74")) host->pwr_reg_add |= MCI_ST_DATA74DIREN; - if (of_get_property(np, "st,sig-dir-cmd", NULL)) + if (of_property_read_bool(np, "st,sig-dir-cmd")) host->pwr_reg_add |= MCI_ST_CMDDIREN; - if (of_get_property(np, "st,sig-pin-fbclk", NULL)) + if (of_property_read_bool(np, "st,sig-pin-fbclk")) host->pwr_reg_add |= MCI_ST_FBCLKEN; - if (of_get_property(np, "st,sig-dir", NULL)) + if (of_property_read_bool(np, "st,sig-dir")) host->pwr_reg_add |= MCI_STM32_DIRPOL; - if (of_get_property(np, "st,neg-edge", NULL)) + if (of_property_read_bool(np, "st,neg-edge")) host->clk_reg_add |= MCI_STM32_CLK_NEGEDGE; - if (of_get_property(np, "st,use-ckin", NULL)) + if (of_property_read_bool(np, "st,use-ckin")) mmci_probe_level_translator(mmc); - if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) + if (of_property_read_bool(np, "mmc-cap-mmc-highspeed")) mmc->caps |= MMC_CAP_MMC_HIGHSPEED; - if (of_get_property(np, "mmc-cap-sd-highspeed", NULL)) + if (of_property_read_bool(np, "mmc-cap-sd-highspeed")) mmc->caps |= MMC_CAP_SD_HIGHSPEED; return 0; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 57d39283924d..ce78edfb402b 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1345,8 +1345,7 @@ static int mmc_omap_probe(struct platform_device *pdev) if (irq < 0) return -ENXIO; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->virt_base = devm_ioremap_resource(&pdev->dev, res); + host->virt_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(host->virt_base)) return PTR_ERR(host->virt_base); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 4bd744755205..517dde777413 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1736,18 +1736,18 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) if (legacy && legacy->name) pdata->name = legacy->name; - if (of_find_property(np, "ti,dual-volt", NULL)) + if (of_property_read_bool(np, "ti,dual-volt")) pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT; - if (of_find_property(np, "ti,non-removable", NULL)) { + if (of_property_read_bool(np, "ti,non-removable")) { pdata->nonremovable = true; pdata->no_regulator_off_init = true; } - if (of_find_property(np, "ti,needs-special-reset", NULL)) + if (of_property_read_bool(np, "ti,needs-special-reset")) pdata->features |= HSMMC_HAS_UPDATED_RESET; - if (of_find_property(np, "ti,needs-special-hs-handling", NULL)) + if (of_property_read_bool(np, "ti,needs-special-hs-handling")) pdata->features |= HSMMC_HAS_HSPE_SUPPORT; return pdata; diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c index 3dc143b03939..6f9d31a886ba 100644 --- a/drivers/mmc/host/owl-mmc.c +++ b/drivers/mmc/host/owl-mmc.c @@ -578,8 +578,7 @@ static int owl_mmc_probe(struct platform_device *pdev) owl_host->mmc = mmc; spin_lock_init(&owl_host->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - owl_host->base = devm_ioremap_resource(&pdev->dev, res); + owl_host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(owl_host->base)) { ret = PTR_ERR(owl_host->base); goto err_free_host; diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index f38003f6b1ca..9ab813903b2c 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -72,11 +72,10 @@ enum renesas_sdhi_dma_cookie { static unsigned long global_flags; /* - * Workaround for avoiding to use RX DMAC by multiple channels. - * On R-Car H3 ES1.* and M3-W ES1.0, when multiple SDHI channels use - * RX DMAC simultaneously, sometimes hundreds of bytes data are not - * stored into the system memory even if the DMAC interrupt happened. - * So, this driver then uses one RX DMAC channel only. + * Workaround for avoiding to use RX DMAC by multiple channels. On R-Car M3-W + * ES1.0, when multiple SDHI channels use RX DMAC simultaneously, sometimes + * hundreds of data bytes are not stored into the system memory even if the + * DMAC interrupt happened. So, this driver then uses one RX DMAC channel only. */ #define SDHI_INTERNAL_DMAC_RX_IN_USE 0 @@ -222,7 +221,6 @@ static const struct renesas_sdhi_quirks sdhi_quirks_r9a09g011 = { */ static const struct soc_device_attribute sdhi_quirks_match[] = { { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, - { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_4tap_nohs400_one_rx }, { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap }, { .soc_id = "r8a7796", .revision = "ES1.0", .data = &sdhi_quirks_4tap_nohs400_one_rx }, { .soc_id = "r8a7796", .revision = "ES1.[12]", .data = &sdhi_quirks_4tap_nohs400 }, diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index 6f2de54a5987..b24aa27da50c 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -12,6 +12,7 @@ #include <linux/mmc/mmc.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/reset.h> #include "sdhci-pltfm.h" @@ -66,7 +67,11 @@ struct sdhci_cdns_phy_param { struct sdhci_cdns_priv { void __iomem *hrs_addr; + void __iomem *ctl_addr; /* write control */ + spinlock_t wrlock; /* write lock */ bool enhanced_strobe; + void (*priv_writel)(struct sdhci_cdns_priv *priv, u32 val, void __iomem *reg); + struct reset_control *rst_hw; unsigned int nr_phy_params; struct sdhci_cdns_phy_param phy_params[]; }; @@ -76,6 +81,11 @@ struct sdhci_cdns_phy_cfg { u8 addr; }; +struct sdhci_cdns_drv_data { + int (*init)(struct platform_device *pdev); + const struct sdhci_pltfm_data pltfm_data; +}; + static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = { { "cdns,phy-input-delay-sd-highspeed", SDHCI_CDNS_PHY_DLY_SD_HS, }, { "cdns,phy-input-delay-legacy", SDHCI_CDNS_PHY_DLY_SD_DEFAULT, }, @@ -90,6 +100,12 @@ static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = { { "cdns,phy-dll-delay-strobe", SDHCI_CDNS_PHY_DLY_STROBE, }, }; +static inline void cdns_writel(struct sdhci_cdns_priv *priv, u32 val, + void __iomem *reg) +{ + writel(val, reg); +} + static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv, u8 addr, u8 data) { @@ -104,17 +120,17 @@ static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv, tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) | FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr); - writel(tmp, reg); + priv->priv_writel(priv, tmp, reg); tmp |= SDHCI_CDNS_HRS04_WR; - writel(tmp, reg); + priv->priv_writel(priv, tmp, reg); ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 0, 10); if (ret) return ret; tmp &= ~SDHCI_CDNS_HRS04_WR; - writel(tmp, reg); + priv->priv_writel(priv, tmp, reg); ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK), 0, 10); @@ -191,7 +207,7 @@ static void sdhci_cdns_set_emmc_mode(struct sdhci_cdns_priv *priv, u32 mode) tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06); tmp &= ~SDHCI_CDNS_HRS06_MODE; tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode); - writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS06); + priv->priv_writel(priv, tmp, priv->hrs_addr + SDHCI_CDNS_HRS06); } static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv) @@ -223,7 +239,7 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val) */ for (i = 0; i < 2; i++) { tmp |= SDHCI_CDNS_HRS06_TUNE_UP; - writel(tmp, reg); + priv->priv_writel(priv, tmp, reg); ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), @@ -309,6 +325,91 @@ static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host, sdhci_set_uhs_signaling(host, timing); } +/* Elba control register bits [6:3] are byte-lane enables */ +#define ELBA_BYTE_ENABLE_MASK(x) ((x) << 3) + +/* + * The Pensando Elba SoC explicitly controls byte-lane enabling on writes + * which includes writes to the HRS registers. The write lock (wrlock) + * is used to ensure byte-lane enable, using write control (ctl_addr), + * occurs before the data write. + */ +static void elba_priv_writel(struct sdhci_cdns_priv *priv, u32 val, + void __iomem *reg) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->wrlock, flags); + writel(GENMASK(7, 3), priv->ctl_addr); + writel(val, reg); + spin_unlock_irqrestore(&priv->wrlock, flags); +} + +static void elba_write_l(struct sdhci_host *host, u32 val, int reg) +{ + elba_priv_writel(sdhci_cdns_priv(host), val, host->ioaddr + reg); +} + +static void elba_write_w(struct sdhci_host *host, u16 val, int reg) +{ + struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); + u32 shift = reg & GENMASK(1, 0); + unsigned long flags; + u32 byte_enables; + + byte_enables = GENMASK(1, 0) << shift; + spin_lock_irqsave(&priv->wrlock, flags); + writel(ELBA_BYTE_ENABLE_MASK(byte_enables), priv->ctl_addr); + writew(val, host->ioaddr + reg); + spin_unlock_irqrestore(&priv->wrlock, flags); +} + +static void elba_write_b(struct sdhci_host *host, u8 val, int reg) +{ + struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); + u32 shift = reg & GENMASK(1, 0); + unsigned long flags; + u32 byte_enables; + + byte_enables = BIT(0) << shift; + spin_lock_irqsave(&priv->wrlock, flags); + writel(ELBA_BYTE_ENABLE_MASK(byte_enables), priv->ctl_addr); + writeb(val, host->ioaddr + reg); + spin_unlock_irqrestore(&priv->wrlock, flags); +} + +static const struct sdhci_ops sdhci_elba_ops = { + .write_l = elba_write_l, + .write_w = elba_write_w, + .write_b = elba_write_b, + .set_clock = sdhci_set_clock, + .get_timeout_clock = sdhci_cdns_get_timeout_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_cdns_set_uhs_signaling, +}; + +static int elba_drv_init(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); + void __iomem *ioaddr; + + host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA; + spin_lock_init(&priv->wrlock); + + /* Byte-lane control register */ + ioaddr = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(ioaddr)) + return PTR_ERR(ioaddr); + + priv->ctl_addr = ioaddr; + priv->priv_writel = elba_priv_writel; + writel(ELBA_BYTE_ENABLE_MASK(0xf), priv->ctl_addr); + + return 0; +} + static const struct sdhci_ops sdhci_cdns_ops = { .set_clock = sdhci_set_clock, .get_timeout_clock = sdhci_cdns_get_timeout_clock, @@ -318,13 +419,24 @@ static const struct sdhci_ops sdhci_cdns_ops = { .set_uhs_signaling = sdhci_cdns_set_uhs_signaling, }; -static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = { - .ops = &sdhci_cdns_ops, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +static const struct sdhci_cdns_drv_data sdhci_cdns_uniphier_drv_data = { + .pltfm_data = { + .ops = &sdhci_cdns_ops, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + }, }; -static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = { - .ops = &sdhci_cdns_ops, +static const struct sdhci_cdns_drv_data sdhci_elba_drv_data = { + .init = elba_drv_init, + .pltfm_data = { + .ops = &sdhci_elba_ops, + }, +}; + +static const struct sdhci_cdns_drv_data sdhci_cdns_drv_data = { + .pltfm_data = { + .ops = &sdhci_cdns_ops, + }, }; static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc, @@ -347,10 +459,26 @@ static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc, SDHCI_CDNS_HRS06_MODE_MMC_HS400); } +static void sdhci_cdns_mmc_hw_reset(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); + + dev_dbg(mmc_dev(host->mmc), "emmc hardware reset\n"); + + reset_control_assert(priv->rst_hw); + /* For eMMC, minimum is 1us but give it 3us for good measure */ + udelay(3); + + reset_control_deassert(priv->rst_hw); + /* For eMMC, minimum is 200us but give it 300us for good measure */ + usleep_range(300, 1000); +} + static int sdhci_cdns_probe(struct platform_device *pdev) { struct sdhci_host *host; - const struct sdhci_pltfm_data *data; + const struct sdhci_cdns_drv_data *data; struct sdhci_pltfm_host *pltfm_host; struct sdhci_cdns_priv *priv; struct clk *clk; @@ -369,10 +497,10 @@ static int sdhci_cdns_probe(struct platform_device *pdev) data = of_device_get_match_data(dev); if (!data) - data = &sdhci_cdns_pltfm_data; + data = &sdhci_cdns_drv_data; nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node); - host = sdhci_pltfm_init(pdev, data, + host = sdhci_pltfm_init(pdev, &data->pltfm_data, struct_size(priv, phy_params, nr_phy_params)); if (IS_ERR(host)) { ret = PTR_ERR(host); @@ -386,9 +514,15 @@ static int sdhci_cdns_probe(struct platform_device *pdev) priv->nr_phy_params = nr_phy_params; priv->hrs_addr = host->ioaddr; priv->enhanced_strobe = false; + priv->priv_writel = cdns_writel; host->ioaddr += SDHCI_CDNS_SRS_BASE; host->mmc_host_ops.hs400_enhanced_strobe = sdhci_cdns_hs400_enhanced_strobe; + if (data->init) { + ret = data->init(pdev); + if (ret) + goto free; + } sdhci_enable_v4_mode(host); __sdhci_read_caps(host, &version, NULL, NULL); @@ -404,6 +538,15 @@ static int sdhci_cdns_probe(struct platform_device *pdev) if (ret) goto free; + if (host->mmc->caps & MMC_CAP_HW_RESET) { + priv->rst_hw = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(priv->rst_hw)) + return dev_err_probe(mmc_dev(host->mmc), PTR_ERR(priv->rst_hw), + "reset controller error\n"); + if (priv->rst_hw) + host->mmc_host_ops.card_hw_reset = sdhci_cdns_mmc_hw_reset; + } + ret = sdhci_add_host(host); if (ret) goto free; @@ -453,7 +596,11 @@ static const struct dev_pm_ops sdhci_cdns_pm_ops = { static const struct of_device_id sdhci_cdns_match[] = { { .compatible = "socionext,uniphier-sd4hc", - .data = &sdhci_cdns_uniphier_pltfm_data, + .data = &sdhci_cdns_uniphier_drv_data, + }, + { + .compatible = "amd,pensando-elba-sd4hc", + .data = &sdhci_elba_drv_data, }, { .compatible = "cdns,sd4hc" }, { /* sentinel */ } diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 58f042fdd4f4..d7c0c0b9e26c 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1597,7 +1597,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, struct esdhc_platform_data *boarddata = &imx_data->boarddata; int ret; - if (of_get_property(np, "fsl,wp-controller", NULL)) + if (of_property_read_bool(np, "fsl,wp-controller")) boarddata->wp_type = ESDHC_WP_CONTROLLER; /* @@ -1614,7 +1614,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, of_property_read_u32(np, "fsl,strobe-dll-delay-target", &boarddata->strobe_dll_delay_target); - if (of_find_property(np, "no-1-8-v", NULL)) + if (of_property_read_bool(np, "no-1-8-v")) host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line)) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 89c431a34c43..294dd605fd2b 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -41,11 +41,41 @@ #define VENDOR_ENHANCED_STROBE BIT(0) #define PHY_CLK_TOO_SLOW_HZ 400000 +#define MIN_PHY_CLK_HZ 50000000 #define SDHCI_ITAPDLY_CHGWIN 0x200 #define SDHCI_ITAPDLY_ENABLE 0x100 #define SDHCI_OTAPDLY_ENABLE 0x40 +#define PHY_CTRL_REG1 0x270 +#define PHY_CTRL_ITAPDLY_ENA_MASK BIT(0) +#define PHY_CTRL_ITAPDLY_SEL_MASK GENMASK(5, 1) +#define PHY_CTRL_ITAPDLY_SEL_SHIFT 1 +#define PHY_CTRL_ITAP_CHG_WIN_MASK BIT(6) +#define PHY_CTRL_OTAPDLY_ENA_MASK BIT(8) +#define PHY_CTRL_OTAPDLY_SEL_MASK GENMASK(15, 12) +#define PHY_CTRL_OTAPDLY_SEL_SHIFT 12 +#define PHY_CTRL_STRB_SEL_MASK GENMASK(23, 16) +#define PHY_CTRL_STRB_SEL_SHIFT 16 +#define PHY_CTRL_TEST_CTRL_MASK GENMASK(31, 24) + +#define PHY_CTRL_REG2 0x274 +#define PHY_CTRL_EN_DLL_MASK BIT(0) +#define PHY_CTRL_DLL_RDY_MASK BIT(1) +#define PHY_CTRL_FREQ_SEL_MASK GENMASK(6, 4) +#define PHY_CTRL_FREQ_SEL_SHIFT 4 +#define PHY_CTRL_SEL_DLY_TX_MASK BIT(16) +#define PHY_CTRL_SEL_DLY_RX_MASK BIT(17) +#define FREQSEL_200M_170M 0x0 +#define FREQSEL_170M_140M 0x1 +#define FREQSEL_140M_110M 0x2 +#define FREQSEL_110M_80M 0x3 +#define FREQSEL_80M_50M 0x4 +#define FREQSEL_275M_250M 0x5 +#define FREQSEL_250M_225M 0x6 +#define FREQSEL_225M_200M 0x7 +#define PHY_DLL_TIMEOUT_MS 100 + /* Default settings for ZynqMP Clock Phases */ #define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0} #define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0} @@ -53,6 +83,11 @@ #define VERSAL_ICLK_PHASE {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0} #define VERSAL_OCLK_PHASE {0, 60, 48, 0, 48, 72, 90, 36, 60, 90, 0} +#define VERSAL_NET_EMMC_ICLK_PHASE {0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0} +#define VERSAL_NET_EMMC_OCLK_PHASE {0, 113, 0, 0, 0, 0, 0, 0, 113, 79, 45} + +#define VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL 0X77 + /* * On some SoCs the syscon area has a feature where the upper 16-bits of * each 32-bit register act as a write mask for the lower 16-bits. This allows @@ -135,6 +170,7 @@ struct sdhci_arasan_clk_data { * @clk_ahb: Pointer to the AHB clock * @phy: Pointer to the generic phy * @is_phy_on: True if the PHY is on; false if not. + * @internal_phy_reg: True if the PHY is within the Host controller. * @has_cqe: True if controller has command queuing engine. * @clk_data: Struct for the Arasan Controller Clock Data. * @clk_ops: Struct for the Arasan Controller Clock Operations. @@ -147,6 +183,7 @@ struct sdhci_arasan_data { struct clk *clk_ahb; struct phy *phy; bool is_phy_on; + bool internal_phy_reg; bool has_cqe; struct sdhci_arasan_clk_data clk_data; @@ -193,13 +230,6 @@ static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = { .hiword_update = false, }; -static const struct sdhci_arasan_soc_ctl_map thunderbay_soc_ctl_map = { - .baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 }, - .clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 }, - .support64b = { .reg = 0x4, .width = 1, .shift = 24 }, - .hiword_update = false, -}; - static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = { .baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 }, .clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 }, @@ -207,6 +237,61 @@ static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = { .hiword_update = false, }; +static void sdhci_arasan_phy_set_delaychain(struct sdhci_host *host, bool enable) +{ + u32 reg; + + reg = readl(host->ioaddr + PHY_CTRL_REG2); + if (enable) + reg |= (PHY_CTRL_SEL_DLY_TX_MASK | PHY_CTRL_SEL_DLY_RX_MASK); + else + reg &= ~(PHY_CTRL_SEL_DLY_TX_MASK | PHY_CTRL_SEL_DLY_RX_MASK); + + writel(reg, host->ioaddr + PHY_CTRL_REG2); +} + +static int sdhci_arasan_phy_set_dll(struct sdhci_host *host, bool enable) +{ + u32 reg; + + reg = readl(host->ioaddr + PHY_CTRL_REG2); + if (enable) + reg |= PHY_CTRL_EN_DLL_MASK; + else + reg &= ~PHY_CTRL_EN_DLL_MASK; + + writel(reg, host->ioaddr + PHY_CTRL_REG2); + + if (!enable) + return 0; + + return readl_relaxed_poll_timeout(host->ioaddr + PHY_CTRL_REG2, reg, + (reg & PHY_CTRL_DLL_RDY_MASK), 10, + 1000 * PHY_DLL_TIMEOUT_MS); +} + +static void sdhci_arasan_phy_dll_set_freq(struct sdhci_host *host, int clock) +{ + u32 reg, freq_sel, freq; + + freq = DIV_ROUND_CLOSEST(clock, 1000000); + if (freq <= 200 && freq > 170) + freq_sel = FREQSEL_200M_170M; + else if (freq <= 170 && freq > 140) + freq_sel = FREQSEL_170M_140M; + else if (freq <= 140 && freq > 110) + freq_sel = FREQSEL_140M_110M; + else if (freq <= 110 && freq > 80) + freq_sel = FREQSEL_110M_80M; + else + freq_sel = FREQSEL_80M_50M; + + reg = readl(host->ioaddr + PHY_CTRL_REG2); + reg &= ~PHY_CTRL_FREQ_SEL_MASK; + reg |= (freq_sel << PHY_CTRL_FREQ_SEL_SHIFT); + writel(reg, host->ioaddr + PHY_CTRL_REG2); +} + /** * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers * @@ -321,11 +406,24 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) } /* Set the Input and Output Clock Phase Delays */ - if (clk_data->set_clk_delays) + if (clk_data->set_clk_delays && clock > PHY_CLK_TOO_SLOW_HZ) clk_data->set_clk_delays(host); + if (sdhci_arasan->internal_phy_reg && clock >= MIN_PHY_CLK_HZ) { + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + sdhci_arasan_phy_set_dll(host, 0); + sdhci_arasan_phy_set_delaychain(host, 0); + sdhci_arasan_phy_dll_set_freq(host, clock); + } else if (sdhci_arasan->internal_phy_reg) { + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + sdhci_arasan_phy_set_delaychain(host, 1); + } + sdhci_set_clock(host, clock); + if (sdhci_arasan->internal_phy_reg && clock >= MIN_PHY_CLK_HZ) + sdhci_arasan_phy_set_dll(host, 1); + if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE) /* * Some controllers immediately report SDHCI_CLOCK_INT_STABLE @@ -465,15 +563,6 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, }; -static const struct sdhci_pltfm_data sdhci_arasan_thunderbay_pdata = { - .ops = &sdhci_arasan_cqe_ops, - .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | - SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | - SDHCI_QUIRK2_STOP_WITH_TC | - SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400, -}; - #ifdef CONFIG_PM_SLEEP /** * sdhci_arasan_suspend - Suspend method for the driver @@ -897,6 +986,101 @@ static const struct clk_ops versal_sampleclk_ops = { .set_phase = sdhci_versal_sampleclk_set_phase, }; +static int sdhci_versal_net_emmc_sdcardclk_set_phase(struct clk_hw *hw, int degrees) +{ + struct sdhci_arasan_clk_data *clk_data = + container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); + struct sdhci_arasan_data *sdhci_arasan = + container_of(clk_data, struct sdhci_arasan_data, clk_data); + struct sdhci_host *host = sdhci_arasan->host; + u8 tap_delay, tap_max = 0; + + switch (host->timing) { + case MMC_TIMING_MMC_HS: + case MMC_TIMING_MMC_DDR52: + tap_max = 16; + break; + case MMC_TIMING_MMC_HS200: + case MMC_TIMING_MMC_HS400: + /* For 200MHz clock, 32 Taps are available */ + tap_max = 32; + break; + default: + break; + } + + tap_delay = (degrees * tap_max) / 360; + + /* Set the Clock Phase */ + if (tap_delay) { + u32 regval; + + regval = sdhci_readl(host, PHY_CTRL_REG1); + regval |= PHY_CTRL_OTAPDLY_ENA_MASK; + sdhci_writel(host, regval, PHY_CTRL_REG1); + regval &= ~PHY_CTRL_OTAPDLY_SEL_MASK; + regval |= tap_delay << PHY_CTRL_OTAPDLY_SEL_SHIFT; + sdhci_writel(host, regval, PHY_CTRL_REG1); + } + + return 0; +} + +static const struct clk_ops versal_net_sdcardclk_ops = { + .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, + .set_phase = sdhci_versal_net_emmc_sdcardclk_set_phase, +}; + +static int sdhci_versal_net_emmc_sampleclk_set_phase(struct clk_hw *hw, int degrees) +{ + struct sdhci_arasan_clk_data *clk_data = + container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); + struct sdhci_arasan_data *sdhci_arasan = + container_of(clk_data, struct sdhci_arasan_data, clk_data); + struct sdhci_host *host = sdhci_arasan->host; + u8 tap_delay, tap_max = 0; + u32 regval; + + switch (host->timing) { + case MMC_TIMING_MMC_HS: + case MMC_TIMING_MMC_DDR52: + tap_max = 32; + break; + case MMC_TIMING_MMC_HS400: + /* Strobe select tap point for strb90 and strb180 */ + regval = sdhci_readl(host, PHY_CTRL_REG1); + regval &= ~PHY_CTRL_STRB_SEL_MASK; + regval |= VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL << PHY_CTRL_STRB_SEL_SHIFT; + sdhci_writel(host, regval, PHY_CTRL_REG1); + break; + default: + break; + } + + tap_delay = (degrees * tap_max) / 360; + + /* Set the Clock Phase */ + if (tap_delay) { + regval = sdhci_readl(host, PHY_CTRL_REG1); + regval |= PHY_CTRL_ITAP_CHG_WIN_MASK; + sdhci_writel(host, regval, PHY_CTRL_REG1); + regval |= PHY_CTRL_ITAPDLY_ENA_MASK; + sdhci_writel(host, regval, PHY_CTRL_REG1); + regval &= ~PHY_CTRL_ITAPDLY_SEL_MASK; + regval |= tap_delay << PHY_CTRL_ITAPDLY_SEL_SHIFT; + sdhci_writel(host, regval, PHY_CTRL_REG1); + regval &= ~PHY_CTRL_ITAP_CHG_WIN_MASK; + sdhci_writel(host, regval, PHY_CTRL_REG1); + } + + return 0; +} + +static const struct clk_ops versal_net_sampleclk_ops = { + .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, + .set_phase = sdhci_versal_net_emmc_sampleclk_set_phase, +}; + static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid) { u16 clk; @@ -1107,7 +1291,17 @@ static void arasan_dt_parse_clk_phases(struct device *dev, clk_data->clk_phase_out[i] = versal_oclk_phase[i]; } } + if (of_device_is_compatible(dev->of_node, "xlnx,versal-net-emmc")) { + u32 versal_net_iclk_phase[MMC_TIMING_MMC_HS400 + 1] = + VERSAL_NET_EMMC_ICLK_PHASE; + u32 versal_net_oclk_phase[MMC_TIMING_MMC_HS400 + 1] = + VERSAL_NET_EMMC_OCLK_PHASE; + for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { + clk_data->clk_phase_in[i] = versal_net_iclk_phase[i]; + clk_data->clk_phase_out[i] = versal_net_oclk_phase[i]; + } + } arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY, "clk-phase-legacy"); arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS, @@ -1150,12 +1344,6 @@ static struct sdhci_arasan_of_data sdhci_arasan_generic_data = { .clk_ops = &arasan_clk_ops, }; -static const struct sdhci_arasan_of_data sdhci_arasan_thunderbay_data = { - .soc_ctl_map = &thunderbay_soc_ctl_map, - .pdata = &sdhci_arasan_thunderbay_pdata, - .clk_ops = &arasan_clk_ops, -}; - static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = { .ops = &sdhci_arasan_cqe_ops, .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | @@ -1225,6 +1413,14 @@ static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = { SDHCI_QUIRK2_STOP_WITH_TC, }; +static const struct sdhci_pltfm_data sdhci_arasan_versal_net_pdata = { + .ops = &sdhci_arasan_ops, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | + SDHCI_QUIRK2_STOP_WITH_TC | + SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400, +}; + static const struct sdhci_arasan_clk_ops zynqmp_clk_ops = { .sdcardclk_ops = &zynqmp_sdcardclk_ops, .sampleclk_ops = &zynqmp_sampleclk_ops, @@ -1245,6 +1441,16 @@ static struct sdhci_arasan_of_data sdhci_arasan_versal_data = { .clk_ops = &versal_clk_ops, }; +static const struct sdhci_arasan_clk_ops versal_net_clk_ops = { + .sdcardclk_ops = &versal_net_sdcardclk_ops, + .sampleclk_ops = &versal_net_sampleclk_ops, +}; + +static struct sdhci_arasan_of_data sdhci_arasan_versal_net_data = { + .pdata = &sdhci_arasan_versal_net_pdata, + .clk_ops = &versal_net_clk_ops, +}; + static struct sdhci_arasan_of_data intel_keembay_emmc_data = { .soc_ctl_map = &intel_keembay_soc_ctl_map, .pdata = &sdhci_keembay_emmc_pdata, @@ -1289,10 +1495,6 @@ static const struct of_device_id sdhci_arasan_of_match[] = { .compatible = "intel,keembay-sdhci-5.1-sdio", .data = &intel_keembay_sdio_data, }, - { - .compatible = "intel,thunderbay-sdhci-5.1", - .data = &sdhci_arasan_thunderbay_data, - }, /* Generic compatible below here */ { .compatible = "arasan,sdhci-8.9a", @@ -1314,6 +1516,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = { .compatible = "xlnx,versal-8.9a", .data = &sdhci_arasan_versal_data, }, + { + .compatible = "xlnx,versal-net-emmc", + .data = &sdhci_arasan_versal_net_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); @@ -1434,7 +1640,7 @@ static void sdhci_arasan_unregister_sdclk(struct device *dev) { struct device_node *np = dev->of_node; - if (!of_find_property(np, "#clock-cells", NULL)) + if (!of_property_present(np, "#clock-cells")) return; of_clk_del_provider(dev->of_node); @@ -1630,6 +1836,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev) int ret; struct device_node *node; struct clk *clk_xin; + struct clk *clk_dll; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct device *dev = &pdev->dev; @@ -1703,6 +1910,12 @@ static int sdhci_arasan_probe(struct platform_device *pdev) goto clk_dis_ahb; } + clk_dll = devm_clk_get_optional_enabled(dev, "gate"); + if (IS_ERR(clk_dll)) { + ret = dev_err_probe(dev, PTR_ERR(clk_dll), "failed to get dll clk\n"); + goto clk_disable_all; + } + if (of_property_read_bool(np, "xlnx,fails-without-test-cd")) sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST; @@ -1716,8 +1929,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") || of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") || - of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio") || - of_device_is_compatible(np, "intel,thunderbay-sdhci-5.1")) { + of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) { sdhci_arasan_update_clockmultiplier(host, 0x0); sdhci_arasan_update_support64b(host, 0x0); @@ -1781,6 +1993,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev) host->mmc->caps2 |= MMC_CAP2_CQE_DCMD; } + if (of_device_is_compatible(np, "xlnx,versal-net-emmc")) + sdhci_arasan->internal_phy_reg = true; + ret = sdhci_arasan_add_host(sdhci_arasan); if (ret) goto err_add_host; diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c index ba6677bf7372..25b4073f698b 100644 --- a/drivers/mmc/host/sdhci-of-aspeed.c +++ b/drivers/mmc/host/sdhci-of-aspeed.c @@ -547,8 +547,7 @@ static int aspeed_sdc_probe(struct platform_device *pdev) return ret; } - sdc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - sdc->regs = devm_ioremap_resource(&pdev->dev, sdc->res); + sdc->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &sdc->res); if (IS_ERR(sdc->regs)) { ret = PTR_ERR(sdc->regs); goto err_clk; diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index d1490469184b..e68cd87998c8 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -126,6 +126,13 @@ static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host) return pltfm_host->clock; } +static unsigned int rk35xx_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + return clk_round_rate(pltfm_host->clk, ULONG_MAX); +} + static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc, struct mmc_request *mrq) { @@ -343,7 +350,7 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { .set_clock = dwcmshc_rk3568_set_clock, .set_bus_width = sdhci_set_bus_width, .set_uhs_signaling = dwcmshc_set_uhs_signaling, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_max_clock = rk35xx_get_max_clock, .reset = rk35xx_sdhci_reset, .adma_write_desc = dwcmshc_adma_write_desc, }; diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 4712adac7f7c..48ca1cf15b19 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -133,6 +133,7 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host, return ret; } } + /* * The DAT[3:0] line signal levels and the CMD line signal level are * not compatible with standard SDHC register. The line signal levels @@ -144,6 +145,16 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host, ret = value & 0x000fffff; ret |= (value >> 4) & SDHCI_DATA_LVL_MASK; ret |= (value << 1) & SDHCI_CMD_LVL; + + /* + * Some controllers have unreliable Data Line Active + * bit for commands with busy signal. This affects + * Command Inhibit (data) bit. Just ignore it since + * MMC core driver has already polled card status + * with CMD13 after any command with busy siganl. + */ + if (esdhc->quirk_ignore_data_inhibit) + ret &= ~SDHCI_DATA_INHIBIT; return ret; } @@ -158,19 +169,6 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host, return ret; } - /* - * Some controllers have unreliable Data Line Active - * bit for commands with busy signal. This affects - * Command Inhibit (data) bit. Just ignore it since - * MMC core driver has already polled card status - * with CMD13 after any command with busy siganl. - */ - if ((spec_reg == SDHCI_PRESENT_STATE) && - (esdhc->quirk_ignore_data_inhibit == true)) { - ret = value & ~SDHCI_DATA_INHIBIT; - return ret; - } - ret = value; return ret; } diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index 98cadff47b2b..620f52ad9667 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -339,22 +339,24 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) reg_val &= ~SDHCI_CLOCK_CARD_EN; sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL); - /* UnLock WP */ - pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8); - scratch_8 &= 0x7f; - pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); - - /* Set pcr 0x354[16] to choose dll clock, and set the default phase */ - pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, ®_val); - reg_val &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK); - reg_val |= (O2_SD_SEL_DLL | O2_SD_FIX_PHASE); - pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, reg_val); + if ((host->timing == MMC_TIMING_MMC_HS200) || + (host->timing == MMC_TIMING_UHS_SDR104)) { + /* UnLock WP */ + pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8); + scratch_8 &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); - /* Lock WP */ - pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8); - scratch_8 |= 0x80; - pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); + /* Set pcr 0x354[16] to choose dll clock, and set the default phase */ + pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, ®_val); + reg_val &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK); + reg_val |= (O2_SD_SEL_DLL | O2_SD_FIX_PHASE); + pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, reg_val); + /* Lock WP */ + pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8); + scratch_8 |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); + } /* Start clk */ reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL); reg_val |= SDHCI_CLOCK_CARD_EN; diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 328b132bbe57..673e750a8490 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -54,7 +54,6 @@ static bool sdhci_wp_inverted(struct device *dev) #endif /* CONFIG_PPC */ } -#ifdef CONFIG_OF static void sdhci_get_compatibility(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); @@ -72,9 +71,6 @@ static void sdhci_get_compatibility(struct platform_device *pdev) of_device_is_compatible(np, "fsl,mpc8536-esdhc")) host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; } -#else -void sdhci_get_compatibility(struct platform_device *pdev) {} -#endif /* CONFIG_OF */ void sdhci_get_property(struct platform_device *pdev) { diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index fc306eb1f845..91aca8f8d6ef 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -228,7 +228,7 @@ static struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev) if (!pdata) return NULL; - if (of_find_property(np, "non-removable", NULL)) + if (of_property_read_bool(np, "non-removable")) pdata->flags |= PXA_FLAG_CARD_PERMANENT; of_property_read_u32(np, "bus-width", &bus_width); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 9085f3932443..504015e84308 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -437,12 +437,12 @@ static int sdhci_s3c_parse_dt(struct device *dev, pdata->max_width = max_width; /* get the card detection method */ - if (of_get_property(node, "broken-cd", NULL)) { + if (of_property_read_bool(node, "broken-cd")) { pdata->cd_type = S3C_SDHCI_CD_NONE; return 0; } - if (of_get_property(node, "non-removable", NULL)) { + if (of_property_read_bool(node, "non-removable")) { pdata->cd_type = S3C_SDHCI_CD_PERMANENT; return 0; } diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 672d37ea98d0..7cdf0f54e3a5 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -85,6 +85,7 @@ #define DRIVER_STRENGTH_40_OHM 0x4 #define CLOCK_TOO_SLOW_HZ 50000000 +#define SDHCI_AM654_AUTOSUSPEND_DELAY -1 /* Command Queue Host Controller Interface Base address */ #define SDHCI_AM654_CQE_BASE_ADDR 0x200 @@ -808,16 +809,10 @@ static int sdhci_am654_probe(struct platform_device *pdev) pltfm_host->clk = clk_xin; - /* Clocks are enabled using pm_runtime */ - pm_runtime_enable(dev); - ret = pm_runtime_resume_and_get(dev); - if (ret) - goto pm_runtime_disable; - base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(base)) { ret = PTR_ERR(base); - goto pm_runtime_put; + goto err_pltfm_free; } sdhci_am654->base = devm_regmap_init_mmio(dev, base, @@ -825,31 +820,47 @@ static int sdhci_am654_probe(struct platform_device *pdev) if (IS_ERR(sdhci_am654->base)) { dev_err(dev, "Failed to initialize regmap\n"); ret = PTR_ERR(sdhci_am654->base); - goto pm_runtime_put; + goto err_pltfm_free; } ret = sdhci_am654_get_of_property(pdev, sdhci_am654); if (ret) - goto pm_runtime_put; + goto err_pltfm_free; ret = mmc_of_parse(host->mmc); if (ret) { dev_err_probe(dev, ret, "parsing dt failed\n"); - goto pm_runtime_put; + goto err_pltfm_free; } host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning; + pm_runtime_get_noresume(dev); + ret = pm_runtime_set_active(dev); + if (ret) + goto pm_put; + pm_runtime_enable(dev); + ret = clk_prepare_enable(pltfm_host->clk); + if (ret) + goto pm_disable; + ret = sdhci_am654_init(host); if (ret) - goto pm_runtime_put; + goto clk_disable; + /* Setting up autosuspend */ + pm_runtime_set_autosuspend_delay(dev, SDHCI_AM654_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; -pm_runtime_put: - pm_runtime_put_sync(dev); -pm_runtime_disable: +clk_disable: + clk_disable_unprepare(pltfm_host->clk); +pm_disable: pm_runtime_disable(dev); +pm_put: + pm_runtime_put_noidle(dev); err_pltfm_free: sdhci_pltfm_free(pdev); return ret; @@ -858,23 +869,127 @@ err_pltfm_free: static int sdhci_am654_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); int ret; - sdhci_remove_host(host, true); - ret = pm_runtime_put_sync(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) return ret; + sdhci_remove_host(host, true); + clk_disable_unprepare(pltfm_host->clk); pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); sdhci_pltfm_free(pdev); + return 0; +} + +#ifdef CONFIG_PM +static int sdhci_am654_restore(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); + u32 ctl_cfg_2 = 0; + u32 val; + int ret; + + if (sdhci_am654->flags & DLL_CALIB) { + regmap_read(sdhci_am654->base, PHY_STAT1, &val); + if (~val & CALDONE_MASK) { + /* Calibrate IO lines */ + regmap_update_bits(sdhci_am654->base, PHY_CTRL1, + PDB_MASK, PDB_MASK); + ret = regmap_read_poll_timeout(sdhci_am654->base, + PHY_STAT1, val, + val & CALDONE_MASK, + 1, 20); + if (ret) + return ret; + } + } + + /* Enable pins by setting IO mux to 0 */ + if (sdhci_am654->flags & IOMUX_PRESENT) + regmap_update_bits(sdhci_am654->base, PHY_CTRL1, + IOMUX_ENABLE_MASK, 0); + /* Set slot type based on SD or eMMC */ + if (host->mmc->caps & MMC_CAP_NONREMOVABLE) + ctl_cfg_2 = SLOTTYPE_EMBEDDED; + + regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK, + ctl_cfg_2); + + regmap_read(sdhci_am654->base, CTL_CFG_3, &val); + if (~val & TUNINGFORSDR50_MASK) + /* Enable tuning for SDR50 */ + regmap_update_bits(sdhci_am654->base, CTL_CFG_3, TUNINGFORSDR50_MASK, + TUNINGFORSDR50_MASK); + + return 0; +} + +static int sdhci_am654_runtime_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + int ret; + + if (host->tuning_mode != SDHCI_TUNING_MODE_3) + mmc_retune_needed(host->mmc); + + ret = cqhci_suspend(host->mmc); + if (ret) + return ret; + + ret = sdhci_runtime_suspend_host(host); + if (ret) + return ret; + + /* disable the clock */ + clk_disable_unprepare(pltfm_host->clk); return 0; } +static int sdhci_am654_runtime_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + int ret; + + /* Enable the clock */ + ret = clk_prepare_enable(pltfm_host->clk); + if (ret) + return ret; + + ret = sdhci_am654_restore(host); + if (ret) + return ret; + + ret = sdhci_runtime_resume_host(host, 0); + if (ret) + return ret; + + ret = cqhci_resume(host->mmc); + if (ret) + return ret; + + return 0; +} +#endif + +static const struct dev_pm_ops sdhci_am654_dev_pm_ops = { + SET_RUNTIME_PM_OPS(sdhci_am654_runtime_suspend, + sdhci_am654_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + static struct platform_driver sdhci_am654_driver = { .driver = { .name = "sdhci-am654", .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &sdhci_am654_dev_pm_ops, .of_match_table = sdhci_am654_of_match, }, .probe = sdhci_am654_probe, diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 76a8cd3a186f..57b8c1a96756 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -101,14 +101,6 @@ static inline void sdricoh_writel(struct sdricoh_host *host, unsigned int reg, } -static inline unsigned int sdricoh_readw(struct sdricoh_host *host, - unsigned int reg) -{ - unsigned int value = readw(host->iobase + reg); - dev_vdbg(host->dev, "rb %x 0x%x\n", reg, value); - return value; -} - static inline void sdricoh_writew(struct sdricoh_host *host, unsigned int reg, unsigned short value) { diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index e24c3d284515..be7f18fd4836 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1084,7 +1084,7 @@ static void tmio_mmc_of_parse(struct platform_device *pdev, * For new platforms, please use "disable-wp" instead of * "toshiba,mmc-wrprotect-disable" */ - if (of_get_property(np, "toshiba,mmc-wrprotect-disable", NULL)) + if (of_property_read_bool(np, "toshiba,mmc-wrprotect-disable")) mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; } diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 99515be6e5e5..2f59917b105e 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1790,8 +1790,7 @@ static int usdhi6_probe(struct platform_device *pdev) host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->base = devm_ioremap_resource(dev, res); + host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(host->base)) { ret = PTR_ERR(host->base); goto e_free_mmc; diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 72f65f32abbc..e4c4bfac3763 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -1341,8 +1341,6 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, return; } - return; - copy_error_message: strncpy(vub300->vub_name, "SDIO pseudocode download failed", sizeof(vub300->vub_name)); diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 9aa3027ca25e..68525d900046 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -802,10 +802,8 @@ static int wmt_mci_probe(struct platform_device *pdev) priv->power_inverted = 0; priv->cd_inverted = 0; - if (of_get_property(np, "sdon-inverted", NULL)) - priv->power_inverted = 1; - if (of_get_property(np, "cd-inverted", NULL)) - priv->cd_inverted = 1; + priv->power_inverted = of_property_read_bool(np, "sdon-inverted"); + priv->cd_inverted = of_property_read_bool(np, "cd-inverted"); priv->sdmmc_base = of_iomap(np, 0); if (!priv->sdmmc_base) { diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 812e6b583b25..461d1543893b 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -450,6 +450,7 @@ struct mmc_host { unsigned int retune_paused:1; /* re-tuning is temporarily disabled */ unsigned int retune_crc_disable:1; /* don't trigger retune upon crc */ unsigned int can_dma_map_merge:1; /* merging can be used */ + unsigned int vqmmc_enabled:1; /* vqmmc regulator is enabled */ int rescan_disable; /* disable card detection */ int rescan_entered; /* used with nonremovable devices */ @@ -598,6 +599,8 @@ static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc, #endif int mmc_regulator_get_supply(struct mmc_host *mmc); +int mmc_regulator_enable_vqmmc(struct mmc_host *mmc); +void mmc_regulator_disable_vqmmc(struct mmc_host *mmc); static inline int mmc_card_is_removable(struct mmc_host *host) { |