]> Git Repo - J-linux.git/blob - drivers/mmc/host/sdhci-of-aspeed.c
Merge tag 'trace-v5.13-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[J-linux.git] / drivers / mmc / host / sdhci-of-aspeed.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Copyright (C) 2019 ASPEED Technology Inc. */
3 /* Copyright (C) 2019 IBM Corp. */
4
5 #include <linux/clk.h>
6 #include <linux/delay.h>
7 #include <linux/device.h>
8 #include <linux/io.h>
9 #include <linux/math64.h>
10 #include <linux/mmc/host.h>
11 #include <linux/module.h>
12 #include <linux/of_address.h>
13 #include <linux/of.h>
14 #include <linux/of_platform.h>
15 #include <linux/platform_device.h>
16 #include <linux/spinlock.h>
17
18 #include "sdhci-pltfm.h"
19
20 #define ASPEED_SDC_INFO                 0x00
21 #define   ASPEED_SDC_S1_MMC8            BIT(25)
22 #define   ASPEED_SDC_S0_MMC8            BIT(24)
23 #define ASPEED_SDC_PHASE                0xf4
24 #define   ASPEED_SDC_S1_PHASE_IN        GENMASK(25, 21)
25 #define   ASPEED_SDC_S0_PHASE_IN        GENMASK(20, 16)
26 #define   ASPEED_SDC_S1_PHASE_OUT       GENMASK(15, 11)
27 #define   ASPEED_SDC_S1_PHASE_IN_EN     BIT(10)
28 #define   ASPEED_SDC_S1_PHASE_OUT_EN    GENMASK(9, 8)
29 #define   ASPEED_SDC_S0_PHASE_OUT       GENMASK(7, 3)
30 #define   ASPEED_SDC_S0_PHASE_IN_EN     BIT(2)
31 #define   ASPEED_SDC_S0_PHASE_OUT_EN    GENMASK(1, 0)
32 #define   ASPEED_SDC_PHASE_MAX          31
33
34 struct aspeed_sdc {
35         struct clk *clk;
36         struct resource *res;
37
38         spinlock_t lock;
39         void __iomem *regs;
40 };
41
42 struct aspeed_sdhci_tap_param {
43         bool valid;
44
45 #define ASPEED_SDHCI_TAP_PARAM_INVERT_CLK       BIT(4)
46         u8 in;
47         u8 out;
48 };
49
50 struct aspeed_sdhci_tap_desc {
51         u32 tap_mask;
52         u32 enable_mask;
53         u8 enable_value;
54 };
55
56 struct aspeed_sdhci_phase_desc {
57         struct aspeed_sdhci_tap_desc in;
58         struct aspeed_sdhci_tap_desc out;
59 };
60
61 struct aspeed_sdhci_pdata {
62         unsigned int clk_div_start;
63         const struct aspeed_sdhci_phase_desc *phase_desc;
64         size_t nr_phase_descs;
65 };
66
67 struct aspeed_sdhci {
68         const struct aspeed_sdhci_pdata *pdata;
69         struct aspeed_sdc *parent;
70         u32 width_mask;
71         struct mmc_clk_phase_map phase_map;
72         const struct aspeed_sdhci_phase_desc *phase_desc;
73 };
74
75 static void aspeed_sdc_configure_8bit_mode(struct aspeed_sdc *sdc,
76                                            struct aspeed_sdhci *sdhci,
77                                            bool bus8)
78 {
79         u32 info;
80
81         /* Set/clear 8 bit mode */
82         spin_lock(&sdc->lock);
83         info = readl(sdc->regs + ASPEED_SDC_INFO);
84         if (bus8)
85                 info |= sdhci->width_mask;
86         else
87                 info &= ~sdhci->width_mask;
88         writel(info, sdc->regs + ASPEED_SDC_INFO);
89         spin_unlock(&sdc->lock);
90 }
91
92 static u32
93 aspeed_sdc_set_phase_tap(const struct aspeed_sdhci_tap_desc *desc,
94                          u8 tap, bool enable, u32 reg)
95 {
96         reg &= ~(desc->enable_mask | desc->tap_mask);
97         if (enable) {
98                 reg |= tap << __ffs(desc->tap_mask);
99                 reg |= desc->enable_value << __ffs(desc->enable_mask);
100         }
101
102         return reg;
103 }
104
105 static void
106 aspeed_sdc_set_phase_taps(struct aspeed_sdc *sdc,
107                           const struct aspeed_sdhci_phase_desc *desc,
108                           const struct aspeed_sdhci_tap_param *taps)
109 {
110         u32 reg;
111
112         spin_lock(&sdc->lock);
113         reg = readl(sdc->regs + ASPEED_SDC_PHASE);
114
115         reg = aspeed_sdc_set_phase_tap(&desc->in, taps->in, taps->valid, reg);
116         reg = aspeed_sdc_set_phase_tap(&desc->out, taps->out, taps->valid, reg);
117
118         writel(reg, sdc->regs + ASPEED_SDC_PHASE);
119         spin_unlock(&sdc->lock);
120 }
121
122 #define PICOSECONDS_PER_SECOND          1000000000000ULL
123 #define ASPEED_SDHCI_NR_TAPS            15
124 /* Measured value with *handwave* environmentals and static loading */
125 #define ASPEED_SDHCI_MAX_TAP_DELAY_PS   1253
126 static int aspeed_sdhci_phase_to_tap(struct device *dev, unsigned long rate_hz,
127                                      int phase_deg)
128 {
129         u64 phase_period_ps;
130         u64 prop_delay_ps;
131         u64 clk_period_ps;
132         unsigned int tap;
133         u8 inverted;
134
135         phase_deg %= 360;
136
137         if (phase_deg >= 180) {
138                 inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK;
139                 phase_deg -= 180;
140                 dev_dbg(dev,
141                         "Inverting clock to reduce phase correction from %d to %d degrees\n",
142                         phase_deg + 180, phase_deg);
143         } else {
144                 inverted = 0;
145         }
146
147         prop_delay_ps = ASPEED_SDHCI_MAX_TAP_DELAY_PS / ASPEED_SDHCI_NR_TAPS;
148         clk_period_ps = div_u64(PICOSECONDS_PER_SECOND, (u64)rate_hz);
149         phase_period_ps = div_u64((u64)phase_deg * clk_period_ps, 360ULL);
150
151         tap = div_u64(phase_period_ps, prop_delay_ps);
152         if (tap > ASPEED_SDHCI_NR_TAPS) {
153                 dev_warn(dev,
154                          "Requested out of range phase tap %d for %d degrees of phase compensation at %luHz, clamping to tap %d\n",
155                          tap, phase_deg, rate_hz, ASPEED_SDHCI_NR_TAPS);
156                 tap = ASPEED_SDHCI_NR_TAPS;
157         }
158
159         return inverted | tap;
160 }
161
162 static void
163 aspeed_sdhci_phases_to_taps(struct device *dev, unsigned long rate,
164                             const struct mmc_clk_phase *phases,
165                             struct aspeed_sdhci_tap_param *taps)
166 {
167         taps->valid = phases->valid;
168
169         if (!phases->valid)
170                 return;
171
172         taps->in = aspeed_sdhci_phase_to_tap(dev, rate, phases->in_deg);
173         taps->out = aspeed_sdhci_phase_to_tap(dev, rate, phases->out_deg);
174 }
175
176 static void
177 aspeed_sdhci_configure_phase(struct sdhci_host *host, unsigned long rate)
178 {
179         struct aspeed_sdhci_tap_param _taps = {0}, *taps = &_taps;
180         struct mmc_clk_phase *params;
181         struct aspeed_sdhci *sdhci;
182         struct device *dev;
183
184         dev = mmc_dev(host->mmc);
185         sdhci = sdhci_pltfm_priv(sdhci_priv(host));
186
187         if (!sdhci->phase_desc)
188                 return;
189
190         params = &sdhci->phase_map.phase[host->timing];
191         aspeed_sdhci_phases_to_taps(dev, rate, params, taps);
192         aspeed_sdc_set_phase_taps(sdhci->parent, sdhci->phase_desc, taps);
193         dev_dbg(dev,
194                 "Using taps [%d, %d] for [%d, %d] degrees of phase correction at %luHz (%d)\n",
195                 taps->in & ASPEED_SDHCI_NR_TAPS,
196                 taps->out & ASPEED_SDHCI_NR_TAPS,
197                 params->in_deg, params->out_deg, rate, host->timing);
198 }
199
200 static void aspeed_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
201 {
202         struct sdhci_pltfm_host *pltfm_host;
203         unsigned long parent, bus;
204         struct aspeed_sdhci *sdhci;
205         int div;
206         u16 clk;
207
208         pltfm_host = sdhci_priv(host);
209         sdhci = sdhci_pltfm_priv(pltfm_host);
210
211         parent = clk_get_rate(pltfm_host->clk);
212
213         sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
214
215         if (clock == 0)
216                 return;
217
218         if (WARN_ON(clock > host->max_clk))
219                 clock = host->max_clk;
220
221         /*
222          * Regarding the AST2600:
223          *
224          * If (EMMC12C[7:6], EMMC12C[15:8] == 0) then
225          *   period of SDCLK = period of SDMCLK.
226          *
227          * If (EMMC12C[7:6], EMMC12C[15:8] != 0) then
228          *   period of SDCLK = period of SDMCLK * 2 * (EMMC12C[7:6], EMMC[15:8])
229          *
230          * If you keep EMMC12C[7:6] = 0 and EMMC12C[15:8] as one-hot,
231          * 0x1/0x2/0x4/etc, you will find it is compatible to AST2400 or AST2500
232          *
233          * Keep the one-hot behaviour for backwards compatibility except for
234          * supporting the value 0 in (EMMC12C[7:6], EMMC12C[15:8]), and capture
235          * the 0-value capability in clk_div_start.
236          */
237         for (div = sdhci->pdata->clk_div_start; div < 256; div *= 2) {
238                 bus = parent / div;
239                 if (bus <= clock)
240                         break;
241         }
242
243         div >>= 1;
244
245         clk = div << SDHCI_DIVIDER_SHIFT;
246
247         aspeed_sdhci_configure_phase(host, bus);
248
249         sdhci_enable_clk(host, clk);
250 }
251
252 static unsigned int aspeed_sdhci_get_max_clock(struct sdhci_host *host)
253 {
254         if (host->mmc->f_max)
255                 return host->mmc->f_max;
256
257         return sdhci_pltfm_clk_get_max_clock(host);
258 }
259
260 static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width)
261 {
262         struct sdhci_pltfm_host *pltfm_priv;
263         struct aspeed_sdhci *aspeed_sdhci;
264         struct aspeed_sdc *aspeed_sdc;
265         u8 ctrl;
266
267         pltfm_priv = sdhci_priv(host);
268         aspeed_sdhci = sdhci_pltfm_priv(pltfm_priv);
269         aspeed_sdc = aspeed_sdhci->parent;
270
271         /* Set/clear 8-bit mode */
272         aspeed_sdc_configure_8bit_mode(aspeed_sdc, aspeed_sdhci,
273                                        width == MMC_BUS_WIDTH_8);
274
275         /* Set/clear 1 or 4 bit mode */
276         ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
277         if (width == MMC_BUS_WIDTH_4)
278                 ctrl |= SDHCI_CTRL_4BITBUS;
279         else
280                 ctrl &= ~SDHCI_CTRL_4BITBUS;
281         sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
282 }
283
284 static u32 aspeed_sdhci_readl(struct sdhci_host *host, int reg)
285 {
286         u32 val = readl(host->ioaddr + reg);
287
288         if (unlikely(reg == SDHCI_PRESENT_STATE) &&
289             (host->mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH))
290                 val ^= SDHCI_CARD_PRESENT;
291
292         return val;
293 }
294
295 static const struct sdhci_ops aspeed_sdhci_ops = {
296         .read_l = aspeed_sdhci_readl,
297         .set_clock = aspeed_sdhci_set_clock,
298         .get_max_clock = aspeed_sdhci_get_max_clock,
299         .set_bus_width = aspeed_sdhci_set_bus_width,
300         .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
301         .reset = sdhci_reset,
302         .set_uhs_signaling = sdhci_set_uhs_signaling,
303 };
304
305 static const struct sdhci_pltfm_data aspeed_sdhci_pdata = {
306         .ops = &aspeed_sdhci_ops,
307         .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
308 };
309
310 static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci *dev,
311                                               struct resource *res)
312 {
313         resource_size_t delta;
314
315         if (!res || resource_type(res) != IORESOURCE_MEM)
316                 return -EINVAL;
317
318         if (res->start < dev->parent->res->start)
319                 return -EINVAL;
320
321         delta = res->start - dev->parent->res->start;
322         if (delta & (0x100 - 1))
323                 return -EINVAL;
324
325         return (delta / 0x100) - 1;
326 }
327
328 static int aspeed_sdhci_probe(struct platform_device *pdev)
329 {
330         const struct aspeed_sdhci_pdata *aspeed_pdata;
331         struct sdhci_pltfm_host *pltfm_host;
332         struct aspeed_sdhci *dev;
333         struct sdhci_host *host;
334         struct resource *res;
335         int slot;
336         int ret;
337
338         aspeed_pdata = of_device_get_match_data(&pdev->dev);
339         if (!aspeed_pdata) {
340                 dev_err(&pdev->dev, "Missing platform configuration data\n");
341                 return -EINVAL;
342         }
343
344         host = sdhci_pltfm_init(pdev, &aspeed_sdhci_pdata, sizeof(*dev));
345         if (IS_ERR(host))
346                 return PTR_ERR(host);
347
348         pltfm_host = sdhci_priv(host);
349         dev = sdhci_pltfm_priv(pltfm_host);
350         dev->pdata = aspeed_pdata;
351         dev->parent = dev_get_drvdata(pdev->dev.parent);
352
353         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
354         slot = aspeed_sdhci_calculate_slot(dev, res);
355
356         if (slot < 0)
357                 return slot;
358         else if (slot >= 2)
359                 return -EINVAL;
360
361         if (slot < dev->pdata->nr_phase_descs) {
362                 dev->phase_desc = &dev->pdata->phase_desc[slot];
363         } else {
364                 dev_info(&pdev->dev,
365                          "Phase control not supported for slot %d\n", slot);
366                 dev->phase_desc = NULL;
367         }
368
369         dev->width_mask = !slot ? ASPEED_SDC_S0_MMC8 : ASPEED_SDC_S1_MMC8;
370
371         dev_info(&pdev->dev, "Configured for slot %d\n", slot);
372
373         sdhci_get_of_property(pdev);
374
375         pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
376         if (IS_ERR(pltfm_host->clk))
377                 return PTR_ERR(pltfm_host->clk);
378
379         ret = clk_prepare_enable(pltfm_host->clk);
380         if (ret) {
381                 dev_err(&pdev->dev, "Unable to enable SDIO clock\n");
382                 goto err_pltfm_free;
383         }
384
385         ret = mmc_of_parse(host->mmc);
386         if (ret)
387                 goto err_sdhci_add;
388
389         if (dev->phase_desc)
390                 mmc_of_parse_clk_phase(host->mmc, &dev->phase_map);
391
392         ret = sdhci_add_host(host);
393         if (ret)
394                 goto err_sdhci_add;
395
396         return 0;
397
398 err_sdhci_add:
399         clk_disable_unprepare(pltfm_host->clk);
400 err_pltfm_free:
401         sdhci_pltfm_free(pdev);
402         return ret;
403 }
404
405 static int aspeed_sdhci_remove(struct platform_device *pdev)
406 {
407         struct sdhci_pltfm_host *pltfm_host;
408         struct sdhci_host *host;
409         int dead = 0;
410
411         host = platform_get_drvdata(pdev);
412         pltfm_host = sdhci_priv(host);
413
414         sdhci_remove_host(host, dead);
415
416         clk_disable_unprepare(pltfm_host->clk);
417
418         sdhci_pltfm_free(pdev);
419
420         return 0;
421 }
422
423 static const struct aspeed_sdhci_pdata ast2400_sdhci_pdata = {
424         .clk_div_start = 2,
425 };
426
427 static const struct aspeed_sdhci_phase_desc ast2600_sdhci_phase[] = {
428         /* SDHCI/Slot 0 */
429         [0] = {
430                 .in = {
431                         .tap_mask = ASPEED_SDC_S0_PHASE_IN,
432                         .enable_mask = ASPEED_SDC_S0_PHASE_IN_EN,
433                         .enable_value = 1,
434                 },
435                 .out = {
436                         .tap_mask = ASPEED_SDC_S0_PHASE_OUT,
437                         .enable_mask = ASPEED_SDC_S0_PHASE_OUT_EN,
438                         .enable_value = 3,
439                 },
440         },
441         /* SDHCI/Slot 1 */
442         [1] = {
443                 .in = {
444                         .tap_mask = ASPEED_SDC_S1_PHASE_IN,
445                         .enable_mask = ASPEED_SDC_S1_PHASE_IN_EN,
446                         .enable_value = 1,
447                 },
448                 .out = {
449                         .tap_mask = ASPEED_SDC_S1_PHASE_OUT,
450                         .enable_mask = ASPEED_SDC_S1_PHASE_OUT_EN,
451                         .enable_value = 3,
452                 },
453         },
454 };
455
456 static const struct aspeed_sdhci_pdata ast2600_sdhci_pdata = {
457         .clk_div_start = 1,
458         .phase_desc = ast2600_sdhci_phase,
459         .nr_phase_descs = ARRAY_SIZE(ast2600_sdhci_phase),
460 };
461
462 static const struct of_device_id aspeed_sdhci_of_match[] = {
463         { .compatible = "aspeed,ast2400-sdhci", .data = &ast2400_sdhci_pdata, },
464         { .compatible = "aspeed,ast2500-sdhci", .data = &ast2400_sdhci_pdata, },
465         { .compatible = "aspeed,ast2600-sdhci", .data = &ast2600_sdhci_pdata, },
466         { }
467 };
468
469 static struct platform_driver aspeed_sdhci_driver = {
470         .driver         = {
471                 .name   = "sdhci-aspeed",
472                 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
473                 .of_match_table = aspeed_sdhci_of_match,
474         },
475         .probe          = aspeed_sdhci_probe,
476         .remove         = aspeed_sdhci_remove,
477 };
478
479 static int aspeed_sdc_probe(struct platform_device *pdev)
480
481 {
482         struct device_node *parent, *child;
483         struct aspeed_sdc *sdc;
484         int ret;
485
486         sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL);
487         if (!sdc)
488                 return -ENOMEM;
489
490         spin_lock_init(&sdc->lock);
491
492         sdc->clk = devm_clk_get(&pdev->dev, NULL);
493         if (IS_ERR(sdc->clk))
494                 return PTR_ERR(sdc->clk);
495
496         ret = clk_prepare_enable(sdc->clk);
497         if (ret) {
498                 dev_err(&pdev->dev, "Unable to enable SDCLK\n");
499                 return ret;
500         }
501
502         sdc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
503         sdc->regs = devm_ioremap_resource(&pdev->dev, sdc->res);
504         if (IS_ERR(sdc->regs)) {
505                 ret = PTR_ERR(sdc->regs);
506                 goto err_clk;
507         }
508
509         dev_set_drvdata(&pdev->dev, sdc);
510
511         parent = pdev->dev.of_node;
512         for_each_available_child_of_node(parent, child) {
513                 struct platform_device *cpdev;
514
515                 cpdev = of_platform_device_create(child, NULL, &pdev->dev);
516                 if (!cpdev) {
517                         of_node_put(child);
518                         ret = -ENODEV;
519                         goto err_clk;
520                 }
521         }
522
523         return 0;
524
525 err_clk:
526         clk_disable_unprepare(sdc->clk);
527         return ret;
528 }
529
530 static int aspeed_sdc_remove(struct platform_device *pdev)
531 {
532         struct aspeed_sdc *sdc = dev_get_drvdata(&pdev->dev);
533
534         clk_disable_unprepare(sdc->clk);
535
536         return 0;
537 }
538
539 static const struct of_device_id aspeed_sdc_of_match[] = {
540         { .compatible = "aspeed,ast2400-sd-controller", },
541         { .compatible = "aspeed,ast2500-sd-controller", },
542         { .compatible = "aspeed,ast2600-sd-controller", },
543         { }
544 };
545
546 MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match);
547
548 static struct platform_driver aspeed_sdc_driver = {
549         .driver         = {
550                 .name   = "sd-controller-aspeed",
551                 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
552                 .pm     = &sdhci_pltfm_pmops,
553                 .of_match_table = aspeed_sdc_of_match,
554         },
555         .probe          = aspeed_sdc_probe,
556         .remove         = aspeed_sdc_remove,
557 };
558
559 #if defined(CONFIG_MMC_SDHCI_OF_ASPEED_TEST)
560 #include "sdhci-of-aspeed-test.c"
561
562 static inline int aspeed_sdc_tests_init(void)
563 {
564         return __kunit_test_suites_init(aspeed_sdc_test_suites);
565 }
566
567 static inline void aspeed_sdc_tests_exit(void)
568 {
569         __kunit_test_suites_exit(aspeed_sdc_test_suites);
570 }
571 #else
572 static inline int aspeed_sdc_tests_init(void)
573 {
574         return 0;
575 }
576
577 static inline void aspeed_sdc_tests_exit(void)
578 {
579 }
580 #endif
581
582 static int __init aspeed_sdc_init(void)
583 {
584         int rc;
585
586         rc = platform_driver_register(&aspeed_sdhci_driver);
587         if (rc < 0)
588                 return rc;
589
590         rc = platform_driver_register(&aspeed_sdc_driver);
591         if (rc < 0)
592                 goto cleanup_sdhci;
593
594         rc = aspeed_sdc_tests_init();
595         if (rc < 0) {
596                 platform_driver_unregister(&aspeed_sdc_driver);
597                 goto cleanup_sdhci;
598         }
599
600         return 0;
601
602 cleanup_sdhci:
603         platform_driver_unregister(&aspeed_sdhci_driver);
604
605         return rc;
606 }
607 module_init(aspeed_sdc_init);
608
609 static void __exit aspeed_sdc_exit(void)
610 {
611         aspeed_sdc_tests_exit();
612
613         platform_driver_unregister(&aspeed_sdc_driver);
614         platform_driver_unregister(&aspeed_sdhci_driver);
615 }
616 module_exit(aspeed_sdc_exit);
617
618 MODULE_DESCRIPTION("Driver for the ASPEED SD/SDIO/SDHCI Controllers");
619 MODULE_AUTHOR("Ryan Chen <[email protected]>");
620 MODULE_AUTHOR("Andrew Jeffery <[email protected]>");
621 MODULE_LICENSE("GPL");
This page took 0.065449 seconds and 4 git commands to generate.