Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: sdhci-brcmstb: save and restore registers during PM

Added support to save and restore registers that are critical
during PM.

Signed-off-by: Kamal Dasu <kamal.dasu@broadcom.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Kamal Dasu and committed by
Ulf Hansson
b7e61480 eea94bdd

+107 -5
+107 -5
drivers/mmc/host/sdhci-brcmstb.c
··· 38 38 #define SDIO_CFG_OP_DLY_DEFAULT 0x80000003 39 39 #define SDIO_CFG_CQ_CAPABILITY 0x4c 40 40 #define SDIO_CFG_CQ_CAPABILITY_FMUL GENMASK(13, 12) 41 + #define SDIO_CFG_SD_PIN_SEL 0x44 42 + #define SDIO_CFG_V1_SD_PIN_SEL 0x54 43 + #define SDIO_CFG_PHY_SW_MODE_0_RX_CTRL 0x7C 41 44 #define SDIO_CFG_MAX_50MHZ_MODE 0x1ac 42 45 #define SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE BIT(31) 43 46 #define SDIO_CFG_MAX_50MHZ_MODE_ENABLE BIT(0) 47 + 48 + #define SDIO_BOOT_MAIN_CTL 0x0 44 49 45 50 #define MMC_CAP_HSE_MASK (MMC_CAP2_HSX00_1_2V | MMC_CAP2_HSX00_1_8V) 46 51 /* Select all SD UHS type I SDR speed above 50MB/s */ 47 52 #define MMC_CAP_UHS_I_SDR_MASK (MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104) 48 53 49 - struct sdhci_brcmstb_priv { 50 - void __iomem *cfg_regs; 51 - unsigned int flags; 52 - struct clk *base_clk; 53 - u32 base_freq_hz; 54 + enum cfg_core_ver { 55 + SDIO_CFG_CORE_V1 = 1, 56 + SDIO_CFG_CORE_V2, 57 + }; 58 + 59 + struct sdhci_brcmstb_saved_regs { 60 + u32 sd_pin_sel; 61 + u32 phy_sw_mode0_rxctrl; 62 + u32 max_50mhz_mode; 63 + u32 boot_main_ctl; 54 64 }; 55 65 56 66 struct brcmstb_match_priv { 57 67 void (*cfginit)(struct sdhci_host *host); 58 68 void (*hs400es)(struct mmc_host *mmc, struct mmc_ios *ios); 69 + void (*save_restore_regs)(struct mmc_host *mmc, int save); 59 70 struct sdhci_ops *ops; 60 71 const unsigned int flags; 61 72 }; 73 + 74 + struct sdhci_brcmstb_priv { 75 + void __iomem *cfg_regs; 76 + void __iomem *boot_regs; 77 + struct sdhci_brcmstb_saved_regs saved_regs; 78 + unsigned int flags; 79 + struct clk *base_clk; 80 + u32 base_freq_hz; 81 + const struct brcmstb_match_priv *match_priv; 82 + }; 83 + 84 + static void sdhci_brcmstb_save_regs(struct mmc_host *mmc, enum cfg_core_ver ver) 85 + { 86 + struct sdhci_host *host = mmc_priv(mmc); 87 + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 88 + struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host); 89 + struct sdhci_brcmstb_saved_regs *sr = &priv->saved_regs; 90 + void __iomem *cr = priv->cfg_regs; 91 + bool is_emmc = mmc->caps & MMC_CAP_NONREMOVABLE; 92 + 93 + if (is_emmc && priv->boot_regs) 94 + sr->boot_main_ctl = readl(priv->boot_regs + SDIO_BOOT_MAIN_CTL); 95 + 96 + if (ver == SDIO_CFG_CORE_V1) { 97 + sr->sd_pin_sel = readl(cr + SDIO_CFG_V1_SD_PIN_SEL); 98 + return; 99 + } 100 + 101 + sr->sd_pin_sel = readl(cr + SDIO_CFG_SD_PIN_SEL); 102 + sr->phy_sw_mode0_rxctrl = readl(cr + SDIO_CFG_PHY_SW_MODE_0_RX_CTRL); 103 + sr->max_50mhz_mode = readl(cr + SDIO_CFG_MAX_50MHZ_MODE); 104 + } 105 + 106 + static void sdhci_brcmstb_restore_regs(struct mmc_host *mmc, enum cfg_core_ver ver) 107 + { 108 + struct sdhci_host *host = mmc_priv(mmc); 109 + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 110 + struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host); 111 + struct sdhci_brcmstb_saved_regs *sr = &priv->saved_regs; 112 + void __iomem *cr = priv->cfg_regs; 113 + bool is_emmc = mmc->caps & MMC_CAP_NONREMOVABLE; 114 + 115 + if (is_emmc && priv->boot_regs) 116 + writel(sr->boot_main_ctl, priv->boot_regs + SDIO_BOOT_MAIN_CTL); 117 + 118 + if (ver == SDIO_CFG_CORE_V1) { 119 + writel(sr->sd_pin_sel, cr + SDIO_CFG_SD_PIN_SEL); 120 + return; 121 + } 122 + 123 + writel(sr->sd_pin_sel, cr + SDIO_CFG_SD_PIN_SEL); 124 + writel(sr->phy_sw_mode0_rxctrl, cr + SDIO_CFG_PHY_SW_MODE_0_RX_CTRL); 125 + writel(sr->max_50mhz_mode, cr + SDIO_CFG_MAX_50MHZ_MODE); 126 + } 127 + 128 + static void sdhci_brcmstb_save_restore_regs_v1(struct mmc_host *mmc, int save) 129 + { 130 + if (save) 131 + sdhci_brcmstb_save_regs(mmc, SDIO_CFG_CORE_V1); 132 + else 133 + sdhci_brcmstb_restore_regs(mmc, SDIO_CFG_CORE_V1); 134 + } 135 + 136 + static void sdhci_brcmstb_save_restore_regs_v2(struct mmc_host *mmc, int save) 137 + { 138 + if (save) 139 + sdhci_brcmstb_save_regs(mmc, SDIO_CFG_CORE_V2); 140 + else 141 + sdhci_brcmstb_restore_regs(mmc, SDIO_CFG_CORE_V2); 142 + } 62 143 63 144 static inline void enable_clock_gating(struct sdhci_host *host) 64 145 { ··· 387 306 388 307 static struct brcmstb_match_priv match_priv_7445 = { 389 308 .flags = BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT, 309 + .save_restore_regs = sdhci_brcmstb_save_restore_regs_v1, 390 310 .ops = &sdhci_brcmstb_ops, 391 311 }; 392 312 393 313 static struct brcmstb_match_priv match_priv_72116 = { 394 314 .flags = BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT, 315 + .save_restore_regs = sdhci_brcmstb_save_restore_regs_v1, 395 316 .ops = &sdhci_brcmstb_ops_72116, 396 317 }; 397 318 398 319 static const struct brcmstb_match_priv match_priv_7216 = { 399 320 .flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE, 321 + .save_restore_regs = sdhci_brcmstb_save_restore_regs_v2, 400 322 .hs400es = sdhci_brcmstb_hs400es, 401 323 .ops = &sdhci_brcmstb_ops_7216, 402 324 }; 403 325 404 326 static struct brcmstb_match_priv match_priv_74165b0 = { 405 327 .flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE, 328 + .save_restore_regs = sdhci_brcmstb_save_restore_regs_v2, 406 329 .hs400es = sdhci_brcmstb_hs400es, 407 330 .ops = &sdhci_brcmstb_ops_74165b0, 408 331 }; ··· 514 429 515 430 pltfm_host = sdhci_priv(host); 516 431 priv = sdhci_pltfm_priv(pltfm_host); 432 + priv->match_priv = match->data; 517 433 if (device_property_read_bool(&pdev->dev, "supports-cqe")) { 518 434 priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_CQE; 519 435 match_priv->ops->irq = sdhci_brcmstb_cqhci_irq; ··· 531 445 res = mmc_of_parse(host->mmc); 532 446 if (res) 533 447 goto err; 448 + 449 + /* map non-standard BOOT registers if present */ 450 + if (host->mmc->caps & MMC_CAP_NONREMOVABLE) { 451 + priv->boot_regs = devm_platform_get_and_ioremap_resource(pdev, 2, NULL); 452 + if (IS_ERR(priv->boot_regs)) 453 + priv->boot_regs = NULL; 454 + } 534 455 535 456 /* 536 457 * Automatic clock gating does not work for SD cards that may ··· 628 535 struct sdhci_host *host = dev_get_drvdata(dev); 629 536 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 630 537 struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host); 538 + const struct brcmstb_match_priv *match_priv = priv->match_priv; 539 + 631 540 int ret; 541 + 542 + if (match_priv->save_restore_regs) 543 + match_priv->save_restore_regs(host->mmc, 1); 632 544 633 545 clk_disable_unprepare(priv->base_clk); 634 546 if (host->mmc->caps2 & MMC_CAP2_CQE) { ··· 650 552 struct sdhci_host *host = dev_get_drvdata(dev); 651 553 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 652 554 struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host); 555 + const struct brcmstb_match_priv *match_priv = priv->match_priv; 653 556 int ret; 654 557 655 558 ret = sdhci_pltfm_resume(dev); ··· 666 567 (clk_get_rate(priv->base_clk) != priv->base_freq_hz)) 667 568 ret = clk_set_rate(priv->base_clk, priv->base_freq_hz); 668 569 } 570 + 571 + if (match_priv->save_restore_regs) 572 + match_priv->save_restore_regs(host->mmc, 0); 669 573 670 574 if (host->mmc->caps2 & MMC_CAP2_CQE) 671 575 ret = cqhci_resume(host->mmc);