blob: fadab7d40bb795232f86586fe4352aa539bdc754 [file] [log] [blame]
Lokesh Vutlabc9979f2018-08-27 15:57:54 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
Nishanth Menoneaa39c62023-11-01 15:56:03 -05003 * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
Lokesh Vutlabc9979f2018-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 Abbas7a7e2c72021-02-04 15:10:53 +053012#include <mmc.h>
Lokesh Vutlabc9979f2018-08-27 15:57:54 +053013#include <power-domain.h>
Faiz Abbase9aed582019-06-11 00:43:38 +053014#include <regmap.h>
Lokesh Vutlabc9979f2018-08-27 15:57:54 +053015#include <sdhci.h>
Faiz Abbas2c2fc962021-02-04 15:10:50 +053016#include <soc.h>
Simon Glass9bc15642020-02-03 07:36:16 -070017#include <dm/device_compat.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060018#include <linux/bitops.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070019#include <linux/err.h>
Lokesh Vutlabc9979f2018-08-27 15:57:54 +053020
Faiz Abbase9aed582019-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 Abbas8cc051e2020-01-16 19:42:19 +053044#define STRBSEL_4BIT_MASK GENMASK(27, 24)
45#define STRBSEL_8BIT_MASK GENMASK(31, 24)
Faiz Abbase9aed582019-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 Abbas8cc051e2020-01-16 19:42:19 +053050#define FREQSEL_SHIFT 8
51#define FREQSEL_MASK GENMASK(10, 8)
Faiz Abbasc73f04e2021-02-04 15:10:52 +053052#define CLKBUFSEL_SHIFT 0
53#define CLKBUFSEL_MASK GENMASK(2, 0)
Faiz Abbase9aed582019-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 Abbasdef2a0f2021-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 Abbase9aed582019-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 Abbasd8fb3092019-06-11 00:43:31 +053085#define AM654_SDHCI_MIN_FREQ 400000
Faiz Abbasdef2a0f2021-02-04 15:10:51 +053086#define CLOCK_TOO_SLOW_HZ 50000000
Lokesh Vutlabc9979f2018-08-27 15:57:54 +053087
Judith Mendez87bcbde2024-04-18 14:00:58 -050088#define ENABLE 0x1
89
Faiz Abbasd8fb3092019-06-11 00:43:31 +053090struct am654_sdhci_plat {
Lokesh Vutlabc9979f2018-08-27 15:57:54 +053091 struct mmc_config cfg;
92 struct mmc mmc;
Faiz Abbase9aed582019-06-11 00:43:38 +053093 struct regmap *base;
94 bool non_removable;
Faiz Abbas7101e122020-07-29 07:03:41 +053095 u32 otap_del_sel[MMC_MODES_END];
Faiz Abbasdef2a0f2021-02-04 15:10:51 +053096 u32 itap_del_sel[MMC_MODES_END];
Judith Mendez87bcbde2024-04-18 14:00:58 -050097 u32 itap_del_ena[MMC_MODES_END];
Faiz Abbase9aed582019-06-11 00:43:38 +053098 u32 trm_icp;
99 u32 drv_strength;
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530100 u32 strb_sel;
Faiz Abbasc73f04e2021-02-04 15:10:52 +0530101 u32 clkbuf_sel;
Faiz Abbasfd8be702019-06-13 10:29:51 +0530102 u32 flags;
Judith Mendez81c1d442024-04-18 14:00:56 -0500103 bool dll_enable;
Faiz Abbasb7f57bb2021-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 Abbas947e8f32021-02-04 15:10:49 +0530108#define DLL_CALIB BIT(4)
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530109};
110
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530111struct timing_data {
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530112 const char *otap_binding;
113 const char *itap_binding;
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530114 u32 capability;
115};
116
Judith Mendez81c1d442024-04-18 14:00:56 -0500117struct window {
118 u8 start;
119 u8 end;
120 u8 length;
121};
122
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530123static const struct timing_data td[] = {
Faiz Abbasdef2a0f2021-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 Abbasc6eb9e72020-02-26 13:44:33 +0530157};
158
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530159struct am654_driver_data {
160 const struct sdhci_ops *ops;
161 u32 flags;
162};
163
Faiz Abbasdef2a0f2021-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 Mendez87bcbde2024-04-18 14:00:58 -0500229 u32 itapdly, u32 enable)
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530230{
Judith Mendez87bcbde2024-04-18 14:00:58 -0500231 regmap_update_bits(plat->base, PHY_CTRL4, ITAPDLYENA_MASK,
232 enable << ITAPDLYENA_SHIFT);
Faiz Abbasdef2a0f2021-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 Mendez87bcbde2024-04-18 14:00:58 -0500250 am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode],
251 plat->itap_del_ena[mode]);
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530252}
253
Faiz Abbase9aed582019-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 Glassfa20e932020-12-03 16:55:20 -0700257 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbase9aed582019-06-11 00:43:38 +0530258 unsigned int speed = host->mmc->clock;
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530259 int mode = host->mmc->selected_mode;
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530260 u32 otap_del_sel;
Faiz Abbase9aed582019-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 Abbas2c45a2c2021-02-04 15:10:47 +0530269 regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0);
Faiz Abbase9aed582019-06-11 00:43:38 +0530270
271 /* restart clock */
272 sdhci_set_clock(host->mmc, speed);
273
274 /* switch phy back on */
Faiz Abbasdef2a0f2021-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 Abbas8cc051e2020-01-16 19:42:19 +0530279
Faiz Abbasdef2a0f2021-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 Abbas8cc051e2020-01-16 19:42:19 +0530286
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530287 val |= plat->strb_sel << STRBSEL_SHIFT;
288 }
Faiz Abbas947e8f32021-02-04 15:10:49 +0530289
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530290 regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
Faiz Abbas947e8f32021-02-04 15:10:49 +0530291
Judith Mendezc9eb1dc2024-04-18 14:00:59 -0500292 if ((mode > UHS_SDR25 || mode == MMC_DDR_52) && speed >= CLOCK_TOO_SLOW_HZ) {
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530293 ret = am654_sdhci_setup_dll(plat, speed);
Faiz Abbase9aed582019-06-11 00:43:38 +0530294 if (ret)
295 return ret;
Judith Mendez81c1d442024-04-18 14:00:56 -0500296
297 plat->dll_enable = true;
Judith Mendez5d217152024-04-18 14:01:00 -0500298 if (mode == MMC_HS_400) {
299 plat->itap_del_ena[mode] = ENABLE;
300 plat->itap_del_sel[mode] = plat->itap_del_sel[mode - 1];
301 }
302
Judith Mendezc9eb1dc2024-04-18 14:00:59 -0500303 am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode],
304 plat->itap_del_ena[mode]);
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530305 } else {
306 am654_sdhci_setup_delay_chain(plat, mode);
Judith Mendez81c1d442024-04-18 14:00:56 -0500307 plat->dll_enable = false;
Faiz Abbase9aed582019-06-11 00:43:38 +0530308 }
309
Faiz Abbasc73f04e2021-02-04 15:10:52 +0530310 regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK,
311 plat->clkbuf_sel);
312
Faiz Abbase9aed582019-06-11 00:43:38 +0530313 return 0;
314}
315
Faiz Abbase9aed582019-06-11 00:43:38 +0530316int am654_sdhci_init(struct am654_sdhci_plat *plat)
317{
318 u32 ctl_cfg_2 = 0;
319 u32 mask, val;
320 int ret;
321
322 /* Reset OTAP to default value */
323 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
324 regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0);
325
Faiz Abbas947e8f32021-02-04 15:10:49 +0530326 if (plat->flags & DLL_CALIB) {
Faiz Abbasfd8be702019-06-13 10:29:51 +0530327 regmap_read(plat->base, PHY_STAT1, &val);
328 if (~val & CALDONE_MASK) {
329 /* Calibrate IO lines */
330 regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK,
331 PDB_MASK);
332 ret = regmap_read_poll_timeout(plat->base, PHY_STAT1,
333 val, val & CALDONE_MASK,
334 1, 20);
335 if (ret)
336 return ret;
337 }
Faiz Abbasfd8be702019-06-13 10:29:51 +0530338 }
Faiz Abbase9aed582019-06-11 00:43:38 +0530339
340 /* Enable pins by setting IO mux to 0 */
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530341 if (plat->flags & IOMUX_PRESENT)
342 regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0);
Faiz Abbase9aed582019-06-11 00:43:38 +0530343
344 /* Set slot type based on SD or eMMC */
345 if (plat->non_removable)
346 ctl_cfg_2 = SLOTTYPE_EMBEDDED;
347
348 regmap_update_bits(plat->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2);
349
350 return 0;
351}
352
Faiz Abbase4425cb2020-02-26 13:44:34 +0530353#define MAX_SDCD_DEBOUNCE_TIME 2000
354static int am654_sdhci_deferred_probe(struct sdhci_host *host)
355{
356 struct udevice *dev = host->mmc->dev;
Simon Glassfa20e932020-12-03 16:55:20 -0700357 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbase4425cb2020-02-26 13:44:34 +0530358 unsigned long start;
359 int val;
360
361 /*
362 * The controller takes about 1 second to debounce the card detect line
363 * and doesn't let us power on until that time is up. Instead of waiting
364 * for 1 second at every stage, poll on the CARD_PRESENT bit upto a
365 * maximum of 2 seconds to be safe..
366 */
367 start = get_timer(0);
368 do {
369 if (get_timer(start) > MAX_SDCD_DEBOUNCE_TIME)
370 return -ENOMEDIUM;
371
372 val = mmc_getcd(host->mmc);
373 } while (!val);
374
375 am654_sdhci_init(plat);
376
377 return sdhci_probe(dev);
378}
379
Faiz Abbas36c8c5c2021-02-04 15:10:54 +0530380static void am654_sdhci_write_b(struct sdhci_host *host, u8 val, int reg)
381{
382 if (reg == SDHCI_HOST_CONTROL) {
383 switch (host->mmc->selected_mode) {
384 /*
385 * According to the data manual, HISPD bit
386 * should not be set in these speed modes.
387 */
388 case SD_HS:
389 case MMC_HS:
390 case UHS_SDR12:
391 case UHS_SDR25:
392 val &= ~SDHCI_CTRL_HISPD;
393 default:
394 break;
395 }
396 }
397
398 writeb(val, host->ioaddr + reg);
399}
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530400#ifdef MMC_SUPPORTS_TUNING
Judith Mendez81c1d442024-04-18 14:00:56 -0500401#define ITAPDLY_LENGTH 32
402#define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1)
403
404static u32 am654_sdhci_calculate_itap(struct udevice *dev, struct window
405 *fail_window, u8 num_fails, bool circular_buffer)
406{
407 u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0;
408 u8 first_fail_start = 0, last_fail_end = 0;
409 struct window pass_window = {0, 0, 0};
410 int prev_fail_end = -1;
411 u8 i;
412
413 if (!num_fails)
414 return ITAPDLY_LAST_INDEX >> 1;
415
416 if (fail_window->length == ITAPDLY_LENGTH) {
417 dev_err(dev, "No passing ITAPDLY, return 0\n");
418 return 0;
419 }
420
421 first_fail_start = fail_window->start;
422 last_fail_end = fail_window[num_fails - 1].end;
423
424 for (i = 0; i < num_fails; i++) {
425 start_fail = fail_window[i].start;
426 end_fail = fail_window[i].end;
427 pass_length = start_fail - (prev_fail_end + 1);
428
429 if (pass_length > pass_window.length) {
430 pass_window.start = prev_fail_end + 1;
431 pass_window.length = pass_length;
432 }
433 prev_fail_end = end_fail;
434 }
435
436 if (!circular_buffer)
437 pass_length = ITAPDLY_LAST_INDEX - last_fail_end;
438 else
439 pass_length = ITAPDLY_LAST_INDEX - last_fail_end + first_fail_start;
440
441 if (pass_length > pass_window.length) {
442 pass_window.start = last_fail_end + 1;
443 pass_window.length = pass_length;
444 }
445
446 if (!circular_buffer)
447 itap = pass_window.start + (pass_window.length >> 1);
448 else
449 itap = (pass_window.start + (pass_window.length >> 1)) % ITAPDLY_LENGTH;
450
451 return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap;
452}
453
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530454static int am654_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
455{
456 struct udevice *dev = mmc->dev;
457 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Judith Mendez81c1d442024-04-18 14:00:56 -0500458 struct window fail_window[ITAPDLY_LENGTH];
Judith Mendez87bcbde2024-04-18 14:00:58 -0500459 int mode = mmc->selected_mode;
Judith Mendez81c1d442024-04-18 14:00:56 -0500460 u8 curr_pass, itap;
461 u8 fail_index = 0;
462 u8 prev_pass = 1;
463
464 memset(fail_window, 0, sizeof(fail_window));
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530465
466 /* Enable ITAPDLY */
Judith Mendez87bcbde2024-04-18 14:00:58 -0500467 plat->itap_del_ena[mode] = ENABLE;
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530468
Judith Mendez81c1d442024-04-18 14:00:56 -0500469 for (itap = 0; itap < ITAPDLY_LENGTH; itap++) {
Judith Mendez87bcbde2024-04-18 14:00:58 -0500470 am654_sdhci_write_itapdly(plat, itap, plat->itap_del_ena[mode]);
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530471
Judith Mendez81c1d442024-04-18 14:00:56 -0500472 curr_pass = !mmc_send_tuning(mmc, opcode);
473
474 if (!curr_pass && prev_pass)
475 fail_window[fail_index].start = itap;
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530476
Judith Mendez81c1d442024-04-18 14:00:56 -0500477 if (!curr_pass) {
478 fail_window[fail_index].end = itap;
479 fail_window[fail_index].length++;
480 }
481
482 if (curr_pass && !prev_pass)
483 fail_index++;
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530484
Judith Mendez81c1d442024-04-18 14:00:56 -0500485 prev_pass = curr_pass;
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530486 }
Judith Mendez81c1d442024-04-18 14:00:56 -0500487
488 if (fail_window[fail_index].length != 0)
489 fail_index++;
490
491 itap = am654_sdhci_calculate_itap(dev, fail_window, fail_index,
492 plat->dll_enable);
493
Judith Mendez5d217152024-04-18 14:01:00 -0500494 /* Save ITAPDLY */
495 plat->itap_del_sel[mode] = itap;
496
Judith Mendez87bcbde2024-04-18 14:00:58 -0500497 am654_sdhci_write_itapdly(plat, itap, plat->itap_del_ena[mode]);
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530498
499 return 0;
500}
501#endif
Faiz Abbase4425cb2020-02-26 13:44:34 +0530502const struct sdhci_ops am654_sdhci_ops = {
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530503#ifdef MMC_SUPPORTS_TUNING
504 .platform_execute_tuning = am654_sdhci_execute_tuning,
505#endif
Faiz Abbase4425cb2020-02-26 13:44:34 +0530506 .deferred_probe = am654_sdhci_deferred_probe,
507 .set_ios_post = &am654_sdhci_set_ios_post,
Faiz Abbas9c10cfe2021-02-04 15:10:55 +0530508 .set_control_reg = sdhci_set_control_reg,
Faiz Abbas36c8c5c2021-02-04 15:10:54 +0530509 .write_b = am654_sdhci_write_b,
Faiz Abbase4425cb2020-02-26 13:44:34 +0530510};
511
512const struct am654_driver_data am654_drv_data = {
513 .ops = &am654_sdhci_ops,
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530514 .flags = DLL_PRESENT | IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT,
515};
516
517const struct am654_driver_data am654_sr1_drv_data = {
518 .ops = &am654_sdhci_ops,
Faiz Abbas947e8f32021-02-04 15:10:49 +0530519 .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | DLL_CALIB |
520 STRBSEL_4_BIT,
Faiz Abbase4425cb2020-02-26 13:44:34 +0530521};
522
523const struct am654_driver_data j721e_8bit_drv_data = {
524 .ops = &am654_sdhci_ops,
Faiz Abbas947e8f32021-02-04 15:10:49 +0530525 .flags = DLL_PRESENT | DLL_CALIB,
Faiz Abbase4425cb2020-02-26 13:44:34 +0530526};
527
528static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host)
529{
530 struct udevice *dev = host->mmc->dev;
Simon Glassfa20e932020-12-03 16:55:20 -0700531 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Nitin Yadav83db1f92024-04-18 14:00:57 -0500532 int mode = host->mmc->selected_mode;
533 u32 otap_del_sel;
Judith Mendez87bcbde2024-04-18 14:00:58 -0500534 u32 itap_del_ena;
Nitin Yadav83db1f92024-04-18 14:00:57 -0500535 u32 itap_del_sel;
536 u32 mask, val;
Faiz Abbase4425cb2020-02-26 13:44:34 +0530537
Nitin Yadav83db1f92024-04-18 14:00:57 -0500538 otap_del_sel = plat->otap_del_sel[mode];
539
Faiz Abbase4425cb2020-02-26 13:44:34 +0530540 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
Nitin Yadav83db1f92024-04-18 14:00:57 -0500541 val = (1 << OTAPDLYENA_SHIFT) |
542 (otap_del_sel << OTAPDLYSEL_SHIFT);
543
Judith Mendez87bcbde2024-04-18 14:00:58 -0500544 itap_del_ena = plat->itap_del_ena[mode];
Nitin Yadav83db1f92024-04-18 14:00:57 -0500545 itap_del_sel = plat->itap_del_sel[mode];
546
547 mask |= ITAPDLYENA_MASK | ITAPDLYSEL_MASK;
Judith Mendez87bcbde2024-04-18 14:00:58 -0500548 val |= (itap_del_ena << ITAPDLYENA_SHIFT) |
Nitin Yadav83db1f92024-04-18 14:00:57 -0500549 (itap_del_sel << ITAPDLYSEL_SHIFT);
550
551 regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK,
552 1 << ITAPCHGWIN_SHIFT);
Faiz Abbase4425cb2020-02-26 13:44:34 +0530553 regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
Nitin Yadav83db1f92024-04-18 14:00:57 -0500554 regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
Faiz Abbase4425cb2020-02-26 13:44:34 +0530555
Faiz Abbasc73f04e2021-02-04 15:10:52 +0530556 regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK,
557 plat->clkbuf_sel);
558
Faiz Abbase4425cb2020-02-26 13:44:34 +0530559 return 0;
560}
561
562const struct sdhci_ops j721e_4bit_sdhci_ops = {
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530563#ifdef MMC_SUPPORTS_TUNING
564 .platform_execute_tuning = am654_sdhci_execute_tuning,
565#endif
Faiz Abbase4425cb2020-02-26 13:44:34 +0530566 .deferred_probe = am654_sdhci_deferred_probe,
567 .set_ios_post = &j721e_4bit_sdhci_set_ios_post,
Faiz Abbas9c10cfe2021-02-04 15:10:55 +0530568 .set_control_reg = sdhci_set_control_reg,
Faiz Abbas36c8c5c2021-02-04 15:10:54 +0530569 .write_b = am654_sdhci_write_b,
Faiz Abbase4425cb2020-02-26 13:44:34 +0530570};
571
572const struct am654_driver_data j721e_4bit_drv_data = {
573 .ops = &j721e_4bit_sdhci_ops,
574 .flags = IOMUX_PRESENT,
575};
576
Dave Gerlach057d6af2021-04-23 11:27:40 -0500577static const struct am654_driver_data sdhci_am64_8bit_drvdata = {
578 .ops = &am654_sdhci_ops,
579 .flags = DLL_PRESENT | DLL_CALIB,
580};
581
582static const struct am654_driver_data sdhci_am64_4bit_drvdata = {
583 .ops = &j721e_4bit_sdhci_ops,
584 .flags = IOMUX_PRESENT,
585};
586
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530587const struct soc_attr am654_sdhci_soc_attr[] = {
588 { .family = "AM65X", .revision = "SR1.0", .data = &am654_sr1_drv_data},
589 {/* sentinel */}
590};
591
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530592static int sdhci_am654_get_otap_delay(struct udevice *dev,
593 struct mmc_config *cfg)
594{
Simon Glassfa20e932020-12-03 16:55:20 -0700595 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530596 int ret;
597 int i;
598
599 /* ti,otap-del-sel-legacy is mandatory */
600 ret = dev_read_u32(dev, "ti,otap-del-sel-legacy",
601 &plat->otap_del_sel[0]);
602 if (ret)
603 return ret;
604 /*
605 * Remove the corresponding capability if an otap-del-sel
606 * value is not found
607 */
Nitin Yadav83db1f92024-04-18 14:00:57 -0500608 for (i = MMC_LEGACY; i <= MMC_HS_400; i++) {
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530609 ret = dev_read_u32(dev, td[i].otap_binding,
610 &plat->otap_del_sel[i]);
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530611 if (ret) {
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530612 dev_dbg(dev, "Couldn't find %s\n", td[i].otap_binding);
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530613 /*
614 * Remove the corresponding capability
615 * if an otap-del-sel value is not found
616 */
617 cfg->host_caps &= ~td[i].capability;
618 }
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530619
Judith Mendez87bcbde2024-04-18 14:00:58 -0500620 if (td[i].itap_binding) {
621 ret = dev_read_u32(dev, td[i].itap_binding,
622 &plat->itap_del_sel[i]);
623
624 if (!ret)
625 plat->itap_del_ena[i] = ENABLE;
626 }
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530627 }
628
629 return 0;
630}
631
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530632static int am654_sdhci_probe(struct udevice *dev)
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530633{
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530634 struct am654_driver_data *drv_data =
635 (struct am654_driver_data *)dev_get_driver_data(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700636 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530637 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
638 struct sdhci_host *host = dev_get_priv(dev);
Faiz Abbase9aed582019-06-11 00:43:38 +0530639 struct mmc_config *cfg = &plat->cfg;
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530640 const struct soc_attr *soc;
641 const struct am654_driver_data *soc_drv_data;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530642 struct clk clk;
643 unsigned long clock;
644 int ret;
645
Faiz Abbasdc2bcc22020-01-16 19:42:18 +0530646 ret = clk_get_by_name(dev, "clk_xin", &clk);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530647 if (ret) {
648 dev_err(dev, "failed to get clock\n");
649 return ret;
650 }
651
652 clock = clk_get_rate(&clk);
653 if (IS_ERR_VALUE(clock)) {
654 dev_err(dev, "failed to get rate\n");
655 return clock;
656 }
657
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530658 host->max_clk = clock;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530659 host->mmc = &plat->mmc;
Faiz Abbase9aed582019-06-11 00:43:38 +0530660 host->mmc->dev = dev;
Faiz Abbas36c8c5c2021-02-04 15:10:54 +0530661 host->ops = drv_data->ops;
Faiz Abbase9aed582019-06-11 00:43:38 +0530662 ret = sdhci_setup_cfg(cfg, host, cfg->f_max,
663 AM654_SDHCI_MIN_FREQ);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530664 if (ret)
665 return ret;
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530666
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530667 ret = sdhci_am654_get_otap_delay(dev, cfg);
668 if (ret)
669 return ret;
670
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530671 /* Update ops based on SoC revision */
672 soc = soc_device_match(am654_sdhci_soc_attr);
673 if (soc && soc->data) {
674 soc_drv_data = soc->data;
675 host->ops = soc_drv_data->ops;
676 }
677
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530678 host->mmc->priv = host;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530679 upriv->mmc = host->mmc;
680
Faiz Abbase9aed582019-06-11 00:43:38 +0530681 regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1);
682
Faiz Abbase4425cb2020-02-26 13:44:34 +0530683 return 0;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530684}
685
Simon Glassaad29ae2020-12-03 16:55:21 -0700686static int am654_sdhci_of_to_plat(struct udevice *dev)
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530687{
Simon Glassfa20e932020-12-03 16:55:20 -0700688 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530689 struct sdhci_host *host = dev_get_priv(dev);
Faiz Abbase9aed582019-06-11 00:43:38 +0530690 struct mmc_config *cfg = &plat->cfg;
691 u32 drv_strength;
692 int ret;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530693
694 host->name = dev->name;
Johan Jonker8d5d8e02023-03-13 01:32:04 +0100695 host->ioaddr = dev_read_addr_ptr(dev);
Faiz Abbase9aed582019-06-11 00:43:38 +0530696 plat->non_removable = dev_read_bool(dev, "non-removable");
697
Faiz Abbasfd8be702019-06-13 10:29:51 +0530698 if (plat->flags & DLL_PRESENT) {
699 ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp);
700 if (ret)
701 return ret;
702
703 ret = dev_read_u32(dev, "ti,driver-strength-ohm",
704 &drv_strength);
705 if (ret)
706 return ret;
Faiz Abbase9aed582019-06-11 00:43:38 +0530707
Faiz Abbasfd8be702019-06-13 10:29:51 +0530708 switch (drv_strength) {
709 case 50:
710 plat->drv_strength = DRIVER_STRENGTH_50_OHM;
711 break;
712 case 33:
713 plat->drv_strength = DRIVER_STRENGTH_33_OHM;
714 break;
715 case 66:
716 plat->drv_strength = DRIVER_STRENGTH_66_OHM;
717 break;
718 case 100:
719 plat->drv_strength = DRIVER_STRENGTH_100_OHM;
720 break;
721 case 40:
722 plat->drv_strength = DRIVER_STRENGTH_40_OHM;
723 break;
724 default:
725 dev_err(dev, "Invalid driver strength\n");
726 return -EINVAL;
727 }
Faiz Abbase9aed582019-06-11 00:43:38 +0530728 }
729
Aswath Govindraju4509fb62021-05-25 15:08:23 +0530730 dev_read_u32(dev, "ti,strobe-sel", &plat->strb_sel);
Faiz Abbasc73f04e2021-02-04 15:10:52 +0530731 dev_read_u32(dev, "ti,clkbuf-sel", &plat->clkbuf_sel);
732
Faiz Abbase9aed582019-06-11 00:43:38 +0530733 ret = mmc_of_parse(dev, cfg);
734 if (ret)
735 return ret;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530736
737 return 0;
738}
739
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530740static int am654_sdhci_bind(struct udevice *dev)
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530741{
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530742 struct am654_driver_data *drv_data =
743 (struct am654_driver_data *)dev_get_driver_data(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700744 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530745 const struct soc_attr *soc;
746 const struct am654_driver_data *soc_drv_data;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530747
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530748 plat->flags = drv_data->flags;
749
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530750 /* Update flags based on SoC revision */
751 soc = soc_device_match(am654_sdhci_soc_attr);
752 if (soc && soc->data) {
753 soc_drv_data = soc->data;
754 plat->flags = soc_drv_data->flags;
755 }
756
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530757 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
758}
759
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530760static const struct udevice_id am654_sdhci_ids[] = {
Faiz Abbasfd8be702019-06-13 10:29:51 +0530761 {
762 .compatible = "ti,am654-sdhci-5.1",
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530763 .data = (ulong)&am654_drv_data,
Faiz Abbasfd8be702019-06-13 10:29:51 +0530764 },
765 {
766 .compatible = "ti,j721e-sdhci-8bit",
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530767 .data = (ulong)&j721e_8bit_drv_data,
Faiz Abbasfd8be702019-06-13 10:29:51 +0530768 },
769 {
770 .compatible = "ti,j721e-sdhci-4bit",
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530771 .data = (ulong)&j721e_4bit_drv_data,
Faiz Abbasfd8be702019-06-13 10:29:51 +0530772 },
Dave Gerlach057d6af2021-04-23 11:27:40 -0500773 {
774 .compatible = "ti,am64-sdhci-8bit",
775 .data = (ulong)&sdhci_am64_8bit_drvdata,
776 },
777 {
778 .compatible = "ti,am64-sdhci-4bit",
779 .data = (ulong)&sdhci_am64_4bit_drvdata,
780 },
Aswath Govindraju71b9a7b2022-05-25 13:38:39 +0530781 {
782 .compatible = "ti,am62-sdhci",
783 .data = (ulong)&sdhci_am64_4bit_drvdata,
784 },
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530785 { }
786};
787
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530788U_BOOT_DRIVER(am654_sdhci_drv) = {
789 .name = "am654_sdhci",
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530790 .id = UCLASS_MMC,
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530791 .of_match = am654_sdhci_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700792 .of_to_plat = am654_sdhci_of_to_plat,
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530793 .ops = &sdhci_ops,
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530794 .bind = am654_sdhci_bind,
795 .probe = am654_sdhci_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700796 .priv_auto = sizeof(struct sdhci_host),
Simon Glass71fa5b42020-12-03 16:55:18 -0700797 .plat_auto = sizeof(struct am654_sdhci_plat),
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530798};