1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * sdhci_am654.c - SDHCI driver for TI's AM654 SOCs |
4 | * |
5 | * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com |
6 | * |
7 | */ |
8 | #include <linux/clk.h> |
9 | #include <linux/iopoll.h> |
10 | #include <linux/of.h> |
11 | #include <linux/module.h> |
12 | #include <linux/pm_runtime.h> |
13 | #include <linux/property.h> |
14 | #include <linux/regmap.h> |
15 | #include <linux/sys_soc.h> |
16 | |
17 | #include "cqhci.h" |
18 | #include "sdhci-cqhci.h" |
19 | #include "sdhci-pltfm.h" |
20 | |
21 | /* CTL_CFG Registers */ |
22 | #define CTL_CFG_2 0x14 |
23 | #define CTL_CFG_3 0x18 |
24 | |
25 | #define SLOTTYPE_MASK GENMASK(31, 30) |
26 | #define SLOTTYPE_EMBEDDED BIT(30) |
27 | #define TUNINGFORSDR50_MASK BIT(13) |
28 | |
29 | /* PHY Registers */ |
30 | #define PHY_CTRL1 0x100 |
31 | #define PHY_CTRL2 0x104 |
32 | #define PHY_CTRL3 0x108 |
33 | #define PHY_CTRL4 0x10C |
34 | #define PHY_CTRL5 0x110 |
35 | #define PHY_CTRL6 0x114 |
36 | #define PHY_STAT1 0x130 |
37 | #define PHY_STAT2 0x134 |
38 | |
39 | #define IOMUX_ENABLE_SHIFT 31 |
40 | #define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT) |
41 | #define OTAPDLYENA_SHIFT 20 |
42 | #define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT) |
43 | #define OTAPDLYSEL_SHIFT 12 |
44 | #define OTAPDLYSEL_MASK GENMASK(15, 12) |
45 | #define STRBSEL_SHIFT 24 |
46 | #define STRBSEL_4BIT_MASK GENMASK(27, 24) |
47 | #define STRBSEL_8BIT_MASK GENMASK(31, 24) |
48 | #define SEL50_SHIFT 8 |
49 | #define SEL50_MASK BIT(SEL50_SHIFT) |
50 | #define SEL100_SHIFT 9 |
51 | #define SEL100_MASK BIT(SEL100_SHIFT) |
52 | #define FREQSEL_SHIFT 8 |
53 | #define FREQSEL_MASK GENMASK(10, 8) |
54 | #define CLKBUFSEL_SHIFT 0 |
55 | #define CLKBUFSEL_MASK GENMASK(2, 0) |
56 | #define DLL_TRIM_ICP_SHIFT 4 |
57 | #define DLL_TRIM_ICP_MASK GENMASK(7, 4) |
58 | #define DR_TY_SHIFT 20 |
59 | #define DR_TY_MASK GENMASK(22, 20) |
60 | #define ENDLL_SHIFT 1 |
61 | #define ENDLL_MASK BIT(ENDLL_SHIFT) |
62 | #define DLLRDY_SHIFT 0 |
63 | #define DLLRDY_MASK BIT(DLLRDY_SHIFT) |
64 | #define PDB_SHIFT 0 |
65 | #define PDB_MASK BIT(PDB_SHIFT) |
66 | #define CALDONE_SHIFT 1 |
67 | #define CALDONE_MASK BIT(CALDONE_SHIFT) |
68 | #define RETRIM_SHIFT 17 |
69 | #define RETRIM_MASK BIT(RETRIM_SHIFT) |
70 | #define SELDLYTXCLK_SHIFT 17 |
71 | #define SELDLYTXCLK_MASK BIT(SELDLYTXCLK_SHIFT) |
72 | #define SELDLYRXCLK_SHIFT 16 |
73 | #define SELDLYRXCLK_MASK BIT(SELDLYRXCLK_SHIFT) |
74 | #define ITAPDLYSEL_SHIFT 0 |
75 | #define ITAPDLYSEL_MASK GENMASK(4, 0) |
76 | #define ITAPDLYENA_SHIFT 8 |
77 | #define ITAPDLYENA_MASK BIT(ITAPDLYENA_SHIFT) |
78 | #define ITAPCHGWIN_SHIFT 9 |
79 | #define ITAPCHGWIN_MASK BIT(ITAPCHGWIN_SHIFT) |
80 | |
81 | #define DRIVER_STRENGTH_50_OHM 0x0 |
82 | #define DRIVER_STRENGTH_33_OHM 0x1 |
83 | #define DRIVER_STRENGTH_66_OHM 0x2 |
84 | #define DRIVER_STRENGTH_100_OHM 0x3 |
85 | #define DRIVER_STRENGTH_40_OHM 0x4 |
86 | |
87 | #define CLOCK_TOO_SLOW_HZ 50000000 |
88 | #define SDHCI_AM654_AUTOSUSPEND_DELAY -1 |
89 | |
90 | /* Command Queue Host Controller Interface Base address */ |
91 | #define SDHCI_AM654_CQE_BASE_ADDR 0x200 |
92 | |
93 | static struct regmap_config sdhci_am654_regmap_config = { |
94 | .reg_bits = 32, |
95 | .val_bits = 32, |
96 | .reg_stride = 4, |
97 | .fast_io = true, |
98 | }; |
99 | |
100 | struct timing_data { |
101 | const char *otap_binding; |
102 | const char *itap_binding; |
103 | u32 capability; |
104 | }; |
105 | |
106 | static const struct timing_data td[] = { |
107 | [MMC_TIMING_LEGACY] = {.otap_binding: "ti,otap-del-sel-legacy" , |
108 | .itap_binding: "ti,itap-del-sel-legacy" , |
109 | .capability: 0}, |
110 | [MMC_TIMING_MMC_HS] = {"ti,otap-del-sel-mmc-hs" , |
111 | "ti,itap-del-sel-mmc-hs" , |
112 | MMC_CAP_MMC_HIGHSPEED}, |
113 | [MMC_TIMING_SD_HS] = {"ti,otap-del-sel-sd-hs" , |
114 | "ti,itap-del-sel-sd-hs" , |
115 | MMC_CAP_SD_HIGHSPEED}, |
116 | [MMC_TIMING_UHS_SDR12] = {"ti,otap-del-sel-sdr12" , |
117 | "ti,itap-del-sel-sdr12" , |
118 | MMC_CAP_UHS_SDR12}, |
119 | [MMC_TIMING_UHS_SDR25] = {"ti,otap-del-sel-sdr25" , |
120 | "ti,itap-del-sel-sdr25" , |
121 | MMC_CAP_UHS_SDR25}, |
122 | [MMC_TIMING_UHS_SDR50] = {"ti,otap-del-sel-sdr50" , |
123 | NULL, |
124 | MMC_CAP_UHS_SDR50}, |
125 | [MMC_TIMING_UHS_SDR104] = {"ti,otap-del-sel-sdr104" , |
126 | NULL, |
127 | MMC_CAP_UHS_SDR104}, |
128 | [MMC_TIMING_UHS_DDR50] = {"ti,otap-del-sel-ddr50" , |
129 | NULL, |
130 | MMC_CAP_UHS_DDR50}, |
131 | [MMC_TIMING_MMC_DDR52] = {"ti,otap-del-sel-ddr52" , |
132 | "ti,itap-del-sel-ddr52" , |
133 | MMC_CAP_DDR}, |
134 | [MMC_TIMING_MMC_HS200] = {"ti,otap-del-sel-hs200" , |
135 | NULL, |
136 | MMC_CAP2_HS200}, |
137 | [MMC_TIMING_MMC_HS400] = {"ti,otap-del-sel-hs400" , |
138 | NULL, |
139 | MMC_CAP2_HS400}, |
140 | }; |
141 | |
142 | struct sdhci_am654_data { |
143 | struct regmap *base; |
144 | bool legacy_otapdly; |
145 | int otap_del_sel[ARRAY_SIZE(td)]; |
146 | int itap_del_sel[ARRAY_SIZE(td)]; |
147 | int clkbuf_sel; |
148 | int trm_icp; |
149 | int drv_strength; |
150 | int strb_sel; |
151 | u32 flags; |
152 | u32 quirks; |
153 | |
154 | #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) |
155 | }; |
156 | |
157 | struct sdhci_am654_driver_data { |
158 | const struct sdhci_pltfm_data *pdata; |
159 | u32 flags; |
160 | #define IOMUX_PRESENT (1 << 0) |
161 | #define FREQSEL_2_BIT (1 << 1) |
162 | #define STRBSEL_4_BIT (1 << 2) |
163 | #define DLL_PRESENT (1 << 3) |
164 | #define DLL_CALIB (1 << 4) |
165 | }; |
166 | |
167 | static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock) |
168 | { |
169 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
170 | struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(host: pltfm_host); |
171 | int sel50, sel100, freqsel; |
172 | u32 mask, val; |
173 | int ret; |
174 | |
175 | /* Disable delay chain mode */ |
176 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL5, |
177 | SELDLYTXCLK_MASK | SELDLYRXCLK_MASK, val: 0); |
178 | |
179 | if (sdhci_am654->flags & FREQSEL_2_BIT) { |
180 | switch (clock) { |
181 | case 200000000: |
182 | sel50 = 0; |
183 | sel100 = 0; |
184 | break; |
185 | case 100000000: |
186 | sel50 = 0; |
187 | sel100 = 1; |
188 | break; |
189 | default: |
190 | sel50 = 1; |
191 | sel100 = 0; |
192 | } |
193 | |
194 | /* Configure PHY DLL frequency */ |
195 | mask = SEL50_MASK | SEL100_MASK; |
196 | val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT); |
197 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL5, mask, val); |
198 | |
199 | } else { |
200 | switch (clock) { |
201 | case 200000000: |
202 | freqsel = 0x0; |
203 | break; |
204 | default: |
205 | freqsel = 0x4; |
206 | } |
207 | |
208 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL5, FREQSEL_MASK, |
209 | val: freqsel << FREQSEL_SHIFT); |
210 | } |
211 | /* Configure DLL TRIM */ |
212 | mask = DLL_TRIM_ICP_MASK; |
213 | val = sdhci_am654->trm_icp << DLL_TRIM_ICP_SHIFT; |
214 | |
215 | /* Configure DLL driver strength */ |
216 | mask |= DR_TY_MASK; |
217 | val |= sdhci_am654->drv_strength << DR_TY_SHIFT; |
218 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL1, mask, val); |
219 | |
220 | /* Enable DLL */ |
221 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, |
222 | val: 0x1 << ENDLL_SHIFT); |
223 | /* |
224 | * Poll for DLL ready. Use a one second timeout. |
225 | * Works in all experiments done so far |
226 | */ |
227 | ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1, val, |
228 | val & DLLRDY_MASK, 1000, 1000000); |
229 | if (ret) { |
230 | dev_err(mmc_dev(host->mmc), "DLL failed to relock\n" ); |
231 | return; |
232 | } |
233 | } |
234 | |
235 | static void sdhci_am654_write_itapdly(struct sdhci_am654_data *sdhci_am654, |
236 | u32 itapdly) |
237 | { |
238 | /* Set ITAPCHGWIN before writing to ITAPDLY */ |
239 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, |
240 | val: 1 << ITAPCHGWIN_SHIFT); |
241 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL4, ITAPDLYSEL_MASK, |
242 | val: itapdly << ITAPDLYSEL_SHIFT); |
243 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, val: 0); |
244 | } |
245 | |
246 | static void sdhci_am654_setup_delay_chain(struct sdhci_am654_data *sdhci_am654, |
247 | unsigned char timing) |
248 | { |
249 | u32 mask, val; |
250 | |
251 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, val: 0); |
252 | |
253 | val = 1 << SELDLYTXCLK_SHIFT | 1 << SELDLYRXCLK_SHIFT; |
254 | mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK; |
255 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL5, mask, val); |
256 | |
257 | sdhci_am654_write_itapdly(sdhci_am654, |
258 | itapdly: sdhci_am654->itap_del_sel[timing]); |
259 | } |
260 | |
261 | static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) |
262 | { |
263 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
264 | struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(host: pltfm_host); |
265 | unsigned char timing = host->mmc->ios.timing; |
266 | u32 otap_del_sel; |
267 | u32 otap_del_ena; |
268 | u32 mask, val; |
269 | |
270 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, val: 0); |
271 | |
272 | sdhci_set_clock(host, clock); |
273 | |
274 | /* Setup DLL Output TAP delay */ |
275 | if (sdhci_am654->legacy_otapdly) |
276 | otap_del_sel = sdhci_am654->otap_del_sel[0]; |
277 | else |
278 | otap_del_sel = sdhci_am654->otap_del_sel[timing]; |
279 | |
280 | otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0; |
281 | |
282 | mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; |
283 | val = (otap_del_ena << OTAPDLYENA_SHIFT) | |
284 | (otap_del_sel << OTAPDLYSEL_SHIFT); |
285 | |
286 | /* Write to STRBSEL for HS400 speed mode */ |
287 | if (timing == MMC_TIMING_MMC_HS400) { |
288 | if (sdhci_am654->flags & STRBSEL_4_BIT) |
289 | mask |= STRBSEL_4BIT_MASK; |
290 | else |
291 | mask |= STRBSEL_8BIT_MASK; |
292 | |
293 | val |= sdhci_am654->strb_sel << STRBSEL_SHIFT; |
294 | } |
295 | |
296 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL4, mask, val); |
297 | |
298 | if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) |
299 | sdhci_am654_setup_dll(host, clock); |
300 | else |
301 | sdhci_am654_setup_delay_chain(sdhci_am654, timing); |
302 | |
303 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, |
304 | val: sdhci_am654->clkbuf_sel); |
305 | } |
306 | |
307 | static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, |
308 | unsigned int clock) |
309 | { |
310 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
311 | struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(host: pltfm_host); |
312 | unsigned char timing = host->mmc->ios.timing; |
313 | u32 otap_del_sel; |
314 | u32 mask, val; |
315 | |
316 | /* Setup DLL Output TAP delay */ |
317 | if (sdhci_am654->legacy_otapdly) |
318 | otap_del_sel = sdhci_am654->otap_del_sel[0]; |
319 | else |
320 | otap_del_sel = sdhci_am654->otap_del_sel[timing]; |
321 | |
322 | mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; |
323 | val = (0x1 << OTAPDLYENA_SHIFT) | |
324 | (otap_del_sel << OTAPDLYSEL_SHIFT); |
325 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL4, mask, val); |
326 | |
327 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, |
328 | val: sdhci_am654->clkbuf_sel); |
329 | |
330 | sdhci_set_clock(host, clock); |
331 | } |
332 | |
333 | static u8 sdhci_am654_write_power_on(struct sdhci_host *host, u8 val, int reg) |
334 | { |
335 | writeb(val, addr: host->ioaddr + reg); |
336 | usleep_range(min: 1000, max: 10000); |
337 | return readb(addr: host->ioaddr + reg); |
338 | } |
339 | |
340 | #define MAX_POWER_ON_TIMEOUT 1500000 /* us */ |
341 | static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg) |
342 | { |
343 | unsigned char timing = host->mmc->ios.timing; |
344 | u8 pwr; |
345 | int ret; |
346 | |
347 | if (reg == SDHCI_HOST_CONTROL) { |
348 | switch (timing) { |
349 | /* |
350 | * According to the data manual, HISPD bit |
351 | * should not be set in these speed modes. |
352 | */ |
353 | case MMC_TIMING_SD_HS: |
354 | case MMC_TIMING_MMC_HS: |
355 | val &= ~SDHCI_CTRL_HISPD; |
356 | } |
357 | } |
358 | |
359 | writeb(val, addr: host->ioaddr + reg); |
360 | if (reg == SDHCI_POWER_CONTROL && (val & SDHCI_POWER_ON)) { |
361 | /* |
362 | * Power on will not happen until the card detect debounce |
363 | * timer expires. Wait at least 1.5 seconds for the power on |
364 | * bit to be set |
365 | */ |
366 | ret = read_poll_timeout(sdhci_am654_write_power_on, pwr, |
367 | pwr & SDHCI_POWER_ON, 0, |
368 | MAX_POWER_ON_TIMEOUT, false, host, val, |
369 | reg); |
370 | if (ret) |
371 | dev_info(mmc_dev(host->mmc), "Power on failed\n" ); |
372 | } |
373 | } |
374 | |
375 | static void sdhci_am654_reset(struct sdhci_host *host, u8 mask) |
376 | { |
377 | u8 ctrl; |
378 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
379 | struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(host: pltfm_host); |
380 | |
381 | sdhci_and_cqhci_reset(host, mask); |
382 | |
383 | if (sdhci_am654->quirks & SDHCI_AM654_QUIRK_FORCE_CDTEST) { |
384 | ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); |
385 | ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN; |
386 | sdhci_writeb(host, val: ctrl, SDHCI_HOST_CONTROL); |
387 | } |
388 | } |
389 | |
390 | static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode) |
391 | { |
392 | struct sdhci_host *host = mmc_priv(host: mmc); |
393 | int err = sdhci_execute_tuning(mmc, opcode); |
394 | |
395 | if (err) |
396 | return err; |
397 | /* |
398 | * Tuning data remains in the buffer after tuning. |
399 | * Do a command and data reset to get rid of it |
400 | */ |
401 | sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); |
402 | |
403 | return 0; |
404 | } |
405 | |
406 | static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask) |
407 | { |
408 | int cmd_error = 0; |
409 | int data_error = 0; |
410 | |
411 | if (!sdhci_cqe_irq(host, intmask, cmd_error: &cmd_error, data_error: &data_error)) |
412 | return intmask; |
413 | |
414 | cqhci_irq(mmc: host->mmc, intmask, cmd_error, data_error); |
415 | |
416 | return 0; |
417 | } |
418 | |
419 | #define ITAP_MAX 32 |
420 | static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, |
421 | u32 opcode) |
422 | { |
423 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
424 | struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(host: pltfm_host); |
425 | int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len; |
426 | u32 itap; |
427 | |
428 | /* Enable ITAPDLY */ |
429 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK, |
430 | val: 1 << ITAPDLYENA_SHIFT); |
431 | |
432 | for (itap = 0; itap < ITAP_MAX; itap++) { |
433 | sdhci_am654_write_itapdly(sdhci_am654, itapdly: itap); |
434 | |
435 | cur_val = !mmc_send_tuning(host: host->mmc, opcode, NULL); |
436 | if (cur_val && !prev_val) |
437 | pass_window = itap; |
438 | |
439 | if (!cur_val) |
440 | fail_len++; |
441 | |
442 | prev_val = cur_val; |
443 | } |
444 | /* |
445 | * Having determined the length of the failing window and start of |
446 | * the passing window calculate the length of the passing window and |
447 | * set the final value halfway through it considering the range as a |
448 | * circular buffer |
449 | */ |
450 | pass_len = ITAP_MAX - fail_len; |
451 | itap = (pass_window + (pass_len >> 1)) % ITAP_MAX; |
452 | sdhci_am654_write_itapdly(sdhci_am654, itapdly: itap); |
453 | |
454 | return 0; |
455 | } |
456 | |
457 | static struct sdhci_ops sdhci_am654_ops = { |
458 | .platform_execute_tuning = sdhci_am654_platform_execute_tuning, |
459 | .get_max_clock = sdhci_pltfm_clk_get_max_clock, |
460 | .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, |
461 | .set_uhs_signaling = sdhci_set_uhs_signaling, |
462 | .set_bus_width = sdhci_set_bus_width, |
463 | .set_power = sdhci_set_power_and_bus_voltage, |
464 | .set_clock = sdhci_am654_set_clock, |
465 | .write_b = sdhci_am654_write_b, |
466 | .irq = sdhci_am654_cqhci_irq, |
467 | .reset = sdhci_and_cqhci_reset, |
468 | }; |
469 | |
470 | static const struct sdhci_pltfm_data sdhci_am654_pdata = { |
471 | .ops = &sdhci_am654_ops, |
472 | .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, |
473 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, |
474 | }; |
475 | |
476 | static const struct sdhci_am654_driver_data sdhci_am654_sr1_drvdata = { |
477 | .pdata = &sdhci_am654_pdata, |
478 | .flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT | |
479 | DLL_CALIB, |
480 | }; |
481 | |
482 | static const struct sdhci_am654_driver_data sdhci_am654_drvdata = { |
483 | .pdata = &sdhci_am654_pdata, |
484 | .flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT, |
485 | }; |
486 | |
487 | static struct sdhci_ops sdhci_j721e_8bit_ops = { |
488 | .platform_execute_tuning = sdhci_am654_platform_execute_tuning, |
489 | .get_max_clock = sdhci_pltfm_clk_get_max_clock, |
490 | .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, |
491 | .set_uhs_signaling = sdhci_set_uhs_signaling, |
492 | .set_bus_width = sdhci_set_bus_width, |
493 | .set_power = sdhci_set_power_and_bus_voltage, |
494 | .set_clock = sdhci_am654_set_clock, |
495 | .write_b = sdhci_am654_write_b, |
496 | .irq = sdhci_am654_cqhci_irq, |
497 | .reset = sdhci_and_cqhci_reset, |
498 | }; |
499 | |
500 | static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = { |
501 | .ops = &sdhci_j721e_8bit_ops, |
502 | .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, |
503 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, |
504 | }; |
505 | |
506 | static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = { |
507 | .pdata = &sdhci_j721e_8bit_pdata, |
508 | .flags = DLL_PRESENT | DLL_CALIB, |
509 | }; |
510 | |
511 | static struct sdhci_ops sdhci_j721e_4bit_ops = { |
512 | .platform_execute_tuning = sdhci_am654_platform_execute_tuning, |
513 | .get_max_clock = sdhci_pltfm_clk_get_max_clock, |
514 | .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, |
515 | .set_uhs_signaling = sdhci_set_uhs_signaling, |
516 | .set_bus_width = sdhci_set_bus_width, |
517 | .set_power = sdhci_set_power_and_bus_voltage, |
518 | .set_clock = sdhci_j721e_4bit_set_clock, |
519 | .write_b = sdhci_am654_write_b, |
520 | .irq = sdhci_am654_cqhci_irq, |
521 | .reset = sdhci_am654_reset, |
522 | }; |
523 | |
524 | static const struct sdhci_pltfm_data sdhci_j721e_4bit_pdata = { |
525 | .ops = &sdhci_j721e_4bit_ops, |
526 | .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, |
527 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, |
528 | }; |
529 | |
530 | static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = { |
531 | .pdata = &sdhci_j721e_4bit_pdata, |
532 | .flags = IOMUX_PRESENT, |
533 | }; |
534 | |
535 | static const struct soc_device_attribute sdhci_am654_devices[] = { |
536 | { .family = "AM65X" , |
537 | .revision = "SR1.0" , |
538 | .data = &sdhci_am654_sr1_drvdata |
539 | }, |
540 | {/* sentinel */} |
541 | }; |
542 | |
543 | static void sdhci_am654_dumpregs(struct mmc_host *mmc) |
544 | { |
545 | sdhci_dumpregs(host: mmc_priv(host: mmc)); |
546 | } |
547 | |
548 | static const struct cqhci_host_ops sdhci_am654_cqhci_ops = { |
549 | .enable = sdhci_cqe_enable, |
550 | .disable = sdhci_cqe_disable, |
551 | .dumpregs = sdhci_am654_dumpregs, |
552 | }; |
553 | |
554 | static int sdhci_am654_cqe_add_host(struct sdhci_host *host) |
555 | { |
556 | struct cqhci_host *cq_host; |
557 | |
558 | cq_host = devm_kzalloc(mmc_dev(host->mmc), size: sizeof(struct cqhci_host), |
559 | GFP_KERNEL); |
560 | if (!cq_host) |
561 | return -ENOMEM; |
562 | |
563 | cq_host->mmio = host->ioaddr + SDHCI_AM654_CQE_BASE_ADDR; |
564 | cq_host->quirks |= CQHCI_QUIRK_SHORT_TXFR_DESC_SZ; |
565 | cq_host->caps |= CQHCI_TASK_DESC_SZ_128; |
566 | cq_host->ops = &sdhci_am654_cqhci_ops; |
567 | |
568 | host->mmc->caps2 |= MMC_CAP2_CQE; |
569 | |
570 | return cqhci_init(cq_host, mmc: host->mmc, dma64: 1); |
571 | } |
572 | |
573 | static int sdhci_am654_get_otap_delay(struct sdhci_host *host, |
574 | struct sdhci_am654_data *sdhci_am654) |
575 | { |
576 | struct device *dev = mmc_dev(host->mmc); |
577 | int i; |
578 | int ret; |
579 | |
580 | ret = device_property_read_u32(dev, propname: td[MMC_TIMING_LEGACY].otap_binding, |
581 | val: &sdhci_am654->otap_del_sel[MMC_TIMING_LEGACY]); |
582 | if (ret) { |
583 | /* |
584 | * ti,otap-del-sel-legacy is mandatory, look for old binding |
585 | * if not found. |
586 | */ |
587 | ret = device_property_read_u32(dev, propname: "ti,otap-del-sel" , |
588 | val: &sdhci_am654->otap_del_sel[0]); |
589 | if (ret) { |
590 | dev_err(dev, "Couldn't find otap-del-sel\n" ); |
591 | |
592 | return ret; |
593 | } |
594 | |
595 | dev_info(dev, "Using legacy binding ti,otap-del-sel\n" ); |
596 | sdhci_am654->legacy_otapdly = true; |
597 | |
598 | return 0; |
599 | } |
600 | |
601 | for (i = MMC_TIMING_MMC_HS; i <= MMC_TIMING_MMC_HS400; i++) { |
602 | |
603 | ret = device_property_read_u32(dev, propname: td[i].otap_binding, |
604 | val: &sdhci_am654->otap_del_sel[i]); |
605 | if (ret) { |
606 | dev_dbg(dev, "Couldn't find %s\n" , |
607 | td[i].otap_binding); |
608 | /* |
609 | * Remove the corresponding capability |
610 | * if an otap-del-sel value is not found |
611 | */ |
612 | if (i <= MMC_TIMING_MMC_DDR52) |
613 | host->mmc->caps &= ~td[i].capability; |
614 | else |
615 | host->mmc->caps2 &= ~td[i].capability; |
616 | } |
617 | |
618 | if (td[i].itap_binding) |
619 | device_property_read_u32(dev, propname: td[i].itap_binding, |
620 | val: &sdhci_am654->itap_del_sel[i]); |
621 | } |
622 | |
623 | return 0; |
624 | } |
625 | |
626 | static int sdhci_am654_init(struct sdhci_host *host) |
627 | { |
628 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
629 | struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(host: pltfm_host); |
630 | u32 ctl_cfg_2 = 0; |
631 | u32 mask; |
632 | u32 val; |
633 | int ret; |
634 | |
635 | /* Reset OTAP to default value */ |
636 | mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; |
637 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL4, mask, val: 0x0); |
638 | |
639 | if (sdhci_am654->flags & DLL_CALIB) { |
640 | regmap_read(map: sdhci_am654->base, PHY_STAT1, val: &val); |
641 | if (~val & CALDONE_MASK) { |
642 | /* Calibrate IO lines */ |
643 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL1, |
644 | PDB_MASK, PDB_MASK); |
645 | ret = regmap_read_poll_timeout(sdhci_am654->base, |
646 | PHY_STAT1, val, |
647 | val & CALDONE_MASK, |
648 | 1, 20); |
649 | if (ret) |
650 | return ret; |
651 | } |
652 | } |
653 | |
654 | /* Enable pins by setting IO mux to 0 */ |
655 | if (sdhci_am654->flags & IOMUX_PRESENT) |
656 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL1, |
657 | IOMUX_ENABLE_MASK, val: 0); |
658 | |
659 | /* Set slot type based on SD or eMMC */ |
660 | if (host->mmc->caps & MMC_CAP_NONREMOVABLE) |
661 | ctl_cfg_2 = SLOTTYPE_EMBEDDED; |
662 | |
663 | regmap_update_bits(map: sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK, |
664 | val: ctl_cfg_2); |
665 | |
666 | /* Enable tuning for SDR50 */ |
667 | regmap_update_bits(map: sdhci_am654->base, CTL_CFG_3, TUNINGFORSDR50_MASK, |
668 | TUNINGFORSDR50_MASK); |
669 | |
670 | ret = sdhci_setup_host(host); |
671 | if (ret) |
672 | return ret; |
673 | |
674 | ret = sdhci_am654_cqe_add_host(host); |
675 | if (ret) |
676 | goto err_cleanup_host; |
677 | |
678 | ret = sdhci_am654_get_otap_delay(host, sdhci_am654); |
679 | if (ret) |
680 | goto err_cleanup_host; |
681 | |
682 | ret = __sdhci_add_host(host); |
683 | if (ret) |
684 | goto err_cleanup_host; |
685 | |
686 | return 0; |
687 | |
688 | err_cleanup_host: |
689 | sdhci_cleanup_host(host); |
690 | return ret; |
691 | } |
692 | |
693 | static int sdhci_am654_get_of_property(struct platform_device *pdev, |
694 | struct sdhci_am654_data *sdhci_am654) |
695 | { |
696 | struct device *dev = &pdev->dev; |
697 | int drv_strength; |
698 | int ret; |
699 | |
700 | if (sdhci_am654->flags & DLL_PRESENT) { |
701 | ret = device_property_read_u32(dev, propname: "ti,trm-icp" , |
702 | val: &sdhci_am654->trm_icp); |
703 | if (ret) |
704 | return ret; |
705 | |
706 | ret = device_property_read_u32(dev, propname: "ti,driver-strength-ohm" , |
707 | val: &drv_strength); |
708 | if (ret) |
709 | return ret; |
710 | |
711 | switch (drv_strength) { |
712 | case 50: |
713 | sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM; |
714 | break; |
715 | case 33: |
716 | sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM; |
717 | break; |
718 | case 66: |
719 | sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM; |
720 | break; |
721 | case 100: |
722 | sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM; |
723 | break; |
724 | case 40: |
725 | sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM; |
726 | break; |
727 | default: |
728 | dev_err(dev, "Invalid driver strength\n" ); |
729 | return -EINVAL; |
730 | } |
731 | } |
732 | |
733 | device_property_read_u32(dev, propname: "ti,strobe-sel" , val: &sdhci_am654->strb_sel); |
734 | device_property_read_u32(dev, propname: "ti,clkbuf-sel" , |
735 | val: &sdhci_am654->clkbuf_sel); |
736 | |
737 | if (device_property_read_bool(dev, propname: "ti,fails-without-test-cd" )) |
738 | sdhci_am654->quirks |= SDHCI_AM654_QUIRK_FORCE_CDTEST; |
739 | |
740 | sdhci_get_of_property(pdev); |
741 | |
742 | return 0; |
743 | } |
744 | |
745 | static const struct of_device_id sdhci_am654_of_match[] = { |
746 | { |
747 | .compatible = "ti,am654-sdhci-5.1" , |
748 | .data = &sdhci_am654_drvdata, |
749 | }, |
750 | { |
751 | .compatible = "ti,j721e-sdhci-8bit" , |
752 | .data = &sdhci_j721e_8bit_drvdata, |
753 | }, |
754 | { |
755 | .compatible = "ti,j721e-sdhci-4bit" , |
756 | .data = &sdhci_j721e_4bit_drvdata, |
757 | }, |
758 | { |
759 | .compatible = "ti,am64-sdhci-8bit" , |
760 | .data = &sdhci_j721e_8bit_drvdata, |
761 | }, |
762 | { |
763 | .compatible = "ti,am64-sdhci-4bit" , |
764 | .data = &sdhci_j721e_4bit_drvdata, |
765 | }, |
766 | { |
767 | .compatible = "ti,am62-sdhci" , |
768 | .data = &sdhci_j721e_4bit_drvdata, |
769 | }, |
770 | { /* sentinel */ } |
771 | }; |
772 | MODULE_DEVICE_TABLE(of, sdhci_am654_of_match); |
773 | |
774 | static int sdhci_am654_probe(struct platform_device *pdev) |
775 | { |
776 | const struct sdhci_am654_driver_data *drvdata; |
777 | const struct soc_device_attribute *soc; |
778 | struct sdhci_pltfm_host *pltfm_host; |
779 | struct sdhci_am654_data *sdhci_am654; |
780 | const struct of_device_id *match; |
781 | struct sdhci_host *host; |
782 | struct clk *clk_xin; |
783 | struct device *dev = &pdev->dev; |
784 | void __iomem *base; |
785 | int ret; |
786 | |
787 | match = of_match_node(matches: sdhci_am654_of_match, node: pdev->dev.of_node); |
788 | drvdata = match->data; |
789 | |
790 | /* Update drvdata based on SoC revision */ |
791 | soc = soc_device_match(matches: sdhci_am654_devices); |
792 | if (soc && soc->data) |
793 | drvdata = soc->data; |
794 | |
795 | host = sdhci_pltfm_init(pdev, pdata: drvdata->pdata, priv_size: sizeof(*sdhci_am654)); |
796 | if (IS_ERR(ptr: host)) |
797 | return PTR_ERR(ptr: host); |
798 | |
799 | pltfm_host = sdhci_priv(host); |
800 | sdhci_am654 = sdhci_pltfm_priv(host: pltfm_host); |
801 | sdhci_am654->flags = drvdata->flags; |
802 | |
803 | clk_xin = devm_clk_get(dev, id: "clk_xin" ); |
804 | if (IS_ERR(ptr: clk_xin)) { |
805 | dev_err(dev, "clk_xin clock not found.\n" ); |
806 | ret = PTR_ERR(ptr: clk_xin); |
807 | goto err_pltfm_free; |
808 | } |
809 | |
810 | pltfm_host->clk = clk_xin; |
811 | |
812 | base = devm_platform_ioremap_resource(pdev, index: 1); |
813 | if (IS_ERR(ptr: base)) { |
814 | ret = PTR_ERR(ptr: base); |
815 | goto err_pltfm_free; |
816 | } |
817 | |
818 | sdhci_am654->base = devm_regmap_init_mmio(dev, base, |
819 | &sdhci_am654_regmap_config); |
820 | if (IS_ERR(ptr: sdhci_am654->base)) { |
821 | dev_err(dev, "Failed to initialize regmap\n" ); |
822 | ret = PTR_ERR(ptr: sdhci_am654->base); |
823 | goto err_pltfm_free; |
824 | } |
825 | |
826 | ret = sdhci_am654_get_of_property(pdev, sdhci_am654); |
827 | if (ret) |
828 | goto err_pltfm_free; |
829 | |
830 | ret = mmc_of_parse(host: host->mmc); |
831 | if (ret) { |
832 | dev_err_probe(dev, err: ret, fmt: "parsing dt failed\n" ); |
833 | goto err_pltfm_free; |
834 | } |
835 | |
836 | host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning; |
837 | |
838 | pm_runtime_get_noresume(dev); |
839 | ret = pm_runtime_set_active(dev); |
840 | if (ret) |
841 | goto pm_put; |
842 | pm_runtime_enable(dev); |
843 | ret = clk_prepare_enable(clk: pltfm_host->clk); |
844 | if (ret) |
845 | goto pm_disable; |
846 | |
847 | ret = sdhci_am654_init(host); |
848 | if (ret) |
849 | goto clk_disable; |
850 | |
851 | /* Setting up autosuspend */ |
852 | pm_runtime_set_autosuspend_delay(dev, SDHCI_AM654_AUTOSUSPEND_DELAY); |
853 | pm_runtime_use_autosuspend(dev); |
854 | pm_runtime_mark_last_busy(dev); |
855 | pm_runtime_put_autosuspend(dev); |
856 | return 0; |
857 | |
858 | clk_disable: |
859 | clk_disable_unprepare(clk: pltfm_host->clk); |
860 | pm_disable: |
861 | pm_runtime_disable(dev); |
862 | pm_put: |
863 | pm_runtime_put_noidle(dev); |
864 | err_pltfm_free: |
865 | sdhci_pltfm_free(pdev); |
866 | return ret; |
867 | } |
868 | |
869 | static void sdhci_am654_remove(struct platform_device *pdev) |
870 | { |
871 | struct sdhci_host *host = platform_get_drvdata(pdev); |
872 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
873 | struct device *dev = &pdev->dev; |
874 | int ret; |
875 | |
876 | ret = pm_runtime_get_sync(dev); |
877 | if (ret < 0) |
878 | dev_err(dev, "pm_runtime_get_sync() Failed\n" ); |
879 | |
880 | sdhci_remove_host(host, dead: true); |
881 | clk_disable_unprepare(clk: pltfm_host->clk); |
882 | pm_runtime_disable(dev); |
883 | pm_runtime_put_noidle(dev); |
884 | sdhci_pltfm_free(pdev); |
885 | } |
886 | |
887 | #ifdef CONFIG_PM |
888 | static int sdhci_am654_restore(struct sdhci_host *host) |
889 | { |
890 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
891 | struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(host: pltfm_host); |
892 | u32 ctl_cfg_2 = 0; |
893 | u32 val; |
894 | int ret; |
895 | |
896 | if (sdhci_am654->flags & DLL_CALIB) { |
897 | regmap_read(map: sdhci_am654->base, PHY_STAT1, val: &val); |
898 | if (~val & CALDONE_MASK) { |
899 | /* Calibrate IO lines */ |
900 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL1, |
901 | PDB_MASK, PDB_MASK); |
902 | ret = regmap_read_poll_timeout(sdhci_am654->base, |
903 | PHY_STAT1, val, |
904 | val & CALDONE_MASK, |
905 | 1, 20); |
906 | if (ret) |
907 | return ret; |
908 | } |
909 | } |
910 | |
911 | /* Enable pins by setting IO mux to 0 */ |
912 | if (sdhci_am654->flags & IOMUX_PRESENT) |
913 | regmap_update_bits(map: sdhci_am654->base, PHY_CTRL1, |
914 | IOMUX_ENABLE_MASK, val: 0); |
915 | |
916 | /* Set slot type based on SD or eMMC */ |
917 | if (host->mmc->caps & MMC_CAP_NONREMOVABLE) |
918 | ctl_cfg_2 = SLOTTYPE_EMBEDDED; |
919 | |
920 | regmap_update_bits(map: sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK, |
921 | val: ctl_cfg_2); |
922 | |
923 | regmap_read(map: sdhci_am654->base, CTL_CFG_3, val: &val); |
924 | if (~val & TUNINGFORSDR50_MASK) |
925 | /* Enable tuning for SDR50 */ |
926 | regmap_update_bits(map: sdhci_am654->base, CTL_CFG_3, TUNINGFORSDR50_MASK, |
927 | TUNINGFORSDR50_MASK); |
928 | |
929 | return 0; |
930 | } |
931 | |
932 | static int sdhci_am654_runtime_suspend(struct device *dev) |
933 | { |
934 | struct sdhci_host *host = dev_get_drvdata(dev); |
935 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
936 | int ret; |
937 | |
938 | if (host->tuning_mode != SDHCI_TUNING_MODE_3) |
939 | mmc_retune_needed(host: host->mmc); |
940 | |
941 | ret = cqhci_suspend(mmc: host->mmc); |
942 | if (ret) |
943 | return ret; |
944 | |
945 | ret = sdhci_runtime_suspend_host(host); |
946 | if (ret) |
947 | return ret; |
948 | |
949 | /* disable the clock */ |
950 | clk_disable_unprepare(clk: pltfm_host->clk); |
951 | return 0; |
952 | } |
953 | |
954 | static int sdhci_am654_runtime_resume(struct device *dev) |
955 | { |
956 | struct sdhci_host *host = dev_get_drvdata(dev); |
957 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
958 | int ret; |
959 | |
960 | /* Enable the clock */ |
961 | ret = clk_prepare_enable(clk: pltfm_host->clk); |
962 | if (ret) |
963 | return ret; |
964 | |
965 | ret = sdhci_am654_restore(host); |
966 | if (ret) |
967 | return ret; |
968 | |
969 | ret = sdhci_runtime_resume_host(host, soft_reset: 0); |
970 | if (ret) |
971 | return ret; |
972 | |
973 | ret = cqhci_resume(mmc: host->mmc); |
974 | if (ret) |
975 | return ret; |
976 | |
977 | return 0; |
978 | } |
979 | #endif |
980 | |
981 | static const struct dev_pm_ops sdhci_am654_dev_pm_ops = { |
982 | SET_RUNTIME_PM_OPS(sdhci_am654_runtime_suspend, |
983 | sdhci_am654_runtime_resume, NULL) |
984 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
985 | pm_runtime_force_resume) |
986 | }; |
987 | |
988 | static struct platform_driver sdhci_am654_driver = { |
989 | .driver = { |
990 | .name = "sdhci-am654" , |
991 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
992 | .pm = &sdhci_am654_dev_pm_ops, |
993 | .of_match_table = sdhci_am654_of_match, |
994 | }, |
995 | .probe = sdhci_am654_probe, |
996 | .remove_new = sdhci_am654_remove, |
997 | }; |
998 | |
999 | module_platform_driver(sdhci_am654_driver); |
1000 | |
1001 | MODULE_DESCRIPTION("Driver for SDHCI Controller on TI's AM654 devices" ); |
1002 | MODULE_AUTHOR("Faiz Abbas <faiz_abbas@ti.com>" ); |
1003 | MODULE_LICENSE("GPL" ); |
1004 | |