1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Marvell SD Host Controller Interface
4 */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <malloc.h>
9 #include <sdhci.h>
10 #include <asm/global_data.h>
11 #include <linux/mbus.h>
12
13 #define MVSDH_NAME "mv_sdh"
14
15 #define SDHCI_WINDOW_CTRL(win) (0x4080 + ((win) << 4))
16 #define SDHCI_WINDOW_BASE(win) (0x4084 + ((win) << 4))
17
18 DECLARE_GLOBAL_DATA_PTR;
19
20 struct mv_sdhci_plat {
21 struct mmc_config cfg;
22 struct mmc mmc;
23 };
24
sdhci_mvebu_mbus_config(void __iomem * base)25 static void sdhci_mvebu_mbus_config(void __iomem *base)
26 {
27 const struct mbus_dram_target_info *dram;
28 int i;
29
30 dram = mvebu_mbus_dram_info();
31
32 for (i = 0; i < 4; i++) {
33 writel(0, base + SDHCI_WINDOW_CTRL(i));
34 writel(0, base + SDHCI_WINDOW_BASE(i));
35 }
36
37 for (i = 0; i < dram->num_cs; i++) {
38 const struct mbus_dram_window *cs = dram->cs + i;
39
40 /* Write size, attributes and target id to control register */
41 writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
42 (dram->mbus_dram_target_id << 4) | 1,
43 base + SDHCI_WINDOW_CTRL(i));
44
45 /* Write base address to base register */
46 writel(cs->base, base + SDHCI_WINDOW_BASE(i));
47 }
48 }
49
mv_sdhci_probe(struct udevice * dev)50 static int mv_sdhci_probe(struct udevice *dev)
51 {
52 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
53 struct mv_sdhci_plat *plat = dev_get_plat(dev);
54 struct sdhci_host *host = dev_get_priv(dev);
55 int ret;
56
57 host->name = MVSDH_NAME;
58 host->ioaddr = dev_read_addr_ptr(dev);
59 host->quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD;
60 host->mmc = &plat->mmc;
61 host->mmc->dev = dev;
62 host->mmc->priv = host;
63
64 ret = mmc_of_parse(dev, &plat->cfg);
65 if (ret)
66 return ret;
67
68 ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
69 if (ret)
70 return ret;
71
72 /* Configure SDHCI MBUS mbus bridge windows */
73 sdhci_mvebu_mbus_config(host->ioaddr);
74
75 upriv->mmc = host->mmc;
76
77 return sdhci_probe(dev);
78 }
79
mv_sdhci_bind(struct udevice * dev)80 static int mv_sdhci_bind(struct udevice *dev)
81 {
82 struct mv_sdhci_plat *plat = dev_get_plat(dev);
83
84 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
85 }
86
87 static const struct udevice_id mv_sdhci_ids[] = {
88 { .compatible = "marvell,armada-380-sdhci" },
89 { }
90 };
91
92 U_BOOT_DRIVER(mv_sdhci_drv) = {
93 .name = MVSDH_NAME,
94 .id = UCLASS_MMC,
95 .of_match = mv_sdhci_ids,
96 .bind = mv_sdhci_bind,
97 .probe = mv_sdhci_probe,
98 .ops = &sdhci_ops,
99 .priv_auto = sizeof(struct sdhci_host),
100 .plat_auto = sizeof(struct mv_sdhci_plat),
101 };
102