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 | 17 | #include <linux/module.h> |
| 18 | 18 | #include <linux/of.h> |
| 19 | 19 | #include <linux/platform_device.h> |
| 20 | +#include <linux/pm_domain.h> | |
| 20 | 21 | #include <linux/pm_runtime.h> |
| 21 | 22 | #include <linux/reset.h> |
| 22 | 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 | 772 | static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode) |
| 749 | 773 | { |
| 750 | 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 | 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 | 1215 | static const struct dwcmshc_pltfm_data sdhci_dwcmshc_th1520_pdata = { |
| 1180 | 1216 | .pdata = { |
| 1181 | 1217 | .ops = &sdhci_dwcmshc_th1520_ops, |
| @@ -1274,6 +1310,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { · 92 unmodified lines | ||
| 1274 | 1310 | .compatible = "rockchip,rk3588-dwcmshc", |
| 1275 | 1311 | .data = &sdhci_dwcmshc_rk35xx_pdata, |
| 1276 | 1312 | }, |
| 1313 | + { | |
| 1314 | + .compatible = "rockchip,rk3576-dwcmshc", | |
| 1315 | + .data = &sdhci_dwcmshc_rk3576_pdata, | |
| 1316 | + }, | |
| 1277 | 1317 | { |
| 1278 | 1318 | .compatible = "rockchip,rk3568-dwcmshc", |
| 1279 | 1319 | .data = &sdhci_dwcmshc_rk35xx_pdata, |
| @@ -155,6 +155,7 @@ struct sdhci_am654_data { · 154 unmodified lines | ||
| 155 | 155 | u32 tuning_loop; |
| 156 | 156 | |
| 157 | 157 | #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) |
| 158 | +#define SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA BIT(1) | |
| 158 | 159 | }; |
| 159 | 160 | |
| 160 | 161 | struct window { |
| @@ -166,6 +167,7 @@ struct window { · 5 unmodified lines | ||
| 166 | 167 | struct sdhci_am654_driver_data { |
| 167 | 168 | const struct sdhci_pltfm_data *pdata; |
| 168 | 169 | u32 flags; |
| 170 | + u32 quirks; | |
| 169 | 171 | #define IOMUX_PRESENT (1 << 0) |
| 170 | 172 | #define FREQSEL_2_BIT (1 << 1) |
| 171 | 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 | 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 | 384 | static u8 sdhci_am654_write_power_on(struct sdhci_host *host, u8 val, int reg) |
| 360 | 385 | { |
| 361 | 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 | 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 | 684 | static const struct soc_device_attribute sdhci_am654_devices[] = { |
| 654 | 685 | { .family = "AM65X", |
| 655 | 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 | 905 | .compatible = "ti,am62-sdhci", |
| 875 | − .data = &sdhci_j721e_4bit_drvdata, | |
| 906 | + .data = &sdhci_am62_4bit_drvdata, | |
| 876 | 907 | }, |
| 877 | 908 | { /* sentinel */ } |
| 878 | 909 | }; |
| @@ -906,6 +937,7 @@ static int sdhci_am654_probe(struct platform_device *pdev) · 27 unmodified lines | ||
| 906 | 937 | pltfm_host = sdhci_priv(host); |
| 907 | 938 | sdhci_am654 = sdhci_pltfm_priv(pltfm_host); |
| 908 | 939 | sdhci_am654->flags = drvdata->flags; |
| 940 | + sdhci_am654->quirks = drvdata->quirks; | |
| 909 | 941 | |
| 910 | 942 | clk_xin = devm_clk_get(dev, "clk_xin"); |
| 911 | 943 | if (IS_ERR(clk_xin)) { |
| @@ -940,6 +972,7 @@ static int sdhci_am654_probe(struct platform_device *pdev) · 28 unmodified lines | ||
| 940 | 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 | 976 | host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning; |
| 944 | 977 | |
| 945 | 978 | pm_runtime_get_noresume(dev); |