blob: aad9d8b85b461ebd125837b21c8381b9666d31db [file] [log] [blame]
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
4 *
5 * Texas Instruments' K3 SD Host Controller Interface
6 */
7
8#include <clk.h>
9#include <common.h>
10#include <dm.h>
11#include <malloc.h>
12#include <power-domain.h>
Faiz Abbasce142ff2019-06-11 00:43:38 +053013#include <regmap.h>
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +053014#include <sdhci.h>
Simon Glass336d4612020-02-03 07:36:16 -070015#include <dm/device_compat.h>
Simon Glass61b29b82020-02-03 07:36:15 -070016#include <linux/err.h>
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +053017
Faiz Abbasce142ff2019-06-11 00:43:38 +053018/* CTL_CFG Registers */
19#define CTL_CFG_2 0x14
20
21#define SLOTTYPE_MASK GENMASK(31, 30)
22#define SLOTTYPE_EMBEDDED BIT(30)
23
24/* PHY Registers */
25#define PHY_CTRL1 0x100
26#define PHY_CTRL2 0x104
27#define PHY_CTRL3 0x108
28#define PHY_CTRL4 0x10C
29#define PHY_CTRL5 0x110
30#define PHY_CTRL6 0x114
31#define PHY_STAT1 0x130
32#define PHY_STAT2 0x134
33
34#define IOMUX_ENABLE_SHIFT 31
35#define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT)
36#define OTAPDLYENA_SHIFT 20
37#define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT)
38#define OTAPDLYSEL_SHIFT 12
39#define OTAPDLYSEL_MASK GENMASK(15, 12)
40#define STRBSEL_SHIFT 24
Faiz Abbasa20008e2020-01-16 19:42:19 +053041#define STRBSEL_4BIT_MASK GENMASK(27, 24)
42#define STRBSEL_8BIT_MASK GENMASK(31, 24)
Faiz Abbasce142ff2019-06-11 00:43:38 +053043#define SEL50_SHIFT 8
44#define SEL50_MASK BIT(SEL50_SHIFT)
45#define SEL100_SHIFT 9
46#define SEL100_MASK BIT(SEL100_SHIFT)
Faiz Abbasa20008e2020-01-16 19:42:19 +053047#define FREQSEL_SHIFT 8
48#define FREQSEL_MASK GENMASK(10, 8)
Faiz Abbasce142ff2019-06-11 00:43:38 +053049#define DLL_TRIM_ICP_SHIFT 4
50#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
51#define DR_TY_SHIFT 20
52#define DR_TY_MASK GENMASK(22, 20)
53#define ENDLL_SHIFT 1
54#define ENDLL_MASK BIT(ENDLL_SHIFT)
55#define DLLRDY_SHIFT 0
56#define DLLRDY_MASK BIT(DLLRDY_SHIFT)
57#define PDB_SHIFT 0
58#define PDB_MASK BIT(PDB_SHIFT)
59#define CALDONE_SHIFT 1
60#define CALDONE_MASK BIT(CALDONE_SHIFT)
61#define RETRIM_SHIFT 17
62#define RETRIM_MASK BIT(RETRIM_SHIFT)
63
64#define DRIVER_STRENGTH_50_OHM 0x0
65#define DRIVER_STRENGTH_33_OHM 0x1
66#define DRIVER_STRENGTH_66_OHM 0x2
67#define DRIVER_STRENGTH_100_OHM 0x3
68#define DRIVER_STRENGTH_40_OHM 0x4
69
Faiz Abbas3a1a0df2019-06-11 00:43:31 +053070#define AM654_SDHCI_MIN_FREQ 400000
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +053071
Faiz Abbas3a1a0df2019-06-11 00:43:31 +053072struct am654_sdhci_plat {
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +053073 struct mmc_config cfg;
74 struct mmc mmc;
Faiz Abbasce142ff2019-06-11 00:43:38 +053075 struct regmap *base;
76 bool non_removable;
77 u32 otap_del_sel;
78 u32 trm_icp;
79 u32 drv_strength;
Faiz Abbasa20008e2020-01-16 19:42:19 +053080 u32 strb_sel;
Faiz Abbas794453f2019-06-13 10:29:51 +053081 u32 flags;
82#define DLL_PRESENT (1 << 0)
Faiz Abbasa20008e2020-01-16 19:42:19 +053083#define IOMUX_PRESENT (1 << 1)
84#define FREQSEL_2_BIT (1 << 2)
85#define STRBSEL_4_BIT (1 << 3)
Faiz Abbasce142ff2019-06-11 00:43:38 +053086 bool dll_on;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +053087};
88
Faiz Abbasa20008e2020-01-16 19:42:19 +053089struct am654_driver_data {
90 const struct sdhci_ops *ops;
91 u32 flags;
92};
93
Faiz Abbasf6058072019-06-11 00:43:41 +053094static void am654_sdhci_set_control_reg(struct sdhci_host *host)
95{
96 struct mmc *mmc = (struct mmc *)host->mmc;
97 u32 reg;
98
99 if (IS_SD(host->mmc) &&
100 mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
101 reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
102 reg |= SDHCI_CTRL_VDD_180;
103 sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
104 }
105
106 sdhci_set_uhs_timing(host);
107}
108
Faiz Abbasce142ff2019-06-11 00:43:38 +0530109static int am654_sdhci_set_ios_post(struct sdhci_host *host)
110{
111 struct udevice *dev = host->mmc->dev;
112 struct am654_sdhci_plat *plat = dev_get_platdata(dev);
113 unsigned int speed = host->mmc->clock;
Faiz Abbasa20008e2020-01-16 19:42:19 +0530114 int sel50, sel100, freqsel;
Faiz Abbasce142ff2019-06-11 00:43:38 +0530115 u32 mask, val;
116 int ret;
117
118 /* Reset SD Clock Enable */
119 val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
120 val &= ~SDHCI_CLOCK_CARD_EN;
121 sdhci_writew(host, val, SDHCI_CLOCK_CONTROL);
122
123 /* power off phy */
124 if (plat->dll_on) {
125 regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0);
126
127 plat->dll_on = false;
128 }
129
130 /* restart clock */
131 sdhci_set_clock(host->mmc, speed);
132
133 /* switch phy back on */
134 if (speed > AM654_SDHCI_MIN_FREQ) {
135 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
136 val = (1 << OTAPDLYENA_SHIFT) |
137 (plat->otap_del_sel << OTAPDLYSEL_SHIFT);
Faiz Abbasa20008e2020-01-16 19:42:19 +0530138
139 /* Write to STRBSEL for HS400 speed mode */
140 if (host->mmc->selected_mode == MMC_HS_400) {
141 if (plat->flags & STRBSEL_4_BIT)
142 mask |= STRBSEL_4BIT_MASK;
143 else
144 mask |= STRBSEL_8BIT_MASK;
145
146 val |= plat->strb_sel << STRBSEL_SHIFT;
Faiz Abbasce142ff2019-06-11 00:43:38 +0530147 }
148
Faiz Abbasa20008e2020-01-16 19:42:19 +0530149 regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
150
151 if (plat->flags & FREQSEL_2_BIT) {
152 switch (speed) {
153 case 200000000:
154 sel50 = 0;
155 sel100 = 0;
156 break;
157 case 100000000:
158 sel50 = 0;
159 sel100 = 1;
160 break;
161 default:
162 sel50 = 1;
163 sel100 = 0;
164 }
165
166 /* Configure PHY DLL frequency */
167 mask = SEL50_MASK | SEL100_MASK;
168 val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
169 regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
170 } else {
171 switch (speed) {
172 case 200000000:
173 freqsel = 0x0;
174 break;
175 default:
176 freqsel = 0x4;
177 }
178 regmap_update_bits(plat->base, PHY_CTRL5, FREQSEL_MASK,
179 freqsel << FREQSEL_SHIFT);
180 }
Faiz Abbasce142ff2019-06-11 00:43:38 +0530181
182 /* Enable DLL */
183 regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK,
184 0x1 << ENDLL_SHIFT);
185 /*
186 * Poll for DLL ready. Use a one second timeout.
187 * Works in all experiments done so far
188 */
189 ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
190 val & DLLRDY_MASK, 1000, 1000000);
191 if (ret)
192 return ret;
193
194 plat->dll_on = true;
195 }
196
197 return 0;
198}
199
200const struct sdhci_ops am654_sdhci_ops = {
Faiz Abbasf6058072019-06-11 00:43:41 +0530201 .set_ios_post = &am654_sdhci_set_ios_post,
202 .set_control_reg = &am654_sdhci_set_control_reg,
Faiz Abbasce142ff2019-06-11 00:43:38 +0530203};
204
Faiz Abbasa20008e2020-01-16 19:42:19 +0530205const struct am654_driver_data am654_drv_data = {
206 .ops = &am654_sdhci_ops,
207 .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | STRBSEL_4_BIT,
208};
209
210const struct am654_driver_data j721e_8bit_drv_data = {
211 .ops = &am654_sdhci_ops,
212 .flags = DLL_PRESENT,
213};
214
215static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host)
216{
217 struct udevice *dev = host->mmc->dev;
218 struct am654_sdhci_plat *plat = dev_get_platdata(dev);
219 u32 mask, val;
220
221 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
222 val = (1 << OTAPDLYENA_SHIFT) |
223 (plat->otap_del_sel << OTAPDLYSEL_SHIFT);
224 regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
225
226 return 0;
227}
228
Faiz Abbas794453f2019-06-13 10:29:51 +0530229const struct sdhci_ops j721e_4bit_sdhci_ops = {
Faiz Abbasa20008e2020-01-16 19:42:19 +0530230 .set_ios_post = &j721e_4bit_sdhci_set_ios_post,
231};
232
233const struct am654_driver_data j721e_4bit_drv_data = {
234 .ops = &j721e_4bit_sdhci_ops,
235 .flags = IOMUX_PRESENT,
Faiz Abbas794453f2019-06-13 10:29:51 +0530236};
237
Faiz Abbasce142ff2019-06-11 00:43:38 +0530238int am654_sdhci_init(struct am654_sdhci_plat *plat)
239{
240 u32 ctl_cfg_2 = 0;
241 u32 mask, val;
242 int ret;
243
244 /* Reset OTAP to default value */
245 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
246 regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0);
247
Faiz Abbas794453f2019-06-13 10:29:51 +0530248 if (plat->flags & DLL_PRESENT) {
249 regmap_read(plat->base, PHY_STAT1, &val);
250 if (~val & CALDONE_MASK) {
251 /* Calibrate IO lines */
252 regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK,
253 PDB_MASK);
254 ret = regmap_read_poll_timeout(plat->base, PHY_STAT1,
255 val, val & CALDONE_MASK,
256 1, 20);
257 if (ret)
258 return ret;
259 }
260
261 /* Configure DLL TRIM */
262 mask = DLL_TRIM_ICP_MASK;
263 val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
264
265 /* Configure DLL driver strength */
266 mask |= DR_TY_MASK;
267 val |= plat->drv_strength << DR_TY_SHIFT;
268 regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530269 }
270
Faiz Abbasce142ff2019-06-11 00:43:38 +0530271 /* Enable pins by setting IO mux to 0 */
Faiz Abbasa20008e2020-01-16 19:42:19 +0530272 if (plat->flags & IOMUX_PRESENT)
273 regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530274
275 /* Set slot type based on SD or eMMC */
276 if (plat->non_removable)
277 ctl_cfg_2 = SLOTTYPE_EMBEDDED;
278
279 regmap_update_bits(plat->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2);
280
281 return 0;
282}
283
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530284static int am654_sdhci_probe(struct udevice *dev)
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530285{
Faiz Abbasa20008e2020-01-16 19:42:19 +0530286 struct am654_driver_data *drv_data =
287 (struct am654_driver_data *)dev_get_driver_data(dev);
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530288 struct am654_sdhci_plat *plat = dev_get_platdata(dev);
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530289 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
290 struct sdhci_host *host = dev_get_priv(dev);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530291 struct mmc_config *cfg = &plat->cfg;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530292 struct clk clk;
293 unsigned long clock;
294 int ret;
295
Faiz Abbasfe0e30c2020-01-16 19:42:18 +0530296 ret = clk_get_by_name(dev, "clk_xin", &clk);
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530297 if (ret) {
298 dev_err(dev, "failed to get clock\n");
299 return ret;
300 }
301
302 clock = clk_get_rate(&clk);
303 if (IS_ERR_VALUE(clock)) {
304 dev_err(dev, "failed to get rate\n");
305 return clock;
306 }
307
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530308 host->max_clk = clock;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530309 host->mmc = &plat->mmc;
Faiz Abbasce142ff2019-06-11 00:43:38 +0530310 host->mmc->dev = dev;
311 ret = sdhci_setup_cfg(cfg, host, cfg->f_max,
312 AM654_SDHCI_MIN_FREQ);
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530313 if (ret)
314 return ret;
Faiz Abbasa20008e2020-01-16 19:42:19 +0530315
316 host->ops = drv_data->ops;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530317 host->mmc->priv = host;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530318 upriv->mmc = host->mmc;
319
Faiz Abbasce142ff2019-06-11 00:43:38 +0530320 regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1);
321
322 am654_sdhci_init(plat);
323
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530324 return sdhci_probe(dev);
325}
326
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530327static int am654_sdhci_ofdata_to_platdata(struct udevice *dev)
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530328{
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530329 struct am654_sdhci_plat *plat = dev_get_platdata(dev);
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530330 struct sdhci_host *host = dev_get_priv(dev);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530331 struct mmc_config *cfg = &plat->cfg;
332 u32 drv_strength;
333 int ret;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530334
335 host->name = dev->name;
336 host->ioaddr = (void *)dev_read_addr(dev);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530337 plat->non_removable = dev_read_bool(dev, "non-removable");
338
Faiz Abbasce142ff2019-06-11 00:43:38 +0530339 ret = dev_read_u32(dev, "ti,otap-del-sel", &plat->otap_del_sel);
340 if (ret)
341 return ret;
342
Faiz Abbas794453f2019-06-13 10:29:51 +0530343 if (plat->flags & DLL_PRESENT) {
344 ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp);
345 if (ret)
346 return ret;
Faiz Abbasce142ff2019-06-11 00:43:38 +0530347
Faiz Abbas794453f2019-06-13 10:29:51 +0530348 ret = dev_read_u32(dev, "ti,driver-strength-ohm",
349 &drv_strength);
350 if (ret)
351 return ret;
352
353 switch (drv_strength) {
354 case 50:
355 plat->drv_strength = DRIVER_STRENGTH_50_OHM;
356 break;
357 case 33:
358 plat->drv_strength = DRIVER_STRENGTH_33_OHM;
359 break;
360 case 66:
361 plat->drv_strength = DRIVER_STRENGTH_66_OHM;
362 break;
363 case 100:
364 plat->drv_strength = DRIVER_STRENGTH_100_OHM;
365 break;
366 case 40:
367 plat->drv_strength = DRIVER_STRENGTH_40_OHM;
368 break;
369 default:
370 dev_err(dev, "Invalid driver strength\n");
371 return -EINVAL;
372 }
Faiz Abbasce142ff2019-06-11 00:43:38 +0530373 }
374
375 ret = mmc_of_parse(dev, cfg);
376 if (ret)
377 return ret;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530378
379 return 0;
380}
381
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530382static int am654_sdhci_bind(struct udevice *dev)
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530383{
Faiz Abbasa20008e2020-01-16 19:42:19 +0530384 struct am654_driver_data *drv_data =
385 (struct am654_driver_data *)dev_get_driver_data(dev);
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530386 struct am654_sdhci_plat *plat = dev_get_platdata(dev);
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530387
Faiz Abbasa20008e2020-01-16 19:42:19 +0530388 plat->flags = drv_data->flags;
389
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530390 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
391}
392
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530393static const struct udevice_id am654_sdhci_ids[] = {
Faiz Abbas794453f2019-06-13 10:29:51 +0530394 {
395 .compatible = "ti,am654-sdhci-5.1",
Faiz Abbasa20008e2020-01-16 19:42:19 +0530396 .data = (ulong)&am654_drv_data,
Faiz Abbas794453f2019-06-13 10:29:51 +0530397 },
398 {
399 .compatible = "ti,j721e-sdhci-8bit",
Faiz Abbasa20008e2020-01-16 19:42:19 +0530400 .data = (ulong)&j721e_8bit_drv_data,
Faiz Abbas794453f2019-06-13 10:29:51 +0530401 },
402 {
403 .compatible = "ti,j721e-sdhci-4bit",
Faiz Abbasa20008e2020-01-16 19:42:19 +0530404 .data = (ulong)&j721e_4bit_drv_data,
Faiz Abbas794453f2019-06-13 10:29:51 +0530405 },
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530406 { }
407};
408
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530409U_BOOT_DRIVER(am654_sdhci_drv) = {
410 .name = "am654_sdhci",
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530411 .id = UCLASS_MMC,
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530412 .of_match = am654_sdhci_ids,
413 .ofdata_to_platdata = am654_sdhci_ofdata_to_platdata,
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530414 .ops = &sdhci_ops,
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530415 .bind = am654_sdhci_bind,
416 .probe = am654_sdhci_probe,
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530417 .priv_auto_alloc_size = sizeof(struct sdhci_host),
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530418 .platdata_auto_alloc_size = sizeof(struct am654_sdhci_plat),
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530419};