40
40
#define SDHCI_CDNS_HRS06_MODE_MMC_DDR 0x3
41
41
#define SDHCI_CDNS_HRS06_MODE_MMC_HS200 0x4
42
42
#define SDHCI_CDNS_HRS06_MODE_MMC_HS400 0x5
43
+ #define SDHCI_CDNS_HRS06_MODE_MMC_HS400ES 0x6
43
44
44
45
/* SRS - Slot Register Set (SDHCI-compatible) */
45
46
#define SDHCI_CDNS_SRS_BASE 0x200
64
65
65
66
struct sdhci_cdns_priv {
66
67
void __iomem * hrs_addr ;
68
+ bool enhanced_strobe ;
67
69
};
68
70
69
71
static void sdhci_cdns_write_phy_reg (struct sdhci_cdns_priv * priv ,
@@ -108,11 +110,30 @@ static unsigned int sdhci_cdns_get_timeout_clock(struct sdhci_host *host)
108
110
return host -> max_clk / 1000 ;
109
111
}
110
112
113
+ static void sdhci_cdns_set_emmc_mode (struct sdhci_cdns_priv * priv , u32 mode )
114
+ {
115
+ u32 tmp ;
116
+
117
+ /* The speed mode for eMMC is selected by HRS06 register */
118
+ tmp = readl (priv -> hrs_addr + SDHCI_CDNS_HRS06 );
119
+ tmp &= ~SDHCI_CDNS_HRS06_MODE_MASK ;
120
+ tmp |= mode ;
121
+ writel (tmp , priv -> hrs_addr + SDHCI_CDNS_HRS06 );
122
+ }
123
+
124
+ static u32 sdhci_cdns_get_emmc_mode (struct sdhci_cdns_priv * priv )
125
+ {
126
+ u32 tmp ;
127
+
128
+ tmp = readl (priv -> hrs_addr + SDHCI_CDNS_HRS06 );
129
+ return tmp & SDHCI_CDNS_HRS06_MODE_MASK ;
130
+ }
131
+
111
132
static void sdhci_cdns_set_uhs_signaling (struct sdhci_host * host ,
112
133
unsigned int timing )
113
134
{
114
135
struct sdhci_cdns_priv * priv = sdhci_cdns_priv (host );
115
- u32 mode , tmp ;
136
+ u32 mode ;
116
137
117
138
switch (timing ) {
118
139
case MMC_TIMING_MMC_HS :
@@ -125,18 +146,17 @@ static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
125
146
mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200 ;
126
147
break ;
127
148
case MMC_TIMING_MMC_HS400 :
128
- mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400 ;
149
+ if (priv -> enhanced_strobe )
150
+ mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES ;
151
+ else
152
+ mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400 ;
129
153
break ;
130
154
default :
131
155
mode = SDHCI_CDNS_HRS06_MODE_SD ;
132
156
break ;
133
157
}
134
158
135
- /* The speed mode for eMMC is selected by HRS06 register */
136
- tmp = readl (priv -> hrs_addr + SDHCI_CDNS_HRS06 );
137
- tmp &= ~SDHCI_CDNS_HRS06_MODE_MASK ;
138
- tmp |= mode ;
139
- writel (tmp , priv -> hrs_addr + SDHCI_CDNS_HRS06 );
159
+ sdhci_cdns_set_emmc_mode (priv , mode );
140
160
141
161
/* For SD, fall back to the default handler */
142
162
if (mode == SDHCI_CDNS_HRS06_MODE_SD )
@@ -213,6 +233,26 @@ static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)
213
233
return sdhci_cdns_set_tune_val (host , end_of_streak - max_streak / 2 );
214
234
}
215
235
236
+ static void sdhci_cdns_hs400_enhanced_strobe (struct mmc_host * mmc ,
237
+ struct mmc_ios * ios )
238
+ {
239
+ struct sdhci_host * host = mmc_priv (mmc );
240
+ struct sdhci_cdns_priv * priv = sdhci_cdns_priv (host );
241
+ u32 mode ;
242
+
243
+ priv -> enhanced_strobe = ios -> enhanced_strobe ;
244
+
245
+ mode = sdhci_cdns_get_emmc_mode (priv );
246
+
247
+ if (mode == SDHCI_CDNS_HRS06_MODE_MMC_HS400 && ios -> enhanced_strobe )
248
+ sdhci_cdns_set_emmc_mode (priv ,
249
+ SDHCI_CDNS_HRS06_MODE_MMC_HS400ES );
250
+
251
+ if (mode == SDHCI_CDNS_HRS06_MODE_MMC_HS400ES && !ios -> enhanced_strobe )
252
+ sdhci_cdns_set_emmc_mode (priv ,
253
+ SDHCI_CDNS_HRS06_MODE_MMC_HS400 );
254
+ }
255
+
216
256
static int sdhci_cdns_probe (struct platform_device * pdev )
217
257
{
218
258
struct sdhci_host * host ;
@@ -240,8 +280,11 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
240
280
241
281
priv = sdhci_cdns_priv (host );
242
282
priv -> hrs_addr = host -> ioaddr ;
283
+ priv -> enhanced_strobe = false;
243
284
host -> ioaddr += SDHCI_CDNS_SRS_BASE ;
244
285
host -> mmc_host_ops .execute_tuning = sdhci_cdns_execute_tuning ;
286
+ host -> mmc_host_ops .hs400_enhanced_strobe =
287
+ sdhci_cdns_hs400_enhanced_strobe ;
245
288
246
289
ret = mmc_of_parse (host -> mmc );
247
290
if (ret )
0 commit comments