blob: dbdd671c88bcc307029c616bac3f3f22fddca16d [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stefan Roese5b372122015-10-01 17:34:41 +02002/*
3 * Marvell SD Host Controller Interface
Stefan Roese5b372122015-10-01 17:34:41 +02004 */
5
Lei Wene75787d2011-06-28 21:50:07 +00006#include <common.h>
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +02007#include <dm.h>
Lei Wene75787d2011-06-28 21:50:07 +00008#include <malloc.h>
9#include <sdhci.h>
Simon Glass401d1c42020-10-30 21:38:53 -060010#include <asm/global_data.h>
Stefan Roese5b372122015-10-01 17:34:41 +020011#include <linux/mbus.h>
12
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +020013#define MVSDH_NAME "mv_sdh"
14
Stefan Roese5b372122015-10-01 17:34:41 +020015#define SDHCI_WINDOW_CTRL(win) (0x4080 + ((win) << 4))
16#define SDHCI_WINDOW_BASE(win) (0x4084 + ((win) << 4))
17
Stefan Roese8af21b02023-02-10 13:23:52 +010018DECLARE_GLOBAL_DATA_PTR;
19
20struct mv_sdhci_plat {
21 struct mmc_config cfg;
22 struct mmc mmc;
23};
24
Stefan Roese5b372122015-10-01 17:34:41 +020025static 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}
Lei Wene75787d2011-06-28 21:50:07 +000049
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +020050static int mv_sdhci_probe(struct udevice *dev)
51{
52 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
Simon Glassc69cda22020-12-03 16:55:20 -070053 struct mv_sdhci_plat *plat = dev_get_plat(dev);
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +020054 struct sdhci_host *host = dev_get_priv(dev);
55 int ret;
56
57 host->name = MVSDH_NAME;
Masahiro Yamada8613c8d2020-07-17 14:36:46 +090058 host->ioaddr = dev_read_addr_ptr(dev);
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +020059 host->quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD;
Baruch Siach41a9fab2019-07-22 18:55:35 +030060 host->mmc = &plat->mmc;
61 host->mmc->dev = dev;
62 host->mmc->priv = host;
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +020063
Baruch Siach24a0f8c2021-02-02 08:43:04 +020064 ret = mmc_of_parse(dev, &plat->cfg);
65 if (ret)
66 return ret;
67
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +020068 ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
69 if (ret)
70 return ret;
71
Stefan Roese46beaec2023-02-10 13:23:50 +010072 /* Configure SDHCI MBUS mbus bridge windows */
73 sdhci_mvebu_mbus_config(host->ioaddr);
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +020074
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +020075 upriv->mmc = host->mmc;
76
77 return sdhci_probe(dev);
78}
79
80static int mv_sdhci_bind(struct udevice *dev)
81{
Simon Glassc69cda22020-12-03 16:55:20 -070082 struct mv_sdhci_plat *plat = dev_get_plat(dev);
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +020083
84 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
85}
86
87static const struct udevice_id mv_sdhci_ids[] = {
88 { .compatible = "marvell,armada-380-sdhci" },
89 { }
90};
91
92U_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,
Simon Glass41575d82020-12-03 16:55:17 -070099 .priv_auto = sizeof(struct sdhci_host),
Simon Glasscaa4daa2020-12-03 16:55:18 -0700100 .plat_auto = sizeof(struct mv_sdhci_plat),
Pierre Bourdon4ec9dd42019-04-11 04:56:58 +0200101};