66 */
77
88#include <linux/io.h>
9+ #include <linux/iopoll.h>
910#include <linux/mmc/host.h>
1011#include <linux/module.h>
1112#include <linux/of.h>
@@ -44,23 +45,67 @@ struct brcmstb_match_priv {
4445
4546static inline void enable_clock_gating (struct sdhci_host * host )
4647{
48+ struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
49+ struct sdhci_brcmstb_priv * priv = sdhci_pltfm_priv (pltfm_host );
4750 u32 reg ;
4851
52+ if (!(priv -> flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK ))
53+ return ;
54+
4955 reg = sdhci_readl (host , SDHCI_VENDOR );
5056 reg |= SDHCI_VENDOR_GATE_SDCLK_EN ;
5157 sdhci_writel (host , reg , SDHCI_VENDOR );
5258}
5359
5460static void brcmstb_reset (struct sdhci_host * host , u8 mask )
5561{
56- struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
57- struct sdhci_brcmstb_priv * priv = sdhci_pltfm_priv (pltfm_host );
58-
5962 sdhci_and_cqhci_reset (host , mask );
6063
6164 /* Reset will clear this, so re-enable it */
62- if (priv -> flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK )
63- enable_clock_gating (host );
65+ enable_clock_gating (host );
66+ }
67+
68+ static void brcmstb_sdhci_reset_cmd_data (struct sdhci_host * host , u8 mask )
69+ {
70+ u32 new_mask = (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA )) << 24 ;
71+ int ret ;
72+ u32 reg ;
73+
74+ /*
75+ * SDHCI_CLOCK_CONTROL register CARD_EN and CLOCK_INT_EN bits shall
76+ * be set along with SOFTWARE_RESET register RESET_CMD or RESET_DATA
77+ * bits, hence access SDHCI_CLOCK_CONTROL register as 32-bit register
78+ */
79+ new_mask |= SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN ;
80+ reg = sdhci_readl (host , SDHCI_CLOCK_CONTROL );
81+ sdhci_writel (host , reg | new_mask , SDHCI_CLOCK_CONTROL );
82+
83+ reg = sdhci_readb (host , SDHCI_SOFTWARE_RESET );
84+
85+ ret = read_poll_timeout_atomic (sdhci_readb , reg , !(reg & mask ),
86+ 10 , 10000 , false,
87+ host , SDHCI_SOFTWARE_RESET );
88+
89+ if (ret ) {
90+ pr_err ("%s: Reset 0x%x never completed.\n" ,
91+ mmc_hostname (host -> mmc ), (int )mask );
92+ sdhci_err_stats_inc (host , CTRL_TIMEOUT );
93+ sdhci_dumpregs (host );
94+ }
95+ }
96+
97+ static void brcmstb_reset_74165b0 (struct sdhci_host * host , u8 mask )
98+ {
99+ /* take care of RESET_ALL as usual */
100+ if (mask & SDHCI_RESET_ALL )
101+ sdhci_and_cqhci_reset (host , SDHCI_RESET_ALL );
102+
103+ /* cmd and/or data treated differently on this core */
104+ if (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA ))
105+ brcmstb_sdhci_reset_cmd_data (host , mask );
106+
107+ /* Reset will clear this, so re-enable it */
108+ enable_clock_gating (host );
64109}
65110
66111static void sdhci_brcmstb_hs400es (struct mmc_host * mmc , struct mmc_ios * ios )
@@ -162,6 +207,13 @@ static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
162207 .set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling ,
163208};
164209
210+ static struct sdhci_ops sdhci_brcmstb_ops_74165b0 = {
211+ .set_clock = sdhci_brcmstb_set_clock ,
212+ .set_bus_width = sdhci_set_bus_width ,
213+ .reset = brcmstb_reset_74165b0 ,
214+ .set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling ,
215+ };
216+
165217static struct brcmstb_match_priv match_priv_7425 = {
166218 .flags = BRCMSTB_MATCH_FLAGS_NO_64BIT |
167219 BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT ,
@@ -179,10 +231,17 @@ static const struct brcmstb_match_priv match_priv_7216 = {
179231 .ops = & sdhci_brcmstb_ops_7216 ,
180232};
181233
234+ static struct brcmstb_match_priv match_priv_74165b0 = {
235+ .flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE ,
236+ .hs400es = sdhci_brcmstb_hs400es ,
237+ .ops = & sdhci_brcmstb_ops_74165b0 ,
238+ };
239+
182240static const struct of_device_id __maybe_unused sdhci_brcm_of_match [] = {
183241 { .compatible = "brcm,bcm7425-sdhci" , .data = & match_priv_7425 },
184242 { .compatible = "brcm,bcm7445-sdhci" , .data = & match_priv_7445 },
185243 { .compatible = "brcm,bcm7216-sdhci" , .data = & match_priv_7216 },
244+ { .compatible = "brcm,bcm74165b0-sdhci" , .data = & match_priv_74165b0 },
186245 {},
187246};
188247
0 commit comments