• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Sunxi SD/MMC host driver
3 *
4 * Copyright (C) 2015 AllWinnertech Ltd.
5 * Author: lixiang <lixiang@allwinnertech>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
12 * kind, whether express or implied; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 */
16 
17 #ifdef CONFIG_ARCH_SUN50IW1P1
18 
19 #include <linux/clk.h>
20 #include <sunxi-clk.h>
21 
22 #include <linux/gpio.h>
23 #include <linux/platform_device.h>
24 #include <linux/spinlock.h>
25 #include <linux/scatterlist.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/slab.h>
28 #include <linux/reset.h>
29 
30 #include <linux/of_address.h>
31 #include <linux/of_gpio.h>
32 #include <linux/of_platform.h>
33 
34 #include <linux/mmc/host.h>
35 #include <linux/mmc/sd.h>
36 #include <linux/mmc/sdio.h>
37 #include <linux/mmc/mmc.h>
38 #include <linux/mmc/core.h>
39 #include <linux/mmc/card.h>
40 #include <linux/mmc/slot-gpio.h>
41 
42 #include "sunxi-mmc.h"
43 #include "sunxi-mmc-sun50iw1p1-0.h"
44 
45 /*reg*/
46 /*SMHC eMMC4.5 DDR Start Bit Detection Control Register */
47 /*SMHC CRC Status Detect Control Register */
48 /*SMHC Card Threshold Control Register */
49 /*SMHC Drive Delay Control Register */
50 /*SMHC Sample Delay Control Register */
51 /*SMHC Data Strobe Delay Control Register */
52 /*SMHC NewTiming Set Register */
53 #define SDXC_REG_EDSD		(0x010C)
54 #define SDXC_REG_CSDC		(0x0054)
55 #define SDXC_REG_THLD		(0x0100)
56 #define SDXC_REG_DRV_DL		(0x0140)
57 #define SDXC_REG_SAMP_DL	(0x0144)
58 #define SDXC_REG_DS_DL		(0x0148)
59 #define SDXC_REG_SD_NTSR	(0x005C)
60 
61 /*bit*/
62 #define SDXC_HS400_MD_EN				(1U<<31)
63 #define SDXC_CARD_WR_THLD_ENB		(1U<<2)
64 #define SDXC_CARD_RD_THLD_ENB		(1U)
65 
66 #define SDXC_DAT_DRV_PH_SEL			(1U<<17)
67 #define SDXC_CMD_DRV_PH_SEL			(1U<<16)
68 #define SDXC_SAMP_DL_SW_EN			(1u<<7)
69 #define SDXC_DS_DL_SW_EN			(1u<<7)
70 
71 #define	SDXC_2X_TIMING_MODE			(1U<<31)
72 
73 /*mask*/
74 #define SDXC_CRC_DET_PARA_MASK		(0xf)
75 #define SDXC_CARD_RD_THLD_MASK		(0x0FFF0000)
76 #define SDXC_TX_TL_MASK				(0xff)
77 #define SDXC_RX_TL_MASK				(0x00FF0000)
78 
79 #define SDXC_SAMP_DL_SW_MASK		(0x0000003F)
80 #define SDXC_DS_DL_SW_MASK			(0x0000003F)
81 
82 #define SDXC_SAM_TIMING_PH_MASK		(0x00000030)
83 
84 /*value*/
85 #define SDXC_CRC_DET_PARA_HS400		(6)
86 #define SDXC_CRC_DET_PARA_OTHER		(3)
87 #define SDXC_FIFO_DETH					(1024>>2)
88 
89 /*size*/
90 #define SDXC_CARD_RD_THLD_SIZE		(0x00000FFF)
91 
92 /*shit*/
93 #define SDXC_CARD_RD_THLD_SIZE_SHIFT		(16)
94 
95 #define SDXC_SAM_TIMING_PH_SHIFT			(4)
96 
97 enum sunxi_mmc_clk_mode {
98 	mmc_clk_400k = 0,
99 	mmc_clk_26M,
100 	mmc_clk_52M,
101 	mmc_clk_52M_DDR4,
102 	mmc_clk_52M_DDR8,
103 	mmc_clk_104M,
104 	mmc_clk_208M,
105 	mmc_clk_104M_DDR,
106 	mmc_clk_208M_DDR,
107 	mmc_clk_mod_num,
108 };
109 
110 struct sunxi_mmc_clk_dly {
111 	enum sunxi_mmc_clk_mode cmod;
112 	char *mod_str;
113 	u32 cmd_drv_ph;
114 	u32 dat_drv_ph;
115 	u32 sam_dly;
116 	u32 ds_dly;
117 	u32 sam_ph;
118 };
119 
120 	/*sample delay and output deley setting */
121 static struct sunxi_mmc_clk_dly mmc_clk_dly[mmc_clk_mod_num] = {
122 	[mmc_clk_400k] = {
123 			  .cmod = mmc_clk_400k,
124 			  .mod_str = "sunxi-dly-400k",
125 			  .cmd_drv_ph = 1,
126 			  .dat_drv_ph = 0,
127 			  .sam_dly = 0,
128 			  .ds_dly = 0,
129 			  .sam_ph = 0,
130 			  },
131 	[mmc_clk_26M] = {
132 			 .cmod = mmc_clk_26M,
133 			 .mod_str = "sunxi-dly-26M",
134 			 .cmd_drv_ph = 1,
135 			 .dat_drv_ph = 0,
136 			 .sam_dly = 0,
137 			 .ds_dly = 0,
138 			 .sam_ph = 0,
139 			 },
140 	[mmc_clk_52M] = {
141 			 .cmod = mmc_clk_52M,
142 			 .mod_str = "sunxi-dly-52M",
143 			 .cmd_drv_ph = 1,
144 			 .dat_drv_ph = 0,
145 			 .sam_dly = 0,
146 			 .ds_dly = 0,
147 			 .sam_ph = 0,
148 			 },
149 	[mmc_clk_52M_DDR4] = {
150 			      .cmod = mmc_clk_52M_DDR4,
151 			      .mod_str = "sunxi-dly-52M-ddr4",
152 			      .cmd_drv_ph = 1,
153 			      .dat_drv_ph = 0,
154 			      .sam_dly = 0,
155 			      .ds_dly = 0,
156 			      .sam_ph = 0,
157 			      },
158 	[mmc_clk_52M_DDR8] = {
159 			      .cmod = mmc_clk_52M_DDR8,
160 			      .mod_str = "sunxi-dly-52M-ddr8",
161 			      .cmd_drv_ph = 1,
162 			      .dat_drv_ph = 0,
163 			      .sam_dly = 0,
164 			      .ds_dly = 0,
165 			      .sam_ph = 0,
166 			      },
167 	[mmc_clk_104M] = {
168 			  .cmod = mmc_clk_104M,
169 			  .mod_str = "sunxi-dly-104M",
170 			  .cmd_drv_ph = 1,
171 			  .dat_drv_ph = 0,
172 			  .sam_dly = 0,
173 			  .ds_dly = 0,
174 			  .sam_ph = 0,
175 
176 			  },
177 	[mmc_clk_208M] = {
178 			  .cmod = mmc_clk_208M,
179 			  .mod_str = "sunxi-dly-208M",
180 			  .cmd_drv_ph = 1,
181 			  .dat_drv_ph = 0,
182 			  .sam_dly = 0,
183 			  .ds_dly = 0,
184 			  .sam_ph = 0,
185 			  },
186 	[mmc_clk_104M_DDR] = {
187 			      .cmod = mmc_clk_104M_DDR,
188 			      .mod_str = "sunxi-dly-104M-ddr",
189 			      .cmd_drv_ph = 1,
190 			      .dat_drv_ph = 0,
191 			      .sam_dly = 0,
192 			      .ds_dly = 0,
193 			      .sam_ph = 0,
194 			      },
195 	[mmc_clk_208M_DDR] = {
196 			      .cmod = mmc_clk_208M_DDR,
197 			      .mod_str = "sunxi-dly-208M-ddr",
198 			      .cmd_drv_ph = 1,
199 			      .dat_drv_ph = 0,
200 			      .sam_dly = 0,
201 			      .ds_dly = 0,
202 			      .sam_ph = 0,
203 			      },
204 };
205 
206 struct sunxi_mmc_spec_regs {
207 	u32 drv_dl;		/*REG_DRV_DL */
208 	u32 samp_dl;		/*REG_SAMP_DL */
209 	u32 ds_dl;		/*REG_DS_DL */
210 	u32 sd_ntsr;		/*REG_SD_NTSR */
211 };
212 
213 static struct sunxi_mmc_spec_regs bak_spec_regs;
214 
215 
sunxi_mmc_set_clk_dly(struct sunxi_mmc_host * host,int clk,int bus_width,int timing)216 static void sunxi_mmc_set_clk_dly(struct sunxi_mmc_host *host, int clk,
217 				  int bus_width, int timing)
218 {
219 	struct mmc_host *mhost = host->mmc;
220 	u32 rval = 0;
221 	enum sunxi_mmc_clk_mode cmod = mmc_clk_400k;
222 	u32 in_clk_dly[5] = { 0 };
223 	int ret = 0;
224 	struct device_node *np = NULL;
225 
226 	if (!mhost->parent || !mhost->parent->of_node) {
227 		SM_ERR(mmc_dev(host->mmc),
228 			"no dts to parse clk dly,use default\n");
229 		return;
230 	}
231 
232 	np = mhost->parent->of_node;
233 
234 	if (clk <= 400 * 1000) {
235 		cmod = mmc_clk_400k;
236 	} else if (clk <= 26 * 1000 * 1000) {
237 		cmod = mmc_clk_26M;
238 	} else if (clk <= 52 * 1000 * 1000) {
239 		if ((bus_width == MMC_BUS_WIDTH_4)
240 		    && sunxi_mmc_ddr_timing(timing)) {
241 			cmod = mmc_clk_52M_DDR4;
242 		} else if ((bus_width == MMC_BUS_WIDTH_8)
243 			   && (timing == MMC_TIMING_MMC_DDR52)) {
244 			cmod = mmc_clk_52M_DDR8;
245 		} else {
246 			cmod = mmc_clk_52M;
247 		}
248 	} else if (clk <= 104 * 1000 * 1000) {
249 		if ((bus_width == MMC_BUS_WIDTH_8)
250 		    && (timing == MMC_TIMING_MMC_HS400)) {
251 			cmod = mmc_clk_104M_DDR;
252 		} else {
253 			cmod = mmc_clk_104M;
254 		}
255 	} else if (clk <= 208 * 1000 * 1000) {
256 		if ((bus_width == MMC_BUS_WIDTH_8)
257 		    && (timing == MMC_TIMING_MMC_HS400)) {
258 			cmod = mmc_clk_208M_DDR;
259 		} else {
260 			cmod = mmc_clk_208M;
261 		}
262 	} else {
263 		SM_ERR(mmc_dev(mhost), "clk %d is out of range\n", clk);
264 		return;
265 	}
266 
267 	ret = of_property_read_u32_array(np, mmc_clk_dly[cmod].mod_str,
268 					 in_clk_dly, ARRAY_SIZE(in_clk_dly));
269 	if (ret) {
270 		SM_DBG(mmc_dev(host->mmc), "failded to get %s used default\n",
271 			mmc_clk_dly[cmod].mod_str);
272 	} else {
273 		mmc_clk_dly[cmod].cmd_drv_ph = in_clk_dly[0];
274 		mmc_clk_dly[cmod].dat_drv_ph = in_clk_dly[1];
275 		/*mmc_clk_dly[cmod].sam_dly             = in_clk_dly[2]; */
276 		/*mmc_clk_dly[cmod].ds_dly              = in_clk_dly[3]; */
277 		mmc_clk_dly[cmod].sam_ph = in_clk_dly[4];
278 		SM_DBG(mmc_dev(host->mmc), "Get %s clk dly ok\n",
279 			mmc_clk_dly[cmod].mod_str);
280 
281 	}
282 
283 	SM_DBG(mmc_dev(host->mmc), "Try set %s clk dly       ok\n",
284 		mmc_clk_dly[cmod].mod_str);
285 	SM_DBG(mmc_dev(host->mmc), "cmd_drv_ph	%d\n",
286 			mmc_clk_dly[cmod].cmd_drv_ph);
287 	SM_DBG(mmc_dev(host->mmc), "dat_drv_ph	%d\n",
288 		mmc_clk_dly[cmod].dat_drv_ph);
289 	/*SM_DBG(mmc_dev(host->mmc),
290 	*	"sam_dly %d\n",mmc_clk_dly[cmod].sam_dly);
291 	*/
292 	/*SM_DBG(mmc_dev(host->mmc),
293 	*	"ds_dly  %d\n",mmc_clk_dly[cmod].ds_dly);
294 	*/
295 	SM_DBG(mmc_dev(host->mmc), "sam_ph	%d\n",
296 		mmc_clk_dly[cmod].sam_ph);
297 
298 	rval = mmc_readl(host, REG_DRV_DL);
299 	if (mmc_clk_dly[cmod].cmd_drv_ph)
300 		rval |= SDXC_CMD_DRV_PH_SEL;	/*180 phase */
301 	else
302 		rval &= ~SDXC_CMD_DRV_PH_SEL;	/*90 phase */
303 
304 
305 	if (mmc_clk_dly[cmod].dat_drv_ph)
306 		rval |= SDXC_DAT_DRV_PH_SEL;	/*180 phase */
307 	else
308 		rval &= ~SDXC_DAT_DRV_PH_SEL;	/*90 phase */
309 
310 	sunxi_r_op(host, mmc_writel(host, REG_DRV_DL, rval));
311 
312 /*
313 *	rval = mmc_readl(host,REG_SAMP_DL);
314 *	rval &= ~SDXC_SAMP_DL_SW_MASK;
315 *	rval |= mmc_clk_dly[cmod].sam_dly & SDXC_SAMP_DL_SW_MASK;
316 *	rval |= SDXC_SAMP_DL_SW_EN;
317 *	mmc_writel(host,REG_SAMP_DL,rval);
318 *
319 *	rval = mmc_readl(host,REG_DS_DL);
320 *	rval &= ~SDXC_DS_DL_SW_MASK;
321 *	rval |= mmc_clk_dly[cmod].ds_dly & SDXC_DS_DL_SW_MASK;
322 *	rval |= SDXC_DS_DL_SW_EN;
323 *	mmc_writel(host,REG_DS_DL,rval);
324 */
325 
326 	rval = mmc_readl(host, REG_SD_NTSR);
327 	rval &= ~SDXC_SAM_TIMING_PH_MASK;
328 	rval |=
329 	    (mmc_clk_dly[cmod].
330 	     sam_ph << SDXC_SAM_TIMING_PH_SHIFT) & SDXC_SAM_TIMING_PH_MASK;
331 	mmc_writel(host, REG_SD_NTSR, rval);
332 
333 	SM_DBG(mmc_dev(host->mmc), " REG_DRV_DL    %08x\n",
334 		mmc_readl(host, REG_DRV_DL));
335 	SM_DBG(mmc_dev(host->mmc), " REG_SAMP_DL  %08x\n",
336 		mmc_readl(host, REG_SAMP_DL));
337 	SM_DBG(mmc_dev(host->mmc), " REG_DS_DL      %08x\n",
338 		mmc_readl(host, REG_DS_DL));
339 
340 }
341 
__sunxi_mmc_do_oclk_onoff(struct sunxi_mmc_host * host,u32 oclk_en,u32 pwr_save,u32 ignore_dat0)342 static int __sunxi_mmc_do_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en,
343 				     u32 pwr_save, u32 ignore_dat0)
344 {
345 	unsigned long expire = jiffies + msecs_to_jiffies(250);
346 	u32 rval;
347 
348 	rval = mmc_readl(host, REG_CLKCR);
349 	rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON | SDXC_MASK_DATA0);
350 
351 	if (oclk_en)
352 		rval |= SDXC_CARD_CLOCK_ON;
353 	if (pwr_save)
354 		rval |= SDXC_LOW_POWER_ON;
355 	if (ignore_dat0)
356 		rval |= SDXC_MASK_DATA0;
357 
358 	mmc_writel(host, REG_CLKCR, rval);
359 
360 	SM_DBG(mmc_dev(host->mmc), "%s REG_CLKCR:%x\n", __func__,
361 		mmc_readl(host, REG_CLKCR));
362 
363 	rval = SDXC_START | SDXC_UPCLK_ONLY | SDXC_WAIT_PRE_OVER;
364 	mmc_writel(host, REG_CMDR, rval);
365 
366 	do {
367 		rval = mmc_readl(host, REG_CMDR);
368 	} while (time_before(jiffies, expire) && (rval & SDXC_START));
369 
370 	/* clear irq status bits set by the command */
371 	/*? */
372 	mmc_writel(host, REG_RINTR,
373 			mmc_readl(host, REG_RINTR) & ~SDXC_SDIO_INTERRUPT);
374 
375 	if (rval & SDXC_START) {
376 		SM_ERR(mmc_dev(host->mmc), "fatal err update clk timeout\n");
377 		return -EIO;
378 	}
379 
380 	/*only use mask data0 when update clk,clear it when not update clk */
381 	if (ignore_dat0)
382 		mmc_writel(host, REG_CLKCR,
383 			   mmc_readl(host, REG_CLKCR) & ~SDXC_MASK_DATA0);
384 
385 	return 0;
386 }
387 
sunxi_mmc_oclk_onoff(struct sunxi_mmc_host * host,u32 oclk_en)388 static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
389 {
390 	struct device_node *np = NULL;
391 	struct mmc_host *mmc = host->mmc;
392 	int pwr_save = 0;
393 	int len = 0;
394 
395 	if (!mmc->parent || !mmc->parent->of_node) {
396 		SM_ERR(mmc_dev(host->mmc),
397 			"no dts to parse power save mode\n");
398 		return -EIO;
399 	}
400 
401 	np = mmc->parent->of_node;
402 	if (of_find_property(np, "sunxi-power-save-mode", &len))
403 		pwr_save = 1;
404 	return __sunxi_mmc_do_oclk_onoff(host, oclk_en, pwr_save, 1);
405 }
406 
sunxi_mmc_oclk_onoff_sdmmc0(struct sunxi_mmc_host * host,u32 oclk_en)407 int sunxi_mmc_oclk_onoff_sdmmc0(struct sunxi_mmc_host *host, u32 oclk_en)
408 {
409 	return sunxi_mmc_oclk_onoff(host, oclk_en);
410 }
411 
sunxi_mmc_2xmod_onoff(struct sunxi_mmc_host * host,u32 newmode_en)412 static void sunxi_mmc_2xmod_onoff(struct sunxi_mmc_host *host, u32 newmode_en)
413 {
414 	u32 rval = mmc_readl(host, REG_SD_NTSR);
415 
416 	if (newmode_en)
417 		rval |= SDXC_2X_TIMING_MODE;
418 	else
419 		rval &= ~SDXC_2X_TIMING_MODE;
420 
421 	mmc_writel(host, REG_SD_NTSR, rval);
422 
423 	SM_DBG(mmc_dev(host->mmc), "REG_SD_NTSR: 0x%08x ,val %x\n",
424 		mmc_readl(host, REG_SD_NTSR), rval);
425 }
426 
sunxi_mmc_clk_set_rate_for_sdmmc0(struct sunxi_mmc_host * host,struct mmc_ios * ios)427 int sunxi_mmc_clk_set_rate_for_sdmmc0(struct sunxi_mmc_host *host,
428 				      struct mmc_ios *ios)
429 {
430 	u32 mod_clk = 0;
431 	u32 src_clk = 0;
432 	u32 rval = 0;
433 	s32 err = 0;
434 	u32 rate = 0;
435 	char *sclk_name = NULL;
436 	struct clk *mclk = host->clk_mmc;
437 	struct clk *sclk = NULL;
438 	struct device *dev = mmc_dev(host->mmc);
439 	int div = 0;
440 
441 	if (ios->clock == 0) {
442 		__sunxi_mmc_do_oclk_onoff(host, 0, 0, 1);
443 		return 0;
444 	}
445 
446 	if (sunxi_mmc_ddr_timing(ios->timing)) {
447 		mod_clk = ios->clock << 2;
448 		div = 1;
449 	} else {
450 		mod_clk = ios->clock << 1;
451 		div = 0;
452 	}
453 
454 	if (ios->clock <= 400000) {
455 		sclk = clk_get(dev, "osc24m");
456 		sclk_name = "osc24m";
457 	} else {
458 		sclk = clk_get(dev, "pll_periph");
459 		sclk_name = "pll_periph";
460 	}
461 	if (IS_ERR(sclk)) {
462 		SM_ERR(mmc_dev(host->mmc), "Error to get source clock %s\n",
463 			sclk_name);
464 		return -1;
465 	}
466 
467 	sunxi_mmc_oclk_onoff(host, 0);
468 
469 	err = clk_set_parent(mclk, sclk);
470 	if (err) {
471 		SM_ERR(mmc_dev(host->mmc), "set parent failed\n");
472 		clk_put(sclk);
473 		return -1;
474 	}
475 
476 	rate = clk_round_rate(mclk, mod_clk);
477 
478 	SM_DBG(mmc_dev(host->mmc), "get round rate %d\n", rate);
479 
480 	clk_disable_unprepare(host->clk_mmc);
481 
482 	err = clk_set_rate(mclk, rate);
483 	if (err) {
484 		SM_ERR(mmc_dev(host->mmc), "set mclk rate error, rate %dHz\n",
485 			rate);
486 		clk_put(sclk);
487 		return -1;
488 	}
489 
490 	rval = clk_prepare_enable(host->clk_mmc);
491 	if (rval) {
492 		SM_ERR(mmc_dev(host->mmc), "Enable mmc clk err %d\n", rval);
493 		return -1;
494 	}
495 
496 	src_clk = clk_get_rate(sclk);
497 	clk_put(sclk);
498 
499 	SM_DBG(mmc_dev(host->mmc), "set round clock %d, soure clk is %d\n",
500 		rate, src_clk);
501 
502 #ifdef MMC_FPGA
503 	if (sunxi_mmc_ddr_timing(ios->timing)) {
504 		/* clear internal divider */
505 		rval = mmc_readl(host, REG_CLKCR);
506 		rval &= ~0xff;
507 		rval |= 1;
508 	} else {
509 		/* support internal divide clock under fpga environment  */
510 		rval = mmc_readl(host, REG_CLKCR);
511 		rval &= ~0xff;
512 		rval |= 24000000 / mod_clk / 2;	/* =24M/400K/2=0x1E */
513 	}
514 	mmc_writel(host, REG_CLKCR, rval);
515 	SM_INFO(mmc_dev(host->mmc), "--FPGA REG_CLKCR: 0x%08x\n",
516 		mmc_readl(host, REG_CLKCR));
517 #else
518 	/* clear internal divider */
519 	rval = mmc_readl(host, REG_CLKCR);
520 	rval &= ~0xff;
521 	rval |= div;
522 	mmc_writel(host, REG_CLKCR, rval);
523 #endif
524 
525 	/*sunxi_of_parse_clk_dly(host); */
526 	sunxi_mmc_2xmod_onoff(host, 1);
527 
528 	if (sunxi_mmc_ddr_timing(ios->timing))
529 		ios->clock = rate >> 2;
530 	else
531 		ios->clock = rate >> 1;
532 
533 
534 	sunxi_mmc_set_clk_dly(host, ios->clock, ios->bus_width, ios->timing);
535 
536 	return sunxi_mmc_oclk_onoff(host, 1);
537 }
538 
sunxi_mmc_thld_ctl_for_sdmmc0(struct sunxi_mmc_host * host,struct mmc_ios * ios,struct mmc_data * data)539 void sunxi_mmc_thld_ctl_for_sdmmc0(struct sunxi_mmc_host *host,
540 				   struct mmc_ios *ios, struct mmc_data *data)
541 {
542 	u32 bsz = data->blksz;
543 	/*unit:byte */
544 	/*u32 tdtl = (host->dma_tl & SDXC_TX_TL_MASK)<<2; */
545 	/*unit:byte*/
546 	u32 rdtl = ((host->dma_tl & SDXC_RX_TL_MASK) >> 16) << 2;
547 	u32 rval = 0;
548 
549 	if ((data->flags & MMC_DATA_READ)
550 	    && (bsz <= SDXC_CARD_RD_THLD_SIZE)
551 	    /*((SDXC_FIFO_DETH<<2)-bsz) >= (rdtl) */
552 	    && ((SDXC_FIFO_DETH << 2) >= (rdtl + bsz))
553 	    && (ios->timing == MMC_TIMING_MMC_HS200)) {
554 		rval = mmc_readl(host, REG_THLD);
555 		rval &= ~SDXC_CARD_RD_THLD_MASK;
556 		rval |= data->blksz << SDXC_CARD_RD_THLD_SIZE_SHIFT;
557 		rval |= SDXC_CARD_RD_THLD_ENB;
558 		mmc_writel(host, REG_THLD, rval);
559 	} else {
560 		rval = mmc_readl(host, REG_THLD);
561 		rval &= ~SDXC_CARD_RD_THLD_ENB;
562 		mmc_writel(host, REG_THLD, rval);
563 	}
564 
565 	SM_DBG(mmc_dev(host->mmc), "--SDXC_REG_THLD: 0x%08x\n",
566 		mmc_readl(host, REG_THLD));
567 
568 }
569 
sunxi_mmc_save_spec_reg0(struct sunxi_mmc_host * host)570 void sunxi_mmc_save_spec_reg0(struct sunxi_mmc_host *host)
571 {
572 	bak_spec_regs.drv_dl = mmc_readl(host, REG_DRV_DL);
573 	bak_spec_regs.samp_dl = mmc_readl(host, REG_SAMP_DL);
574 	bak_spec_regs.ds_dl = mmc_readl(host, REG_DS_DL);
575 	bak_spec_regs.sd_ntsr = mmc_readl(host, REG_SD_NTSR);
576 }
577 
sunxi_mmc_restore_spec_reg0(struct sunxi_mmc_host * host)578 void sunxi_mmc_restore_spec_reg0(struct sunxi_mmc_host *host)
579 {
580 	sunxi_r_op(host, mmc_writel(host, REG_DRV_DL, bak_spec_regs.drv_dl));
581 	mmc_writel(host, REG_SAMP_DL, bak_spec_regs.samp_dl);
582 	mmc_writel(host, REG_DS_DL, bak_spec_regs.ds_dl);
583 	mmc_writel(host, REG_SD_NTSR, bak_spec_regs.sd_ntsr);
584 }
585 
586 #endif
587