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

mmc: sdhci-brcmstb: add new sdhci reset sequence for brcm 74165b0

74165b0 shall use a new sdio controller core version which
requires a different reset sequence. For core reset we use
sdhci_reset. For CMD and/or DATA reset added a new function
to also enable SDHCI clocks SDHCI_CLOCK_CARD_EN
SDHCI_CLOCK_INT_EN along with the SDHCI_RESET_CMD and/or
SDHCI_RESET_DATA fields.

Signed-off-by: Kamal Dasu <kdasu@broadcom.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/20240103222338.31447-3-kamal.dasu@broadcom.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Kamal Dasu and committed by
Ulf Hansson
fe86da36 0a8d397c

+64 -5
+64 -5
drivers/mmc/host/sdhci-brcmstb.c
··· 6 6 */ 7 7 8 8 #include <linux/io.h> 9 + #include <linux/iopoll.h> 9 10 #include <linux/mmc/host.h> 10 11 #include <linux/module.h> 11 12 #include <linux/of.h> ··· 45 44 46 45 static inline void enable_clock_gating(struct sdhci_host *host) 47 46 { 47 + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 48 + struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host); 48 49 u32 reg; 50 + 51 + if (!(priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK)) 52 + return; 49 53 50 54 reg = sdhci_readl(host, SDHCI_VENDOR); 51 55 reg |= SDHCI_VENDOR_GATE_SDCLK_EN; ··· 59 53 60 54 static void brcmstb_reset(struct sdhci_host *host, u8 mask) 61 55 { 62 - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 63 - struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host); 64 - 65 56 sdhci_and_cqhci_reset(host, mask); 66 57 67 58 /* Reset will clear this, so re-enable it */ 68 - if (priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK) 69 - enable_clock_gating(host); 59 + enable_clock_gating(host); 60 + } 61 + 62 + static void brcmstb_sdhci_reset_cmd_data(struct sdhci_host *host, u8 mask) 63 + { 64 + u32 new_mask = (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) << 24; 65 + int ret; 66 + u32 reg; 67 + 68 + /* 69 + * SDHCI_CLOCK_CONTROL register CARD_EN and CLOCK_INT_EN bits shall 70 + * be set along with SOFTWARE_RESET register RESET_CMD or RESET_DATA 71 + * bits, hence access SDHCI_CLOCK_CONTROL register as 32-bit register 72 + */ 73 + new_mask |= SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN; 74 + reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); 75 + sdhci_writel(host, reg | new_mask, SDHCI_CLOCK_CONTROL); 76 + 77 + reg = sdhci_readb(host, SDHCI_SOFTWARE_RESET); 78 + 79 + ret = read_poll_timeout_atomic(sdhci_readb, reg, !(reg & mask), 80 + 10, 10000, false, 81 + host, SDHCI_SOFTWARE_RESET); 82 + 83 + if (ret) { 84 + pr_err("%s: Reset 0x%x never completed.\n", 85 + mmc_hostname(host->mmc), (int)mask); 86 + sdhci_err_stats_inc(host, CTRL_TIMEOUT); 87 + sdhci_dumpregs(host); 88 + } 89 + } 90 + 91 + static void brcmstb_reset_74165b0(struct sdhci_host *host, u8 mask) 92 + { 93 + /* take care of RESET_ALL as usual */ 94 + if (mask & SDHCI_RESET_ALL) 95 + sdhci_and_cqhci_reset(host, SDHCI_RESET_ALL); 96 + 97 + /* cmd and/or data treated differently on this core */ 98 + if (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) 99 + brcmstb_sdhci_reset_cmd_data(host, mask); 100 + 101 + /* Reset will clear this, so re-enable it */ 102 + enable_clock_gating(host); 70 103 } 71 104 72 105 static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios) ··· 207 162 .set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling, 208 163 }; 209 164 165 + static struct sdhci_ops sdhci_brcmstb_ops_74165b0 = { 166 + .set_clock = sdhci_brcmstb_set_clock, 167 + .set_bus_width = sdhci_set_bus_width, 168 + .reset = brcmstb_reset_74165b0, 169 + .set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling, 170 + }; 171 + 210 172 static struct brcmstb_match_priv match_priv_7425 = { 211 173 .flags = BRCMSTB_MATCH_FLAGS_NO_64BIT | 212 174 BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT, ··· 231 179 .ops = &sdhci_brcmstb_ops_7216, 232 180 }; 233 181 182 + static struct brcmstb_match_priv match_priv_74165b0 = { 183 + .flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE, 184 + .hs400es = sdhci_brcmstb_hs400es, 185 + .ops = &sdhci_brcmstb_ops_74165b0, 186 + }; 187 + 234 188 static const struct of_device_id __maybe_unused sdhci_brcm_of_match[] = { 235 189 { .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 }, 236 190 { .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 }, 237 191 { .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 }, 192 + { .compatible = "brcm,bcm74165b0-sdhci", .data = &match_priv_74165b0 }, 238 193 {}, 239 194 }; 240 195