#include "msdc_autok.h"
#include "msdc_host_hw.h"
#include "msdc_slave_hw.h"
#include "msdc_if.h"
#include "drvcust_if.h"


#define TUNE_CMD_ERR_MASK (CMD_ERR_NO_RESP | CMD_ERR_RESP_CRCERR | CMD_ERR_WAIT_CMD_TO )
#define TUNE_DAT_ERR_MASK (CMD_ERR_DATA_CRCERR | CMD_ERR_WAIT_DATATO | CMD_ERR_DATA_FAILED)


#define MSDC_FIFO_THD_1K       (1024)
#define TUNE_TX_CNT            (100)
#define TUNE_DATA_TX_ADDR      (0x358000)

#ifdef __MODEL_slt__
#define AUTOK_CMD_TIMES     (8)
#else
#define AUTOK_CMD_TIMES     (20)
#endif

enum AUTOK_PARAM{
    CMD_EDGE,                      /* command response sample selection (MSDC_SMPL_RISING, MSDC_SMPL_FALLING)*/
    RDATA_EDGE,                    /* read data sample selection (MSDC_SMPL_RISING, MSDC_SMPL_FALLING)*/

    RD_FIFO_EDGE,                  /* read data async fifo out edge select*/
    WD_FIFO_EDGE,                  /* write data crc status async fifo out edge select*/

    CMD_RD_D_DLY1,                  /* [Data Tune]CMD Pad RX Delay Line1 Control. This register is used to fine-tune CMD pad macro respose latch timing. Total 32 stages[Data Tune]*/
    CMD_RD_D_DLY1_SEL,              /* [Data Tune]CMD Pad RX Delay Line1 Sel-> delay cell1 enable*/
    CMD_RD_D_DLY2,                  /* [Data Tune]CMD Pad RX Delay Line2 Control. This register is used to fine-tune CMD pad macro respose latch timing. Total 32 stages[Data Tune]*/
    CMD_RD_D_DLY2_SEL,              /* [Data Tune]CMD Pad RX Delay Line1 Sel-> delay cell2 enable*/
    DAT_RD_D_DLY1,                  /* [Data Tune]DAT Pad RX Delay Line1 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D_DLY1_SEL,              /* [Data Tune]DAT Pad RX Delay Line1 Sel-> delay cell1 enable*/
    DAT_RD_D_DLY2,                  /* [Data Tune]DAT Pad RX Delay Line2 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D_DLY2_SEL,              /* [Data Tune]DAT Pad RX Delay Line2 Sel-> delay cell2 enable*/
#if HS400_DDLSEL_SEPARATE_TUNING
    DAT_RD_D_DDL_SEL,               /* [Data Tune]DAT Pad RX Delay Line1 separate tuning enable*/
    DAT_RD_D0_DLY1,                  /* [Data Tune]DAT0 Pad RX Delay Line1 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D1_DLY1,                  /* [Data Tune]DAT1 Pad RX Delay Line1 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D2_DLY1,                  /* [Data Tune]DAT2 Pad RX Delay Line1 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D3_DLY1,                  /* [Data Tune]DAT3 Pad RX Delay Line1 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D4_DLY1,                  /* [Data Tune]DAT4 Pad RX Delay Line1 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D5_DLY1,                  /* [Data Tune]DAT5 Pad RX Delay Line1 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D6_DLY1,                  /* [Data Tune]DAT6 Pad RX Delay Line1 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D7_DLY1,                  /* [Data Tune]DAT7 Pad RX Delay Line1 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D0_DLY2,                  /* [Data Tune]DAT0 Pad RX Delay Line2 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D1_DLY2,                  /* [Data Tune]DAT1 Pad RX Delay Line2 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D2_DLY2,                  /* [Data Tune]DAT2 Pad RX Delay Line2 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D3_DLY2,                  /* [Data Tune]DAT3 Pad RX Delay Line2 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D4_DLY2,                  /* [Data Tune]DAT4 Pad RX Delay Line2 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D5_DLY2,                  /* [Data Tune]DAT5 Pad RX Delay Line2 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D6_DLY2,                  /* [Data Tune]DAT6 Pad RX Delay Line2 Control (for MSDC RD), Total 32 stages [Data Tune]*/
    DAT_RD_D7_DLY2,                  /* [Data Tune]DAT7 Pad RX Delay Line2 Control (for MSDC RD), Total 32 stages [Data Tune]*/
#endif

    INT_DAT_LATCH_CK,              /* Internal MSDC clock phase selection. Total 8 stages, each stage can delay 1 clock period of msdc_src_ck*/

    EMMC50_DS_Z_DLY1,              /* DS Pad Z clk delay count, range: 0~63, Z dly1(0~31)+Z dly2(0~31)*/
    EMMC50_DS_Z_DLY1_SEL,          /* DS Pad Z clk del sel: [dly2_sel:dly1_sel] -> [0,1]: dly1 enable [1,2]:dl2 & dly1 enable ,else :no dly enable,*/
    EMMC50_DS_Z_DLY2,              /* DS Pad Z clk delay count, range: 0~63, Z dly1(0~31)+Z dly2(0~31)*/
    EMMC50_DS_Z_DLY2_SEL,          /* DS Pad Z clk del sel: [dly2_sel:dly1_sel] -> [0,1]: dly1 enable [1,2]:dl2 & dly1 enable ,else :no dly enable,*/
    EMMC50_DS_ZDLY_DLY,            /* DS Pad Z_DLY clk delay count, range: 0~31*/
    TUNING_PARAM_COUNT,

    READ_DATA_SMPL_SEL,            /* Data line rising/falling latch  fine tune selection in read transaction. 1'b0: All data line share one value indicated by MSDC_IOCON.R_D_SMPL. 1'b1: Each data line has its own  selection value indicated by Data line (x): MSDC_IOCON.R_D(x)_SMPL*/
    WRITE_DATA_SMPL_SEL,           /* Data line rising/falling latch  fine tune selection in write transaction. 1'b0: All data line share one value indicated by MSDC_IOCON.W_D_SMPL. 1'b1: Each data line has its own  selection value indicated by Data line (x): MSDC_IOCON.W_D(x)_SMPL*/
    DATA_DLYLINE_SEL,              /* Data line delay line fine tune selection. 1'b0: All data line share one delay selection value indicated by PAD_TUNE.PAD_DAT_RD_RXDLY. 1'b1: Each data line has its own delay selection value indicated by Data line (x): DAT_RD_DLY(x).DAT0_RD_DLY*/
    MSDC_DAT_TUNE_SEL,             /* [Data Tune]CMD & DATA Pin tune Data Selection[Data Tune Sel]*/
    MSDC_WCRC_ASYNC_FIFO_SEL,      /* [Async_FIFO Mode Sel For Write Path]*/
    MSDC_RESP_ASYNC_FIFO_SEL,      /* [Async_FIFO Mode Sel For CMD Path]*/

    EMMC50_WDATA_MUX_EN,           /*Write Path Mux for emmc50 function & emmc45 function , Only emmc50 design valid,[1-eMMC50, 0-eMMC45]*/
    EMMC50_CMD_MUX_EN,             /*CMD Path Mux for emmc50 function & emmc45 function , Only emmc50 design valid,[1-eMMC50, 0-eMMC45]*/
    EMMC50_WDATA_EDGE,             /* write data crc status async fifo output edge select*/

    TUNE_CKGEN_MSDC_DLY_SEL,            /* CKBUF in CKGEN Delay Selection. Total 32 stages*/
    TUNE_CMD_RSP_TA_CNTR,               /* CMD response turn around period. The turn around cycle = TUNE_CMD_RSP_TA_CNTR + 2, Only for USH104 mode, this register should be set to 0 in non-UHS104 mode*/
    TUNE_WRDAT_CRCS_TA_CNTR,            /* Write data and CRC status turn around period. The turn around cycle = TUNE_WRDAT_CRCS_TA_CNTR + 2, Only for USH104 mode,  this register should be set to 0 in non-UHS104 mode*/
    TUNE_PAD_CLK_TXDLY,                 /* CLK Pad TX Delay Control. This register is used to add delay to CLK phase. Total 32 stages*/
    TOTAL_PARAM_COUNT
};
struct AUTOK_PARAM_RANGE{
    unsigned int start;
    unsigned int end;
};
struct AUTOK_PARAM_INFO{
    struct AUTOK_PARAM_RANGE range;
    char * param_name;
};
struct BOUND_INFO{
    unsigned int Bound_Start;
    unsigned int Bound_End;
    unsigned int Bound_width;
    unsigned int is_fullbound;
};

#define BD_MAX_CNT 4                           /* Max Allowed Boundary Number */
struct AUTOK_SCAN_RES{
    struct BOUND_INFO   bd_info[BD_MAX_CNT];   /* Bound info record ,currently only allow max to 2 bound exist*/
    unsigned int bd_cnt;                       /* Bound cnt record , must be in rang [0,3]*/
    unsigned int fbd_cnt;                      /* Full boundart cnt record*/
};
struct AUTOK_REF_INFO{
    struct AUTOK_SCAN_RES scan_info[2];    /*inf[0] - rising edge res, inf[1] - falling edge res*/
    unsigned int   opt_edge_sel;   /* optimised sample edge select*/
    unsigned int   opt_dly_cnt;    /* optimised dly cnt sel*/
    unsigned int   cycle_cnt;      /*1clk cycle equal how many delay cell cnt, if cnt is 0 that is cannot calc cycle_cnt by current Boundary info*/
};
unsigned int autok_debug_level = AUTOK_DBG_ERROR;//AUTOK_DBG_RES;


enum TUNE_TYPE {
	TUNE_CMD = 0,
	TUNE_DATA,
	TUNE_LATCH_CK,
};


const struct AUTOK_PARAM_INFO autok_param_info[]={
    {{0,1},  "CMD_EDGE"},
    {{0,1},  "RDATA_EDGE"},        /*async fifo mode Pad dat edge must fix to 0*/
    {{0,1},  "RD_FIFO_EDGE"},
    {{0,1},  "WD_FIFO_EDGE"},

    {{0,31}, "CMD_RD_D_DLY1"},     /*Cmd Pad Tune Data Phase*/
    {{0,1},  "CMD_RD_D_DLY1_SEL"},
    {{0,31}, "CMD_RD_D_DLY2"},
    {{0,1},  "CMD_RD_D_DLY2_SEL"},

    {{0,31}, "DAT_RD_D_DLY1"},     /*Data Pad Tune Data Phase*/
    {{0,1},  "DAT_RD_D_DLY1_SEL"},
    {{0,31}, "DAT_RD_D_DLY2"},
    {{0,1},  "DAT_RD_D_DLY2_SEL"},
#if HS400_DDLSEL_SEPARATE_TUNING
    {{0,1},  "DAT_RD_D_DDL_SEL"},
    {{0,31}, "DAT_RD_D0_DLY1"},     /*Data Pad Tune Data Phase*/
    {{0,31}, "DAT_RD_D1_DLY1"},
    {{0,31}, "DAT_RD_D2_DLY1"},
    {{0,31}, "DAT_RD_D3_DLY1"},
    {{0,31}, "DAT_RD_D4_DLY1"},
    {{0,31}, "DAT_RD_D5_DLY1"},
    {{0,31}, "DAT_RD_D6_DLY1"},
    {{0,31}, "DAT_RD_D7_DLY1"},
    {{0,31}, "DAT_RD_D0_DLY2"},     /*Data Pad Tune Data Phase*/
    {{0,31}, "DAT_RD_D1_DLY2"},
    {{0,31}, "DAT_RD_D2_DLY2"},
    {{0,31}, "DAT_RD_D3_DLY2"},
    {{0,31}, "DAT_RD_D4_DLY2"},
    {{0,31}, "DAT_RD_D5_DLY2"},
    {{0,31}, "DAT_RD_D6_DLY2"},
    {{0,31}, "DAT_RD_D7_DLY2"},
#endif

    {{0,7},  "INT_DAT_LATCH_CK"},  /*Latch CK Delay for data read when clock stop*/

    {{0,31}, "EMMC50_DS_Z_DLY1"},  /*eMMC50 Related tuning param*/
    {{0,1},  "EMMC50_DS_Z_DLY1_SEL"},
    {{0,31}, "EMMC50_DS_Z_DLY2"},
    {{0,1},  "EMMC50_DS_Z_DLY2_SEL"},
    {{0,31}, "EMMC50_DS_ZDLY_DLY"},

    /*=================================================*/
    /*Timming Related Mux & Common Setting Config*/
    {{0,1},  "READ_DATA_SMPL_SEL"},        /*all data line path share sample edge*/
    {{0,1},  "WRITE_DATA_SMPL_SEL"},
    {{0,1},  "DATA_DLYLINE_SEL"},           /*clK tune all data Line share dly */
    {{0,1},  "MSDC_WCRC_ASYNC_FIFO_SEL"},   /*data tune mode select*/
    {{0,1},  "MSDC_RESP_ASYNC_FIFO_SEL"},   /*data tune mode select*/
    /*eMMC50 Function Mux*/
    {{0,1},  "EMMC50_WDATA_MUX_EN"},        /*write path switch to emmc45*/
    {{0,1},  "EMMC50_CMD_MUX_EN"},          /*response path switch to emmc45*/
    {{0,1},  "EMMC50_WDATA_EDGE"},
    /*Common Setting Config*/
    {{0,31}, "TUNE_CKGEN_MSDC_DLY_SEL"},
    {{1,7},  "TUNE_CMD_RSP_TA_CNTR"},
    {{1,7},  "TUNE_WRDAT_CRCS_TA_CNTR"},
    {{0,31}, "TUNE_PAD_CLK_TXDLY"},         /*tx clk dly fix to 0 for HQA res*/
};

#if 0
#else
/**********************************************************
 *                        AutoK Basic Interface Implenment                          *
 **********************************************************/
#if 0
static int autok_f0_rw_direct(msdc_cmd *host, unsigned int u4Addr, char *out, char in, bool write)
{
    struct mmc_request mrq = {NULL};
    struct mmc_command cmd = {0};
    int ret = E_RESULT_PASS;

    if (u4Addr & ~0x1FFFF)
        return -EINVAL;
    cmd.opcode = SD_IO_RW_DIRECT;
    cmd.arg = write ? 0x80000000 : 0x00000000;
    cmd.arg |= 0 << 28;                                      /*function number = 0*/
    cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;   /*read after write flage*/
    cmd.arg |= u4Addr << 9;
    cmd.arg |= in;
    cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;

    cmd.retries = 0;
    cmd.data = NULL;
    mrq.cmd = &cmd;

    ret = autok_wait_for_req(host,&mrq);
    if(out){
        *out = cmd.resp[0] & 0xFF;
    }

    return ret;
}

#endif

#define CMD19_DATA_DUMP 0
#define CMD21_DATA_DUMP 0
/******************************************************************
 *                                                                                                             *
 *                        autok auto tuning interface implenment                               *
 *                                                                                                             *
 ******************************************************************/
static int autok_send_cmd19(msdc_cmd *host)
{
    return cmd19_sd_send_tuning_pattern();
}
static int autok_send_cmd21(msdc_cmd *host)
{
    int ret = E_RESULT_PASS;
	unsigned int data_len = 0;
	unsigned char szTuningBlock[128] = {0};
	#if CMD21_DATA_DUMP
	unsigned int i = 0;
	#endif


	if(host->BusWidth == 4)
	{
        data_len = 64;
		MSDC_LOG(MSG_LVL_ERR, "cmd21 tuning process in bus width 4!\n");
	}
	else if(host->BusWidth == 8)
    {
        data_len = 128;
    }
	else
	{
        MSDC_LOG(MSG_LVL_ERR, "cmd21 tuning process is only used at 4/8bit width!\n");
		return E_RESULT_ERR;
	}

	x_memset(szTuningBlock, 0, sizeof(szTuningBlock));
	//ret = cmd21_mmc_send_tuning_block(szTuningBlock, data_len);

	ret = cmd21_mmc_send_tuning_block(szTuningBlock, data_len);


	#if CMD21_DATA_DUMP
    for(i=0; i<data_len; i++)
    {
        MSDC_LOG(MSG_LVL_ERR,"\t 0x%x \t",(unsigned char)szTuningBlock[i]);
    }
    #endif


    return ret;
}

static int autok_send_cmd12(msdc_cmd *host)
{
	return cmd12_stop_transmission();
}

static int autok_send_cmd13(msdc_cmd *host)
{
	unsigned int u4status = 0;
	int ret = E_RESULT_PASS;

	ret = cmd13_send_status(&u4status);

	return ret;

}

static int autok_send_cmd8(msdc_cmd *host)
{
    unsigned char szBlock[512] = {0};
    int ret = E_RESULT_PASS;

    x_memset(szBlock, 0 , sizeof(szBlock));

	ret = cmd8_mmc_send_ext_csd(szBlock);

    return ret;
}

static int autok_send_cmd17(msdc_cmd *host)
{
    unsigned char szBlock[512] = {0};
    int ret = E_RESULT_PASS;

    x_memset(szBlock, 0 , sizeof(szBlock));

	//ret = cmd17_read_single_block((unsigned long long )0x19000000, szBlock, 512);//zero data,no CRC ERR
	ret = cmd17_read_single_block((unsigned long long )0x0, szBlock, 512);//zero data,no CRC ERR
//	ret = cmd17_read_single_block((unsigned long long )0x000000, szBlock, 512);//Valid data, CRC ERR

    return ret;
}

static int autok_send_cmd18(msdc_cmd *host)
{
    unsigned char szBlock[2048] = {0};
    int ret = E_RESULT_PASS;

    x_memset(szBlock, 0 , sizeof(szBlock));
	cmd23_set_block_count(2048 >> SDHC_BLK_SIZE_ORDER, 0);
	ret = cmd18_read_multiple_block((unsigned long long )0x000000, szBlock, 2048);

    return ret;
}


static int autok_send_cmd24(msdc_cmd *host)
{
    unsigned int szBlock[512] = {0};
    int ret = E_RESULT_PASS;
	unsigned int i = 0;

    x_memset(szBlock, 0 , sizeof(szBlock));
	 for (i =0; i < 512; i++)
  	{
	  	szBlock[i] = 0x55aa55aa;
  	}

	ret = cmd24_write_single_block((unsigned long long )0x000000, szBlock, 512);

    return ret;
}

#endif
static int autok_send_tune_cmd(msdc_cmd *host, unsigned int opcode,enum TUNE_TYPE tune_type_value)
{
    unsigned int ret = 0;
    if (opcode == 19) {
        ret = autok_send_cmd19(host);
    } else if (opcode == 21) {
        ret = autok_send_cmd21(host);
    } else if (opcode == 13) {
        ret = autok_send_cmd13(host);
    } else if (opcode == 12) {
        ret = autok_send_cmd12(host);
    } else if (opcode == 17) {
        ret = autok_send_cmd17(host);
    } else if (opcode == 18) {
        ret = autok_send_cmd18(host);
    } else if (opcode == 24) {
        ret = autok_send_cmd24(host);
    } else if (opcode == 8) {
        ret = autok_send_cmd8(host);
    } else {
        ret = 0;
    }
    return ret;
}

#if defined(SDIO_TUNE_WRITE_PATH)
static int autok_cmd53_tune_cccr_write(msdc_cmd *host)
{
    int ret = 0;
	#if 0
    unsigned int wDat = 0x5A;
    unsigned int test_cnt = 10;
    int i = 0;
    do{
        i++;
       if((ret = autok_f0_rw_extended(host, 0xE0, &wDat, 4, 1, 0, 0))!= 0){
                MSDC_LOG(MSG_LVL_ERR,"[ERROR]CMD53(%d) Write CCCR0 Error: 0x%x\n",i,ret);
                autok_f0_rw_direct(host,0x6,NULL,0,1);  /* abort data transfer don't care response*/
                return ret;
        }
    }while(--test_cnt);
	#else
	//TO---DO
	#endif

    return ret;
}
#endif

static int autok_simple_score(char* res_str,unsigned int result)
{
    unsigned int bit = 0;
    unsigned int num = 0;
    unsigned int old = 0;

    if (0 == result) {
        strncpy(res_str,"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",32);   /* maybe result is 0*/
		res_str[32] = '\0';
        return 32;
    }
    if (0xFFFFFFFF == result) {
        strncpy(res_str,"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",32);
		res_str[32] = '\0';
        return 0;
    }
    while (bit < 32) {                                                 /* calc continue zero number */
        if (result & (1 << bit)) {
            res_str[bit]='X';
            bit++;
            if (old < num)
                old = num;
            num = 0;
            continue;
        }
        res_str[bit]='O';
        bit++;
        num++;
    }
    if (num > old)
        old = num;
    return old;
}
static int autok_simple_score64(char* res_str64,unsigned long long  result64)
{
    unsigned int bit = 0;
    unsigned int num = 0;
    unsigned int old = 0;

    if (0 == result64) {
        strncpy(res_str64,"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",64);   /* maybe result is 0*/
		res_str64[64] = '\0';
        return 64;
    }
    if (0xFFFFFFFFFFFFFFFF == result64) {
        strncpy(res_str64,"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",64);
		res_str64[64] = '\0';
        return 0;
    }
    while (bit < 64) {                                                 /* calc continue zero number */
        if (result64 & ((unsigned long long )(1LL << bit))) {
            res_str64[bit]='X';
            bit++;
            if (old < num)
                old = num;
            num = 0;
            continue;
        }
        res_str64[bit]='O';
        bit++;
        num++;
    }
    if (num > old)
        old = num;
    return old;
}

enum AUTOK_RAWD_SCAN_STA_E{
    RD_SCAN_NONE,
    RD_SCAN_PAD_BOUND_S,
    RD_SCAN_PAD_BOUND_E,
    RD_SCAN_PAD_MARGIN,
};
static int autok_check_scan_res64(unsigned long long  rawdat, struct AUTOK_SCAN_RES *scan_res)
{
    unsigned int bit;
    unsigned int filter = 2;
    enum AUTOK_RAWD_SCAN_STA_E RawScanSta =RD_SCAN_NONE;
    struct BOUND_INFO *pBD = (struct BOUND_INFO *)scan_res->bd_info;

    for(bit=0; bit<64; bit++){
        if (rawdat & (1LL << bit)) {
            switch (RawScanSta) {
                case RD_SCAN_NONE:
                    RawScanSta = RD_SCAN_PAD_BOUND_S;
                    pBD->Bound_Start= 0;
                    pBD->Bound_width = 1;
                    scan_res->bd_cnt += 1;
                break;
                case RD_SCAN_PAD_MARGIN:
                    RawScanSta = RD_SCAN_PAD_BOUND_S;
                    pBD->Bound_Start = bit;
                    pBD->Bound_width = 1;
                    scan_res->bd_cnt += 1;
                break;
                case RD_SCAN_PAD_BOUND_E:
				if ((filter) && ((bit - pBD->Bound_End) <= AUTOK_TUNING_INACCURACY)) {
					AUTOK_DBGPRINT(AUTOK_DBG_TRACE,
					       "[AUTOK]WARN: Try to filter the holes on raw data \r\n");
					RawScanSta = RD_SCAN_PAD_BOUND_S;

					pBD->Bound_width += (bit - pBD->Bound_End);
                            pBD->Bound_End= 0;
                            filter--;

                            if(pBD->is_fullbound){       /* update full bound info*/
                                pBD->is_fullbound = 0;
                                scan_res->fbd_cnt -= 1;;
                            }

                        } else{    /*Get the next boundary information*/
                           pBD++;
                           pBD->Bound_Start = bit;
                           pBD->Bound_width = 1;
                           RawScanSta = RD_SCAN_PAD_BOUND_S;
                           scan_res->bd_cnt += 1;
                           if(scan_res->bd_cnt > BD_MAX_CNT){
                               MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Error: more than %d Boundary Exist\r\n",BD_MAX_CNT);
                               return -1;
                            }
                    }
                break;
                case RD_SCAN_PAD_BOUND_S:
                    pBD->Bound_width++;
                break;
                default:
                break;
            }
        }else {
            switch (RawScanSta) {
                case RD_SCAN_NONE:
                    RawScanSta = RD_SCAN_PAD_MARGIN;
                break;
                case RD_SCAN_PAD_BOUND_S:
                    RawScanSta = RD_SCAN_PAD_BOUND_E;
                    pBD->Bound_End= bit - 1;
                    if(pBD->Bound_Start > 0){     /*update full bound info*/
                        pBD->is_fullbound = 1;
                        scan_res->fbd_cnt += 1;
                    }
                break;
                case RD_SCAN_PAD_MARGIN:
                case RD_SCAN_PAD_BOUND_E:
                default:
                break;
            }
        }
    }
    if((pBD->Bound_End == 0)&&(pBD->Bound_width)!=0)
    {
        pBD->Bound_End = pBD->Bound_Start + pBD->Bound_width - 1;
    }
   return 0;
}
static int autok_calc_bit_cnt(unsigned int result)
{
    unsigned int cnt = 0;
    if(result == 0){
        return 0;
    }else if(result == 0xFFFFFFFF){
        return 32;
    }
    do{
        if(result & 0x1){cnt++;}
        result = result >> 1;
    }while(result);
    return cnt;
}
static int autok_ta_sel(unsigned int *raw_list, unsigned int *pmid)
{
    int i = 0;
    unsigned int raw = 0;
    unsigned int r_start = 0;                           /*range start*/
    unsigned int r_stop  = 7;                       /*range stop*/
    unsigned int score = 0;
    unsigned int score_max = 0;
    unsigned int score_max_id = 0;
    unsigned int inaccuracy = TUNING_INACCURACY;

    for (i = 0; i <= 7; i++) {
        score = autok_calc_bit_cnt(raw_list[i]^0xFFFFFFFF);
        if (score > score_max) {
            score_max = score;
            score_max_id = i;
        }
    }
    if(score_max < 5){
        return -1;
    }
    raw = raw_list[score_max_id];
    AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]The maximum offset is %d\r\n",
        score_max_id);
FIND:
    for (i = 0; i <= 7; i++) {
        if (autok_calc_bit_cnt(raw_list[i]^raw) <= inaccuracy) {
            r_start = i;
            break;
        }
    }
    for (i = 7; i >= 0; i--) {
        if (autok_calc_bit_cnt(raw_list[i]^raw) <= inaccuracy) {
            r_stop = i;
            break;
        }
    }
    if((r_start+2) <= r_stop) {/* At least get the TA of which the margin has either left 1T and right 1T*/
        *pmid = (r_start+r_stop+1)/2;
    } else {
        inaccuracy++;
        if (inaccuracy < 5) {
            AUTOK_DBGPRINT(AUTOK_DBG_RES, "Enlarge the inaccuracy[%d]\r\n", inaccuracy);
            goto FIND;
        }
    }
    if (*pmid) {
        AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]Find suitable range[%d %d], TA_sel=%d\r\n",
            r_start, r_stop, *pmid);
    }
    else {
        *pmid = score_max_id;
        AUTOK_DBGPRINT(AUTOK_DBG_RES,"Un-expected pattern, pls check!, TA_sel=%d\r\n",
            *pmid);
    }
    return 0;
}
static int autok_pad_dly_sel(struct AUTOK_REF_INFO* pInfo)
{
    struct AUTOK_SCAN_RES* pBdInfo_R=NULL;     /*scan result @ rising edge*/
    struct AUTOK_SCAN_RES* pBdInfo_F=NULL;     /*scan result @ falling edge*/
    struct BOUND_INFO* pBdPrev = NULL;         /* Save the first boundary info for calc optimised dly count*/
    struct BOUND_INFO* pBdNext = NULL;         /* Save the second boundary info for calc optimised dly count*/
    struct BOUND_INFO* pBdTmp = NULL;
    unsigned int FBound_Cnt_R = 0;      /*Full Boundary count*/
    unsigned int Bound_Cnt_R = 0;
    unsigned int Bound_Cnt_F = 0;
    unsigned int cycle_cnt = 64;
    int uBD_mid_prev = 0;
    int uBD_mid_next = 0;
    int uBD_width = 3;
    int uDlySel_F = 0;
    int uDlySel_R = 0;
    int uMgLost_F = 0;                  /*for falling edge margin compress*/
    int uMgLost_R = 0;                  /*for rising edge margin compress*/
    unsigned int i = 0;
    unsigned int ret = 0;

    pBdInfo_R = &(pInfo->scan_info[0]);
    pBdInfo_F = &(pInfo->scan_info[1]);
    FBound_Cnt_R =  pBdInfo_R->fbd_cnt;
    Bound_Cnt_R =   pBdInfo_R->bd_cnt;
    Bound_Cnt_F =   pBdInfo_F->bd_cnt;

    switch(FBound_Cnt_R){
        case 4: /*SSSS Corner may cover 2~3T */
        case 3:
            MSDC_LOG(MSG_LVL_ERR,"[ATUOK]Warning: Too Many Full boundary count:%d\r\n",FBound_Cnt_R);
        case 2: {  /*mode_1 : 2 full boudary*/
            for(i=0; i< BD_MAX_CNT; i++){
                if(pBdInfo_R->bd_info[i].is_fullbound){
                    pBdPrev = &(pBdInfo_R->bd_info[i]);
                    break;
                }
            }
            i++;
            for(; i<BD_MAX_CNT;i++){
                if(pBdInfo_R->bd_info[i].is_fullbound){
                    pBdNext = &(pBdInfo_R->bd_info[i]);
                    break;
                }
            }
            if(pBdPrev && pBdNext){
                uBD_mid_prev = (pBdPrev->Bound_Start + pBdPrev->Bound_End)/2;
                uBD_mid_next = (pBdNext->Bound_Start + pBdNext->Bound_End)/2;
                uBD_width = (pBdPrev->Bound_width + pBdNext->Bound_width)/2; /* while in 2 full bound case ,bd_width calc*/
                cycle_cnt = uBD_mid_next - uBD_mid_prev;
                /*delay count sel@rising edge*/
                if(uBD_mid_prev >= cycle_cnt/2){
                    uDlySel_R = uBD_mid_prev - cycle_cnt/2;
                    uMgLost_R = 0;
                }else if((cycle_cnt/2 - uBD_mid_prev) > AUTOK_MARGIN_THOLD){
                    uDlySel_R = uBD_mid_prev + cycle_cnt/2;
                    uMgLost_R = 0;
                }else{
                    uDlySel_R = 0;
                    uMgLost_R = cycle_cnt/2 - uBD_mid_prev;
                }
                /*delay count sel@falling edge*/
                pBdTmp = &(pBdInfo_R->bd_info[0]);
                if(pBdTmp->is_fullbound){           /*ooooxxxooooooxxxooo*/
                    uDlySel_F = uBD_mid_prev;
                    uMgLost_F = 0;
                }else{                                /*xooooooxxxoooooooxxxoo*/
                    if(pBdTmp->Bound_End > uBD_width/2){
                        uDlySel_F = (pBdTmp->Bound_End)-(uBD_width/2);
                        uMgLost_F = 0;
                    }else{
                        uDlySel_F = 0;
                        uMgLost_F = (uBD_width/2)-(pBdTmp->Bound_End);
                    }
                }
            }else{  /* error can not find 2 foull boary*/
                MSDC_LOG(MSG_LVL_ERR,"[AUTOK]error can not find 2 foull boudary @ Mode_1");
                 return -1;
            }
            break;
        }
        case 1:{/* rising edge find one full boundary*/
            if(Bound_Cnt_R > 1){  /*mode_2: 1full boundary and boundary count > 1*/
                pBdPrev = &(pBdInfo_R->bd_info[0]);
                pBdNext = &(pBdInfo_R->bd_info[1]);
                uBD_width = (pBdPrev->is_fullbound) ? (pBdPrev->Bound_width):(pBdNext->Bound_width);

                if((pBdPrev->is_fullbound)||(pBdNext->is_fullbound)){
                    if(pBdPrev->Bound_Start > 0){
                        cycle_cnt = pBdNext->Bound_Start - pBdPrev->Bound_Start;
                    }else{
                        cycle_cnt = pBdNext->Bound_End - pBdPrev->Bound_End;
                    }
                    /*delay count sel@rising & falling edge*/
                    if(pBdPrev->is_fullbound){
                        uBD_mid_prev=(pBdPrev->Bound_Start+pBdPrev->Bound_End)/2;
                        uDlySel_F = uBD_mid_prev;
                        uMgLost_F = 0;
                        if(uBD_mid_prev >= cycle_cnt/2){
                            uDlySel_R = uBD_mid_prev - cycle_cnt/2;
                            uMgLost_R = 0;
                        }else if((cycle_cnt/2 - uBD_mid_prev)>AUTOK_MARGIN_THOLD){
                            uDlySel_R = uBD_mid_prev + cycle_cnt/2;
                            uMgLost_R = 0;
                        }else{
                            uDlySel_R = 0;
                            uMgLost_R = cycle_cnt/2 - uBD_mid_prev;
                        }
                    }else{  /* first boundary not full boudary */
                        uBD_mid_next=(pBdNext->Bound_Start+pBdNext->Bound_End)/2;
                        uDlySel_R = uBD_mid_next - cycle_cnt/2;
                        uMgLost_R = 0;
                        if(pBdPrev->Bound_End > uBD_width/2){
                            uDlySel_F = (pBdPrev->Bound_End)-(uBD_width/2);
                            uMgLost_F = 0;
                        }else{
                            uDlySel_F = 0;
                            uMgLost_F = (uBD_width/2)-(pBdPrev->Bound_End);
                        }
                    }
                }else{
                    return -1; /* full bound must in first 2 boundary*/
                }
            }else if(Bound_Cnt_F >0){  /*mode_3:   1 full boundary and only one boundary exist @rising edge */
                pBdPrev = &(pBdInfo_R->bd_info[0]);   /*this boundary is full bound*/
                pBdNext = &(pBdInfo_F->bd_info[0]);
                uBD_mid_prev = (pBdPrev->Bound_Start + pBdPrev->Bound_End)/2;
                uBD_width = pBdPrev->Bound_width;
                if(pBdNext->Bound_Start == 0){
                    cycle_cnt = (pBdPrev->Bound_End - pBdNext->Bound_End)*2;
                }else if(pBdNext->Bound_End== 63){
                    cycle_cnt = (pBdNext->Bound_Start-pBdPrev->Bound_Start)*2;
                }else{
                    uBD_mid_next = (pBdNext->Bound_Start + pBdNext->Bound_End)/2;
				cycle_cnt = (uBD_mid_next > uBD_mid_prev) ?
				(uBD_mid_next - uBD_mid_prev) * 2 : (uBD_mid_prev - uBD_mid_next) * 2;
                }
                uDlySel_F = uBD_mid_prev;
                uMgLost_F = 0;

                if(uBD_mid_prev >= cycle_cnt/2){                           /*case 1*/
                    uDlySel_R = uBD_mid_prev - cycle_cnt/2;
                    uMgLost_R = 0;
                }else if(cycle_cnt/2 - uBD_mid_prev <= AUTOK_MARGIN_THOLD){/*case 2*/
                    uDlySel_R = 0;
                    uMgLost_R = cycle_cnt/2 - uBD_mid_prev;
                }else if(cycle_cnt/2 + uBD_mid_prev <= 63){                /* case 3*/
                    uDlySel_R = cycle_cnt/2 + uBD_mid_prev;
                    uMgLost_R = 0;
                }else if(32 - uBD_mid_prev <= AUTOK_MARGIN_THOLD){         /*case 4*/
                    uDlySel_R = 0;
                    uMgLost_R = cycle_cnt/2 - uBD_mid_prev;
                }else{                                                     /* case 5*/
                    uDlySel_R = 63;
                    uMgLost_R = uBD_mid_prev + cycle_cnt/2 - 63;
                }
            }else{  /*mode_4: falling edge no boundary found & rising edge only one full boundary exist*/
                pBdPrev = &(pBdInfo_R->bd_info[0]);   /*this boundary is full bound */
                uBD_mid_prev = (pBdPrev->Bound_Start + pBdPrev->Bound_End)/2;
                uBD_width = pBdPrev->Bound_width;
			cycle_cnt = (pBdPrev->Bound_End > (64-pBdPrev->Bound_Start)) ?
			2 * pBdPrev->Bound_End : 2 * (64-pBdPrev->Bound_Start);
                if(uBD_mid_prev >= 32){
                    uDlySel_R = 0;
                    uMgLost_R = 0xFF;  /*Margin enough donot care margin lost*/
                    uDlySel_F = uBD_mid_prev;
                    uMgLost_F = 0xFF;  /*Margin enough donot care margin lost*/
                }else{
                    uDlySel_R = 63;
                    uMgLost_R = 0xFF;  /*Margin enough donot care margin lost*/
                    uDlySel_F = uBD_mid_prev;
                    uMgLost_F = 0xFF;  /*Margin enough donot care margin lost*/
                }
                MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Warning: 1T > %d\r\n",cycle_cnt);
            }
            break;
        }
        case 0:{ /* rising edge cannot find full boudary*/
            if(Bound_Cnt_R == 2){
                pBdPrev = &(pBdInfo_R->bd_info[0]);
                pBdNext = &(pBdInfo_F->bd_info[0]);   /*this boundary is full bound*/
                if(pBdNext->is_fullbound){  /*mode_5: rising_edge 2 boundary(not full bound),falling edge 1 full boundary*/
                  uBD_width = pBdNext->Bound_width;
                  cycle_cnt = 2*(pBdNext->Bound_End - pBdPrev->Bound_End);
                  uBD_mid_next = (pBdNext->Bound_Start + pBdNext->Bound_End)/2;
                  uDlySel_R = uBD_mid_next;
                  uMgLost_R = 0;
                  if(pBdPrev->Bound_End >= uBD_width/2){
                      uDlySel_F = pBdPrev->Bound_End - uBD_width/2;
                      uMgLost_F = 0;
                  }else{
                      uDlySel_F = 0;
                      uMgLost_F = uBD_width/2 - pBdPrev->Bound_End;
                  }
                }else{
                    /*for falling edge there must be one full boundary between two bounary_mid &@rising*/
                    return -1;
                }
            }else if (Bound_Cnt_R == 1){
                if(Bound_Cnt_F > 1){
                    /*when rising_edge have only one boundary(not full bound), falling edge shoule not more than 1Bound exist*/
                    return -1;
                }else if(Bound_Cnt_F == 1 ){  /*mode_6: rising edge only 1 boundary(not full Bound) & falling edge have only 1 bound too*/
                    pBdPrev = &(pBdInfo_R->bd_info[0]);
                    pBdNext = &(pBdInfo_F->bd_info[0]);
                    if(pBdNext->is_fullbound){
                        uBD_width = pBdNext->Bound_width;
                    }else{
					uBD_width = (pBdNext->Bound_width > pBdPrev->Bound_width) ?
					(pBdNext->Bound_width + 1) : (pBdPrev->Bound_width + 1);
                        uBD_width = (uBD_width > AUTOK_BD_WIDTH_REF)? uBD_width : AUTOK_BD_WIDTH_REF;
                    } /*Boundary width calc done */
                    if(pBdPrev->Bound_Start == 0){
                        if(pBdNext->Bound_Start == 0){
                            return -1; /*Current Desing Not Allowed*/
                        }
					cycle_cnt =
					    (pBdNext->Bound_Start - pBdPrev->Bound_End +
					     uBD_width) * 2;
                    }else if(pBdPrev->Bound_End== 63){
                        if(pBdNext->Bound_End== 63){
                            return -1; /*Current Desing Not Allowed*/
                        }
					cycle_cnt =
					    (pBdPrev->Bound_Start - pBdNext->Bound_End +
					     uBD_width) * 2;
                    }/*cycle count calc done*/
                    if(pBdPrev->Bound_Start == 0){/* calc optimise delay count*/
                        if(pBdPrev->Bound_End >= uBD_width/2){/* falling edge sel*/
                            uDlySel_F = pBdPrev->Bound_End - uBD_width/2;
                            uMgLost_F = 0;
                        }else{
                            uDlySel_F = 0;
                            uMgLost_F = uBD_width/2 - pBdPrev->Bound_End;
                        }
                        if(pBdPrev->Bound_End - uBD_width/2 + cycle_cnt/2 > 63){/* rising edge sel*/
                            uDlySel_R = 63;
						uMgLost_R =
						    pBdPrev->Bound_End - uBD_width / 2 +
						    cycle_cnt / 2 - 63;
                        }else{
						uDlySel_R =
						    pBdPrev->Bound_End - uBD_width / 2 +
						    cycle_cnt / 2;
                            uMgLost_R = 0;
                        }
                    }else if(pBdPrev->Bound_End == 63){
                        if(pBdPrev->Bound_Start+ uBD_width/2 < 63){/* falling edge sel*/
                            uDlySel_F = pBdPrev->Bound_Start+ uBD_width/2;
                            uMgLost_F = 0;
                        }else{
                            uDlySel_F = 63;
						uMgLost_F =
						    pBdPrev->Bound_Start + uBD_width / 2 - 63;
                        }
                        if(pBdPrev->Bound_Start+ uBD_width/2 < cycle_cnt/2){/* rising edge sel*/
                            uDlySel_R = 0;
						uMgLost_R =
						    cycle_cnt / 2 - (pBdPrev->Bound_Start +
								     uBD_width / 2);
                        }else{
						uDlySel_R =
						    pBdPrev->Bound_Start + uBD_width / 2 -
						    cycle_cnt / 2;
                            uMgLost_R = 0;
                        }
                    }else{
                        return -1;
                    }
                }else if(Bound_Cnt_F == 0){  /*mode_7: rising edge only one bound(not full),falling no boundary*/
                    pBdPrev = &(pBdInfo_R->bd_info[0]);
                    pBdNext = &(pBdInfo_F->bd_info[0]);
                    cycle_cnt = 128;
                    if(pBdPrev->Bound_Start == 0){
                        uDlySel_F = 0;
                        uMgLost_F = 0xFF;
                        uDlySel_R = 63;
                        uMgLost_R = 0xFF;
                    }else if(pBdPrev->Bound_End == 63){
                        uDlySel_F = 63;
                        uMgLost_F = 0xFF;
                        uDlySel_R = 0;
                        uMgLost_R = 0xFF;
                    }else{
                        return -1;
                    }
                    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Warning: 1T > %d\r\n",cycle_cnt);

                }
            }else if (Bound_Cnt_R == 0){/*Rising Edge No Boundary found*/
                if(Bound_Cnt_F > 1){
                    /* falling edge not allowed two boundary Exist for this case*/
                    return -1;
                }else if(Bound_Cnt_F > 0){ /*mode_8: falling edge have one Boundary exist*/
                    pBdPrev = &(pBdInfo_F->bd_info[0]);   /*this boundary is full bound */
                    if(pBdPrev->is_fullbound){
                        uBD_mid_prev = (pBdPrev->Bound_Start + pBdPrev->Bound_End)/2;
					cycle_cnt = (pBdPrev->Bound_End > (64 - pBdPrev->Bound_Start)) ?
					2 * pBdPrev->Bound_End : 2 * (64 - pBdPrev->Bound_Start);
                        if(uBD_mid_prev >= 32){
                            uDlySel_R = uBD_mid_prev;
                            uMgLost_R = 0xFF;
                            uDlySel_F = 0;
                            uMgLost_F = 0xFF;
                        }else{
                            uDlySel_R = uBD_mid_prev;
                            uMgLost_R = 0xFF;
                            uDlySel_F = 63;
                            uMgLost_F = 0xFF;
                        }

                    }else{
                        cycle_cnt =  128;
                        if(pBdPrev->Bound_Start == 0){
                            uDlySel_R = 0;
                            uMgLost_R = 0xFF;
                            uDlySel_F = 63;
                            uMgLost_F = 0xFF;
                        }else{/* bound_end = 63*/
                            uDlySel_R = 63;
                            uMgLost_R = 0xFF;
                            uDlySel_F = 0;
                            uMgLost_F = 0xFF;
                        }
                    }
                    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Warning: 1T > %d\r\n",cycle_cnt);
                }else{/* falling edge no boundary exist no need tuning */
				cycle_cnt = 128;
                    uDlySel_F = 31;
                    uMgLost_F = 0xFF;
                    uDlySel_R = 31;
                    uMgLost_R = 0xFF;
                    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Warning: 1T > %d\r\n",cycle_cnt);
                }
            }else {
                /*Error if bound_cnt>3 there must be at least one full boundary exist*/
                return -1;
            }
            break;
        }
        default:
            /* warning if boundary count > 4(from current hw design, this case cannot happen)*/
            return -1;
            break;
    }
    /*Select Optimised Sample edge & delay count (the small one)*/
    pInfo->cycle_cnt =  cycle_cnt;
	/*
    if(uDlySel_R<=uDlySel_F){
        pInfo->opt_edge_sel = 0;
        pInfo->opt_dly_cnt = uDlySel_R;
    }else{
        pInfo->opt_edge_sel = 1;
        pInfo->opt_dly_cnt = uDlySel_F;

    }
	*/
	pInfo->opt_edge_sel = 0;
	pInfo->opt_dly_cnt = uDlySel_R;

    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Analysis Result: 1T = %d\r\n ",cycle_cnt);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Analysis Result: Rising Dly Sel: %d, MgLost: %d\r\n",uDlySel_R,uMgLost_R);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Analysis Result: Falling Dly Sel: %d, MgLost: %d\r\n",uDlySel_F,uMgLost_F);
    return ret;
}
static int
autok_pad_dly_sel_single_edge(struct AUTOK_SCAN_RES* pInfo,unsigned int cycle_cnt_ref, unsigned int* pDlySel)
{
    struct BOUND_INFO* pBdPrev = NULL;         /* Save the first boundary info for calc optimised dly count*/
    struct BOUND_INFO* pBdNext = NULL;         /* Save the second boundary info for calc optimised dly count*/
    unsigned int Bound_Cnt = 0;
    unsigned int uBD_mid_prev = 0;
    int uDlySel = 0;
    int uMgLost = 0;
    unsigned int ret = 0;
    Bound_Cnt = pInfo->bd_cnt;
    if(Bound_Cnt > 1){
        pBdPrev = &(pInfo->bd_info[0]);
        pBdNext = &(pInfo->bd_info[1]);
        if(!(pBdPrev->is_fullbound)){ /* mode_1:at least 2 Bound and Boud0_Start == 0*/
            uDlySel = (pBdPrev->Bound_End + pBdNext->Bound_Start)/2;
            uMgLost = (uDlySel > 31) ? (uDlySel-31) : 0;
            uDlySel = (uDlySel > 31) ? 31 : uDlySel;

        }else{                        /*mode_2: at least 2 Bound found  and Bound0_Start != 0  */
            uBD_mid_prev = (pBdPrev->Bound_Start + pBdPrev->Bound_End)/2;
            if(uBD_mid_prev >= cycle_cnt_ref/2){
                uDlySel = uBD_mid_prev - cycle_cnt_ref/2;
                uMgLost = 0;
            }else if(cycle_cnt_ref/2 - uBD_mid_prev < AUTOK_MARGIN_THOLD){
                uDlySel = 0;
                uMgLost = cycle_cnt_ref/2 - uBD_mid_prev;
            }else{
                uDlySel = (pBdPrev->Bound_End + pBdNext->Bound_Start)/2;
                if((uDlySel > 31) &&(uDlySel - 31 < AUTOK_MARGIN_THOLD)){
                    uDlySel =  31;
                    uMgLost = uDlySel-31;
                }else{
                    uDlySel = uDlySel;
                    uMgLost = 0;
                }
            }
        }
    }else if(Bound_Cnt > 0){  /* only one bound fond*/
        pBdPrev = &(pInfo->bd_info[0]);
        if(pBdPrev->is_fullbound){  /*mode_3: Bound_S != 0*/
            uBD_mid_prev = (pBdPrev->Bound_Start + pBdPrev->Bound_End)/2;
            if(uBD_mid_prev >= cycle_cnt_ref/2){
                uDlySel = uBD_mid_prev - cycle_cnt_ref/2;
                uMgLost = 0;
            }else if(cycle_cnt_ref/2 - uBD_mid_prev < AUTOK_MARGIN_THOLD){
                uDlySel = 0;
                uMgLost = cycle_cnt_ref/2 - uBD_mid_prev;
            }else if((uBD_mid_prev > 31 - AUTOK_MARGIN_THOLD) ||(pBdPrev->Bound_Start >= 16)){
                uDlySel = 0;
                uMgLost = cycle_cnt_ref/2 - uBD_mid_prev;
            }else if(uBD_mid_prev + cycle_cnt_ref/2 <= 63){/* Left Margin not enough must need to select the right side*/
                uDlySel =  uBD_mid_prev + cycle_cnt_ref/2;
                uMgLost =  0;
            }else{
                uDlySel = 63;
                uMgLost =  uBD_mid_prev + cycle_cnt_ref/2 - 63;
            }
        }else if(pBdPrev->Bound_Start == 0){ /* mode_4 : Only one Boud and Boud_S = 0  (Currently 1T nearly equal 64 )*/
            uBD_mid_prev = (pBdPrev->Bound_Start + pBdPrev->Bound_End)/2;  /*May not exactly by for Cycle_Cnt enough can don't care*/
            if(pBdPrev->Bound_Start + cycle_cnt_ref/2 >= 31){
                uDlySel = 31;
                uMgLost =  uBD_mid_prev + cycle_cnt_ref/2 - 31;
            }else{
                uDlySel =  uBD_mid_prev + cycle_cnt_ref/2;
                uMgLost = 0;
            }
        }else{  /* mode_5: Only one Boud and Boud_E = 64*/
            uBD_mid_prev = (pBdPrev->Bound_Start + pBdPrev->Bound_End)/2;  /*May not exactly by for Cycle_Cnt enough can don't care*/
            if(pBdPrev->Bound_Start < cycle_cnt_ref/2 ){
                uDlySel = 0;
                uMgLost = cycle_cnt_ref/2 - uBD_mid_prev;
            }else if( uBD_mid_prev - cycle_cnt_ref/2 > 31){
                uDlySel =  31;
                uMgLost = uBD_mid_prev - cycle_cnt_ref/2 - 31;
            }else{
                uDlySel =  uBD_mid_prev - cycle_cnt_ref/2;
                uMgLost = 0;
            }
        }
    }else{ /*mode_6: no bound foud*/
        uDlySel = 31;
        uMgLost = 0xFF;
    }
    *pDlySel = uDlySel;
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Result: Dly Sel:%d, MgLost:%d\r\n",uDlySel,uMgLost);
    if(uDlySel > 31){
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Warning Dly Sel %d > 31 easily effected by Voltage Swing\r\n",uDlySel);
    }
    return ret;
}
#if HS400_DSCLK_NEED_TUNING
static int autok_ds_dly_sel(struct AUTOK_SCAN_RES* pInfo,unsigned int* pDlySel)
{
    unsigned int ret = 0;
    int uDlySel = 0;
    unsigned int Bound_Cnt = pInfo->bd_cnt;

    if(pInfo->fbd_cnt > 0){     /*no more than 2 boundary exist*/
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Error: Scan DS Not allow Full boundary Occurs!\r\n");
        //return -1;
    }
    if(Bound_Cnt > 1){          /*bound count == 2*/
        uDlySel = (pInfo->bd_info[0].Bound_End + pInfo->bd_info[1].Bound_Start)/2;
    }else if(Bound_Cnt > 0){    /*bound count == 1*/
        if(pInfo->bd_info[0].Bound_Start == 0){
            if(pInfo->bd_info[0].Bound_End > 31){
                uDlySel = (pInfo->bd_info[0].Bound_End + 64)/2;
                MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Warning: DS Delay not in range 0~31!\r\n");
            }else{
                uDlySel = (pInfo->bd_info[0].Bound_End + 31)/2;
            }
        }else{
            uDlySel = pInfo->bd_info[0].Bound_Start/2;
        }
    }else{                      /*bound count == 0*/
       uDlySel = 16;
    }
    *pDlySel = uDlySel;
    return ret;

}
#endif

/*************************************************************************
* FUNCTION
*  msdc_autok_adjust_param
*
* DESCRIPTION
*  This function for auto-K, adjust msdc parameter
*
* PARAMETERS
*    host: msdc host manipulator pointer
*    param: enum of msdc parameter
*    value: value of msdc parameter
*    rw: AUTOK_READ/AUTOK_WRITE
*
* RETURN VALUES
*    error code: 0 success,
*               -1 parameter input error
*               -2 read/write fail
*               -3 else error
*************************************************************************/
static int msdc_autok_adjust_param(msdc_cmd *host, enum AUTOK_PARAM param, unsigned int *value, int rw)
{
    volatile unsigned int* reg;
    unsigned int field = 0;

    switch (param)
    {
        case READ_DATA_SMPL_SEL:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for READ_DATA_SMPL_SEL is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }

            reg = (unsigned int*)MSDC_IOCON;
            field = (unsigned int)(MSDC_IOCON_R_D_SMPL_SEL);
            break;
        case WRITE_DATA_SMPL_SEL:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for WRITE_DATA_SMPL_SEL is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }

            reg = (unsigned int*)MSDC_IOCON;
            field = (unsigned int)(MSDC_IOCON_W_D_SMPL_SEL);
            break;
        case DATA_DLYLINE_SEL:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DATA_DLYLINE_SEL is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }

            reg = (unsigned int*)MSDC_IOCON;
            field = (unsigned int)(MSDC_IOCON_D_DLYLINE_SEL);
            break;
        case MSDC_DAT_TUNE_SEL:  /* 0-Dat tune 1-CLk tune ;*/
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DATA_DLYLINE_SEL is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PAD_TUNE;
            field = (unsigned int)(PAD_RXDLY_SEL);
            break;
        case MSDC_WCRC_ASYNC_FIFO_SEL:
           if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DATA_DLYLINE_SEL is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PATCH_BIT2;
            field = (unsigned int)(CFG_CRCSTS);
        break;
        case MSDC_RESP_ASYNC_FIFO_SEL:
           if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DATA_DLYLINE_SEL is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PATCH_BIT2;
            field = (unsigned int)(CFG_RESP);
        break;
        case CMD_EDGE:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for CMD_EDGE is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)MSDC_IOCON;
            field = (unsigned int)(MSDC_IOCON_R_SMPL);
            break;
        case RDATA_EDGE:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for RDATA_EDGE is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)MSDC_IOCON;
            field = (unsigned int)(MSDC_IOCON_D_SMPL);
            break;
        case RD_FIFO_EDGE:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for RDATA_EDGE is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PATCH_BIT0;
            field = (unsigned int)(RD_DAT_SEL);
            break;
        case WD_FIFO_EDGE:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for WDATA_EDGE is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PATCH_BIT2;
            field = (unsigned int)(CFG_CRCSTS_EDGE);
            break;
        case CMD_RD_D_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for CMD_RD_DLY is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PAD_TUNE;
            field = (unsigned int)(PAD_CMD_RXDLY);
            break;
        case CMD_RD_D_DLY1_SEL:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for CMD_RD_DLY is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PAD_TUNE;
            field = (unsigned int)(PAD_CMD_RD_RX_DLY_SEL);
            break;
        case CMD_RD_D_DLY2:
            if((rw == AUTOK_WRITE) && (*value > 31)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for CMD_RD_DLY is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PAD_TUNE1;
            field = (unsigned int)(PAD_TUNE1_CMDRDLY2);
            break;
        case CMD_RD_D_DLY2_SEL:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for CMD_RD_DLY is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PAD_TUNE1;
            field = (unsigned int)(PAD_TUNE1_CMDRRDLY2SEL);
            break;
        case DAT_RD_D_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT0_RD_DLY is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PAD_TUNE;
            field = (unsigned int)(PAD_DAT_RD_RXDLY);
            break;
        case DAT_RD_D_DLY1_SEL:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for CMD_RD_DLY is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PAD_TUNE;
            field = (unsigned int)(PAD_DAT_RD_RXDLY_SEL);
            break;
        case DAT_RD_D_DLY2:
            if((rw == AUTOK_WRITE) && (*value > 31)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT1_RD_DLY is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PAD_TUNE1;
            field = (unsigned int)(PAD_TUNE1_DATRRDLY2);
            break;
        case DAT_RD_D_DLY2_SEL:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for CMD_RD_DLY is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PAD_TUNE1;
            field = (unsigned int)(PAD_TUNE1_DATRRDLY2SEL);
            break;
#if HS400_DDLSEL_SEPARATE_TUNING
        case DAT_RD_D_DDL_SEL:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DDLSEL is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)MSDC_IOCON;
            field = (unsigned int)(MSDC_IOCON_D_DLYLINE_SEL);
            break;
        case DAT_RD_D0_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D0_DLY1 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY0;
            field = (unsigned int)(MSDC_DAT_RDDLY0_D0_LINE1);
            break;
        case DAT_RD_D1_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D1_DLY1 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY0;
            field = (unsigned int)(MSDC_DAT_RDDLY0_D1_LINE1);
            break;
        case DAT_RD_D2_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D2_DLY1 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY0;
            field = (unsigned int)(MSDC_DAT_RDDLY0_D2_LINE1);
            break;
        case DAT_RD_D3_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D3_DLY1 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY0;
            field = (unsigned int)(MSDC_DAT_RDDLY0_D3_LINE1);
            break;
        case DAT_RD_D4_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D4_DLY1 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY1;
            field = (unsigned int)(MSDC_DAT_RDDLY1_D4_LINE1);
            break;
        case DAT_RD_D5_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D5_DLY1 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY1;
            field = (unsigned int)(MSDC_DAT_RDDLY1_D5_LINE1);
            break;
        case DAT_RD_D6_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D6_DLY1 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY1;
            field = (unsigned int)(MSDC_DAT_RDDLY1_D6_LINE1);
            break;
        case DAT_RD_D7_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D7_DLY1 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY1;
            field = (unsigned int)(MSDC_DAT_RDDLY1_D7_LINE1);
            break;
        case DAT_RD_D0_DLY2:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D0_DLY2 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY2;
            field = (unsigned int)(MSDC_DAT_RDDLY2_D0_LINE2);
            break;
        case DAT_RD_D1_DLY2:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D1_DLY2 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY2;
            field = (unsigned int)(MSDC_DAT_RDDLY2_D1_LINE2);
            break;
        case DAT_RD_D2_DLY2:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D2_DLY2 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY2;
            field = (unsigned int)(MSDC_DAT_RDDLY2_D2_LINE2);
            break;
        case DAT_RD_D3_DLY2:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D3_DLY2 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY2;
            field = (unsigned int)(MSDC_DAT_RDDLY2_D3_LINE2);
            break;
        case DAT_RD_D4_DLY2:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D4_DLY2 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY3;
            field = (unsigned int)(MSDC_DAT_RDDLY3_D4_LINE2);
            break;
        case DAT_RD_D5_DLY2:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D5_DLY2 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY3;
            field = (unsigned int)(MSDC_DAT_RDDLY3_D5_LINE2);
            break;
        case DAT_RD_D6_DLY2:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D6_DLY2 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY3;
            field = (unsigned int)(MSDC_DAT_RDDLY3_D6_LINE2);
            break;
        case DAT_RD_D7_DLY2:
            if((rw == AUTOK_WRITE) && (*value > 31)){
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for DAT_RD_D7_DLY2 is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)DAT_RD_DLY3;
            field = (unsigned int)(MSDC_DAT_RDDLY3_D7_LINE2);
            break;
#endif
        case INT_DAT_LATCH_CK:
            if((rw == AUTOK_WRITE) && (*value > 7)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for INT_DAT_LATCH_CK is out of range, it should be [0~7]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PATCH_BIT0;
            field = (unsigned int)(INT_DAT_LATCH_CK_SEL);
            break;
        case TUNE_CKGEN_MSDC_DLY_SEL:
            if((rw == AUTOK_WRITE) && (*value > 31)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for TUNE_CKGEN_MSDC_DLY_SEL is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PATCH_BIT0;
            field = (unsigned int)(CKGEN_MSDC_DLY_SEL);
            break;
        case TUNE_CMD_RSP_TA_CNTR:
            if((rw == AUTOK_WRITE) && (*value > 7)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for TUNE_CMD_RSP_TA_CNTR is out of range, it should be [0~7]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PATCH_BIT1;
            field = (unsigned int)(CMD_RSP_TA_CNTR);
            break;
        case TUNE_WRDAT_CRCS_TA_CNTR:
            if((rw == AUTOK_WRITE) && (*value > 7)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for TUNE_WRDAT_CRCS_TA_CNTR is out of range, it should be [0~7]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PATCH_BIT1;
            field = (unsigned int)(WRDAT_CRCS_TA_CNTR);
            break;
        case TUNE_PAD_CLK_TXDLY:
            if((rw == AUTOK_WRITE) && (*value > 31)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for TUNE_PAD_CLK_TXDLY is out of range, it should be [0~31]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)PAD_TUNE;
            field = (unsigned int)(PAD_CLK_TXDLY);
            break;
        case EMMC50_WDATA_MUX_EN:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for EMMC50_WDATA_MUX_EN is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)EMMC50_CFG0;
            field = (unsigned int)(CRC_STS_SEL);
            break;
        case EMMC50_CMD_MUX_EN:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for EMMC50_CMD_MUX_EN is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)EMMC50_CFG0;
            field = (unsigned int)(CFG_CMD_RESP_SEL);
            break;
        case EMMC50_WDATA_EDGE:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for EMMC50_WDATA_EDGE is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)EMMC50_CFG0;
            field = (unsigned int)(CRC_STS_EDGE);
            break;
        case EMMC50_DS_Z_DLY1:
            if((rw == AUTOK_WRITE) && (*value > 31)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for EMMC50_DS_Z_DLY1 is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)EMMC50_PAD_DS_TUNE;
            field = (unsigned int)(MSDC_EMMC50_PAD_DS_TUNE_DLY1);
            break;
        case EMMC50_DS_Z_DLY1_SEL:
            if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for EMMC50_DS_Z_DLY1_SEL is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)EMMC50_PAD_DS_TUNE;
            field = (unsigned int)(MSDC_EMMC50_PAD_DS_TUNE_DLYSEL);
            break;
        case EMMC50_DS_Z_DLY2:
           if((rw == AUTOK_WRITE) && (*value > 31)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for EMMC50_DS_Z_DLY2 is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)EMMC50_PAD_DS_TUNE;
            field = (unsigned int)(MSDC_EMMC50_PAD_DS_TUNE_DLY2);
            break;
        case EMMC50_DS_Z_DLY2_SEL:
           if((rw == AUTOK_WRITE) && (*value > 1)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for EMMC50_DS_Z_DLY1_SEL is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)EMMC50_PAD_DS_TUNE;
            field = (unsigned int)(MSDC_EMMC50_PAD_DS_TUNE_DLY2SEL);
            break;
             break;
        case EMMC50_DS_ZDLY_DLY:
           if((rw == AUTOK_WRITE) && (*value > 31)){
                AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Input value(%d) for EMMC50_DS_Z_DLY2 is out of range, it should be [0~1]\n", __func__, *value);
                return -1;
            }
            reg = (unsigned int*)EMMC50_PAD_DS_TUNE;
            field = (unsigned int)(MSDC_EMMC50_PAD_DS_TUNE_DLY3);
             break;
        default:
            AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Value of [enum AUTOK_PARAM param] is wrong\n", __func__);
            return -1;
    }

    if(rw == AUTOK_READ)
        MSDC_GET_FIELD(reg, field, *value);
    else if(rw == AUTOK_WRITE) {
        MSDC_SET_FIELD(reg, field, *value);

        if (param == TUNE_CKGEN_MSDC_DLY_SEL)
            MsdcCommDelay(1000);
    }
    else{
        AUTOK_DBGPRINT(AUTOK_DBG_WARN,"[%s] Value of [int rw] is wrong\n", __func__);
        return -1;
    }
    return 0;
}
static int autok_param_update(enum AUTOK_PARAM param_id, unsigned int result, unsigned char* autok_tune_res)
{
    if (param_id < TUNING_PARAM_COUNT){
        if ((result > autok_param_info[param_id].range.end) ||
            (result < autok_param_info[param_id].range.start)) {
			MSDC_LOG(MSG_LVL_ERR, "[AUTOK]param outof range : %d not in [%d,%d]\r\n",
					result, autok_param_info[param_id].range.start,
					autok_param_info[param_id].range.end);
            return -1;
        } else {
            autok_tune_res[param_id] = (unsigned char)result;
            return 0;
        }
	}
	MSDC_LOG(MSG_LVL_ERR, "[AUTOK]param not found\r\n");
	return -1;
}
static int autok_param_apply(msdc_cmd *host,unsigned char* autok_tune_res)
{
    unsigned int i=0;
    unsigned int value = 0;
    for(i=0; i<TUNING_PARAM_COUNT; i++){
        value = (unsigned char)autok_tune_res[i];
        msdc_autok_adjust_param(host, i, &value, AUTOK_WRITE);
    }
    return 0;
}
static int autok_result_dump(msdc_cmd *host,unsigned char* autok_tune_res)
{
    unsigned int i=0;
    for(i=0; i<TUNING_PARAM_COUNT; i++){
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]param %s:%d\r\n",autok_param_info[i].param_name,autok_tune_res[i]);
    }
    return 0;
}

#if AUTOK_PARAM_DUMP_ENABLE
static int autok_register_dump(msdc_cmd *host)
{
    unsigned int i=0;
    unsigned int value = 0;
    for(i=0; i<TUNING_PARAM_COUNT; i++){
        msdc_autok_adjust_param(host, i, &value, AUTOK_READ);
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]reg field %s:%d\r\n",autok_param_info[i].param_name,value);
    }
    return 0;
}
#endif
void autok_tuning_parameter_init(msdc_cmd* host, unsigned char* res)
{

/*    MSDC_SET_FIELD(PATCH_BIT2, 7<<29, 2);*/
/*    MSDC_SET_FIELD(PATCH_BIT2, 7<<16, 4);*/

    autok_param_apply(host,res);
}
/*******************************************************
 *    Function: msdc_autok_adjust_paddly                                    *
 *    Param   : value - delay cnt from 0 to 63                                *
 *                  pad_sel - 0 for cmd pad and 1 for data pad              *
 *******************************************************/
#define CMD_PAD_RDLY 0
#define DAT_PAD_RDLY 1
#define DS_PAD_RDLY 2
#if HS400_DDLSEL_SEPARATE_TUNING
#define DS_PAD_RDLY_SEP 3
#define DS_PAD_RDLY_SEP_EN 4
unsigned int sep_en = 0;
#endif
static void msdc_autok_adjust_paddly(msdc_cmd *host, unsigned int *value, unsigned int pad_sel)
{
    unsigned int uCfgL = 0;
    unsigned int uCfgLSel = 0;
    unsigned int uCfgH = 0;
    unsigned int uCfgHSel = 0;
    unsigned int dly_cnt = *value;
#if HS400_DDLSEL_SEPARATE_TUNING
    unsigned int uddl1,uddl2,i;
#endif

    uCfgL = (dly_cnt>31)?(31):dly_cnt;
    uCfgH = (dly_cnt>31)?(dly_cnt-32):0;

    uCfgLSel = (uCfgL > 0)?1:0;
    uCfgHSel = (uCfgH > 0)?1:0;
    switch(pad_sel)
    {
	case CMD_PAD_RDLY:
            msdc_autok_adjust_param(host, CMD_RD_D_DLY1, &uCfgL, AUTOK_WRITE);   /*PAD_TUNE0[16],PAD_CMD_RXDLY*/

            msdc_autok_adjust_param(host, CMD_RD_D_DLY2, &uCfgH, AUTOK_WRITE);    /*PAD_TUNE1[16],PAD_CMD_RXDLY2 */
            msdc_autok_adjust_param(host, CMD_RD_D_DLY1_SEL, &uCfgLSel, AUTOK_WRITE);  /*PAD_TUNE0[21],1:through data-delay line*/
            msdc_autok_adjust_param(host, CMD_RD_D_DLY2_SEL, &uCfgHSel, AUTOK_WRITE);  /*PAD_TUNE1[21],1:through data-delay line2 */
        break;
	case DAT_PAD_RDLY:
            msdc_autok_adjust_param(host, DAT_RD_D_DLY1, &uCfgL, AUTOK_WRITE); /*PAD_TUNE0[8],PAD_DAT_RD_RXDLY*/

            msdc_autok_adjust_param(host, DAT_RD_D_DLY2, &uCfgH, AUTOK_WRITE); /*PAD_TUNE1[8],PAD_DAT_RD_RXDLY line2*/
            msdc_autok_adjust_param(host, DAT_RD_D_DLY1_SEL, &uCfgLSel, AUTOK_WRITE); /*PAD_TUNE0[13],1:through data-delay line*/
            msdc_autok_adjust_param(host, DAT_RD_D_DLY2_SEL, &uCfgHSel, AUTOK_WRITE); /*PAD_TUNE1[13],1:through data-delay line2*/
        break;
	case DS_PAD_RDLY:
            msdc_autok_adjust_param(host, EMMC50_DS_Z_DLY1, &uCfgL, AUTOK_WRITE);/*EMMC50_PAD_DS_TUNE,EMMC50_PAD_DS_TUNE[2]*/

            msdc_autok_adjust_param(host, EMMC50_DS_Z_DLY2, &uCfgH, AUTOK_WRITE); /*EMMC50_AD_DS_TUNE,EMMC50_PAD_DS_TUNE[1]*/
            msdc_autok_adjust_param(host, EMMC50_DS_Z_DLY1_SEL, &uCfgLSel, AUTOK_WRITE);
            msdc_autok_adjust_param(host, EMMC50_DS_Z_DLY2_SEL, &uCfgHSel, AUTOK_WRITE);
        break;
#if HS400_DDLSEL_SEPARATE_TUNING
        case DS_PAD_RDLY_SEP:
            msdc_autok_adjust_param(host, DAT_RD_D_DLY1_SEL, &uCfgLSel, AUTOK_WRITE); /*PAD_TUNE0[13],1:through data-delay line*/
            msdc_autok_adjust_param(host, DAT_RD_D_DLY2_SEL, &uCfgHSel, AUTOK_WRITE); /*PAD_TUNE1[13],1:through data-delay line2*/
            uddl1 = DAT_RD_D0_DLY1 + sep_en;
            uddl2 = DAT_RD_D0_DLY2 + sep_en;
            msdc_autok_adjust_param(host, uddl1, &uCfgL, AUTOK_WRITE); /*PAD_TUNE0[8],PAD_DAT_RD_RXDLY*/
            msdc_autok_adjust_param(host, uddl2, &uCfgH, AUTOK_WRITE); /*PAD_TUNE1[8],PAD_DAT_RD_RXDLY line2*/
        break;
        case DS_PAD_RDLY_SEP_EN:
    	    sep_en =  *value;
            dly_cnt = 0;
            uddl1 = DAT_RD_D0_DLY1;
            uddl2 = DAT_RD_D0_DLY2;
            for(i=0; i<8; i++){//clear delay line
                msdc_autok_adjust_param(host, uddl1+i, &dly_cnt, AUTOK_WRITE); /*PAD_TUNE0[8],PAD_DAT_RD_RXDLY*/
                msdc_autok_adjust_param(host, uddl2+i, &dly_cnt, AUTOK_WRITE); /*PAD_TUNE1[8],PAD_DAT_RD_RXDLY line2*/
            }
        break;
#endif
     }
}
static void autok_paddly_update(unsigned int pad_sel,unsigned int dly_cnt,unsigned char* autok_tune_res)
{
    unsigned int uCfgL = 0;
    unsigned int uCfgLSel = 0;
    unsigned int uCfgH = 0;
    unsigned int uCfgHSel = 0;

    uCfgL = (dly_cnt>31)?(31):dly_cnt;
    uCfgH = (dly_cnt>31)?(dly_cnt-32):0;

    uCfgLSel = (uCfgL > 0)?1:0;
    uCfgHSel = (uCfgH > 0)?1:0;
    switch(pad_sel)
    {
	case CMD_PAD_RDLY:
            autok_param_update(CMD_RD_D_DLY1, uCfgL,autok_tune_res);

            autok_param_update(CMD_RD_D_DLY2, uCfgH,autok_tune_res);
            autok_param_update(CMD_RD_D_DLY1_SEL, uCfgLSel,autok_tune_res);
            autok_param_update(CMD_RD_D_DLY2_SEL, uCfgHSel,autok_tune_res);
        break;
	case DAT_PAD_RDLY:
            autok_param_update(DAT_RD_D_DLY1, uCfgL,autok_tune_res);

            autok_param_update(DAT_RD_D_DLY2, uCfgH,autok_tune_res);
            autok_param_update(DAT_RD_D_DLY1_SEL, uCfgLSel,autok_tune_res);
            autok_param_update(DAT_RD_D_DLY2_SEL, uCfgHSel,autok_tune_res);
        break;
	case DS_PAD_RDLY:
            autok_param_update(EMMC50_DS_Z_DLY1, uCfgL,autok_tune_res);

            autok_param_update(EMMC50_DS_Z_DLY2, uCfgH,autok_tune_res);
            autok_param_update(EMMC50_DS_Z_DLY1_SEL, uCfgLSel,autok_tune_res);
            autok_param_update(EMMC50_DS_Z_DLY2_SEL, uCfgHSel,autok_tune_res);
        break;
     }
}

/*******************************************************
 *                        Exectue tuning IF Implenment                          *
 *******************************************************/
static int autok_write_param(msdc_cmd* host,enum AUTOK_PARAM param, unsigned int value)
{
   msdc_autok_adjust_param(host, param, &value, AUTOK_WRITE);
   return 0;
}

VOID MsdcDumpTotalRegister(VOID)
{
	unsigned int i = 0;
	unsigned int u4regs [] = {0x0,0x4,0x8,0xc,
						0x10,0x14,0x18,0x1c,
						0x30,0x34,0x38,0x3c,
						0x40,0x44,0x48,0x4c,
						0x50,0x54,0x58,0x5c,
						0x60,
						0x70,0x74,0x78,0x7c,
						0x80,0x84,0x88,0x8c,
						0x90,0x94,0x98,0x9c,
						0xa0,0xa4,0xa8,
						0xb0,0xb4,0xb8,
						0xf0,0xf4,0xf8,0xfc,
						0x100,0x104,0x110,0x114,
						0x118,
						0x180,0x184,0x188,0x18c,
						0x190,0x194,0x198,0x19c,
						0x208,0x20c,0x228};
	MSDC_LOG(MSG_LVL_ERR,"num %d \n",sizeof(u4regs)/sizeof(unsigned int));

	for(i=0; i < sizeof(u4regs)/sizeof(unsigned int); i++)
	{
		MSDC_LOG(MSG_LVL_ERR,"[0X%x] 0x%x \n",u4regs[i],MSDC_READ32(IO_VIRT + 0x6d000 + u4regs[i]));
	}
}

extern int g_clk_tx_dly;
int autok_path_sel(msdc_cmd* host)
{
    //MSDC_SET_FIELD(PATCH_BIT2, 7<<29, 2);  /*LATCH_TA_EN Config for WCRC Path*/
    //MSDC_SET_FIELD(PATCH_BIT2, 7<<16, 4);  /*LATCH_TA_EN Config for CMD Path*/

	//all sample and dealy share one data pin
    autok_write_param(host, READ_DATA_SMPL_SEL,0);  /*IOCON[5]*/
	MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL_SEL_SEL, 0);/*IOCON[9]*/
    autok_write_param(host, WRITE_DATA_SMPL_SEL,0); /*IOCON[8]*/
    autok_write_param(host, DATA_DLYLINE_SEL,   0);    /*IOCON[3],clK tune all data Line share dly */
#if defined(CHIP_DENALI_3_DAT_TUNE)
    autok_write_param(host, MSDC_DAT_TUNE_SEL,1);       /*PAD_TUNE0[15] ,tune clock path, tune mode select*/
#else
    autok_write_param(host, MSDC_DAT_TUNE_SEL,0);       /*PAD_TUNE0[15] ,tune data path, tune mode select*/
#endif
    autok_write_param(host, MSDC_WCRC_ASYNC_FIFO_SEL,1);  /*PATCH_BIT2[28],latch CRC Status ,select async fifo path*/
    autok_write_param(host, MSDC_RESP_ASYNC_FIFO_SEL,0);  /*PATCH_BIT2[15],latch CMD Response ,select async fifo path*/
    /*eMMC50 Function Mux*/
    autok_write_param(host, EMMC50_WDATA_MUX_EN,    0);   /*EMMC50_CFG0[4],write path switch to emmc45*/
    autok_write_param(host, EMMC50_CMD_MUX_EN,      0);   /*EMMC50_CFG0[9],response path switch to emmc45*/
    autok_write_param(host, EMMC50_WDATA_EDGE,      0);   /*EMMC50_CFG0[3],select rising eage at emmc50 hs400*/
    /*Common Setting Config*/
    autok_write_param(host, TUNE_CKGEN_MSDC_DLY_SEL,    AUTOK_CKGEN_VALUE); /*patch_bit0[10], ckgen*/
    autok_write_param(host, TUNE_CMD_RSP_TA_CNTR,       AUTOK_CMD_TA_VALUE); /*patch_bit1[3], TA*/
    autok_write_param(host, TUNE_WRDAT_CRCS_TA_CNTR,    AUTOK_CRC_TA_VALUE); /*patch_bit1[0], TA*/
	 /*tx clk dly fix to 0 for HQA res*/
    ///autok_write_param(host, TUNE_PAD_CLK_TXDLY,         g_clk_tx_dly);
    autok_write_param(host, TUNE_PAD_CLK_TXDLY,         AUTOK_CMD_TX_VALUE); /*PAD_TUNE0[27],tx clk dly fix to 0 for HQA res*/
	MSDC_SET_FIELD(PATCH_BIT1, MSDC_PB1_GET_BUSY_MARGIN, AUTOK_BUSY_MA_VALUE);
	MSDC_SET_FIELD(PATCH_BIT1, MSDC_PB1_GET_CRC_MARGIN, AUTOK_CRC_MA_VALUE);

    MSDC_LOG(MSG_LVL_ERR,"---CLK TX DLY  %d----\n",(MSDC_READ32(PAD_TUNE) >> PAD_CLK_TXDLY_SHIFT) & 0X1F);
    return 0;
}
int autok_init_sdr104(msdc_cmd* host)
{
    autok_path_sel(host);
    /*if any specific config need modify add here*/
	/* LATCH_TA_EN Config for WCRC Path non_HS400 */
	MSDC_SET_FIELD(PATCH_BIT2, MSDC_BIT2_CRCSTS_LATCH_SEL, AUTOK_CRC_LATCH_EN_NON_HS400_VALUE);
	/* LATCH_TA_EN Config for CMD Path non_HS400 */
	MSDC_SET_FIELD(PATCH_BIT2, MSDC_BIT2_RESP_LATCH_ENSEL, AUTOK_CMD_LATCH_EN_NON_HS400_VALUE);
	return 0;
}
int autok_init_hs200(msdc_cmd* host)
{
    autok_path_sel(host);
    /*if any specific config need modify add here*/
	/* LATCH_TA_EN Config for WCRC Path non_HS400 */
	MSDC_SET_FIELD(PATCH_BIT2, MSDC_BIT2_CRCSTS_LATCH_SEL, AUTOK_CRC_LATCH_EN_NON_HS400_VALUE);
	/* LATCH_TA_EN Config for CMD Path non_HS400 */
	MSDC_SET_FIELD(PATCH_BIT2, MSDC_BIT2_RESP_LATCH_ENSEL, AUTOK_CMD_LATCH_EN_NON_HS400_VALUE);
	return 0;
}
int autok_init_hs400(msdc_cmd* host)
{
    autok_path_sel(host);
    /*if any specific config need modify add here*/
	MSDC_SET_FIELD(PATCH_BIT1, CMD_RSP_TA_CNTR, 0); /*patch_bit1[3], TA*/
	MSDC_SET_FIELD(PATCH_BIT1, WRDAT_CRCS_TA_CNTR, 0);/*patch_bit1[0], TA*/
	MSDC_SET_FIELD(PATCH_BIT1, MSDC_PB1_GET_CRC_MARGIN, 0);
	MSDC_SET_FIELD(PATCH_BIT1, STOP_DLY_SEL, 6);
	//for SDR, select the rising sample edge, for DDR/CMD, still use IOCON
	MSDC_SET_FIELD(PATCH_BIT0, MSDC_BIT0_RD_RAT_SEL, 0);
	MSDC_SET_FIELD(PATCH_BIT0, MSDC_BIT0_DESC_UP_SEL, 1);
	 /* LATCH_TA_EN Config for WCRC Path HS400 */
	MSDC_SET_FIELD(PATCH_BIT2, MSDC_BIT2_RESP_LATCH_ENSEL, AUTOK_CRC_LATCH_EN_HS400_VALUE);
	/* LATCH_TA_EN Config for CMD Path HS400 */
	MSDC_SET_FIELD(PATCH_BIT2, MSDC_BIT2_CRCSTS_LATCH_SEL, AUTOK_CMD_LATCH_EN_HS400_VALUE);
	/*write path switch to emmc45 */
	autok_write_param(host, EMMC50_WDATA_MUX_EN, 1);
	/* Specifical for HS400 Path Sel */
	autok_write_param(host, MSDC_WCRC_ASYNC_FIFO_SEL, 0);
	return 0;
}

#define CATH_SIGNEL 0
#define DRVING_TEST 0

int execute_online_tuning_hs400(msdc_cmd* host, unsigned char* res)
{
    int ret = 0;
    unsigned int uCmdEdge = 0;
    unsigned long long  RawData64 = 0LL;
    unsigned int score = 0;
	unsigned int DS_score1 = 0;
	unsigned int DS_score2 = 0;
    unsigned int i = 0,j = 0,k = 0;
    struct AUTOK_REF_INFO uCmdInfo;
    struct AUTOK_SCAN_RES* pBdInfo;
    char tune_result_str64[65];
    unsigned char p_autok_tune_res[TUNING_PARAM_COUNT];
    unsigned int opcode = 13;
	unsigned int u4ClkTxDly = 0;

	unsigned int   opt_edge_sel;   /* optimised sample edge select*/
	unsigned int   opt_dly_cnt;    /* optimised dly cnt sel*/
	unsigned int   cycle_cnt;

	#if HS400_REDUCE_DS_TUNE_TIME
	unsigned int u4valid_window = 0;
	#endif

	#if HS400_DSCLK_NEED_TUNING
	unsigned int RawData = 0;
	struct AUTOK_REF_INFO uDatInfo;
	unsigned int uDatDly = 0;
	#if HS400_DDLSEL_SEPARATE_TUNING
    unsigned int uDatDly_sep[8];
    unsigned int uTuneSepFlag = 0;
	#endif
	#endif

    autok_init_hs400(host);
    x_memset((void*)p_autok_tune_res, 0, sizeof(p_autok_tune_res) / sizeof(unsigned char));

	autok_tuning_parameter_init(host, p_autok_tune_res);

    #if defined(CC_MT5893) || defined(CC_MT5895)
	MSDC_SET_FIELD(SDC_CMD_STS, SDC_CMD_STS_RX_ENHANCE_EN, 1);
	MSDC_SET_FIELD(PAD_TUNE, PAD_CLK_TXDLY, 3);//For setup time ,have to shift clock
    #elif defined(CC_MT5886)
	MSDC_SET_FIELD(PAD_TUNE, PAD_CLK_TXDLY, 2);//For setup time ,have to shift clock
    #endif
	MSDC_GET_FIELD(PAD_TUNE, PAD_CLK_TXDLY, u4ClkTxDly);
	MSDC_LOG(MSG_LVL_ERR,"==CLK TX DLY %d \n", u4ClkTxDly);

	//x_thread_delay(5000);
	/*Set TX  delay for HQA*/
	/*
	MSDC_SET_FIELD(EMMC50_PAD_CMD_TUNE, MSDC_EMMC50_PAD_CMD_TUNE_TXDLY, cmd_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT01_TUNE, MSDC_EMMC50_PAD_DAT0_TXDLY, dat_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT01_TUNE, MSDC_EMMC50_PAD_DAT1_TXDLY, dat_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT23_TUNE, MSDC_EMMC50_PAD_DAT2_TXDLY, dat_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT23_TUNE, MSDC_EMMC50_PAD_DAT3_TXDLY, dat_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT45_TUNE, MSDC_EMMC50_PAD_DAT4_TXDLY, dat_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT45_TUNE, MSDC_EMMC50_PAD_DAT5_TXDLY, dat_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT67_TUNE, MSDC_EMMC50_PAD_DAT6_TXDLY, dat_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT67_TUNE, MSDC_EMMC50_PAD_DAT7_TXDLY, dat_tx);
	*/

	//1    Step1 : Tuning Cmd Path
	//autok_param_update(TUNE_CKGEN_MSDC_DLY_SEL, i,p_autok_tune_res);
	MSDC_LOG(MSG_LVL_ERR,
			"[AUTOK]Step1.Optimised CMD Pad Data Delay Sel opcode = %d \r\n", opcode);
	AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]CMD_EDGE \t CMD_RD_R_DLY1~2 \r\n");

	//MsdcDumpTotalRegister();

	x_memset(&uCmdInfo, 0, sizeof(struct AUTOK_REF_INFO));
	uCmdEdge = 0;
	do {
		pBdInfo = (struct AUTOK_SCAN_RES*) & (uCmdInfo.scan_info[uCmdEdge]);
		msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);   //IOCON[1],command response sample
		RawData64 = 0LL;
		for (j = 0; j < 64; j++) {
			msdc_autok_adjust_paddly(host, &j, CMD_PAD_RDLY);
			for(k = 0; k < AUTOK_CMD_TIMES / 2; k++) {
				ret = autok_send_tune_cmd(host, opcode, TUNE_CMD);
                #if CATH_SIGNEL
				MSDC_LOG(MSG_LVL_ERR,"--Catch Signel, exit now \n");
				goto AUTOK_DONE;
				#endif
				if ((ret & TUNE_CMD_ERR_MASK) != 0)	{
					autok_send_tune_cmd(host, 12, 0);
					RawData64 |= (unsigned long long)(1LL << j);
					break;
				}
			}
		}
		score = autok_simple_score64(tune_result_str64, RawData64);
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
				"[AUTOK][%d] %d \t %d \t %s\r\n",
				i, uCmdEdge, score, tune_result_str64);
		if ((ret = autok_check_scan_res64(RawData64, pBdInfo))) {
			goto AUTOK_DONE;
		}
		AUTOK_DBGPRINT(AUTOK_DBG_RES,
				"[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n",
				uCmdEdge, pBdInfo->bd_cnt, pBdInfo->fbd_cnt);

		for (i = 0; i < BD_MAX_CNT; i++) {
			AUTOK_DBGPRINT(AUTOK_DBG_RES,
				       "[AUTOK]BoundInf[%d]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n", i,
				       pBdInfo->bd_info[i].Bound_Start, pBdInfo->bd_info[i].Bound_End,
				       pBdInfo->bd_info[i].Bound_width, pBdInfo->bd_info[i].is_fullbound);
		}

		uCmdEdge ^= 0x1;
	} while (uCmdEdge);

	if (autok_pad_dly_sel(&uCmdInfo) == 0) {
		autok_param_update(CMD_EDGE, uCmdInfo.opt_edge_sel, p_autok_tune_res);
		autok_paddly_update(CMD_PAD_RDLY, uCmdInfo.opt_dly_cnt, p_autok_tune_res);
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
				"[AUTOK]================CMD TUNE Result================\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
				"[AUTOK]Sample Edge Sel: %d, Delay Cnt Sel:%d, cycle cnt %d \r\n",
				uCmdInfo.opt_edge_sel, uCmdInfo.opt_dly_cnt, uCmdInfo.cycle_cnt);
	} else {
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
				"[AUTOK][Error]=============Analysis Failed!!=======================\r\n");
	}
	//p_autok_tune_res[EMMC50_DS_Z_DLY1] = uCmdInfo.cycle_cnt / 4;
	//p_autok_tune_res[EMMC50_DS_Z_DLY1_SEL] = 1;
	p_autok_tune_res[EMMC50_DS_ZDLY_DLY] = 20;//uCmdInfo.cycle_cnt / 2;

    //1    Step2 : Tuning DS Clk Path-ZCLK
    opcode = 17;

#if HS400_DDLSEL_SEPARATE_TUNING
HS400_RETUNE_STEP2:
#endif
	/*
    autok_tuning_parameter_init(host,p_autok_tune_res);
	MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step2.Scan DS Clk Pad Delay\r\n");
	AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]DS_ZDLY_DLY DS_ZCLK_DLY1~2 \r\n");
    x_memset(&uDatInfo,0,sizeof(struct AUTOK_REF_INFO));
    pBdInfo = (struct AUTOK_SCAN_RES*)&(uDatInfo.scan_info[0]);
    RawData64 = 0LL;

	#if HS400_REDUCE_DS_TUNE_TIME
	u4valid_window = 0;
	#endif

    for(j=0;j<32;j++){
       msdc_autok_adjust_paddly(host, &j,DS_PAD_RDLY);
        for(k=0;k<AUTOK_CMD_TIMES/4;k++){
			ret = autok_send_tune_cmd(host, opcode, TUNE_DATA);
            if((ret& TUNE_CMD_ERR_MASK) != 0){
                MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Error Autok CMD Failed while tune DS Delay\r\n");
                goto AUTOK_DONE;
            }else if((ret & TUNE_DAT_ERR_MASK) != 0){
                RawData64 |= (unsigned long long )(1LL << j);
                break;
            }
        }
		#if HS400_REDUCE_DS_TUNE_TIME
		//find the valid window
		if (0 == (RawData64 & (1LL << j)))
		{
			u4valid_window ++;//it's ooo
		}
		else
		{
			if (u4valid_window > 0)
			{
				RawData64 |= (unsigned long long )((0xFFFFFFFFFFFFFFFF) << j);
                break;
			}
		}
		#endif
    }
	RawData64 |= 0xffffffff00000000;
    score = autok_simple_score64(tune_result_str64,RawData64);
	*/
		/*check if the window is improved or be worse*/
	/*
	#if HS400_DDLSEL_SEPARATE_TUNING
	if(uTuneSepFlag == 0) {
		DS_score1 = score;
	}
	else {
		DS_score2 = score;

		if (DS_score2 < DS_score1) {
			//get worse, keep the original settings

			//restore each data pin delay to keep the raw DS window size.
			for(i=0; i<8; i++){
				p_autok_tune_res[DAT_RD_D0_DLY1+i]= 0;
				p_autok_tune_res[DAT_RD_D_DLY1_SEL] = 0;
				p_autok_tune_res[DAT_RD_D0_DLY2+i] = 0;
				p_autok_tune_res[DAT_RD_D_DLY2_SEL] = 0;
			}
			p_autok_tune_res[DAT_RD_D_DDL_SEL] = 0;
			AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]##WARNING! the window get worse, keep the original settigns.%d -> %d\r\n",DS_score1,DS_score2);
			goto HS400_TUNING_END;
		}
	}
	#endif
    #if HS400_DDLSEL_SEPARATE_TUNING
	if (score > AUTOK_DATA_PIN_SEPARATE_TUNE_LEVEL)
	{
	    MSDC_LOG(MSG_LVL_ERR,"\n==The DLY1 Window is good %d, Do Not Separate Tuning,Current level %d ==\n",score,AUTOK_DATA_PIN_SEPARATE_TUNE_LEVEL);
		uTuneSepFlag = 1;
	}
    #endif
    AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK][%d] %d \t %d \t %s\r\n",i,uCmdEdge, score, tune_result_str64);

    if((ret = autok_check_scan_res64(RawData64,pBdInfo)))
         goto AUTOK_DONE;
	AUTOK_DBGPRINT(AUTOK_DBG_RES,
		       "[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n", uCmdEdge,
		       pBdInfo->bd_cnt, pBdInfo->fbd_cnt);

	for (i = 0; i < BD_MAX_CNT; i++) {
		AUTOK_DBGPRINT(AUTOK_DBG_RES,
			       "[AUTOK]BoundInf[%d]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n", i,
			       pBdInfo->bd_info[i].Bound_Start, pBdInfo->bd_info[i].Bound_End,
			       pBdInfo->bd_info[i].Bound_width, pBdInfo->bd_info[i].is_fullbound);
     }

    if(autok_ds_dly_sel(pBdInfo,&uDatDly) == 0){
        autok_paddly_update(DS_PAD_RDLY,uDatDly,p_autok_tune_res);
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
			       "[AUTOK]================DS ZDLY1-2 Result================\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]Sample Delay Cnt Sel:%d\r\n", uDatDly);
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]DLY1 %d Sel %d, DLY2 %d, Sel %d\r\n",
			p_autok_tune_res[EMMC50_DS_Z_DLY1],p_autok_tune_res[EMMC50_DS_Z_DLY1_SEL],
			p_autok_tune_res[EMMC50_DS_Z_DLY2],p_autok_tune_res[EMMC50_DS_Z_DLY2_SEL]);

    }else{
        AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK][Error]=============Analysis Failed!!=======================\r\n");
		//restore each data pin delay to keep the raw DS window size.
		for(i=0; i<8; i++){
			p_autok_tune_res[DAT_RD_D0_DLY1+i]= 0;
			p_autok_tune_res[DAT_RD_D_DLY1_SEL] = 0;
			p_autok_tune_res[DAT_RD_D0_DLY2+i] = 0;
			p_autok_tune_res[DAT_RD_D_DLY2_SEL] = 0;
		}
		p_autok_tune_res[DAT_RD_D_DDL_SEL] = 0;
    }
	#if HS400_DSCLK_NEED_TUNING
	//1    Step3 : Tuning DS  Clk Path-ZDLY
    //p_autok_tune_res[EMMC50_DS_Z_DLY1]= 8;
    //p_autok_tune_res[EMMC50_DS_Z_DLY1_SEL] = 1;
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step3.Scan DS(ZDLY) Clk Pad Delay\r\n");
    AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]DS_ZDLY_DLY DS_ZCLK_DLY1~2 \r\n");
    pBdInfo = (struct AUTOK_SCAN_RES*)&(uDatInfo.scan_info[1]);
    RawData = 0;

	#if HS400_REDUCE_DS_TUNE_TIME
	u4valid_window = 0;
	#endif
    for(j=0;j<32;j++){
		msdc_autok_adjust_param(host, EMMC50_DS_ZDLY_DLY, &j, AUTOK_WRITE);
        for(k=0;k<AUTOK_CMD_TIMES/4;k++){
            ret = autok_send_tune_cmd(host,opcode,TUNE_CMD);  //CMD17
            if((ret& TUNE_CMD_ERR_MASK) != 0){
                MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Error Autok CMD Failed while tune DS(ZDLY) Delay\r\n");
                goto AUTOK_DONE;
            }else if((ret& TUNE_DAT_ERR_MASK) != 0){
                RawData |= (unsigned int)(1 << j);
                break;
            }
		}

		#if HS400_REDUCE_DS_TUNE_TIME
		//find the valid window
		if (0 == (RawData & (1 << j)))
		{
			u4valid_window ++;//it's ooo
		}
		else
		{
			if (u4valid_window > 0)
			{
				RawData |= (unsigned int)((0xFFFFFFFF) << j);
				break;
			}
		}
		#endif

    }
    score = autok_simple_score(tune_result_str64,RawData);

    AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK][%d] %d \t %d \t %s\r\n",i,uCmdEdge, score, tune_result_str64);
    if((ret = autok_check_scan_res64(RawData,pBdInfo)))
         goto AUTOK_DONE;
	AUTOK_DBGPRINT(AUTOK_DBG_RES,
		       "[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n", uCmdEdge,
		       pBdInfo->bd_cnt, pBdInfo->fbd_cnt);

	for (i = 0; i < BD_MAX_CNT; i++) {
		AUTOK_DBGPRINT(AUTOK_DBG_RES,
				"[AUTOK]BoundInf[%d]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n", i,
				pBdInfo->bd_info[i].Bound_Start, pBdInfo->bd_info[i].Bound_End,
				pBdInfo->bd_info[i].Bound_width, pBdInfo->bd_info[i].is_fullbound);
	}

    if(autok_ds_dly_sel(pBdInfo,&uDatDly) == 0){
		autok_param_update(EMMC50_DS_ZDLY_DLY,uDatDly,p_autok_tune_res);
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
				"[AUTOK]================DS DLY3 Tune Result ================\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]Sample ZDelay Cnt Sel:%d\r\n", uDatDly);
	}else{
        AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK][Error]=============Analysis Failed!!=======================\r\n");
		//restore each data pin delay to keep the raw DS window size.
		for(i=0; i<8; i++){
			p_autok_tune_res[DAT_RD_D0_DLY1+i]= 0;
			p_autok_tune_res[DAT_RD_D_DLY1_SEL] = 0;
			p_autok_tune_res[DAT_RD_D0_DLY2+i] = 0;
			p_autok_tune_res[DAT_RD_D_DLY2_SEL] = 0;
		}
		p_autok_tune_res[EMMC50_DS_ZDLY_DLY] = 20;
		p_autok_tune_res[DAT_RD_D_DDL_SEL] = 0;
    }
	#endif
	*/
	#if HS400_DDLSEL_SEPARATE_TUNING
    if (uTuneSepFlag == 0)
    {
        uTuneSepFlag = 1;
        //opcode = 17;
        opcode = 8;
		/*
        uDatDly = p_autok_tune_res[EMMC50_DS_Z_DLY1] + p_autok_tune_res[EMMC50_DS_Z_DLY2];
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]EMMC50_DS_Z_DLY2=%d, EMMC50_DS_Z_DLY1=%d\n",p_autok_tune_res[EMMC50_DS_Z_DLY2],p_autok_tune_res[EMMC50_DS_Z_DLY1]);
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]uDatDly=%d\n",uDatDly);
		*/
    	p_autok_tune_res[DAT_RD_D_DDL_SEL] = 1;
        autok_tuning_parameter_init(host, p_autok_tune_res);
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step4.Scan Per-bit DATA Pad Delay\r\n");
        for (i = 0; i < 8; i++) {
            msdc_autok_adjust_paddly(host, &i, DS_PAD_RDLY_SEP_EN);
			#if HS400_REDUCE_DS_TUNE_TIME
			u4valid_window = 0;
			#endif
            RawData64 = 0LL;
			for (j = 0; j < 32; j++) {
				msdc_autok_adjust_paddly(host, &j, DS_PAD_RDLY_SEP);
				for (k = 0; k < AUTOK_CMD_TIMES / 4; k++) {
					ret = autok_send_tune_cmd(host, opcode, TUNE_DATA);
					if ((ret& TUNE_CMD_ERR_MASK) != 0) {
						MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Error Autok CMD Failed while tune DS Delay\r\n");
						goto AUTOK_DONE;
					} else if ((ret & TUNE_DAT_ERR_MASK) != 0) {
						RawData64 |= (unsigned long long )(1LL << j);
						break;
					}
				}

				#if HS400_REDUCE_DS_TUNE_TIME
				//find the valid window
				if (0 == (RawData64 & (1LL << j))) {
					u4valid_window ++;//it's ooo
				} else {
					if (u4valid_window > 0)	{
						RawData64 |= (unsigned long long )((0xFFFFFFFFFFFFFFFF) << j);
						break;
					}
				}
				#endif
			}
			RawData64 |= 0xffffffff00000000;
			score = autok_simple_score64(tune_result_str64, RawData64);

			uDatDly_sep[i] = score;
			if (uDatDly_sep[i] < uDatDly)
				uDatDly = uDatDly_sep[i];
			AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] %d \t %d \t %s\r\n",
					i, uCmdEdge, score, tune_result_str64);
        }

        for (i = 0; i < 8; i++) {
            uDatDly_sep[i] = uDatDly_sep[i] - uDatDly  + 1; //add more delay to avoid NG window
            MSDC_LOG(MSG_LVL_ERR, "uDatDly_sep[%d]=%d \n", i, uDatDly_sep[i]);
            p_autok_tune_res[DAT_RD_D0_DLY1 + i]= uDatDly_sep[i] & 0x1f;
            p_autok_tune_res[DAT_RD_D_DLY1_SEL] = 1;
            if (uDatDly > 0x1f) {
                p_autok_tune_res[DAT_RD_D0_DLY2+i] = (unsigned char)uDatDly_sep[i] - 0x1f;
                p_autok_tune_res[DAT_RD_D_DLY2_SEL] = 1;
            }
        }

		autok_tuning_parameter_init(host, p_autok_tune_res);
		MSDC_LOG(MSG_LVL_ERR, "[AUTOK]Step2.Scan DS Clk Pad Delay\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]DS_ZDLY_DLY DS_ZCLK_DLY1~2 \r\n");
		x_memset(&uDatInfo, 0, sizeof(struct AUTOK_REF_INFO));
		pBdInfo = (struct AUTOK_SCAN_RES*) & (uDatInfo.scan_info[0]);
		RawData64 = 0LL;

		#if HS400_REDUCE_DS_TUNE_TIME
		u4valid_window = 0;
		#endif

		for (j = 0; j < 32; j++) {
			msdc_autok_adjust_paddly(host, &j,DS_PAD_RDLY);
			for(k = 0; k < AUTOK_CMD_TIMES / 4; k++) {
				ret = autok_send_tune_cmd(host, opcode, TUNE_DATA);
				if ((ret & TUNE_CMD_ERR_MASK) != 0) {
					MSDC_LOG(MSG_LVL_ERR, "[AUTOK]Error Autok CMD Failed while tune DS Delay\r\n");
					goto AUTOK_DONE;
				} else if ((ret & TUNE_DAT_ERR_MASK) != 0) {
					RawData64 |= (unsigned long long )(1LL << j);
					break;
				}
			}

			#if HS400_REDUCE_DS_TUNE_TIME
			//find the valid window
			if (0 == (RawData64 & (1LL << j))) {
				u4valid_window ++;//it's ooo
			} else {
				if (u4valid_window > 0)	{
					RawData64 |= (unsigned long long )((0xFFFFFFFFFFFFFFFF) << j);
					break;
				}
			}
			#endif
		}
		RawData64 |= 0xffffffff00000000;
		score = autok_simple_score64(tune_result_str64,RawData64);

		AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK][%d] %d \t %d \t %s\r\n",
				i, uCmdEdge, score, tune_result_str64);

		if ((ret = autok_check_scan_res64(RawData64,pBdInfo)))
			 goto AUTOK_DONE;
		AUTOK_DBGPRINT(AUTOK_DBG_RES,
				"[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n", uCmdEdge,
				pBdInfo->bd_cnt, pBdInfo->fbd_cnt);

		for (i = 0; i < BD_MAX_CNT; i++) {
			AUTOK_DBGPRINT(AUTOK_DBG_RES,
					"[AUTOK]BoundInf[%d]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n", i,
					pBdInfo->bd_info[i].Bound_Start, pBdInfo->bd_info[i].Bound_End,
					pBdInfo->bd_info[i].Bound_width, pBdInfo->bd_info[i].is_fullbound);
		}

		if (autok_ds_dly_sel(pBdInfo, &uDatDly) == 0) {
			autok_paddly_update(DS_PAD_RDLY, uDatDly, p_autok_tune_res);
			AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
					"[AUTOK]================DS ZDLY1-2 Result================\r\n");
			AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]Sample Delay Cnt Sel:%d\r\n", uDatDly);
			AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]DLY1 %d Sel %d, DLY2 %d, Sel %d\r\n",
					p_autok_tune_res[EMMC50_DS_Z_DLY1], p_autok_tune_res[EMMC50_DS_Z_DLY1_SEL],
					p_autok_tune_res[EMMC50_DS_Z_DLY2], p_autok_tune_res[EMMC50_DS_Z_DLY2_SEL]);
		} else {
			AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
					"[AUTOK][Error]=============Analysis Failed!!=======================\r\n");
			/* restore each data pin delay to keep the raw DS window size. */
			for (i = 0; i < 8; i++) {
				p_autok_tune_res[DAT_RD_D0_DLY1 + i]= 0;
				p_autok_tune_res[DAT_RD_D_DLY1_SEL] = 0;
				p_autok_tune_res[DAT_RD_D0_DLY2 + i] = 0;
				p_autok_tune_res[DAT_RD_D_DLY2_SEL] = 0;
			}
			p_autok_tune_res[DAT_RD_D_DDL_SEL] = 0;
		}

		p_autok_tune_res[EMMC50_DS_ZDLY_DLY] = (unsigned char)20;
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]Sample ZDelay Cnt Sel:%d\r\n", 20);

        //goto HS400_RETUNE_STEP2;
    }
	#endif

	//MsdcDumpTotalRegister();
HS400_TUNING_END:

    autok_tuning_parameter_init(host,p_autok_tune_res);

#if AUTOK_PARAM_DUMP_ENABLE
    autok_result_dump(host,p_autok_tune_res);
    autok_register_dump(host);
#endif
    if(res != NULL){
        memcpy((void*)res,(void*)p_autok_tune_res,sizeof(p_autok_tune_res)/sizeof(unsigned char));
    }
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Online Tune Alg Complete\r\n");

AUTOK_DONE:

	return ret;
}

/* online tuning for latch ck */
int autok_execute_tuning_latch_ck(msdc_cmd *host, unsigned int opcode,
	unsigned int latch_ck_initail_value)
{
	unsigned int ret = 0;
	unsigned int j = 0, k = 0;
	unsigned int latch = 0;

	MSDC_WRITE32(MSDC_INT, 0xffffffff);
	for (j = latch_ck_initail_value; j < 8; j += 1/*(host->hclk / host->sclk)*/) {
		MSDC_SET_FIELD(PATCH_BIT0, MSDC_PB0_INT_DAT_LATCH_CK_SEL, j);
		MSDC_GET_FIELD(PATCH_BIT0, MSDC_PB0_INT_DAT_LATCH_CK_SEL, latch);
		MSDC_LOG(MSG_LVL_ERR,"[AUTOK]LATCH CK = %d, opcode %d \r\n", latch,opcode);
		for (k = 0; k < AUTOK_CMD_TIMES ; k++) {
			ret = autok_send_tune_cmd(host, opcode, TUNE_LATCH_CK);
			if ((ret & TUNE_CMD_ERR_MASK) != 0) {
				MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Error Autok CMD Failed while tune LATCH CK\r\n");
				break;
			} else if ((ret & TUNE_DAT_ERR_MASK) != 0) {
				MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Error Autok  tune LATCH_CK error %d\r\n", j);
				break;
			}
		}
		if (ret == 0) {

			MSDC_LOG(MSG_LVL_ERR,"Set the Latch CK %d \n",j);
			MSDC_SET_FIELD(PATCH_BIT0, MSDC_PB0_INT_DAT_LATCH_CK_SEL, j);
			break;
		}
	}
	return j;
}
 /*online tuning for eMMC4.5(hs200)*/
int execute_online_tuning_hs200(msdc_cmd* host, unsigned char* res)
{
    int ret = 0;
    unsigned int uCmdEdge = 0;
    unsigned long long  RawData64 = 0LL;
    unsigned int score = 0;
    unsigned int i = 0,j = 0,k = 0;
    struct AUTOK_REF_INFO uCmdInfo;
    struct AUTOK_REF_INFO uDatInfo;
    struct AUTOK_SCAN_RES* pBdInfo;
    char tune_result_str64[65];
    unsigned char p_autok_tune_res[TUNING_PARAM_COUNT];
    unsigned int opcode = CMD21_SEND_TUNING_BLOCK;//CMD17_READ_SINGLE_BLOCK;
    unsigned int uDatDly = 0;
	unsigned int u4ClkTxDly = 0;


    autok_init_hs200(host);
    x_memset((void*)p_autok_tune_res, 0, sizeof(p_autok_tune_res)/sizeof(unsigned char));
    p_autok_tune_res[INT_DAT_LATCH_CK] = 3;//Need set proper latch clock for specific emmc(multi-block read),special kernel need 3

	//autok_write_param(host, TUNE_PAD_CLK_TXDLY,    (unsigned int)*res);

        //1    Step1 : Tuning Cmd Path
        //autok_param_update(TUNE_CKGEN_MSDC_DLY_SEL, i,p_autok_tune_res);
        autok_tuning_parameter_init(host,p_autok_tune_res);
		MSDC_SET_FIELD(PAD_TUNE, PAD_CLK_TXDLY, 5);//For setup time ,have to shift clock

        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step1.Optimised CMD Pad Data Delay Sel\r\n");
        AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]CMD_EDGE \t CMD_RD_R_DLY1~2 \r\n");
        x_memset(&uCmdInfo,0,sizeof(struct AUTOK_REF_INFO));
        uCmdEdge = 0;
        do{
            pBdInfo = (struct AUTOK_SCAN_RES*)&(uCmdInfo.scan_info[uCmdEdge]);
            msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
            RawData64 = 0LL;
            for(j=0;j<64;j++){
                msdc_autok_adjust_paddly(host, &j,CMD_PAD_RDLY);
                for(k=0;k<AUTOK_CMD_TIMES;k++){
				ret = autok_send_tune_cmd(host, opcode, TUNE_CMD);
                    if((ret& TUNE_CMD_ERR_MASK) != 0)
                    {
                        autok_send_cmd12(host);
                        RawData64 |= (unsigned long long )(1LL << j);
                        break;
                    }
                }
            }
            score = autok_simple_score64(tune_result_str64,RawData64);
            AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK][%d] %d \t %d \t %s\r\n",i,uCmdEdge, score, tune_result_str64);
            if((ret = autok_check_scan_res64(RawData64,pBdInfo))){
                goto AUTOK_DONE;
            }

		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
			       "[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n",
			       uCmdEdge, pBdInfo->bd_cnt, pBdInfo->fbd_cnt);

		for (i = 0; i < BD_MAX_CNT; i++) {
			AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
				       "[AUTOK]BoundInf[%d]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n", i,
				       pBdInfo->bd_info[i].Bound_Start, pBdInfo->bd_info[i].Bound_End,
				       pBdInfo->bd_info[i].Bound_width, pBdInfo->bd_info[i].is_fullbound);
		}

            uCmdEdge ^= 0x1;
        }while(uCmdEdge);
        if(autok_pad_dly_sel(&uCmdInfo) ==0){
            autok_param_update(CMD_EDGE,uCmdInfo.opt_edge_sel,p_autok_tune_res);
            autok_paddly_update(CMD_PAD_RDLY,uCmdInfo.opt_dly_cnt,p_autok_tune_res);
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
			       "[AUTOK]================[HS200]Tune CMD================\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]Sample Edge Sel: %d, Delay Cnt Sel:%d\r\n",
			       uCmdInfo.opt_edge_sel, uCmdInfo.opt_dly_cnt);
        }else{
            AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK][Error]=============Analysis Failed!!=======================\r\n");
        }
        //1 Step2 Tuning Data Path(Only Rising Edge Used)
		autok_tuning_parameter_init(host,p_autok_tune_res);
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step2.Optimised Dat Pad Data Delay Sel\r\n");
        AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]DAT_EDGE \t DAT_RD_R_DLY1~2 \r\n");
        x_memset(&uDatInfo,0,sizeof(struct AUTOK_REF_INFO));
        pBdInfo = (struct AUTOK_SCAN_RES*)&(uDatInfo.scan_info[0]);
        RawData64 = 0LL;
        for(j=0;j<64;j++){
           msdc_autok_adjust_paddly(host, &j,DAT_PAD_RDLY);
            for(k=0;k<AUTOK_CMD_TIMES/2;k++){
                ret = autok_send_tune_cmd(host,opcode,TUNE_DATA);
                if((ret & TUNE_CMD_ERR_MASK) != 0){
                    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Error Autok CMD Failed while tune Read,opcode %d \r\n",opcode);
                    goto AUTOK_DONE;
                }else if((ret& TUNE_DAT_ERR_MASK) != 0)
                {
                    RawData64 |= (unsigned long long )(1LL << j);
                    break;
                }
            }
        }
        score = autok_simple_score64(tune_result_str64,RawData64);
        AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK][%d] %d \t %d \t %s\r\n",i,0, score, tune_result_str64);
        if((ret = autok_check_scan_res64(RawData64,pBdInfo))){
            goto AUTOK_DONE;
        };
	AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
		       "[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n", 0,
		       pBdInfo->bd_cnt, pBdInfo->fbd_cnt);

	for (i = 0; i < BD_MAX_CNT; i++) {
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
			       "[AUTOK]BoundInf[%d]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n", i,
			       pBdInfo->bd_info[i].Bound_Start, pBdInfo->bd_info[i].Bound_End,
			       pBdInfo->bd_info[i].Bound_width, pBdInfo->bd_info[i].is_fullbound);
	}

        if(autok_pad_dly_sel_single_edge(pBdInfo,uCmdInfo.cycle_cnt,&uDatDly)==0){
            autok_paddly_update(DAT_PAD_RDLY,uDatDly,p_autok_tune_res);
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
			       "[AUTOK]================[HS200]Tune Data Rising Done================\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]Sample Edge Sel: 0, Delay Cnt Sel:%d\r\n",
			       uDatDly);
    }

    autok_tuning_parameter_init(host,p_autok_tune_res);


	/*    Step3 : Tuning LATCH CK  */
	opcode = 18;
	p_autok_tune_res[INT_DAT_LATCH_CK] = (unsigned char)autok_execute_tuning_latch_ck(host, opcode,p_autok_tune_res[INT_DAT_LATCH_CK]);

	MSDC_GET_FIELD(PAD_TUNE, PAD_CLK_TXDLY, u4ClkTxDly);

	MSDC_LOG(MSG_LVL_ERR,"==Latch CK tune val is %d ,CLK TX DLY %d \n",p_autok_tune_res[INT_DAT_LATCH_CK],u4ClkTxDly);
    #if AUTOK_PARAM_DUMP_ENABLE
    autok_result_dump(host,p_autok_tune_res);
    autok_register_dump(host);
    #endif
    if(res != NULL){
         memcpy((void*)res,(void*)p_autok_tune_res,sizeof(p_autok_tune_res)/sizeof(unsigned char));
    }

    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Online Tune Alg Complete\r\n");

AUTOK_DONE:
	return ret;
}


/*Tuning low clock frequency mode*/
int execute_online_tuning_HsMode(msdc_cmd* host, unsigned char* res)
{
    int ret = 0;
    unsigned int uCmdEdge = 0;
    unsigned long long  RawData64 = 0LL;
    unsigned int score = 0;
    unsigned int i = 0,j = 0,k = 0;
    struct AUTOK_REF_INFO uCmdInfo;
    struct AUTOK_REF_INFO uDatInfo;
    struct AUTOK_SCAN_RES* pBdInfo;
    char tune_result_str64[65];
    unsigned char p_autok_tune_res[TUNING_PARAM_COUNT];
    unsigned int opcode = 13;
    unsigned int uDatDly = 0;
	unsigned int u4ClkTxDly = 0;

	MSDC_LOG(MSG_LVL_ERR,"=============tuning_HsMode===============\n");


    g_msdc_pub_info.g_msdc_runing_autok = 1;
    autok_init_hs200(host);
    x_memset((void*)p_autok_tune_res, 0, sizeof(p_autok_tune_res)/sizeof(unsigned char));
    p_autok_tune_res[INT_DAT_LATCH_CK] = 1;//Need set proper latch clock for specific emmc(multi-block read),



        //1    Step1 : Tuning Cmd Path
        //autok_param_update(TUNE_CKGEN_MSDC_DLY_SEL, i,p_autok_tune_res);
        autok_tuning_parameter_init(host,p_autok_tune_res);
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step1.Optimised CMD Pad Data Delay Sel\r\n");
        AUTOK_DBGPRINT(MSG_LVL_ERR, "[AUTOK]CMD_EDGE \t CMD_RD_R_DLY1~2 \r\n");
        x_memset(&uCmdInfo,0,sizeof(struct AUTOK_REF_INFO));
        uCmdEdge = 0;
        do{
            pBdInfo = (struct AUTOK_SCAN_RES*)&(uCmdInfo.scan_info[uCmdEdge]);
            msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
            RawData64 = 0LL;
            for(j=0;j<64;j++){
                msdc_autok_adjust_paddly(host, &j,CMD_PAD_RDLY);
                for(k=0;k<AUTOK_CMD_TIMES;k++){
				ret = autok_send_tune_cmd(host, opcode, TUNE_CMD);
                    if((ret& TUNE_CMD_ERR_MASK) != 0)
                    {
                        autok_send_cmd12(host);
                        RawData64 |= (unsigned long long )(1LL << j);
                        break;
                    }
                }
            }
            score = autok_simple_score64(tune_result_str64,RawData64);
            AUTOK_DBGPRINT(MSG_LVL_ERR, "[AUTOK][%d] %d \t %d \t %s\r\n",i,uCmdEdge, score, tune_result_str64);
            if((ret = autok_check_scan_res64(RawData64,pBdInfo))){
                goto AUTOK_DONE;
            }

		AUTOK_DBGPRINT(MSG_LVL_ERR,
			       "[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n",
			       uCmdEdge, pBdInfo->bd_cnt, pBdInfo->fbd_cnt);

		for (i = 0; i < BD_MAX_CNT; i++) {
			AUTOK_DBGPRINT(MSG_LVL_ERR,
				       "[AUTOK]BoundInf[%d]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n", i,
				       pBdInfo->bd_info[i].Bound_Start, pBdInfo->bd_info[i].Bound_End,
				       pBdInfo->bd_info[i].Bound_width, pBdInfo->bd_info[i].is_fullbound);
		}

            uCmdEdge ^= 0x1;
        }while(uCmdEdge);
        if(autok_pad_dly_sel(&uCmdInfo) ==0){
            autok_param_update(CMD_EDGE,uCmdInfo.opt_edge_sel,p_autok_tune_res);
            autok_paddly_update(CMD_PAD_RDLY,uCmdInfo.opt_dly_cnt,p_autok_tune_res);
		AUTOK_DBGPRINT(MSG_LVL_ERR,
			       "[AUTOK]================Analysis Result[HS Mode]================\r\n");
		AUTOK_DBGPRINT(MSG_LVL_ERR, "[AUTOK]Sample Edge Sel: %d, Delay Cnt Sel:%d\r\n",
			       uCmdInfo.opt_edge_sel, uCmdInfo.opt_dly_cnt);
        }else{
            AUTOK_DBGPRINT(MSG_LVL_ERR, "[AUTOK][Error]=============Analysis Failed!!=======================\r\n");
        }
        //1 Step2 Tuning Data Path(Only Rising Edge Used)
		opcode = 17;
		autok_tuning_parameter_init(host,p_autok_tune_res);
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step2.Optimised Dat Pad Data Delay Sel\r\n");
        AUTOK_DBGPRINT(MSG_LVL_ERR, "[AUTOK]DAT_EDGE \t DAT_RD_R_DLY1~2 \r\n");
        x_memset(&uDatInfo,0,sizeof(struct AUTOK_REF_INFO));
        pBdInfo = (struct AUTOK_SCAN_RES*)&(uDatInfo.scan_info[0]);
        RawData64 = 0LL;
        for(j=0;j<64;j++){
           msdc_autok_adjust_paddly(host, &j,DAT_PAD_RDLY);
            for(k=0;k<AUTOK_CMD_TIMES/2;k++){
                ret = autok_send_tune_cmd(host,opcode,TUNE_DATA);
                if((ret & TUNE_CMD_ERR_MASK) != 0){
                    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Error Autok CMD Failed while tune Read,opcode %d \r\n",opcode);
                    goto AUTOK_DONE;
                }else if((ret& TUNE_DAT_ERR_MASK) != 0)
                {
                    RawData64 |= (unsigned long long )(1LL << j);
                    break;
                }
            }
        }
        score = autok_simple_score64(tune_result_str64,RawData64);
        AUTOK_DBGPRINT(MSG_LVL_ERR, "[AUTOK][%d] %d \t %d \t %s\r\n",i,0, score, tune_result_str64);
        if((ret = autok_check_scan_res64(RawData64,pBdInfo))){
            goto AUTOK_DONE;
        };
	AUTOK_DBGPRINT(MSG_LVL_ERR,
		       "[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n", 0,
		       pBdInfo->bd_cnt, pBdInfo->fbd_cnt);

	for (i = 0; i < BD_MAX_CNT; i++) {
		AUTOK_DBGPRINT(MSG_LVL_ERR,
			       "[AUTOK]BoundInf[%d]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n", i,
			       pBdInfo->bd_info[i].Bound_Start, pBdInfo->bd_info[i].Bound_End,
			       pBdInfo->bd_info[i].Bound_width, pBdInfo->bd_info[i].is_fullbound);
	}

        if(autok_pad_dly_sel_single_edge(pBdInfo,uCmdInfo.cycle_cnt,&uDatDly)==0){
            autok_paddly_update(DAT_PAD_RDLY,uDatDly,p_autok_tune_res);
		AUTOK_DBGPRINT(MSG_LVL_ERR,
			       "[AUTOK]================Analysis Result[HS Mode]================\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]Sample Edge Sel: 0, Delay Cnt Sel:%d\r\n",
			       uDatDly);
    }

    autok_tuning_parameter_init(host,p_autok_tune_res);


	/*    Step3 : Tuning LATCH CK  */

	//p_autok_tune_res[INT_DAT_LATCH_CK] = autok_execute_tuning_latch_ck(host, opcode,0);

	MSDC_GET_FIELD(PAD_TUNE, PAD_CLK_TXDLY, u4ClkTxDly);

	MSDC_LOG(MSG_LVL_ERR,"==Latch CK tune val is %d ,CLK TX DLY %d \n",p_autok_tune_res[INT_DAT_LATCH_CK],u4ClkTxDly);
    autok_result_dump(host,p_autok_tune_res);
    #if AUTOK_PARAM_DUMP_ENABLE
    autok_register_dump(host);
    #endif
    if(res != NULL){
         memcpy((void*)res,(void*)p_autok_tune_res,sizeof(p_autok_tune_res)/sizeof(unsigned char));
    }
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Online Tune Alg Complete\r\n");

AUTOK_DONE:
	g_msdc_pub_info.g_msdc_runing_autok = 0;
	return ret;
}


/* online tuning for SDIO/SD*/
int execute_online_tuning(msdc_cmd* host, unsigned char* res)
{
	int ret = 0;
	unsigned int uCmdEdge = 0;
	unsigned long long  RawData64 = 0LL;
	unsigned int score = 0;
	unsigned int i = 0,j = 0,k = 0;
	struct AUTOK_REF_INFO uCmdInfo;
	struct AUTOK_REF_INFO uDatInfo;
	struct AUTOK_SCAN_RES* pBdInfo;
	char tune_result_str64[65];
	unsigned char p_autok_tune_res[TUNING_PARAM_COUNT];
	unsigned int opcode = 17; //USE cmd17, cmd19 not support now.
	unsigned int uDatDly = 0;
	unsigned int u4ClkTxDly = 0;


	g_msdc_pub_info.g_msdc_runing_autok = 1;
	autok_init_hs200(host);
	x_memset((void*)p_autok_tune_res, 0, sizeof(p_autok_tune_res)/sizeof(unsigned char));
	p_autok_tune_res[INT_DAT_LATCH_CK] = 3;//Need set proper latch clock for specific emmc(multi-block read),special kernel need 3


		//1    Step1 : Tuning Cmd Path
		//autok_param_update(TUNE_CKGEN_MSDC_DLY_SEL, i,p_autok_tune_res);
		autok_tuning_parameter_init(host,p_autok_tune_res);
		MSDC_SET_FIELD(PAD_TUNE, PAD_CLK_TXDLY, 5);//For setup time ,have to shift clock

		MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step1.Optimised CMD Pad Data Delay Sel\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]CMD_EDGE \t CMD_RD_R_DLY1~2 \r\n");
		x_memset(&uCmdInfo,0,sizeof(struct AUTOK_REF_INFO));
		uCmdEdge = 0;
		do{
			pBdInfo = (struct AUTOK_SCAN_RES*)&(uCmdInfo.scan_info[uCmdEdge]);
			msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
			RawData64 = 0LL;
			for(j=0;j<64;j++){
				msdc_autok_adjust_paddly(host, &j,CMD_PAD_RDLY);
				for(k=0;k<AUTOK_CMD_TIMES;k++){
				ret = autok_send_tune_cmd(host, opcode, TUNE_CMD);
					if((ret& TUNE_CMD_ERR_MASK) != 0)
					{
						autok_send_cmd12(host);
						RawData64 |= (unsigned long long )(1LL << j);
						break;
					}
				}
			}
			score = autok_simple_score64(tune_result_str64,RawData64);
			AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] %d \t %d \t %s\r\n",i,uCmdEdge, score, tune_result_str64);
			if((ret = autok_check_scan_res64(RawData64,pBdInfo))){
				goto AUTOK_DONE;
			}

		AUTOK_DBGPRINT(AUTOK_DBG_RES,
				   "[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n",
				   uCmdEdge, pBdInfo->bd_cnt, pBdInfo->fbd_cnt);

		for (i = 0; i < BD_MAX_CNT; i++) {
			AUTOK_DBGPRINT(AUTOK_DBG_RES,
					   "[AUTOK]BoundInf[%d]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n", i,
					   pBdInfo->bd_info[i].Bound_Start, pBdInfo->bd_info[i].Bound_End,
					   pBdInfo->bd_info[i].Bound_width, pBdInfo->bd_info[i].is_fullbound);
		}

			uCmdEdge ^= 0x1;
		}while(uCmdEdge);
		if(autok_pad_dly_sel(&uCmdInfo) ==0){
			autok_param_update(CMD_EDGE,uCmdInfo.opt_edge_sel,p_autok_tune_res);
			autok_paddly_update(CMD_PAD_RDLY,uCmdInfo.opt_dly_cnt,p_autok_tune_res);
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
				   "[AUTOK]================[SDR104]Tune CMD================\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]Sample Edge Sel: %d, Delay Cnt Sel:%d\r\n",
				   uCmdInfo.opt_edge_sel, uCmdInfo.opt_dly_cnt);
		}else{
			AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK][Error]=============Analysis Failed!!=======================\r\n");
		}
		//1 Step2 Tuning Data Path(Only Rising Edge Used)
		autok_tuning_parameter_init(host,p_autok_tune_res);
		MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step2.Optimised Dat Pad Data Delay Sel\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]DAT_EDGE \t DAT_RD_R_DLY1~2 \r\n");
		x_memset(&uDatInfo,0,sizeof(struct AUTOK_REF_INFO));
		pBdInfo = (struct AUTOK_SCAN_RES*)&(uDatInfo.scan_info[0]);
		RawData64 = 0LL;
		for(j=0;j<64;j++){
		   msdc_autok_adjust_paddly(host, &j,DAT_PAD_RDLY);
			for(k=0;k<AUTOK_CMD_TIMES/2;k++){
				ret = autok_send_tune_cmd(host,opcode,TUNE_DATA);
				if((ret & TUNE_CMD_ERR_MASK) != 0){
					MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Error Autok CMD Failed while tune Read,opcode %d \r\n",opcode);
					goto AUTOK_DONE;
				}else if((ret& TUNE_DAT_ERR_MASK) != 0)
				{
					RawData64 |= (unsigned long long )(1LL << j);
					break;
				}
			}
		}
		score = autok_simple_score64(tune_result_str64,RawData64);
		AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] %d \t %d \t %s\r\n",i,0, score, tune_result_str64);
		if((ret = autok_check_scan_res64(RawData64,pBdInfo))){
			goto AUTOK_DONE;
		};
	AUTOK_DBGPRINT(AUTOK_DBG_RES,
			   "[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n", 0,
			   pBdInfo->bd_cnt, pBdInfo->fbd_cnt);

	for (i = 0; i < BD_MAX_CNT; i++) {
		AUTOK_DBGPRINT(AUTOK_DBG_RES,
				   "[AUTOK]BoundInf[%d]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n", i,
				   pBdInfo->bd_info[i].Bound_Start, pBdInfo->bd_info[i].Bound_End,
				   pBdInfo->bd_info[i].Bound_width, pBdInfo->bd_info[i].is_fullbound);
	}

		if(autok_pad_dly_sel_single_edge(pBdInfo,uCmdInfo.cycle_cnt,&uDatDly)==0){
			autok_paddly_update(DAT_PAD_RDLY,uDatDly,p_autok_tune_res);
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR,
				   "[AUTOK]================[SDR104]Tune Data Rising Only================\r\n");
		AUTOK_DBGPRINT(AUTOK_DBG_ERROR, "[AUTOK]Sample Edge Sel: 0, Delay Cnt Sel:%d\r\n",
				   uDatDly);
	}

	autok_tuning_parameter_init(host,p_autok_tune_res);


	/*	  Step3 : Tuning LATCH CK  */
	opcode = 18;
	p_autok_tune_res[INT_DAT_LATCH_CK] = (unsigned char)autok_execute_tuning_latch_ck(host, opcode,p_autok_tune_res[INT_DAT_LATCH_CK]);

	MSDC_GET_FIELD(PAD_TUNE, PAD_CLK_TXDLY, u4ClkTxDly);

	MSDC_LOG(MSG_LVL_ERR,"==Latch CK tune val is %d ,CLK TX DLY %d \n",p_autok_tune_res[INT_DAT_LATCH_CK],u4ClkTxDly);
#if AUTOK_PARAM_DUMP_ENABLE
	autok_result_dump(host,p_autok_tune_res);
	autok_register_dump(host);
#endif
	if(res != NULL){
		 memcpy((void*)res,(void*)p_autok_tune_res,sizeof(p_autok_tune_res)/sizeof(unsigned char));
	}

	MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Online Tune Alg Complete\r\n");

	AUTOK_DONE:
	g_msdc_pub_info.g_msdc_runing_autok = 0;

	return ret;
}

int execute_online_tuning_stress(msdc_cmd* host)
{
    int ret = 0;
    unsigned int uCmdEdge = 0;
    unsigned int uDatEdge = 0;
    unsigned long long  RawData64 = 0LL;
    unsigned int score = 0;
    unsigned int i,j,k;
    struct AUTOK_REF_INFO uCmdInfo;
    struct AUTOK_REF_INFO uDatInfo;
    struct AUTOK_SCAN_RES* pBdInfo;
    char tune_result_str64[65];
    unsigned char p_autok_tune_res[TUNING_PARAM_COUNT];

	g_msdc_pub_info.g_msdc_runing_autok = 1;
    autok_init_sdr104(host);
    x_memset((void*)p_autok_tune_res, 0, sizeof(p_autok_tune_res)/sizeof(unsigned char));

    //1 Step1. CMD Path Optimised Delay Count
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step1.Optimised CMD Pad Data Delay Sel\r\n");
    AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]CMD_EDGE \t CMD_RD_R_DLY1~2 \r\n");
    for(i=0;i<32;i++){
        msdc_autok_adjust_param(host, TUNE_CKGEN_MSDC_DLY_SEL, &i, AUTOK_WRITE);
        x_memset(&uCmdInfo,0,sizeof(struct AUTOK_REF_INFO));
        uCmdEdge = 0;
        do{
            pBdInfo = (struct AUTOK_SCAN_RES*)&(uCmdInfo.scan_info[uCmdEdge]);
             msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
             RawData64 = 0LL;
             for(j=0;j<64;j++){
                msdc_autok_adjust_paddly(host, &j,CMD_PAD_RDLY);
                 for(k=0;k<AUTOK_CMD_TIMES;k++){
					ret = autok_send_tune_cmd(host, MMC_SEND_TUNING_BLOCK, TUNE_CMD);
					if ((ret & TUNE_CMD_ERR_MASK) != 0) {
                         RawData64 |= (unsigned long long )(1LL << j);
                         break;
                     }
                 }
             }
             score = autok_simple_score64(tune_result_str64,RawData64);
             AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] %d \t %d \t %s\r\n",i,uCmdEdge, score, tune_result_str64);
            /*get Boundary info*/
            if((ret = autok_check_scan_res64(RawData64,pBdInfo))){
                goto AUTOK_DONE;
            };

			AUTOK_DBGPRINT(AUTOK_DBG_RES,
				       "[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n",
				       uCmdEdge, pBdInfo->bd_cnt, pBdInfo->fbd_cnt);
			AUTOK_DBGPRINT(AUTOK_DBG_RES,
				       "[AUTOK]BoundInf[0]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n",
				       pBdInfo->bd_info[0].Bound_Start,
				       pBdInfo->bd_info[0].Bound_End,
				       pBdInfo->bd_info[0].Bound_width,
				       pBdInfo->bd_info[0].is_fullbound);
			AUTOK_DBGPRINT(AUTOK_DBG_RES,
				       "[AUTOK]BoundInf[1]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n",
				       pBdInfo->bd_info[1].Bound_Start,
				       pBdInfo->bd_info[1].Bound_End,
				       pBdInfo->bd_info[1].Bound_width,
				       pBdInfo->bd_info[1].is_fullbound);
			AUTOK_DBGPRINT(AUTOK_DBG_RES,
				       "[AUTOK]BoundInf[2]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n",
				       pBdInfo->bd_info[2].Bound_Start,
				       pBdInfo->bd_info[2].Bound_End,
				       pBdInfo->bd_info[2].Bound_width,
				       pBdInfo->bd_info[2].is_fullbound);

            uCmdEdge ^= 0x1;
        }while(uCmdEdge);

        autok_pad_dly_sel(&uCmdInfo);

		AUTOK_DBGPRINT(AUTOK_DBG_RES,
			       "[AUTOK]================Analysis Result[SD(IO)]===============\r\n");
        AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]Sample Edge Sel: %d, Delay Cnt Sel:%d\r\n",
                uCmdInfo.opt_edge_sel,uCmdInfo.opt_dly_cnt);
    }
	i = 0;
	msdc_autok_adjust_param(host, CKGEN_MSDC_DLY_SEL, &i, AUTOK_WRITE);
    //1 Step2. DATA Path Optimised Delay Count
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step2.Optimised CMD Pad Data Delay Sel\r\n");
    AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]CMD_EDGE \t CMD_RD_R_DLY1~2 \r\n");
    uCmdEdge = 0;
    for(i=0;i<32;i++){
        msdc_autok_adjust_param(host, TUNE_CKGEN_MSDC_DLY_SEL, &i, AUTOK_WRITE);
        x_memset(&uDatInfo,0,sizeof(struct AUTOK_REF_INFO));
        uDatEdge = 0;
        do{
            pBdInfo = (struct AUTOK_SCAN_RES*)&(uDatInfo.scan_info[uDatEdge]);
             msdc_autok_adjust_param(host, RD_FIFO_EDGE, &uDatEdge, AUTOK_WRITE);
             RawData64 = 0LL;
             for(j=0;j<64;j++){
               msdc_autok_adjust_paddly(host, &j,DAT_PAD_RDLY);
               rd_retry:
                for(k=0;k<AUTOK_CMD_TIMES;k++){
					ret = autok_send_tune_cmd(host, MMC_SEND_TUNING_BLOCK, TUNE_DATA);
					if ((ret & TUNE_CMD_ERR_MASK) != 0) {
                       uCmdEdge ^= 0x1;
                       msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
                       goto rd_retry;
					} else if ((ret & TUNE_DAT_ERR_MASK) != 0) {
                        RawData64 |= (unsigned long long )(1LL << j);
                        break;
                    }
                }
             }
             score = autok_simple_score64(tune_result_str64,RawData64);
             AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] %d \t %d \t %s\r\n",i,uDatEdge, score, tune_result_str64);
            /*get Boundary info*/
            if((ret = autok_check_scan_res64(RawData64,pBdInfo))){
                goto AUTOK_DONE;
            };

			AUTOK_DBGPRINT(AUTOK_DBG_RES,
				       "[AUTOK]Edge:%d \t BoundaryCnt:%d \t FullBoundaryCnt:%d \t\r\n",
				       uDatEdge, pBdInfo->bd_cnt, pBdInfo->fbd_cnt);
			AUTOK_DBGPRINT(AUTOK_DBG_RES,
				       "[AUTOK]BoundInf[0]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n",
				       pBdInfo->bd_info[0].Bound_Start,
				       pBdInfo->bd_info[0].Bound_End,
				       pBdInfo->bd_info[0].Bound_width,
				       pBdInfo->bd_info[0].is_fullbound);
			AUTOK_DBGPRINT(AUTOK_DBG_RES,
				       "[AUTOK]BoundInf[1]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n",
				       pBdInfo->bd_info[1].Bound_Start,
				       pBdInfo->bd_info[1].Bound_End,
				       pBdInfo->bd_info[1].Bound_width,
				       pBdInfo->bd_info[1].is_fullbound);
			AUTOK_DBGPRINT(AUTOK_DBG_RES,
				       "[AUTOK]BoundInf[2]: S:%d \t E:%d \t W:%d \t FullBound:%d\r\n",
				       pBdInfo->bd_info[2].Bound_Start,
				       pBdInfo->bd_info[2].Bound_End,
				       pBdInfo->bd_info[2].Bound_width,
				       pBdInfo->bd_info[2].is_fullbound);

            uDatEdge ^= 0x1;
        }while(uDatEdge);

        autok_pad_dly_sel(&uDatInfo);

		AUTOK_DBGPRINT(AUTOK_DBG_RES,
			       "[AUTOK]================Analysis Result[SD(IO)]===============\r\n");
        AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]Sample Edge Sel: %d, Delay Cnt Sel:%d\r\n",
                uDatInfo.opt_edge_sel,uDatInfo.opt_dly_cnt);
    }
	i = 0;
	msdc_autok_adjust_param(host, CKGEN_MSDC_DLY_SEL, &i, AUTOK_WRITE);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Online Tune Alg Complete\r\n");

	AUTOK_DONE:
	g_msdc_pub_info.g_msdc_runing_autok = 0;

    return ret;
}
/********************************************************************
 *                               Offline tune for SDIO/eMMC/SD                                      *
 *                                     Common Interface                                                    *
 ********************************************************************/
int execute_offline_tuning_hs400(msdc_cmd* host)
{
    int ret = 0;

    unsigned int i,j,k;
    unsigned int uCkgenSel = 0;
    unsigned int uCmdPadDDly = 0;
    unsigned int uCmdEdge = 0;
    unsigned int res_cmd_ta = 1;

    unsigned long long  RawData64 = 0LL;
    unsigned int score = 0;
    char tune_result_str32[33];
    char tune_result_str64[65];
    unsigned int g_ta_raw[SCALE_TA_CNTR];
    unsigned int g_ta_score[SCALE_TA_CNTR];
    unsigned char p_autok_tune_res[TUNING_PARAM_COUNT];

    unsigned int opcode = 17;
	g_msdc_pub_info.g_msdc_runing_autok = 1;
    autok_init_hs400(host);
    x_memset((void*)p_autok_tune_res, 0, sizeof(p_autok_tune_res)/sizeof(unsigned char));
    p_autok_tune_res[EMMC50_DS_Z_DLY1] = 7;
    p_autok_tune_res[EMMC50_DS_Z_DLY1_SEL] = 1;
    p_autok_tune_res[EMMC50_DS_ZDLY_DLY]= 24;


    /************************************************************
      *                                                                                                    *
      *                        Step 1 :Caculate CMD_RSP_TA                                  *
      *                                                                                                    *
      ************************************************************/
     autok_tuning_parameter_init(host,p_autok_tune_res);
     MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step1.Scan CMD_RSP_TA Base on Cmd Pad Delay\r\n");
     AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]CMD_EDGE \t TUNE_CMD_RSP_TA_CNTR \t PAD_CMD_D_DLY \r\n");
     uCmdEdge = 0;
     do{
         msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
         for(i=0; i<8; i++)
         {
             g_ta_raw[i]=0;
             msdc_autok_adjust_param(host, TUNE_CMD_RSP_TA_CNTR, &i, AUTOK_WRITE);
             for(j=0; j<32; j++)
             {
                 msdc_autok_adjust_param(host, CMD_RD_D_DLY1, &j, AUTOK_WRITE);

                 for(k=0;k<AUTOK_CMD_TIMES;k++){
					ret = autok_send_tune_cmd(host, opcode, TUNE_CMD);

					if ((ret & TUNE_CMD_ERR_MASK) != 0)
                     {
                         g_ta_raw[i] |= (1 << j);
                         break;
                     }
                 }
             }
             g_ta_score[i] = autok_simple_score(tune_result_str32,g_ta_raw[i]);
             AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]%d \t %d\t %d \t %s\r\n",uCmdEdge, i,g_ta_score[i],tune_result_str32);
         }

         if(autok_ta_sel(g_ta_raw,&res_cmd_ta) == 0){
			/* autok_param_update(CMD_RSP_TA_CNTR, res_cmd_ta, p_autok_tune_res); */
			msdc_autok_adjust_param(host, CMD_RSP_TA_CNTR, &res_cmd_ta, AUTOK_WRITE);
             MSDC_LOG(MSG_LVL_ERR,"[AUTOK]CMD_TA Sel:%d\r\n",res_cmd_ta);
             break;
         }else{
             MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Internal Boundary Occours,need switch cmd edge for rescan!\r\n");
             uCmdEdge ^= 1;   /* TA select Fail need switch cmd edge for rescan*/
         }
     }while(uCmdEdge);
   /************************************************************
      *                                                                                                    *
      *     Step 2 :Scan CMD Pad Delay Base on CMD_EDGE & CKGEN             *
      *                                                                                                    *
      ************************************************************/
     autok_tuning_parameter_init(host,p_autok_tune_res);
     MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step2.Scan CMD Pad Data Delay\r\n");
     AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]CMD_EDGE \t CKGEN \t CMD_RD_R_DLY1~2 \r\n");
     uCmdEdge = 0;
     uCmdPadDDly = 0;

 msdc_autok_adjust_paddly(host, &uCmdPadDDly,CMD_PAD_RDLY);
     do{
         msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
         for(i=0;i<32;i++){
             RawData64 = 0LL;
             msdc_autok_adjust_param(host, TUNE_CKGEN_MSDC_DLY_SEL, &i, AUTOK_WRITE);

             for(j=0;j<64;j++){
                msdc_autok_adjust_paddly(host, &j,CMD_PAD_RDLY);
                 for(k=0;k<AUTOK_CMD_TIMES;k++){
					ret = autok_send_tune_cmd(host, opcode, TUNE_CMD);
					if ((ret & TUNE_CMD_ERR_MASK) != 0) {
                         RawData64 |= (unsigned long long )(1LL << j);
                         break;
                     }
                 }
             }
             score = autok_simple_score64(tune_result_str64,RawData64);
			AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]%d \t %d \t %d \t %s\r\n",
				       /*(unsigned int)((RawData64>>32)&0xFFFFFFFF),(unsigned int)(RawData64&0xFFFFFFFF), */
				       uCmdEdge, i, score, tune_result_str64);
         }
         uCmdEdge ^= 0x1;
     }while(uCmdEdge);
	uCkgenSel = 0;
	msdc_autok_adjust_param(host, CKGEN_MSDC_DLY_SEL, &uCkgenSel, AUTOK_WRITE);
    /************************************************************
       *                                                                                                    *
       *     Step 3 :Scan Dat Pad Delay Base on Data_EDGE & CKGEN             *
       *                                                                                                    *
       ************************************************************/
	opcode = MMC_SEND_TUNING_BLOCK_HS200;
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step3.Scan DS Clk Pad Delay\r\n");
    AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]DS_ZDLY_DLY DS_ZCLK_DLY1~2 \r\n");
    for(i=0;i<32; i++){
        msdc_autok_adjust_param(host, EMMC50_DS_ZDLY_DLY, &i, AUTOK_WRITE);
        uCmdEdge = 0;
        RawData64 = 0LL;
    for(j=0;j<64;j++){
       msdc_autok_adjust_paddly(host, &j,DS_PAD_RDLY);
       rd_retry0:
        for(k=0;k<AUTOK_CMD_TIMES;k++){
				ret = autok_send_tune_cmd(host, opcode, TUNE_DATA);
				if ((ret & TUNE_DAT_ERR_MASK) != 0) {
               uCmdEdge ^= 0x1;
               msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
               goto rd_retry0;
				} else if ((ret & TUNE_DAT_ERR_MASK) != 0) {
                RawData64 |= (unsigned long long )(1LL << j);
                break;
            }
        }
    }
    score = autok_simple_score64(tune_result_str64,RawData64);
    AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] %d \t %d \t %s\r\n",i, uCmdEdge, score, tune_result_str64);
}
 /*CMD 17 Single block read*/
	opcode = MMC_READ_SINGLE_BLOCK;
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step3.Scan DS Clk Pad Delay\r\n");
    AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]DS_ZDLY_DLY DS_ZCLK_DLY1~2 \r\n");

    for(i=0;i<32; i++){
        msdc_autok_adjust_param(host, EMMC50_DS_ZDLY_DLY, &i, AUTOK_WRITE);
        uCmdEdge = 0;
        RawData64 = 0LL;
        for(j=0;j<64;j++){
           msdc_autok_adjust_paddly(host, &j,DS_PAD_RDLY);
           rd_retry1:
            for(k=0;k<AUTOK_CMD_TIMES;k++){
				ret = autok_send_tune_cmd(host, opcode, TUNE_DATA);
				if ((ret & TUNE_DAT_ERR_MASK) != 0) {
                   uCmdEdge ^= 0x1;
                   msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
                   goto rd_retry1;
				} else if ((ret & TUNE_DAT_ERR_MASK) != 0) {
                    RawData64 |= (unsigned long long )(1LL << j);
                    break;
                }
            }
        }
        score = autok_simple_score64(tune_result_str64,RawData64);
        AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] %d \t %d \t %s\r\n",i,uCmdEdge, score, tune_result_str64);
   }

   autok_tuning_parameter_init(host,p_autok_tune_res);

	g_msdc_pub_info.g_msdc_runing_autok = 0;
    return ret;
}
/*#define SDIO_TUNE_WRITE_PATH*/
int execute_offline_tuning(msdc_cmd* host)
{
                                          /*AUTOK_CODE_RELEASE*/
    int ret = 0;
    unsigned int i,j,k;
    unsigned int uCkgenSel = 0;
    unsigned int uCmdPadDDly = 0;
    unsigned int uDatEdge = 0;
    unsigned int res_cmd_ta = 1;
    unsigned int uCmdEdge = 0;
	#if defined(SDIO_TUNE_WRITE_PATH)
    unsigned int uWCrcEdge = 0;
	#endif

    unsigned long long  RawData64 = 0LL;
    unsigned int score = 0;
    char tune_result_str32[33];
    char tune_result_str64[65];
    unsigned int g_ta_raw[SCALE_TA_CNTR];
    unsigned int g_ta_score[SCALE_TA_CNTR];
    unsigned char p_autok_tune_res[TUNING_PARAM_COUNT];
    unsigned int opcode = MMC_SEND_TUNING_BLOCK;

	g_msdc_pub_info.g_msdc_runing_autok = 1;
    x_memset((void*)p_autok_tune_res, 0, sizeof(p_autok_tune_res)/sizeof(unsigned char));
    if(HOST_EMMC == host->host_type)//sdio?  not used in TV, should not go here
	{
		opcode = MMC_SEND_TUNING_BLOCK;
        autok_init_sdr104(host);
    }else if(HOST_SD == host->host_type)
    {
		opcode = MMC_SEND_TUNING_BLOCK_HS200;
        autok_init_hs200(host);
    }

  /************************************************************
     *                                                                                                    *
     *                        Step 1 :Caculate CMD_RSP_TA                                  *
     *                                                                                                    *
     ************************************************************/
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step1.Scan CMD_RSP_TA Base on Cmd Pad Delay\r\n");
    AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]CMD_EDGE \t TUNE_CMD_RSP_TA_CNTR \t PAD_CMD_D_DLY \r\n");
    uCmdEdge = 0;
    do{
        msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
        for(i=0; i<8; i++)
        {
            g_ta_raw[i]=0;
            msdc_autok_adjust_param(host, TUNE_CMD_RSP_TA_CNTR, &i, AUTOK_WRITE);
            for(j=0; j<32; j++)
            {
                msdc_autok_adjust_param(host, CMD_RD_D_DLY1, &j, AUTOK_WRITE);

                for(k=0;k<AUTOK_CMD_TIMES;k++){
					ret = autok_send_tune_cmd(host, opcode, TUNE_CMD);

					if ((ret & TUNE_CMD_ERR_MASK) != 0) {
                        g_ta_raw[i] |= (1 << j);
                        break;
                    }
                }
            }
            g_ta_score[i] = autok_simple_score(tune_result_str32,g_ta_raw[i]);
            AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]%d \t %d\t %d \t %s\r\n",uCmdEdge, i,g_ta_score[i],tune_result_str32);
        }

        if(autok_ta_sel(g_ta_raw,&res_cmd_ta) == 0){
			msdc_autok_adjust_param(host, CMD_RSP_TA_CNTR, &res_cmd_ta, AUTOK_WRITE);
            MSDC_LOG(MSG_LVL_ERR,"[AUTOK]CMD_TA Sel:%d\r\n",res_cmd_ta);
            break;
        }else{
            MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Internal Boundary Occours,need switch cmd edge for rescan!\r\n");
            uCmdEdge ^= 1;   /* TA select Fail need switch cmd edge for rescan*/
        }
    }while(uCmdEdge);
  /************************************************************
     *                                                                                                    *
     *     Step 2 :Scan CMD Pad Delay Base on CMD_EDGE & CKGEN             *
     *                                                                                                    *
     ************************************************************/
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step2.Scan CMD Pad Data Delay\r\n");
    AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]CMD_EDGE \t CKGEN \t CMD_RD_R_DLY1~2 \r\n");
    uCmdEdge = 0;
    uCmdPadDDly = 0;

 msdc_autok_adjust_paddly(host, &uCmdPadDDly,CMD_PAD_RDLY);
    do{
        msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
        for(i=0;i<32;i++){
            RawData64 = 0LL;
            msdc_autok_adjust_param(host, TUNE_CKGEN_MSDC_DLY_SEL, &i, AUTOK_WRITE);

            for(j=0;j<64;j++){
               msdc_autok_adjust_paddly(host, &j,CMD_PAD_RDLY);
                for(k=0;k<AUTOK_CMD_TIMES;k++){
						ret = autok_send_tune_cmd(host, opcode, TUNE_CMD);
						if ((ret & TUNE_CMD_ERR_MASK) != 0) {
                        RawData64 |= (unsigned long long )(1LL << j);
                        break;
                    }
                }
            }
            score = autok_simple_score64(tune_result_str64,RawData64);
			AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]%d \t %d \t %d \t %s\r\n",
			/*(unsigned int)((RawData64>>32)&0xFFFFFFFF),(unsigned int)(RawData64&0xFFFFFFFF), */
			uCmdEdge, i, score, tune_result_str64);
        }
        uCmdEdge ^= 0x1;
    }while(uCmdEdge);

	uCkgenSel = 0;
	msdc_autok_adjust_param(host, CKGEN_MSDC_DLY_SEL, &uCkgenSel, AUTOK_WRITE);
    /************************************************************
       *                                                                                                    *
       *     Step 3 :Scan Dat Pad Delay Base on Data_EDGE & CKGEN             *
       *                                                                                                    *
       ************************************************************/
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step3.Scan Dat Pad Delay\r\n");
	AUTOK_DBGPRINT(AUTOK_DBG_RES,
		       "[AUTOK]CMD_EDGE \t DAT_EDGE \t CKGEN \t DAT_RD_R_DLY1~2 \r\n");
    uCmdEdge = 0;
    uDatEdge = 0;
    do{
        msdc_autok_adjust_param(host, RD_FIFO_EDGE, &uDatEdge, AUTOK_WRITE);
        for(i=0;i<32;i++){
            RawData64 = 0LL;
            msdc_autok_adjust_param(host, TUNE_CKGEN_MSDC_DLY_SEL, &i, AUTOK_WRITE);

            for(j=0;j<64;j++){
               msdc_autok_adjust_paddly(host, &j,DAT_PAD_RDLY);
               rd_retry:
                for(k=0;k<AUTOK_CMD_TIMES;k++){
					ret = autok_send_tune_cmd(host, opcode, TUNE_DATA);
					if ((ret & TUNE_DAT_ERR_MASK) != 0) {
                       uCmdEdge ^= 0x1;
                       msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
                       goto rd_retry;
					} else if ((ret & TUNE_DAT_ERR_MASK) != 0) {
                        RawData64 |= (unsigned long long )(1LL << j);
                        break;
                    }
                }
            }
            score = autok_simple_score64(tune_result_str64,RawData64);
			AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] \t %d \t %d \t %d \t %s\r\n",
				       uCmdEdge, uDatEdge, i, score, tune_result_str64);
        }
        uDatEdge ^= 0x1;
    }while(uDatEdge);
	uCkgenSel = 0;
	msdc_autok_adjust_param(host, CKGEN_MSDC_DLY_SEL, &uCkgenSel, AUTOK_WRITE);
  #if defined(SDIO_TUNE_WRITE_PATH)
    /************************************************************
       *                                                                                                    *
       *     Step 4:Scan Write Pad Delay Base on WCRC_EDGE & CKGEN          *
       *                                                                                                    *
       ************************************************************/
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step4.Scan Data Pad Delay on Write Path\r\n");
	AUTOK_DBGPRINT(AUTOK_DBG_RES,
		       "[AUTOK]CMD_EDGE \t WCRC_EDGE \t CKGEN \t DAT_RD_R_DLY1~2 \r\n");
    uCmdEdge = 0;
    uWCrcEdge = 0;
    do{
       msdc_autok_adjust_param(host, WD_FIFO_EDGE, &uWCrcEdge, AUTOK_WRITE);
       for(i=0;i<32;i++){
           RawData64 = 0LL;
           msdc_autok_adjust_param(host, TUNE_CKGEN_MSDC_DLY_SEL, &i, AUTOK_WRITE);

           for(j=0;j<64;j++){
              msdc_autok_adjust_paddly(host, &j,DAT_PAD_RDLY);
              wd_retry:
               for(k=0;k<2;k++){
                   ret = autok_cmd53_tune_cccr_write(host);
					if ((ret & TUNE_CMD_ERR_MASK) != 0) {
                      uCmdEdge ^= 0x1;
                      msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
                      goto wd_retry;
					} else if ((ret & TUNE_DAT_ERR_MASK) != 0) {
                       RawData64 |= (unsigned long long )(1LL << j);
                       break;
                   }
               }
           }
           score = autok_simple_score64(tune_result_str64,RawData64);
			AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] \t %d \t %d \t %d \t %s\r\n",
				       uCmdEdge, uWCrcEdge, i, score, tune_result_str64);
       }
       uWCrcEdge ^= 0x1;
    }while(uWCrcEdge);

	uCkgenSel = 0;
	msdc_autok_adjust_param(host, CKGEN_MSDC_DLY_SEL, &uCkgenSel, AUTOK_WRITE);
     /************************************************************
       *                                                                                                    *
       *     Step 5 :Scan Write TA Base on Pad Delay                                      *
       *                                                                                                    *
       ************************************************************/
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step5.Scan WCRC_TA Base on Data Pad Delay\r\n");
	AUTOK_DBGPRINT(AUTOK_DBG_RES,
		       "[AUTOK]WCRC_EDGE \t WRDAT_CRCS_TA_CNTR \t DAT_RD_R_DLY1~2 \r\n");
    uCmdEdge = 0;
    uWCrcEdge = 0;
    do{
        msdc_autok_adjust_param(host, WD_FIFO_EDGE, &uWCrcEdge, AUTOK_WRITE);
        for(i=0; i<8; i++)
        {
            g_ta_raw[i]=0;
            msdc_autok_adjust_param(host, TUNE_WRDAT_CRCS_TA_CNTR, &i, AUTOK_WRITE);
            for(j=0; j<32; j++)
            {
                msdc_autok_adjust_paddly(host, &j,DAT_PAD_RDLY);

                retry:
                for(k=0;k<AUTOK_CMD_TIMES;k++){
                    ret = autok_cmd53_tune_cccr_write(host);
					if ((ret & TUNE_CMD_ERR_MASK) != 0) {
                      uCmdEdge ^= 0x1;
                      msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
                      goto retry;
					} else if ((ret & TUNE_DAT_ERR_MASK) != 0) {
                        g_ta_raw[i] |= (1 << j);
                       break;
                   }
                }
            }
            g_ta_score[i] = autok_simple_score(tune_result_str32,g_ta_raw[i]);
            AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] \t %d \t %d\t %d \t %s\r\n",uCmdEdge, uWCrcEdge, i,g_ta_score[i],tune_result_str32);
        }

        if(autok_ta_sel(g_ta_raw,&res_wcrc_ta) == 0){
			msdc_autok_adjust_param(host, WRDAT_CRCS_TA_CNTR, &res_wcrc_ta, AUTOK_WRITE);
            MSDC_LOG(MSG_LVL_ERR,"[AUTOK]CMD_TA Sel:%d\r\n",res_wcrc_ta);
            break;
        }else{
            MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Internal Boundary Occours,need switch cmd edge for rescan!\r\n");
            uWCrcEdge ^= 1;   /* TA select Fail need switch cmd edge for rescan*/
        }
    }while(uWCrcEdge);
#endif
    //1 Debug Info for reference
    /************************************************************
     *                                                                                                    *
     *     Step [1] :Scan CMD Pad Delay Base on CMD_EDGE & CKGEN             *
     *                                                                                                    *
     ************************************************************/
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step[1].Scan CMD Pad Data Delay\r\n");
    AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]CMD_EDGE \t CKGEN \t CMD_RD_R_DLY1~2 \r\n");
    uCmdEdge = 0;
    uCmdPadDDly = 0;

 msdc_autok_adjust_paddly(host, &uCmdPadDDly,CMD_PAD_RDLY);

    for(i=0;i<32;i++){
        do{
            msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
            RawData64 = 0LL;
            msdc_autok_adjust_param(host, TUNE_CKGEN_MSDC_DLY_SEL, &i, AUTOK_WRITE);

            for(j=0;j<64;j++){
               msdc_autok_adjust_paddly(host, &j,CMD_PAD_RDLY);
                for(k=0;k<AUTOK_CMD_TIMES;k++){
					ret = autok_send_tune_cmd(host, opcode, TUNE_CMD);
					if ((ret & TUNE_CMD_ERR_MASK) != 0) {
                        RawData64 |= (unsigned long long )(1LL << j);
                        break;
                    }
                }
            }
            score = autok_simple_score64(tune_result_str64,RawData64);
            AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK]%d \t %d \t %d \t %s\r\n",/*(unsigned int)((RawData64>>32)&0xFFFFFFFF),(unsigned int)(RawData64&0xFFFFFFFF),*/uCmdEdge, i, score, tune_result_str64);
                uCmdEdge ^= 0x1;
         }while(uCmdEdge);
    }
	uCkgenSel = 0;
	msdc_autok_adjust_param(host, CKGEN_MSDC_DLY_SEL, &uCkgenSel, AUTOK_WRITE);

    /************************************************************
       *                                                                                                    *
       *     Step [2] :Scan Dat Pad Delay Base on Data_EDGE & CKGEN             *
       *                                                                                                    *
       ************************************************************/
    autok_tuning_parameter_init(host,p_autok_tune_res);
    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Step[2].Scan Dat Pad Delay\r\n");
	AUTOK_DBGPRINT(AUTOK_DBG_RES,
		       "[AUTOK]CMD_EDGE \t DAT_EDGE \t CKGEN \t DAT_RD_R_DLY1~2 \r\n");
    uCmdEdge = 0;
    uDatEdge = 0;
    for(i=0;i<32;i++){
        do{
            msdc_autok_adjust_param(host, RD_FIFO_EDGE, &uDatEdge, AUTOK_WRITE);
            RawData64 = 0LL;
            msdc_autok_adjust_param(host, TUNE_CKGEN_MSDC_DLY_SEL, &i, AUTOK_WRITE);

            for(j=0;j<64;j++){
               msdc_autok_adjust_paddly(host, &j,DAT_PAD_RDLY);
               rd_retry1:
                for(k=0;k<AUTOK_CMD_TIMES;k++){
					ret = autok_send_tune_cmd(host, opcode, TUNE_DATA);
					if ((ret & TUNE_CMD_ERR_MASK) != 0) {
                       uCmdEdge ^= 0x1;
                       msdc_autok_adjust_param(host, CMD_EDGE, &uCmdEdge, AUTOK_WRITE);
                       goto rd_retry1;
					} else if ((ret & TUNE_DAT_ERR_MASK) != 0) {
                        RawData64 |= (unsigned long long )(1LL << j);
                        break;
                    }
                }
            }
            score = autok_simple_score64(tune_result_str64,RawData64);
			AUTOK_DBGPRINT(AUTOK_DBG_RES, "[AUTOK][%d] \t %d \t %d \t %d \t %s\r\n",
				       uCmdEdge, uDatEdge, i, score, tune_result_str64);
            uDatEdge ^= 0x1;
        }while(uDatEdge);

    }

	uCkgenSel = 0;
	msdc_autok_adjust_param(host, CKGEN_MSDC_DLY_SEL, &uCkgenSel, AUTOK_WRITE);

    MSDC_LOG(MSG_LVL_ERR,"[AUTOK]Offline Tune Alg Complete\r\n");

	g_msdc_pub_info.g_msdc_runing_autok = 0;
	return ret;
}
#if AUTOK_OFFLINE_TUNE_TX_ENABLE
int autok_offline_tuning_TX(msdc_cmd *host)
{
	int ret = 0;
	unsigned int response;
	unsigned int tune_tx_value;
	unsigned int tune_cnt;
	unsigned int i;
	unsigned int tune_crc_cnt[32];
	unsigned int tune_pass_cnt[32];
	unsigned int tune_tmo_cnt[32];
	char tune_result[33];
	unsigned int cmd_tx;
	unsigned int dat0_tx;
	unsigned int dat1_tx;
	unsigned int dat2_tx;
	unsigned int dat3_tx;
	unsigned int dat4_tx;
	unsigned int dat5_tx;
	unsigned int dat6_tx;
	unsigned int dat7_tx;
	MSDC_LOG(MSG_LVL_ERR,"[AUTOK][tune cmd TX]=========start========\r\n");
	/* store tx setting */
	MSDC_GET_FIELD(EMMC50_PAD_CMD_TUNE, MSDC_EMMC50_PAD_CMD_TUNE_TXDLY, cmd_tx);
	MSDC_GET_FIELD(EMMC50_PAD_DAT01_TUNE, MSDC_EMMC50_PAD_DAT0_TXDLY, dat0_tx);
	MSDC_GET_FIELD(EMMC50_PAD_DAT01_TUNE, MSDC_EMMC50_PAD_DAT1_TXDLY, dat1_tx);
	MSDC_GET_FIELD(EMMC50_PAD_DAT23_TUNE, MSDC_EMMC50_PAD_DAT2_TXDLY, dat2_tx);
	MSDC_GET_FIELD(EMMC50_PAD_DAT23_TUNE, MSDC_EMMC50_PAD_DAT3_TXDLY, dat3_tx);
	MSDC_GET_FIELD(EMMC50_PAD_DAT45_TUNE, MSDC_EMMC50_PAD_DAT4_TXDLY, dat4_tx);
	MSDC_GET_FIELD(EMMC50_PAD_DAT45_TUNE, MSDC_EMMC50_PAD_DAT5_TXDLY, dat5_tx);
	MSDC_GET_FIELD(EMMC50_PAD_DAT67_TUNE, MSDC_EMMC50_PAD_DAT6_TXDLY, dat6_tx);
	MSDC_GET_FIELD(EMMC50_PAD_DAT67_TUNE, MSDC_EMMC50_PAD_DAT7_TXDLY, dat7_tx);
	//1    Step1 : Tuning Cmd TX
	for (tune_tx_value = 0;tune_tx_value < 32;tune_tx_value++) {
		tune_tmo_cnt[tune_tx_value] = 0;
		tune_crc_cnt[tune_tx_value] = 0;
		tune_pass_cnt[tune_tx_value] = 0;
		MSDC_SET_FIELD(EMMC50_PAD_CMD_TUNE, MSDC_EMMC50_PAD_CMD_TUNE_TXDLY, tune_tx_value);
		for (tune_cnt = 0;tune_cnt < TUNE_TX_CNT;tune_cnt++) {
			ret = autok_send_tune_cmd(host, 13, TUNE_CMD);
			if ((ret & CMD_ERR_WAIT_CMD_TO) != 0) {
				tune_tmo_cnt[tune_tx_value]++;
			}
			else if ((ret&(CMD_ERR_RESP_CRCERR)) != 0) {
				tune_crc_cnt[tune_tx_value]++;
			}
			else if ((ret & (E_RESULT_PASS)) == 0) {
				tune_pass_cnt[tune_tx_value]++;
			}
		}

		/* MSDC_LOG(MSG_LVL_ERR,"[AUTOK]tune_cmd_TX cmd_tx_value = %d tmo_cnt = %d crc_cnt = %d pass_cnt = %d\r\n",tune_tx_value,
		tune_tmo_cnt[tune_tx_value],tune_crc_cnt[tune_tx_value],tune_pass_cnt[tune_tx_value]); */
	}
	/* print result */
	for (i = 0;i < 32;i++) {
		if ((tune_tmo_cnt[i] != 0) || (tune_crc_cnt[i] != 0))
			tune_result[i] = 'X';
		else if (tune_pass_cnt[i] == TUNE_TX_CNT)
			tune_result[i] = 'O';
	}
	tune_result[32] = '\0';
	MSDC_LOG(MSG_LVL_ERR,"[AUTOK]tune_cmd_TX 0 - 31      %s\r\n",tune_result);
	MSDC_LOG(MSG_LVL_ERR,"[AUTOK][tune cmd TX]=========end========\r\n");
	/* restore cmd tx setting */
	MSDC_SET_FIELD(EMMC50_PAD_CMD_TUNE, MSDC_EMMC50_PAD_CMD_TUNE_TXDLY, cmd_tx);
	MSDC_LOG(MSG_LVL_ERR,"[AUTOK][tune data TX]=========start========\r\n");
	//1    Step2 : Tuning Data TX
	for (tune_tx_value = 0;tune_tx_value < 32;tune_tx_value++) {
		tune_tmo_cnt[tune_tx_value] = 0;
		tune_crc_cnt[tune_tx_value] = 0;
		tune_pass_cnt[tune_tx_value] = 0;
		MSDC_SET_FIELD(EMMC50_PAD_DAT01_TUNE, MSDC_EMMC50_PAD_DAT0_TXDLY, tune_tx_value);
		MSDC_SET_FIELD(EMMC50_PAD_DAT01_TUNE, MSDC_EMMC50_PAD_DAT1_TXDLY, tune_tx_value);
		MSDC_SET_FIELD(EMMC50_PAD_DAT23_TUNE, MSDC_EMMC50_PAD_DAT2_TXDLY, tune_tx_value);
		MSDC_SET_FIELD(EMMC50_PAD_DAT23_TUNE, MSDC_EMMC50_PAD_DAT3_TXDLY, tune_tx_value);
		MSDC_SET_FIELD(EMMC50_PAD_DAT45_TUNE, MSDC_EMMC50_PAD_DAT4_TXDLY, tune_tx_value);
		MSDC_SET_FIELD(EMMC50_PAD_DAT45_TUNE, MSDC_EMMC50_PAD_DAT5_TXDLY, tune_tx_value);
		MSDC_SET_FIELD(EMMC50_PAD_DAT67_TUNE, MSDC_EMMC50_PAD_DAT6_TXDLY, tune_tx_value);
		MSDC_SET_FIELD(EMMC50_PAD_DAT67_TUNE, MSDC_EMMC50_PAD_DAT7_TXDLY, tune_tx_value);
		for (tune_cnt = 0;tune_cnt < TUNE_TX_CNT;tune_cnt++) {

			/* check device status */
			response = 0;
			while (((response >> 9) & 0xF) != 4) {
				ret = autok_send_tune_cmd(host, 13, TUNE_CMD);
				if ((ret & (CMD_ERR_RESP_CRCERR | CMD_ERR_WAIT_CMD_TO)) != 0) {
					MSDC_LOG(MSG_LVL_ERR,"[AUTOK]------while tune data TX cmd13 occur error------\r\n");
					MSDC_LOG(MSG_LVL_ERR,"[AUTOK]------tune data TX fail------\r\n");
					goto end;
				}
				response = MSDC_READ32(SDC_RESP0);
				if ((((response >> 9) & 0xF) == 5) || (((response >> 9) & 0xF) == 6))
					ret = autok_send_tune_cmd(host, 12, TUNE_CMD);
			}
			/* send cmd24 write one block data */
			ret = autok_send_tune_cmd(host, 24, TUNE_DATA);
			response = MSDC_READ32(SDC_RESP0);
			if ((ret & (CMD_ERR_RESP_CRCERR | CMD_ERR_WAIT_CMD_TO)) != 0) {
				MSDC_LOG(MSG_LVL_ERR,"[AUTOK]------while tune data TX cmd%d occur error------\r\n",24);
				MSDC_LOG(MSG_LVL_ERR,"[AUTOK]------tune data TX fail------\r\n");
				goto end;
			}
			if ((ret & CMD_ERR_WAIT_DATATO) != 0) {
				tune_tmo_cnt[tune_tx_value]++;
			}
			else if ((ret & (CMD_ERR_DATA_CRCERR)) != 0) {
				tune_crc_cnt[tune_tx_value]++;
			}
			else if ((ret & (E_RESULT_PASS)) == 0) {
				tune_pass_cnt[tune_tx_value]++;
			}
		}

		/* MSDC_LOG(MSG_LVL_ERR,"[AUTOK]tune_data_TX data_tx_value = %d tmo_cnt = %d crc_cnt = %d pass_cnt = %d\r\n",tune_tx_value,
			tune_tmo_cnt[tune_tx_value],tune_crc_cnt[tune_tx_value],tune_pass_cnt[tune_tx_value]); */
	}
	/* print result */
	for (i = 0;i < 32;i++) {
		if ((tune_tmo_cnt[i] != 0) || (tune_crc_cnt[i] != 0))
			tune_result[i] = 'X';
		else if (tune_pass_cnt[i] == TUNE_TX_CNT)
			tune_result[i] = 'O';
	}
	tune_result[32] = '\0';
	MSDC_LOG(MSG_LVL_ERR,"[AUTOK]tune_data_TX 0 - 31      %s\r\n",tune_result);

	/* restore data tx setting */
	MSDC_SET_FIELD(EMMC50_PAD_DAT01_TUNE, MSDC_EMMC50_PAD_DAT0_TXDLY, dat0_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT01_TUNE, MSDC_EMMC50_PAD_DAT1_TXDLY, dat1_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT23_TUNE, MSDC_EMMC50_PAD_DAT2_TXDLY, dat2_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT23_TUNE, MSDC_EMMC50_PAD_DAT3_TXDLY, dat3_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT45_TUNE, MSDC_EMMC50_PAD_DAT4_TXDLY, dat4_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT45_TUNE, MSDC_EMMC50_PAD_DAT5_TXDLY, dat5_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT67_TUNE, MSDC_EMMC50_PAD_DAT6_TXDLY, dat6_tx);
	MSDC_SET_FIELD(EMMC50_PAD_DAT67_TUNE, MSDC_EMMC50_PAD_DAT7_TXDLY, dat7_tx);

	MSDC_LOG(MSG_LVL_ERR,"[AUTOK][tune data TX]=========end========\r\n");
	goto end;
adtc_cmd_err:
	MSDC_LOG(MSG_LVL_ERR,"[AUTOK]------MSDC host reset------\r\n");
	msdc_reset();
	msdc_clear_fifo();
	MSDC_WRITE32(MSDC_INT, 0xffffffff);
	response = 0;
	while (((response >> 9) & 0xF) != 4) {
		ret = autok_send_tune_cmd(host, 13, TUNE_CMD);
		response = MSDC_READ32(SDC_RESP0);
		if ((((response >> 9) & 0xF) == 5) || (((response >> 9) & 0xF) == 6))
			ret = autok_send_tune_cmd(host, 12, TUNE_CMD);
	}
end:
	return ret;
}
#endif
int sdio_execute_tuning(msdc_cmd *host, unsigned char* res)
{
    int ret = 0;
	unsigned int clk_pwdn = 0;
	unsigned int int_en = 0;
    MSDC_LOG(MSG_LVL_ERR,"[SD]----------------Tuning Start---------------\r\n");

	int_en = MSDC_READ32(MSDC_INTEN);
	MSDC_WRITE32(MSDC_INTEN, 0);
	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CK_EN, clk_pwdn);
	MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_CK_EN, 1);
#if AUTOK_OFFLINE_TUNE_ENABLE
    if(execute_offline_tuning(host, res) != 0){
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK] ========Error: Autok Failed========");
    }
#endif
    if(execute_online_tuning(host, res) != 0){
        MSDC_LOG(MSG_LVL_ERR,"[AUTOK] ========Error: Autok Failed========");
    }
	MSDC_WRITE32(MSDC_INT, 0xffffffff);
	MSDC_WRITE32(MSDC_INTEN, int_en);
	MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_CK_EN, clk_pwdn);


  return ret;
}

int hs400_execute_tuning(msdc_cmd *host, unsigned char* res)
{
    int ret = 0;
	unsigned int clk_pwdn = 0;
	unsigned int int_en = 0;

    MSDC_LOG(MSG_LVL_ERR,"[HS400]----------------Tuning Start bus width %d---------------\r\n",host->BusWidth);
	int_en = MSDC_READ32(MSDC_INTEN);
	MSDC_WRITE32(MSDC_INTEN, 0);
	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CK_EN, clk_pwdn);
	MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_CK_EN, 1);

	g_msdc_pub_info.g_msdc_runing_autok = 1;

    #if HS400_OFFLINE_TUNE_ENABLE
	MSDC_LOG(MSG_LVL_ERR,"HS400 Offline tuning \n");
    ret = execute_offline_tuning_hs400(host);
    #endif
	MSDC_LOG(MSG_LVL_ERR,"HS400 Online tuning \n");
    ret = execute_online_tuning_hs400(host, res);

#if AUTOK_OFFLINE_TUNE_TX_ENABLE
	autok_offline_tuning_TX(host);
#endif

	g_msdc_pub_info.g_msdc_runing_autok = 0;

    MSDC_LOG(MSG_LVL_ERR,"[HS400]----------------Tuning END---------------\r\n");
	MSDC_WRITE32(MSDC_INT, 0xffffffff);
	MSDC_WRITE32(MSDC_INTEN, int_en);
	MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_CK_EN, clk_pwdn);


	return ret;
}

int hs200_execute_tuning (msdc_cmd *host, unsigned char* res)
{

	int ret = 0;
	unsigned int clk_pwdn = 0;
	unsigned int int_en = 0;

	MSDC_LOG(MSG_LVL_ERR,"[HS200]----------------Tuning Start ---------------\n");
	int_en = MSDC_READ32(MSDC_INTEN);
	MSDC_WRITE32(MSDC_INTEN, 0);
	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CK_EN, clk_pwdn);
	MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_CK_EN, 1);

	g_msdc_pub_info.g_msdc_runing_autok = 1;

#if HS200_OFFLINE_TUNE_ENABLE
	MSDC_LOG(MSG_LVL_ERR,"HS200 Offline tuning \n");
	ret = execute_offline_tuning(host);
#endif
	MSDC_LOG(MSG_LVL_ERR,"HS200 Online tuning \n");
	ret = execute_online_tuning_hs200(host,res);

#if AUTOK_OFFLINE_TUNE_TX_ENABLE
	autok_offline_tuning_TX(host);
#endif


	g_msdc_pub_info.g_msdc_runing_autok = 0;

	MSDC_LOG(MSG_LVL_ERR,"[HS200]----------------Tuning END---------------\n");
	MSDC_WRITE32(MSDC_INT, 0xffffffff);
	MSDC_WRITE32(MSDC_INTEN, int_en);
	MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_CK_EN, clk_pwdn);
	return ret;
}
