diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 214b8fc05de6..ad998fbab545 100755 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -29,59 +29,6 @@ #include "rk_sdmmc_dbg.h" -/*CRU SDMMC TUNING*/ -/* -* sdmmc,sdio0,sdio1,emmc id=0~3 -* cclk_in_drv, cclk_in_sample i=0,1 -*/ - -static u32 cru_tuning_base = 0; - -#define CRU_SDMMC_CON(id, tuning_type) (cru_tuning_base + ((id) * 8) + ((tuning_type) * 4)) - -#define MAX_DELAY_LINE (0xff) -#define FREQ_REF_150MHZ (150000000) -#define PRECISE_ADJUST (0) - -#define SDMMC_TUNING_SEL(tuning_type) ( tuning_type? 10:11 ) -#define SDMMC_TUNING_DELAYNUM(tuning_type) ( tuning_type? 2:3 ) -#define SDMMC_TUNING_DEGREE(tuning_type) ( tuning_type? 0:1 ) -#define SDMMC_TUNING_INIT_STATE (0) - -enum{ - SDMMC_SHIFT_DEGREE_0 = 0, - SDMMC_SHIFT_DEGREE_90, - SDMMC_SHIFT_DEGREE_180, - SDMMC_SHIFT_DEGREE_270, - SDMMC_SHIFT_DEGREE_INVALID, -}; - -const char *phase_desc[SDMMC_SHIFT_DEGREE_INVALID + 1] = { - "SDMMC_SHIFT_DEGREE_0", - "SDMMC_SHIFT_DEGREE_90", - "SDMMC_SHIFT_DEGREE_180", - "SDMMC_SHIFT_DEGREE_270", - "SDMMC_SHIFT_DEGREE_INVALID", -}; - -enum{ - USE_CLK_AFTER_PHASE = 0, - USE_CLK_AFTER_PHASE_AND_DELAY_LINE = 1, -}; - -enum{ - IO_DRV_2MA = 0x0, - IO_DRV_4MA = 0x1, - IO_DRV_8MA = 0x2, - IO_DRV_12MA = 0x3, -}; - -enum{ - SLEW_RATE_SLOW = 0, - SLEW_RATE_FAST = 1, -}; - - /* Rockchip implementation specific driver private data */ struct dw_mci_rockchip_priv_data { enum dw_mci_rockchip_type ctrl_type; @@ -98,39 +45,46 @@ static struct dw_mci_rockchip_compatible { { .compatible = "rockchip,rk31xx-sdmmc", .ctrl_type = DW_MCI_TYPE_RK3188, - },{ + }, + { .compatible = "rockchip,rk32xx-sdmmc", .ctrl_type = DW_MCI_TYPE_RK3288, - },{ + }, + { .compatible = "rockchip,rk3036-sdmmc", .ctrl_type = DW_MCI_TYPE_RK3036, - },{ + }, + { .compatible = "rockchip,rk312x-sdmmc", .ctrl_type = DW_MCI_TYPE_RK312X, - },{ + }, + { .compatible = "rockchip,rk3368-sdmmc", .ctrl_type = DW_MCI_TYPE_RK3368, }, }; +#define syscon_find(np, property) \ +syscon_regmap_lookup_by_phandle(np, property) + static int dw_mci_rockchip_priv_init(struct dw_mci *host) { struct dw_mci_rockchip_priv_data *priv; int idx; priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); - if(!priv){ + if (!priv) { dev_err(host->dev, "mem alloc failed for private data\n"); return -ENOMEM; } - for(idx = 0; idx < ARRAY_SIZE(rockchip_compat); idx++){ - if(of_device_is_compatible(host->dev->of_node, - rockchip_compat[idx].compatible)) { + for (idx = 0; idx < ARRAY_SIZE(rockchip_compat); idx++) { + if (of_device_is_compatible(host->dev->of_node, + rockchip_compat[idx].compatible)) { priv->ctrl_type = rockchip_compat[idx].ctrl_type; host->cid = priv->ctrl_type; - host->grf = syscon_regmap_lookup_by_phandle(host->dev->of_node, - "rockchip,grf"); + host->grf = syscon_find(host->dev->of_node, + "rockchip,grf"); } } @@ -143,9 +97,9 @@ static int dw_mci_rockchip_setup_clock(struct dw_mci *host) struct dw_mci_rockchip_priv_data *priv = host->priv; if ((priv->ctrl_type == DW_MCI_TYPE_RK3288) || - (priv->ctrl_type == DW_MCI_TYPE_RK3036) || - (priv->ctrl_type == DW_MCI_TYPE_RK312X) || - (priv->ctrl_type == DW_MCI_TYPE_RK3368)) + (priv->ctrl_type == DW_MCI_TYPE_RK3036) || + (priv->ctrl_type == DW_MCI_TYPE_RK312X) || + (priv->ctrl_type == DW_MCI_TYPE_RK3368)) host->bus_hz /= (priv->ciu_div + 1); return 0; @@ -153,175 +107,88 @@ static int dw_mci_rockchip_setup_clock(struct dw_mci *host) static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr) { - } static void dw_mci_rockchip_set_ios(struct dw_mci *host, struct mmc_ios *ios) { - } static int dw_mci_rockchip_parse_dt(struct dw_mci *host) -{ - return 0; -} -static inline u8 dw_mci_rockchip_get_delaynum(struct dw_mci *host, u8 con_id, u8 tuning_type) -{ - u32 regs; - u8 delaynum; - - regs = cru_readl(CRU_SDMMC_CON(con_id, tuning_type)); - delaynum = ((regs>>SDMMC_TUNING_DELAYNUM(tuning_type)) & 0xff); - - return delaynum; -} - -static inline void dw_mci_rockchip_set_delaynum(struct dw_mci *host, u8 con_id, u8 tuning_type, u8 delaynum) -{ - u32 regs; - regs = cru_readl(CRU_SDMMC_CON(con_id, tuning_type)); - regs &= ~( 0xff << SDMMC_TUNING_DELAYNUM(tuning_type)); - regs |= (delaynum << SDMMC_TUNING_DELAYNUM(tuning_type)); - regs |= (0xff << (SDMMC_TUNING_DELAYNUM(tuning_type)+16)); - - MMC_DBG_INFO_FUNC(host->mmc,"tuning_result[delayline]: con_id = %d, tuning_type = %d, CRU_CON = 0x%x. [%s]", - con_id, tuning_type, regs, mmc_hostname(host->mmc)); - - cru_writel(regs, CRU_SDMMC_CON(con_id, tuning_type)); - - MMC_DBG_INFO_FUNC(host->mmc,"CRU_SDMMC_CON(con_id, tuning_type) = 0x%x, regs = 0x%x [%s]", - CRU_SDMMC_CON(con_id, tuning_type), cru_readl(CRU_SDMMC_CON(con_id, tuning_type)), mmc_hostname(host->mmc)); -} - -static inline void dw_mci_rockchip_set_degree(struct dw_mci *host, u8 con_id, u8 tuning_type, u8 phase) -{ - u32 regs; - - regs = cru_readl(CRU_SDMMC_CON(con_id, tuning_type)); - regs &= ~( 0x3 << SDMMC_TUNING_DEGREE(tuning_type)); - regs |= (phase << SDMMC_TUNING_DEGREE(tuning_type)); - regs |= (0x3 << (SDMMC_TUNING_DEGREE(tuning_type)+16)); - - MMC_DBG_INFO_FUNC(host->mmc,"tuning_result[phase]: con_id = %d, tuning_type= %d, CRU_CON = 0x%x. [%s]", - con_id, tuning_type, regs, mmc_hostname(host->mmc)); - - cru_writel(regs, CRU_SDMMC_CON(con_id, tuning_type)); - MMC_DBG_INFO_FUNC(host->mmc,"CRU_SDMMC_CON(con_id, tuning_type) = 0x%x, regs = 0x%x [%s]", - CRU_SDMMC_CON(con_id, tuning_type), cru_readl(CRU_SDMMC_CON(con_id, tuning_type)), mmc_hostname(host->mmc)); -} - -static inline void dw_mci_rockchip_turning_sel(struct dw_mci *host, u8 con_id, u8 tuning_type, u8 mode) -{ - u32 regs; - regs = cru_readl(CRU_SDMMC_CON(con_id, tuning_type)) ; - regs &= ~( 0x1 << SDMMC_TUNING_SEL(tuning_type)); - regs |= (mode << SDMMC_TUNING_SEL(tuning_type)); - regs |= (0x1 << (SDMMC_TUNING_SEL(tuning_type)+16)); - - MMC_DBG_INFO_FUNC(host->mmc,"tuning_sel: con_id = %d, tuning_type = %d, CRU_CON = 0x%x. [%s]", - con_id, tuning_type, regs, mmc_hostname(host->mmc)); - - cru_writel(regs, CRU_SDMMC_CON(con_id, tuning_type)); -} - - -static inline u8 dw_mci_rockchip_get_phase(struct dw_mci *host, u8 con_id, u8 tuning_type) { return 0; } -static inline u8 dw_mci_rockchip_move_next_clksmpl(struct dw_mci *host, u8 con_id, u8 tuning_type, u8 val) +#define ROCKCHIP_MMC_DELAY_SEL BIT(10) +#define ROCKCHIP_MMC_DEGREE_MASK 0x3 +#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 +#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) +#define PSECS_PER_SEC 1000000000000LL + +/* + * Each fine delay is between 40ps-80ps. Assume each fine delay is 60ps to + * simplify calculations. So 45degs could be anywhere between 33deg and 66deg. + */ +#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 + +#define NUM_PHASES 32 +#define TUNING_ITERATION_TO_PHASE(i) (DIV_ROUND_UP((i) * 360, NUM_PHASES)) + +static int rockchip_mmc_set_phase(int degrees, struct dw_mci *host) { - u32 regs; - - regs = cru_readl(CRU_SDMMC_CON(con_id, tuning_type)) ; + unsigned long rate = clk_get_rate(host->clk_mmc)/2; /* 150M */ + u8 nineties, remainder; + u8 delay_num; + u32 raw_value; + u64 delay; - if(tuning_type) { - val = ((regs>>SDMMC_TUNING_DELAYNUM(tuning_type)) & 0xff); - } + degrees++; + degrees -= ((degrees) * 10 % (360/NUM_PHASES*10)) / 10; + nineties = degrees / 90; + remainder = (degrees % 90) / (360/NUM_PHASES); - return val; + delay = PSECS_PER_SEC; + do_div(delay, rate); + do_div(delay, NUM_PHASES); + do_div(delay, ROCKCHIP_MMC_DELAY_ELEMENT_PSEC); + + delay *= remainder; + delay_num = (u8) min(delay, 255ULL); + + raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; + raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; + raw_value |= nineties; + + cru_writel(0x00010001, host->tune_regsbase); + cru_writel(((0x07ff << 16)|(raw_value)), host->tune_regsbase + 4); + cru_writel(0x00010000, host->tune_regsbase); + + return 0; } -static void dw_mci_rockchip_load_signal_integrity(struct dw_mci *host, u32 sr, u32 drv) +static int dw_mci_tuning_test(struct dw_mci_slot *slot, u32 opcode, + struct dw_mci_tuning_data *tuning_data, + u8 *blk_test) { - if (unlikely((drv > IO_DRV_12MA) || (sr > SLEW_RATE_FAST))) { - MMC_DBG_ERR_FUNC(host->mmc,"wrong signal integrity setting: drv = %d, sr = %d ![%s]", - drv, sr, mmc_hostname(host->mmc)); - return; - } - - if(cpu_is_rk3288()){ - /*Note 00: 2ma 01:4ma 10:8ma 11:12ma - For consider line loading and IP's slew rate, - we should match these by every board depends for signal integrity. - slew rate >= 2*pi*f*Vpeak = max(|d'(Vpeak)/dt|) - */ - if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) { - grf_writel(0xff005500 | (drv << 14) | (drv << 12) | - (drv << 10) | (drv << 8), 0x01f8); /* GPIO4C4-C7 */ - grf_writel(0x000f0000 | (drv << 0) | (drv << 2), 0x01fc); /* GPIO4D0-D1 */ - grf_writel(0x03f00000 | (sr << 4) | (sr << 5) | (sr << 6) | - (sr << 7) | (sr << 8) | (sr << 9) , 0x011c); /* slew rate*/ - }else if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) { - grf_writel(0x3fff0000 | (drv << 0) | (drv << 2) | (drv << 4) | - (drv << 6) | (drv << 8) | (drv << 10) | - (drv << 12), 0x0218); /* GPIO6C0-C6 */ - grf_writel(0x003f0000 | (sr << 0) | (sr << 1) | (sr << 2) | - (sr << 3) | (sr << 4) | (sr << 5), 0x012c); /* slew rate */ - }else if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) { - /* emmc hardware relative addr match requirement, assume 4ma not slow slew rate */ - grf_writel(0xffff5555, 0x01e0); /* GPIO3A0-A7 */ - grf_writel(0x000c0006, 0x01e4); /* GPIO3B1 */ - grf_writel(0x003f0015, 0x01e8); /* GPIO3C2-C0 */ - } - } else if (host->cid == DW_MCI_TYPE_RK3368) { - if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) { - regmap_write(host->grf, 0x21c, 0xff000000 | (drv << 14) | (drv << 12) | - (drv << 10) | (drv << 8)); /* GPIO2D4-D7 */ - regmap_write(host->grf, 0x220, 0x000f0000 | (drv << 0) | (drv << 2)); /* GPIO3A0-A1 */ - }else if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) { - regmap_write(host->grf, 0x210, 0xfc000000 | (drv << 10) | (drv << 12) | (drv << 14)); /* GPIO2A5-A7 */ - regmap_write(host->grf, 0x214, 0x003f0000 | (drv << 0) | (drv << 2) | (drv << 4)); /* GPIO2B0-2 */ - }else if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) { - regmap_write(host->grf, 0x208, 0xfff00000 | (drv << 4) | (drv << 6) | (drv << 8) | (drv << 10) - | (drv << 12) | (drv << 14)); /* GPIO1C2-C7 */ - regmap_write(host->grf, 0x20c, 0x003f0000 | (drv << 0) | (drv << 2) | (drv << 4)); /* GPIO1D0-D2 */ - regmap_write(host->grf, 0x210, 0x03000000 | (drv << 8)); /* GPIO2A4 */ - } - } - -} -static void dw_mci_rockchip_load_tuning_base(struct dw_mci *host) -{ - /* load tuning base */ - if (cpu_is_rk3288()) { - cru_tuning_base = RK3288_CRU_SDMMC_CON0; - } else if (host->cid == DW_MCI_TYPE_RK3368) { - if (IS_ERR(host->grf)) - pr_err("rk_sdmmc: dts couldn't find grf regmap\n"); - - cru_tuning_base = 0x400; - } -} - -static int inline __dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode, - u8 *blk_test, unsigned int blksz) -{ - struct dw_mci *host = slot->host; - struct mmc_host *mmc = slot->mmc; - struct mmc_request mrq = {NULL}; + struct dw_mci *host = slot->host; + struct mmc_host *mmc = slot->mmc; + const u8 *blk_pattern = tuning_data->blk_pattern; + unsigned int blksz = tuning_data->blksz; + struct mmc_request mrq = { NULL }; struct mmc_command cmd = {0}; struct mmc_command stop = {0}; struct mmc_data data = {0}; struct scatterlist sg; + memset(blk_test, 0, blksz); + cmd.opcode = opcode; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + stop.opcode = MMC_STOP_TRANSMISSION; stop.arg = 0; stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + data.blksz = blksz; data.blocks = 1; data.flags = MMC_DATA_READ; @@ -336,322 +203,139 @@ static int inline __dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 mci_writel(host, TMOUT, ~0); mmc_wait_for_req(mmc, &mrq); - if(!cmd.error && !data.error){ - return 0; - }else{ - dev_dbg(host->dev, - "Tuning error: cmd.error:%d, data.error:%d\n",cmd.error, data.error); - return -EIO; + if (!cmd.error && !data.error) { + if (!memcmp(blk_pattern, blk_test, blksz)) + return 0; + + return -EIO; + } else { + dev_err(host->dev, + "Tuning error: cmd.error:%d, data.error:%d\n", + cmd.error, data.error); + if (cmd.error) + return cmd.error; + else + return data.error; } - } - -static int dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode, - struct dw_mci_tuning_data *tuning_data) +static int +dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode, + struct dw_mci_tuning_data *tuning_data) { - struct dw_mci *host = slot->host; - u8 step; - u8 candidates_delayline[MAX_DELAY_LINE] = {0}; - u8 candidates_degree[SDMMC_SHIFT_DEGREE_INVALID] = {4,4,4,4}; - u8 default_drv; - u8 index = 0; - u8 start_degree = 0; - u32 start_delayline = 0; - const u8 *blk_pattern = tuning_data->blk_pattern; - u8 *blk_test; - int ret = -1; - int ref = 0; + struct device *dev = host->dev; + struct device_node *np = dev->of_node; unsigned int blksz = tuning_data->blksz; + u8 *blk_test; + int ret = 0; + int i; + bool v, prev_v = 0, first_v; + struct range_t { + int start; + int end; /* inclusive */ + }; + struct range_t *ranges; + unsigned int range_count = 0; + int longest_range_len = -1; + int longest_range = -1; + int middle_phase; - MMC_DBG_INFO_FUNC(host->mmc,"execute tuning: [%s]", mmc_hostname(host->mmc)); - - dw_mci_rockchip_load_tuning_base(host); + if (!of_property_read_u32(np, "tune_regsbase", &host->tune_regsbase)) { + pr_info("[%s] tuning regsbase addr 0x%03x.\n", + mmc_hostname(host->mmc), host->tune_regsbase); + } else { + pr_err("[%s] tuning regsbase addr is missing!\n", + mmc_hostname(host->mmc)); + return -1; + } blk_test = kmalloc(blksz, GFP_KERNEL); if (!blk_test) - { - MMC_DBG_ERR_FUNC(host->mmc,"execute tuning: blk_test kmalloc failed[%s]", - mmc_hostname(host->mmc)); return -ENOMEM; - } - - /* Select use delay line*/ - dw_mci_rockchip_turning_sel(host, tuning_data->con_id, tuning_data->tuning_type, - USE_CLK_AFTER_PHASE_AND_DELAY_LINE); - - /* For RK32XX signoff 150M clk, 1 cycle = 6.66ns , and 1/4 phase = 1.66ns. - Netlist level sample LT: 10.531ns / 42.126ps WC: 19.695ns / 76.936ps. - So we take average --- 60ps, (1.66ns/ 2) = 0.83(middle-value),TAKE 0.9 - 0.9 / 60ps = 15 delayline - */ - if (cpu_is_rk3288() && !(rockchip_get_cpu_version() > 0)) { - /* RK3288, non-eco */ - ref = DIV_ROUND_UP(FREQ_REF_150MHZ, host->bus_hz); - step = (15 * ref); - if (step > MAX_DELAY_LINE) { - step = MAX_DELAY_LINE; - MMC_DBG_WARN_FUNC(host->mmc, - "execute tuning: TOO LARGE STEP![%s]", mmc_hostname(host->mmc)); - } - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: SOC is RK3288, ref = %d, step = %d[%s]", - ref, step, mmc_hostname(host->mmc)); - - } else { - step = (15 * ((FREQ_REF_150MHZ / host->bus_hz) * 100)) / 100; - if (step > MAX_DELAY_LINE) { - step = MAX_DELAY_LINE; - MMC_DBG_WARN_FUNC(host->mmc, - "execute tuning: TOO LARGE STEP![%s]", mmc_hostname(host->mmc)); - } - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: SOC id is %d, step = %d[%s]", - host->cid, step, mmc_hostname(host->mmc)); - } + ranges = kmalloc_array(NUM_PHASES / 2 + 1, sizeof(*ranges), GFP_KERNEL); + if (!ranges) { + ret = -ENOMEM; + goto free_blk_test; + } -re_phase: - /* calcute slew rate & drv strength in timing tuning */ - if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) - default_drv = IO_DRV_4MA; - else - default_drv = IO_DRV_8MA; + /* Try each phase and extract good ranges */ + for (i = 0; i < NUM_PHASES - 6; i++) { + rockchip_mmc_set_phase(TUNING_ITERATION_TO_PHASE(i), host); + v = !dw_mci_tuning_test(slot, opcode, tuning_data, blk_test); - dw_mci_rockchip_load_signal_integrity(host, SLEW_RATE_SLOW, default_drv); - /* Loop degree from 0 ~ 270 */ - for(start_degree = SDMMC_SHIFT_DEGREE_0; start_degree <= SDMMC_SHIFT_DEGREE_270; start_degree++){ - dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, start_degree); - if(0 == __dw_mci_rockchip_execute_tuning(slot, opcode, blk_test, blksz)){ - if(!memcmp(blk_pattern, blk_test, blksz)){ - /* Successfully tuning in this condition*/ - candidates_degree[index] = start_degree; - index++; - } - } - /* eMMC spec does not require a delay between tuning cycles - * but eMMC should be guaranteed to complete a sequence of 40 times CMD21 - * withnin 150ms, some eMMC may limit 4ms gap between any two sequential CMD21 - */ - if (opcode == MMC_SEND_TUNING_BLOCK) - mdelay(1); - else - /* MMC_SEND_TUNING_BLOCK_HS200 */ - mdelay(5); - } - - MMC_DBG_BOOT_FUNC(host->mmc,"\n execute tuning: candidates_degree = %s \t%s \t%s \t%s[%s]", - phase_desc[candidates_degree[0]], phase_desc[candidates_degree[1]], - phase_desc[candidates_degree[2]], phase_desc[candidates_degree[3]], - mmc_hostname(host->mmc)); - - - if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_0) - && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_90) - && (candidates_degree[2] == SDMMC_SHIFT_DEGREE_180)){ - - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_90 [%s]", - mmc_hostname(host->mmc)); - if (host->cid == DW_MCI_TYPE_RK3368 && (candidates_degree[3] == SDMMC_SHIFT_DEGREE_270)) { - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_180 [%s]", - mmc_hostname(host->mmc)); - dw_mci_rockchip_set_degree(host, tuning_data->con_id, - tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_180); + if ((!prev_v) && v) { + range_count++; + ranges[range_count-1].start = i; } - else { - dw_mci_rockchip_set_degree(host, tuning_data->con_id, - tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_90); + if (v) + ranges[range_count-1].end = i; + + if (i == 0) + first_v = v; + + prev_v = v; + } + + if (range_count == 0) { + dev_err(host->dev, "All phases bad!"); + ret = -EIO; + goto free; + } + + /* wrap around case, merge the end points + if ((range_count > 1) && first_v && v) { + ranges[0].start = ranges[range_count-1].start; + range_count--; + } + */ + + if ((ranges[0].start == 0) && (ranges[0].end == NUM_PHASES - 1)) { + rockchip_mmc_set_phase(0, host); + dev_err(host->dev, + "All phases work, using default phase %d.", 0); + goto free; + } + + /* Find the longest range */ + for (i = 0; i < range_count; i++) { + int len = (ranges[i].end - ranges[i].start + 1); + + if (len < 0) + len += NUM_PHASES; + + if (longest_range_len < len) { + longest_range_len = len; + longest_range = i; } - ret = 0; - goto done; - }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_90) - && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_180) - && (candidates_degree[2] == SDMMC_SHIFT_DEGREE_270)){ - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_180 [%s]", - mmc_hostname(host->mmc)); - dw_mci_rockchip_set_degree(host, tuning_data->con_id, - tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_180); - ret = 0; - goto done; - }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_0) - && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_90) - && (candidates_degree[2] == SDMMC_SHIFT_DEGREE_INVALID)){ + dev_err(host->dev, "Good phase range %d-%d (%d len)\n", + TUNING_ITERATION_TO_PHASE(ranges[i].start), + TUNING_ITERATION_TO_PHASE(ranges[i].end), + len + ); + } - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_0 ~ SDMMC_SHIFT_DEGREE_90[%s]", - mmc_hostname(host->mmc)); - - dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_0); - #if PRECISE_ADJUST - goto delayline; - #else - dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step); - ret = 0; - goto done; - #endif - }else if((candidates_degree[0]==SDMMC_SHIFT_DEGREE_0) - && (candidates_degree[1]==SDMMC_SHIFT_DEGREE_180) - && (candidates_degree[2]==SDMMC_SHIFT_DEGREE_270)){ - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_0 AND SDMMC_SHIFT_DEGREE_180 AND SDMMC_SHIFT_DEGREE_270[%s]", - mmc_hostname(host->mmc)); - dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_180); - dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step); - ret = 0; - goto done; - }else if((candidates_degree[0]==SDMMC_SHIFT_DEGREE_0) - && (candidates_degree[1]==SDMMC_SHIFT_DEGREE_180)){ + dev_err(host->dev, "Best phase range %d-%d (%d len)\n", + TUNING_ITERATION_TO_PHASE(ranges[longest_range].start), + TUNING_ITERATION_TO_PHASE(ranges[longest_range].end), + longest_range_len + ); - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_0 AND SDMMC_SHIFT_DEGREE_180[%s]", - mmc_hostname(host->mmc)); + middle_phase = ranges[longest_range].start + longest_range_len / 2; + middle_phase %= NUM_PHASES; + dev_err(host->dev, "Successfully tuned phase to %d\n", + TUNING_ITERATION_TO_PHASE(middle_phase)); - /* FixMe: NO sense any signal indicator make this case happen*/ - dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_0); - goto delayline; - }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_90) - && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_180) - && (candidates_degree[2] == SDMMC_SHIFT_DEGREE_INVALID)){ + rockchip_mmc_set_phase(TUNING_ITERATION_TO_PHASE(middle_phase), host); - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_90 ~ SDMMC_SHIFT_DEGREE_180[%s]", - mmc_hostname(host->mmc)); - - dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_90); - #if PRECISE_ADJUST - goto delayline; - #else - dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step); - ret = 0; - goto done; - #endif - }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_180) - && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_270)){ - - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_180 ~ SDMMC_SHIFT_DEGREE_270[%s]", - mmc_hostname(host->mmc)); - - dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_180); - #if PRECISE_ADJUST - goto delayline; - #else - dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step); - ret = 0; - goto done; - #endif - }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_180) - && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_INVALID)){ - - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = [SDMMC_SHIFT_DEGREE_90 + n ~ SDMMC_SHIFT_DEGREE_180][%s]", - mmc_hostname(host->mmc)); - - dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_90); - #if PRECISE_ADJUST - goto delayline; - #else - default_drv++; - goto re_phase; - //dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step); - //ret = 0; - //goto done; - #endif - }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_90) - && (candidates_degree[1] == SDMMC_SHIFT_DEGREE_INVALID)){ - - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = [SDMMC_SHIFT_DEGREE_0 + n ~ SDMMC_SHIFT_DEGREE_90][%s]", - mmc_hostname(host->mmc)); - - dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_0); - #if PRECISE_ADJUST - goto delayline; - #else - default_drv++; - goto re_phase; - //dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step); - //ret = 0; - //goto done; - #endif - }else if((candidates_degree[0] == SDMMC_SHIFT_DEGREE_270)){ - - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_270 [%s]", - mmc_hostname(host->mmc)); - - /*FixME: so urgly signal indicator, HW engineer help!*/ - - //dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_180); - #if PRECISE_ADJUST - goto delayline; - #else - default_drv++; - goto re_phase; - //dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step); - //ret = 0; - //goto done; - #endif - }else{ - MMC_DBG_ERR_FUNC(host->mmc, - "execute tuning: candidates_degree beyong limited case! [%s]", - mmc_hostname(host->mmc)); - default_drv++; - goto re_phase; - if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) - BUG(); - return -EAGAIN; - } - -delayline: - index = 0; - for(start_delayline = 0; start_delayline <= MAX_DELAY_LINE; start_delayline += step){ - - dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, - tuning_data->tuning_type, start_delayline); - if(0 == __dw_mci_rockchip_execute_tuning(slot, opcode, blk_test, blksz)){ - if(!memcmp(blk_pattern, blk_test, blksz)){ - /* Successfully tuning in this condition*/ - candidates_delayline[index] = start_delayline; - index++; - } - } - } - if((index < 2) && (index != 0)) { - /* setup 400ps, consider line loading, at least 600ps wc. - for 150M, 15 steps =900ps ,too larger scale, should step smaller in principle - */ - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_delayline failed for no enough elements [%s]", - mmc_hostname(host->mmc)); - - /* Make step smaller, and re-calculate */ - step = step >> 1; - index = 0; - goto delayline; - }else if(index >= 2){ - /* Find it! */ - MMC_DBG_INFO_FUNC(host->mmc, - "execute tuning: candidates_delayline calculate successfully [%s]", - mmc_hostname(host->mmc)); - - dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, - tuning_data->tuning_type, candidates_delayline[index/2]); - ret = 0; - goto done; - } - -done: - kfree(blk_test); - blk_test = NULL; - return ret; - +free: + kfree(ranges); +free_blk_test: + kfree(blk_test); + return ret; } /* Common capabilities of RK32XX SoC */ @@ -662,7 +346,7 @@ static unsigned long rockchip_dwmmc_caps[4] = { MMC_CAP_CMD23, }; -unsigned int rockchip_dwmmc_hold_reg[4] = {1,0,0,0}; +unsigned int rockchip_dwmmc_hold_reg[4] = {1, 0, 0, 0}; static const struct dw_mci_drv_data rockchip_drv_data = { .caps = rockchip_dwmmc_caps, @@ -686,7 +370,7 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev) { const struct dw_mci_drv_data *drv_data; const struct of_device_id *match; - + match = of_match_node(dw_mci_rockchip_match, pdev->dev.of_node); drv_data = match->data; return dw_mci_pltfm_register(pdev, drv_data); diff --git a/drivers/mmc/host/rk_sdmmc.c b/drivers/mmc/host/rk_sdmmc.c index 6621ea9ec1b7..4fdcf930232a 100755 --- a/drivers/mmc/host/rk_sdmmc.c +++ b/drivers/mmc/host/rk_sdmmc.c @@ -1946,23 +1946,6 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) return -EINVAL; } - - /* Recommend sample phase and delayline - Fixme: Mix-use these three controllers will cause - con_id mismatch. - */ - if (mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) - tuning_data.con_id = 3; - else if(mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) - tuning_data.con_id = 1; - else - tuning_data.con_id = 0; - - /* 0: driver, from host->devices - 1: sample, from devices->host - */ - tuning_data.tuning_type = 1; - if (drv_data && drv_data->execute_tuning) err = drv_data->execute_tuning(slot, opcode, &tuning_data); diff --git a/drivers/mmc/host/rk_sdmmc.h b/drivers/mmc/host/rk_sdmmc.h index 2e0012924822..e0c4818e0d39 100755 --- a/drivers/mmc/host/rk_sdmmc.h +++ b/drivers/mmc/host/rk_sdmmc.h @@ -342,9 +342,6 @@ int last_detect_state; struct dw_mci_tuning_data { const u8 *blk_pattern; unsigned int blksz; - - u8 con_id; - u8 tuning_type; }; /** diff --git a/include/linux/mmc/rk_mmc.h b/include/linux/mmc/rk_mmc.h index 6492a4764dfa..a736e4afb859 100755 --- a/include/linux/mmc/rk_mmc.h +++ b/include/linux/mmc/rk_mmc.h @@ -220,6 +220,7 @@ struct dw_mci { struct regmap *grf; u32 *regs_buffer; const struct dw_mci_rst_ops *rst_ops; + u32 tune_regsbase; }; /* DMA ops for Internal/External DMAC interface */