1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Copyright (C) 2019 ASPEED Technology Inc. */
3 /* Copyright (C) 2019 IBM Corp. */
6 #include <linux/delay.h>
7 #include <linux/device.h>
9 #include <linux/math64.h>
10 #include <linux/mmc/host.h>
11 #include <linux/module.h>
12 #include <linux/of_address.h>
14 #include <linux/of_platform.h>
15 #include <linux/platform_device.h>
16 #include <linux/spinlock.h>
18 #include "sdhci-pltfm.h"
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
35 #define ASPEED_SDC_CAP1_1_8V (0 * 32 + 26)
37 #define ASPEED_SDC_CAP2_SDR104 (1 * 32 + 1)
47 struct aspeed_sdhci_tap_param
{
50 #define ASPEED_SDHCI_TAP_PARAM_INVERT_CLK BIT(4)
55 struct aspeed_sdhci_tap_desc
{
61 struct aspeed_sdhci_phase_desc
{
62 struct aspeed_sdhci_tap_desc in
;
63 struct aspeed_sdhci_tap_desc out
;
66 struct aspeed_sdhci_pdata
{
67 unsigned int clk_div_start
;
68 const struct aspeed_sdhci_phase_desc
*phase_desc
;
69 size_t nr_phase_descs
;
73 const struct aspeed_sdhci_pdata
*pdata
;
74 struct aspeed_sdc
*parent
;
76 struct mmc_clk_phase_map phase_map
;
77 const struct aspeed_sdhci_phase_desc
*phase_desc
;
81 * The function sets the mirror register for updating
82 * capbilities of the current slot.
84 * slot | capability | caps_reg | mirror_reg
85 * -----|-------------|----------|------------
86 * 0 | CAP1_1_8V | SDIO140 | SDIO10
87 * 0 | CAP2_SDR104 | SDIO144 | SDIO14
88 * 1 | CAP1_1_8V | SDIO240 | SDIO20
89 * 1 | CAP2_SDR104 | SDIO244 | SDIO24
91 static void aspeed_sdc_set_slot_capability(struct sdhci_host
*host
, struct aspeed_sdc
*sdc
,
92 int capability
, bool enable
, u8 slot
)
94 u32 mirror_reg_offset
;
101 cap_reg
= capability
/ 32;
102 cap_val
= sdhci_readl(host
, 0x40 + (cap_reg
* 4));
104 cap_val
|= BIT(capability
% 32);
106 cap_val
&= ~BIT(capability
% 32);
107 mirror_reg_offset
= ((slot
+ 1) * 0x10) + (cap_reg
* 4);
108 writel(cap_val
, sdc
->regs
+ mirror_reg_offset
);
111 static void aspeed_sdc_configure_8bit_mode(struct aspeed_sdc
*sdc
,
112 struct aspeed_sdhci
*sdhci
,
117 /* Set/clear 8 bit mode */
118 spin_lock(&sdc
->lock
);
119 info
= readl(sdc
->regs
+ ASPEED_SDC_INFO
);
121 info
|= sdhci
->width_mask
;
123 info
&= ~sdhci
->width_mask
;
124 writel(info
, sdc
->regs
+ ASPEED_SDC_INFO
);
125 spin_unlock(&sdc
->lock
);
129 aspeed_sdc_set_phase_tap(const struct aspeed_sdhci_tap_desc
*desc
,
130 u8 tap
, bool enable
, u32 reg
)
132 reg
&= ~(desc
->enable_mask
| desc
->tap_mask
);
134 reg
|= tap
<< __ffs(desc
->tap_mask
);
135 reg
|= desc
->enable_value
<< __ffs(desc
->enable_mask
);
142 aspeed_sdc_set_phase_taps(struct aspeed_sdc
*sdc
,
143 const struct aspeed_sdhci_phase_desc
*desc
,
144 const struct aspeed_sdhci_tap_param
*taps
)
148 spin_lock(&sdc
->lock
);
149 reg
= readl(sdc
->regs
+ ASPEED_SDC_PHASE
);
151 reg
= aspeed_sdc_set_phase_tap(&desc
->in
, taps
->in
, taps
->valid
, reg
);
152 reg
= aspeed_sdc_set_phase_tap(&desc
->out
, taps
->out
, taps
->valid
, reg
);
154 writel(reg
, sdc
->regs
+ ASPEED_SDC_PHASE
);
155 spin_unlock(&sdc
->lock
);
158 #define PICOSECONDS_PER_SECOND 1000000000000ULL
159 #define ASPEED_SDHCI_NR_TAPS 15
160 /* Measured value with *handwave* environmentals and static loading */
161 #define ASPEED_SDHCI_MAX_TAP_DELAY_PS 1253
162 static int aspeed_sdhci_phase_to_tap(struct device
*dev
, unsigned long rate_hz
,
173 if (phase_deg
>= 180) {
174 inverted
= ASPEED_SDHCI_TAP_PARAM_INVERT_CLK
;
177 "Inverting clock to reduce phase correction from %d to %d degrees\n",
178 phase_deg
+ 180, phase_deg
);
183 prop_delay_ps
= ASPEED_SDHCI_MAX_TAP_DELAY_PS
/ ASPEED_SDHCI_NR_TAPS
;
184 clk_period_ps
= div_u64(PICOSECONDS_PER_SECOND
, (u64
)rate_hz
);
185 phase_period_ps
= div_u64((u64
)phase_deg
* clk_period_ps
, 360ULL);
187 tap
= div_u64(phase_period_ps
, prop_delay_ps
);
188 if (tap
> ASPEED_SDHCI_NR_TAPS
) {
190 "Requested out of range phase tap %d for %d degrees of phase compensation at %luHz, clamping to tap %d\n",
191 tap
, phase_deg
, rate_hz
, ASPEED_SDHCI_NR_TAPS
);
192 tap
= ASPEED_SDHCI_NR_TAPS
;
195 return inverted
| tap
;
199 aspeed_sdhci_phases_to_taps(struct device
*dev
, unsigned long rate
,
200 const struct mmc_clk_phase
*phases
,
201 struct aspeed_sdhci_tap_param
*taps
)
203 taps
->valid
= phases
->valid
;
208 taps
->in
= aspeed_sdhci_phase_to_tap(dev
, rate
, phases
->in_deg
);
209 taps
->out
= aspeed_sdhci_phase_to_tap(dev
, rate
, phases
->out_deg
);
213 aspeed_sdhci_configure_phase(struct sdhci_host
*host
, unsigned long rate
)
215 struct aspeed_sdhci_tap_param _taps
= {0}, *taps
= &_taps
;
216 struct mmc_clk_phase
*params
;
217 struct aspeed_sdhci
*sdhci
;
220 dev
= mmc_dev(host
->mmc
);
221 sdhci
= sdhci_pltfm_priv(sdhci_priv(host
));
223 if (!sdhci
->phase_desc
)
226 params
= &sdhci
->phase_map
.phase
[host
->timing
];
227 aspeed_sdhci_phases_to_taps(dev
, rate
, params
, taps
);
228 aspeed_sdc_set_phase_taps(sdhci
->parent
, sdhci
->phase_desc
, taps
);
230 "Using taps [%d, %d] for [%d, %d] degrees of phase correction at %luHz (%d)\n",
231 taps
->in
& ASPEED_SDHCI_NR_TAPS
,
232 taps
->out
& ASPEED_SDHCI_NR_TAPS
,
233 params
->in_deg
, params
->out_deg
, rate
, host
->timing
);
236 static void aspeed_sdhci_set_clock(struct sdhci_host
*host
, unsigned int clock
)
238 struct sdhci_pltfm_host
*pltfm_host
;
239 unsigned long parent
, bus
;
240 struct aspeed_sdhci
*sdhci
;
244 pltfm_host
= sdhci_priv(host
);
245 sdhci
= sdhci_pltfm_priv(pltfm_host
);
247 parent
= clk_get_rate(pltfm_host
->clk
);
249 sdhci_writew(host
, 0, SDHCI_CLOCK_CONTROL
);
254 if (WARN_ON(clock
> host
->max_clk
))
255 clock
= host
->max_clk
;
258 * Regarding the AST2600:
260 * If (EMMC12C[7:6], EMMC12C[15:8] == 0) then
261 * period of SDCLK = period of SDMCLK.
263 * If (EMMC12C[7:6], EMMC12C[15:8] != 0) then
264 * period of SDCLK = period of SDMCLK * 2 * (EMMC12C[7:6], EMMC[15:8])
266 * If you keep EMMC12C[7:6] = 0 and EMMC12C[15:8] as one-hot,
267 * 0x1/0x2/0x4/etc, you will find it is compatible to AST2400 or AST2500
269 * Keep the one-hot behaviour for backwards compatibility except for
270 * supporting the value 0 in (EMMC12C[7:6], EMMC12C[15:8]), and capture
271 * the 0-value capability in clk_div_start.
273 for (div
= sdhci
->pdata
->clk_div_start
; div
< 256; div
*= 2) {
281 clk
= div
<< SDHCI_DIVIDER_SHIFT
;
283 aspeed_sdhci_configure_phase(host
, bus
);
285 sdhci_enable_clk(host
, clk
);
288 static unsigned int aspeed_sdhci_get_max_clock(struct sdhci_host
*host
)
290 if (host
->mmc
->f_max
)
291 return host
->mmc
->f_max
;
293 return sdhci_pltfm_clk_get_max_clock(host
);
296 static void aspeed_sdhci_set_bus_width(struct sdhci_host
*host
, int width
)
298 struct sdhci_pltfm_host
*pltfm_priv
;
299 struct aspeed_sdhci
*aspeed_sdhci
;
300 struct aspeed_sdc
*aspeed_sdc
;
303 pltfm_priv
= sdhci_priv(host
);
304 aspeed_sdhci
= sdhci_pltfm_priv(pltfm_priv
);
305 aspeed_sdc
= aspeed_sdhci
->parent
;
307 /* Set/clear 8-bit mode */
308 aspeed_sdc_configure_8bit_mode(aspeed_sdc
, aspeed_sdhci
,
309 width
== MMC_BUS_WIDTH_8
);
311 /* Set/clear 1 or 4 bit mode */
312 ctrl
= sdhci_readb(host
, SDHCI_HOST_CONTROL
);
313 if (width
== MMC_BUS_WIDTH_4
)
314 ctrl
|= SDHCI_CTRL_4BITBUS
;
316 ctrl
&= ~SDHCI_CTRL_4BITBUS
;
317 sdhci_writeb(host
, ctrl
, SDHCI_HOST_CONTROL
);
320 static u32
aspeed_sdhci_readl(struct sdhci_host
*host
, int reg
)
322 u32 val
= readl(host
->ioaddr
+ reg
);
324 if (unlikely(reg
== SDHCI_PRESENT_STATE
) &&
325 (host
->mmc
->caps2
& MMC_CAP2_CD_ACTIVE_HIGH
))
326 val
^= SDHCI_CARD_PRESENT
;
331 static const struct sdhci_ops aspeed_sdhci_ops
= {
332 .read_l
= aspeed_sdhci_readl
,
333 .set_clock
= aspeed_sdhci_set_clock
,
334 .get_max_clock
= aspeed_sdhci_get_max_clock
,
335 .set_bus_width
= aspeed_sdhci_set_bus_width
,
336 .get_timeout_clock
= sdhci_pltfm_clk_get_max_clock
,
337 .reset
= sdhci_reset
,
338 .set_uhs_signaling
= sdhci_set_uhs_signaling
,
341 static const struct sdhci_pltfm_data aspeed_sdhci_pdata
= {
342 .ops
= &aspeed_sdhci_ops
,
343 .quirks
= SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN
,
346 static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci
*dev
,
347 struct resource
*res
)
349 resource_size_t delta
;
351 if (!res
|| resource_type(res
) != IORESOURCE_MEM
)
354 if (res
->start
< dev
->parent
->res
->start
)
357 delta
= res
->start
- dev
->parent
->res
->start
;
358 if (delta
& (0x100 - 1))
361 return (delta
/ 0x100) - 1;
364 static int aspeed_sdhci_probe(struct platform_device
*pdev
)
366 const struct aspeed_sdhci_pdata
*aspeed_pdata
;
367 struct device_node
*np
= pdev
->dev
.of_node
;
368 struct sdhci_pltfm_host
*pltfm_host
;
369 struct aspeed_sdhci
*dev
;
370 struct sdhci_host
*host
;
371 struct resource
*res
;
375 aspeed_pdata
= of_device_get_match_data(&pdev
->dev
);
377 dev_err(&pdev
->dev
, "Missing platform configuration data\n");
381 host
= sdhci_pltfm_init(pdev
, &aspeed_sdhci_pdata
, sizeof(*dev
));
383 return PTR_ERR(host
);
385 pltfm_host
= sdhci_priv(host
);
386 dev
= sdhci_pltfm_priv(pltfm_host
);
387 dev
->pdata
= aspeed_pdata
;
388 dev
->parent
= dev_get_drvdata(pdev
->dev
.parent
);
390 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
391 slot
= aspeed_sdhci_calculate_slot(dev
, res
);
398 if (slot
< dev
->pdata
->nr_phase_descs
) {
399 dev
->phase_desc
= &dev
->pdata
->phase_desc
[slot
];
402 "Phase control not supported for slot %d\n", slot
);
403 dev
->phase_desc
= NULL
;
406 dev
->width_mask
= !slot
? ASPEED_SDC_S0_MMC8
: ASPEED_SDC_S1_MMC8
;
408 dev_info(&pdev
->dev
, "Configured for slot %d\n", slot
);
410 sdhci_get_of_property(pdev
);
412 if (of_property_read_bool(np
, "mmc-hs200-1_8v") ||
413 of_property_read_bool(np
, "sd-uhs-sdr104")) {
414 aspeed_sdc_set_slot_capability(host
, dev
->parent
, ASPEED_SDC_CAP1_1_8V
,
418 if (of_property_read_bool(np
, "sd-uhs-sdr104")) {
419 aspeed_sdc_set_slot_capability(host
, dev
->parent
, ASPEED_SDC_CAP2_SDR104
,
423 pltfm_host
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
424 if (IS_ERR(pltfm_host
->clk
))
425 return PTR_ERR(pltfm_host
->clk
);
427 ret
= clk_prepare_enable(pltfm_host
->clk
);
429 dev_err(&pdev
->dev
, "Unable to enable SDIO clock\n");
433 ret
= mmc_of_parse(host
->mmc
);
438 mmc_of_parse_clk_phase(&pdev
->dev
, &dev
->phase_map
);
440 ret
= sdhci_add_host(host
);
447 clk_disable_unprepare(pltfm_host
->clk
);
449 sdhci_pltfm_free(pdev
);
453 static void aspeed_sdhci_remove(struct platform_device
*pdev
)
455 struct sdhci_pltfm_host
*pltfm_host
;
456 struct sdhci_host
*host
;
458 host
= platform_get_drvdata(pdev
);
459 pltfm_host
= sdhci_priv(host
);
461 sdhci_remove_host(host
, 0);
463 clk_disable_unprepare(pltfm_host
->clk
);
465 sdhci_pltfm_free(pdev
);
468 static const struct aspeed_sdhci_pdata ast2400_sdhci_pdata
= {
472 static const struct aspeed_sdhci_phase_desc ast2600_sdhci_phase
[] = {
476 .tap_mask
= ASPEED_SDC_S0_PHASE_IN
,
477 .enable_mask
= ASPEED_SDC_S0_PHASE_IN_EN
,
481 .tap_mask
= ASPEED_SDC_S0_PHASE_OUT
,
482 .enable_mask
= ASPEED_SDC_S0_PHASE_OUT_EN
,
489 .tap_mask
= ASPEED_SDC_S1_PHASE_IN
,
490 .enable_mask
= ASPEED_SDC_S1_PHASE_IN_EN
,
494 .tap_mask
= ASPEED_SDC_S1_PHASE_OUT
,
495 .enable_mask
= ASPEED_SDC_S1_PHASE_OUT_EN
,
501 static const struct aspeed_sdhci_pdata ast2600_sdhci_pdata
= {
503 .phase_desc
= ast2600_sdhci_phase
,
504 .nr_phase_descs
= ARRAY_SIZE(ast2600_sdhci_phase
),
507 static const struct of_device_id aspeed_sdhci_of_match
[] = {
508 { .compatible
= "aspeed,ast2400-sdhci", .data
= &ast2400_sdhci_pdata
, },
509 { .compatible
= "aspeed,ast2500-sdhci", .data
= &ast2400_sdhci_pdata
, },
510 { .compatible
= "aspeed,ast2600-sdhci", .data
= &ast2600_sdhci_pdata
, },
513 MODULE_DEVICE_TABLE(of
, aspeed_sdhci_of_match
);
515 static struct platform_driver aspeed_sdhci_driver
= {
517 .name
= "sdhci-aspeed",
518 .probe_type
= PROBE_PREFER_ASYNCHRONOUS
,
519 .of_match_table
= aspeed_sdhci_of_match
,
521 .probe
= aspeed_sdhci_probe
,
522 .remove
= aspeed_sdhci_remove
,
525 static int aspeed_sdc_probe(struct platform_device
*pdev
)
528 struct device_node
*parent
, *child
;
529 struct aspeed_sdc
*sdc
;
532 sdc
= devm_kzalloc(&pdev
->dev
, sizeof(*sdc
), GFP_KERNEL
);
536 spin_lock_init(&sdc
->lock
);
538 sdc
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
539 if (IS_ERR(sdc
->clk
))
540 return PTR_ERR(sdc
->clk
);
542 ret
= clk_prepare_enable(sdc
->clk
);
544 dev_err(&pdev
->dev
, "Unable to enable SDCLK\n");
548 sdc
->regs
= devm_platform_get_and_ioremap_resource(pdev
, 0, &sdc
->res
);
549 if (IS_ERR(sdc
->regs
)) {
550 ret
= PTR_ERR(sdc
->regs
);
554 dev_set_drvdata(&pdev
->dev
, sdc
);
556 parent
= pdev
->dev
.of_node
;
557 for_each_available_child_of_node(parent
, child
) {
558 struct platform_device
*cpdev
;
560 cpdev
= of_platform_device_create(child
, NULL
, &pdev
->dev
);
571 clk_disable_unprepare(sdc
->clk
);
575 static void aspeed_sdc_remove(struct platform_device
*pdev
)
577 struct aspeed_sdc
*sdc
= dev_get_drvdata(&pdev
->dev
);
579 clk_disable_unprepare(sdc
->clk
);
582 static const struct of_device_id aspeed_sdc_of_match
[] = {
583 { .compatible
= "aspeed,ast2400-sd-controller", },
584 { .compatible
= "aspeed,ast2500-sd-controller", },
585 { .compatible
= "aspeed,ast2600-sd-controller", },
589 MODULE_DEVICE_TABLE(of
, aspeed_sdc_of_match
);
591 static struct platform_driver aspeed_sdc_driver
= {
593 .name
= "sd-controller-aspeed",
594 .probe_type
= PROBE_PREFER_ASYNCHRONOUS
,
595 .pm
= &sdhci_pltfm_pmops
,
596 .of_match_table
= aspeed_sdc_of_match
,
598 .probe
= aspeed_sdc_probe
,
599 .remove
= aspeed_sdc_remove
,
602 #if defined(CONFIG_MMC_SDHCI_OF_ASPEED_TEST)
603 #include "sdhci-of-aspeed-test.c"
606 static int __init
aspeed_sdc_init(void)
610 rc
= platform_driver_register(&aspeed_sdhci_driver
);
614 rc
= platform_driver_register(&aspeed_sdc_driver
);
616 platform_driver_unregister(&aspeed_sdhci_driver
);
620 module_init(aspeed_sdc_init
);
622 static void __exit
aspeed_sdc_exit(void)
624 platform_driver_unregister(&aspeed_sdc_driver
);
625 platform_driver_unregister(&aspeed_sdhci_driver
);
627 module_exit(aspeed_sdc_exit
);
629 MODULE_DESCRIPTION("Driver for the ASPEED SD/SDIO/SDHCI Controllers");
630 MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
631 MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
632 MODULE_LICENSE("GPL");