Pull MMC host fixes from Ulf Hansson: - sdhci_am654: Fix MMC init failures on am62x boards - sdhci-of-dwcmshc: Add PD workaround on RK3576 to avoid hang * tag 'mmc-v6.15-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: mmc: sdhci_am654: Add SDHCI_QUIRK2_SUPPRESS_V1P8_ENA quirk to am62 compatible mmc: sdhci-of-dwcmshc: add PD workaround on RK3576
Unified · Split
| @@ -17,6 +17,7 @@ · 16 unmodified lines | |||
| 17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 18 | #include <linux/of.h> | 18 | #include <linux/of.h> |
| 19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 20 | #include <linux/pm_domain.h> | ||
| 20 | #include <linux/pm_runtime.h> | 21 | #include <linux/pm_runtime.h> |
| 21 | #include <linux/reset.h> | 22 | #include <linux/reset.h> |
| 22 | #include <linux/sizes.h> | 23 | #include <linux/sizes.h> |
| @@ -745,6 +746,29 @@ static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv · 722 unmodified lines | |||
| 745 | } | 746 | } |
| 746 | } | 747 | } |
| 747 | 748 | ||
| 749 | static void dwcmshc_rk3576_postinit(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) | ||
| 750 | { | ||
| 751 | struct device *dev = mmc_dev(host->mmc); | ||
| 752 | int ret; | ||
| 753 | |||
| 754 | /* | ||
| 755 | * This works around the design of the RK3576's power domains, which | ||
| 756 | * makes the PD_NVM power domain, which the sdhci controller on the | ||
| 757 | * RK3576 is in, never come back the same way once it's run-time | ||
| 758 | * suspended once. This can happen during early kernel boot if no driver | ||
| 759 | * is using either PD_NVM or its child power domain PD_SDGMAC for a | ||
| 760 | * short moment, leading to it being turned off to save power. By | ||
| 761 | * keeping it on, sdhci suspending won't lead to PD_NVM becoming a | ||
| 762 | * candidate for getting turned off. | ||
| 763 | */ | ||
| 764 | ret = dev_pm_genpd_rpm_always_on(dev, true); | ||
| 765 | if (ret && ret != -EOPNOTSUPP) | ||
| 766 | dev_warn(dev, "failed to set PD rpm always on, SoC may hang later: %pe\n", | ||
| 767 | ERR_PTR(ret)); | ||
| 768 | |||
| 769 | dwcmshc_rk35xx_postinit(host, dwc_priv); | ||
| 770 | } | ||
| 771 | |||
| 748 | static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode) | 772 | static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode) |
| 749 | { | 773 | { |
| 750 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 774 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
| @@ -1176,6 +1200,18 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { · 425 unmodified lines | |||
| 1176 | .postinit = dwcmshc_rk35xx_postinit, | 1200 | .postinit = dwcmshc_rk35xx_postinit, |
| 1177 | }; | 1201 | }; |
| 1178 | 1202 | ||
| 1203 | static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk3576_pdata = { | ||
| 1204 | .pdata = { | ||
| 1205 | .ops = &sdhci_dwcmshc_rk35xx_ops, | ||
| 1206 | .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | | ||
| 1207 | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, | ||
| 1208 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | | ||
| 1209 | SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, | ||
| 1210 | }, | ||
| 1211 | .init = dwcmshc_rk35xx_init, | ||
| 1212 | .postinit = dwcmshc_rk3576_postinit, | ||
| 1213 | }; | ||
| 1214 | |||
| 1179 | static const struct dwcmshc_pltfm_data sdhci_dwcmshc_th1520_pdata = { | 1215 | static const struct dwcmshc_pltfm_data sdhci_dwcmshc_th1520_pdata = { |
| 1180 | .pdata = { | 1216 | .pdata = { |
| 1181 | .ops = &sdhci_dwcmshc_th1520_ops, | 1217 | .ops = &sdhci_dwcmshc_th1520_ops, |
| @@ -1274,6 +1310,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { · 92 unmodified lines | |||
| 1274 | .compatible = "rockchip,rk3588-dwcmshc", | 1310 | .compatible = "rockchip,rk3588-dwcmshc", |
| 1275 | .data = &sdhci_dwcmshc_rk35xx_pdata, | 1311 | .data = &sdhci_dwcmshc_rk35xx_pdata, |
| 1276 | }, | 1312 | }, |
| 1313 | { | ||
| 1314 | .compatible = "rockchip,rk3576-dwcmshc", | ||
| 1315 | .data = &sdhci_dwcmshc_rk3576_pdata, | ||
| 1316 | }, | ||
| 1277 | { | 1317 | { |
| 1278 | .compatible = "rockchip,rk3568-dwcmshc", | 1318 | .compatible = "rockchip,rk3568-dwcmshc", |
| 1279 | .data = &sdhci_dwcmshc_rk35xx_pdata, | 1319 | .data = &sdhci_dwcmshc_rk35xx_pdata, |
| @@ -155,6 +155,7 @@ struct sdhci_am654_data { · 154 unmodified lines | |||
| 155 | u32 tuning_loop; | 155 | u32 tuning_loop; |
| 156 | 156 | ||
| 157 | #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) | 157 | #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) |
| 158 | #define SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA BIT(1) | ||
| 158 | }; | 159 | }; |
| 159 | 160 | ||
| 160 | struct window { | 161 | struct window { |
| @@ -166,6 +167,7 @@ struct window { · 5 unmodified lines | |||
| 166 | struct sdhci_am654_driver_data { | 167 | struct sdhci_am654_driver_data { |
| 167 | const struct sdhci_pltfm_data *pdata; | 168 | const struct sdhci_pltfm_data *pdata; |
| 168 | u32 flags; | 169 | u32 flags; |
| 170 | u32 quirks; | ||
| 169 | #define IOMUX_PRESENT (1 << 0) | 171 | #define IOMUX_PRESENT (1 << 0) |
| 170 | #define FREQSEL_2_BIT (1 << 1) | 172 | #define FREQSEL_2_BIT (1 << 1) |
| 171 | #define STRBSEL_4_BIT (1 << 2) | 173 | #define STRBSEL_4_BIT (1 << 2) |
| @@ -356,6 +358,29 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, · 184 unmodified lines | |||
| 356 | sdhci_set_clock(host, clock); | 358 | sdhci_set_clock(host, clock); |
| 357 | } | 359 | } |
| 358 | 360 | ||
| 361 | static int sdhci_am654_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) | ||
| 362 | { | ||
| 363 | struct sdhci_host *host = mmc_priv(mmc); | ||
| 364 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | ||
| 365 | struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); | ||
| 366 | int ret; | ||
| 367 | |||
| 368 | if ((sdhci_am654->quirks & SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA) && | ||
| 369 | ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { | ||
| 370 | if (!IS_ERR(mmc->supply.vqmmc)) { | ||
| 371 | ret = mmc_regulator_set_vqmmc(mmc, ios); | ||
| 372 | if (ret < 0) { | ||
| 373 | pr_err("%s: Switching to 1.8V signalling voltage failed,\n", | ||
| 374 | mmc_hostname(mmc)); | ||
| 375 | return -EIO; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | return 0; | ||
| 379 | } | ||
| 380 | |||
| 381 | return sdhci_start_signal_voltage_switch(mmc, ios); | ||
| 382 | } | ||
| 383 | |||
| 359 | static u8 sdhci_am654_write_power_on(struct sdhci_host *host, u8 val, int reg) | 384 | static u8 sdhci_am654_write_power_on(struct sdhci_host *host, u8 val, int reg) |
| 360 | { | 385 | { |
| 361 | writeb(val, host->ioaddr + reg); | 386 | writeb(val, host->ioaddr + reg); |
| @@ -650,6 +675,12 @@ static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = { · 288 unmodified lines | |||
| 650 | .flags = IOMUX_PRESENT, | 675 | .flags = IOMUX_PRESENT, |
| 651 | }; | 676 | }; |
| 652 | 677 | ||
| 678 | static const struct sdhci_am654_driver_data sdhci_am62_4bit_drvdata = { | ||
| 679 | .pdata = &sdhci_j721e_4bit_pdata, | ||
| 680 | .flags = IOMUX_PRESENT, | ||
| 681 | .quirks = SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA, | ||
| 682 | }; | ||
| 683 | |||
| 653 | static const struct soc_device_attribute sdhci_am654_devices[] = { | 684 | static const struct soc_device_attribute sdhci_am654_devices[] = { |
| 654 | { .family = "AM65X", | 685 | { .family = "AM65X", |
| 655 | .revision = "SR1.0", | 686 | .revision = "SR1.0", |
| @@ -872,7 +903,7 @@ static const struct of_device_id sdhci_am654_of_match[] = { · 216 unmodified lines | |||
| 872 | }, | 903 | }, |
| 873 | { | 904 | { |
| 874 | .compatible = "ti,am62-sdhci", | 905 | .compatible = "ti,am62-sdhci", |
| 875 | .data = &sdhci_j721e_4bit_drvdata, | 906 | .data = &sdhci_am62_4bit_drvdata, |
| 876 | }, | 907 | }, |
| 877 | { /* sentinel */ } | 908 | { /* sentinel */ } |
| 878 | }; | 909 | }; |
| @@ -906,6 +937,7 @@ static int sdhci_am654_probe(struct platform_device *pdev) · 27 unmodified lines | |||
| 906 | pltfm_host = sdhci_priv(host); | 937 | pltfm_host = sdhci_priv(host); |
| 907 | sdhci_am654 = sdhci_pltfm_priv(pltfm_host); | 938 | sdhci_am654 = sdhci_pltfm_priv(pltfm_host); |
| 908 | sdhci_am654->flags = drvdata->flags; | 939 | sdhci_am654->flags = drvdata->flags; |
| 940 | sdhci_am654->quirks = drvdata->quirks; | ||
| 909 | 941 | ||
| 910 | clk_xin = devm_clk_get(dev, "clk_xin"); | 942 | clk_xin = devm_clk_get(dev, "clk_xin"); |
| 911 | if (IS_ERR(clk_xin)) { | 943 | if (IS_ERR(clk_xin)) { |
| @@ -940,6 +972,7 @@ static int sdhci_am654_probe(struct platform_device *pdev) · 28 unmodified lines | |||
| 940 | goto err_pltfm_free; | 972 | goto err_pltfm_free; |
| 941 | } | 973 | } |
| 942 | 974 | ||
| 975 | host->mmc_host_ops.start_signal_voltage_switch = sdhci_am654_start_signal_voltage_switch; | ||
| 943 | host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning; | 976 | host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning; |
| 944 | 977 | ||
| 945 | pm_runtime_get_noresume(dev); | 978 | pm_runtime_get_noresume(dev); |