emmc: optimizing emmc hs400 timing process
authorLong Yu <long.yu@amlogic.com>
Mon, 7 Aug 2017 10:44:55 +0000 (18:44 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Thu, 10 Aug 2017 11:27:55 +0000 (04:27 -0700)
PD#148082: emmc: optimizing emmc hs400 timing process

1. optimizing emmc hs400 timing

2. adjust the sampling method of the cmd line

3. clear intf3 register after suspending process

Change-Id: Ifb566f267b0cbc21c360ed63e8cdf2b98dfc4313
Signed-off-by: Long Yu <long.yu@amlogic.com>
arch/arm64/boot/dts/amlogic/axg_s400.dts
drivers/amlogic/mmc/aml_sd_emmc.c
drivers/amlogic/mmc/aml_sd_emmc_v3.c
drivers/amlogic/mmc/amlsd_of.c
include/linux/amlogic/aml_sd_emmc_internal.h
include/linux/amlogic/amlsd.h

index e3e4c6d..a6d84ae 100644 (file)
                        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>;
index 96aff57..8df5bcf 100644 (file)
@@ -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);
index ad21c5e..21dffdb 100644 (file)
@@ -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;
 }
 
-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;
 }
+
index e803944..17d2755 100644 (file)
@@ -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*/
index 2489035..a004227 100644 (file)
@@ -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
index e376a61..cc515a5 100644 (file)
@@ -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)