blob: 0b265196f025ea147af717ab151e09b760c2a750 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Wenyou Yang11fd15d2015-11-02 10:57:09 +08002/*
3 * Copyright (C) 2015 Atmel Corporation
4 * Wenyou.Yang <wenyou.yang@atmel.com>
Wenyou Yang11fd15d2015-11-02 10:57:09 +08005 */
6
Wenyou Yang83e88a42016-08-10 10:51:05 +08007#include <clk.h>
8#include <dm.h>
Wenyou Yang11fd15d2015-11-02 10:57:09 +08009#include <malloc.h>
10#include <sdhci.h>
11#include <asm/arch/clk.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060012#include <asm/global_data.h>
Wenyou Yang11fd15d2015-11-02 10:57:09 +080013
14#define ATMEL_SDHC_MIN_FREQ 400000
Ludovic Desrochese5a07b82017-11-17 14:51:27 +080015#define ATMEL_SDHC_GCK_RATE 240000000
Wenyou Yang11fd15d2015-11-02 10:57:09 +080016
Zixun LId46f2892023-05-17 15:49:45 +020017#define ATMEL_SDHC_MC1R 0x204
18#define ATMEL_SDHC_MC1R_FCD 0x80
19
Wenyou Yang83e88a42016-08-10 10:51:05 +080020#ifndef CONFIG_DM_MMC
Wenyou Yang11fd15d2015-11-02 10:57:09 +080021int atmel_sdhci_init(void *regbase, u32 id)
22{
23 struct sdhci_host *host;
24 u32 max_clk, min_clk = ATMEL_SDHC_MIN_FREQ;
25
26 host = (struct sdhci_host *)calloc(1, sizeof(struct sdhci_host));
27 if (!host) {
28 printf("%s: sdhci_host calloc failed\n", __func__);
29 return -ENOMEM;
30 }
31
32 host->name = "atmel_sdhci";
33 host->ioaddr = regbase;
Wenyou Yang4fadd972017-05-11 08:25:12 +080034 host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
Wenyou Yang11fd15d2015-11-02 10:57:09 +080035 max_clk = at91_get_periph_generated_clk(id);
36 if (!max_clk) {
37 printf("%s: Failed to get the proper clock\n", __func__);
38 free(host);
39 return -ENODEV;
40 }
Stefan Herbrechtsmeierbc47e0e2017-01-17 15:58:48 +010041 host->max_clk = max_clk;
Wenyou Yang11fd15d2015-11-02 10:57:09 +080042
Stefan Herbrechtsmeierbc47e0e2017-01-17 15:58:48 +010043 add_sdhci(host, 0, min_clk);
Wenyou Yang11fd15d2015-11-02 10:57:09 +080044
45 return 0;
46}
Wenyou Yang83e88a42016-08-10 10:51:05 +080047
48#else
49
50DECLARE_GLOBAL_DATA_PTR;
51
52struct atmel_sdhci_plat {
53 struct mmc_config cfg;
54 struct mmc mmc;
55};
56
Zixun LId46f2892023-05-17 15:49:45 +020057static void atmel_sdhci_config_fcd(struct sdhci_host *host)
58{
59 u8 mc1r;
60
61 /* If nonremovable, assume that the card is always present.
62 *
63 * WA: SAMA5D2 doesn't drive CMD if using CD GPIO line.
64 */
65 if ((host->mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE)
66#if CONFIG_IS_ENABLED(DM_GPIO)
67 || dm_gpio_get_value(&host->cd_gpio) >= 0
68#endif
69 ) {
70 sdhci_readb(host, ATMEL_SDHC_MC1R);
71 mc1r |= ATMEL_SDHC_MC1R_FCD;
72 sdhci_writeb(host, mc1r, ATMEL_SDHC_MC1R);
73 }
74}
75
Sergiu Mogae554c3e2022-06-22 16:30:47 +030076static int atmel_sdhci_deferred_probe(struct sdhci_host *host)
77{
78 struct udevice *dev = host->mmc->dev;
Zixun LId46f2892023-05-17 15:49:45 +020079 int ret;
Sergiu Mogae554c3e2022-06-22 16:30:47 +030080
Zixun LId46f2892023-05-17 15:49:45 +020081 ret = sdhci_probe(dev);
82 if (ret)
83 return ret;
84
85 atmel_sdhci_config_fcd(host);
86
87 return 0;
Sergiu Mogae554c3e2022-06-22 16:30:47 +030088}
89
90static const struct sdhci_ops atmel_sdhci_ops = {
91 .deferred_probe = atmel_sdhci_deferred_probe,
92};
93
Wenyou Yang83e88a42016-08-10 10:51:05 +080094static int atmel_sdhci_probe(struct udevice *dev)
95{
96 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -070097 struct atmel_sdhci_plat *plat = dev_get_plat(dev);
Wenyou Yang83e88a42016-08-10 10:51:05 +080098 struct sdhci_host *host = dev_get_priv(dev);
99 u32 max_clk;
Wenyou Yang83e88a42016-08-10 10:51:05 +0800100 struct clk clk;
101 int ret;
102
Wenyou Yang038dff82016-09-27 11:00:34 +0800103 ret = clk_get_by_index(dev, 0, &clk);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800104 if (ret)
105 return ret;
106
107 ret = clk_enable(&clk);
108 if (ret)
109 return ret;
110
111 host->name = dev->name;
Masahiro Yamada1096ae12020-07-17 14:36:46 +0900112 host->ioaddr = dev_read_addr_ptr(dev);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800113
Wenyou Yang4fadd972017-05-11 08:25:12 +0800114 host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
Simon Glassdd79d6e2017-01-17 16:52:55 -0700115 host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
Wenyou Yang83e88a42016-08-10 10:51:05 +0800116 "bus-width", 4);
117
Wenyou Yang038dff82016-09-27 11:00:34 +0800118 ret = clk_get_by_index(dev, 1, &clk);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800119 if (ret)
120 return ret;
121
Eugen Hristev90805e12020-08-27 12:16:15 +0300122 clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800123
124 max_clk = clk_get_rate(&clk);
125 if (!max_clk)
126 return -EINVAL;
127
Eugen Hristev3110c752020-08-27 12:25:56 +0300128 ret = clk_enable(&clk);
Eugen Hristeva5630512020-11-09 13:02:17 +0200129 /* return error only if the clock really has a clock enable func */
130 if (ret && ret != -ENOSYS)
Eugen Hristev3110c752020-08-27 12:25:56 +0300131 return ret;
132
Eugen Hristev6fb8abf2020-08-27 12:25:57 +0300133 ret = mmc_of_parse(dev, &plat->cfg);
134 if (ret)
135 return ret;
136
Stefan Herbrechtsmeierbc47e0e2017-01-17 15:58:48 +0100137 host->max_clk = max_clk;
Peng Fan9a8f4992019-08-06 02:47:47 +0000138 host->mmc = &plat->mmc;
139 host->mmc->dev = dev;
Stefan Herbrechtsmeierbc47e0e2017-01-17 15:58:48 +0100140
141 ret = sdhci_setup_cfg(&plat->cfg, host, 0, ATMEL_SDHC_MIN_FREQ);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800142 if (ret)
143 return ret;
144
Wenyou Yang83e88a42016-08-10 10:51:05 +0800145 host->mmc->priv = host;
Sergiu Mogae554c3e2022-06-22 16:30:47 +0300146 host->ops = &atmel_sdhci_ops;
Wenyou Yang83e88a42016-08-10 10:51:05 +0800147 upriv->mmc = host->mmc;
148
Zixun LId46f2892023-05-17 15:49:45 +0200149 ret = sdhci_probe(dev);
150 if (ret)
151 return ret;
152
153 atmel_sdhci_config_fcd(host);
154
155 return 0;
Wenyou Yang83e88a42016-08-10 10:51:05 +0800156}
157
158static int atmel_sdhci_bind(struct udevice *dev)
159{
Simon Glassfa20e932020-12-03 16:55:20 -0700160 struct atmel_sdhci_plat *plat = dev_get_plat(dev);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800161
Masahiro Yamadacdb67f32016-09-06 22:17:32 +0900162 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800163}
164
165static const struct udevice_id atmel_sdhci_ids[] = {
166 { .compatible = "atmel,sama5d2-sdhci" },
Sandeep Sheriker Mallikarjuncba5eb62019-09-27 13:08:36 +0000167 { .compatible = "microchip,sam9x60-sdhci" },
Eugen Hristev3e742992020-08-27 12:04:41 +0300168 { .compatible = "microchip,sama7g5-sdhci" },
Wenyou Yang83e88a42016-08-10 10:51:05 +0800169 { }
170};
171
172U_BOOT_DRIVER(atmel_sdhci_drv) = {
173 .name = "atmel_sdhci",
174 .id = UCLASS_MMC,
175 .of_match = atmel_sdhci_ids,
176 .ops = &sdhci_ops,
177 .bind = atmel_sdhci_bind,
178 .probe = atmel_sdhci_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700179 .priv_auto = sizeof(struct sdhci_host),
Simon Glass71fa5b42020-12-03 16:55:18 -0700180 .plat_auto = sizeof(struct atmel_sdhci_plat),
Wenyou Yang83e88a42016-08-10 10:51:05 +0800181};
182#endif