1
2
3
4
5
6
7
8
9
10#include <linux/acpi.h>
11#include <linux/clk.h>
12#include <linux/dma-mapping.h>
13#include <linux/iopoll.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/of_device.h>
18#include <linux/sizes.h>
19
20#include "sdhci-pltfm.h"
21
22#define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16)
23
24
25#define DWCMSHC_CTRL_HS400 0x7
26
27
28#define DWCMSHC_P_VENDOR_AREA1 0xe8
29#define DWCMSHC_AREA1_MASK GENMASK(11, 0)
30
31#define DWCMSHC_HOST_CTRL3 0x8
32#define DWCMSHC_EMMC_CONTROL 0x2c
33#define DWCMSHC_ENHANCED_STROBE BIT(8)
34#define DWCMSHC_EMMC_ATCTRL 0x40
35
36
37#define DWCMSHC_EMMC_DLL_CTRL 0x800
38#define DWCMSHC_EMMC_DLL_RXCLK 0x804
39#define DWCMSHC_EMMC_DLL_TXCLK 0x808
40#define DWCMSHC_EMMC_DLL_STRBIN 0x80c
41#define DLL_STRBIN_TAPNUM_FROM_SW BIT(24)
42#define DWCMSHC_EMMC_DLL_STATUS0 0x840
43#define DWCMSHC_EMMC_DLL_START BIT(0)
44#define DWCMSHC_EMMC_DLL_LOCKED BIT(8)
45#define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9)
46#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29
47#define DWCMSHC_EMMC_DLL_START_POINT 16
48#define DWCMSHC_EMMC_DLL_INC 8
49#define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
50#define DLL_TXCLK_TAPNUM_DEFAULT 0x8
51#define DLL_STRBIN_TAPNUM_DEFAULT 0x8
52#define DLL_TXCLK_TAPNUM_FROM_SW BIT(24)
53#define DLL_RXCLK_NO_INVERTER 1
54#define DLL_RXCLK_INVERTER 0
55#define DLL_LOCK_WO_TMOUT(x) \
56 ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
57 (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
58#define RK3568_MAX_CLKS 3
59
60#define BOUNDARY_OK(addr, len) \
61 ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
62
63struct rk3568_priv {
64
65 struct clk_bulk_data rockchip_clks[RK3568_MAX_CLKS];
66 u8 txclk_tapnum;
67};
68
69struct dwcmshc_priv {
70 struct clk *bus_clk;
71 int vendor_specific_area1;
72 void *priv;
73};
74
75
76
77
78
79static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
80 dma_addr_t addr, int len, unsigned int cmd)
81{
82 int tmplen, offset;
83
84 if (likely(!len || BOUNDARY_OK(addr, len))) {
85 sdhci_adma_write_desc(host, desc, addr, len, cmd);
86 return;
87 }
88
89 offset = addr & (SZ_128M - 1);
90 tmplen = SZ_128M - offset;
91 sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
92
93 addr += tmplen;
94 len -= tmplen;
95 sdhci_adma_write_desc(host, desc, addr, len, cmd);
96}
97
98static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host)
99{
100 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
101
102 if (pltfm_host->clk)
103 return sdhci_pltfm_clk_get_max_clock(host);
104 else
105 return pltfm_host->clock;
106}
107
108static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc,
109 struct mmc_request *mrq)
110{
111 struct sdhci_host *host = mmc_priv(mmc);
112
113
114
115
116
117
118 if (mrq->sbc && (mrq->sbc->arg & SDHCI_DWCMSHC_ARG2_STUFF))
119 host->flags &= ~SDHCI_AUTO_CMD23;
120 else
121 host->flags |= SDHCI_AUTO_CMD23;
122}
123
124static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq)
125{
126 dwcmshc_check_auto_cmd23(mmc, mrq);
127
128 sdhci_request(mmc, mrq);
129}
130
131static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
132 unsigned int timing)
133{
134 u16 ctrl_2;
135
136 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
137
138 ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
139 if ((timing == MMC_TIMING_MMC_HS200) ||
140 (timing == MMC_TIMING_UHS_SDR104))
141 ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
142 else if (timing == MMC_TIMING_UHS_SDR12)
143 ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
144 else if ((timing == MMC_TIMING_UHS_SDR25) ||
145 (timing == MMC_TIMING_MMC_HS))
146 ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
147 else if (timing == MMC_TIMING_UHS_SDR50)
148 ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
149 else if ((timing == MMC_TIMING_UHS_DDR50) ||
150 (timing == MMC_TIMING_MMC_DDR52))
151 ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
152 else if (timing == MMC_TIMING_MMC_HS400)
153 ctrl_2 |= DWCMSHC_CTRL_HS400;
154 sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
155}
156
157static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc,
158 struct mmc_ios *ios)
159{
160 u32 vendor;
161 struct sdhci_host *host = mmc_priv(mmc);
162 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
163 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
164 int reg = priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL;
165
166 vendor = sdhci_readl(host, reg);
167 if (ios->enhanced_strobe)
168 vendor |= DWCMSHC_ENHANCED_STROBE;
169 else
170 vendor &= ~DWCMSHC_ENHANCED_STROBE;
171
172 sdhci_writel(host, vendor, reg);
173}
174
175static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock)
176{
177 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
178 struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
179 struct rk3568_priv *priv = dwc_priv->priv;
180 u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
181 u32 extra, reg;
182 int err;
183
184 host->mmc->actual_clock = 0;
185
186
187
188
189
190
191 extra = DWCMSHC_EMMC_DLL_DLYENA |
192 DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
193 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
194
195 if (clock == 0)
196 return;
197
198
199 if (clock <= 400000)
200 clock = 375000;
201
202 err = clk_set_rate(pltfm_host->clk, clock);
203 if (err)
204 dev_err(mmc_dev(host->mmc), "fail to set clock %d", clock);
205
206 sdhci_set_clock(host, clock);
207
208
209 reg = dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3;
210 extra = sdhci_readl(host, reg);
211 extra &= ~BIT(0);
212 sdhci_writel(host, extra, reg);
213
214 if (clock <= 400000) {
215
216 sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
217 return;
218 }
219
220
221 sdhci_writel(host, BIT(1), DWCMSHC_EMMC_DLL_CTRL);
222 udelay(1);
223 sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL);
224
225
226 extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
227 0x2 << DWCMSHC_EMMC_DLL_INC |
228 DWCMSHC_EMMC_DLL_START;
229 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL);
230 err = readl_poll_timeout(host->ioaddr + DWCMSHC_EMMC_DLL_STATUS0,
231 extra, DLL_LOCK_WO_TMOUT(extra), 1,
232 500 * USEC_PER_MSEC);
233 if (err) {
234 dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n");
235 return;
236 }
237
238 extra = 0x1 << 16 |
239 0x2 << 17 |
240 0x3 << 19;
241 sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
242
243 if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
244 host->mmc->ios.timing == MMC_TIMING_MMC_HS400)
245 txclk_tapnum = priv->txclk_tapnum;
246
247 extra = DWCMSHC_EMMC_DLL_DLYENA |
248 DLL_TXCLK_TAPNUM_FROM_SW |
249 txclk_tapnum;
250 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
251
252 extra = DWCMSHC_EMMC_DLL_DLYENA |
253 DLL_STRBIN_TAPNUM_DEFAULT |
254 DLL_STRBIN_TAPNUM_FROM_SW;
255 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
256}
257
258static const struct sdhci_ops sdhci_dwcmshc_ops = {
259 .set_clock = sdhci_set_clock,
260 .set_bus_width = sdhci_set_bus_width,
261 .set_uhs_signaling = dwcmshc_set_uhs_signaling,
262 .get_max_clock = dwcmshc_get_max_clock,
263 .reset = sdhci_reset,
264 .adma_write_desc = dwcmshc_adma_write_desc,
265};
266
267static const struct sdhci_ops sdhci_dwcmshc_rk3568_ops = {
268 .set_clock = dwcmshc_rk3568_set_clock,
269 .set_bus_width = sdhci_set_bus_width,
270 .set_uhs_signaling = dwcmshc_set_uhs_signaling,
271 .get_max_clock = sdhci_pltfm_clk_get_max_clock,
272 .reset = sdhci_reset,
273 .adma_write_desc = dwcmshc_adma_write_desc,
274};
275
276static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
277 .ops = &sdhci_dwcmshc_ops,
278 .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
279 .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
280};
281
282static const struct sdhci_pltfm_data sdhci_dwcmshc_rk3568_pdata = {
283 .ops = &sdhci_dwcmshc_rk3568_ops,
284 .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
285 SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
286 .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
287 SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
288};
289
290static int dwcmshc_rk3568_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
291{
292 int err;
293 struct rk3568_priv *priv = dwc_priv->priv;
294
295 priv->rockchip_clks[0].id = "axi";
296 priv->rockchip_clks[1].id = "block";
297 priv->rockchip_clks[2].id = "timer";
298 err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK3568_MAX_CLKS,
299 priv->rockchip_clks);
300 if (err) {
301 dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err);
302 return err;
303 }
304
305 err = clk_bulk_prepare_enable(RK3568_MAX_CLKS, priv->rockchip_clks);
306 if (err) {
307 dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err);
308 return err;
309 }
310
311 if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum",
312 &priv->txclk_tapnum))
313 priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
314
315
316 sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3);
317
318 sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
319 sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN);
320
321 return 0;
322}
323
324static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
325 {
326 .compatible = "rockchip,rk3568-dwcmshc",
327 .data = &sdhci_dwcmshc_rk3568_pdata,
328 },
329 {
330 .compatible = "snps,dwcmshc-sdhci",
331 .data = &sdhci_dwcmshc_pdata,
332 },
333 {},
334};
335MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
336
337#ifdef CONFIG_ACPI
338static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = {
339 { .id = "MLNXBF30" },
340 {}
341};
342#endif
343
344static int dwcmshc_probe(struct platform_device *pdev)
345{
346 struct device *dev = &pdev->dev;
347 struct sdhci_pltfm_host *pltfm_host;
348 struct sdhci_host *host;
349 struct dwcmshc_priv *priv;
350 struct rk3568_priv *rk_priv = NULL;
351 const struct sdhci_pltfm_data *pltfm_data;
352 int err;
353 u32 extra;
354
355 pltfm_data = of_device_get_match_data(&pdev->dev);
356 if (!pltfm_data) {
357 dev_err(&pdev->dev, "Error: No device match data found\n");
358 return -ENODEV;
359 }
360
361 host = sdhci_pltfm_init(pdev, pltfm_data,
362 sizeof(struct dwcmshc_priv));
363 if (IS_ERR(host))
364 return PTR_ERR(host);
365
366
367
368
369 extra = DIV_ROUND_UP_ULL(dma_get_required_mask(dev), SZ_128M);
370 if (extra > SDHCI_MAX_SEGS)
371 extra = SDHCI_MAX_SEGS;
372 host->adma_table_cnt += extra;
373
374 pltfm_host = sdhci_priv(host);
375 priv = sdhci_pltfm_priv(pltfm_host);
376
377 if (dev->of_node) {
378 pltfm_host->clk = devm_clk_get(dev, "core");
379 if (IS_ERR(pltfm_host->clk)) {
380 err = PTR_ERR(pltfm_host->clk);
381 dev_err(dev, "failed to get core clk: %d\n", err);
382 goto free_pltfm;
383 }
384 err = clk_prepare_enable(pltfm_host->clk);
385 if (err)
386 goto free_pltfm;
387
388 priv->bus_clk = devm_clk_get(dev, "bus");
389 if (!IS_ERR(priv->bus_clk))
390 clk_prepare_enable(priv->bus_clk);
391 }
392
393 err = mmc_of_parse(host->mmc);
394 if (err)
395 goto err_clk;
396
397 sdhci_get_of_property(pdev);
398
399 priv->vendor_specific_area1 =
400 sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK;
401
402 host->mmc_host_ops.request = dwcmshc_request;
403 host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
404
405 if (pltfm_data == &sdhci_dwcmshc_rk3568_pdata) {
406 rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk3568_priv), GFP_KERNEL);
407 if (!rk_priv) {
408 err = -ENOMEM;
409 goto err_clk;
410 }
411
412 priv->priv = rk_priv;
413
414 err = dwcmshc_rk3568_init(host, priv);
415 if (err)
416 goto err_clk;
417 }
418
419 host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
420
421 err = sdhci_add_host(host);
422 if (err)
423 goto err_clk;
424
425 return 0;
426
427err_clk:
428 clk_disable_unprepare(pltfm_host->clk);
429 clk_disable_unprepare(priv->bus_clk);
430 if (rk_priv)
431 clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
432 rk_priv->rockchip_clks);
433free_pltfm:
434 sdhci_pltfm_free(pdev);
435 return err;
436}
437
438static int dwcmshc_remove(struct platform_device *pdev)
439{
440 struct sdhci_host *host = platform_get_drvdata(pdev);
441 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
442 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
443 struct rk3568_priv *rk_priv = priv->priv;
444
445 sdhci_remove_host(host, 0);
446
447 clk_disable_unprepare(pltfm_host->clk);
448 clk_disable_unprepare(priv->bus_clk);
449 if (rk_priv)
450 clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
451 rk_priv->rockchip_clks);
452 sdhci_pltfm_free(pdev);
453
454 return 0;
455}
456
457#ifdef CONFIG_PM_SLEEP
458static int dwcmshc_suspend(struct device *dev)
459{
460 struct sdhci_host *host = dev_get_drvdata(dev);
461 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
462 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
463 struct rk3568_priv *rk_priv = priv->priv;
464 int ret;
465
466 ret = sdhci_suspend_host(host);
467 if (ret)
468 return ret;
469
470 clk_disable_unprepare(pltfm_host->clk);
471 if (!IS_ERR(priv->bus_clk))
472 clk_disable_unprepare(priv->bus_clk);
473
474 if (rk_priv)
475 clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
476 rk_priv->rockchip_clks);
477
478 return ret;
479}
480
481static int dwcmshc_resume(struct device *dev)
482{
483 struct sdhci_host *host = dev_get_drvdata(dev);
484 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
485 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
486 struct rk3568_priv *rk_priv = priv->priv;
487 int ret;
488
489 ret = clk_prepare_enable(pltfm_host->clk);
490 if (ret)
491 return ret;
492
493 if (!IS_ERR(priv->bus_clk)) {
494 ret = clk_prepare_enable(priv->bus_clk);
495 if (ret)
496 return ret;
497 }
498
499 if (rk_priv) {
500 ret = clk_bulk_prepare_enable(RK3568_MAX_CLKS,
501 rk_priv->rockchip_clks);
502 if (ret)
503 return ret;
504 }
505
506 return sdhci_resume_host(host);
507}
508#endif
509
510static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume);
511
512static struct platform_driver sdhci_dwcmshc_driver = {
513 .driver = {
514 .name = "sdhci-dwcmshc",
515 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
516 .of_match_table = sdhci_dwcmshc_dt_ids,
517 .acpi_match_table = ACPI_PTR(sdhci_dwcmshc_acpi_ids),
518 .pm = &dwcmshc_pmops,
519 },
520 .probe = dwcmshc_probe,
521 .remove = dwcmshc_remove,
522};
523module_platform_driver(sdhci_dwcmshc_driver);
524
525MODULE_DESCRIPTION("SDHCI platform driver for Synopsys DWC MSHC");
526MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
527MODULE_LICENSE("GPL v2");
528