1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Exynos Specific Extensions for Synopsys DW Multimedia Card Interface driver
4 *
5 * Copyright (C) 2012, Samsung Electronics Co., Ltd.
6 */
7
8 #include <linux/module.h>
9 #include <linux/platform_device.h>
10 #include <linux/clk.h>
11 #include <linux/mmc/host.h>
12 #include <linux/mmc/mmc.h>
13 #include <linux/of.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/slab.h>
16
17 #include "dw_mmc.h"
18 #include "dw_mmc-pltfm.h"
19 #include "dw_mmc-exynos.h"
20
21 /* Variations in Exynos specific dw-mshc controller */
22 enum dw_mci_exynos_type {
23 DW_MCI_TYPE_EXYNOS4210,
24 DW_MCI_TYPE_EXYNOS4412,
25 DW_MCI_TYPE_EXYNOS5250,
26 DW_MCI_TYPE_EXYNOS5420,
27 DW_MCI_TYPE_EXYNOS5420_SMU,
28 DW_MCI_TYPE_EXYNOS7,
29 DW_MCI_TYPE_EXYNOS7_SMU,
30 DW_MCI_TYPE_EXYNOS7870,
31 DW_MCI_TYPE_EXYNOS7870_SMU,
32 DW_MCI_TYPE_ARTPEC8,
33 };
34
35 /* Exynos implementation specific driver private data */
36 struct dw_mci_exynos_priv_data {
37 enum dw_mci_exynos_type ctrl_type;
38 u8 ciu_div;
39 u32 sdr_timing;
40 u32 ddr_timing;
41 u32 hs400_timing;
42 u32 tuned_sample;
43 u32 cur_speed;
44 u32 dqs_delay;
45 u32 saved_dqs_en;
46 u32 saved_strobe_ctrl;
47 };
48
49 static struct dw_mci_exynos_compatible {
50 char *compatible;
51 enum dw_mci_exynos_type ctrl_type;
52 } exynos_compat[] = {
53 {
54 .compatible = "samsung,exynos4210-dw-mshc",
55 .ctrl_type = DW_MCI_TYPE_EXYNOS4210,
56 }, {
57 .compatible = "samsung,exynos4412-dw-mshc",
58 .ctrl_type = DW_MCI_TYPE_EXYNOS4412,
59 }, {
60 .compatible = "samsung,exynos5250-dw-mshc",
61 .ctrl_type = DW_MCI_TYPE_EXYNOS5250,
62 }, {
63 .compatible = "samsung,exynos5420-dw-mshc",
64 .ctrl_type = DW_MCI_TYPE_EXYNOS5420,
65 }, {
66 .compatible = "samsung,exynos5420-dw-mshc-smu",
67 .ctrl_type = DW_MCI_TYPE_EXYNOS5420_SMU,
68 }, {
69 .compatible = "samsung,exynos7-dw-mshc",
70 .ctrl_type = DW_MCI_TYPE_EXYNOS7,
71 }, {
72 .compatible = "samsung,exynos7-dw-mshc-smu",
73 .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU,
74 }, {
75 .compatible = "samsung,exynos7870-dw-mshc",
76 .ctrl_type = DW_MCI_TYPE_EXYNOS7870,
77 }, {
78 .compatible = "samsung,exynos7870-dw-mshc-smu",
79 .ctrl_type = DW_MCI_TYPE_EXYNOS7870_SMU,
80 }, {
81 .compatible = "axis,artpec8-dw-mshc",
82 .ctrl_type = DW_MCI_TYPE_ARTPEC8,
83 },
84 };
85
dw_mci_exynos_get_ciu_div(struct dw_mci * host)86 static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
87 {
88 struct dw_mci_exynos_priv_data *priv = host->priv;
89
90 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
91 return EXYNOS4412_FIXED_CIU_CLK_DIV;
92 else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
93 return EXYNOS4210_FIXED_CIU_CLK_DIV;
94 else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
95 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
96 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
97 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
98 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
99 return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
100 else
101 return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
102 }
103
dw_mci_exynos_config_smu(struct dw_mci * host)104 static void dw_mci_exynos_config_smu(struct dw_mci *host)
105 {
106 struct dw_mci_exynos_priv_data *priv = host->priv;
107
108 /*
109 * If Exynos is provided the Security management,
110 * set for non-ecryption mode at this time.
111 */
112 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU ||
113 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
114 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) {
115 mci_writel(host, MPSBEGIN0, 0);
116 mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX);
117 mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT |
118 SDMMC_MPSCTRL_NON_SECURE_READ_BIT |
119 SDMMC_MPSCTRL_VALID |
120 SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
121 }
122 }
123
dw_mci_exynos_priv_init(struct dw_mci * host)124 static int dw_mci_exynos_priv_init(struct dw_mci *host)
125 {
126 struct dw_mci_exynos_priv_data *priv = host->priv;
127
128 dw_mci_exynos_config_smu(host);
129
130 if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
131 priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
132 priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
133 priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
134 mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
135 if (!priv->dqs_delay)
136 priv->dqs_delay =
137 DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
138 }
139
140 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
141 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) {
142 /* Quirk needed for certain Exynos SoCs */
143 host->quirks |= DW_MMC_QUIRK_FIFO64_32;
144 }
145
146 if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) {
147 /* Quirk needed for the ARTPEC-8 SoC */
148 host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT;
149 }
150
151 host->bus_hz /= (priv->ciu_div + 1);
152
153 return 0;
154 }
155
dw_mci_exynos_set_clksel_timing(struct dw_mci * host,u32 timing)156 static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
157 {
158 struct dw_mci_exynos_priv_data *priv = host->priv;
159 u32 clksel;
160
161 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
162 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
163 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
164 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
165 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
166 clksel = mci_readl(host, CLKSEL64);
167 else
168 clksel = mci_readl(host, CLKSEL);
169
170 clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
171
172 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
173 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
174 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
175 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
176 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
177 mci_writel(host, CLKSEL64, clksel);
178 else
179 mci_writel(host, CLKSEL, clksel);
180
181 /*
182 * Exynos4412 and Exynos5250 extends the use of CMD register with the
183 * use of bit 29 (which is reserved on standard MSHC controllers) for
184 * optionally bypassing the HOLD register for command and data. The
185 * HOLD register should be bypassed in case there is no phase shift
186 * applied on CMD/DATA that is sent to the card.
187 */
188 if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->slot)
189 set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->slot->flags);
190 }
191
192 #ifdef CONFIG_PM
dw_mci_exynos_runtime_resume(struct device * dev)193 static int dw_mci_exynos_runtime_resume(struct device *dev)
194 {
195 struct dw_mci *host = dev_get_drvdata(dev);
196 int ret;
197
198 ret = dw_mci_runtime_resume(dev);
199 if (ret)
200 return ret;
201
202 dw_mci_exynos_config_smu(host);
203
204 return ret;
205 }
206 #endif /* CONFIG_PM */
207
208 #ifdef CONFIG_PM_SLEEP
209 /**
210 * dw_mci_exynos_suspend_noirq - Exynos-specific suspend code
211 * @dev: Device to suspend (this device)
212 *
213 * This ensures that device will be in runtime active state in
214 * dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume()
215 */
dw_mci_exynos_suspend_noirq(struct device * dev)216 static int dw_mci_exynos_suspend_noirq(struct device *dev)
217 {
218 pm_runtime_get_noresume(dev);
219 return pm_runtime_force_suspend(dev);
220 }
221
222 /**
223 * dw_mci_exynos_resume_noirq - Exynos-specific resume code
224 * @dev: Device to resume (this device)
225 *
226 * On exynos5420 there is a silicon errata that will sometimes leave the
227 * WAKEUP_INT bit in the CLKSEL register asserted. This bit is 1 to indicate
228 * that it fired and we can clear it by writing a 1 back. Clear it to prevent
229 * interrupts from going off constantly.
230 *
231 * We run this code on all exynos variants because it doesn't hurt.
232 */
dw_mci_exynos_resume_noirq(struct device * dev)233 static int dw_mci_exynos_resume_noirq(struct device *dev)
234 {
235 struct dw_mci *host = dev_get_drvdata(dev);
236 struct dw_mci_exynos_priv_data *priv = host->priv;
237 u32 clksel;
238 int ret;
239
240 ret = pm_runtime_force_resume(dev);
241 if (ret)
242 return ret;
243
244 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
245 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
246 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
247 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
248 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
249 clksel = mci_readl(host, CLKSEL64);
250 else
251 clksel = mci_readl(host, CLKSEL);
252
253 if (clksel & SDMMC_CLKSEL_WAKEUP_INT) {
254 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
255 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
256 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
257 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
258 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
259 mci_writel(host, CLKSEL64, clksel);
260 else
261 mci_writel(host, CLKSEL, clksel);
262 }
263
264 pm_runtime_put(dev);
265
266 return 0;
267 }
268 #endif /* CONFIG_PM_SLEEP */
269
dw_mci_exynos_config_hs400(struct dw_mci * host,u32 timing)270 static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
271 {
272 struct dw_mci_exynos_priv_data *priv = host->priv;
273 u32 dqs, strobe;
274
275 /*
276 * Not supported to configure register
277 * related to HS400
278 */
279 if ((priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) ||
280 (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)) {
281 if (timing == MMC_TIMING_MMC_HS400)
282 dev_warn(host->dev,
283 "cannot configure HS400, unsupported chipset\n");
284 return;
285 }
286
287 dqs = priv->saved_dqs_en;
288 strobe = priv->saved_strobe_ctrl;
289
290 if (timing == MMC_TIMING_MMC_HS400) {
291 dqs |= DATA_STROBE_EN;
292 strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
293 } else if (timing == MMC_TIMING_UHS_SDR104) {
294 dqs &= 0xffffff00;
295 } else {
296 dqs &= ~DATA_STROBE_EN;
297 }
298
299 mci_writel(host, HS400_DQS_EN, dqs);
300 mci_writel(host, HS400_DLINE_CTRL, strobe);
301 }
302
dw_mci_exynos_adjust_clock(struct dw_mci * host,unsigned int wanted)303 static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
304 {
305 struct dw_mci_exynos_priv_data *priv = host->priv;
306 unsigned long actual;
307 u8 div;
308 int ret;
309 /*
310 * Don't care if wanted clock is zero or
311 * ciu clock is unavailable
312 */
313 if (!wanted || IS_ERR(host->ciu_clk))
314 return;
315
316 /* Guaranteed minimum frequency for cclkin */
317 if (wanted < EXYNOS_CCLKIN_MIN)
318 wanted = EXYNOS_CCLKIN_MIN;
319
320 if (wanted == priv->cur_speed)
321 return;
322
323 div = dw_mci_exynos_get_ciu_div(host);
324 ret = clk_set_rate(host->ciu_clk, wanted * div);
325 if (ret)
326 dev_warn(host->dev,
327 "failed to set clk-rate %u error: %d\n",
328 wanted * div, ret);
329 actual = clk_get_rate(host->ciu_clk);
330 host->bus_hz = actual / div;
331 priv->cur_speed = wanted;
332 host->current_speed = 0;
333 }
334
dw_mci_exynos_set_ios(struct dw_mci * host,struct mmc_ios * ios)335 static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
336 {
337 struct dw_mci_exynos_priv_data *priv = host->priv;
338 unsigned int wanted = ios->clock;
339 u32 timing = ios->timing, clksel;
340
341 switch (timing) {
342 case MMC_TIMING_MMC_HS400:
343 /* Update tuned sample timing */
344 clksel = SDMMC_CLKSEL_UP_SAMPLE(
345 priv->hs400_timing, priv->tuned_sample);
346 wanted <<= 1;
347 break;
348 case MMC_TIMING_MMC_DDR52:
349 clksel = priv->ddr_timing;
350 /* Should be double rate for DDR mode */
351 if (ios->bus_width == MMC_BUS_WIDTH_8)
352 wanted <<= 1;
353 break;
354 case MMC_TIMING_UHS_SDR104:
355 case MMC_TIMING_UHS_SDR50:
356 clksel = (priv->sdr_timing & 0xfff8ffff) |
357 (priv->ciu_div << 16);
358 break;
359 case MMC_TIMING_UHS_DDR50:
360 clksel = (priv->ddr_timing & 0xfff8ffff) |
361 (priv->ciu_div << 16);
362 break;
363 default:
364 clksel = priv->sdr_timing;
365 }
366
367 /* Set clock timing for the requested speed mode*/
368 dw_mci_exynos_set_clksel_timing(host, clksel);
369
370 /* Configure setting for HS400 */
371 dw_mci_exynos_config_hs400(host, timing);
372
373 /* Configure clock rate */
374 dw_mci_exynos_adjust_clock(host, wanted);
375 }
376
dw_mci_exynos_parse_dt(struct dw_mci * host)377 static int dw_mci_exynos_parse_dt(struct dw_mci *host)
378 {
379 struct dw_mci_exynos_priv_data *priv;
380 struct device_node *np = host->dev->of_node;
381 u32 timing[2];
382 u32 div = 0;
383 int idx;
384 int ret;
385
386 priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
387 if (!priv)
388 return -ENOMEM;
389
390 for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) {
391 if (of_device_is_compatible(np, exynos_compat[idx].compatible))
392 priv->ctrl_type = exynos_compat[idx].ctrl_type;
393 }
394
395 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
396 priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
397 else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
398 priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
399 else {
400 of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
401 priv->ciu_div = div;
402 }
403
404 ret = of_property_read_u32_array(np,
405 "samsung,dw-mshc-sdr-timing", timing, 2);
406 if (ret)
407 return ret;
408
409 priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
410
411 ret = of_property_read_u32_array(np,
412 "samsung,dw-mshc-ddr-timing", timing, 2);
413 if (ret)
414 return ret;
415
416 priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
417
418 ret = of_property_read_u32_array(np,
419 "samsung,dw-mshc-hs400-timing", timing, 2);
420 if (!ret && of_property_read_u32(np,
421 "samsung,read-strobe-delay", &priv->dqs_delay))
422 dev_dbg(host->dev,
423 "read-strobe-delay is not found, assuming usage of default value\n");
424
425 priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1],
426 HS400_FIXED_CIU_CLK_DIV);
427 host->priv = priv;
428 return 0;
429 }
430
dw_mci_exynos_get_clksmpl(struct dw_mci * host)431 static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host)
432 {
433 struct dw_mci_exynos_priv_data *priv = host->priv;
434
435 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
436 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
437 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
438 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
439 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
440 return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64));
441 else
442 return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL));
443 }
444
dw_mci_exynos_set_clksmpl(struct dw_mci * host,u8 sample)445 static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
446 {
447 u32 clksel;
448 struct dw_mci_exynos_priv_data *priv = host->priv;
449
450 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
451 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
452 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
453 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
454 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
455 clksel = mci_readl(host, CLKSEL64);
456 else
457 clksel = mci_readl(host, CLKSEL);
458 clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
459 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
460 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
461 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
462 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
463 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
464 mci_writel(host, CLKSEL64, clksel);
465 else
466 mci_writel(host, CLKSEL, clksel);
467 }
468
dw_mci_exynos_move_next_clksmpl(struct dw_mci * host)469 static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
470 {
471 struct dw_mci_exynos_priv_data *priv = host->priv;
472 u32 clksel;
473 u8 sample;
474
475 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
476 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
477 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
478 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
479 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
480 clksel = mci_readl(host, CLKSEL64);
481 else
482 clksel = mci_readl(host, CLKSEL);
483
484 sample = (clksel + 1) & 0x7;
485 clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
486
487 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
488 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
489 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
490 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
491 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
492 mci_writel(host, CLKSEL64, clksel);
493 else
494 mci_writel(host, CLKSEL, clksel);
495
496 return sample;
497 }
498
dw_mci_exynos_get_best_clksmpl(u8 candidates)499 static s8 dw_mci_exynos_get_best_clksmpl(u8 candidates)
500 {
501 const u8 iter = 8;
502 u8 __c;
503 s8 i, loc = -1;
504
505 for (i = 0; i < iter; i++) {
506 __c = ror8(candidates, i);
507 if ((__c & 0xc7) == 0xc7) {
508 loc = i;
509 goto out;
510 }
511 }
512
513 for (i = 0; i < iter; i++) {
514 __c = ror8(candidates, i);
515 if ((__c & 0x83) == 0x83) {
516 loc = i;
517 goto out;
518 }
519 }
520
521 /*
522 * If there is no cadiates value, then it needs to return -EIO.
523 * If there are candidates values and don't find bset clk sample value,
524 * then use a first candidates clock sample value.
525 */
526 for (i = 0; i < iter; i++) {
527 __c = ror8(candidates, i);
528 if ((__c & 0x1) == 0x1) {
529 loc = i;
530 goto out;
531 }
532 }
533 out:
534 return loc;
535 }
536
dw_mci_exynos_execute_tuning(struct dw_mci_slot * slot,u32 opcode)537 static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
538 {
539 struct dw_mci *host = slot->host;
540 struct dw_mci_exynos_priv_data *priv = host->priv;
541 struct mmc_host *mmc = slot->mmc;
542 u8 start_smpl, smpl, candidates = 0;
543 s8 found;
544 int ret = 0;
545
546 start_smpl = dw_mci_exynos_get_clksmpl(host);
547
548 do {
549 mci_writel(host, TMOUT, ~0);
550 smpl = dw_mci_exynos_move_next_clksmpl(host);
551
552 if (!mmc_send_tuning(mmc, opcode, NULL))
553 candidates |= (1 << smpl);
554
555 } while (start_smpl != smpl);
556
557 found = dw_mci_exynos_get_best_clksmpl(candidates);
558 if (found >= 0) {
559 dw_mci_exynos_set_clksmpl(host, found);
560 priv->tuned_sample = found;
561 } else {
562 ret = -EIO;
563 dev_warn(&mmc->class_dev,
564 "There is no candidates value about clksmpl!\n");
565 }
566
567 return ret;
568 }
569
dw_mci_exynos_prepare_hs400_tuning(struct dw_mci * host,struct mmc_ios * ios)570 static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
571 struct mmc_ios *ios)
572 {
573 struct dw_mci_exynos_priv_data *priv = host->priv;
574
575 dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
576 dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
577
578 return 0;
579 }
580
dw_mci_exynos_set_data_timeout(struct dw_mci * host,unsigned int timeout_ns)581 static void dw_mci_exynos_set_data_timeout(struct dw_mci *host,
582 unsigned int timeout_ns)
583 {
584 u32 clk_div, tmout;
585 u64 tmp;
586 unsigned int tmp2;
587
588 clk_div = (mci_readl(host, CLKDIV) & 0xFF) * 2;
589 if (clk_div == 0)
590 clk_div = 1;
591
592 tmp = DIV_ROUND_UP_ULL((u64)timeout_ns * host->bus_hz, NSEC_PER_SEC);
593 tmp = DIV_ROUND_UP_ULL(tmp, clk_div);
594
595 /* TMOUT[7:0] (RESPONSE_TIMEOUT) */
596 tmout = 0xFF; /* Set maximum */
597
598 /*
599 * Extended HW timer (max = 0x6FFFFF2):
600 * ((TMOUT[10:8] - 1) * 0xFFFFFF + TMOUT[31:11] * 8)
601 */
602 if (!tmp || tmp > 0x6FFFFF2)
603 tmout |= (0xFFFFFF << 8);
604 else {
605 /* TMOUT[10:8] */
606 tmp2 = (((unsigned int)tmp / 0xFFFFFF) + 1) & 0x7;
607 tmout |= tmp2 << 8;
608
609 /* TMOUT[31:11] */
610 tmp = tmp - ((tmp2 - 1) * 0xFFFFFF);
611 tmout |= (tmp & 0xFFFFF8) << 8;
612 }
613
614 mci_writel(host, TMOUT, tmout);
615 dev_dbg(host->dev, "timeout_ns: %u => TMOUT[31:8]: %#08x",
616 timeout_ns, tmout >> 8);
617 }
618
dw_mci_exynos_get_drto_clks(struct dw_mci * host)619 static u32 dw_mci_exynos_get_drto_clks(struct dw_mci *host)
620 {
621 u32 drto_clks;
622
623 drto_clks = mci_readl(host, TMOUT) >> 8;
624
625 return (((drto_clks & 0x7) - 1) * 0xFFFFFF) + ((drto_clks & 0xFFFFF8));
626 }
627
628 /* Common capabilities of Exynos4/Exynos5 SoC */
629 static unsigned long exynos_dwmmc_caps[4] = {
630 MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA,
631 0,
632 0,
633 0,
634 };
635
636 static const struct dw_mci_drv_data exynos_drv_data = {
637 .caps = exynos_dwmmc_caps,
638 .num_caps = ARRAY_SIZE(exynos_dwmmc_caps),
639 .common_caps = MMC_CAP_CMD23,
640 .init = dw_mci_exynos_priv_init,
641 .set_ios = dw_mci_exynos_set_ios,
642 .parse_dt = dw_mci_exynos_parse_dt,
643 .execute_tuning = dw_mci_exynos_execute_tuning,
644 .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning,
645 };
646
647 static const struct dw_mci_drv_data artpec_drv_data = {
648 .common_caps = MMC_CAP_CMD23,
649 .init = dw_mci_exynos_priv_init,
650 .set_ios = dw_mci_exynos_set_ios,
651 .parse_dt = dw_mci_exynos_parse_dt,
652 .execute_tuning = dw_mci_exynos_execute_tuning,
653 .set_data_timeout = dw_mci_exynos_set_data_timeout,
654 .get_drto_clks = dw_mci_exynos_get_drto_clks,
655 };
656
657 static const struct of_device_id dw_mci_exynos_match[] = {
658 { .compatible = "samsung,exynos4412-dw-mshc",
659 .data = &exynos_drv_data, },
660 { .compatible = "samsung,exynos5250-dw-mshc",
661 .data = &exynos_drv_data, },
662 { .compatible = "samsung,exynos5420-dw-mshc",
663 .data = &exynos_drv_data, },
664 { .compatible = "samsung,exynos5420-dw-mshc-smu",
665 .data = &exynos_drv_data, },
666 { .compatible = "samsung,exynos7-dw-mshc",
667 .data = &exynos_drv_data, },
668 { .compatible = "samsung,exynos7-dw-mshc-smu",
669 .data = &exynos_drv_data, },
670 { .compatible = "samsung,exynos7870-dw-mshc",
671 .data = &exynos_drv_data, },
672 { .compatible = "samsung,exynos7870-dw-mshc-smu",
673 .data = &exynos_drv_data, },
674 { .compatible = "axis,artpec8-dw-mshc",
675 .data = &artpec_drv_data, },
676 {},
677 };
678 MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
679
dw_mci_exynos_probe(struct platform_device * pdev)680 static int dw_mci_exynos_probe(struct platform_device *pdev)
681 {
682 const struct dw_mci_drv_data *drv_data;
683 const struct of_device_id *match;
684 int ret;
685
686 match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node);
687 drv_data = match->data;
688
689 pm_runtime_get_noresume(&pdev->dev);
690 pm_runtime_set_active(&pdev->dev);
691 pm_runtime_enable(&pdev->dev);
692
693 ret = dw_mci_pltfm_register(pdev, drv_data);
694 if (ret) {
695 pm_runtime_disable(&pdev->dev);
696 pm_runtime_set_suspended(&pdev->dev);
697 pm_runtime_put_noidle(&pdev->dev);
698
699 return ret;
700 }
701
702 return 0;
703 }
704
dw_mci_exynos_remove(struct platform_device * pdev)705 static void dw_mci_exynos_remove(struct platform_device *pdev)
706 {
707 pm_runtime_disable(&pdev->dev);
708 pm_runtime_set_suspended(&pdev->dev);
709 pm_runtime_put_noidle(&pdev->dev);
710
711 dw_mci_pltfm_remove(pdev);
712 }
713
714 static const struct dev_pm_ops dw_mci_exynos_pmops = {
715 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq,
716 dw_mci_exynos_resume_noirq)
717 SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
718 dw_mci_exynos_runtime_resume,
719 NULL)
720 };
721
722 static struct platform_driver dw_mci_exynos_pltfm_driver = {
723 .probe = dw_mci_exynos_probe,
724 .remove = dw_mci_exynos_remove,
725 .driver = {
726 .name = "dwmmc_exynos",
727 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
728 .of_match_table = dw_mci_exynos_match,
729 .pm = &dw_mci_exynos_pmops,
730 },
731 };
732
733 module_platform_driver(dw_mci_exynos_pltfm_driver);
734
735 MODULE_DESCRIPTION("Samsung Specific DW-MSHC Driver Extension");
736 MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com");
737 MODULE_LICENSE("GPL v2");
738 MODULE_ALIAS("platform:dwmmc_exynos");
739