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 */
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) {
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 */
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;
}
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) ||
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;
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)
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)
{
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);
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;
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);
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,
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));
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);
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;
}
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));
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;
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) {
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);
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);
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);
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;
}
-int aml_post_hs400_timming(struct mmc_host *mmc)
+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;
}
+