diff --git a/arch/arm64/boot/dts/amlogic/axg_s400.dts b/arch/arm64/boot/dts/amlogic/axg_s400.dts index e3e4c6db663b..a6d84aefb130 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400.dts @@ -617,6 +617,7 @@ f_max = <200000000>; max_req_size = <0x20000>; /**128KB*/ gpio_dat3 = <&gpio BOOT_3 GPIO_ACTIVE_HIGH>; + tx_delay = <8>; hw_reset = <&gpio BOOT_9 GPIO_ACTIVE_HIGH>; pinmux_base = <0xff634400>; card_type = <1>; diff --git a/drivers/amlogic/mmc/aml_sd_emmc.c b/drivers/amlogic/mmc/aml_sd_emmc.c index 96aff5767c82..8df5bcf4e33c 100644 --- a/drivers/amlogic/mmc/aml_sd_emmc.c +++ b/drivers/amlogic/mmc/aml_sd_emmc.c @@ -577,7 +577,7 @@ _cali_retry: } #endif -static u32 aml_sd_emmc_tuning_transfer(struct mmc_host *mmc, +u32 aml_sd_emmc_tuning_transfer(struct mmc_host *mmc, u32 opcode, const u8 *blk_pattern, u8 *blk_test, u32 blksz) { struct amlsd_host *host = mmc_priv(mmc); diff --git a/drivers/amlogic/mmc/aml_sd_emmc_v3.c b/drivers/amlogic/mmc/aml_sd_emmc_v3.c index ad21c5e71b0b..21dffdb48f62 100644 --- a/drivers/amlogic/mmc/aml_sd_emmc_v3.c +++ b/drivers/amlogic/mmc/aml_sd_emmc_v3.c @@ -60,7 +60,7 @@ int meson_mmc_clk_init_v3(struct amlsd_host *host) vclkc = 0; pclkc->div = 60; /* 400KHz */ pclkc->src = 0; /* 0: Crystal 24MHz */ - pclkc->core_phase = 2; /* 2: 180 phase */ + pclkc->core_phase = 3; /* 2: 180 phase */ pclkc->rx_phase = 0; pclkc->tx_phase = 0; pclkc->always_on = 1; /* Keep clock always on */ @@ -143,10 +143,14 @@ static int meson_mmc_clk_set_rate_v3(struct amlsd_host *host, mmc->actual_clock = clk_rate / clk_div; #else - if (clk_ios == mmc->actual_clock) + if (clk_ios == mmc->actual_clock) { + pr_info("[%s] clk_ios: %lu, return .............. clock: 0x%x\n", + __func__, clk_ios, + readl(host->base + SD_EMMC_CLOCK_V3)); return 0; - pr_info("[%s] before clock: 0x%x\n", - __func__, readl(host->base + SD_EMMC_CLOCK_V3)); + } + pr_info("[%s] clk_ios: %lu,before clock: 0x%x\n", + __func__, clk_ios, readl(host->base + SD_EMMC_CLOCK_V3)); /* stop clock */ vcfg = readl(host->base + SD_EMMC_CFG); if (!conf->stop_clk) { @@ -167,10 +171,11 @@ static int meson_mmc_clk_set_rate_v3(struct amlsd_host *host, dev_dbg(host->dev, "change clock rate %u -> %lu\n", mmc->actual_clock, clk_ios); ret = clk_set_rate(host->cfg_div_clk, clk_ios); - if (clk_ios && clk_ios != clk_get_rate(host->cfg_div_clk)) + if (clk_ios && clk_ios != clk_get_rate(host->cfg_div_clk)) { dev_warn(host->dev, "divider requested rate %lu != actual rate %lu: ret=%d\n", clk_ios, clk_get_rate(host->cfg_div_clk), ret); - else + mmc->actual_clock = clk_get_rate(host->cfg_div_clk); + } else mmc->actual_clock = clk_ios; /* (re)start clock, if non-zero */ @@ -183,12 +188,12 @@ static int meson_mmc_clk_set_rate_v3(struct amlsd_host *host, source_base = ioremap_nocache(P_HHI_NAND_CLK_CNTL, sizeof(u32)); - /* pr_info("actual_clock :%u, HHI_nand: 0x%x\n", - * mmc->actual_clock, readl(source_base)); - */ - /* pr_info("[%s] after clock: 0x%x\n", - * __func__, readl(host->base + SD_EMMC_CLOCK_V3)); - */ + pr_info("actual_clock :%u, HHI_nand: 0x%x\n", + mmc->actual_clock, readl(source_base)); + + pr_info("[%s] after clock: 0x%x\n", + __func__, readl(host->base + SD_EMMC_CLOCK_V3)); + iounmap(source_base); return ret; } @@ -199,12 +204,11 @@ static void aml_sd_emmc_set_timing_v3(struct amlsd_host *host, struct amlsd_platform *pdata = host->pdata; u32 vctrl; struct sd_emmc_config *ctrl = (struct sd_emmc_config *)&vctrl; - u32 vclkc; + u32 vclkc = readl(host->base + SD_EMMC_CLOCK_V3); struct sd_emmc_clock_v3 *clkc = (struct sd_emmc_clock_v3 *)&vclkc; u32 adjust; struct sd_emmc_adjust_v3 *gadjust = (struct sd_emmc_adjust_v3 *)&adjust; u8 clk_div = 0; - u32 clk_rate = 1000000000; vctrl = readl(host->base + SD_EMMC_CFG); if ((timing == MMC_TIMING_MMC_HS400) || @@ -216,21 +220,26 @@ static void aml_sd_emmc_set_timing_v3(struct amlsd_host *host, adjust = readl(host->base + SD_EMMC_ADJUST_V3); gadjust->ds_enable = 1; writel(adjust, host->base + SD_EMMC_ADJUST_V3); - clk_rate = 400000000; - /*host->tuning_mode = AUTO_TUNING_MODE;*/ + clkc->tx_delay = pdata->tx_delay; } + pr_info("%s: try set sd/emmc to HS400 mode\n", + mmc_hostname(host->mmc)); } - vclkc = readl(host->base + SD_EMMC_CLOCK_V3); ctrl->ddr = 1; clk_div = clkc->div; if (clk_div & 0x01) clk_div++; clkc->div = clk_div / 2; + if (aml_card_type_mmc(pdata)) + clkc->core_phase = 2; writel(vclkc, host->base + SD_EMMC_CLOCK_V3); pdata->clkc = vclkc; - host->mmc->actual_clock = clk_rate / clk_div; pr_info("%s: try set sd/emmc to DDR mode\n", mmc_hostname(host->mmc)); + } else if (timing == MMC_TIMING_MMC_HS) { + clkc->core_phase = 3; + writel(vclkc, host->base + SD_EMMC_CLOCK_V3); + pdata->clkc = vclkc; } else ctrl->ddr = 0; @@ -258,6 +267,7 @@ static void aml_sd_emmc_set_power_v3(struct amlsd_host *host, writel(0, host->base + SD_EMMC_DELAY1_V3); writel(0, host->base + SD_EMMC_DELAY2_V3); writel(0, host->base + SD_EMMC_ADJUST_V3); + writel(0, host->base + SD_EMMC_INTF3); break; default: if (pdata->pwr_pre) @@ -294,42 +304,6 @@ void meson_mmc_set_ios_v3(struct mmc_host *mmc, aml_cs_dont_care(mmc); } -int aml_mmc_execute_tuning_v3(struct mmc_host *mmc, u32 opcode) -{ - struct amlsd_host *host = mmc_priv(mmc); - struct aml_tuning_data tuning_data; - int err = 0; - u32 intf3; - - if (opcode == MMC_SEND_TUNING_BLOCK_HS200) { - if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { - tuning_data.blk_pattern = tuning_blk_pattern_8bit; - tuning_data.blksz = sizeof(tuning_blk_pattern_8bit); - } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) { - tuning_data.blk_pattern = tuning_blk_pattern_4bit; - tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); - } else { - return -EINVAL; - } - } else if (opcode == MMC_SEND_TUNING_BLOCK) { - tuning_data.blk_pattern = tuning_blk_pattern_4bit; - tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); - } else { - sd_emmc_err("Undefined command(%d) for tuning\n", opcode); - return -EINVAL; - } - - intf3 = readl(host->base + SD_EMMC_INTF3); - intf3 |= (1 << 22); - writel(intf3, host->base + SD_EMMC_INTF3); - - pr_info("%s: gclock=0x%x, gdelay1=0x%x, gdelay2=0x%x,intf3=0x%x\n", - mmc_hostname(mmc), readl(host->base + SD_EMMC_CLOCK_V3), - readl(host->base + SD_EMMC_DELAY1_V3), - readl(host->base + SD_EMMC_DELAY2_V3), - readl(host->base + SD_EMMC_INTF3)); - return err; -} irqreturn_t meson_mmc_irq_thread_v3(int irq, void *dev_id) { @@ -512,8 +486,6 @@ static int aml_sd_emmc_cali_v3(struct mmc_host *mmc, return data.error | cmd.error; } -#define EMMC_TIMMING_DBG 1 - static int emmc_eyetest_log(struct mmc_host *mmc, u32 line_x) { struct amlsd_host *host = mmc_priv(mmc); @@ -521,22 +493,13 @@ static int emmc_eyetest_log(struct mmc_host *mmc, u32 line_x) u32 adjust = readl(host->base + SD_EMMC_ADJUST_V3); struct sd_emmc_adjust_v3 *gadjust = (struct sd_emmc_adjust_v3 *)&adjust; - /*u32 delay1 = sd_emmc_regs->reg.v3.gdelay1; - *struct sd_emmc_delay1 *gdelay1 = (struct sd_emmc_delay1 *)&delay1; - *u32 delay2 = sd_emmc_regs->reg.v3.gdelay2; - *struct sd_emmc_delay2 *gdelay2 = (struct sd_emmc_delay2 *)&delay2; - *u32 clktest_log = 0; - *struct clktest_log gclktest_log = - * (struct clktest_log *)&(clktest_log); - *u32 clktest_out = 0; - */ u32 eyetest_log = 0; struct eyetest_log *geyetest_log = (struct eyetest_log *)&(eyetest_log); u32 eyetest_out0 = 0, eyetest_out1 = 0; u32 intf3 = readl(host->base + SD_EMMC_INTF3); struct intf3 *gintf3 = (struct intf3 *)&(intf3); u32 vcfg = readl(host->base + SD_EMMC_CFG); - int j = 0; + int retry = 3; u64 tmp = 0; u32 blksz = 512; u8 *blk_test; @@ -544,14 +507,9 @@ static int emmc_eyetest_log(struct mmc_host *mmc, u32 line_x) if (!blk_test) return -ENOMEM; host->is_tunning = 1; - emmc_dbg(EMMC_TIMMING_DBG, - "line_x: %d\n", line_x); - /*sd_emmc_regs->reg.v3.gdelay1 = delay1; - *sd_emmc_regs->reg.v3.gdelay2 = delay2; - */ - emmc_dbg(EMMC_TIMMING_DBG, "delay1: 0x%x , delay2: 0x%x\n", + emmc_dbg(AMLSD_DBG_V3, "delay1: 0x%x , delay2: 0x%x, line_x: %d\n", readl(host->base + SD_EMMC_DELAY1_V3), - readl(host->base + SD_EMMC_DELAY2_V3)); + readl(host->base + SD_EMMC_DELAY2_V3), line_x); gadjust->cali_enable = 1; gadjust->cali_sel = line_x; writel(adjust, host->base + SD_EMMC_ADJUST_V3); @@ -559,13 +517,13 @@ static int emmc_eyetest_log(struct mmc_host *mmc, u32 line_x) gintf3->eyetest_exp = 7; else gintf3->eyetest_exp = 3; +RETRY: + gintf3->eyetest_on = 1; writel(intf3, host->base + SD_EMMC_INTF3); - emmc_dbg(EMMC_TIMMING_DBG, "intf3: 0x%x,adjust: 0x%x\n", - readl(host->base + SD_EMMC_INTF3), - readl(host->base + SD_EMMC_ADJUST_V3)); /*****test start*************/ + udelay(5); if (line_x < 9) aml_sd_emmc_cali_v3(mmc, MMC_READ_MULTIPLE_BLOCK, @@ -574,30 +532,27 @@ static int emmc_eyetest_log(struct mmc_host *mmc, u32 line_x) aml_sd_emmc_cali_v3(mmc, MMC_READ_MULTIPLE_BLOCK, blk_test, blksz, 80); - + udelay(1); eyetest_log = readl(host->base + SD_EMMC_EYETEST_LOG); eyetest_out0 = readl(host->base + SD_EMMC_EYETEST_OUT0); eyetest_out1 = readl(host->base + SD_EMMC_EYETEST_OUT1); - while ((!(geyetest_log->eyetest_done & 0x1))) { - eyetest_out0 = readl(host->base + SD_EMMC_EYETEST_OUT0); - eyetest_out1 = readl(host->base + SD_EMMC_EYETEST_OUT1); - eyetest_log = readl(host->base + SD_EMMC_EYETEST_LOG); - emmc_dbg(EMMC_TIMMING_DBG, "testing eyetest times: 0x%x, out: 0x%x, 0x%x\n", + if (!(geyetest_log->eyetest_done & 0x1)) { + pr_warn("testing eyetest times: 0x%x, out: 0x%x, 0x%x\n", readl(host->base + SD_EMMC_EYETEST_LOG), eyetest_out0, eyetest_out1); - if (j == 10) - break; - j++; + gintf3->eyetest_on = 0; + writel(intf3, host->base + SD_EMMC_INTF3); + retry--; + if (retry == 0) { + pr_warn("[%s][%d] retry eyetest failed\n", + __func__, __LINE__); + return 1; + } + goto RETRY; } - emmc_dbg(EMMC_TIMMING_DBG, "test done! eyetest times: 0x%x, out: 0x%x, 0x%x\n", - readl(host->base + SD_EMMC_EYETEST_LOG), - eyetest_out0, eyetest_out1); gintf3->eyetest_on = 0; writel(intf3, host->base + SD_EMMC_INTF3); - emmc_dbg(EMMC_TIMMING_DBG, "intf3: 0x%x,adjust: 0x%x\n", - readl(host->base + SD_EMMC_INTF3), - readl(host->base + SD_EMMC_ADJUST_V3)); if (vcfg & 0x4) { if (pdata->count > 32) { eyetest_out1 <<= (32 - (pdata->count - 32)); @@ -606,7 +561,7 @@ static int emmc_eyetest_log(struct mmc_host *mmc, u32 line_x) eyetest_out1 = 0x0; } pdata->align[line_x] = ((tmp | eyetest_out1) << 32) | eyetest_out0; - emmc_dbg(EMMC_TIMMING_DBG, "u64 eyetestout 0x%llx\n", + emmc_dbg(AMLSD_DBG_V3, "u64 eyetestout 0x%llx\n", pdata->align[line_x]); host->is_tunning = 0; kfree(blk_test); @@ -636,8 +591,8 @@ static int emmc_detect_base_line(u64 *arr) max = first[i]; } } - pr_warn("%s [%d] detect line:%d, max: %u\n", - __func__, __LINE__, l_max, max); + emmc_dbg(AMLSD_DBG_V3, "%s detect line:%d, max: %u\n", + __func__, l_max, max); return max; } @@ -659,20 +614,20 @@ static int emmc_all_data_line_alignment(struct mmc_host *mmc) if (temp <= 4) continue; result = base_line - temp; - emmc_dbg(EMMC_TIMMING_DBG, "line_x: %d, result: %d\n", + emmc_dbg(AMLSD_DBG_V3, "line_x: %d, result: %d\n", line_x, result); if (line_x < 5) delay1 |= result << (6 * line_x); else delay2 |= result << (6 * (line_x - 5)); } - delay1 |= readl(host->base + SD_EMMC_DELAY1_V3); - delay2 |= readl(host->base + SD_EMMC_DELAY2_V3); + emmc_dbg(AMLSD_DBG_V3, "delay1: 0x%x, delay2: 0x%x\n", + delay1, delay2); + delay1 += readl(host->base + SD_EMMC_DELAY1_V3); + delay2 += readl(host->base + SD_EMMC_DELAY2_V3); writel(delay1, host->base + SD_EMMC_DELAY1_V3); writel(delay2, host->base + SD_EMMC_DELAY2_V3); - emmc_dbg(EMMC_TIMMING_DBG, "delay1: 0x%x, delay2: 0x%x\n", - delay1, delay2); - emmc_dbg(EMMC_TIMMING_DBG, "gdelay1: 0x%x, gdelay2: 0x%x\n", + emmc_dbg(AMLSD_DBG_V3, "gdelay1: 0x%x, gdelay2: 0x%x\n", readl(host->base + SD_EMMC_DELAY1_V3), readl(host->base + SD_EMMC_DELAY2_V3)); @@ -685,31 +640,37 @@ static int emmc_ds_data_alignment(struct mmc_host *mmc) struct amlsd_platform *pdata = host->pdata; u32 delay1 = readl(host->base + SD_EMMC_DELAY1_V3); u32 delay2 = readl(host->base + SD_EMMC_DELAY2_V3); - int i; + int i, line_x, temp = 0; - for (i = 0; i < 64; i++) { - pr_info("i = %d, delay1: 0x%x, delay2: 0x%x\n", + for (line_x = 0; line_x < 8; line_x++) { + temp = fbinary(pdata->align[line_x]); + if (temp <= 4) + continue; + for (i = 0; i < 64; i++) { + emmc_dbg(AMLSD_DBG_V3, "i = %d, delay1: 0x%x, delay2: 0x%x\n", i, readl(host->base + SD_EMMC_DELAY1_V3), readl(host->base + SD_EMMC_DELAY2_V3)); - delay1 += (1<<0)|(1<<6)|(1<<12)|(1<<18)|(1<<24); - delay2 += (1<<0)|(1<<6)|(1<<12)|(1<<24); - writel(delay1, host->base + SD_EMMC_DELAY1_V3); - writel(delay2, host->base + SD_EMMC_DELAY2_V3); - emmc_eyetest_log(mmc, 3); - emmc_eyetest_log(mmc, 8); - if (pdata->align[3] & 0xf) - break; - } - if (i == 64) { - pr_warn("%s [%d] Don't find line delay which aligned with DS\n", + if (line_x < 5) + delay1 += 1 << (6 * line_x); + else + delay2 += 1 << (6 * (line_x - 5)); + writel(delay1, host->base + SD_EMMC_DELAY1_V3); + writel(delay2, host->base + SD_EMMC_DELAY2_V3); + emmc_eyetest_log(mmc, line_x); + if (pdata->align[line_x] & 0xf) + break; + } + if (i == 64) { + pr_warn("%s [%d] Don't find line delay which aligned with DS\n", __func__, __LINE__); - return 1; + return 1; + } } return 0; } -static void print_all_line_eyetest(struct mmc_host *mmc) +static void update_all_line_eyetest(struct mmc_host *mmc) { int line_x; @@ -725,13 +686,13 @@ static int emmc_ds_core_align(struct mmc_host *mmc) u32 delay2 = readl(host->base + SD_EMMC_DELAY2_V3); u32 delay2_bak = delay2; u32 count = 0; - u32 ds_count = 0; + u32 ds_count = 0, cmd_count = 0; - if (pdata->align[8] & 0xf) - return 0; ds_count = fbinary(pdata->align[8]); - //BUG_ON(ds_count >= 4 && ds_count <= 8); - emmc_dbg(EMMC_TIMMING_DBG, "ds_count:%d,delay1:0x%x,delay2:0x%x\n", + if (ds_count == 0) + if ((pdata->align[8] & 0xf0) == 0) + return 0; + emmc_dbg(AMLSD_DBG_V3, "ds_count:%d,delay1:0x%x,delay2:0x%x\n", ds_count, readl(host->base + SD_EMMC_DELAY1_V3), readl(host->base + SD_EMMC_DELAY2_V3)); if (ds_count < 20) { @@ -753,10 +714,14 @@ static int emmc_ds_core_align(struct mmc_host *mmc) count = ((delay2>>18) & 0x3f) - ((delay2_bak>>18) & 0x3f); pdata->ds_core = count; delay1 += (count<<0)|(count<<6)|(count<<12)|(count<<18)|(count<<24); - delay2 += (count<<0)|(count<<6)|(count<<12)|(count<<24); + delay2 += (count<<0)|(count<<6)|(count<<12); + cmd_count = fbinary(pdata->align[9]); + if (cmd_count < (pdata->count / 2)) + cmd_count = (pdata->count / 2) - cmd_count; + delay2 += (cmd_count<<24); writel(delay1, host->base + SD_EMMC_DELAY1_V3); writel(delay2, host->base + SD_EMMC_DELAY2_V3); - emmc_dbg(EMMC_TIMMING_DBG, + emmc_dbg(AMLSD_DBG_V3, "ds_count:%d,delay1:0x%x,delay2:0x%x,count: %u\n", ds_count, readl(host->base + SD_EMMC_DELAY1_V3), readl(host->base + SD_EMMC_DELAY2_V3), count); @@ -773,40 +738,73 @@ static int emmc_ds_manual_sht(struct mmc_host *mmc) u8 *blk_test = NULL; u32 blksz = 512; int i, err = 0; - u32 sta = 0, end = 0, flag = 0; + int match[32]; + int best_start = -1, best_size = -1; + int cur_start = -1, cur_size = 0; + sd_emmc_debug = 0x2000; blk_test = kmalloc(blksz * CALI_BLK_CNT, GFP_KERNEL); if (!blk_test) return -ENOMEM; - print_all_line_eyetest(mmc); + update_all_line_eyetest(mmc); emmc_ds_core_align(mmc); - print_all_line_eyetest(mmc); + update_all_line_eyetest(mmc); emmc_all_data_line_alignment(mmc); - print_all_line_eyetest(mmc); + update_all_line_eyetest(mmc); emmc_ds_data_alignment(mmc); - print_all_line_eyetest(mmc); + update_all_line_eyetest(mmc); host->is_tunning = 1; - for (i = 0; i < 64; i++) { + for (i = 0; i < 32; i++) { gintf3->ds_sht_m += 1; writel(intf3, host->base + SD_EMMC_INTF3); err = aml_sd_emmc_cali_v3(mmc, MMC_READ_MULTIPLE_BLOCK, blk_test, blksz, 20); - emmc_dbg(EMMC_TIMMING_DBG, "intf3: 0x%x, err: %d\n", - readl(host->base + SD_EMMC_INTF3), err); - if (!err && !flag) { - sta = i; - flag = 1; - } else if (err && flag) { - end = i-1; - break; + emmc_dbg(AMLSD_DBG_V3, "intf3: 0x%x, err[%d]: %d\n", + readl(host->base + SD_EMMC_INTF3), i, err); + if (!err) + match[i] = 0; + else + match[i] = -1; + } + for (i = 0; i < 32; i++) { + if (match[i] == 0) { + if (cur_start < 0) + cur_start = i; + cur_size++; + } else { + if (cur_start >= 0) { + if (best_start < 0) { + best_start = cur_start; + best_size = cur_size; + } else { + if (best_size < cur_size) { + best_start = cur_start; + best_size = cur_size; + } + } + cur_start = -1; + cur_size = 0; + } } } - gintf3->ds_sht_m = (sta + end) / 2; + if (cur_start >= 0) { + if (best_start < 0) { + best_start = cur_start; + best_size = cur_size; + } else if (best_size < cur_size) { + best_start = cur_start; + best_size = cur_size; + } + cur_start = -1; + cur_size = -1; + } + + gintf3->ds_sht_m = (best_start + best_size) / 2; writel(intf3, host->base + SD_EMMC_INTF3); - emmc_dbg(EMMC_TIMMING_DBG, "sta:%u, end:%u,ds_sht:%u, intf3:0x%x", - sta, end, gintf3->ds_sht_m, + pr_info("ds_sht:%u, window:%d, intf3:0x%x", + gintf3->ds_sht_m, best_size, readl(host->base + SD_EMMC_INTF3)); host->is_tunning = 0; kfree(blk_test); @@ -835,8 +833,6 @@ static unsigned int emmc_clktest(struct mmc_host *mmc) gintf3->clktest_exp = 8; gintf3->clktest_on_m = 1; writel(intf3, host->base + SD_EMMC_INTF3); - emmc_dbg(EMMC_TIMMING_DBG, "CFG: 0x%x\n", - readl(host->base + SD_EMMC_CFG)); clktest_log = readl(host->base + SD_EMMC_CLKTEST_LOG); clktest = readl(host->base + SD_EMMC_CLKTEST_OUT); @@ -865,19 +861,250 @@ static unsigned int emmc_clktest(struct mmc_host *mmc) writel(intf3, host->base + SD_EMMC_INTF3); vcfg |= (1 << 23); writel(vcfg, host->base + SD_EMMC_CFG); - - emmc_dbg(EMMC_TIMMING_DBG, "CFG: 0x%x\n", - readl(host->base + SD_EMMC_CFG)); pdata->count = count; pdata->delay_cell = delay_cell; return count; } +static int _aml_sd_emmc_execute_tuning(struct mmc_host *mmc, u32 opcode, + struct aml_tuning_data *tuning_data, + u32 adj_win_start) +{ +#if 1 /* need finish later */ + struct amlsd_host *host = mmc_priv(mmc); + struct amlsd_platform *pdata = host->pdata; + u32 vclk; + struct sd_emmc_clock_v3 *clkc = (struct sd_emmc_clock_v3 *)&(vclk); + u32 vctrl; + struct sd_emmc_config *ctrl = (struct sd_emmc_config *)&vctrl; + u32 adjust = readl(host->base + SD_EMMC_ADJUST_V3); + struct sd_emmc_adjust_v3 *gadjust = + (struct sd_emmc_adjust_v3 *)&adjust; + u32 clk_rate = 1000000000; + const u8 *blk_pattern = tuning_data->blk_pattern; + unsigned int blksz = tuning_data->blksz; + unsigned long flags; + int ret = 0; + u32 nmatch = 0; + int adj_delay = 0; + u8 *blk_test; + u8 tuning_num = 0; + u32 clock, clk_div; + u32 adj_delay_find; + int wrap_win_start = -1, wrap_win_size = 0; + int best_win_start = -1, best_win_size = 0; + int curr_win_start = -1, curr_win_size = 0; + + writel(0, host->base + SD_EMMC_ADJUST_V3); + +tunning: + spin_lock_irqsave(&host->mrq_lock, flags); + pdata->need_retuning = false; + spin_unlock_irqrestore(&host->mrq_lock, flags); + vclk = readl(host->base + SD_EMMC_CLOCK_V3); + vctrl = readl(host->base + SD_EMMC_CFG); + clk_div = clkc->div; + clock = clk_rate / clk_div;/*200MHz, bus_clk */ + pdata->mmc->actual_clock = ctrl->ddr ? + (clock / 2) : clock;/*100MHz in ddr */ + + if (ctrl->ddr == 1) { + blksz = 512; + opcode = 17; + } + blk_test = kmalloc(blksz, GFP_KERNEL); + if (!blk_test) + return -ENOMEM; + + host->is_tunning = 1; + pr_info("%s: clk %d %s tuning start\n", + mmc_hostname(mmc), (ctrl->ddr ? (clock / 2) : clock), + (ctrl->ddr ? "DDR mode" : "SDR mode")); + for (adj_delay = 0; adj_delay < clk_div; adj_delay++) { + gadjust->adj_delay = adj_delay; + gadjust->adj_enable = 1; + gadjust->cali_enable = 0; + gadjust->cali_rise = 0; + writel(adjust, host->base + SD_EMMC_ADJUST_V3); + nmatch = aml_sd_emmc_tuning_transfer(mmc, opcode, + blk_pattern, blk_test, blksz); + /*get a ok adjust point!*/ + if (nmatch == TUNING_NUM_PER_POINT) { + if (adj_delay == 0) + wrap_win_start = adj_delay; + + if (wrap_win_start >= 0) + wrap_win_size++; + + if (curr_win_start < 0) + curr_win_start = adj_delay; + + curr_win_size++; + pr_info("%s: rx_tuning_result[%d] = %d\n", + mmc_hostname(host->mmc), adj_delay, nmatch); + } else { + if (curr_win_start >= 0) { + if (best_win_start < 0) { + best_win_start = curr_win_start; + best_win_size = curr_win_size; + } else { + if (best_win_size < curr_win_size) { + best_win_start = curr_win_start; + best_win_size = curr_win_size; + } + } + + wrap_win_start = -1; + curr_win_start = -1; + curr_win_size = 0; + } + } + + } + /* last point is ok! */ + if (curr_win_start >= 0) { + if (best_win_start < 0) { + best_win_start = curr_win_start; + best_win_size = curr_win_size; + } else if (wrap_win_size > 0) { + /* Wrap around case */ + if (curr_win_size + wrap_win_size > best_win_size) { + best_win_start = curr_win_start; + best_win_size = curr_win_size + wrap_win_size; + } + } else if (best_win_size < curr_win_size) { + best_win_start = curr_win_start; + best_win_size = curr_win_size; + } + + curr_win_start = -1; + curr_win_size = 0; + } + if (best_win_size <= 0) { + if ((tuning_num++ > MAX_TUNING_RETRY) + || (clkc->div >= 10)) { + kfree(blk_test); + pr_info("%s: final result of tuning failed\n", + mmc_hostname(host->mmc)); + return -1; + } + clkc->div += 1; + writel(vclk, host->base + SD_EMMC_CLOCK_V3); + pdata->clkc = readl(host->base + SD_EMMC_CLOCK_V3); + pr_info("%s: tuning failed, reduce freq and retuning\n", + mmc_hostname(host->mmc)); + goto tunning; + } else { + pr_info("%s: best_win_start =%d, best_win_size =%d\n", + mmc_hostname(host->mmc), best_win_start, best_win_size); + } + + if ((best_win_size != clk_div) + || (aml_card_type_sdio(pdata) + && (get_cpu_type() == MESON_CPU_MAJOR_ID_GXM))) { + adj_delay_find = best_win_start + (best_win_size - 1) / 2 + + (best_win_size - 1) % 2; + adj_delay_find = adj_delay_find % clk_div; + } else + adj_delay_find = 0; + + /* fixme, for retry debug. */ + if (aml_card_type_mmc(pdata) + && (clk_div <= 5) && (adj_win_start != 100) + && (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB)) { + pr_info("%s: adj_win_start %d\n", + mmc_hostname(host->mmc), adj_win_start); + adj_delay_find = adj_win_start % clk_div; + } + gadjust->adj_delay = adj_delay_find; + gadjust->adj_enable = 1; + gadjust->cali_enable = 0; + gadjust->cali_rise = 0; + writel(adjust, host->base + SD_EMMC_ADJUST_V3); + host->is_tunning = 0; + + pr_info("%s: sd_emmc_regs->gclock=0x%x,sd_emmc_regs->gadjust=0x%x\n", + mmc_hostname(host->mmc), + readl(host->base + SD_EMMC_CLOCK_V3), + readl(host->base + SD_EMMC_ADJUST_V3)); + kfree(blk_test); + /* do not dynamical tuning for no emmc device */ + if ((pdata->is_in) && !aml_card_type_mmc(pdata)) + schedule_delayed_work(&pdata->retuning, 15*HZ); + return ret; +#endif + return 0; +} + +int aml_emmc_hs200_timming(struct mmc_host *mmc) +{ + struct amlsd_host *host = mmc_priv(mmc); + u32 adjust = readl(host->base + SD_EMMC_ADJUST_V3); + struct sd_emmc_adjust *gadjust = + (struct sd_emmc_adjust *)&adjust; + emmc_clktest(mmc); + update_all_line_eyetest(mmc); + emmc_all_data_line_alignment(mmc); + gadjust->cali_enable = 1; + gadjust->adj_auto = 1; + writel(adjust, host->base + SD_EMMC_ADJUST_V3); + return 0; +} + +int aml_mmc_execute_tuning_v3(struct mmc_host *mmc, u32 opcode) +{ + struct amlsd_host *host = mmc_priv(mmc); + struct amlsd_platform *pdata = host->pdata; + struct aml_tuning_data tuning_data; + int err = -EINVAL; + u32 adj_win_start = 100; + u32 intf3; + + if (opcode == MMC_SEND_TUNING_BLOCK_HS200) { + if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { + tuning_data.blk_pattern = tuning_blk_pattern_8bit; + tuning_data.blksz = sizeof(tuning_blk_pattern_8bit); + } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) { + tuning_data.blk_pattern = tuning_blk_pattern_4bit; + tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); + } else { + return -EINVAL; + } + } else if (opcode == MMC_SEND_TUNING_BLOCK) { + tuning_data.blk_pattern = tuning_blk_pattern_4bit; + tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); + } else { + sd_emmc_err("Undefined command(%d) for tuning\n", opcode); + return -EINVAL; + } + + if (aml_card_type_sdio(pdata)) + err = _aml_sd_emmc_execute_tuning(mmc, opcode, + &tuning_data, adj_win_start); + else if (!(pdata->caps2 & MMC_CAP2_HS400)) { + intf3 = readl(host->base + SD_EMMC_INTF3); + intf3 |= (1<<22); + writel(intf3, (host->base + SD_EMMC_INTF3)); + err = aml_emmc_hs200_timming(mmc); + } else { + intf3 = readl(host->base + SD_EMMC_INTF3); + intf3 |= (1<<22); + writel(intf3, (host->base + SD_EMMC_INTF3)); + err = 0; + } + + pr_info("%s: gclock=0x%x, gdelay1=0x%x, gdelay2=0x%x,intf3=0x%x\n", + mmc_hostname(mmc), readl(host->base + SD_EMMC_CLOCK_V3), + readl(host->base + SD_EMMC_DELAY1_V3), + readl(host->base + SD_EMMC_DELAY2_V3), + readl(host->base + SD_EMMC_INTF3)); + return err; +} int aml_post_hs400_timming(struct mmc_host *mmc) { int ret = 0; - emmc_clktest(mmc); ret = emmc_ds_manual_sht(mmc); return 0; } + diff --git a/drivers/amlogic/mmc/amlsd_of.c b/drivers/amlogic/mmc/amlsd_of.c index e8039442225b..17d275525add 100644 --- a/drivers/amlogic/mmc/amlsd_of.c +++ b/drivers/amlogic/mmc/amlsd_of.c @@ -182,6 +182,8 @@ int amlsd_get_platform_data(struct platform_device *pdev, prop, pdata->card_type); SD_PARSE_U32_PROP_HEX(child, "pinmux_base", prop, pdata->base); + SD_PARSE_U32_PROP_DEC(child, "tx_delay", + prop, pdata->tx_delay); if (get_cpu_type() > MESON_CPU_MAJOR_ID_M8B) { if (aml_card_type_mmc(pdata)) { /*tx_phase set default value first*/ diff --git a/include/linux/amlogic/aml_sd_emmc_internal.h b/include/linux/amlogic/aml_sd_emmc_internal.h index 2489035ae0a4..a004227db5c4 100644 --- a/include/linux/amlogic/aml_sd_emmc_internal.h +++ b/include/linux/amlogic/aml_sd_emmc_internal.h @@ -24,10 +24,6 @@ extern int meson_mmc_clk_init_v3(struct amlsd_host *host); extern void meson_mmc_set_ios_v3(struct mmc_host *mmc, struct mmc_ios *ios); -/*extern int aml_sd_emmc_execute_tuning_(struct mmc_host *mmc, u32 opcode, - * struct aml_tuning_data *tuning_data, u32 adj_win_start); - */ - extern void aml_sd_emmc_set_buswidth(struct amlsd_host *host, u32 busw_ios); extern int meson_mmc_request_done(struct mmc_host *mmc, @@ -41,4 +37,7 @@ extern void aml_sd_emmc_send_stop(struct amlsd_host *host); extern int aml_sd_emmc_post_dma(struct amlsd_host *host, struct mmc_request *mrq); +extern u32 aml_sd_emmc_tuning_transfer(struct mmc_host *mmc, + u32 opcode, const u8 *blk_pattern, u8 *blk_test, u32 blksz); + #endif diff --git a/include/linux/amlogic/amlsd.h b/include/linux/amlogic/amlsd.h index e376a61c6f22..cc515a541df3 100644 --- a/include/linux/amlogic/amlsd.h +++ b/include/linux/amlogic/amlsd.h @@ -64,6 +64,7 @@ extern const u8 tuning_blk_pattern_8bit[128]; #define AMLSD_DBG_IRQ (1<<10) #define AMLSD_DBG_CLKC (1<<11) #define AMLSD_DBG_TUNING (1<<12) +#define AMLSD_DBG_V3 (1<<13) #define DETECT_CARD_IN 1 #define DETECT_CARD_OUT 2 @@ -109,8 +110,8 @@ extern const u8 tuning_blk_pattern_8bit[128]; #define sd_emmc_err(fmt, args...) \ pr_warn("[%s] " fmt, __func__, ##args) -#define emmc_dbg(emmc_timming_dbg, fmt, args...) do {\ - if (emmc_timming_dbg) \ +#define emmc_dbg(dbg_level, fmt, args...) do {\ + if (dbg_level & sd_emmc_debug) \ pr_warn("[%s]" fmt, __func__, ##args); \ } while (0)