emmc: add fix adj calculation.
authorNan Li <nan.li@amlogic.com>
Thu, 30 Aug 2018 11:16:30 +0000 (19:16 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Wed, 19 Sep 2018 14:52:40 +0000 (07:52 -0700)
PD#173425: add emmc fix adj calculation.

Change-Id: Iab512f0971abe0d0452be4d0b58405c6eba103eb
Signed-off-by: Nan Li <nan.li@amlogic.com>
drivers/amlogic/mmc/aml_sd_emmc.c
drivers/amlogic/mmc/aml_sd_emmc_v3.c
include/linux/amlogic/sd.h

index 326f705..25c0778 100644 (file)
@@ -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,
index f64a0e8..b2f9f1a 100644 (file)
 #include <linux/amlogic/amlsd.h>
 #include <linux/amlogic/aml_sd_emmc_internal.h>
 
+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;
index 91e02ea..7aee14a 100644 (file)
@@ -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;