]>
Commit | Line | Data |
---|---|---|
7657c3a7 AH |
1 | /* |
2 | * Freescale eSDHC controller driver. | |
3 | * | |
f060bc9c | 4 | * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc. |
7657c3a7 AH |
5 | * Copyright (c) 2009 MontaVista Software, Inc. |
6 | * | |
7 | * Authors: Xiaobo Xie <X.Xie@freescale.com> | |
8 | * Anton Vorontsov <avorontsov@ru.mvista.com> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or (at | |
13 | * your option) any later version. | |
14 | */ | |
15 | ||
66b50a00 | 16 | #include <linux/err.h> |
7657c3a7 | 17 | #include <linux/io.h> |
f060bc9c | 18 | #include <linux/of.h> |
7657c3a7 | 19 | #include <linux/delay.h> |
88b47679 | 20 | #include <linux/module.h> |
151ede40 | 21 | #include <linux/sys_soc.h> |
7657c3a7 | 22 | #include <linux/mmc/host.h> |
38576af1 | 23 | #include "sdhci-pltfm.h" |
80872e21 | 24 | #include "sdhci-esdhc.h" |
7657c3a7 | 25 | |
137ccd46 | 26 | #define VENDOR_V_22 0x12 |
a4071fbb | 27 | #define VENDOR_V_23 0x13 |
f4932cfd | 28 | |
29 | struct sdhci_esdhc { | |
30 | u8 vendor_ver; | |
31 | u8 spec_ver; | |
151ede40 | 32 | bool quirk_incorrect_hostver; |
f4932cfd | 33 | }; |
34 | ||
35 | /** | |
36 | * esdhc_read*_fixup - Fixup the value read from incompatible eSDHC register | |
37 | * to make it compatible with SD spec. | |
38 | * | |
39 | * @host: pointer to sdhci_host | |
40 | * @spec_reg: SD spec register address | |
41 | * @value: 32bit eSDHC register value on spec_reg address | |
42 | * | |
43 | * In SD spec, there are 8/16/32/64 bits registers, while all of eSDHC | |
44 | * registers are 32 bits. There are differences in register size, register | |
45 | * address, register function, bit position and function between eSDHC spec | |
46 | * and SD spec. | |
47 | * | |
48 | * Return a fixed up register value | |
49 | */ | |
50 | static u32 esdhc_readl_fixup(struct sdhci_host *host, | |
51 | int spec_reg, u32 value) | |
137ccd46 | 52 | { |
f4932cfd | 53 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
8605e7ae | 54 | struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
137ccd46 JH |
55 | u32 ret; |
56 | ||
137ccd46 JH |
57 | /* |
58 | * The bit of ADMA flag in eSDHC is not compatible with standard | |
59 | * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is | |
60 | * supported by eSDHC. | |
61 | * And for many FSL eSDHC controller, the reset value of field | |
f4932cfd | 62 | * SDHCI_CAN_DO_ADMA1 is 1, but some of them can't support ADMA, |
137ccd46 | 63 | * only these vendor version is greater than 2.2/0x12 support ADMA. |
137ccd46 | 64 | */ |
f4932cfd | 65 | if ((spec_reg == SDHCI_CAPABILITIES) && (value & SDHCI_CAN_DO_ADMA1)) { |
66 | if (esdhc->vendor_ver > VENDOR_V_22) { | |
67 | ret = value | SDHCI_CAN_DO_ADMA2; | |
68 | return ret; | |
69 | } | |
137ccd46 | 70 | } |
b0921d5c MW |
71 | /* |
72 | * The DAT[3:0] line signal levels and the CMD line signal level are | |
73 | * not compatible with standard SDHC register. The line signal levels | |
74 | * DAT[7:0] are at bits 31:24 and the command line signal level is at | |
75 | * bit 23. All other bits are the same as in the standard SDHC | |
76 | * register. | |
77 | */ | |
78 | if (spec_reg == SDHCI_PRESENT_STATE) { | |
79 | ret = value & 0x000fffff; | |
80 | ret |= (value >> 4) & SDHCI_DATA_LVL_MASK; | |
81 | ret |= (value << 1) & SDHCI_CMD_LVL; | |
82 | return ret; | |
83 | } | |
84 | ||
f4932cfd | 85 | ret = value; |
137ccd46 JH |
86 | return ret; |
87 | } | |
88 | ||
f4932cfd | 89 | static u16 esdhc_readw_fixup(struct sdhci_host *host, |
90 | int spec_reg, u32 value) | |
7657c3a7 | 91 | { |
151ede40 | 92 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
93 | struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); | |
7657c3a7 | 94 | u16 ret; |
f4932cfd | 95 | int shift = (spec_reg & 0x2) * 8; |
7657c3a7 | 96 | |
f4932cfd | 97 | if (spec_reg == SDHCI_HOST_VERSION) |
98 | ret = value & 0xffff; | |
7657c3a7 | 99 | else |
f4932cfd | 100 | ret = (value >> shift) & 0xffff; |
151ede40 | 101 | /* Workaround for T4240-R1.0-R2.0 eSDHC which has incorrect |
102 | * vendor version and spec version information. | |
103 | */ | |
104 | if ((spec_reg == SDHCI_HOST_VERSION) && | |
105 | (esdhc->quirk_incorrect_hostver)) | |
106 | ret = (VENDOR_V_23 << SDHCI_VENDOR_VER_SHIFT) | SDHCI_SPEC_200; | |
e51cbc9e X |
107 | return ret; |
108 | } | |
109 | ||
f4932cfd | 110 | static u8 esdhc_readb_fixup(struct sdhci_host *host, |
111 | int spec_reg, u32 value) | |
e51cbc9e | 112 | { |
f4932cfd | 113 | u8 ret; |
114 | u8 dma_bits; | |
115 | int shift = (spec_reg & 0x3) * 8; | |
116 | ||
117 | ret = (value >> shift) & 0xff; | |
ba8c4dc9 RZ |
118 | |
119 | /* | |
120 | * "DMA select" locates at offset 0x28 in SD specification, but on | |
121 | * P5020 or P3041, it locates at 0x29. | |
122 | */ | |
f4932cfd | 123 | if (spec_reg == SDHCI_HOST_CONTROL) { |
ba8c4dc9 | 124 | /* DMA select is 22,23 bits in Protocol Control Register */ |
f4932cfd | 125 | dma_bits = (value >> 5) & SDHCI_CTRL_DMA_MASK; |
ba8c4dc9 RZ |
126 | /* fixup the result */ |
127 | ret &= ~SDHCI_CTRL_DMA_MASK; | |
128 | ret |= dma_bits; | |
129 | } | |
7657c3a7 AH |
130 | return ret; |
131 | } | |
132 | ||
f4932cfd | 133 | /** |
134 | * esdhc_write*_fixup - Fixup the SD spec register value so that it could be | |
135 | * written into eSDHC register. | |
136 | * | |
137 | * @host: pointer to sdhci_host | |
138 | * @spec_reg: SD spec register address | |
139 | * @value: 8/16/32bit SD spec register value that would be written | |
140 | * @old_value: 32bit eSDHC register value on spec_reg address | |
141 | * | |
142 | * In SD spec, there are 8/16/32/64 bits registers, while all of eSDHC | |
143 | * registers are 32 bits. There are differences in register size, register | |
144 | * address, register function, bit position and function between eSDHC spec | |
145 | * and SD spec. | |
146 | * | |
147 | * Return a fixed up register value | |
148 | */ | |
149 | static u32 esdhc_writel_fixup(struct sdhci_host *host, | |
150 | int spec_reg, u32 value, u32 old_value) | |
a4071fbb | 151 | { |
f4932cfd | 152 | u32 ret; |
153 | ||
a4071fbb | 154 | /* |
f4932cfd | 155 | * Enabling IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE] |
156 | * when SYSCTL[RSTD] is set for some special operations. | |
157 | * No any impact on other operation. | |
a4071fbb | 158 | */ |
f4932cfd | 159 | if (spec_reg == SDHCI_INT_ENABLE) |
160 | ret = value | SDHCI_INT_BLK_GAP; | |
161 | else | |
162 | ret = value; | |
163 | ||
164 | return ret; | |
a4071fbb HZ |
165 | } |
166 | ||
f4932cfd | 167 | static u32 esdhc_writew_fixup(struct sdhci_host *host, |
168 | int spec_reg, u16 value, u32 old_value) | |
7657c3a7 | 169 | { |
f4932cfd | 170 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
171 | int shift = (spec_reg & 0x2) * 8; | |
172 | u32 ret; | |
173 | ||
174 | switch (spec_reg) { | |
175 | case SDHCI_TRANSFER_MODE: | |
176 | /* | |
177 | * Postpone this write, we must do it together with a | |
178 | * command write that is down below. Return old value. | |
179 | */ | |
180 | pltfm_host->xfer_mode_shadow = value; | |
181 | return old_value; | |
182 | case SDHCI_COMMAND: | |
183 | ret = (value << 16) | pltfm_host->xfer_mode_shadow; | |
184 | return ret; | |
185 | } | |
186 | ||
187 | ret = old_value & (~(0xffff << shift)); | |
188 | ret |= (value << shift); | |
189 | ||
190 | if (spec_reg == SDHCI_BLOCK_SIZE) { | |
7657c3a7 AH |
191 | /* |
192 | * Two last DMA bits are reserved, and first one is used for | |
193 | * non-standard blksz of 4096 bytes that we don't support | |
194 | * yet. So clear the DMA boundary bits. | |
195 | */ | |
f4932cfd | 196 | ret &= (~SDHCI_MAKE_BLKSZ(0x7, 0)); |
7657c3a7 | 197 | } |
f4932cfd | 198 | return ret; |
7657c3a7 AH |
199 | } |
200 | ||
f4932cfd | 201 | static u32 esdhc_writeb_fixup(struct sdhci_host *host, |
202 | int spec_reg, u8 value, u32 old_value) | |
7657c3a7 | 203 | { |
f4932cfd | 204 | u32 ret; |
205 | u32 dma_bits; | |
206 | u8 tmp; | |
207 | int shift = (spec_reg & 0x3) * 8; | |
208 | ||
9e4703df | 209 | /* |
210 | * eSDHC doesn't have a standard power control register, so we do | |
211 | * nothing here to avoid incorrect operation. | |
212 | */ | |
213 | if (spec_reg == SDHCI_POWER_CONTROL) | |
214 | return old_value; | |
ba8c4dc9 RZ |
215 | /* |
216 | * "DMA select" location is offset 0x28 in SD specification, but on | |
217 | * P5020 or P3041, it's located at 0x29. | |
218 | */ | |
f4932cfd | 219 | if (spec_reg == SDHCI_HOST_CONTROL) { |
dcaff04d OG |
220 | /* |
221 | * If host control register is not standard, exit | |
222 | * this function | |
223 | */ | |
224 | if (host->quirks2 & SDHCI_QUIRK2_BROKEN_HOST_CONTROL) | |
f4932cfd | 225 | return old_value; |
dcaff04d | 226 | |
ba8c4dc9 | 227 | /* DMA select is 22,23 bits in Protocol Control Register */ |
f4932cfd | 228 | dma_bits = (value & SDHCI_CTRL_DMA_MASK) << 5; |
229 | ret = (old_value & (~(SDHCI_CTRL_DMA_MASK << 5))) | dma_bits; | |
230 | tmp = (value & (~SDHCI_CTRL_DMA_MASK)) | | |
231 | (old_value & SDHCI_CTRL_DMA_MASK); | |
232 | ret = (ret & (~0xff)) | tmp; | |
233 | ||
234 | /* Prevent SDHCI core from writing reserved bits (e.g. HISPD) */ | |
235 | ret &= ~ESDHC_HOST_CONTROL_RES; | |
236 | return ret; | |
ba8c4dc9 RZ |
237 | } |
238 | ||
f4932cfd | 239 | ret = (old_value & (~(0xff << shift))) | (value << shift); |
240 | return ret; | |
241 | } | |
242 | ||
243 | static u32 esdhc_be_readl(struct sdhci_host *host, int reg) | |
244 | { | |
245 | u32 ret; | |
246 | u32 value; | |
247 | ||
248 | value = ioread32be(host->ioaddr + reg); | |
249 | ret = esdhc_readl_fixup(host, reg, value); | |
250 | ||
251 | return ret; | |
252 | } | |
253 | ||
254 | static u32 esdhc_le_readl(struct sdhci_host *host, int reg) | |
255 | { | |
256 | u32 ret; | |
257 | u32 value; | |
258 | ||
259 | value = ioread32(host->ioaddr + reg); | |
260 | ret = esdhc_readl_fixup(host, reg, value); | |
261 | ||
262 | return ret; | |
263 | } | |
264 | ||
265 | static u16 esdhc_be_readw(struct sdhci_host *host, int reg) | |
266 | { | |
267 | u16 ret; | |
268 | u32 value; | |
269 | int base = reg & ~0x3; | |
270 | ||
271 | value = ioread32be(host->ioaddr + base); | |
272 | ret = esdhc_readw_fixup(host, reg, value); | |
273 | return ret; | |
274 | } | |
275 | ||
276 | static u16 esdhc_le_readw(struct sdhci_host *host, int reg) | |
277 | { | |
278 | u16 ret; | |
279 | u32 value; | |
280 | int base = reg & ~0x3; | |
281 | ||
282 | value = ioread32(host->ioaddr + base); | |
283 | ret = esdhc_readw_fixup(host, reg, value); | |
284 | return ret; | |
285 | } | |
286 | ||
287 | static u8 esdhc_be_readb(struct sdhci_host *host, int reg) | |
288 | { | |
289 | u8 ret; | |
290 | u32 value; | |
291 | int base = reg & ~0x3; | |
292 | ||
293 | value = ioread32be(host->ioaddr + base); | |
294 | ret = esdhc_readb_fixup(host, reg, value); | |
295 | return ret; | |
296 | } | |
297 | ||
298 | static u8 esdhc_le_readb(struct sdhci_host *host, int reg) | |
299 | { | |
300 | u8 ret; | |
301 | u32 value; | |
302 | int base = reg & ~0x3; | |
303 | ||
304 | value = ioread32(host->ioaddr + base); | |
305 | ret = esdhc_readb_fixup(host, reg, value); | |
306 | return ret; | |
307 | } | |
308 | ||
309 | static void esdhc_be_writel(struct sdhci_host *host, u32 val, int reg) | |
310 | { | |
311 | u32 value; | |
312 | ||
313 | value = esdhc_writel_fixup(host, reg, val, 0); | |
314 | iowrite32be(value, host->ioaddr + reg); | |
315 | } | |
316 | ||
317 | static void esdhc_le_writel(struct sdhci_host *host, u32 val, int reg) | |
318 | { | |
319 | u32 value; | |
320 | ||
321 | value = esdhc_writel_fixup(host, reg, val, 0); | |
322 | iowrite32(value, host->ioaddr + reg); | |
323 | } | |
324 | ||
325 | static void esdhc_be_writew(struct sdhci_host *host, u16 val, int reg) | |
326 | { | |
327 | int base = reg & ~0x3; | |
328 | u32 value; | |
329 | u32 ret; | |
330 | ||
331 | value = ioread32be(host->ioaddr + base); | |
332 | ret = esdhc_writew_fixup(host, reg, val, value); | |
333 | if (reg != SDHCI_TRANSFER_MODE) | |
334 | iowrite32be(ret, host->ioaddr + base); | |
335 | } | |
336 | ||
337 | static void esdhc_le_writew(struct sdhci_host *host, u16 val, int reg) | |
338 | { | |
339 | int base = reg & ~0x3; | |
340 | u32 value; | |
341 | u32 ret; | |
342 | ||
343 | value = ioread32(host->ioaddr + base); | |
344 | ret = esdhc_writew_fixup(host, reg, val, value); | |
345 | if (reg != SDHCI_TRANSFER_MODE) | |
346 | iowrite32(ret, host->ioaddr + base); | |
347 | } | |
348 | ||
349 | static void esdhc_be_writeb(struct sdhci_host *host, u8 val, int reg) | |
350 | { | |
351 | int base = reg & ~0x3; | |
352 | u32 value; | |
353 | u32 ret; | |
354 | ||
355 | value = ioread32be(host->ioaddr + base); | |
356 | ret = esdhc_writeb_fixup(host, reg, val, value); | |
357 | iowrite32be(ret, host->ioaddr + base); | |
358 | } | |
359 | ||
360 | static void esdhc_le_writeb(struct sdhci_host *host, u8 val, int reg) | |
361 | { | |
362 | int base = reg & ~0x3; | |
363 | u32 value; | |
364 | u32 ret; | |
365 | ||
366 | value = ioread32(host->ioaddr + base); | |
367 | ret = esdhc_writeb_fixup(host, reg, val, value); | |
368 | iowrite32(ret, host->ioaddr + base); | |
7657c3a7 AH |
369 | } |
370 | ||
a4071fbb HZ |
371 | /* |
372 | * For Abort or Suspend after Stop at Block Gap, ignore the ADMA | |
373 | * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC]) | |
374 | * and Block Gap Event(IRQSTAT[BGE]) are also set. | |
375 | * For Continue, apply soft reset for data(SYSCTL[RSTD]); | |
376 | * and re-issue the entire read transaction from beginning. | |
377 | */ | |
f4932cfd | 378 | static void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask) |
a4071fbb | 379 | { |
f4932cfd | 380 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
8605e7ae | 381 | struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
a4071fbb HZ |
382 | bool applicable; |
383 | dma_addr_t dmastart; | |
384 | dma_addr_t dmanow; | |
385 | ||
a4071fbb | 386 | applicable = (intmask & SDHCI_INT_DATA_END) && |
f4932cfd | 387 | (intmask & SDHCI_INT_BLK_GAP) && |
388 | (esdhc->vendor_ver == VENDOR_V_23); | |
a4071fbb HZ |
389 | if (!applicable) |
390 | return; | |
391 | ||
392 | host->data->error = 0; | |
393 | dmastart = sg_dma_address(host->data->sg); | |
394 | dmanow = dmastart + host->data->bytes_xfered; | |
395 | /* | |
396 | * Force update to the next DMA block boundary. | |
397 | */ | |
398 | dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) + | |
399 | SDHCI_DEFAULT_BOUNDARY_SIZE; | |
400 | host->data->bytes_xfered = dmanow - dmastart; | |
401 | sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS); | |
402 | } | |
403 | ||
80872e21 | 404 | static int esdhc_of_enable_dma(struct sdhci_host *host) |
7657c3a7 | 405 | { |
f4932cfd | 406 | u32 value; |
407 | ||
408 | value = sdhci_readl(host, ESDHC_DMA_SYSCTL); | |
409 | value |= ESDHC_DMA_SNOOP; | |
410 | sdhci_writel(host, value, ESDHC_DMA_SYSCTL); | |
7657c3a7 AH |
411 | return 0; |
412 | } | |
413 | ||
80872e21 | 414 | static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host) |
7657c3a7 | 415 | { |
e307148f | 416 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
7657c3a7 | 417 | |
e307148f | 418 | return pltfm_host->clock; |
7657c3a7 AH |
419 | } |
420 | ||
80872e21 | 421 | static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) |
7657c3a7 | 422 | { |
e307148f | 423 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
7657c3a7 | 424 | |
e307148f | 425 | return pltfm_host->clock / 256 / 16; |
7657c3a7 AH |
426 | } |
427 | ||
f060bc9c JH |
428 | static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) |
429 | { | |
f4932cfd | 430 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
8605e7ae | 431 | struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
bd455029 | 432 | int pre_div = 1; |
d31fc00a | 433 | int div = 1; |
e87d2db2 | 434 | u32 timeout; |
d31fc00a DA |
435 | u32 temp; |
436 | ||
1650d0c7 RK |
437 | host->mmc->actual_clock = 0; |
438 | ||
d31fc00a | 439 | if (clock == 0) |
373073ef | 440 | return; |
d31fc00a | 441 | |
77bd2f6f | 442 | /* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */ |
f4932cfd | 443 | if (esdhc->vendor_ver < VENDOR_V_23) |
77bd2f6f YL |
444 | pre_div = 2; |
445 | ||
f060bc9c JH |
446 | /* Workaround to reduce the clock frequency for p1010 esdhc */ |
447 | if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { | |
448 | if (clock > 20000000) | |
449 | clock -= 5000000; | |
450 | if (clock > 40000000) | |
451 | clock -= 5000000; | |
452 | } | |
453 | ||
d31fc00a | 454 | temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); |
e87d2db2 | 455 | temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | |
456 | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); | |
d31fc00a DA |
457 | sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); |
458 | ||
459 | while (host->max_clk / pre_div / 16 > clock && pre_div < 256) | |
460 | pre_div *= 2; | |
461 | ||
462 | while (host->max_clk / pre_div / div > clock && div < 16) | |
463 | div++; | |
464 | ||
465 | dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", | |
e76b8559 | 466 | clock, host->max_clk / pre_div / div); |
bd455029 | 467 | host->mmc->actual_clock = host->max_clk / pre_div / div; |
d31fc00a DA |
468 | pre_div >>= 1; |
469 | div--; | |
470 | ||
471 | temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); | |
472 | temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | |
473 | | (div << ESDHC_DIVIDER_SHIFT) | |
474 | | (pre_div << ESDHC_PREDIV_SHIFT)); | |
475 | sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); | |
e87d2db2 | 476 | |
477 | /* Wait max 20 ms */ | |
478 | timeout = 20; | |
479 | while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) { | |
480 | if (timeout == 0) { | |
481 | pr_err("%s: Internal clock never stabilised.\n", | |
482 | mmc_hostname(host->mmc)); | |
483 | return; | |
484 | } | |
485 | timeout--; | |
486 | mdelay(1); | |
487 | } | |
488 | ||
489 | temp |= ESDHC_CLOCK_SDCLKEN; | |
490 | sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); | |
f060bc9c JH |
491 | } |
492 | ||
2317f56c | 493 | static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) |
66b50a00 OG |
494 | { |
495 | u32 ctrl; | |
496 | ||
f4932cfd | 497 | ctrl = sdhci_readl(host, ESDHC_PROCTL); |
498 | ctrl &= (~ESDHC_CTRL_BUSWIDTH_MASK); | |
66b50a00 OG |
499 | switch (width) { |
500 | case MMC_BUS_WIDTH_8: | |
f4932cfd | 501 | ctrl |= ESDHC_CTRL_8BITBUS; |
66b50a00 OG |
502 | break; |
503 | ||
504 | case MMC_BUS_WIDTH_4: | |
f4932cfd | 505 | ctrl |= ESDHC_CTRL_4BITBUS; |
66b50a00 OG |
506 | break; |
507 | ||
508 | default: | |
66b50a00 OG |
509 | break; |
510 | } | |
511 | ||
f4932cfd | 512 | sdhci_writel(host, ctrl, ESDHC_PROCTL); |
66b50a00 OG |
513 | } |
514 | ||
304f0a98 AIB |
515 | static void esdhc_reset(struct sdhci_host *host, u8 mask) |
516 | { | |
517 | sdhci_reset(host, mask); | |
518 | ||
519 | sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); | |
520 | sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); | |
521 | } | |
522 | ||
9e48b336 | 523 | #ifdef CONFIG_PM_SLEEP |
723f7924 RK |
524 | static u32 esdhc_proctl; |
525 | static int esdhc_of_suspend(struct device *dev) | |
526 | { | |
527 | struct sdhci_host *host = dev_get_drvdata(dev); | |
528 | ||
f4932cfd | 529 | esdhc_proctl = sdhci_readl(host, SDHCI_HOST_CONTROL); |
723f7924 RK |
530 | |
531 | return sdhci_suspend_host(host); | |
532 | } | |
533 | ||
06732b84 | 534 | static int esdhc_of_resume(struct device *dev) |
723f7924 RK |
535 | { |
536 | struct sdhci_host *host = dev_get_drvdata(dev); | |
537 | int ret = sdhci_resume_host(host); | |
538 | ||
539 | if (ret == 0) { | |
540 | /* Isn't this already done by sdhci_resume_host() ? --rmk */ | |
541 | esdhc_of_enable_dma(host); | |
f4932cfd | 542 | sdhci_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL); |
723f7924 | 543 | } |
723f7924 RK |
544 | return ret; |
545 | } | |
723f7924 RK |
546 | #endif |
547 | ||
9e48b336 UH |
548 | static SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops, |
549 | esdhc_of_suspend, | |
550 | esdhc_of_resume); | |
551 | ||
f4932cfd | 552 | static const struct sdhci_ops sdhci_esdhc_be_ops = { |
553 | .read_l = esdhc_be_readl, | |
554 | .read_w = esdhc_be_readw, | |
555 | .read_b = esdhc_be_readb, | |
556 | .write_l = esdhc_be_writel, | |
557 | .write_w = esdhc_be_writew, | |
558 | .write_b = esdhc_be_writeb, | |
559 | .set_clock = esdhc_of_set_clock, | |
560 | .enable_dma = esdhc_of_enable_dma, | |
561 | .get_max_clock = esdhc_of_get_max_clock, | |
562 | .get_min_clock = esdhc_of_get_min_clock, | |
563 | .adma_workaround = esdhc_of_adma_workaround, | |
564 | .set_bus_width = esdhc_pltfm_set_bus_width, | |
565 | .reset = esdhc_reset, | |
566 | .set_uhs_signaling = sdhci_set_uhs_signaling, | |
567 | }; | |
568 | ||
569 | static const struct sdhci_ops sdhci_esdhc_le_ops = { | |
570 | .read_l = esdhc_le_readl, | |
571 | .read_w = esdhc_le_readw, | |
572 | .read_b = esdhc_le_readb, | |
573 | .write_l = esdhc_le_writel, | |
574 | .write_w = esdhc_le_writew, | |
575 | .write_b = esdhc_le_writeb, | |
576 | .set_clock = esdhc_of_set_clock, | |
577 | .enable_dma = esdhc_of_enable_dma, | |
578 | .get_max_clock = esdhc_of_get_max_clock, | |
579 | .get_min_clock = esdhc_of_get_min_clock, | |
580 | .adma_workaround = esdhc_of_adma_workaround, | |
581 | .set_bus_width = esdhc_pltfm_set_bus_width, | |
582 | .reset = esdhc_reset, | |
583 | .set_uhs_signaling = sdhci_set_uhs_signaling, | |
584 | }; | |
585 | ||
586 | static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = { | |
e9acc77d | 587 | .quirks = ESDHC_DEFAULT_QUIRKS | |
588 | #ifdef CONFIG_PPC | |
589 | SDHCI_QUIRK_BROKEN_CARD_DETECTION | | |
590 | #endif | |
591 | SDHCI_QUIRK_NO_CARD_NO_RESET | | |
592 | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, | |
f4932cfd | 593 | .ops = &sdhci_esdhc_be_ops, |
594 | }; | |
595 | ||
596 | static const struct sdhci_pltfm_data sdhci_esdhc_le_pdata = { | |
e9acc77d | 597 | .quirks = ESDHC_DEFAULT_QUIRKS | |
598 | SDHCI_QUIRK_NO_CARD_NO_RESET | | |
599 | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, | |
f4932cfd | 600 | .ops = &sdhci_esdhc_le_ops, |
7657c3a7 | 601 | }; |
38576af1 | 602 | |
151ede40 | 603 | static struct soc_device_attribute soc_incorrect_hostver[] = { |
604 | { .family = "QorIQ T4240", .revision = "1.0", }, | |
605 | { .family = "QorIQ T4240", .revision = "2.0", }, | |
606 | { }, | |
607 | }; | |
608 | ||
f4932cfd | 609 | static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) |
610 | { | |
611 | struct sdhci_pltfm_host *pltfm_host; | |
612 | struct sdhci_esdhc *esdhc; | |
613 | u16 host_ver; | |
614 | ||
615 | pltfm_host = sdhci_priv(host); | |
8605e7ae | 616 | esdhc = sdhci_pltfm_priv(pltfm_host); |
f4932cfd | 617 | |
618 | host_ver = sdhci_readw(host, SDHCI_HOST_VERSION); | |
619 | esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >> | |
620 | SDHCI_VENDOR_VER_SHIFT; | |
621 | esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK; | |
151ede40 | 622 | if (soc_device_match(soc_incorrect_hostver)) |
623 | esdhc->quirk_incorrect_hostver = true; | |
624 | else | |
625 | esdhc->quirk_incorrect_hostver = false; | |
f4932cfd | 626 | } |
627 | ||
c3be1efd | 628 | static int sdhci_esdhc_probe(struct platform_device *pdev) |
38576af1 | 629 | { |
66b50a00 | 630 | struct sdhci_host *host; |
dcaff04d | 631 | struct device_node *np; |
1ef5e49e | 632 | struct sdhci_pltfm_host *pltfm_host; |
633 | struct sdhci_esdhc *esdhc; | |
66b50a00 OG |
634 | int ret; |
635 | ||
f4932cfd | 636 | np = pdev->dev.of_node; |
637 | ||
150d4240 | 638 | if (of_property_read_bool(np, "little-endian")) |
8605e7ae JZ |
639 | host = sdhci_pltfm_init(pdev, &sdhci_esdhc_le_pdata, |
640 | sizeof(struct sdhci_esdhc)); | |
f4932cfd | 641 | else |
8605e7ae JZ |
642 | host = sdhci_pltfm_init(pdev, &sdhci_esdhc_be_pdata, |
643 | sizeof(struct sdhci_esdhc)); | |
f4932cfd | 644 | |
66b50a00 OG |
645 | if (IS_ERR(host)) |
646 | return PTR_ERR(host); | |
647 | ||
f4932cfd | 648 | esdhc_init(pdev, host); |
649 | ||
66b50a00 OG |
650 | sdhci_get_of_property(pdev); |
651 | ||
1ef5e49e | 652 | pltfm_host = sdhci_priv(host); |
8605e7ae | 653 | esdhc = sdhci_pltfm_priv(pltfm_host); |
1ef5e49e | 654 | if (esdhc->vendor_ver == VENDOR_V_22) |
655 | host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; | |
656 | ||
657 | if (esdhc->vendor_ver > VENDOR_V_22) | |
658 | host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; | |
659 | ||
74fd5e30 YL |
660 | if (of_device_is_compatible(np, "fsl,p5040-esdhc") || |
661 | of_device_is_compatible(np, "fsl,p5020-esdhc") || | |
662 | of_device_is_compatible(np, "fsl,p4080-esdhc") || | |
663 | of_device_is_compatible(np, "fsl,p1020-esdhc") || | |
e9acc77d | 664 | of_device_is_compatible(np, "fsl,t1040-esdhc")) |
74fd5e30 YL |
665 | host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; |
666 | ||
a22950c8 | 667 | if (of_device_is_compatible(np, "fsl,ls1021a-esdhc")) |
668 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; | |
669 | ||
dcaff04d OG |
670 | if (of_device_is_compatible(np, "fsl,p2020-esdhc")) { |
671 | /* | |
672 | * Freescale messed up with P2020 as it has a non-standard | |
673 | * host control register | |
674 | */ | |
675 | host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL; | |
676 | } | |
677 | ||
66b50a00 | 678 | /* call to generic mmc_of_parse to support additional capabilities */ |
f0991408 UH |
679 | ret = mmc_of_parse(host->mmc); |
680 | if (ret) | |
681 | goto err; | |
682 | ||
490104ac | 683 | mmc_of_parse_voltage(np, &host->ocr_mask); |
66b50a00 OG |
684 | |
685 | ret = sdhci_add_host(host); | |
686 | if (ret) | |
f0991408 | 687 | goto err; |
66b50a00 | 688 | |
f0991408 UH |
689 | return 0; |
690 | err: | |
691 | sdhci_pltfm_free(pdev); | |
66b50a00 | 692 | return ret; |
38576af1 SG |
693 | } |
694 | ||
38576af1 SG |
695 | static const struct of_device_id sdhci_esdhc_of_match[] = { |
696 | { .compatible = "fsl,mpc8379-esdhc" }, | |
697 | { .compatible = "fsl,mpc8536-esdhc" }, | |
698 | { .compatible = "fsl,esdhc" }, | |
699 | { } | |
700 | }; | |
701 | MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match); | |
702 | ||
703 | static struct platform_driver sdhci_esdhc_driver = { | |
704 | .driver = { | |
705 | .name = "sdhci-esdhc", | |
38576af1 | 706 | .of_match_table = sdhci_esdhc_of_match, |
9e48b336 | 707 | .pm = &esdhc_of_dev_pm_ops, |
38576af1 SG |
708 | }, |
709 | .probe = sdhci_esdhc_probe, | |
caebcae9 | 710 | .remove = sdhci_pltfm_unregister, |
38576af1 SG |
711 | }; |
712 | ||
d1f81a64 | 713 | module_platform_driver(sdhci_esdhc_driver); |
38576af1 SG |
714 | |
715 | MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC"); | |
716 | MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, " | |
717 | "Anton Vorontsov <avorontsov@ru.mvista.com>"); | |
718 | MODULE_LICENSE("GPL v2"); |