xref: /linux/drivers/mmc/host/sdhci-of-dwcmshc.c (revision 172cdcaefea5c297fdb3d20b7d5aff60ae4fbce6)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for Synopsys DesignWare Cores Mobile Storage Host Controller
4  *
5  * Copyright (C) 2018 Synaptics Incorporated
6  *
7  * Author: Jisheng Zhang <jszhang@kernel.org>
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 /* DWCMSHC specific Mode Select value */
25 #define DWCMSHC_CTRL_HS400		0x7
26 
27 /* DWC IP vendor area 1 pointer */
28 #define DWCMSHC_P_VENDOR_AREA1		0xe8
29 #define DWCMSHC_AREA1_MASK		GENMASK(11, 0)
30 /* Offset inside the  vendor area 1 */
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 /* Rockchip specific Registers */
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 
63 struct rk3568_priv {
64 	/* Rockchip specified optional clocks */
65 	struct clk_bulk_data rockchip_clks[RK3568_MAX_CLKS];
66 	u8 txclk_tapnum;
67 };
68 
69 struct dwcmshc_priv {
70 	struct clk	*bus_clk;
71 	int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */
72 	void *priv; /* pointer to SoC private stuff */
73 };
74 
75 /*
76  * If DMA addr spans 128MB boundary, we split the DMA transfer into two
77  * so that each DMA transfer doesn't exceed the boundary.
78  */
79 static 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 
98 static 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 
108 static 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 	 * No matter V4 is enabled or not, ARGUMENT2 register is 32-bit
115 	 * block count register which doesn't support stuff bits of
116 	 * CMD23 argument on dwcmsch host controller.
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 
124 static 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 
131 static 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 	/* Select Bus Speed Mode for host */
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 
157 static 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 
175 static 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 	 * DO NOT TOUCH THIS SETTING. RX clk inverter unit is enabled
188 	 * by default, but it shouldn't be enabled. We should anyway
189 	 * disable it before issuing any cmds.
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 	/* Rockchip platform only support 375KHz for identify mode */
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 	/* Disable cmd conflict check */
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 		/* Disable DLL to reset sample clock */
216 		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
217 		return;
218 	}
219 
220 	/* Reset DLL */
221 	sdhci_writel(host, BIT(1), DWCMSHC_EMMC_DLL_CTRL);
222 	udelay(1);
223 	sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL);
224 
225 	/* Init DLL settings */
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 | /* tune clock stop en */
239 		0x2 << 17 | /* pre-change delay */
240 		0x3 << 19;  /* post-change delay */
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 
258 static 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 
267 static 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 
276 static 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 
282 static 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 
290 static 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 	/* Disable cmd conflict check */
316 	sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3);
317 	/* Reset previous settings */
318 	sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
319 	sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN);
320 
321 	return 0;
322 }
323 
324 static 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 };
335 MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
336 
337 #ifdef CONFIG_ACPI
338 static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = {
339 	{ .id = "MLNXBF30" },
340 	{}
341 };
342 #endif
343 
344 static 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 	 * extra adma table cnt for cross 128M boundary handling.
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 
427 err_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);
433 free_pltfm:
434 	sdhci_pltfm_free(pdev);
435 	return err;
436 }
437 
438 static 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
458 static 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 
481 static 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 
510 static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume);
511 
512 static 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 };
523 module_platform_driver(sdhci_dwcmshc_driver);
524 
525 MODULE_DESCRIPTION("SDHCI platform driver for Synopsys DWC MSHC");
526 MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
527 MODULE_LICENSE("GPL v2");
528