blob: d92bad97b71e9c2964ca969a1b54704e3c8bfca4 [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
7#include <common.h>
Wenyou Yang83e88a42016-08-10 10:51:05 +08008#include <clk.h>
9#include <dm.h>
Wenyou Yang11fd15d2015-11-02 10:57:09 +080010#include <malloc.h>
11#include <sdhci.h>
12#include <asm/arch/clk.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060013#include <asm/global_data.h>
Wenyou Yang11fd15d2015-11-02 10:57:09 +080014
15#define ATMEL_SDHC_MIN_FREQ 400000
Ludovic Desrochese5a07b82017-11-17 14:51:27 +080016#define ATMEL_SDHC_GCK_RATE 240000000
Wenyou Yang11fd15d2015-11-02 10:57:09 +080017
Zixun LId46f2892023-05-17 15:49:45 +020018#define ATMEL_SDHC_MC1R 0x204
19#define ATMEL_SDHC_MC1R_FCD 0x80
20
Wenyou Yang83e88a42016-08-10 10:51:05 +080021#ifndef CONFIG_DM_MMC
Wenyou Yang11fd15d2015-11-02 10:57:09 +080022int atmel_sdhci_init(void *regbase, u32 id)
23{
24 struct sdhci_host *host;
25 u32 max_clk, min_clk = ATMEL_SDHC_MIN_FREQ;
26
27 host = (struct sdhci_host *)calloc(1, sizeof(struct sdhci_host));
28 if (!host) {
29 printf("%s: sdhci_host calloc failed\n", __func__);
30 return -ENOMEM;
31 }
32
33 host->name = "atmel_sdhci";
34 host->ioaddr = regbase;
Wenyou Yang4fadd972017-05-11 08:25:12 +080035 host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
Wenyou Yang11fd15d2015-11-02 10:57:09 +080036 max_clk = at91_get_periph_generated_clk(id);
37 if (!max_clk) {
38 printf("%s: Failed to get the proper clock\n", __func__);
39 free(host);
40 return -ENODEV;
41 }
Stefan Herbrechtsmeierbc47e0e2017-01-17 15:58:48 +010042 host->max_clk = max_clk;
Wenyou Yang11fd15d2015-11-02 10:57:09 +080043
Stefan Herbrechtsmeierbc47e0e2017-01-17 15:58:48 +010044 add_sdhci(host, 0, min_clk);
Wenyou Yang11fd15d2015-11-02 10:57:09 +080045
46 return 0;
47}
Wenyou Yang83e88a42016-08-10 10:51:05 +080048
49#else
50
51DECLARE_GLOBAL_DATA_PTR;
52
53struct atmel_sdhci_plat {
54 struct mmc_config cfg;
55 struct mmc mmc;
56};
57
Zixun LId46f2892023-05-17 15:49:45 +020058static void atmel_sdhci_config_fcd(struct sdhci_host *host)
59{
60 u8 mc1r;
61
62 /* If nonremovable, assume that the card is always present.
63 *
64 * WA: SAMA5D2 doesn't drive CMD if using CD GPIO line.
65 */
66 if ((host->mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE)
67#if CONFIG_IS_ENABLED(DM_GPIO)
68 || dm_gpio_get_value(&host->cd_gpio) >= 0
69#endif
70 ) {
71 sdhci_readb(host, ATMEL_SDHC_MC1R);
72 mc1r |= ATMEL_SDHC_MC1R_FCD;
73 sdhci_writeb(host, mc1r, ATMEL_SDHC_MC1R);
74 }
75}
76
Sergiu Mogae554c3e2022-06-22 16:30:47 +030077static int atmel_sdhci_deferred_probe(struct sdhci_host *host)
78{
79 struct udevice *dev = host->mmc->dev;
Zixun LId46f2892023-05-17 15:49:45 +020080 int ret;
Sergiu Mogae554c3e2022-06-22 16:30:47 +030081
Zixun LId46f2892023-05-17 15:49:45 +020082 ret = sdhci_probe(dev);
83 if (ret)
84 return ret;
85
86 atmel_sdhci_config_fcd(host);
87
88 return 0;
Sergiu Mogae554c3e2022-06-22 16:30:47 +030089}
90
91static const struct sdhci_ops atmel_sdhci_ops = {
92 .deferred_probe = atmel_sdhci_deferred_probe,
93};
94
Wenyou Yang83e88a42016-08-10 10:51:05 +080095static int atmel_sdhci_probe(struct udevice *dev)
96{
97 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -070098 struct atmel_sdhci_plat *plat = dev_get_plat(dev);
Wenyou Yang83e88a42016-08-10 10:51:05 +080099 struct sdhci_host *host = dev_get_priv(dev);
100 u32 max_clk;
Wenyou Yang83e88a42016-08-10 10:51:05 +0800101 struct clk clk;
102 int ret;
103
Wenyou Yang038dff82016-09-27 11:00:34 +0800104 ret = clk_get_by_index(dev, 0, &clk);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800105 if (ret)
106 return ret;
107
108 ret = clk_enable(&clk);
109 if (ret)
110 return ret;
111
112 host->name = dev->name;
Masahiro Yamada1096ae12020-07-17 14:36:46 +0900113 host->ioaddr = dev_read_addr_ptr(dev);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800114
Wenyou Yang4fadd972017-05-11 08:25:12 +0800115 host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
Simon Glassdd79d6e2017-01-17 16:52:55 -0700116 host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
Wenyou Yang83e88a42016-08-10 10:51:05 +0800117 "bus-width", 4);
118
Wenyou Yang038dff82016-09-27 11:00:34 +0800119 ret = clk_get_by_index(dev, 1, &clk);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800120 if (ret)
121 return ret;
122
Eugen Hristev90805e12020-08-27 12:16:15 +0300123 clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800124
125 max_clk = clk_get_rate(&clk);
126 if (!max_clk)
127 return -EINVAL;
128
Eugen Hristev3110c752020-08-27 12:25:56 +0300129 ret = clk_enable(&clk);
Eugen Hristeva5630512020-11-09 13:02:17 +0200130 /* return error only if the clock really has a clock enable func */
131 if (ret && ret != -ENOSYS)
Eugen Hristev3110c752020-08-27 12:25:56 +0300132 return ret;
133
Eugen Hristev6fb8abf2020-08-27 12:25:57 +0300134 ret = mmc_of_parse(dev, &plat->cfg);
135 if (ret)
136 return ret;
137
Stefan Herbrechtsmeierbc47e0e2017-01-17 15:58:48 +0100138 host->max_clk = max_clk;
Peng Fan9a8f4992019-08-06 02:47:47 +0000139 host->mmc = &plat->mmc;
140 host->mmc->dev = dev;
Stefan Herbrechtsmeierbc47e0e2017-01-17 15:58:48 +0100141
142 ret = sdhci_setup_cfg(&plat->cfg, host, 0, ATMEL_SDHC_MIN_FREQ);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800143 if (ret)
144 return ret;
145
Wenyou Yang83e88a42016-08-10 10:51:05 +0800146 host->mmc->priv = host;
Sergiu Mogae554c3e2022-06-22 16:30:47 +0300147 host->ops = &atmel_sdhci_ops;
Wenyou Yang83e88a42016-08-10 10:51:05 +0800148 upriv->mmc = host->mmc;
149
Zixun LId46f2892023-05-17 15:49:45 +0200150 ret = sdhci_probe(dev);
151 if (ret)
152 return ret;
153
154 atmel_sdhci_config_fcd(host);
155
156 return 0;
Wenyou Yang83e88a42016-08-10 10:51:05 +0800157}
158
159static int atmel_sdhci_bind(struct udevice *dev)
160{
Simon Glassfa20e932020-12-03 16:55:20 -0700161 struct atmel_sdhci_plat *plat = dev_get_plat(dev);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800162
Masahiro Yamadacdb67f32016-09-06 22:17:32 +0900163 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
Wenyou Yang83e88a42016-08-10 10:51:05 +0800164}
165
166static const struct udevice_id atmel_sdhci_ids[] = {
167 { .compatible = "atmel,sama5d2-sdhci" },
Sandeep Sheriker Mallikarjuncba5eb62019-09-27 13:08:36 +0000168 { .compatible = "microchip,sam9x60-sdhci" },
Eugen Hristev3e742992020-08-27 12:04:41 +0300169 { .compatible = "microchip,sama7g5-sdhci" },
Wenyou Yang83e88a42016-08-10 10:51:05 +0800170 { }
171};
172
173U_BOOT_DRIVER(atmel_sdhci_drv) = {
174 .name = "atmel_sdhci",
175 .id = UCLASS_MMC,
176 .of_match = atmel_sdhci_ids,
177 .ops = &sdhci_ops,
178 .bind = atmel_sdhci_bind,
179 .probe = atmel_sdhci_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700180 .priv_auto = sizeof(struct sdhci_host),
Simon Glass71fa5b42020-12-03 16:55:18 -0700181 .plat_auto = sizeof(struct atmel_sdhci_plat),
Wenyou Yang83e88a42016-08-10 10:51:05 +0800182};
183#endif