Commit fe86da36 authored by Kamal Dasu's avatar Kamal Dasu Committed by Ulf Hansson

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: default avatarKamal Dasu <kdasu@broadcom.com>
Acked-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/20240103222338.31447-3-kamal.dasu@broadcom.comSigned-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 0a8d397c
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -44,8 +45,13 @@ struct brcmstb_match_priv { ...@@ -44,8 +45,13 @@ struct brcmstb_match_priv {
static inline void enable_clock_gating(struct sdhci_host *host) static inline void enable_clock_gating(struct sdhci_host *host)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
u32 reg; u32 reg;
if (!(priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK))
return;
reg = sdhci_readl(host, SDHCI_VENDOR); reg = sdhci_readl(host, SDHCI_VENDOR);
reg |= SDHCI_VENDOR_GATE_SDCLK_EN; reg |= SDHCI_VENDOR_GATE_SDCLK_EN;
sdhci_writel(host, reg, SDHCI_VENDOR); sdhci_writel(host, reg, SDHCI_VENDOR);
...@@ -53,14 +59,53 @@ static inline void enable_clock_gating(struct sdhci_host *host) ...@@ -53,14 +59,53 @@ static inline void enable_clock_gating(struct sdhci_host *host)
static void brcmstb_reset(struct sdhci_host *host, u8 mask) static void brcmstb_reset(struct sdhci_host *host, u8 mask)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
sdhci_and_cqhci_reset(host, mask); sdhci_and_cqhci_reset(host, mask);
/* Reset will clear this, so re-enable it */ /* Reset will clear this, so re-enable it */
if (priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK) enable_clock_gating(host);
enable_clock_gating(host); }
static void brcmstb_sdhci_reset_cmd_data(struct sdhci_host *host, u8 mask)
{
u32 new_mask = (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) << 24;
int ret;
u32 reg;
/*
* SDHCI_CLOCK_CONTROL register CARD_EN and CLOCK_INT_EN bits shall
* be set along with SOFTWARE_RESET register RESET_CMD or RESET_DATA
* bits, hence access SDHCI_CLOCK_CONTROL register as 32-bit register
*/
new_mask |= SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN;
reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
sdhci_writel(host, reg | new_mask, SDHCI_CLOCK_CONTROL);
reg = sdhci_readb(host, SDHCI_SOFTWARE_RESET);
ret = read_poll_timeout_atomic(sdhci_readb, reg, !(reg & mask),
10, 10000, false,
host, SDHCI_SOFTWARE_RESET);
if (ret) {
pr_err("%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
sdhci_err_stats_inc(host, CTRL_TIMEOUT);
sdhci_dumpregs(host);
}
}
static void brcmstb_reset_74165b0(struct sdhci_host *host, u8 mask)
{
/* take care of RESET_ALL as usual */
if (mask & SDHCI_RESET_ALL)
sdhci_and_cqhci_reset(host, SDHCI_RESET_ALL);
/* cmd and/or data treated differently on this core */
if (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA))
brcmstb_sdhci_reset_cmd_data(host, mask);
/* Reset will clear this, so re-enable it */
enable_clock_gating(host);
} }
static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios) static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios)
...@@ -162,6 +207,13 @@ static struct sdhci_ops sdhci_brcmstb_ops_7216 = { ...@@ -162,6 +207,13 @@ static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
.set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling, .set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling,
}; };
static struct sdhci_ops sdhci_brcmstb_ops_74165b0 = {
.set_clock = sdhci_brcmstb_set_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = brcmstb_reset_74165b0,
.set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling,
};
static struct brcmstb_match_priv match_priv_7425 = { static struct brcmstb_match_priv match_priv_7425 = {
.flags = BRCMSTB_MATCH_FLAGS_NO_64BIT | .flags = BRCMSTB_MATCH_FLAGS_NO_64BIT |
BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT, BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
...@@ -179,10 +231,17 @@ static const struct brcmstb_match_priv match_priv_7216 = { ...@@ -179,10 +231,17 @@ static const struct brcmstb_match_priv match_priv_7216 = {
.ops = &sdhci_brcmstb_ops_7216, .ops = &sdhci_brcmstb_ops_7216,
}; };
static struct brcmstb_match_priv match_priv_74165b0 = {
.flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE,
.hs400es = sdhci_brcmstb_hs400es,
.ops = &sdhci_brcmstb_ops_74165b0,
};
static const struct of_device_id __maybe_unused sdhci_brcm_of_match[] = { static const struct of_device_id __maybe_unused sdhci_brcm_of_match[] = {
{ .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 }, { .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 },
{ .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 }, { .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 },
{ .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 }, { .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 },
{ .compatible = "brcm,bcm74165b0-sdhci", .data = &match_priv_74165b0 },
{}, {},
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment