From a42b76b952bd8ab9fbadf662d23187aec08bda53 Mon Sep 17 00:00:00 2001 From: Nan Li Date: Thu, 30 Aug 2018 19:16:30 +0800 Subject: [PATCH] emmc: add fix adj calculation. PD#173425: add emmc fix adj calculation. Change-Id: Iab512f0971abe0d0452be4d0b58405c6eba103eb Signed-off-by: Nan Li --- drivers/amlogic/mmc/aml_sd_emmc.c | 18 ++++- drivers/amlogic/mmc/aml_sd_emmc_v3.c | 110 ++++++++++++++++++++++++++- include/linux/amlogic/sd.h | 17 +++++ 3 files changed, 137 insertions(+), 8 deletions(-) diff --git a/drivers/amlogic/mmc/aml_sd_emmc.c b/drivers/amlogic/mmc/aml_sd_emmc.c index 326f705a324b..25c0778c64cc 100644 --- a/drivers/amlogic/mmc/aml_sd_emmc.c +++ b/drivers/amlogic/mmc/aml_sd_emmc.c @@ -3513,12 +3513,17 @@ static struct meson_mmc_data mmc_data_g12a = { .ds_pin_poll_en = 0x48, .ds_pin_poll_bit = 13, .tdma_f = 1, - .sdmmc.init.core_phase = 3, + .sdmmc.init.core_phase = 2, .sdmmc.init.tx_phase = 0, .sdmmc.init.rx_phase = 0, - .sdmmc.hs.core_phase = 3, + .sdmmc.emmc_init.core_phase = 0, + .sdmmc.emmc_init.tx_phase = 2, + .sdmmc.hs.core_phase = 0, + .sdmmc.hs.tx_phase = 2, .sdmmc.ddr.core_phase = 2, + .sdmmc.ddr.tx_phase = 0, .sdmmc.hs2.core_phase = 3, + .sdmmc.hs2.tx_phase = 0, .sdmmc.hs4.tx_delay = 0, .sdmmc.sd_hs.core_phase = 2, .sdmmc.sdr104.core_phase = 2, @@ -3534,12 +3539,17 @@ static struct meson_mmc_data mmc_data_g12b = { .ds_pin_poll = 0x3a, .ds_pin_poll_en = 0x48, .ds_pin_poll_bit = 13, - .sdmmc.init.core_phase = 3, + .sdmmc.init.core_phase = 2, .sdmmc.init.tx_phase = 0, .sdmmc.init.rx_phase = 0, - .sdmmc.hs.core_phase = 1, + .sdmmc.emmc_init.core_phase = 0, + .sdmmc.emmc_init.tx_phase = 2, + .sdmmc.hs.core_phase = 0, + .sdmmc.hs.tx_phase = 2, .sdmmc.ddr.core_phase = 2, + .sdmmc.ddr.tx_phase = 0, .sdmmc.hs2.core_phase = 3, + .sdmmc.hs2.tx_phase = 0, .sdmmc.hs4.tx_delay = 0, .sdmmc.sd_hs.core_phase = 2, .sdmmc.sdr104.core_phase = 2, diff --git a/drivers/amlogic/mmc/aml_sd_emmc_v3.c b/drivers/amlogic/mmc/aml_sd_emmc_v3.c index f64a0e83bb72..b2f9f1ad3c16 100644 --- a/drivers/amlogic/mmc/aml_sd_emmc_v3.c +++ b/drivers/amlogic/mmc/aml_sd_emmc_v3.c @@ -42,6 +42,71 @@ #include #include +int aml_fixdiv_calc(unsigned int *fixdiv, struct clock_lay_t *clk) +{ + int ret = 0; + unsigned int full_div, source_cycle; /* in ns*/ + unsigned int sdclk_idx, todly_idx_max, todly_idx_min; + unsigned int inv_idx_min, inv_idx_max; + unsigned int val_idx_min, val_idx_max, val_idx_win, val_idx_sta; + + if (!fixdiv || !clk) + return -EPERM; + + if (clk->core == clk->old_core) + return 1; + clk->old_core = clk->core; + + pr_debug(">>>%s source clk %d, core clk %d\n", + __func__, clk->source, clk->core); + full_div = clk->source / clk->core; + sdclk_idx = full_div / 2; + sdclk_idx -= full_div % 2 ? 0 : 1; + + pr_debug("full_div %d, sdclk_idx %d\n", full_div, sdclk_idx); + /* ns */ + source_cycle = 1000000000 / clk->source; + pr_debug("cycle of source clock is %d\n", source_cycle); + if (source_cycle < TODLY_MAX_NS) { + todly_idx_max + = (TODLY_MAX_NS + source_cycle - 1) / source_cycle; + todly_idx_min = TODLY_MIN_NS / source_cycle; + pr_debug("todly_idx_min %d, todly_idx_max %d\n", + todly_idx_min, todly_idx_max); + inv_idx_min = todly_idx_min + sdclk_idx; + inv_idx_max = todly_idx_max + sdclk_idx; + pr_debug("inv_idx_min %d, inv_idx_max %d\n", + inv_idx_min, inv_idx_max); + inv_idx_min = inv_idx_min % full_div; + inv_idx_max = inv_idx_max % full_div; + pr_debug("ROUND: inv_idx_min %d, inv_idx_max %d\n", + inv_idx_min, inv_idx_max); + + if (inv_idx_min > inv_idx_max) { + val_idx_min = inv_idx_max + 1; + val_idx_max = inv_idx_min - 1; + val_idx_sta = val_idx_min; + val_idx_win = val_idx_max - val_idx_min; + } else if (inv_idx_min <= inv_idx_max) { + val_idx_max = inv_idx_max + 1; + val_idx_min = inv_idx_min - 1; + val_idx_sta = val_idx_max; + val_idx_win = (full_div + val_idx_min) - val_idx_max; + } + } else { + val_idx_max = sdclk_idx + 1; + val_idx_min = sdclk_idx - 1; + val_idx_sta = val_idx_max; + val_idx_win = full_div / 2; + } + + pr_debug("val_idx_sta %d, val_idx_win %d\n", val_idx_sta, val_idx_win); + *fixdiv = val_idx_sta + (val_idx_win >> 1); + + pr_debug("fixdiv = %d\n", *fixdiv); + return ret; +} + int meson_mmc_clk_init_v3(struct amlsd_host *host) { int ret = 0; @@ -50,6 +115,7 @@ int meson_mmc_clk_init_v3(struct amlsd_host *host) u32 vconf = 0; struct sd_emmc_config *pconf = (struct sd_emmc_config *)&vconf; struct mmc_phase *init = &(host->data->sdmmc.init); + struct mmc_phase *emmc_init = &(host->data->sdmmc.emmc_init); writel(0, host->base + SD_EMMC_CLOCK_V3); #ifndef SD_EMMC_CLK_CTRL @@ -62,11 +128,13 @@ int meson_mmc_clk_init_v3(struct amlsd_host *host) pclkc->div = 60; /* 400KHz */ pclkc->src = 0; /* 0: Crystal 24MHz */ pclkc->core_phase = init->core_phase; /* 2: 180 phase */ - if ((host->mem->start == host->data->port_b_base) - && (host->data->chip_type == MMC_CHIP_G12A)) - pclkc->core_phase = 2; pclkc->rx_phase = init->rx_phase; pclkc->tx_phase = init->tx_phase; + if ((host->mem->start == host->data->port_c_base) + && (host->data->chip_type >= MMC_CHIP_G12A)) { + pclkc->core_phase = emmc_init->core_phase; + pclkc->tx_phase = emmc_init->tx_phase; + } pclkc->always_on = 1; /* Keep clock always on */ writel(vclkc, host->base + SD_EMMC_CLOCK_V3); @@ -102,6 +170,8 @@ static int meson_mmc_clk_set_rate_v3(struct mmc_host *mmc, struct clk *src0_clk = NULL; u32 vcfg = 0; struct sd_emmc_config *conf = (struct sd_emmc_config *)&vcfg; + u32 vclkc = 0; + struct sd_emmc_clock_v3 *clkc = (struct sd_emmc_clock_v3 *)&vclkc; #endif #ifdef SD_EMMC_CLK_CTRL @@ -190,6 +260,11 @@ static int meson_mmc_clk_set_rate_v3(struct mmc_host *mmc, } else mmc->actual_clock = clk_ios; + vclkc = readl(host->base + SD_EMMC_CLOCK_V3); + pdata->clk_lay.source = clk_get_rate(host->cfg_div_clk) * clkc->div; + pdata->clk_lay.core = clk_get_rate(host->cfg_div_clk); + + /* (re)start clock, if non-zero */ if (clk_ios) { vcfg = readl(host->base + SD_EMMC_CFG); @@ -221,6 +296,7 @@ static void aml_sd_emmc_set_timing_v3(struct amlsd_platform *pdata, struct sd_emmc_adjust_v3 *gadjust = (struct sd_emmc_adjust_v3 *)&adjust; u8 clk_div = 0; struct para_e *para = &(host->data->sdmmc); + unsigned int fixdiv = 0, ret = 0; vctrl = readl(host->base + SD_EMMC_CFG); if ((timing == MMC_TIMING_MMC_HS400) || @@ -248,17 +324,21 @@ static void aml_sd_emmc_set_timing_v3(struct amlsd_platform *pdata, if (clk_div & 0x01) clk_div++; clkc->div = clk_div / 2; - if (aml_card_type_mmc(pdata)) + if (aml_card_type_mmc(pdata)) { clkc->core_phase = para->ddr.core_phase; + clkc->tx_phase = para->ddr.tx_phase; + } pr_info("%s: try set sd/emmc to DDR mode\n", mmc_hostname(host->mmc)); } else if (timing == MMC_TIMING_MMC_HS) { clkc->core_phase = para->hs.core_phase; + clkc->tx_phase = para->hs.tx_phase; /* overide co-phase by dts */ if (pdata->co_phase) clkc->core_phase = pdata->co_phase; } else if (timing == MMC_TIMING_MMC_HS200) { clkc->core_phase = para->hs2.core_phase; + clkc->tx_phase = para->hs2.tx_phase; } else if ((timing == MMC_TIMING_SD_HS) && aml_card_type_non_sdio(pdata)) { clkc->core_phase = para->sd_hs.core_phase; @@ -268,6 +348,26 @@ static void aml_sd_emmc_set_timing_v3(struct amlsd_platform *pdata, } else ctrl->ddr = 0; + if (aml_card_type_mmc(pdata) + && (host->data->chip_type >= MMC_CHIP_G12A)) { + if (timing <= MMC_TIMING_MMC_HS) { + ret = aml_fixdiv_calc(&fixdiv, &pdata->clk_lay); + if (!ret) { + adjust = readl(host->base + SD_EMMC_ADJUST_V3); + gadjust->adj_delay = fixdiv; + gadjust->adj_enable = 1; + writel(adjust, host->base + SD_EMMC_ADJUST_V3); + pr_info("fixdiv calc done: adj = %x\n", adjust); + } + } else if (timing == MMC_TIMING_MMC_DDR52) { + adjust = readl(host->base + SD_EMMC_ADJUST_V3); + gadjust->adj_delay = 0; + gadjust->adj_enable = 0; + writel(adjust, host->base + SD_EMMC_ADJUST_V3); + pr_debug("ddr52 close calc: adj = %x\n", adjust); + } + } + writel(vclkc, host->base + SD_EMMC_CLOCK_V3); pdata->clkc = vclkc; @@ -1400,6 +1500,8 @@ int aml_mmc_execute_tuning_v3(struct mmc_host *mmc, u32 opcode) u32 adj_win_start = 100; u32 intf3; + writel(0, (host->base + SD_EMMC_ADJUST_V3)); + if (opcode == MMC_SEND_TUNING_BLOCK_HS200) { if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { tuning_data.blk_pattern = tuning_blk_pattern_8bit; diff --git a/include/linux/amlogic/sd.h b/include/linux/amlogic/sd.h index 91e02eabf9d6..7aee14a13542 100644 --- a/include/linux/amlogic/sd.h +++ b/include/linux/amlogic/sd.h @@ -200,6 +200,7 @@ struct mmc_phase { struct para_e { struct mmc_phase init; + struct mmc_phase emmc_init; struct mmc_phase hs; struct mmc_phase ddr; struct mmc_phase hs2; @@ -226,6 +227,21 @@ struct meson_mmc_data { struct amlsd_host; struct sd_emmc_desc_info; +struct clock_lay_t { + /* source clk, 24Mhz, 1Ghz */ + unsigned int source; + /* core clk, Hz */ + unsigned int core; + /* old core clk, Hz */ + unsigned int old_core; + /* bus clk */ + unsigned int sdclk; +}; + +/* todly in ns*/ +#define TODLY_MIN_NS (2) +#define TODLY_MAX_NS (14) + struct amlsd_platform { struct amlsd_host *host; struct mmc_host *mmc; @@ -263,6 +279,7 @@ struct amlsd_platform { unsigned int clock; /* signalling voltage (1.8V or 3.3V) */ unsigned char signal_voltage; + struct clock_lay_t clk_lay; int bus_width; int bl_len; int stop_clk;