2 * Rockchip Specific Extensions for Synopsys DW Multimedia Card Interface driver
4 * Copyright (C) 2014, Rockchip Electronics Co., Ltd.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/clk.h>
15 #include <linux/mmc/host.h>
16 #include <linux/mmc/mmc.h>
17 #include <linux/mmc/rk_mmc.h>
19 #include <linux/of_gpio.h>
20 #include <linux/slab.h>
21 #include <linux/rockchip/cpu.h>
22 #include <linux/rockchip/cru.h>
23 #include <linux/delay.h>
24 #include <linux/mfd/syscon.h>
25 #include <linux/regmap.h>
27 #include "dw_mmc-pltfm.h"
28 #include "../../clk/rockchip/clk-ops.h"
30 #include "rk_sdmmc_dbg.h"
34 * sdmmc,sdio0,sdio1,emmc id=0~3
35 * cclk_in_drv, cclk_in_sample i=0,1
38 static u32 cru_tuning_base = 0;
40 #define CRU_SDMMC_CON(id, tuning_type) (cru_tuning_base + ((id) * 8) + ((tuning_type) * 4))
42 #define MAX_DELAY_LINE (0xff)
43 #define FREQ_REF_150MHZ (150000000)
44 #define PRECISE_ADJUST (0)
46 #define SDMMC_TUNING_SEL(tuning_type) ( tuning_type? 10:11 )
47 #define SDMMC_TUNING_DELAYNUM(tuning_type) ( tuning_type? 2:3 )
48 #define SDMMC_TUNING_DEGREE(tuning_type) ( tuning_type? 0:1 )
49 #define SDMMC_TUNING_INIT_STATE (0)
52 SDMMC_SHIFT_DEGREE_0 = 0,
53 SDMMC_SHIFT_DEGREE_90,
54 SDMMC_SHIFT_DEGREE_180,
55 SDMMC_SHIFT_DEGREE_270,
56 SDMMC_SHIFT_DEGREE_INVALID,
59 const char *phase_desc[SDMMC_SHIFT_DEGREE_INVALID + 1] = {
60 "SDMMC_SHIFT_DEGREE_0",
61 "SDMMC_SHIFT_DEGREE_90",
62 "SDMMC_SHIFT_DEGREE_180",
63 "SDMMC_SHIFT_DEGREE_270",
64 "SDMMC_SHIFT_DEGREE_INVALID",
68 USE_CLK_AFTER_PHASE = 0,
69 USE_CLK_AFTER_PHASE_AND_DELAY_LINE = 1,
85 /* Rockchip implementation specific driver private data */
86 struct dw_mci_rockchip_priv_data {
87 enum dw_mci_rockchip_type ctrl_type;
94 static struct dw_mci_rockchip_compatible {
96 enum dw_mci_rockchip_type ctrl_type;
97 } rockchip_compat[] = {
99 .compatible = "rockchip,rk31xx-sdmmc",
100 .ctrl_type = DW_MCI_TYPE_RK3188,
102 .compatible = "rockchip,rk32xx-sdmmc",
103 .ctrl_type = DW_MCI_TYPE_RK3288,
105 .compatible = "rockchip,rk3036-sdmmc",
106 .ctrl_type = DW_MCI_TYPE_RK3036,
108 .compatible = "rockchip,rk312x-sdmmc",
109 .ctrl_type = DW_MCI_TYPE_RK312X,
111 .compatible = "rockchip,rk3368-sdmmc",
112 .ctrl_type = DW_MCI_TYPE_RK3368,
116 static int dw_mci_rockchip_priv_init(struct dw_mci *host)
118 struct dw_mci_rockchip_priv_data *priv;
121 priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
123 dev_err(host->dev, "mem alloc failed for private data\n");
127 for(idx = 0; idx < ARRAY_SIZE(rockchip_compat); idx++){
128 if(of_device_is_compatible(host->dev->of_node,
129 rockchip_compat[idx].compatible)) {
130 priv->ctrl_type = rockchip_compat[idx].ctrl_type;
131 host->cid = priv->ctrl_type;
132 host->grf = syscon_regmap_lookup_by_phandle(host->dev->of_node,
141 static int dw_mci_rockchip_setup_clock(struct dw_mci *host)
143 struct dw_mci_rockchip_priv_data *priv = host->priv;
145 if ((priv->ctrl_type == DW_MCI_TYPE_RK3288) ||
146 (priv->ctrl_type == DW_MCI_TYPE_RK3036) ||
147 (priv->ctrl_type == DW_MCI_TYPE_RK312X) ||
148 (priv->ctrl_type == DW_MCI_TYPE_RK3368))
149 host->bus_hz /= (priv->ciu_div + 1);
154 static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
159 static void dw_mci_rockchip_set_ios(struct dw_mci *host, struct mmc_ios *ios)
164 static int dw_mci_rockchip_parse_dt(struct dw_mci *host)
168 static inline u8 dw_mci_rockchip_get_delaynum(struct dw_mci *host, u8 con_id, u8 tuning_type)
173 regs = cru_readl(CRU_SDMMC_CON(con_id, tuning_type));
174 delaynum = ((regs>>SDMMC_TUNING_DELAYNUM(tuning_type)) & 0xff);
179 static inline void dw_mci_rockchip_set_delaynum(struct dw_mci *host, u8 con_id, u8 tuning_type, u8 delaynum)
182 regs = cru_readl(CRU_SDMMC_CON(con_id, tuning_type));
183 regs &= ~( 0xff << SDMMC_TUNING_DELAYNUM(tuning_type));
184 regs |= (delaynum << SDMMC_TUNING_DELAYNUM(tuning_type));
185 regs |= (0xff << (SDMMC_TUNING_DELAYNUM(tuning_type)+16));
187 MMC_DBG_INFO_FUNC(host->mmc,"tuning_result[delayline]: con_id = %d, tuning_type = %d, CRU_CON = 0x%x. [%s]",
188 con_id, tuning_type, regs, mmc_hostname(host->mmc));
190 cru_writel(regs, CRU_SDMMC_CON(con_id, tuning_type));
192 MMC_DBG_INFO_FUNC(host->mmc,"CRU_SDMMC_CON(con_id, tuning_type) = 0x%x, regs = 0x%x [%s]",
193 CRU_SDMMC_CON(con_id, tuning_type), cru_readl(CRU_SDMMC_CON(con_id, tuning_type)), mmc_hostname(host->mmc));
196 static inline void dw_mci_rockchip_set_degree(struct dw_mci *host, u8 con_id, u8 tuning_type, u8 phase)
200 regs = cru_readl(CRU_SDMMC_CON(con_id, tuning_type));
201 regs &= ~( 0x3 << SDMMC_TUNING_DEGREE(tuning_type));
202 regs |= (phase << SDMMC_TUNING_DEGREE(tuning_type));
203 regs |= (0x3 << (SDMMC_TUNING_DEGREE(tuning_type)+16));
205 MMC_DBG_INFO_FUNC(host->mmc,"tuning_result[phase]: con_id = %d, tuning_type= %d, CRU_CON = 0x%x. [%s]",
206 con_id, tuning_type, regs, mmc_hostname(host->mmc));
208 cru_writel(regs, CRU_SDMMC_CON(con_id, tuning_type));
209 MMC_DBG_INFO_FUNC(host->mmc,"CRU_SDMMC_CON(con_id, tuning_type) = 0x%x, regs = 0x%x [%s]",
210 CRU_SDMMC_CON(con_id, tuning_type), cru_readl(CRU_SDMMC_CON(con_id, tuning_type)), mmc_hostname(host->mmc));
213 static inline void dw_mci_rockchip_turning_sel(struct dw_mci *host, u8 con_id, u8 tuning_type, u8 mode)
216 regs = cru_readl(CRU_SDMMC_CON(con_id, tuning_type)) ;
217 regs &= ~( 0x1 << SDMMC_TUNING_SEL(tuning_type));
218 regs |= (mode << SDMMC_TUNING_SEL(tuning_type));
219 regs |= (0x1 << (SDMMC_TUNING_SEL(tuning_type)+16));
221 MMC_DBG_INFO_FUNC(host->mmc,"tuning_sel: con_id = %d, tuning_type = %d, CRU_CON = 0x%x. [%s]",
222 con_id, tuning_type, regs, mmc_hostname(host->mmc));
224 cru_writel(regs, CRU_SDMMC_CON(con_id, tuning_type));
228 static inline u8 dw_mci_rockchip_get_phase(struct dw_mci *host, u8 con_id, u8 tuning_type)
233 static inline u8 dw_mci_rockchip_move_next_clksmpl(struct dw_mci *host, u8 con_id, u8 tuning_type, u8 val)
237 regs = cru_readl(CRU_SDMMC_CON(con_id, tuning_type)) ;
240 val = ((regs>>SDMMC_TUNING_DELAYNUM(tuning_type)) & 0xff);
246 static void dw_mci_rockchip_load_signal_integrity(struct dw_mci *host, u32 sr, u32 drv)
248 if (unlikely((drv > IO_DRV_12MA) || (sr > SLEW_RATE_FAST))) {
249 MMC_DBG_ERR_FUNC(host->mmc,"wrong signal integrity setting: drv = %d, sr = %d ![%s]",
250 drv, sr, mmc_hostname(host->mmc));
255 /*Note 00: 2ma 01:4ma 10:8ma 11:12ma
256 For consider line loading and IP's slew rate,
257 we should match these by every board depends for signal integrity.
258 slew rate >= 2*pi*f*Vpeak = max(|d'(Vpeak)/dt|)
260 if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) {
261 grf_writel(0xff005500 | (drv << 14) | (drv << 12) |
262 (drv << 10) | (drv << 8), 0x01f8); /* GPIO4C4-C7 */
263 grf_writel(0x000f0000 | (drv << 0) | (drv << 2), 0x01fc); /* GPIO4D0-D1 */
264 grf_writel(0x03f00000 | (sr << 4) | (sr << 5) | (sr << 6) |
265 (sr << 7) | (sr << 8) | (sr << 9) , 0x011c); /* slew rate*/
266 }else if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) {
267 grf_writel(0x3fff0000 | (drv << 0) | (drv << 2) | (drv << 4) |
268 (drv << 6) | (drv << 8) | (drv << 10) |
269 (drv << 12), 0x0218); /* GPIO6C0-C6 */
270 grf_writel(0x003f0000 | (sr << 0) | (sr << 1) | (sr << 2) |
271 (sr << 3) | (sr << 4) | (sr << 5), 0x012c); /* slew rate */
272 }else if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) {
273 /* emmc hardware relative addr match requirement, assume 4ma not slow slew rate */
274 grf_writel(0xffff5555, 0x01e0); /* GPIO3A0-A7 */
275 grf_writel(0x000c0006, 0x01e4); /* GPIO3B1 */
276 grf_writel(0x003f0015, 0x01e8); /* GPIO3C2-C0 */
278 } else if (host->cid == DW_MCI_TYPE_RK3368) {
279 if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) {
280 regmap_write(host->grf, 0x21c, 0xff000000 | (drv << 14) | (drv << 12) |
281 (drv << 10) | (drv << 8)); /* GPIO2D4-D7 */
282 regmap_write(host->grf, 0x220, 0x000f0000 | (drv << 0) | (drv << 2)); /* GPIO3A0-A1 */
283 }else if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) {
284 regmap_write(host->grf, 0x210, 0xfc000000 | (drv << 10) | (drv << 12) | (drv << 14)); /* GPIO2A5-A7 */
285 regmap_write(host->grf, 0x214, 0x003f0000 | (drv << 0) | (drv << 2) | (drv << 4)); /* GPIO2B0-2 */
286 }else if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) {
287 regmap_write(host->grf, 0x208, 0xfff00000 | (drv << 4) | (drv << 6) | (drv << 8) | (drv << 10)
288 | (drv << 12) | (drv << 14)); /* GPIO1C2-C7 */
289 regmap_write(host->grf, 0x20c, 0x003f0000 | (drv << 0) | (drv << 2) | (drv << 4)); /* GPIO1D0-D2 */
290 regmap_write(host->grf, 0x210, 0x03000000 | (drv << 8)); /* GPIO2A4 */
295 static void dw_mci_rockchip_load_tuning_base(struct dw_mci *host)
297 /* load tuning base */
298 if (cpu_is_rk3288()) {
299 cru_tuning_base = RK3288_CRU_SDMMC_CON0;
300 } else if (host->cid == DW_MCI_TYPE_RK3368) {
301 if (IS_ERR(host->grf))
302 pr_err("rk_sdmmc: dts couldn't find grf regmap\n");
304 cru_tuning_base = 0x400;
308 static int inline __dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
309 u8 *blk_test, unsigned int blksz)
311 struct dw_mci *host = slot->host;
312 struct mmc_host *mmc = slot->mmc;
313 struct mmc_request mrq = {NULL};
314 struct mmc_command cmd = {0};
315 struct mmc_command stop = {0};
316 struct mmc_data data = {0};
317 struct scatterlist sg;
321 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
322 stop.opcode = MMC_STOP_TRANSMISSION;
324 stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
327 data.flags = MMC_DATA_READ;
331 sg_init_one(&sg, blk_test, blksz);
336 mci_writel(host, TMOUT, ~0);
338 mmc_wait_for_req(mmc, &mrq);
339 if(!cmd.error && !data.error){
343 "Tuning error: cmd.error:%d, data.error:%d\n",cmd.error, data.error);
350 static int dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
351 struct dw_mci_tuning_data *tuning_data)
354 struct dw_mci *host = slot->host;
356 u8 candidates_delayline[MAX_DELAY_LINE] = {0};
357 u8 candidates_degree[SDMMC_SHIFT_DEGREE_INVALID] = {4,4,4,4};
361 u32 start_delayline = 0;
362 const u8 *blk_pattern = tuning_data->blk_pattern;
366 unsigned int blksz = tuning_data->blksz;
368 MMC_DBG_INFO_FUNC(host->mmc,"execute tuning: [%s]", mmc_hostname(host->mmc));
370 dw_mci_rockchip_load_tuning_base(host);
372 blk_test = kmalloc(blksz, GFP_KERNEL);
375 MMC_DBG_ERR_FUNC(host->mmc,"execute tuning: blk_test kmalloc failed[%s]",
376 mmc_hostname(host->mmc));
380 /* Select use delay line*/
381 dw_mci_rockchip_turning_sel(host, tuning_data->con_id, tuning_data->tuning_type,
382 USE_CLK_AFTER_PHASE_AND_DELAY_LINE);
384 /* For RK32XX signoff 150M clk, 1 cycle = 6.66ns , and 1/4 phase = 1.66ns.
385 Netlist level sample LT: 10.531ns / 42.126ps WC: 19.695ns / 76.936ps.
386 So we take average --- 60ps, (1.66ns/ 2) = 0.83(middle-value),TAKE 0.9
387 0.9 / 60ps = 15 delayline
389 if (cpu_is_rk3288() && !(rockchip_get_cpu_version() > 0)) {
390 /* RK3288, non-eco */
391 ref = DIV_ROUND_UP(FREQ_REF_150MHZ, host->bus_hz);
394 if (step > MAX_DELAY_LINE) {
395 step = MAX_DELAY_LINE;
396 MMC_DBG_WARN_FUNC(host->mmc,
397 "execute tuning: TOO LARGE STEP![%s]", mmc_hostname(host->mmc));
399 MMC_DBG_INFO_FUNC(host->mmc,
400 "execute tuning: SOC is RK3288, ref = %d, step = %d[%s]",
401 ref, step, mmc_hostname(host->mmc));
404 step = (15 * ((FREQ_REF_150MHZ / host->bus_hz) * 100)) / 100;
406 if (step > MAX_DELAY_LINE) {
407 step = MAX_DELAY_LINE;
408 MMC_DBG_WARN_FUNC(host->mmc,
409 "execute tuning: TOO LARGE STEP![%s]", mmc_hostname(host->mmc));
411 MMC_DBG_INFO_FUNC(host->mmc,
412 "execute tuning: SOC id is %d, step = %d[%s]",
413 host->cid, step, mmc_hostname(host->mmc));
417 /* calcute slew rate & drv strength in timing tuning */
418 if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)
419 default_drv = IO_DRV_4MA;
421 default_drv = IO_DRV_8MA;
423 dw_mci_rockchip_load_signal_integrity(host, SLEW_RATE_SLOW, default_drv);
424 /* Loop degree from 0 ~ 270 */
425 for(start_degree = SDMMC_SHIFT_DEGREE_0; start_degree <= SDMMC_SHIFT_DEGREE_270; start_degree++){
426 dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, start_degree);
427 if(0 == __dw_mci_rockchip_execute_tuning(slot, opcode, blk_test, blksz)){
428 if(!memcmp(blk_pattern, blk_test, blksz)){
429 /* Successfully tuning in this condition*/
430 candidates_degree[index] = start_degree;
434 /* eMMC spec does not require a delay between tuning cycles
435 * but eMMC should be guaranteed to complete a sequence of 40 times CMD21
436 * withnin 150ms, some eMMC may limit 4ms gap between any two sequential CMD21
438 if (opcode == MMC_SEND_TUNING_BLOCK)
441 /* MMC_SEND_TUNING_BLOCK_HS200 */
445 MMC_DBG_BOOT_FUNC(host->mmc,"\n execute tuning: candidates_degree = %s \t%s \t%s \t%s[%s]",
446 phase_desc[candidates_degree[0]], phase_desc[candidates_degree[1]],
447 phase_desc[candidates_degree[2]], phase_desc[candidates_degree[3]],
448 mmc_hostname(host->mmc));
451 if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_0)
452 && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_90)
453 && (candidates_degree[2] == SDMMC_SHIFT_DEGREE_180)){
455 MMC_DBG_INFO_FUNC(host->mmc,
456 "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_90 [%s]",
457 mmc_hostname(host->mmc));
459 dw_mci_rockchip_set_degree(host, tuning_data->con_id,
460 tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_90);
463 }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_90)
464 && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_180)
465 && (candidates_degree[2] == SDMMC_SHIFT_DEGREE_270)){
466 MMC_DBG_INFO_FUNC(host->mmc,
467 "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_180 [%s]",
468 mmc_hostname(host->mmc));
469 dw_mci_rockchip_set_degree(host, tuning_data->con_id,
470 tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_180);
473 }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_0)
474 && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_90)
475 && (candidates_degree[2] == SDMMC_SHIFT_DEGREE_INVALID)){
477 MMC_DBG_INFO_FUNC(host->mmc,
478 "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_0 ~ SDMMC_SHIFT_DEGREE_90[%s]",
479 mmc_hostname(host->mmc));
481 dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_0);
485 dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step);
489 }else if((candidates_degree[0]==SDMMC_SHIFT_DEGREE_0)
490 && (candidates_degree[1]==SDMMC_SHIFT_DEGREE_180)
491 && (candidates_degree[2]==SDMMC_SHIFT_DEGREE_270)){
492 MMC_DBG_INFO_FUNC(host->mmc,
493 "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_0 AND SDMMC_SHIFT_DEGREE_180 AND SDMMC_SHIFT_DEGREE_270[%s]",
494 mmc_hostname(host->mmc));
495 dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_180);
496 dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step);
499 }else if((candidates_degree[0]==SDMMC_SHIFT_DEGREE_0)
500 && (candidates_degree[1]==SDMMC_SHIFT_DEGREE_180)){
502 MMC_DBG_INFO_FUNC(host->mmc,
503 "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_0 AND SDMMC_SHIFT_DEGREE_180[%s]",
504 mmc_hostname(host->mmc));
506 /* FixMe: NO sense any signal indicator make this case happen*/
507 dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_0);
509 }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_90)
510 && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_180)
511 && (candidates_degree[2] == SDMMC_SHIFT_DEGREE_INVALID)){
513 MMC_DBG_INFO_FUNC(host->mmc,
514 "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_90 ~ SDMMC_SHIFT_DEGREE_180[%s]",
515 mmc_hostname(host->mmc));
517 dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_90);
521 dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step);
525 }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_180)
526 && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_270)){
528 MMC_DBG_INFO_FUNC(host->mmc,
529 "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_180 ~ SDMMC_SHIFT_DEGREE_270[%s]",
530 mmc_hostname(host->mmc));
532 dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_180);
536 dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step);
540 }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_180)
541 && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_INVALID)){
543 MMC_DBG_INFO_FUNC(host->mmc,
544 "execute tuning: candidates_degree = [SDMMC_SHIFT_DEGREE_90 + n ~ SDMMC_SHIFT_DEGREE_180][%s]",
545 mmc_hostname(host->mmc));
547 dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_90);
553 //dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step);
557 }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_90)
558 && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_INVALID)){
560 MMC_DBG_INFO_FUNC(host->mmc,
561 "execute tuning: candidates_degree = [SDMMC_SHIFT_DEGREE_0 + n ~ SDMMC_SHIFT_DEGREE_90][%s]",
562 mmc_hostname(host->mmc));
564 dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_0);
570 //dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step);
574 }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_270)){
576 MMC_DBG_INFO_FUNC(host->mmc,
577 "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_270 [%s]",
578 mmc_hostname(host->mmc));
580 /*FixME: so urgly signal indicator, HW engineer help!*/
582 //dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_180);
588 //dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step);
593 MMC_DBG_ERR_FUNC(host->mmc,
594 "execute tuning: candidates_degree beyong limited case! [%s]",
595 mmc_hostname(host->mmc));
598 if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC)
605 for(start_delayline = 0; start_delayline <= MAX_DELAY_LINE; start_delayline += step){
607 dw_mci_rockchip_set_delaynum(host, tuning_data->con_id,
608 tuning_data->tuning_type, start_delayline);
609 if(0 == __dw_mci_rockchip_execute_tuning(slot, opcode, blk_test, blksz)){
610 if(!memcmp(blk_pattern, blk_test, blksz)){
611 /* Successfully tuning in this condition*/
612 candidates_delayline[index] = start_delayline;
617 if((index < 2) && (index != 0)) {
618 /* setup 400ps, consider line loading, at least 600ps wc.
619 for 150M, 15 steps =900ps ,too larger scale, should step smaller in principle
621 MMC_DBG_INFO_FUNC(host->mmc,
622 "execute tuning: candidates_delayline failed for no enough elements [%s]",
623 mmc_hostname(host->mmc));
625 /* Make step smaller, and re-calculate */
629 }else if(index >= 2){
631 MMC_DBG_INFO_FUNC(host->mmc,
632 "execute tuning: candidates_delayline calculate successfully [%s]",
633 mmc_hostname(host->mmc));
635 dw_mci_rockchip_set_delaynum(host, tuning_data->con_id,
636 tuning_data->tuning_type, candidates_delayline[index/2]);
648 /* Common capabilities of RK32XX SoC */
649 static unsigned long rockchip_dwmmc_caps[4] = {
656 unsigned int rockchip_dwmmc_hold_reg[4] = {1,0,0,0};
658 static const struct dw_mci_drv_data rockchip_drv_data = {
659 .caps = rockchip_dwmmc_caps,
660 .hold_reg_flag = rockchip_dwmmc_hold_reg,
661 .init = dw_mci_rockchip_priv_init,
662 .setup_clock = dw_mci_rockchip_setup_clock,
663 .prepare_command = dw_mci_rockchip_prepare_command,
664 .set_ios = dw_mci_rockchip_set_ios,
665 .parse_dt = dw_mci_rockchip_parse_dt,
666 .execute_tuning = dw_mci_rockchip_execute_tuning,
669 static const struct of_device_id dw_mci_rockchip_match[] = {
670 { .compatible = "rockchip,rk_mmc",
671 .data = &rockchip_drv_data, },
674 MODULE_DEVICE_TABLE(of, dw_mci_rockchip_match);
676 static int dw_mci_rockchip_probe(struct platform_device *pdev)
678 const struct dw_mci_drv_data *drv_data;
679 const struct of_device_id *match;
681 match = of_match_node(dw_mci_rockchip_match, pdev->dev.of_node);
682 drv_data = match->data;
683 return dw_mci_pltfm_register(pdev, drv_data);
686 static struct platform_driver dw_mci_rockchip_pltfm_driver = {
687 .probe = dw_mci_rockchip_probe,
688 .remove = __exit_p(dw_mci_pltfm_remove),
690 .name = "dwmmc_rockchip",
691 .of_match_table = dw_mci_rockchip_match,
692 .pm = &dw_mci_pltfm_pmops,
696 module_platform_driver(dw_mci_rockchip_pltfm_driver);
698 MODULE_DESCRIPTION("Rockchip Specific DW-SDMMC Driver Extension");
699 MODULE_AUTHOR("Shawn Lin <lintao@rock-chips.com>");
700 MODULE_AUTHOR("Bangwang Xie <xbw@rock-chips.com>");
701 MODULE_LICENSE("GPL v2");
702 MODULE_ALIAS("platform:dwmmc-rockchip");