blob: e1047812fa88c83400decfcf273ede1407e09599 [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 Mendezc9eb1dc2024-04-18 14:00:59 -0500298 am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode],
299 plat->itap_del_ena[mode]);
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530300 } else {
301 am654_sdhci_setup_delay_chain(plat, mode);
Judith Mendez81c1d442024-04-18 14:00:56 -0500302 plat->dll_enable = false;
Faiz Abbase9aed582019-06-11 00:43:38 +0530303 }
304
Faiz Abbasc73f04e2021-02-04 15:10:52 +0530305 regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK,
306 plat->clkbuf_sel);
307
Faiz Abbase9aed582019-06-11 00:43:38 +0530308 return 0;
309}
310
Faiz Abbase9aed582019-06-11 00:43:38 +0530311int am654_sdhci_init(struct am654_sdhci_plat *plat)
312{
313 u32 ctl_cfg_2 = 0;
314 u32 mask, val;
315 int ret;
316
317 /* Reset OTAP to default value */
318 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
319 regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0);
320
Faiz Abbas947e8f32021-02-04 15:10:49 +0530321 if (plat->flags & DLL_CALIB) {
Faiz Abbasfd8be702019-06-13 10:29:51 +0530322 regmap_read(plat->base, PHY_STAT1, &val);
323 if (~val & CALDONE_MASK) {
324 /* Calibrate IO lines */
325 regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK,
326 PDB_MASK);
327 ret = regmap_read_poll_timeout(plat->base, PHY_STAT1,
328 val, val & CALDONE_MASK,
329 1, 20);
330 if (ret)
331 return ret;
332 }
Faiz Abbasfd8be702019-06-13 10:29:51 +0530333 }
Faiz Abbase9aed582019-06-11 00:43:38 +0530334
335 /* Enable pins by setting IO mux to 0 */
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530336 if (plat->flags & IOMUX_PRESENT)
337 regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0);
Faiz Abbase9aed582019-06-11 00:43:38 +0530338
339 /* Set slot type based on SD or eMMC */
340 if (plat->non_removable)
341 ctl_cfg_2 = SLOTTYPE_EMBEDDED;
342
343 regmap_update_bits(plat->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2);
344
345 return 0;
346}
347
Faiz Abbase4425cb2020-02-26 13:44:34 +0530348#define MAX_SDCD_DEBOUNCE_TIME 2000
349static int am654_sdhci_deferred_probe(struct sdhci_host *host)
350{
351 struct udevice *dev = host->mmc->dev;
Simon Glassfa20e932020-12-03 16:55:20 -0700352 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbase4425cb2020-02-26 13:44:34 +0530353 unsigned long start;
354 int val;
355
356 /*
357 * The controller takes about 1 second to debounce the card detect line
358 * and doesn't let us power on until that time is up. Instead of waiting
359 * for 1 second at every stage, poll on the CARD_PRESENT bit upto a
360 * maximum of 2 seconds to be safe..
361 */
362 start = get_timer(0);
363 do {
364 if (get_timer(start) > MAX_SDCD_DEBOUNCE_TIME)
365 return -ENOMEDIUM;
366
367 val = mmc_getcd(host->mmc);
368 } while (!val);
369
370 am654_sdhci_init(plat);
371
372 return sdhci_probe(dev);
373}
374
Faiz Abbas36c8c5c2021-02-04 15:10:54 +0530375static void am654_sdhci_write_b(struct sdhci_host *host, u8 val, int reg)
376{
377 if (reg == SDHCI_HOST_CONTROL) {
378 switch (host->mmc->selected_mode) {
379 /*
380 * According to the data manual, HISPD bit
381 * should not be set in these speed modes.
382 */
383 case SD_HS:
384 case MMC_HS:
385 case UHS_SDR12:
386 case UHS_SDR25:
387 val &= ~SDHCI_CTRL_HISPD;
388 default:
389 break;
390 }
391 }
392
393 writeb(val, host->ioaddr + reg);
394}
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530395#ifdef MMC_SUPPORTS_TUNING
Judith Mendez81c1d442024-04-18 14:00:56 -0500396#define ITAPDLY_LENGTH 32
397#define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1)
398
399static u32 am654_sdhci_calculate_itap(struct udevice *dev, struct window
400 *fail_window, u8 num_fails, bool circular_buffer)
401{
402 u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0;
403 u8 first_fail_start = 0, last_fail_end = 0;
404 struct window pass_window = {0, 0, 0};
405 int prev_fail_end = -1;
406 u8 i;
407
408 if (!num_fails)
409 return ITAPDLY_LAST_INDEX >> 1;
410
411 if (fail_window->length == ITAPDLY_LENGTH) {
412 dev_err(dev, "No passing ITAPDLY, return 0\n");
413 return 0;
414 }
415
416 first_fail_start = fail_window->start;
417 last_fail_end = fail_window[num_fails - 1].end;
418
419 for (i = 0; i < num_fails; i++) {
420 start_fail = fail_window[i].start;
421 end_fail = fail_window[i].end;
422 pass_length = start_fail - (prev_fail_end + 1);
423
424 if (pass_length > pass_window.length) {
425 pass_window.start = prev_fail_end + 1;
426 pass_window.length = pass_length;
427 }
428 prev_fail_end = end_fail;
429 }
430
431 if (!circular_buffer)
432 pass_length = ITAPDLY_LAST_INDEX - last_fail_end;
433 else
434 pass_length = ITAPDLY_LAST_INDEX - last_fail_end + first_fail_start;
435
436 if (pass_length > pass_window.length) {
437 pass_window.start = last_fail_end + 1;
438 pass_window.length = pass_length;
439 }
440
441 if (!circular_buffer)
442 itap = pass_window.start + (pass_window.length >> 1);
443 else
444 itap = (pass_window.start + (pass_window.length >> 1)) % ITAPDLY_LENGTH;
445
446 return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap;
447}
448
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530449static int am654_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
450{
451 struct udevice *dev = mmc->dev;
452 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Judith Mendez81c1d442024-04-18 14:00:56 -0500453 struct window fail_window[ITAPDLY_LENGTH];
Judith Mendez87bcbde2024-04-18 14:00:58 -0500454 int mode = mmc->selected_mode;
Judith Mendez81c1d442024-04-18 14:00:56 -0500455 u8 curr_pass, itap;
456 u8 fail_index = 0;
457 u8 prev_pass = 1;
458
459 memset(fail_window, 0, sizeof(fail_window));
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530460
461 /* Enable ITAPDLY */
Judith Mendez87bcbde2024-04-18 14:00:58 -0500462 plat->itap_del_ena[mode] = ENABLE;
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530463
Judith Mendez81c1d442024-04-18 14:00:56 -0500464 for (itap = 0; itap < ITAPDLY_LENGTH; itap++) {
Judith Mendez87bcbde2024-04-18 14:00:58 -0500465 am654_sdhci_write_itapdly(plat, itap, plat->itap_del_ena[mode]);
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530466
Judith Mendez81c1d442024-04-18 14:00:56 -0500467 curr_pass = !mmc_send_tuning(mmc, opcode);
468
469 if (!curr_pass && prev_pass)
470 fail_window[fail_index].start = itap;
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530471
Judith Mendez81c1d442024-04-18 14:00:56 -0500472 if (!curr_pass) {
473 fail_window[fail_index].end = itap;
474 fail_window[fail_index].length++;
475 }
476
477 if (curr_pass && !prev_pass)
478 fail_index++;
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530479
Judith Mendez81c1d442024-04-18 14:00:56 -0500480 prev_pass = curr_pass;
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530481 }
Judith Mendez81c1d442024-04-18 14:00:56 -0500482
483 if (fail_window[fail_index].length != 0)
484 fail_index++;
485
486 itap = am654_sdhci_calculate_itap(dev, fail_window, fail_index,
487 plat->dll_enable);
488
Judith Mendez87bcbde2024-04-18 14:00:58 -0500489 am654_sdhci_write_itapdly(plat, itap, plat->itap_del_ena[mode]);
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530490
491 return 0;
492}
493#endif
Faiz Abbase4425cb2020-02-26 13:44:34 +0530494const struct sdhci_ops am654_sdhci_ops = {
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530495#ifdef MMC_SUPPORTS_TUNING
496 .platform_execute_tuning = am654_sdhci_execute_tuning,
497#endif
Faiz Abbase4425cb2020-02-26 13:44:34 +0530498 .deferred_probe = am654_sdhci_deferred_probe,
499 .set_ios_post = &am654_sdhci_set_ios_post,
Faiz Abbas9c10cfe2021-02-04 15:10:55 +0530500 .set_control_reg = sdhci_set_control_reg,
Faiz Abbas36c8c5c2021-02-04 15:10:54 +0530501 .write_b = am654_sdhci_write_b,
Faiz Abbase4425cb2020-02-26 13:44:34 +0530502};
503
504const struct am654_driver_data am654_drv_data = {
505 .ops = &am654_sdhci_ops,
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530506 .flags = DLL_PRESENT | IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT,
507};
508
509const struct am654_driver_data am654_sr1_drv_data = {
510 .ops = &am654_sdhci_ops,
Faiz Abbas947e8f32021-02-04 15:10:49 +0530511 .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | DLL_CALIB |
512 STRBSEL_4_BIT,
Faiz Abbase4425cb2020-02-26 13:44:34 +0530513};
514
515const struct am654_driver_data j721e_8bit_drv_data = {
516 .ops = &am654_sdhci_ops,
Faiz Abbas947e8f32021-02-04 15:10:49 +0530517 .flags = DLL_PRESENT | DLL_CALIB,
Faiz Abbase4425cb2020-02-26 13:44:34 +0530518};
519
520static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host)
521{
522 struct udevice *dev = host->mmc->dev;
Simon Glassfa20e932020-12-03 16:55:20 -0700523 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Nitin Yadav83db1f92024-04-18 14:00:57 -0500524 int mode = host->mmc->selected_mode;
525 u32 otap_del_sel;
Judith Mendez87bcbde2024-04-18 14:00:58 -0500526 u32 itap_del_ena;
Nitin Yadav83db1f92024-04-18 14:00:57 -0500527 u32 itap_del_sel;
528 u32 mask, val;
Faiz Abbase4425cb2020-02-26 13:44:34 +0530529
Nitin Yadav83db1f92024-04-18 14:00:57 -0500530 otap_del_sel = plat->otap_del_sel[mode];
531
Faiz Abbase4425cb2020-02-26 13:44:34 +0530532 mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
Nitin Yadav83db1f92024-04-18 14:00:57 -0500533 val = (1 << OTAPDLYENA_SHIFT) |
534 (otap_del_sel << OTAPDLYSEL_SHIFT);
535
Judith Mendez87bcbde2024-04-18 14:00:58 -0500536 itap_del_ena = plat->itap_del_ena[mode];
Nitin Yadav83db1f92024-04-18 14:00:57 -0500537 itap_del_sel = plat->itap_del_sel[mode];
538
539 mask |= ITAPDLYENA_MASK | ITAPDLYSEL_MASK;
Judith Mendez87bcbde2024-04-18 14:00:58 -0500540 val |= (itap_del_ena << ITAPDLYENA_SHIFT) |
Nitin Yadav83db1f92024-04-18 14:00:57 -0500541 (itap_del_sel << ITAPDLYSEL_SHIFT);
542
543 regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK,
544 1 << ITAPCHGWIN_SHIFT);
Faiz Abbase4425cb2020-02-26 13:44:34 +0530545 regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
Nitin Yadav83db1f92024-04-18 14:00:57 -0500546 regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
Faiz Abbase4425cb2020-02-26 13:44:34 +0530547
Faiz Abbasc73f04e2021-02-04 15:10:52 +0530548 regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK,
549 plat->clkbuf_sel);
550
Faiz Abbase4425cb2020-02-26 13:44:34 +0530551 return 0;
552}
553
554const struct sdhci_ops j721e_4bit_sdhci_ops = {
Faiz Abbas7a7e2c72021-02-04 15:10:53 +0530555#ifdef MMC_SUPPORTS_TUNING
556 .platform_execute_tuning = am654_sdhci_execute_tuning,
557#endif
Faiz Abbase4425cb2020-02-26 13:44:34 +0530558 .deferred_probe = am654_sdhci_deferred_probe,
559 .set_ios_post = &j721e_4bit_sdhci_set_ios_post,
Faiz Abbas9c10cfe2021-02-04 15:10:55 +0530560 .set_control_reg = sdhci_set_control_reg,
Faiz Abbas36c8c5c2021-02-04 15:10:54 +0530561 .write_b = am654_sdhci_write_b,
Faiz Abbase4425cb2020-02-26 13:44:34 +0530562};
563
564const struct am654_driver_data j721e_4bit_drv_data = {
565 .ops = &j721e_4bit_sdhci_ops,
566 .flags = IOMUX_PRESENT,
567};
568
Dave Gerlach057d6af2021-04-23 11:27:40 -0500569static const struct am654_driver_data sdhci_am64_8bit_drvdata = {
570 .ops = &am654_sdhci_ops,
571 .flags = DLL_PRESENT | DLL_CALIB,
572};
573
574static const struct am654_driver_data sdhci_am64_4bit_drvdata = {
575 .ops = &j721e_4bit_sdhci_ops,
576 .flags = IOMUX_PRESENT,
577};
578
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530579const struct soc_attr am654_sdhci_soc_attr[] = {
580 { .family = "AM65X", .revision = "SR1.0", .data = &am654_sr1_drv_data},
581 {/* sentinel */}
582};
583
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530584static int sdhci_am654_get_otap_delay(struct udevice *dev,
585 struct mmc_config *cfg)
586{
Simon Glassfa20e932020-12-03 16:55:20 -0700587 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530588 int ret;
589 int i;
590
591 /* ti,otap-del-sel-legacy is mandatory */
592 ret = dev_read_u32(dev, "ti,otap-del-sel-legacy",
593 &plat->otap_del_sel[0]);
594 if (ret)
595 return ret;
596 /*
597 * Remove the corresponding capability if an otap-del-sel
598 * value is not found
599 */
Nitin Yadav83db1f92024-04-18 14:00:57 -0500600 for (i = MMC_LEGACY; i <= MMC_HS_400; i++) {
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530601 ret = dev_read_u32(dev, td[i].otap_binding,
602 &plat->otap_del_sel[i]);
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530603 if (ret) {
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530604 dev_dbg(dev, "Couldn't find %s\n", td[i].otap_binding);
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530605 /*
606 * Remove the corresponding capability
607 * if an otap-del-sel value is not found
608 */
609 cfg->host_caps &= ~td[i].capability;
610 }
Faiz Abbasdef2a0f2021-02-04 15:10:51 +0530611
Judith Mendez87bcbde2024-04-18 14:00:58 -0500612 if (td[i].itap_binding) {
613 ret = dev_read_u32(dev, td[i].itap_binding,
614 &plat->itap_del_sel[i]);
615
616 if (!ret)
617 plat->itap_del_ena[i] = ENABLE;
618 }
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530619 }
620
621 return 0;
622}
623
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530624static int am654_sdhci_probe(struct udevice *dev)
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530625{
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530626 struct am654_driver_data *drv_data =
627 (struct am654_driver_data *)dev_get_driver_data(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700628 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530629 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
630 struct sdhci_host *host = dev_get_priv(dev);
Faiz Abbase9aed582019-06-11 00:43:38 +0530631 struct mmc_config *cfg = &plat->cfg;
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530632 const struct soc_attr *soc;
633 const struct am654_driver_data *soc_drv_data;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530634 struct clk clk;
635 unsigned long clock;
636 int ret;
637
Faiz Abbasdc2bcc22020-01-16 19:42:18 +0530638 ret = clk_get_by_name(dev, "clk_xin", &clk);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530639 if (ret) {
640 dev_err(dev, "failed to get clock\n");
641 return ret;
642 }
643
644 clock = clk_get_rate(&clk);
645 if (IS_ERR_VALUE(clock)) {
646 dev_err(dev, "failed to get rate\n");
647 return clock;
648 }
649
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530650 host->max_clk = clock;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530651 host->mmc = &plat->mmc;
Faiz Abbase9aed582019-06-11 00:43:38 +0530652 host->mmc->dev = dev;
Faiz Abbas36c8c5c2021-02-04 15:10:54 +0530653 host->ops = drv_data->ops;
Faiz Abbase9aed582019-06-11 00:43:38 +0530654 ret = sdhci_setup_cfg(cfg, host, cfg->f_max,
655 AM654_SDHCI_MIN_FREQ);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530656 if (ret)
657 return ret;
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530658
Faiz Abbasc6eb9e72020-02-26 13:44:33 +0530659 ret = sdhci_am654_get_otap_delay(dev, cfg);
660 if (ret)
661 return ret;
662
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530663 /* Update ops based on SoC revision */
664 soc = soc_device_match(am654_sdhci_soc_attr);
665 if (soc && soc->data) {
666 soc_drv_data = soc->data;
667 host->ops = soc_drv_data->ops;
668 }
669
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530670 host->mmc->priv = host;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530671 upriv->mmc = host->mmc;
672
Faiz Abbase9aed582019-06-11 00:43:38 +0530673 regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1);
674
Faiz Abbase4425cb2020-02-26 13:44:34 +0530675 return 0;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530676}
677
Simon Glassaad29ae2020-12-03 16:55:21 -0700678static int am654_sdhci_of_to_plat(struct udevice *dev)
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530679{
Simon Glassfa20e932020-12-03 16:55:20 -0700680 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530681 struct sdhci_host *host = dev_get_priv(dev);
Faiz Abbase9aed582019-06-11 00:43:38 +0530682 struct mmc_config *cfg = &plat->cfg;
683 u32 drv_strength;
684 int ret;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530685
686 host->name = dev->name;
Johan Jonker8d5d8e02023-03-13 01:32:04 +0100687 host->ioaddr = dev_read_addr_ptr(dev);
Faiz Abbase9aed582019-06-11 00:43:38 +0530688 plat->non_removable = dev_read_bool(dev, "non-removable");
689
Faiz Abbasfd8be702019-06-13 10:29:51 +0530690 if (plat->flags & DLL_PRESENT) {
691 ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp);
692 if (ret)
693 return ret;
694
695 ret = dev_read_u32(dev, "ti,driver-strength-ohm",
696 &drv_strength);
697 if (ret)
698 return ret;
Faiz Abbase9aed582019-06-11 00:43:38 +0530699
Faiz Abbasfd8be702019-06-13 10:29:51 +0530700 switch (drv_strength) {
701 case 50:
702 plat->drv_strength = DRIVER_STRENGTH_50_OHM;
703 break;
704 case 33:
705 plat->drv_strength = DRIVER_STRENGTH_33_OHM;
706 break;
707 case 66:
708 plat->drv_strength = DRIVER_STRENGTH_66_OHM;
709 break;
710 case 100:
711 plat->drv_strength = DRIVER_STRENGTH_100_OHM;
712 break;
713 case 40:
714 plat->drv_strength = DRIVER_STRENGTH_40_OHM;
715 break;
716 default:
717 dev_err(dev, "Invalid driver strength\n");
718 return -EINVAL;
719 }
Faiz Abbase9aed582019-06-11 00:43:38 +0530720 }
721
Aswath Govindraju4509fb62021-05-25 15:08:23 +0530722 dev_read_u32(dev, "ti,strobe-sel", &plat->strb_sel);
Faiz Abbasc73f04e2021-02-04 15:10:52 +0530723 dev_read_u32(dev, "ti,clkbuf-sel", &plat->clkbuf_sel);
724
Faiz Abbase9aed582019-06-11 00:43:38 +0530725 ret = mmc_of_parse(dev, cfg);
726 if (ret)
727 return ret;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530728
729 return 0;
730}
731
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530732static int am654_sdhci_bind(struct udevice *dev)
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530733{
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530734 struct am654_driver_data *drv_data =
735 (struct am654_driver_data *)dev_get_driver_data(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700736 struct am654_sdhci_plat *plat = dev_get_plat(dev);
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530737 const struct soc_attr *soc;
738 const struct am654_driver_data *soc_drv_data;
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530739
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530740 plat->flags = drv_data->flags;
741
Faiz Abbas2c2fc962021-02-04 15:10:50 +0530742 /* Update flags based on SoC revision */
743 soc = soc_device_match(am654_sdhci_soc_attr);
744 if (soc && soc->data) {
745 soc_drv_data = soc->data;
746 plat->flags = soc_drv_data->flags;
747 }
748
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530749 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
750}
751
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530752static const struct udevice_id am654_sdhci_ids[] = {
Faiz Abbasfd8be702019-06-13 10:29:51 +0530753 {
754 .compatible = "ti,am654-sdhci-5.1",
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530755 .data = (ulong)&am654_drv_data,
Faiz Abbasfd8be702019-06-13 10:29:51 +0530756 },
757 {
758 .compatible = "ti,j721e-sdhci-8bit",
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530759 .data = (ulong)&j721e_8bit_drv_data,
Faiz Abbasfd8be702019-06-13 10:29:51 +0530760 },
761 {
762 .compatible = "ti,j721e-sdhci-4bit",
Faiz Abbas8cc051e2020-01-16 19:42:19 +0530763 .data = (ulong)&j721e_4bit_drv_data,
Faiz Abbasfd8be702019-06-13 10:29:51 +0530764 },
Dave Gerlach057d6af2021-04-23 11:27:40 -0500765 {
766 .compatible = "ti,am64-sdhci-8bit",
767 .data = (ulong)&sdhci_am64_8bit_drvdata,
768 },
769 {
770 .compatible = "ti,am64-sdhci-4bit",
771 .data = (ulong)&sdhci_am64_4bit_drvdata,
772 },
Aswath Govindraju71b9a7b2022-05-25 13:38:39 +0530773 {
774 .compatible = "ti,am62-sdhci",
775 .data = (ulong)&sdhci_am64_4bit_drvdata,
776 },
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530777 { }
778};
779
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530780U_BOOT_DRIVER(am654_sdhci_drv) = {
781 .name = "am654_sdhci",
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530782 .id = UCLASS_MMC,
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530783 .of_match = am654_sdhci_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700784 .of_to_plat = am654_sdhci_of_to_plat,
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530785 .ops = &sdhci_ops,
Faiz Abbasd8fb3092019-06-11 00:43:31 +0530786 .bind = am654_sdhci_bind,
787 .probe = am654_sdhci_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700788 .priv_auto = sizeof(struct sdhci_host),
Simon Glass71fa5b42020-12-03 16:55:18 -0700789 .plat_auto = sizeof(struct am654_sdhci_plat),
Lokesh Vutlabc9979f2018-08-27 15:57:54 +0530790};