OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | From 4215d5757595e7ec7ca146c2b901beb177f415d8 Mon Sep 17 00:00:00 2001 |
2 | From: Yangbo Lu <yangbo.lu@nxp.com> |
||
3 | Date: Wed, 17 Jan 2018 15:37:13 +0800 |
||
4 | Subject: [PATCH 24/30] mmc: layerscape support |
||
5 | |||
6 | This is an integrated patch for layerscape mmc support. |
||
7 | |||
8 | Adrian Hunter <adrian.hunter@intel.com> |
||
9 | Jaehoon Chung <jh80.chung@samsung.com> |
||
10 | Masahiro Yamada <yamada.masahiro@socionext.com> |
||
11 | Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> |
||
12 | --- |
||
13 | drivers/mmc/host/Kconfig | 1 + |
||
14 | drivers/mmc/host/sdhci-esdhc.h | 52 +++++--- |
||
15 | drivers/mmc/host/sdhci-of-esdhc.c | 265 ++++++++++++++++++++++++++++++++++++-- |
||
16 | drivers/mmc/host/sdhci.c | 45 ++++--- |
||
17 | drivers/mmc/host/sdhci.h | 3 + |
||
18 | 5 files changed, 320 insertions(+), 46 deletions(-) |
||
19 | |||
20 | --- a/drivers/mmc/host/Kconfig |
||
21 | +++ b/drivers/mmc/host/Kconfig |
||
22 | @@ -144,6 +144,7 @@ config MMC_SDHCI_OF_ESDHC |
||
23 | depends on MMC_SDHCI_PLTFM |
||
24 | depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE |
||
25 | select MMC_SDHCI_IO_ACCESSORS |
||
26 | + select FSL_GUTS |
||
27 | help |
||
28 | This selects the Freescale eSDHC controller support. |
||
29 | |||
30 | --- a/drivers/mmc/host/sdhci-esdhc.h |
||
31 | +++ b/drivers/mmc/host/sdhci-esdhc.h |
||
32 | @@ -24,30 +24,46 @@ |
||
33 | SDHCI_QUIRK_PIO_NEEDS_DELAY | \ |
||
34 | SDHCI_QUIRK_NO_HISPD_BIT) |
||
35 | |||
36 | -#define ESDHC_PROCTL 0x28 |
||
37 | - |
||
38 | -#define ESDHC_SYSTEM_CONTROL 0x2c |
||
39 | -#define ESDHC_CLOCK_MASK 0x0000fff0 |
||
40 | -#define ESDHC_PREDIV_SHIFT 8 |
||
41 | -#define ESDHC_DIVIDER_SHIFT 4 |
||
42 | -#define ESDHC_CLOCK_PEREN 0x00000004 |
||
43 | -#define ESDHC_CLOCK_HCKEN 0x00000002 |
||
44 | -#define ESDHC_CLOCK_IPGEN 0x00000001 |
||
45 | - |
||
46 | /* pltfm-specific */ |
||
47 | #define ESDHC_HOST_CONTROL_LE 0x20 |
||
48 | |||
49 | /* |
||
50 | - * P2020 interpretation of the SDHCI_HOST_CONTROL register |
||
51 | + * eSDHC register definition |
||
52 | */ |
||
53 | -#define ESDHC_CTRL_4BITBUS (0x1 << 1) |
||
54 | -#define ESDHC_CTRL_8BITBUS (0x2 << 1) |
||
55 | -#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) |
||
56 | - |
||
57 | -/* OF-specific */ |
||
58 | -#define ESDHC_DMA_SYSCTL 0x40c |
||
59 | -#define ESDHC_DMA_SNOOP 0x00000040 |
||
60 | |||
61 | -#define ESDHC_HOST_CONTROL_RES 0x01 |
||
62 | +/* Present State Register */ |
||
63 | +#define ESDHC_PRSSTAT 0x24 |
||
64 | +#define ESDHC_CLOCK_STABLE 0x00000008 |
||
65 | + |
||
66 | +/* Protocol Control Register */ |
||
67 | +#define ESDHC_PROCTL 0x28 |
||
68 | +#define ESDHC_VOLT_SEL 0x00000400 |
||
69 | +#define ESDHC_CTRL_4BITBUS (0x1 << 1) |
||
70 | +#define ESDHC_CTRL_8BITBUS (0x2 << 1) |
||
71 | +#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) |
||
72 | +#define ESDHC_HOST_CONTROL_RES 0x01 |
||
73 | + |
||
74 | +/* System Control Register */ |
||
75 | +#define ESDHC_SYSTEM_CONTROL 0x2c |
||
76 | +#define ESDHC_CLOCK_MASK 0x0000fff0 |
||
77 | +#define ESDHC_PREDIV_SHIFT 8 |
||
78 | +#define ESDHC_DIVIDER_SHIFT 4 |
||
79 | +#define ESDHC_CLOCK_SDCLKEN 0x00000008 |
||
80 | +#define ESDHC_CLOCK_PEREN 0x00000004 |
||
81 | +#define ESDHC_CLOCK_HCKEN 0x00000002 |
||
82 | +#define ESDHC_CLOCK_IPGEN 0x00000001 |
||
83 | + |
||
84 | +/* Host Controller Capabilities Register 2 */ |
||
85 | +#define ESDHC_CAPABILITIES_1 0x114 |
||
86 | + |
||
87 | +/* Tuning Block Control Register */ |
||
88 | +#define ESDHC_TBCTL 0x120 |
||
89 | +#define ESDHC_TB_EN 0x00000004 |
||
90 | + |
||
91 | +/* Control Register for DMA transfer */ |
||
92 | +#define ESDHC_DMA_SYSCTL 0x40c |
||
93 | +#define ESDHC_PERIPHERAL_CLK_SEL 0x00080000 |
||
94 | +#define ESDHC_FLUSH_ASYNC_FIFO 0x00040000 |
||
95 | +#define ESDHC_DMA_SNOOP 0x00000040 |
||
96 | |||
97 | #endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */ |
||
98 | --- a/drivers/mmc/host/sdhci-of-esdhc.c |
||
99 | +++ b/drivers/mmc/host/sdhci-of-esdhc.c |
||
100 | @@ -16,8 +16,12 @@ |
||
101 | #include <linux/err.h> |
||
102 | #include <linux/io.h> |
||
103 | #include <linux/of.h> |
||
104 | +#include <linux/of_address.h> |
||
105 | #include <linux/delay.h> |
||
106 | #include <linux/module.h> |
||
107 | +#include <linux/sys_soc.h> |
||
108 | +#include <linux/clk.h> |
||
109 | +#include <linux/ktime.h> |
||
110 | #include <linux/mmc/host.h> |
||
111 | #include "sdhci-pltfm.h" |
||
112 | #include "sdhci-esdhc.h" |
||
113 | @@ -28,8 +32,12 @@ |
||
114 | struct sdhci_esdhc { |
||
115 | u8 vendor_ver; |
||
116 | u8 spec_ver; |
||
117 | + bool quirk_incorrect_hostver; |
||
118 | + unsigned int peripheral_clock; |
||
119 | }; |
||
120 | |||
121 | +static void esdhc_clock_enable(struct sdhci_host *host, bool enable); |
||
122 | + |
||
123 | /** |
||
124 | * esdhc_read*_fixup - Fixup the value read from incompatible eSDHC register |
||
125 | * to make it compatible with SD spec. |
||
126 | @@ -80,6 +88,17 @@ static u32 esdhc_readl_fixup(struct sdhc |
||
127 | return ret; |
||
128 | } |
||
129 | |||
130 | + /* |
||
131 | + * DTS properties of mmc host are used to enable each speed mode |
||
132 | + * according to soc and board capability. So clean up |
||
133 | + * SDR50/SDR104/DDR50 support bits here. |
||
134 | + */ |
||
135 | + if (spec_reg == SDHCI_CAPABILITIES_1) { |
||
136 | + ret = value & (~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 | |
||
137 | + SDHCI_SUPPORT_DDR50)); |
||
138 | + return ret; |
||
139 | + } |
||
140 | + |
||
141 | ret = value; |
||
142 | return ret; |
||
143 | } |
||
144 | @@ -87,6 +106,8 @@ static u32 esdhc_readl_fixup(struct sdhc |
||
145 | static u16 esdhc_readw_fixup(struct sdhci_host *host, |
||
146 | int spec_reg, u32 value) |
||
147 | { |
||
148 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
||
149 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
||
150 | u16 ret; |
||
151 | int shift = (spec_reg & 0x2) * 8; |
||
152 | |||
153 | @@ -94,6 +115,12 @@ static u16 esdhc_readw_fixup(struct sdhc |
||
154 | ret = value & 0xffff; |
||
155 | else |
||
156 | ret = (value >> shift) & 0xffff; |
||
157 | + /* Workaround for T4240-R1.0-R2.0 eSDHC which has incorrect |
||
158 | + * vendor version and spec version information. |
||
159 | + */ |
||
160 | + if ((spec_reg == SDHCI_HOST_VERSION) && |
||
161 | + (esdhc->quirk_incorrect_hostver)) |
||
162 | + ret = (VENDOR_V_23 << SDHCI_VENDOR_VER_SHIFT) | SDHCI_SPEC_200; |
||
163 | return ret; |
||
164 | } |
||
165 | |||
166 | @@ -235,7 +262,11 @@ static u32 esdhc_be_readl(struct sdhci_h |
||
167 | u32 ret; |
||
168 | u32 value; |
||
169 | |||
170 | - value = ioread32be(host->ioaddr + reg); |
||
171 | + if (reg == SDHCI_CAPABILITIES_1) |
||
172 | + value = ioread32be(host->ioaddr + ESDHC_CAPABILITIES_1); |
||
173 | + else |
||
174 | + value = ioread32be(host->ioaddr + reg); |
||
175 | + |
||
176 | ret = esdhc_readl_fixup(host, reg, value); |
||
177 | |||
178 | return ret; |
||
179 | @@ -246,7 +277,11 @@ static u32 esdhc_le_readl(struct sdhci_h |
||
180 | u32 ret; |
||
181 | u32 value; |
||
182 | |||
183 | - value = ioread32(host->ioaddr + reg); |
||
184 | + if (reg == SDHCI_CAPABILITIES_1) |
||
185 | + value = ioread32(host->ioaddr + ESDHC_CAPABILITIES_1); |
||
186 | + else |
||
187 | + value = ioread32(host->ioaddr + reg); |
||
188 | + |
||
189 | ret = esdhc_readl_fixup(host, reg, value); |
||
190 | |||
191 | return ret; |
||
192 | @@ -404,15 +439,25 @@ static int esdhc_of_enable_dma(struct sd |
||
193 | static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host) |
||
194 | { |
||
195 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
||
196 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
||
197 | |||
198 | - return pltfm_host->clock; |
||
199 | + if (esdhc->peripheral_clock) |
||
200 | + return esdhc->peripheral_clock; |
||
201 | + else |
||
202 | + return pltfm_host->clock; |
||
203 | } |
||
204 | |||
205 | static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) |
||
206 | { |
||
207 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
||
208 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
||
209 | + unsigned int clock; |
||
210 | |||
211 | - return pltfm_host->clock / 256 / 16; |
||
212 | + if (esdhc->peripheral_clock) |
||
213 | + clock = esdhc->peripheral_clock; |
||
214 | + else |
||
215 | + clock = pltfm_host->clock; |
||
216 | + return clock / 256 / 16; |
||
217 | } |
||
218 | |||
219 | static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) |
||
220 | @@ -421,12 +466,15 @@ static void esdhc_of_set_clock(struct sd |
||
221 | struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
||
222 | int pre_div = 1; |
||
223 | int div = 1; |
||
224 | + ktime_t timeout; |
||
225 | u32 temp; |
||
226 | |||
227 | host->mmc->actual_clock = 0; |
||
228 | |||
229 | - if (clock == 0) |
||
230 | + if (clock == 0) { |
||
231 | + esdhc_clock_enable(host, false); |
||
232 | return; |
||
233 | + } |
||
234 | |||
235 | /* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */ |
||
236 | if (esdhc->vendor_ver < VENDOR_V_23) |
||
237 | @@ -454,9 +502,15 @@ static void esdhc_of_set_clock(struct sd |
||
238 | clock -= 5000000; |
||
239 | } |
||
240 | |||
241 | + /* Workaround to reduce the clock frequency for ls1021a esdhc */ |
||
242 | + if (of_find_compatible_node(NULL, NULL, "fsl,ls1021a-esdhc")) { |
||
243 | + if (clock == 50000000) |
||
244 | + clock = 46500000; |
||
245 | + } |
||
246 | + |
||
247 | temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); |
||
248 | - temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
||
249 | - | ESDHC_CLOCK_MASK); |
||
250 | + temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | |
||
251 | + ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); |
||
252 | sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); |
||
253 | |||
254 | while (host->max_clk / pre_div / 16 > clock && pre_div < 256) |
||
255 | @@ -476,7 +530,20 @@ static void esdhc_of_set_clock(struct sd |
||
256 | | (div << ESDHC_DIVIDER_SHIFT) |
||
257 | | (pre_div << ESDHC_PREDIV_SHIFT)); |
||
258 | sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); |
||
259 | - mdelay(1); |
||
260 | + |
||
261 | + /* Wait max 20 ms */ |
||
262 | + timeout = ktime_add_ms(ktime_get(), 20); |
||
263 | + while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) { |
||
264 | + if (ktime_after(ktime_get(), timeout)) { |
||
265 | + pr_err("%s: Internal clock never stabilised.\n", |
||
266 | + mmc_hostname(host->mmc)); |
||
267 | + return; |
||
268 | + } |
||
269 | + udelay(10); |
||
270 | + } |
||
271 | + |
||
272 | + temp |= ESDHC_CLOCK_SDCLKEN; |
||
273 | + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); |
||
274 | } |
||
275 | |||
276 | static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) |
||
277 | @@ -501,12 +568,136 @@ static void esdhc_pltfm_set_bus_width(st |
||
278 | sdhci_writel(host, ctrl, ESDHC_PROCTL); |
||
279 | } |
||
280 | |||
281 | +static void esdhc_clock_enable(struct sdhci_host *host, bool enable) |
||
282 | +{ |
||
283 | + u32 val; |
||
284 | + ktime_t timeout; |
||
285 | + |
||
286 | + val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); |
||
287 | + |
||
288 | + if (enable) |
||
289 | + val |= ESDHC_CLOCK_SDCLKEN; |
||
290 | + else |
||
291 | + val &= ~ESDHC_CLOCK_SDCLKEN; |
||
292 | + |
||
293 | + sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL); |
||
294 | + |
||
295 | + /* Wait max 20 ms */ |
||
296 | + timeout = ktime_add_ms(ktime_get(), 20); |
||
297 | + val = ESDHC_CLOCK_STABLE; |
||
298 | + while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) { |
||
299 | + if (ktime_after(ktime_get(), timeout)) { |
||
300 | + pr_err("%s: Internal clock never stabilised.\n", |
||
301 | + mmc_hostname(host->mmc)); |
||
302 | + break; |
||
303 | + } |
||
304 | + udelay(10); |
||
305 | + } |
||
306 | +} |
||
307 | + |
||
308 | static void esdhc_reset(struct sdhci_host *host, u8 mask) |
||
309 | { |
||
310 | + u32 val; |
||
311 | + |
||
312 | sdhci_reset(host, mask); |
||
313 | |||
314 | sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); |
||
315 | sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); |
||
316 | + |
||
317 | + if (mask & SDHCI_RESET_ALL) { |
||
318 | + val = sdhci_readl(host, ESDHC_TBCTL); |
||
319 | + val &= ~ESDHC_TB_EN; |
||
320 | + sdhci_writel(host, val, ESDHC_TBCTL); |
||
321 | + } |
||
322 | +} |
||
323 | + |
||
324 | +/* The SCFG, Supplemental Configuration Unit, provides SoC specific |
||
325 | + * configuration and status registers for the device. There is a |
||
326 | + * SDHC IO VSEL control register on SCFG for some platforms. It's |
||
327 | + * used to support SDHC IO voltage switching. |
||
328 | + */ |
||
329 | +static const struct of_device_id scfg_device_ids[] = { |
||
330 | + { .compatible = "fsl,t1040-scfg", }, |
||
331 | + { .compatible = "fsl,ls1012a-scfg", }, |
||
332 | + { .compatible = "fsl,ls1046a-scfg", }, |
||
333 | + {} |
||
334 | +}; |
||
335 | + |
||
336 | +/* SDHC IO VSEL control register definition */ |
||
337 | +#define SCFG_SDHCIOVSELCR 0x408 |
||
338 | +#define SDHCIOVSELCR_TGLEN 0x80000000 |
||
339 | +#define SDHCIOVSELCR_VSELVAL 0x60000000 |
||
340 | +#define SDHCIOVSELCR_SDHC_VS 0x00000001 |
||
341 | + |
||
342 | +static int esdhc_signal_voltage_switch(struct mmc_host *mmc, |
||
343 | + struct mmc_ios *ios) |
||
344 | +{ |
||
345 | + struct sdhci_host *host = mmc_priv(mmc); |
||
346 | + struct device_node *scfg_node; |
||
347 | + void __iomem *scfg_base = NULL; |
||
348 | + u32 sdhciovselcr; |
||
349 | + u32 val; |
||
350 | + |
||
351 | + /* |
||
352 | + * Signal Voltage Switching is only applicable for Host Controllers |
||
353 | + * v3.00 and above. |
||
354 | + */ |
||
355 | + if (host->version < SDHCI_SPEC_300) |
||
356 | + return 0; |
||
357 | + |
||
358 | + val = sdhci_readl(host, ESDHC_PROCTL); |
||
359 | + |
||
360 | + switch (ios->signal_voltage) { |
||
361 | + case MMC_SIGNAL_VOLTAGE_330: |
||
362 | + val &= ~ESDHC_VOLT_SEL; |
||
363 | + sdhci_writel(host, val, ESDHC_PROCTL); |
||
364 | + return 0; |
||
365 | + case MMC_SIGNAL_VOLTAGE_180: |
||
366 | + scfg_node = of_find_matching_node(NULL, scfg_device_ids); |
||
367 | + if (scfg_node) |
||
368 | + scfg_base = of_iomap(scfg_node, 0); |
||
369 | + if (scfg_base) { |
||
370 | + sdhciovselcr = SDHCIOVSELCR_TGLEN | |
||
371 | + SDHCIOVSELCR_VSELVAL; |
||
372 | + iowrite32be(sdhciovselcr, |
||
373 | + scfg_base + SCFG_SDHCIOVSELCR); |
||
374 | + |
||
375 | + val |= ESDHC_VOLT_SEL; |
||
376 | + sdhci_writel(host, val, ESDHC_PROCTL); |
||
377 | + mdelay(5); |
||
378 | + |
||
379 | + sdhciovselcr = SDHCIOVSELCR_TGLEN | |
||
380 | + SDHCIOVSELCR_SDHC_VS; |
||
381 | + iowrite32be(sdhciovselcr, |
||
382 | + scfg_base + SCFG_SDHCIOVSELCR); |
||
383 | + iounmap(scfg_base); |
||
384 | + } else { |
||
385 | + val |= ESDHC_VOLT_SEL; |
||
386 | + sdhci_writel(host, val, ESDHC_PROCTL); |
||
387 | + } |
||
388 | + return 0; |
||
389 | + default: |
||
390 | + return 0; |
||
391 | + } |
||
392 | +} |
||
393 | + |
||
394 | +static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) |
||
395 | +{ |
||
396 | + struct sdhci_host *host = mmc_priv(mmc); |
||
397 | + u32 val; |
||
398 | + |
||
399 | + /* Use tuning block for tuning procedure */ |
||
400 | + esdhc_clock_enable(host, false); |
||
401 | + val = sdhci_readl(host, ESDHC_DMA_SYSCTL); |
||
402 | + val |= ESDHC_FLUSH_ASYNC_FIFO; |
||
403 | + sdhci_writel(host, val, ESDHC_DMA_SYSCTL); |
||
404 | + |
||
405 | + val = sdhci_readl(host, ESDHC_TBCTL); |
||
406 | + val |= ESDHC_TB_EN; |
||
407 | + sdhci_writel(host, val, ESDHC_TBCTL); |
||
408 | + esdhc_clock_enable(host, true); |
||
409 | + |
||
410 | + return sdhci_execute_tuning(mmc, opcode); |
||
411 | } |
||
412 | |||
413 | #ifdef CONFIG_PM_SLEEP |
||
414 | @@ -589,10 +780,19 @@ static const struct sdhci_pltfm_data sdh |
||
415 | .ops = &sdhci_esdhc_le_ops, |
||
416 | }; |
||
417 | |||
418 | +static struct soc_device_attribute soc_incorrect_hostver[] = { |
||
419 | + { .family = "QorIQ T4240", .revision = "1.0", }, |
||
420 | + { .family = "QorIQ T4240", .revision = "2.0", }, |
||
421 | + { }, |
||
422 | +}; |
||
423 | + |
||
424 | static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) |
||
425 | { |
||
426 | struct sdhci_pltfm_host *pltfm_host; |
||
427 | struct sdhci_esdhc *esdhc; |
||
428 | + struct device_node *np; |
||
429 | + struct clk *clk; |
||
430 | + u32 val; |
||
431 | u16 host_ver; |
||
432 | |||
433 | pltfm_host = sdhci_priv(host); |
||
434 | @@ -602,6 +802,36 @@ static void esdhc_init(struct platform_d |
||
435 | esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >> |
||
436 | SDHCI_VENDOR_VER_SHIFT; |
||
437 | esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK; |
||
438 | + if (soc_device_match(soc_incorrect_hostver)) |
||
439 | + esdhc->quirk_incorrect_hostver = true; |
||
440 | + else |
||
441 | + esdhc->quirk_incorrect_hostver = false; |
||
442 | + |
||
443 | + np = pdev->dev.of_node; |
||
444 | + clk = of_clk_get(np, 0); |
||
445 | + if (!IS_ERR(clk)) { |
||
446 | + /* |
||
447 | + * esdhc->peripheral_clock would be assigned with a value |
||
448 | + * which is eSDHC base clock when use periperal clock. |
||
449 | + * For ls1046a, the clock value got by common clk API is |
||
450 | + * peripheral clock while the eSDHC base clock is 1/2 |
||
451 | + * peripheral clock. |
||
452 | + */ |
||
453 | + if (of_device_is_compatible(np, "fsl,ls1046a-esdhc")) |
||
454 | + esdhc->peripheral_clock = clk_get_rate(clk) / 2; |
||
455 | + else |
||
456 | + esdhc->peripheral_clock = clk_get_rate(clk); |
||
457 | + |
||
458 | + clk_put(clk); |
||
459 | + } |
||
460 | + |
||
461 | + if (esdhc->peripheral_clock) { |
||
462 | + esdhc_clock_enable(host, false); |
||
463 | + val = sdhci_readl(host, ESDHC_DMA_SYSCTL); |
||
464 | + val |= ESDHC_PERIPHERAL_CLK_SEL; |
||
465 | + sdhci_writel(host, val, ESDHC_DMA_SYSCTL); |
||
466 | + esdhc_clock_enable(host, true); |
||
467 | + } |
||
468 | } |
||
469 | |||
470 | static int sdhci_esdhc_probe(struct platform_device *pdev) |
||
471 | @@ -624,6 +854,11 @@ static int sdhci_esdhc_probe(struct plat |
||
472 | if (IS_ERR(host)) |
||
473 | return PTR_ERR(host); |
||
474 | |||
475 | + host->mmc_host_ops.start_signal_voltage_switch = |
||
476 | + esdhc_signal_voltage_switch; |
||
477 | + host->mmc_host_ops.execute_tuning = esdhc_execute_tuning; |
||
478 | + host->tuning_delay = 1; |
||
479 | + |
||
480 | esdhc_init(pdev, host); |
||
481 | |||
482 | sdhci_get_of_property(pdev); |
||
483 | --- a/drivers/mmc/host/sdhci.c |
||
484 | +++ b/drivers/mmc/host/sdhci.c |
||
485 | @@ -1631,26 +1631,24 @@ static void sdhci_set_ios(struct mmc_hos |
||
486 | |||
487 | ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); |
||
488 | |||
489 | - if ((ios->timing == MMC_TIMING_SD_HS || |
||
490 | - ios->timing == MMC_TIMING_MMC_HS) |
||
491 | - && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) |
||
492 | - ctrl |= SDHCI_CTRL_HISPD; |
||
493 | - else |
||
494 | - ctrl &= ~SDHCI_CTRL_HISPD; |
||
495 | + if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) { |
||
496 | + if ((ios->timing == MMC_TIMING_SD_HS || |
||
497 | + ios->timing == MMC_TIMING_MMC_HS || |
||
498 | + ios->timing == MMC_TIMING_MMC_HS400 || |
||
499 | + ios->timing == MMC_TIMING_MMC_HS200 || |
||
500 | + ios->timing == MMC_TIMING_MMC_DDR52 || |
||
501 | + ios->timing == MMC_TIMING_UHS_SDR50 || |
||
502 | + ios->timing == MMC_TIMING_UHS_SDR104 || |
||
503 | + ios->timing == MMC_TIMING_UHS_DDR50 || |
||
504 | + ios->timing == MMC_TIMING_UHS_SDR25)) |
||
505 | + ctrl |= SDHCI_CTRL_HISPD; |
||
506 | + else |
||
507 | + ctrl &= ~SDHCI_CTRL_HISPD; |
||
508 | + } |
||
509 | |||
510 | if (host->version >= SDHCI_SPEC_300) { |
||
511 | u16 clk, ctrl_2; |
||
512 | |||
513 | - /* In case of UHS-I modes, set High Speed Enable */ |
||
514 | - if ((ios->timing == MMC_TIMING_MMC_HS400) || |
||
515 | - (ios->timing == MMC_TIMING_MMC_HS200) || |
||
516 | - (ios->timing == MMC_TIMING_MMC_DDR52) || |
||
517 | - (ios->timing == MMC_TIMING_UHS_SDR50) || |
||
518 | - (ios->timing == MMC_TIMING_UHS_SDR104) || |
||
519 | - (ios->timing == MMC_TIMING_UHS_DDR50) || |
||
520 | - (ios->timing == MMC_TIMING_UHS_SDR25)) |
||
521 | - ctrl |= SDHCI_CTRL_HISPD; |
||
522 | - |
||
523 | if (!host->preset_enabled) { |
||
524 | sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); |
||
525 | /* |
||
526 | @@ -1963,7 +1961,7 @@ static int sdhci_prepare_hs400_tuning(st |
||
527 | return 0; |
||
528 | } |
||
529 | |||
530 | -static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) |
||
531 | +int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) |
||
532 | { |
||
533 | struct sdhci_host *host = mmc_priv(mmc); |
||
534 | u16 ctrl; |
||
535 | @@ -2022,6 +2020,9 @@ static int sdhci_execute_tuning(struct m |
||
536 | return err; |
||
537 | } |
||
538 | |||
539 | + if (host->tuning_delay < 0) |
||
540 | + host->tuning_delay = opcode == MMC_SEND_TUNING_BLOCK; |
||
541 | + |
||
542 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); |
||
543 | ctrl |= SDHCI_CTRL_EXEC_TUNING; |
||
544 | if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND) |
||
545 | @@ -2134,9 +2135,10 @@ static int sdhci_execute_tuning(struct m |
||
546 | |||
547 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); |
||
548 | |||
549 | - /* eMMC spec does not require a delay between tuning cycles */ |
||
550 | - if (opcode == MMC_SEND_TUNING_BLOCK) |
||
551 | - mdelay(1); |
||
552 | + /* Spec does not require a delay between tuning cycles */ |
||
553 | + if (host->tuning_delay > 0) |
||
554 | + mdelay(host->tuning_delay); |
||
555 | + |
||
556 | } while (ctrl & SDHCI_CTRL_EXEC_TUNING); |
||
557 | |||
558 | /* |
||
559 | @@ -2172,6 +2174,7 @@ out_unlock: |
||
560 | spin_unlock_irqrestore(&host->lock, flags); |
||
561 | return err; |
||
562 | } |
||
563 | +EXPORT_SYMBOL_GPL(sdhci_execute_tuning); |
||
564 | |||
565 | static int sdhci_select_drive_strength(struct mmc_card *card, |
||
566 | unsigned int max_dtr, int host_drv, |
||
567 | @@ -3004,6 +3007,8 @@ struct sdhci_host *sdhci_alloc_host(stru |
||
568 | |||
569 | host->flags = SDHCI_SIGNALING_330; |
||
570 | |||
571 | + host->tuning_delay = -1; |
||
572 | + |
||
573 | return host; |
||
574 | } |
||
575 | |||
576 | --- a/drivers/mmc/host/sdhci.h |
||
577 | +++ b/drivers/mmc/host/sdhci.h |
||
578 | @@ -524,6 +524,8 @@ struct sdhci_host { |
||
579 | #define SDHCI_TUNING_MODE_1 0 |
||
580 | #define SDHCI_TUNING_MODE_2 1 |
||
581 | #define SDHCI_TUNING_MODE_3 2 |
||
582 | + /* Delay (ms) between tuning commands */ |
||
583 | + int tuning_delay; |
||
584 | |||
585 | unsigned long private[0] ____cacheline_aligned; |
||
586 | }; |
||
587 | @@ -689,6 +691,7 @@ void sdhci_set_power_noreg(struct sdhci_ |
||
588 | void sdhci_set_bus_width(struct sdhci_host *host, int width); |
||
589 | void sdhci_reset(struct sdhci_host *host, u8 mask); |
||
590 | void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); |
||
591 | +int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); |
||
592 | |||
593 | #ifdef CONFIG_PM |
||
594 | extern int sdhci_suspend_host(struct sdhci_host *host); |