blob: 6053d3d536e6a29a67772b6415c46aad9a432f4d [file] [log] [blame]
Lokesh Vutlabc9979f2018-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 Abbase9aed582019-06-11 00:43:38 +053013#include <regmap.h>
Lokesh Vutlabc9979f2018-08-27 15:57:54 +053014#include <sdhci.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070015#include <linux/err.h>
Lokesh Vutlabc9979f2018-08-27 15:57:54 +053016
Faiz Abbase9aed582019-06-11 00:43:38 +053017/* CTL_CFG Registers */
18#define CTL_CFG_2 0x14
19
20#define SLOTTYPE_MASK GENMASK(31, 30)
21#define SLOTTYPE_EMBEDDED BIT(30)
22
23/* PHY Registers */
24#define PHY_CTRL1 0x100
25#define PHY_CTRL2 0x104
26#define PHY_CTRL3 0x108
27#define PHY_CTRL4 0x10C
28#define PHY_CTRL5 0x110
29#define PHY_CTRL6 0x114
30#define PHY_STAT1 0x130
31#define PHY_STAT2 0x134
32
33#define IOMUX_ENABLE_SHIFT 31
34#define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT)
35#define OTAPDLYENA_SHIFT 20
36#define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT)
37#define OTAPDLYSEL_SHIFT 12
38#define OTAPDLYSEL_MASK GENMASK(15, 12)
39#define STRBSEL_SHIFT 24
Faiz Abbas8cc051e2020-01-16 19:42:19 +053040#define STRBSEL_4BIT_MASK GENMASK(27, 24)
41#define STRBSEL_8BIT_MASK GENMASK(31, 24)
Faiz Abbase9aed582019-06-11 00:43:38 +053042#define SEL50_SHIFT 8
43#define SEL50_MASK BIT(SEL50_SHIFT)
44#define SEL100_SHIFT 9
45#define SEL100_MASK BIT(SEL100_SHIFT)
Faiz Abbas8cc051e2020-01-16 19:42:19 +053046#define FREQSEL_SHIFT 8
47#define FREQSEL_MASK GENMASK(10, 8)
Faiz Abbase9aed582019-06-11 00:43:38 +053048#define DLL_TRIM_ICP_SHIFT 4
49#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
50#define DR_TY_SHIFT 20
51#define DR_TY_MASK GENMASK(22, 20)
52#define ENDLL_SHIFT 1
53#define ENDLL_MASK BIT(ENDLL_SHIFT)
54#define DLLRDY_SHIFT 0
55#define DLLRDY_MASK BIT(DLLRDY_SHIFT)
56#define PDB_SHIFT 0
57#define PDB_MASK BIT(PDB_SHIFT)
58#define CALDONE_SHIFT 1
59#define CALDONE_MASK BIT(CALDONE_SHIFT)
60#define RETRIM_SHIFT 17
61#define RETRIM_MASK BIT(RETRIM_SHIFT)
62
63#define DRIVER_STRENGTH_50_OHM 0x0
64#define DRIVER_STRENGTH_33_OHM 0x1
65#define DRIVER_STRENGTH_66_OHM 0x2
66#define DRIVER_STRENGTH_100_OHM 0x3
67#define DRIVER_STRENGTH_40_OHM 0x4
68
Faiz Abbasd8fb3092019-06-11 00:43:31 +053069#define AM654_SDHCI_MIN_FREQ 400000
Lokesh Vutlabc9979f2018-08-27 15:57:54 +053070
Faiz Abbasd8fb3092019-06-11 00:43:31 +053071struct am654_sdhci_plat {
Lokesh Vutlabc9979f2018-08-27 15:57:54 +053072 struct mmc_config cfg;
73 struct mmc mmc;
Faiz Abbase9aed582019-06-11 00:43:38 +053074 struct regmap *base;
75 bool non_removable;
76 u32 otap_del_sel;
77 u32 trm_icp;
78 u32 drv_strength;
Faiz Abbas8cc051e2020-01-16 19:42:19 +053079 u32 strb_sel;
Faiz Abbasfd8be702019-06-13 10:29:51 +053080 u32 flags;
81#define DLL_PRESENT (1 << 0)
Faiz Abbas8cc051e2020-01-16 19:42:19 +053082#define IOMUX_PRESENT (1 << 1)
83#define FREQSEL_2_BIT (1 << 2)
84#define STRBSEL_4_BIT (1 << 3)
Faiz Abbase9aed582019-06-11 00:43:38 +053085 bool dll_on;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +053086};
87
Faiz Abbas8cc051e2020-01-16 19:42:19 +053088struct am654_driver_data {
89 const struct sdhci_ops *ops;
90 u32 flags;
91};
92
Faiz Abbas7eecee62019-06-11 00:43:41 +053093static void am654_sdhci_set_control_reg(struct sdhci_host *host)
94{
95 struct mmc *mmc = (struct mmc *)host->mmc;
96 u32 reg;
97
98 if (IS_SD(host->mmc) &&
99 mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
100 reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
101 reg |= SDHCI_CTRL_VDD_180;
102 sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
103 }
104
105 sdhci_set_uhs_timing(host);
106}
107
Faiz Abbase9aed582019-06-11 00:43:38 +0530108static int am654_sdhci_set_ios_post(struct sdhci_host *host)
109{
110 struct udevice *dev = host->mmc->dev;
111 struct am654_sdhci_plat *plat = dev_get_platdata(dev);
112 unsigned int speed = host->mmc->clock;
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530113 int sel50, sel100, freqsel;
Faiz Abbase9aed582019-06-11 00:43:38 +0530114 u32 mask, val;
115 int ret;
116
117 /* Reset SD Clock Enable */
118 val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
119 val &= ~SDHCI_CLOCK_CARD_EN;
120 sdhci_writew(host, val, SDHCI_CLOCK_CONTROL);
121
122 /* power off phy */
123 if (plat->dll_on) {
124 regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0);
125
126 plat->dll_on = false;
127 }
128
129 /* restart clock */
130 sdhci_set_clock(host->mmc, speed);
131
132 /* switch phy back on */
133 if (speed > AM654_SDHCI_MIN_FREQ) {
134 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
135 val = (1 << OTAPDLYENA_SHIFT) |
136 (plat->otap_del_sel << OTAPDLYSEL_SHIFT);
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530137
138 /* Write to STRBSEL for HS400 speed mode */
139 if (host->mmc->selected_mode == MMC_HS_400) {
140 if (plat->flags & STRBSEL_4_BIT)
141 mask |= STRBSEL_4BIT_MASK;
142 else
143 mask |= STRBSEL_8BIT_MASK;
144
145 val |= plat->strb_sel << STRBSEL_SHIFT;
Faiz Abbase9aed582019-06-11 00:43:38 +0530146 }
147
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530148 regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
149
150 if (plat->flags & FREQSEL_2_BIT) {
151 switch (speed) {
152 case 200000000:
153 sel50 = 0;
154 sel100 = 0;
155 break;
156 case 100000000:
157 sel50 = 0;
158 sel100 = 1;
159 break;
160 default:
161 sel50 = 1;
162 sel100 = 0;
163 }
164
165 /* Configure PHY DLL frequency */
166 mask = SEL50_MASK | SEL100_MASK;
167 val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
168 regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
169 } else {
170 switch (speed) {
171 case 200000000:
172 freqsel = 0x0;
173 break;
174 default:
175 freqsel = 0x4;
176 }
177 regmap_update_bits(plat->base, PHY_CTRL5, FREQSEL_MASK,
178 freqsel << FREQSEL_SHIFT);
179 }
Faiz Abbase9aed582019-06-11 00:43:38 +0530180
181 /* Enable DLL */
182 regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK,
183 0x1 << ENDLL_SHIFT);
184 /*
185 * Poll for DLL ready. Use a one second timeout.
186 * Works in all experiments done so far
187 */
188 ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
189 val & DLLRDY_MASK, 1000, 1000000);
190 if (ret)
191 return ret;
192
193 plat->dll_on = true;
194 }
195
196 return 0;
197}
198
199const struct sdhci_ops am654_sdhci_ops = {
Faiz Abbas7eecee62019-06-11 00:43:41 +0530200 .set_ios_post = &am654_sdhci_set_ios_post,
201 .set_control_reg = &am654_sdhci_set_control_reg,
Faiz Abbase9aed582019-06-11 00:43:38 +0530202};
203
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530204const struct am654_driver_data am654_drv_data = {
205 .ops = &am654_sdhci_ops,
206 .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | STRBSEL_4_BIT,
207};
208
209const struct am654_driver_data j721e_8bit_drv_data = {
210 .ops = &am654_sdhci_ops,
211 .flags = DLL_PRESENT,
212};
213
214static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host)
215{
216 struct udevice *dev = host->mmc->dev;
217 struct am654_sdhci_plat *plat = dev_get_platdata(dev);
218 u32 mask, val;
219
220 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
221 val = (1 << OTAPDLYENA_SHIFT) |
222 (plat->otap_del_sel << OTAPDLYSEL_SHIFT);
223 regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
224
225 return 0;
226}
227
Faiz Abbasfd8be702019-06-13 10:29:51 +0530228const struct sdhci_ops j721e_4bit_sdhci_ops = {
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530229 .set_ios_post = &j721e_4bit_sdhci_set_ios_post,
230};
231
232const struct am654_driver_data j721e_4bit_drv_data = {
233 .ops = &j721e_4bit_sdhci_ops,
234 .flags = IOMUX_PRESENT,
Faiz Abbasfd8be702019-06-13 10:29:51 +0530235};
236
Faiz Abbase9aed582019-06-11 00:43:38 +0530237int am654_sdhci_init(struct am654_sdhci_plat *plat)
238{
239 u32 ctl_cfg_2 = 0;
240 u32 mask, val;
241 int ret;
242
243 /* Reset OTAP to default value */
244 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
245 regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0);
246
Faiz Abbasfd8be702019-06-13 10:29:51 +0530247 if (plat->flags & DLL_PRESENT) {
248 regmap_read(plat->base, PHY_STAT1, &val);
249 if (~val & CALDONE_MASK) {
250 /* Calibrate IO lines */
251 regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK,
252 PDB_MASK);
253 ret = regmap_read_poll_timeout(plat->base, PHY_STAT1,
254 val, val & CALDONE_MASK,
255 1, 20);
256 if (ret)
257 return ret;
258 }
Faiz Abbase9aed582019-06-11 00:43:38 +0530259
Faiz Abbasfd8be702019-06-13 10:29:51 +0530260 /* Configure DLL TRIM */
261 mask = DLL_TRIM_ICP_MASK;
262 val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
Faiz Abbase9aed582019-06-11 00:43:38 +0530263
Faiz Abbasfd8be702019-06-13 10:29:51 +0530264 /* Configure DLL driver strength */
265 mask |= DR_TY_MASK;
266 val |= plat->drv_strength << DR_TY_SHIFT;
267 regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
268 }
Faiz Abbase9aed582019-06-11 00:43:38 +0530269
270 /* Enable pins by setting IO mux to 0 */
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530271 if (plat->flags & IOMUX_PRESENT)
272 regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0);
Faiz Abbase9aed582019-06-11 00:43:38 +0530273
274 /* Set slot type based on SD or eMMC */
275 if (plat->non_removable)
276 ctl_cfg_2 = SLOTTYPE_EMBEDDED;
277
278 regmap_update_bits(plat->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2);
279
280 return 0;
281}
282
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530283static int am654_sdhci_probe(struct udevice *dev)
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530284{
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530285 struct am654_driver_data *drv_data =
286 (struct am654_driver_data *)dev_get_driver_data(dev);
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530287 struct am654_sdhci_plat *plat = dev_get_platdata(dev);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530288 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
289 struct sdhci_host *host = dev_get_priv(dev);
Faiz Abbase9aed582019-06-11 00:43:38 +0530290 struct mmc_config *cfg = &plat->cfg;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530291 struct clk clk;
292 unsigned long clock;
293 int ret;
294
Faiz Abbasdc2bcc22020-01-16 19:42:18 +0530295 ret = clk_get_by_name(dev, "clk_xin", &clk);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530296 if (ret) {
297 dev_err(dev, "failed to get clock\n");
298 return ret;
299 }
300
301 clock = clk_get_rate(&clk);
302 if (IS_ERR_VALUE(clock)) {
303 dev_err(dev, "failed to get rate\n");
304 return clock;
305 }
306
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530307 host->max_clk = clock;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530308 host->mmc = &plat->mmc;
Faiz Abbase9aed582019-06-11 00:43:38 +0530309 host->mmc->dev = dev;
310 ret = sdhci_setup_cfg(cfg, host, cfg->f_max,
311 AM654_SDHCI_MIN_FREQ);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530312 if (ret)
313 return ret;
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530314
315 host->ops = drv_data->ops;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530316 host->mmc->priv = host;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530317 upriv->mmc = host->mmc;
318
Faiz Abbase9aed582019-06-11 00:43:38 +0530319 regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1);
320
321 am654_sdhci_init(plat);
322
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530323 return sdhci_probe(dev);
324}
325
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530326static int am654_sdhci_ofdata_to_platdata(struct udevice *dev)
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530327{
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530328 struct am654_sdhci_plat *plat = dev_get_platdata(dev);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530329 struct sdhci_host *host = dev_get_priv(dev);
Faiz Abbase9aed582019-06-11 00:43:38 +0530330 struct mmc_config *cfg = &plat->cfg;
331 u32 drv_strength;
332 int ret;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530333
334 host->name = dev->name;
335 host->ioaddr = (void *)dev_read_addr(dev);
Faiz Abbase9aed582019-06-11 00:43:38 +0530336 plat->non_removable = dev_read_bool(dev, "non-removable");
337
Faiz Abbase9aed582019-06-11 00:43:38 +0530338 ret = dev_read_u32(dev, "ti,otap-del-sel", &plat->otap_del_sel);
339 if (ret)
340 return ret;
341
Faiz Abbasfd8be702019-06-13 10:29:51 +0530342 if (plat->flags & DLL_PRESENT) {
343 ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp);
344 if (ret)
345 return ret;
346
347 ret = dev_read_u32(dev, "ti,driver-strength-ohm",
348 &drv_strength);
349 if (ret)
350 return ret;
Faiz Abbase9aed582019-06-11 00:43:38 +0530351
Faiz Abbasfd8be702019-06-13 10:29:51 +0530352 switch (drv_strength) {
353 case 50:
354 plat->drv_strength = DRIVER_STRENGTH_50_OHM;
355 break;
356 case 33:
357 plat->drv_strength = DRIVER_STRENGTH_33_OHM;
358 break;
359 case 66:
360 plat->drv_strength = DRIVER_STRENGTH_66_OHM;
361 break;
362 case 100:
363 plat->drv_strength = DRIVER_STRENGTH_100_OHM;
364 break;
365 case 40:
366 plat->drv_strength = DRIVER_STRENGTH_40_OHM;
367 break;
368 default:
369 dev_err(dev, "Invalid driver strength\n");
370 return -EINVAL;
371 }
Faiz Abbase9aed582019-06-11 00:43:38 +0530372 }
373
374 ret = mmc_of_parse(dev, cfg);
375 if (ret)
376 return ret;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530377
378 return 0;
379}
380
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530381static int am654_sdhci_bind(struct udevice *dev)
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530382{
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530383 struct am654_driver_data *drv_data =
384 (struct am654_driver_data *)dev_get_driver_data(dev);
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530385 struct am654_sdhci_plat *plat = dev_get_platdata(dev);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530386
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530387 plat->flags = drv_data->flags;
388
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530389 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
390}
391
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530392static const struct udevice_id am654_sdhci_ids[] = {
Faiz Abbasfd8be702019-06-13 10:29:51 +0530393 {
394 .compatible = "ti,am654-sdhci-5.1",
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530395 .data = (ulong)&am654_drv_data,
Faiz Abbasfd8be702019-06-13 10:29:51 +0530396 },
397 {
398 .compatible = "ti,j721e-sdhci-8bit",
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530399 .data = (ulong)&j721e_8bit_drv_data,
Faiz Abbasfd8be702019-06-13 10:29:51 +0530400 },
401 {
402 .compatible = "ti,j721e-sdhci-4bit",
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530403 .data = (ulong)&j721e_4bit_drv_data,
Faiz Abbasfd8be702019-06-13 10:29:51 +0530404 },
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530405 { }
406};
407
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530408U_BOOT_DRIVER(am654_sdhci_drv) = {
409 .name = "am654_sdhci",
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530410 .id = UCLASS_MMC,
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530411 .of_match = am654_sdhci_ids,
412 .ofdata_to_platdata = am654_sdhci_ofdata_to_platdata,
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530413 .ops = &sdhci_ops,
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530414 .bind = am654_sdhci_bind,
415 .probe = am654_sdhci_probe,
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530416 .priv_auto_alloc_size = sizeof(struct sdhci_host),
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530417 .platdata_auto_alloc_size = sizeof(struct am654_sdhci_plat),
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530418};