emmc: modified the fixed adj tuning mode for HS200 [1/1]
authorLong Yu <long.yu@amlogic.com>
Tue, 30 Jul 2019 02:26:02 +0000 (10:26 +0800)
committerTao Zeng <tao.zeng@amlogic.com>
Tue, 30 Jul 2019 10:34:20 +0000 (03:34 -0700)
PD#SWPL-11917

Problem:
Data sampling window has discontinuity

Solution:
Move the data as a whole to find a continuous data window

Verify:
txlx

Change-Id: I76fd41c22ff4c9e2e40b2b47580e25e0284ffbfa
Signed-off-by: Long Yu <long.yu@amlogic.com>
drivers/amlogic/mmc/aml_sd_emmc_v3.c
drivers/mmc/core/sdio.c
include/linux/amlogic/sd.h

index 7238e1e..4dc9285 100644 (file)
@@ -1524,6 +1524,150 @@ static unsigned int aml_sd_emmc_clktest(struct mmc_host *mmc)
        return count;
 }
 
+static void pr_adj_info(char *name,
+               unsigned long x, u32 fir_adj, u32 div)
+{
+       int i;
+
+       pr_info("[%s] fixed_adj_win_map:%lu\n",
+                       name, x);
+       for (i = 0; i < div; i++)
+               pr_info("[%d]=%d\n", (fir_adj + i) % div,
+                               ((x >> i) & 0x1) ? 1 : 0);
+}
+
+static unsigned long _test_fixed_adj(struct amlsd_host *host,
+               struct aml_tuning_data *tuning_data, u32 opcode,
+               u32 adj, u32 div)
+{
+       int i = 0;
+       u32 nmatch = 0;
+       u32 adjust = readl(host->base + SD_EMMC_ADJUST_V3);
+       struct sd_emmc_adjust_v3 *gadjust =
+               (struct sd_emmc_adjust_v3 *)&adjust;
+       const u8 *blk_pattern = tuning_data->blk_pattern;
+       unsigned int blksz = tuning_data->blksz;
+       DECLARE_BITMAP(fixed_adj_map, div);
+
+       bitmap_zero(fixed_adj_map, div);
+       for (i = 0; i < div; i++) {
+               gadjust->adj_delay = adj + i;
+               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(host->mmc, opcode,
+                               blk_pattern, host->blk_test, blksz);
+               /*get a ok adjust point!*/
+               if (nmatch == TUNING_NUM_PER_POINT) {
+                       set_bit(adj+i, fixed_adj_map);
+                       pr_info("%s: rx_tuning_result[%d] = %d\n",
+                               mmc_hostname(host->mmc), adj+i, nmatch);
+               }
+       }
+       return *fixed_adj_map;
+}
+
+static u32 _find_fixed_adj_mid(unsigned long map,
+               u32 adj, u32 div)
+{
+       u32 left, right, mid, size = 0;
+
+       left = find_last_bit(&map, div);
+       right = find_first_bit(&map, div);
+       mid = find_first_zero_bit(&map, div);
+       size = left - right + 1;
+       pr_info("left:%u, right:%u, mid:%u, size:%u\n",
+                       left, right, mid, size);
+       if ((size >= 3) && ((mid < right) || (mid > left))) {
+               mid = (adj + (size - 1) / 2 + (size - 1) % 2) % div;
+               return mid;
+       }
+       return NO_FIXED_ADJ_MID;
+}
+
+static unsigned long _swap_fixed_adj_win(unsigned long map,
+               u32 shift, u32 div)
+{
+       unsigned long left, right;
+
+       bitmap_shift_right(&right, &map,
+                       shift, div);
+       bitmap_shift_left(&left, &map,
+                       div - shift, div);
+       bitmap_or(&map, &right, &left, div);
+       return map;
+}
+
+static void set_fixed_adj_line_delay(u32 step,
+               struct amlsd_host *host)
+{
+       writel(AML_MOVE_DELAY1(step), host->base + SD_EMMC_DELAY1_V3);
+       writel(AML_MOVE_DELAY2(step), host->base + SD_EMMC_DELAY2_V3);
+       pr_info("step:%u, delay1:0x%x, delay2:0x%x\n",
+                       step,
+                       readl(host->base + SD_EMMC_DELAY1_V3),
+                       readl(host->base + SD_EMMC_DELAY2_V3));
+}
+/*     1. find first removed a fixed_adj_point
+ *     2. re-range fixed adj point
+ *     3. retry
+ */
+static u32 _find_fixed_adj_valid_win(struct amlsd_host *host,
+               struct aml_tuning_data *tuning_data, u32 opcode,
+               unsigned long *fixed_adj_map, u32 div)
+{
+       u32 step = 0, ret = NO_FIXED_ADJ_MID, fir_adj = 0xff;
+       unsigned long cur_map[1] = {0};
+       unsigned long prev_map[1] = {0};
+       unsigned long tmp[1] = {0};
+       unsigned long dst[1] = {0};
+
+       div = (div == AML_FIXED_ADJ_MIN) ?
+                       AML_FIXED_ADJ_MIN : AML_FIXED_ADJ_MAX;
+       *prev_map = *fixed_adj_map;
+       pr_adj_info("prev_map", *prev_map, 0, div);
+       for (; step <= 63;) {
+               pr_info("[%s]retry test fixed adj...\n", __func__);
+               step += AML_FIXED_ADJ_STEP;
+               set_fixed_adj_line_delay(step, host);
+               *cur_map = _test_fixed_adj(host, tuning_data, opcode, 0, div);
+               /*pr_adj_info("cur_map", *cur_map, 0, div);*/
+               bitmap_and(tmp, prev_map, cur_map, div);
+               bitmap_xor(dst, prev_map, tmp, div);
+               if (*dst != 0) {
+                       fir_adj = find_first_bit(dst, div);
+                       pr_adj_info(">>>>>>>>bitmap_xor_dst", *dst, 0, div);
+                       pr_info("[%s] fir_adj:%u\n", __func__, fir_adj);
+
+                       *prev_map = _swap_fixed_adj_win(*prev_map,
+                                       fir_adj, div);
+                       pr_adj_info(">>>>>>>>prev_map_range",
+                                       *prev_map, fir_adj, div);
+                       ret = _find_fixed_adj_mid(*prev_map, fir_adj, div);
+                       if (ret != NO_FIXED_ADJ_MID) {
+                               set_fixed_adj_line_delay(0, host);
+                               return ret;
+                       }
+
+                       fir_adj = (fir_adj + find_next_bit(prev_map,
+                               div, 1)) % div;
+               }
+               if (fir_adj == 0xff)
+                       continue;
+
+               *prev_map = *cur_map;
+               *cur_map = _swap_fixed_adj_win(*cur_map, fir_adj, div);
+               pr_adj_info(">>>>>>>>cur_map_range", *cur_map, fir_adj, div);
+               ret = _find_fixed_adj_mid(*cur_map, fir_adj, div);
+               if (ret != NO_FIXED_ADJ_MID)
+                       return ret;
+       }
+
+       pr_info("[%s][%d] no fixed adj\n", __func__, __LINE__);
+       return ret;
+}
+
 static int _aml_sd_emmc_execute_tuning(struct mmc_host *mmc, u32 opcode,
                                        struct aml_tuning_data *tuning_data,
                                        u32 adj_win_start)
@@ -1543,12 +1687,12 @@ static int _aml_sd_emmc_execute_tuning(struct mmc_host *mmc, u32 opcode,
        int adj_delay = 0;
        u8 tuning_num = 0;
        u32 clk_div;
-       u32 adj_delay_find;
+       u32 adj_delay_find =  0xff;
        int wrap_win_start, wrap_win_size;
        int best_win_start, best_win_size;
        int curr_win_start, curr_win_size;
        u32 old_dly, d1_dly, dly;
-       struct para_e *para = &(host->data->sdmmc);
+       unsigned long fixed_adj_map[1];
 
        if ((host->mem->start == host->data->port_b_base)
                        && host->data->tdma_f)
@@ -1578,27 +1722,8 @@ tunning:
        pr_info("%s: clk %d tuning start\n",
                        mmc_hostname(mmc), mmc->actual_clock);
 
-       /*retry adj[clk_div-1] tuning result*/
-       if ((clk_div == 5) && (aml_card_type_mmc(pdata))) {
-               gadjust->adj_delay = clk_div-1;
-               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, host->blk_test, blksz);
-               if (nmatch != TUNING_NUM_PER_POINT) {
-                       if (host->data->chip_type != MMC_CHIP_SM1) {
-                               clkc->core_phase = para->hs2.tx_phase;
-                               clkc->tx_phase = para->hs2.core_phase;
-                       }
-                       writel(vclk, host->base + SD_EMMC_CLOCK_V3);
-                       pr_info("%s:try clock:0x%x>>>rx_tuning[%d] = %d\n",
-                               mmc_hostname(host->mmc),
-                               readl(host->base + SD_EMMC_CLOCK_V3),
-                               gadjust->adj_delay, nmatch);
-               }
-       }
+       if (clk_div <= AML_FIXED_ADJ_MAX)
+               bitmap_zero(fixed_adj_map, clk_div);
        for (adj_delay = 0; adj_delay < clk_div; adj_delay++) {
                gadjust->adj_delay = adj_delay;
                gadjust->adj_enable = 1;
@@ -1622,6 +1747,8 @@ tunning:
                        curr_win_size++;
                        pr_info("%s: rx_tuning_result[%d] = %d\n",
                                mmc_hostname(host->mmc), adj_delay, nmatch);
+                       if (clk_div <= AML_FIXED_ADJ_MAX)
+                               set_bit(adj_delay, fixed_adj_map);
                } else {
                        if (curr_win_start >= 0) {
                                if (best_win_start < 0) {
@@ -1676,6 +1803,10 @@ tunning:
                pr_info("%s: tuning failed, reduce freq and retuning\n",
                        mmc_hostname(host->mmc));
                goto tunning;
+       } else if ((best_win_size < clk_div)
+                       && (clk_div <= AML_FIXED_ADJ_MAX)) {
+               adj_delay_find = _find_fixed_adj_valid_win(host,
+                               tuning_data, opcode, fixed_adj_map, clk_div);
        } else if (best_win_size == clk_div) {
                dly = readl(host->base + SD_EMMC_DELAY1_V3);
                d1_dly = (dly >> 0x6) & 0x3F;
@@ -1700,8 +1831,12 @@ tunning:
                                mmc_hostname(host->mmc),
                                best_win_start, best_win_size);
 
-       adj_delay_find = best_win_start + (best_win_size - 1) / 2
+       if (adj_delay_find == 0xff) {
+               adj_delay_find = best_win_start + (best_win_size - 1) / 2
                + (best_win_size - 1) % 2;
+               pdata->dly1 = old_dly;
+               writel(old_dly, host->base + SD_EMMC_DELAY1_V3);
+       }
        adj_delay_find = adj_delay_find % clk_div;
 
        gadjust->adj_delay = adj_delay_find;
@@ -1710,13 +1845,15 @@ tunning:
        gadjust->cali_rise = 0;
        writel(adjust, host->base + SD_EMMC_ADJUST_V3);
        pdata->adj = adjust;
-       pdata->dly1 = old_dly;
-       writel(old_dly, host->base + SD_EMMC_DELAY1_V3);
+       pdata->dly1 = readl(host->base + SD_EMMC_DELAY1_V3);
 
        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));
+       pr_info("delay1:0x%x, delay2:0x%x\n",
+                       readl(host->base + SD_EMMC_DELAY1_V3),
+                       readl(host->base + SD_EMMC_DELAY2_V3));
        host->is_tunning = 0;
        if ((host->mem->start == host->data->port_b_base)
                        && host->data->tdma_f)
index 4847e06..beff76b 100644 (file)
@@ -1235,10 +1235,14 @@ int sdio_reset_comm(struct mmc_card *card)
        if ((card->cis.vendor == 588) || (card->cis.vendor == 890))
                sdio_reset(host);
 
-       mmc_go_idle(host);
+       host->ios.power_mode = MMC_POWER_OFF;
 
        mmc_set_clock(host, host->f_min);
 
+       host->ios.power_mode = MMC_POWER_UP;
+
+       mmc_go_idle(host);
+
        err = mmc_send_io_op_cond(host, 0, &ocr);
        if (err)
                goto err;
index fbd1388..3a4ee34 100644 (file)
 #undef pr_fmt
 #define pr_fmt(fmt) "meson-mmc: " fmt
 
+#define AML_FIXED_ADJ_MIN      5
+#define AML_FIXED_ADJ_MAX      6
+#define AML_FIXED_ADJ_STEP     4
+#define AML_MOVE_DELAY1(x)     \
+       ((x << 0)|(x << 6)|(x << 12)|(x << 18)|(x << 24))
+#define AML_MOVE_DELAY2(x)     \
+       ((x << 0)|(x << 6)|(x << 12)|(x << 24))
+#define NO_FIXED_ADJ_MID       (1 << 31)
+
 #define         AML_ERROR_RETRY_COUNTER                 10
 #define         AML_TIMEOUT_RETRY_COUNTER         2
 #define AML_CALIBRATION