blob: 2da5334c21f13c1ad93b4154c6dd4c637868cbf0 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stefan Roese207f86e2015-10-01 17:34:41 +02002/*
3 * Marvell SD Host Controller Interface
Stefan Roese207f86e2015-10-01 17:34:41 +02004 */
5
Pierre Bourdonb9af62d2019-04-11 04:56:58 +02006#include <dm.h>
Lei Wen11ebc702011-06-28 21:50:07 +00007#include <malloc.h>
8#include <sdhci.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06009#include <asm/global_data.h>
Stefan Roese207f86e2015-10-01 17:34:41 +020010#include <linux/mbus.h>
11
Pierre Bourdonb9af62d2019-04-11 04:56:58 +020012#define MVSDH_NAME "mv_sdh"
13
Stefan Roese207f86e2015-10-01 17:34:41 +020014#define SDHCI_WINDOW_CTRL(win) (0x4080 + ((win) << 4))
15#define SDHCI_WINDOW_BASE(win) (0x4084 + ((win) << 4))
16
Stefan Roesefb0720b2023-02-10 13:23:52 +010017DECLARE_GLOBAL_DATA_PTR;
18
19struct mv_sdhci_plat {
20 struct mmc_config cfg;
21 struct mmc mmc;
22};
23
Stefan Roese207f86e2015-10-01 17:34:41 +020024static void sdhci_mvebu_mbus_config(void __iomem *base)
25{
26 const struct mbus_dram_target_info *dram;
27 int i;
28
29 dram = mvebu_mbus_dram_info();
30
31 for (i = 0; i < 4; i++) {
32 writel(0, base + SDHCI_WINDOW_CTRL(i));
33 writel(0, base + SDHCI_WINDOW_BASE(i));
34 }
35
36 for (i = 0; i < dram->num_cs; i++) {
37 const struct mbus_dram_window *cs = dram->cs + i;
38
39 /* Write size, attributes and target id to control register */
40 writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
41 (dram->mbus_dram_target_id << 4) | 1,
42 base + SDHCI_WINDOW_CTRL(i));
43
44 /* Write base address to base register */
45 writel(cs->base, base + SDHCI_WINDOW_BASE(i));
46 }
47}
Lei Wen11ebc702011-06-28 21:50:07 +000048
Pierre Bourdonb9af62d2019-04-11 04:56:58 +020049static int mv_sdhci_probe(struct udevice *dev)
50{
51 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -070052 struct mv_sdhci_plat *plat = dev_get_plat(dev);
Pierre Bourdonb9af62d2019-04-11 04:56:58 +020053 struct sdhci_host *host = dev_get_priv(dev);
54 int ret;
55
56 host->name = MVSDH_NAME;
Masahiro Yamada1096ae12020-07-17 14:36:46 +090057 host->ioaddr = dev_read_addr_ptr(dev);
Pierre Bourdonb9af62d2019-04-11 04:56:58 +020058 host->quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD;
Baruch Siachcddbfd42019-07-22 18:55:35 +030059 host->mmc = &plat->mmc;
60 host->mmc->dev = dev;
61 host->mmc->priv = host;
Pierre Bourdonb9af62d2019-04-11 04:56:58 +020062
Baruch Siach8a9cddd2021-02-02 08:43:04 +020063 ret = mmc_of_parse(dev, &plat->cfg);
64 if (ret)
65 return ret;
66
Pierre Bourdonb9af62d2019-04-11 04:56:58 +020067 ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
68 if (ret)
69 return ret;
70
Stefan Roese99c8d532023-02-10 13:23:50 +010071 /* Configure SDHCI MBUS mbus bridge windows */
72 sdhci_mvebu_mbus_config(host->ioaddr);
Pierre Bourdonb9af62d2019-04-11 04:56:58 +020073
Pierre Bourdonb9af62d2019-04-11 04:56:58 +020074 upriv->mmc = host->mmc;
75
76 return sdhci_probe(dev);
77}
78
79static int mv_sdhci_bind(struct udevice *dev)
80{
Simon Glassfa20e932020-12-03 16:55:20 -070081 struct mv_sdhci_plat *plat = dev_get_plat(dev);
Pierre Bourdonb9af62d2019-04-11 04:56:58 +020082
83 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
84}
85
86static const struct udevice_id mv_sdhci_ids[] = {
87 { .compatible = "marvell,armada-380-sdhci" },
88 { }
89};
90
91U_BOOT_DRIVER(mv_sdhci_drv) = {
92 .name = MVSDH_NAME,
93 .id = UCLASS_MMC,
94 .of_match = mv_sdhci_ids,
95 .bind = mv_sdhci_bind,
96 .probe = mv_sdhci_probe,
97 .ops = &sdhci_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -070098 .priv_auto = sizeof(struct sdhci_host),
Simon Glass71fa5b42020-12-03 16:55:18 -070099 .plat_auto = sizeof(struct mv_sdhci_plat),
Pierre Bourdonb9af62d2019-04-11 04:56:58 +0200100};