blob: 62007ebd0f441ebfe1885eae7a1dc11a35c3458e [file] [log] [blame]
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
Nishanth Menona94a4072023-11-01 15:56:03 -05003 * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +05304 *
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>
Faiz Abbasa759abf2021-02-04 15:10:53 +053012#include <mmc.h>
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +053013#include <power-domain.h>
Faiz Abbasce142ff2019-06-11 00:43:38 +053014#include <regmap.h>
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +053015#include <sdhci.h>
Faiz Abbas8c32b5f2021-02-04 15:10:50 +053016#include <soc.h>
Simon Glass336d4612020-02-03 07:36:16 -070017#include <dm/device_compat.h>
Simon Glasscd93d622020-05-10 11:40:13 -060018#include <linux/bitops.h>
Simon Glass61b29b82020-02-03 07:36:15 -070019#include <linux/err.h>
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +053020
Faiz Abbasce142ff2019-06-11 00:43:38 +053021/* CTL_CFG Registers */
22#define CTL_CFG_2 0x14
23
24#define SLOTTYPE_MASK GENMASK(31, 30)
25#define SLOTTYPE_EMBEDDED BIT(30)
26
27/* PHY Registers */
28#define PHY_CTRL1 0x100
29#define PHY_CTRL2 0x104
30#define PHY_CTRL3 0x108
31#define PHY_CTRL4 0x10C
32#define PHY_CTRL5 0x110
33#define PHY_CTRL6 0x114
34#define PHY_STAT1 0x130
35#define PHY_STAT2 0x134
36
37#define IOMUX_ENABLE_SHIFT 31
38#define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT)
39#define OTAPDLYENA_SHIFT 20
40#define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT)
41#define OTAPDLYSEL_SHIFT 12
42#define OTAPDLYSEL_MASK GENMASK(15, 12)
43#define STRBSEL_SHIFT 24
Faiz Abbasa20008e2020-01-16 19:42:19 +053044#define STRBSEL_4BIT_MASK GENMASK(27, 24)
45#define STRBSEL_8BIT_MASK GENMASK(31, 24)
Faiz Abbasce142ff2019-06-11 00:43:38 +053046#define SEL50_SHIFT 8
47#define SEL50_MASK BIT(SEL50_SHIFT)
48#define SEL100_SHIFT 9
49#define SEL100_MASK BIT(SEL100_SHIFT)
Faiz Abbasa20008e2020-01-16 19:42:19 +053050#define FREQSEL_SHIFT 8
51#define FREQSEL_MASK GENMASK(10, 8)
Faiz Abbas194c3752021-02-04 15:10:52 +053052#define CLKBUFSEL_SHIFT 0
53#define CLKBUFSEL_MASK GENMASK(2, 0)
Faiz Abbasce142ff2019-06-11 00:43:38 +053054#define DLL_TRIM_ICP_SHIFT 4
55#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
56#define DR_TY_SHIFT 20
57#define DR_TY_MASK GENMASK(22, 20)
58#define ENDLL_SHIFT 1
59#define ENDLL_MASK BIT(ENDLL_SHIFT)
60#define DLLRDY_SHIFT 0
61#define DLLRDY_MASK BIT(DLLRDY_SHIFT)
62#define PDB_SHIFT 0
63#define PDB_MASK BIT(PDB_SHIFT)
64#define CALDONE_SHIFT 1
65#define CALDONE_MASK BIT(CALDONE_SHIFT)
66#define RETRIM_SHIFT 17
67#define RETRIM_MASK BIT(RETRIM_SHIFT)
Faiz Abbasc9644472021-02-04 15:10:51 +053068#define SELDLYTXCLK_SHIFT 17
69#define SELDLYTXCLK_MASK BIT(SELDLYTXCLK_SHIFT)
70#define SELDLYRXCLK_SHIFT 16
71#define SELDLYRXCLK_MASK BIT(SELDLYRXCLK_SHIFT)
72#define ITAPDLYSEL_SHIFT 0
73#define ITAPDLYSEL_MASK GENMASK(4, 0)
74#define ITAPDLYENA_SHIFT 8
75#define ITAPDLYENA_MASK BIT(ITAPDLYENA_SHIFT)
76#define ITAPCHGWIN_SHIFT 9
77#define ITAPCHGWIN_MASK BIT(ITAPCHGWIN_SHIFT)
Faiz Abbasce142ff2019-06-11 00:43:38 +053078
79#define DRIVER_STRENGTH_50_OHM 0x0
80#define DRIVER_STRENGTH_33_OHM 0x1
81#define DRIVER_STRENGTH_66_OHM 0x2
82#define DRIVER_STRENGTH_100_OHM 0x3
83#define DRIVER_STRENGTH_40_OHM 0x4
84
Faiz Abbas3a1a0df2019-06-11 00:43:31 +053085#define AM654_SDHCI_MIN_FREQ 400000
Faiz Abbasc9644472021-02-04 15:10:51 +053086#define CLOCK_TOO_SLOW_HZ 50000000
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +053087
Judith Mendez056af042024-04-18 14:00:58 -050088#define ENABLE 0x1
89
Faiz Abbas3a1a0df2019-06-11 00:43:31 +053090struct am654_sdhci_plat {
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +053091 struct mmc_config cfg;
92 struct mmc mmc;
Faiz Abbasce142ff2019-06-11 00:43:38 +053093 struct regmap *base;
94 bool non_removable;
Faiz Abbas7d6f45a2020-07-29 07:03:41 +053095 u32 otap_del_sel[MMC_MODES_END];
Faiz Abbasc9644472021-02-04 15:10:51 +053096 u32 itap_del_sel[MMC_MODES_END];
Judith Mendez056af042024-04-18 14:00:58 -050097 u32 itap_del_ena[MMC_MODES_END];
Faiz Abbasce142ff2019-06-11 00:43:38 +053098 u32 trm_icp;
99 u32 drv_strength;
Faiz Abbasa20008e2020-01-16 19:42:19 +0530100 u32 strb_sel;
Faiz Abbas194c3752021-02-04 15:10:52 +0530101 u32 clkbuf_sel;
Faiz Abbas794453f2019-06-13 10:29:51 +0530102 u32 flags;
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500103 bool dll_enable;
Faiz Abbas144e1312021-02-04 15:10:48 +0530104#define DLL_PRESENT BIT(0)
105#define IOMUX_PRESENT BIT(1)
106#define FREQSEL_2_BIT BIT(2)
107#define STRBSEL_4_BIT BIT(3)
Faiz Abbas5b29fd42021-02-04 15:10:49 +0530108#define DLL_CALIB BIT(4)
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530109};
110
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530111struct timing_data {
Faiz Abbasc9644472021-02-04 15:10:51 +0530112 const char *otap_binding;
113 const char *itap_binding;
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530114 u32 capability;
115};
116
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500117struct window {
118 u8 start;
119 u8 end;
120 u8 length;
121};
122
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530123static const struct timing_data td[] = {
Faiz Abbasc9644472021-02-04 15:10:51 +0530124 [MMC_LEGACY] = {"ti,otap-del-sel-legacy",
125 "ti,itap-del-sel-legacy",
126 0},
127 [MMC_HS] = {"ti,otap-del-sel-mmc-hs",
128 "ti,itap-del-sel-mms-hs",
129 MMC_CAP(MMC_HS)},
130 [SD_HS] = {"ti,otap-del-sel-sd-hs",
131 "ti,itap-del-sel-sd-hs",
132 MMC_CAP(SD_HS)},
133 [UHS_SDR12] = {"ti,otap-del-sel-sdr12",
134 "ti,itap-del-sel-sdr12",
135 MMC_CAP(UHS_SDR12)},
136 [UHS_SDR25] = {"ti,otap-del-sel-sdr25",
137 "ti,itap-del-sel-sdr25",
138 MMC_CAP(UHS_SDR25)},
139 [UHS_SDR50] = {"ti,otap-del-sel-sdr50",
140 NULL,
141 MMC_CAP(UHS_SDR50)},
142 [UHS_SDR104] = {"ti,otap-del-sel-sdr104",
143 NULL,
144 MMC_CAP(UHS_SDR104)},
145 [UHS_DDR50] = {"ti,otap-del-sel-ddr50",
146 NULL,
147 MMC_CAP(UHS_DDR50)},
148 [MMC_DDR_52] = {"ti,otap-del-sel-ddr52",
149 "ti,itap-del-sel-ddr52",
150 MMC_CAP(MMC_DDR_52)},
151 [MMC_HS_200] = {"ti,otap-del-sel-hs200",
152 NULL,
153 MMC_CAP(MMC_HS_200)},
154 [MMC_HS_400] = {"ti,otap-del-sel-hs400",
155 NULL,
156 MMC_CAP(MMC_HS_400)},
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530157};
158
Faiz Abbasa20008e2020-01-16 19:42:19 +0530159struct am654_driver_data {
160 const struct sdhci_ops *ops;
161 u32 flags;
162};
163
Faiz Abbasc9644472021-02-04 15:10:51 +0530164static int am654_sdhci_setup_dll(struct am654_sdhci_plat *plat,
165 unsigned int speed)
166{
167 int sel50, sel100, freqsel;
168 u32 mask, val;
169 int ret;
170
171 /* Disable delay chain mode */
172 regmap_update_bits(plat->base, PHY_CTRL5,
173 SELDLYTXCLK_MASK | SELDLYRXCLK_MASK, 0);
174
175 if (plat->flags & FREQSEL_2_BIT) {
176 switch (speed) {
177 case 200000000:
178 sel50 = 0;
179 sel100 = 0;
180 break;
181 case 100000000:
182 sel50 = 0;
183 sel100 = 1;
184 break;
185 default:
186 sel50 = 1;
187 sel100 = 0;
188 }
189
190 /* Configure PHY DLL frequency */
191 mask = SEL50_MASK | SEL100_MASK;
192 val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
193 regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
194 } else {
195 switch (speed) {
196 case 200000000:
197 freqsel = 0x0;
198 break;
199 default:
200 freqsel = 0x4;
201 }
202 regmap_update_bits(plat->base, PHY_CTRL5, FREQSEL_MASK,
203 freqsel << FREQSEL_SHIFT);
204 }
205
206 /* Configure DLL TRIM */
207 mask = DLL_TRIM_ICP_MASK;
208 val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
209
210 /* Configure DLL driver strength */
211 mask |= DR_TY_MASK;
212 val |= plat->drv_strength << DR_TY_SHIFT;
213 regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
214
215 /* Enable DLL */
216 regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK,
217 0x1 << ENDLL_SHIFT);
218 /*
219 * Poll for DLL ready. Use a one second timeout.
220 * Works in all experiments done so far
221 */
222 ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
223 val & DLLRDY_MASK, 1000, 1000000);
224
225 return ret;
226}
227
228static void am654_sdhci_write_itapdly(struct am654_sdhci_plat *plat,
Judith Mendez056af042024-04-18 14:00:58 -0500229 u32 itapdly, u32 enable)
Faiz Abbasc9644472021-02-04 15:10:51 +0530230{
Judith Mendez056af042024-04-18 14:00:58 -0500231 regmap_update_bits(plat->base, PHY_CTRL4, ITAPDLYENA_MASK,
232 enable << ITAPDLYENA_SHIFT);
Faiz Abbasc9644472021-02-04 15:10:51 +0530233 /* Set ITAPCHGWIN before writing to ITAPDLY */
234 regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK,
235 1 << ITAPCHGWIN_SHIFT);
236 regmap_update_bits(plat->base, PHY_CTRL4, ITAPDLYSEL_MASK,
237 itapdly << ITAPDLYSEL_SHIFT);
238 regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
239}
240
241static void am654_sdhci_setup_delay_chain(struct am654_sdhci_plat *plat,
242 int mode)
243{
244 u32 mask, val;
245
246 val = 1 << SELDLYTXCLK_SHIFT | 1 << SELDLYRXCLK_SHIFT;
247 mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK;
248 regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
249
Judith Mendez056af042024-04-18 14:00:58 -0500250 am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode],
251 plat->itap_del_ena[mode]);
Faiz Abbasc9644472021-02-04 15:10:51 +0530252}
253
Faiz Abbasce142ff2019-06-11 00:43:38 +0530254static int am654_sdhci_set_ios_post(struct sdhci_host *host)
255{
256 struct udevice *dev = host->mmc->dev;
Simon Glassc69cda22020-12-03 16:55:20 -0700257 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530258 unsigned int speed = host->mmc->clock;
Faiz Abbasc9644472021-02-04 15:10:51 +0530259 int mode = host->mmc->selected_mode;
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530260 u32 otap_del_sel;
Faiz Abbasce142ff2019-06-11 00:43:38 +0530261 u32 mask, val;
262 int ret;
263
264 /* Reset SD Clock Enable */
265 val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
266 val &= ~SDHCI_CLOCK_CARD_EN;
267 sdhci_writew(host, val, SDHCI_CLOCK_CONTROL);
268
Faiz Abbasc604e202021-02-04 15:10:47 +0530269 regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530270
271 /* restart clock */
272 sdhci_set_clock(host->mmc, speed);
273
274 /* switch phy back on */
Faiz Abbasc9644472021-02-04 15:10:51 +0530275 otap_del_sel = plat->otap_del_sel[mode];
276 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
277 val = (1 << OTAPDLYENA_SHIFT) |
278 (otap_del_sel << OTAPDLYSEL_SHIFT);
Faiz Abbasa20008e2020-01-16 19:42:19 +0530279
Faiz Abbasc9644472021-02-04 15:10:51 +0530280 /* Write to STRBSEL for HS400 speed mode */
281 if (host->mmc->selected_mode == MMC_HS_400) {
282 if (plat->flags & STRBSEL_4_BIT)
283 mask |= STRBSEL_4BIT_MASK;
284 else
285 mask |= STRBSEL_8BIT_MASK;
Faiz Abbasa20008e2020-01-16 19:42:19 +0530286
Faiz Abbasc9644472021-02-04 15:10:51 +0530287 val |= plat->strb_sel << STRBSEL_SHIFT;
288 }
Faiz Abbasce142ff2019-06-11 00:43:38 +0530289
Faiz Abbasc9644472021-02-04 15:10:51 +0530290 regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
Faiz Abbasa20008e2020-01-16 19:42:19 +0530291
Faiz Abbasc9644472021-02-04 15:10:51 +0530292 if (mode > UHS_SDR25 && speed >= CLOCK_TOO_SLOW_HZ) {
293 ret = am654_sdhci_setup_dll(plat, speed);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530294 if (ret)
295 return ret;
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500296
297 plat->dll_enable = true;
Faiz Abbasc9644472021-02-04 15:10:51 +0530298 } else {
299 am654_sdhci_setup_delay_chain(plat, mode);
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500300 plat->dll_enable = false;
Faiz Abbasce142ff2019-06-11 00:43:38 +0530301 }
302
Faiz Abbas194c3752021-02-04 15:10:52 +0530303 regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK,
304 plat->clkbuf_sel);
305
Faiz Abbasce142ff2019-06-11 00:43:38 +0530306 return 0;
307}
308
Faiz Abbasce142ff2019-06-11 00:43:38 +0530309int am654_sdhci_init(struct am654_sdhci_plat *plat)
310{
311 u32 ctl_cfg_2 = 0;
312 u32 mask, val;
313 int ret;
314
315 /* Reset OTAP to default value */
316 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
317 regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0);
318
Faiz Abbas5b29fd42021-02-04 15:10:49 +0530319 if (plat->flags & DLL_CALIB) {
Faiz Abbas794453f2019-06-13 10:29:51 +0530320 regmap_read(plat->base, PHY_STAT1, &val);
321 if (~val & CALDONE_MASK) {
322 /* Calibrate IO lines */
323 regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK,
324 PDB_MASK);
325 ret = regmap_read_poll_timeout(plat->base, PHY_STAT1,
326 val, val & CALDONE_MASK,
327 1, 20);
328 if (ret)
329 return ret;
330 }
Faiz Abbasce142ff2019-06-11 00:43:38 +0530331 }
332
Faiz Abbasce142ff2019-06-11 00:43:38 +0530333 /* Enable pins by setting IO mux to 0 */
Faiz Abbasa20008e2020-01-16 19:42:19 +0530334 if (plat->flags & IOMUX_PRESENT)
335 regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530336
337 /* Set slot type based on SD or eMMC */
338 if (plat->non_removable)
339 ctl_cfg_2 = SLOTTYPE_EMBEDDED;
340
341 regmap_update_bits(plat->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2);
342
343 return 0;
344}
345
Faiz Abbasa8512132020-02-26 13:44:34 +0530346#define MAX_SDCD_DEBOUNCE_TIME 2000
347static int am654_sdhci_deferred_probe(struct sdhci_host *host)
348{
349 struct udevice *dev = host->mmc->dev;
Simon Glassc69cda22020-12-03 16:55:20 -0700350 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbasa8512132020-02-26 13:44:34 +0530351 unsigned long start;
352 int val;
353
354 /*
355 * The controller takes about 1 second to debounce the card detect line
356 * and doesn't let us power on until that time is up. Instead of waiting
357 * for 1 second at every stage, poll on the CARD_PRESENT bit upto a
358 * maximum of 2 seconds to be safe..
359 */
360 start = get_timer(0);
361 do {
362 if (get_timer(start) > MAX_SDCD_DEBOUNCE_TIME)
363 return -ENOMEDIUM;
364
365 val = mmc_getcd(host->mmc);
366 } while (!val);
367
368 am654_sdhci_init(plat);
369
370 return sdhci_probe(dev);
371}
372
Faiz Abbas27a87c82021-02-04 15:10:54 +0530373static void am654_sdhci_write_b(struct sdhci_host *host, u8 val, int reg)
374{
375 if (reg == SDHCI_HOST_CONTROL) {
376 switch (host->mmc->selected_mode) {
377 /*
378 * According to the data manual, HISPD bit
379 * should not be set in these speed modes.
380 */
381 case SD_HS:
382 case MMC_HS:
383 case UHS_SDR12:
384 case UHS_SDR25:
385 val &= ~SDHCI_CTRL_HISPD;
386 default:
387 break;
388 }
389 }
390
391 writeb(val, host->ioaddr + reg);
392}
Faiz Abbasa759abf2021-02-04 15:10:53 +0530393#ifdef MMC_SUPPORTS_TUNING
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500394#define ITAPDLY_LENGTH 32
395#define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1)
396
397static u32 am654_sdhci_calculate_itap(struct udevice *dev, struct window
398 *fail_window, u8 num_fails, bool circular_buffer)
399{
400 u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0;
401 u8 first_fail_start = 0, last_fail_end = 0;
402 struct window pass_window = {0, 0, 0};
403 int prev_fail_end = -1;
404 u8 i;
405
406 if (!num_fails)
407 return ITAPDLY_LAST_INDEX >> 1;
408
409 if (fail_window->length == ITAPDLY_LENGTH) {
410 dev_err(dev, "No passing ITAPDLY, return 0\n");
411 return 0;
412 }
413
414 first_fail_start = fail_window->start;
415 last_fail_end = fail_window[num_fails - 1].end;
416
417 for (i = 0; i < num_fails; i++) {
418 start_fail = fail_window[i].start;
419 end_fail = fail_window[i].end;
420 pass_length = start_fail - (prev_fail_end + 1);
421
422 if (pass_length > pass_window.length) {
423 pass_window.start = prev_fail_end + 1;
424 pass_window.length = pass_length;
425 }
426 prev_fail_end = end_fail;
427 }
428
429 if (!circular_buffer)
430 pass_length = ITAPDLY_LAST_INDEX - last_fail_end;
431 else
432 pass_length = ITAPDLY_LAST_INDEX - last_fail_end + first_fail_start;
433
434 if (pass_length > pass_window.length) {
435 pass_window.start = last_fail_end + 1;
436 pass_window.length = pass_length;
437 }
438
439 if (!circular_buffer)
440 itap = pass_window.start + (pass_window.length >> 1);
441 else
442 itap = (pass_window.start + (pass_window.length >> 1)) % ITAPDLY_LENGTH;
443
444 return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap;
445}
446
Faiz Abbasa759abf2021-02-04 15:10:53 +0530447static int am654_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
448{
449 struct udevice *dev = mmc->dev;
450 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500451 struct window fail_window[ITAPDLY_LENGTH];
Judith Mendez056af042024-04-18 14:00:58 -0500452 int mode = mmc->selected_mode;
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500453 u8 curr_pass, itap;
454 u8 fail_index = 0;
455 u8 prev_pass = 1;
456
457 memset(fail_window, 0, sizeof(fail_window));
Faiz Abbasa759abf2021-02-04 15:10:53 +0530458
459 /* Enable ITAPDLY */
Judith Mendez056af042024-04-18 14:00:58 -0500460 plat->itap_del_ena[mode] = ENABLE;
Faiz Abbasa759abf2021-02-04 15:10:53 +0530461
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500462 for (itap = 0; itap < ITAPDLY_LENGTH; itap++) {
Judith Mendez056af042024-04-18 14:00:58 -0500463 am654_sdhci_write_itapdly(plat, itap, plat->itap_del_ena[mode]);
Faiz Abbasa759abf2021-02-04 15:10:53 +0530464
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500465 curr_pass = !mmc_send_tuning(mmc, opcode);
Faiz Abbasa759abf2021-02-04 15:10:53 +0530466
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500467 if (!curr_pass && prev_pass)
468 fail_window[fail_index].start = itap;
Faiz Abbasa759abf2021-02-04 15:10:53 +0530469
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500470 if (!curr_pass) {
471 fail_window[fail_index].end = itap;
472 fail_window[fail_index].length++;
473 }
474
475 if (curr_pass && !prev_pass)
476 fail_index++;
477
478 prev_pass = curr_pass;
Faiz Abbasa759abf2021-02-04 15:10:53 +0530479 }
Judith Mendez6b8dd9c2024-04-18 14:00:56 -0500480
481 if (fail_window[fail_index].length != 0)
482 fail_index++;
483
484 itap = am654_sdhci_calculate_itap(dev, fail_window, fail_index,
485 plat->dll_enable);
486
Judith Mendez056af042024-04-18 14:00:58 -0500487 am654_sdhci_write_itapdly(plat, itap, plat->itap_del_ena[mode]);
Faiz Abbasa759abf2021-02-04 15:10:53 +0530488
489 return 0;
490}
491#endif
Faiz Abbasa8512132020-02-26 13:44:34 +0530492const struct sdhci_ops am654_sdhci_ops = {
Faiz Abbasa759abf2021-02-04 15:10:53 +0530493#ifdef MMC_SUPPORTS_TUNING
494 .platform_execute_tuning = am654_sdhci_execute_tuning,
495#endif
Faiz Abbasa8512132020-02-26 13:44:34 +0530496 .deferred_probe = am654_sdhci_deferred_probe,
497 .set_ios_post = &am654_sdhci_set_ios_post,
Faiz Abbase9fbbba2021-02-04 15:10:55 +0530498 .set_control_reg = sdhci_set_control_reg,
Faiz Abbas27a87c82021-02-04 15:10:54 +0530499 .write_b = am654_sdhci_write_b,
Faiz Abbasa8512132020-02-26 13:44:34 +0530500};
501
502const struct am654_driver_data am654_drv_data = {
503 .ops = &am654_sdhci_ops,
Faiz Abbas8c32b5f2021-02-04 15:10:50 +0530504 .flags = DLL_PRESENT | IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT,
505};
506
507const struct am654_driver_data am654_sr1_drv_data = {
508 .ops = &am654_sdhci_ops,
Faiz Abbas5b29fd42021-02-04 15:10:49 +0530509 .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | DLL_CALIB |
510 STRBSEL_4_BIT,
Faiz Abbasa8512132020-02-26 13:44:34 +0530511};
512
513const struct am654_driver_data j721e_8bit_drv_data = {
514 .ops = &am654_sdhci_ops,
Faiz Abbas5b29fd42021-02-04 15:10:49 +0530515 .flags = DLL_PRESENT | DLL_CALIB,
Faiz Abbasa8512132020-02-26 13:44:34 +0530516};
517
518static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host)
519{
520 struct udevice *dev = host->mmc->dev;
Simon Glassc69cda22020-12-03 16:55:20 -0700521 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Nitin Yadav5048b5c2024-04-18 14:00:57 -0500522 int mode = host->mmc->selected_mode;
523 u32 otap_del_sel;
Judith Mendez056af042024-04-18 14:00:58 -0500524 u32 itap_del_ena;
Nitin Yadav5048b5c2024-04-18 14:00:57 -0500525 u32 itap_del_sel;
526 u32 mask, val;
Faiz Abbasa8512132020-02-26 13:44:34 +0530527
Nitin Yadav5048b5c2024-04-18 14:00:57 -0500528 otap_del_sel = plat->otap_del_sel[mode];
529
Faiz Abbasa8512132020-02-26 13:44:34 +0530530 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
Nitin Yadav5048b5c2024-04-18 14:00:57 -0500531 val = (1 << OTAPDLYENA_SHIFT) |
532 (otap_del_sel << OTAPDLYSEL_SHIFT);
533
Judith Mendez056af042024-04-18 14:00:58 -0500534 itap_del_ena = plat->itap_del_ena[mode];
Nitin Yadav5048b5c2024-04-18 14:00:57 -0500535 itap_del_sel = plat->itap_del_sel[mode];
536
537 mask |= ITAPDLYENA_MASK | ITAPDLYSEL_MASK;
Judith Mendez056af042024-04-18 14:00:58 -0500538 val |= (itap_del_ena << ITAPDLYENA_SHIFT) |
Nitin Yadav5048b5c2024-04-18 14:00:57 -0500539 (itap_del_sel << ITAPDLYSEL_SHIFT);
540
541 regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK,
542 1 << ITAPCHGWIN_SHIFT);
Faiz Abbasa8512132020-02-26 13:44:34 +0530543 regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
Nitin Yadav5048b5c2024-04-18 14:00:57 -0500544 regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
Faiz Abbasa8512132020-02-26 13:44:34 +0530545
Faiz Abbas194c3752021-02-04 15:10:52 +0530546 regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK,
547 plat->clkbuf_sel);
548
Faiz Abbasa8512132020-02-26 13:44:34 +0530549 return 0;
550}
551
552const struct sdhci_ops j721e_4bit_sdhci_ops = {
Faiz Abbasa759abf2021-02-04 15:10:53 +0530553#ifdef MMC_SUPPORTS_TUNING
554 .platform_execute_tuning = am654_sdhci_execute_tuning,
555#endif
Faiz Abbasa8512132020-02-26 13:44:34 +0530556 .deferred_probe = am654_sdhci_deferred_probe,
557 .set_ios_post = &j721e_4bit_sdhci_set_ios_post,
Faiz Abbase9fbbba2021-02-04 15:10:55 +0530558 .set_control_reg = sdhci_set_control_reg,
Faiz Abbas27a87c82021-02-04 15:10:54 +0530559 .write_b = am654_sdhci_write_b,
Faiz Abbasa8512132020-02-26 13:44:34 +0530560};
561
562const struct am654_driver_data j721e_4bit_drv_data = {
563 .ops = &j721e_4bit_sdhci_ops,
564 .flags = IOMUX_PRESENT,
565};
566
Dave Gerlach7288bea2021-04-23 11:27:40 -0500567static const struct am654_driver_data sdhci_am64_8bit_drvdata = {
568 .ops = &am654_sdhci_ops,
569 .flags = DLL_PRESENT | DLL_CALIB,
570};
571
572static const struct am654_driver_data sdhci_am64_4bit_drvdata = {
573 .ops = &j721e_4bit_sdhci_ops,
574 .flags = IOMUX_PRESENT,
575};
576
Faiz Abbas8c32b5f2021-02-04 15:10:50 +0530577const struct soc_attr am654_sdhci_soc_attr[] = {
578 { .family = "AM65X", .revision = "SR1.0", .data = &am654_sr1_drv_data},
579 {/* sentinel */}
580};
581
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530582static int sdhci_am654_get_otap_delay(struct udevice *dev,
583 struct mmc_config *cfg)
584{
Simon Glassc69cda22020-12-03 16:55:20 -0700585 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530586 int ret;
587 int i;
588
589 /* ti,otap-del-sel-legacy is mandatory */
590 ret = dev_read_u32(dev, "ti,otap-del-sel-legacy",
591 &plat->otap_del_sel[0]);
592 if (ret)
593 return ret;
594 /*
595 * Remove the corresponding capability if an otap-del-sel
596 * value is not found
597 */
Nitin Yadav5048b5c2024-04-18 14:00:57 -0500598 for (i = MMC_LEGACY; i <= MMC_HS_400; i++) {
Faiz Abbasc9644472021-02-04 15:10:51 +0530599 ret = dev_read_u32(dev, td[i].otap_binding,
600 &plat->otap_del_sel[i]);
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530601 if (ret) {
Faiz Abbasc9644472021-02-04 15:10:51 +0530602 dev_dbg(dev, "Couldn't find %s\n", td[i].otap_binding);
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530603 /*
604 * Remove the corresponding capability
605 * if an otap-del-sel value is not found
606 */
607 cfg->host_caps &= ~td[i].capability;
608 }
Faiz Abbasc9644472021-02-04 15:10:51 +0530609
Judith Mendez056af042024-04-18 14:00:58 -0500610 if (td[i].itap_binding) {
611 ret = dev_read_u32(dev, td[i].itap_binding,
612 &plat->itap_del_sel[i]);
613
614 if (!ret)
615 plat->itap_del_ena[i] = ENABLE;
616 }
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530617 }
618
619 return 0;
620}
621
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530622static int am654_sdhci_probe(struct udevice *dev)
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530623{
Faiz Abbasa20008e2020-01-16 19:42:19 +0530624 struct am654_driver_data *drv_data =
625 (struct am654_driver_data *)dev_get_driver_data(dev);
Simon Glassc69cda22020-12-03 16:55:20 -0700626 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530627 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
628 struct sdhci_host *host = dev_get_priv(dev);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530629 struct mmc_config *cfg = &plat->cfg;
Faiz Abbas8c32b5f2021-02-04 15:10:50 +0530630 const struct soc_attr *soc;
631 const struct am654_driver_data *soc_drv_data;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530632 struct clk clk;
633 unsigned long clock;
634 int ret;
635
Faiz Abbasfe0e30c2020-01-16 19:42:18 +0530636 ret = clk_get_by_name(dev, "clk_xin", &clk);
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530637 if (ret) {
638 dev_err(dev, "failed to get clock\n");
639 return ret;
640 }
641
642 clock = clk_get_rate(&clk);
643 if (IS_ERR_VALUE(clock)) {
644 dev_err(dev, "failed to get rate\n");
645 return clock;
646 }
647
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530648 host->max_clk = clock;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530649 host->mmc = &plat->mmc;
Faiz Abbasce142ff2019-06-11 00:43:38 +0530650 host->mmc->dev = dev;
Faiz Abbas27a87c82021-02-04 15:10:54 +0530651 host->ops = drv_data->ops;
Faiz Abbasce142ff2019-06-11 00:43:38 +0530652 ret = sdhci_setup_cfg(cfg, host, cfg->f_max,
653 AM654_SDHCI_MIN_FREQ);
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530654 if (ret)
655 return ret;
Faiz Abbasa20008e2020-01-16 19:42:19 +0530656
Faiz Abbasc7d106b2020-02-26 13:44:33 +0530657 ret = sdhci_am654_get_otap_delay(dev, cfg);
658 if (ret)
659 return ret;
660
Faiz Abbas8c32b5f2021-02-04 15:10:50 +0530661 /* Update ops based on SoC revision */
662 soc = soc_device_match(am654_sdhci_soc_attr);
663 if (soc && soc->data) {
664 soc_drv_data = soc->data;
665 host->ops = soc_drv_data->ops;
666 }
667
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530668 host->mmc->priv = host;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530669 upriv->mmc = host->mmc;
670
Faiz Abbasce142ff2019-06-11 00:43:38 +0530671 regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1);
672
Faiz Abbasa8512132020-02-26 13:44:34 +0530673 return 0;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530674}
675
Simon Glassd1998a92020-12-03 16:55:21 -0700676static int am654_sdhci_of_to_plat(struct udevice *dev)
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530677{
Simon Glassc69cda22020-12-03 16:55:20 -0700678 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530679 struct sdhci_host *host = dev_get_priv(dev);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530680 struct mmc_config *cfg = &plat->cfg;
681 u32 drv_strength;
682 int ret;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530683
684 host->name = dev->name;
Johan Jonkera12a73b2023-03-13 01:32:04 +0100685 host->ioaddr = dev_read_addr_ptr(dev);
Faiz Abbasce142ff2019-06-11 00:43:38 +0530686 plat->non_removable = dev_read_bool(dev, "non-removable");
687
Faiz Abbas794453f2019-06-13 10:29:51 +0530688 if (plat->flags & DLL_PRESENT) {
689 ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp);
690 if (ret)
691 return ret;
Faiz Abbasce142ff2019-06-11 00:43:38 +0530692
Faiz Abbas794453f2019-06-13 10:29:51 +0530693 ret = dev_read_u32(dev, "ti,driver-strength-ohm",
694 &drv_strength);
695 if (ret)
696 return ret;
697
698 switch (drv_strength) {
699 case 50:
700 plat->drv_strength = DRIVER_STRENGTH_50_OHM;
701 break;
702 case 33:
703 plat->drv_strength = DRIVER_STRENGTH_33_OHM;
704 break;
705 case 66:
706 plat->drv_strength = DRIVER_STRENGTH_66_OHM;
707 break;
708 case 100:
709 plat->drv_strength = DRIVER_STRENGTH_100_OHM;
710 break;
711 case 40:
712 plat->drv_strength = DRIVER_STRENGTH_40_OHM;
713 break;
714 default:
715 dev_err(dev, "Invalid driver strength\n");
716 return -EINVAL;
717 }
Faiz Abbasce142ff2019-06-11 00:43:38 +0530718 }
719
Aswath Govindraju46077ef2021-05-25 15:08:23 +0530720 dev_read_u32(dev, "ti,strobe-sel", &plat->strb_sel);
Faiz Abbas194c3752021-02-04 15:10:52 +0530721 dev_read_u32(dev, "ti,clkbuf-sel", &plat->clkbuf_sel);
722
Faiz Abbasce142ff2019-06-11 00:43:38 +0530723 ret = mmc_of_parse(dev, cfg);
724 if (ret)
725 return ret;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530726
727 return 0;
728}
729
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530730static int am654_sdhci_bind(struct udevice *dev)
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530731{
Faiz Abbasa20008e2020-01-16 19:42:19 +0530732 struct am654_driver_data *drv_data =
733 (struct am654_driver_data *)dev_get_driver_data(dev);
Simon Glassc69cda22020-12-03 16:55:20 -0700734 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbas8c32b5f2021-02-04 15:10:50 +0530735 const struct soc_attr *soc;
736 const struct am654_driver_data *soc_drv_data;
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530737
Faiz Abbasa20008e2020-01-16 19:42:19 +0530738 plat->flags = drv_data->flags;
739
Faiz Abbas8c32b5f2021-02-04 15:10:50 +0530740 /* Update flags based on SoC revision */
741 soc = soc_device_match(am654_sdhci_soc_attr);
742 if (soc && soc->data) {
743 soc_drv_data = soc->data;
744 plat->flags = soc_drv_data->flags;
745 }
746
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530747 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
748}
749
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530750static const struct udevice_id am654_sdhci_ids[] = {
Faiz Abbas794453f2019-06-13 10:29:51 +0530751 {
752 .compatible = "ti,am654-sdhci-5.1",
Faiz Abbasa20008e2020-01-16 19:42:19 +0530753 .data = (ulong)&am654_drv_data,
Faiz Abbas794453f2019-06-13 10:29:51 +0530754 },
755 {
756 .compatible = "ti,j721e-sdhci-8bit",
Faiz Abbasa20008e2020-01-16 19:42:19 +0530757 .data = (ulong)&j721e_8bit_drv_data,
Faiz Abbas794453f2019-06-13 10:29:51 +0530758 },
759 {
760 .compatible = "ti,j721e-sdhci-4bit",
Faiz Abbasa20008e2020-01-16 19:42:19 +0530761 .data = (ulong)&j721e_4bit_drv_data,
Faiz Abbas794453f2019-06-13 10:29:51 +0530762 },
Dave Gerlach7288bea2021-04-23 11:27:40 -0500763 {
764 .compatible = "ti,am64-sdhci-8bit",
765 .data = (ulong)&sdhci_am64_8bit_drvdata,
766 },
767 {
768 .compatible = "ti,am64-sdhci-4bit",
769 .data = (ulong)&sdhci_am64_4bit_drvdata,
770 },
Aswath Govindrajued6d7812022-05-25 13:38:39 +0530771 {
772 .compatible = "ti,am62-sdhci",
773 .data = (ulong)&sdhci_am64_4bit_drvdata,
774 },
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530775 { }
776};
777
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530778U_BOOT_DRIVER(am654_sdhci_drv) = {
779 .name = "am654_sdhci",
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530780 .id = UCLASS_MMC,
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530781 .of_match = am654_sdhci_ids,
Simon Glassd1998a92020-12-03 16:55:21 -0700782 .of_to_plat = am654_sdhci_of_to_plat,
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530783 .ops = &sdhci_ops,
Faiz Abbas3a1a0df2019-06-11 00:43:31 +0530784 .bind = am654_sdhci_bind,
785 .probe = am654_sdhci_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700786 .priv_auto = sizeof(struct sdhci_host),
Simon Glasscaa4daa2020-12-03 16:55:18 -0700787 .plat_auto = sizeof(struct am654_sdhci_plat),
Lokesh Vutlaaaa449f2018-08-27 15:57:54 +0530788};