1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Freescale eSDHC ColdFire family controller driver, platform bus. |
4 | * |
5 | * Copyright (c) 2020 Timesys Corporation |
6 | * Author: Angelo Dureghello <angelo.dureghello@timesys.it> |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/platform_data/mmc-esdhc-mcf.h> |
12 | #include <linux/mmc/mmc.h> |
13 | #include "sdhci-pltfm.h" |
14 | #include "sdhci-esdhc.h" |
15 | |
16 | #define ESDHC_PROCTL_D3CD 0x08 |
17 | #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f |
18 | #define ESDHC_DEFAULT_HOST_CONTROL 0x28 |
19 | |
20 | /* |
21 | * Freescale eSDHC has DMA ERR flag at bit 28, not as std spec says, bit 25. |
22 | */ |
23 | #define ESDHC_INT_VENDOR_SPEC_DMA_ERR BIT(28) |
24 | |
25 | struct pltfm_mcf_data { |
26 | struct clk *clk_ipg; |
27 | struct clk *clk_ahb; |
28 | struct clk *clk_per; |
29 | int aside; |
30 | int current_bus_width; |
31 | }; |
32 | |
33 | static inline void esdhc_mcf_buffer_swap32(u32 *buf, int len) |
34 | { |
35 | int i; |
36 | u32 temp; |
37 | |
38 | len = (len + 3) >> 2; |
39 | |
40 | for (i = 0; i < len; i++) { |
41 | temp = swab32(*buf); |
42 | *buf++ = temp; |
43 | } |
44 | } |
45 | |
46 | static inline void esdhc_clrset_be(struct sdhci_host *host, |
47 | u32 mask, u32 val, int reg) |
48 | { |
49 | void __iomem *base = host->ioaddr + (reg & ~3); |
50 | u8 shift = (reg & 3) << 3; |
51 | |
52 | mask <<= shift; |
53 | val <<= shift; |
54 | |
55 | if (reg == SDHCI_HOST_CONTROL) |
56 | val |= ESDHC_PROCTL_D3CD; |
57 | |
58 | writel(val: (readl(addr: base) & ~mask) | val, addr: base); |
59 | } |
60 | |
61 | /* |
62 | * Note: mcf is big-endian, single bytes need to be accessed at big endian |
63 | * offsets. |
64 | */ |
65 | static void esdhc_mcf_writeb_be(struct sdhci_host *host, u8 val, int reg) |
66 | { |
67 | void __iomem *base = host->ioaddr + (reg & ~3); |
68 | u8 shift = (reg & 3) << 3; |
69 | u32 mask = ~(0xff << shift); |
70 | |
71 | if (reg == SDHCI_HOST_CONTROL) { |
72 | u32 host_ctrl = ESDHC_DEFAULT_HOST_CONTROL; |
73 | u8 dma_bits = (val & SDHCI_CTRL_DMA_MASK) >> 3; |
74 | u8 tmp = readb(addr: host->ioaddr + SDHCI_HOST_CONTROL + 1); |
75 | |
76 | tmp &= ~0x03; |
77 | tmp |= dma_bits; |
78 | |
79 | /* |
80 | * Recomposition needed, restore always endianness and |
81 | * keep D3CD and AI, just setting bus width. |
82 | */ |
83 | host_ctrl |= val; |
84 | host_ctrl |= (dma_bits << 8); |
85 | writel(val: host_ctrl, addr: host->ioaddr + SDHCI_HOST_CONTROL); |
86 | |
87 | return; |
88 | } |
89 | |
90 | writel(val: (readl(addr: base) & mask) | (val << shift), addr: base); |
91 | } |
92 | |
93 | static void esdhc_mcf_writew_be(struct sdhci_host *host, u16 val, int reg) |
94 | { |
95 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
96 | struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(host: pltfm_host); |
97 | void __iomem *base = host->ioaddr + (reg & ~3); |
98 | u8 shift = (reg & 3) << 3; |
99 | u32 mask = ~(0xffff << shift); |
100 | |
101 | switch (reg) { |
102 | case SDHCI_TRANSFER_MODE: |
103 | mcf_data->aside = val; |
104 | return; |
105 | case SDHCI_COMMAND: |
106 | if (host->cmd->opcode == MMC_STOP_TRANSMISSION) |
107 | val |= SDHCI_CMD_ABORTCMD; |
108 | |
109 | /* |
110 | * As for the fsl driver, |
111 | * we have to set the mode in a single write here. |
112 | */ |
113 | writel(val: val << 16 | mcf_data->aside, |
114 | addr: host->ioaddr + SDHCI_TRANSFER_MODE); |
115 | return; |
116 | } |
117 | |
118 | writel(val: (readl(addr: base) & mask) | (val << shift), addr: base); |
119 | } |
120 | |
121 | static void esdhc_mcf_writel_be(struct sdhci_host *host, u32 val, int reg) |
122 | { |
123 | writel(val, addr: host->ioaddr + reg); |
124 | } |
125 | |
126 | static u8 esdhc_mcf_readb_be(struct sdhci_host *host, int reg) |
127 | { |
128 | if (reg == SDHCI_HOST_CONTROL) { |
129 | u8 __iomem *base = host->ioaddr + (reg & ~3); |
130 | u16 val = readw(addr: base + 2); |
131 | u8 dma_bits = (val >> 5) & SDHCI_CTRL_DMA_MASK; |
132 | u8 host_ctrl = val & 0xff; |
133 | |
134 | host_ctrl &= ~SDHCI_CTRL_DMA_MASK; |
135 | host_ctrl |= dma_bits; |
136 | |
137 | return host_ctrl; |
138 | } |
139 | |
140 | return readb(addr: host->ioaddr + (reg ^ 0x3)); |
141 | } |
142 | |
143 | static u16 esdhc_mcf_readw_be(struct sdhci_host *host, int reg) |
144 | { |
145 | /* |
146 | * For SDHCI_HOST_VERSION, sdhci specs defines 0xFE, |
147 | * a wrong offset for us, we are at 0xFC. |
148 | */ |
149 | if (reg == SDHCI_HOST_VERSION) |
150 | reg -= 2; |
151 | |
152 | return readw(addr: host->ioaddr + (reg ^ 0x2)); |
153 | } |
154 | |
155 | static u32 esdhc_mcf_readl_be(struct sdhci_host *host, int reg) |
156 | { |
157 | u32 val; |
158 | |
159 | val = readl(addr: host->ioaddr + reg); |
160 | |
161 | /* |
162 | * RM (25.3.9) sd pin clock must never exceed 25Mhz. |
163 | * So forcing legacy mode at 25Mhz. |
164 | */ |
165 | if (unlikely(reg == SDHCI_CAPABILITIES)) |
166 | val &= ~SDHCI_CAN_DO_HISPD; |
167 | |
168 | if (unlikely(reg == SDHCI_INT_STATUS)) { |
169 | if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) { |
170 | val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR; |
171 | val |= SDHCI_INT_ADMA_ERROR; |
172 | } |
173 | } |
174 | |
175 | return val; |
176 | } |
177 | |
178 | static unsigned int esdhc_mcf_get_max_timeout_count(struct sdhci_host *host) |
179 | { |
180 | return 1 << 27; |
181 | } |
182 | |
183 | static void esdhc_mcf_set_timeout(struct sdhci_host *host, |
184 | struct mmc_command *cmd) |
185 | { |
186 | /* Use maximum timeout counter */ |
187 | esdhc_clrset_be(host, ESDHC_SYS_CTRL_DTOCV_MASK, val: 0xE, |
188 | SDHCI_TIMEOUT_CONTROL); |
189 | } |
190 | |
191 | static void esdhc_mcf_reset(struct sdhci_host *host, u8 mask) |
192 | { |
193 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
194 | struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(host: pltfm_host); |
195 | |
196 | sdhci_reset(host, mask); |
197 | |
198 | esdhc_clrset_be(host, ESDHC_CTRL_BUSWIDTH_MASK, |
199 | val: mcf_data->current_bus_width, SDHCI_HOST_CONTROL); |
200 | |
201 | sdhci_writel(host, val: host->ier, SDHCI_INT_ENABLE); |
202 | sdhci_writel(host, val: host->ier, SDHCI_SIGNAL_ENABLE); |
203 | } |
204 | |
205 | static unsigned int esdhc_mcf_pltfm_get_max_clock(struct sdhci_host *host) |
206 | { |
207 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
208 | |
209 | return pltfm_host->clock; |
210 | } |
211 | |
212 | static unsigned int esdhc_mcf_pltfm_get_min_clock(struct sdhci_host *host) |
213 | { |
214 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
215 | |
216 | return pltfm_host->clock / 256 / 16; |
217 | } |
218 | |
219 | static void esdhc_mcf_pltfm_set_clock(struct sdhci_host *host, |
220 | unsigned int clock) |
221 | { |
222 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
223 | unsigned long *pll_dr = (unsigned long *)MCF_PLL_DR; |
224 | u32 fvco, fsys, fesdhc, temp; |
225 | const int sdclkfs[] = {2, 4, 8, 16, 32, 64, 128, 256}; |
226 | int delta, old_delta = clock; |
227 | int i, q, ri, rq; |
228 | |
229 | if (clock == 0) { |
230 | host->mmc->actual_clock = 0; |
231 | return; |
232 | } |
233 | |
234 | /* |
235 | * ColdFire eSDHC clock.s |
236 | * |
237 | * pll -+-> / outdiv1 --> fsys |
238 | * +-> / outdiv3 --> eSDHC clock ---> / SDCCLKFS / DVS |
239 | * |
240 | * mcf5441x datasheet says: |
241 | * (8.1.2) eSDHC should be 40 MHz max |
242 | * (25.3.9) eSDHC input is, as example, 96 Mhz ... |
243 | * (25.3.9) sd pin clock must never exceed 25Mhz |
244 | * |
245 | * fvco = fsys * outdvi1 + 1 |
246 | * fshdc = fvco / outdiv3 + 1 |
247 | */ |
248 | temp = readl(addr: pll_dr); |
249 | fsys = pltfm_host->clock; |
250 | fvco = fsys * ((temp & 0x1f) + 1); |
251 | fesdhc = fvco / (((temp >> 10) & 0x1f) + 1); |
252 | |
253 | for (i = 0; i < 8; ++i) { |
254 | int result = fesdhc / sdclkfs[i]; |
255 | |
256 | for (q = 1; q < 17; ++q) { |
257 | int finale = result / q; |
258 | |
259 | delta = abs(clock - finale); |
260 | |
261 | if (delta < old_delta) { |
262 | old_delta = delta; |
263 | ri = i; |
264 | rq = q; |
265 | } |
266 | } |
267 | } |
268 | |
269 | /* |
270 | * Apply divisors and re-enable all the clocks |
271 | */ |
272 | temp = ((sdclkfs[ri] >> 1) << 8) | ((rq - 1) << 4) | |
273 | (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN); |
274 | esdhc_clrset_be(host, mask: 0x0000fff7, val: temp, SDHCI_CLOCK_CONTROL); |
275 | |
276 | host->mmc->actual_clock = clock; |
277 | |
278 | mdelay(1); |
279 | } |
280 | |
281 | static void esdhc_mcf_pltfm_set_bus_width(struct sdhci_host *host, int width) |
282 | { |
283 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
284 | struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(host: pltfm_host); |
285 | |
286 | switch (width) { |
287 | case MMC_BUS_WIDTH_4: |
288 | mcf_data->current_bus_width = ESDHC_CTRL_4BITBUS; |
289 | break; |
290 | default: |
291 | mcf_data->current_bus_width = 0; |
292 | break; |
293 | } |
294 | |
295 | esdhc_clrset_be(host, ESDHC_CTRL_BUSWIDTH_MASK, |
296 | val: mcf_data->current_bus_width, SDHCI_HOST_CONTROL); |
297 | } |
298 | |
299 | static void esdhc_mcf_request_done(struct sdhci_host *host, |
300 | struct mmc_request *mrq) |
301 | { |
302 | struct sg_mapping_iter sgm; |
303 | u32 *buffer; |
304 | |
305 | if (!mrq->data || !mrq->data->bytes_xfered) |
306 | goto exit_done; |
307 | |
308 | if (mmc_get_dma_dir(data: mrq->data) != DMA_FROM_DEVICE) |
309 | goto exit_done; |
310 | |
311 | /* |
312 | * On mcf5441x there is no hw sdma option/flag to select the dma |
313 | * transfer endiannes. A swap after the transfer is needed. |
314 | */ |
315 | sg_miter_start(miter: &sgm, sgl: mrq->data->sg, nents: mrq->data->sg_len, |
316 | SG_MITER_ATOMIC | SG_MITER_TO_SG | SG_MITER_FROM_SG); |
317 | while (sg_miter_next(miter: &sgm)) { |
318 | buffer = sgm.addr; |
319 | esdhc_mcf_buffer_swap32(buf: buffer, len: sgm.length); |
320 | } |
321 | sg_miter_stop(miter: &sgm); |
322 | |
323 | exit_done: |
324 | mmc_request_done(host->mmc, mrq); |
325 | } |
326 | |
327 | static void esdhc_mcf_copy_to_bounce_buffer(struct sdhci_host *host, |
328 | struct mmc_data *data, |
329 | unsigned int length) |
330 | { |
331 | sg_copy_to_buffer(sgl: data->sg, nents: data->sg_len, |
332 | buf: host->bounce_buffer, buflen: length); |
333 | |
334 | esdhc_mcf_buffer_swap32(buf: (u32 *)host->bounce_buffer, |
335 | len: data->blksz * data->blocks); |
336 | } |
337 | |
338 | static struct sdhci_ops sdhci_esdhc_ops = { |
339 | .reset = esdhc_mcf_reset, |
340 | .set_clock = esdhc_mcf_pltfm_set_clock, |
341 | .get_max_clock = esdhc_mcf_pltfm_get_max_clock, |
342 | .get_min_clock = esdhc_mcf_pltfm_get_min_clock, |
343 | .set_bus_width = esdhc_mcf_pltfm_set_bus_width, |
344 | .get_max_timeout_count = esdhc_mcf_get_max_timeout_count, |
345 | .set_timeout = esdhc_mcf_set_timeout, |
346 | .write_b = esdhc_mcf_writeb_be, |
347 | .write_w = esdhc_mcf_writew_be, |
348 | .write_l = esdhc_mcf_writel_be, |
349 | .read_b = esdhc_mcf_readb_be, |
350 | .read_w = esdhc_mcf_readw_be, |
351 | .read_l = esdhc_mcf_readl_be, |
352 | .copy_to_bounce_buffer = esdhc_mcf_copy_to_bounce_buffer, |
353 | .request_done = esdhc_mcf_request_done, |
354 | }; |
355 | |
356 | static const struct sdhci_pltfm_data sdhci_esdhc_mcf_pdata = { |
357 | .ops = &sdhci_esdhc_ops, |
358 | .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_FORCE_DMA, |
359 | /* |
360 | * Mandatory quirk, |
361 | * controller does not support cmd23, |
362 | * without, on > 8G cards cmd23 is used, and |
363 | * driver times out. |
364 | */ |
365 | SDHCI_QUIRK2_HOST_NO_CMD23, |
366 | }; |
367 | |
368 | static int esdhc_mcf_plat_init(struct sdhci_host *host, |
369 | struct pltfm_mcf_data *mcf_data) |
370 | { |
371 | struct mcf_esdhc_platform_data *plat_data; |
372 | struct device *dev = mmc_dev(host->mmc); |
373 | |
374 | if (!dev->platform_data) { |
375 | dev_err(dev, "no platform data!\n" ); |
376 | return -EINVAL; |
377 | } |
378 | |
379 | plat_data = (struct mcf_esdhc_platform_data *)dev->platform_data; |
380 | |
381 | /* Card_detect */ |
382 | switch (plat_data->cd_type) { |
383 | default: |
384 | case ESDHC_CD_CONTROLLER: |
385 | /* We have a working card_detect back */ |
386 | host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; |
387 | break; |
388 | case ESDHC_CD_PERMANENT: |
389 | host->mmc->caps |= MMC_CAP_NONREMOVABLE; |
390 | break; |
391 | case ESDHC_CD_NONE: |
392 | break; |
393 | } |
394 | |
395 | switch (plat_data->max_bus_width) { |
396 | case 4: |
397 | host->mmc->caps |= MMC_CAP_4_BIT_DATA; |
398 | break; |
399 | case 1: |
400 | default: |
401 | host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; |
402 | break; |
403 | } |
404 | |
405 | return 0; |
406 | } |
407 | |
408 | static int sdhci_esdhc_mcf_probe(struct platform_device *pdev) |
409 | { |
410 | struct sdhci_host *host; |
411 | struct sdhci_pltfm_host *pltfm_host; |
412 | struct pltfm_mcf_data *mcf_data; |
413 | int err; |
414 | |
415 | host = sdhci_pltfm_init(pdev, pdata: &sdhci_esdhc_mcf_pdata, |
416 | priv_size: sizeof(*mcf_data)); |
417 | |
418 | if (IS_ERR(ptr: host)) |
419 | return PTR_ERR(ptr: host); |
420 | |
421 | pltfm_host = sdhci_priv(host); |
422 | mcf_data = sdhci_pltfm_priv(host: pltfm_host); |
423 | |
424 | host->sdma_boundary = 0; |
425 | |
426 | host->flags |= SDHCI_AUTO_CMD12; |
427 | |
428 | mcf_data->clk_ipg = devm_clk_get(dev: &pdev->dev, id: "ipg" ); |
429 | if (IS_ERR(ptr: mcf_data->clk_ipg)) { |
430 | err = PTR_ERR(ptr: mcf_data->clk_ipg); |
431 | goto err_exit; |
432 | } |
433 | |
434 | mcf_data->clk_ahb = devm_clk_get(dev: &pdev->dev, id: "ahb" ); |
435 | if (IS_ERR(ptr: mcf_data->clk_ahb)) { |
436 | err = PTR_ERR(ptr: mcf_data->clk_ahb); |
437 | goto err_exit; |
438 | } |
439 | |
440 | mcf_data->clk_per = devm_clk_get(dev: &pdev->dev, id: "per" ); |
441 | if (IS_ERR(ptr: mcf_data->clk_per)) { |
442 | err = PTR_ERR(ptr: mcf_data->clk_per); |
443 | goto err_exit; |
444 | } |
445 | |
446 | pltfm_host->clk = mcf_data->clk_per; |
447 | pltfm_host->clock = clk_get_rate(clk: pltfm_host->clk); |
448 | err = clk_prepare_enable(clk: mcf_data->clk_per); |
449 | if (err) |
450 | goto err_exit; |
451 | |
452 | err = clk_prepare_enable(clk: mcf_data->clk_ipg); |
453 | if (err) |
454 | goto unprep_per; |
455 | |
456 | err = clk_prepare_enable(clk: mcf_data->clk_ahb); |
457 | if (err) |
458 | goto unprep_ipg; |
459 | |
460 | err = esdhc_mcf_plat_init(host, mcf_data); |
461 | if (err) |
462 | goto unprep_ahb; |
463 | |
464 | err = sdhci_setup_host(host); |
465 | if (err) |
466 | goto unprep_ahb; |
467 | |
468 | if (!host->bounce_buffer) { |
469 | dev_err(&pdev->dev, "bounce buffer not allocated" ); |
470 | err = -ENOMEM; |
471 | goto cleanup; |
472 | } |
473 | |
474 | err = __sdhci_add_host(host); |
475 | if (err) |
476 | goto cleanup; |
477 | |
478 | return 0; |
479 | |
480 | cleanup: |
481 | sdhci_cleanup_host(host); |
482 | unprep_ahb: |
483 | clk_disable_unprepare(clk: mcf_data->clk_ahb); |
484 | unprep_ipg: |
485 | clk_disable_unprepare(clk: mcf_data->clk_ipg); |
486 | unprep_per: |
487 | clk_disable_unprepare(clk: mcf_data->clk_per); |
488 | err_exit: |
489 | sdhci_pltfm_free(pdev); |
490 | |
491 | return err; |
492 | } |
493 | |
494 | static void sdhci_esdhc_mcf_remove(struct platform_device *pdev) |
495 | { |
496 | struct sdhci_host *host = platform_get_drvdata(pdev); |
497 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
498 | struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(host: pltfm_host); |
499 | |
500 | sdhci_remove_host(host, dead: 0); |
501 | |
502 | clk_disable_unprepare(clk: mcf_data->clk_ipg); |
503 | clk_disable_unprepare(clk: mcf_data->clk_ahb); |
504 | clk_disable_unprepare(clk: mcf_data->clk_per); |
505 | |
506 | sdhci_pltfm_free(pdev); |
507 | } |
508 | |
509 | static struct platform_driver sdhci_esdhc_mcf_driver = { |
510 | .driver = { |
511 | .name = "sdhci-esdhc-mcf" , |
512 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
513 | }, |
514 | .probe = sdhci_esdhc_mcf_probe, |
515 | .remove_new = sdhci_esdhc_mcf_remove, |
516 | }; |
517 | |
518 | module_platform_driver(sdhci_esdhc_mcf_driver); |
519 | |
520 | MODULE_DESCRIPTION("SDHCI driver for Freescale ColdFire eSDHC" ); |
521 | MODULE_AUTHOR("Angelo Dureghello <angelo.dureghello@timesys.com>" ); |
522 | MODULE_LICENSE("GPL v2" ); |
523 | |