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>
This commit is contained in:
parent
0a8d397cfc
commit
fe86da368a
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@ -44,8 +45,13 @@ struct brcmstb_match_priv {
|
||||
|
||||
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;
|
||||
|
||||
if (!(priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK))
|
||||
return;
|
||||
|
||||
reg = sdhci_readl(host, SDHCI_VENDOR);
|
||||
reg |= SDHCI_VENDOR_GATE_SDCLK_EN;
|
||||
sdhci_writel(host, reg, SDHCI_VENDOR);
|
||||
@ -53,14 +59,53 @@ static inline void enable_clock_gating(struct sdhci_host *host)
|
||||
|
||||
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);
|
||||
|
||||
/* 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)
|
||||
@ -162,6 +207,13 @@ static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
|
||||
.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 = {
|
||||
.flags = BRCMSTB_MATCH_FLAGS_NO_64BIT |
|
||||
BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
|
||||
@ -179,10 +231,17 @@ static const struct brcmstb_match_priv match_priv_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[] = {
|
||||
{ .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 },
|
||||
{ .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 },
|
||||
{ .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 },
|
||||
{ .compatible = "brcm,bcm74165b0-sdhci", .data = &match_priv_74165b0 },
|
||||
{},
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user