emmc: add fix adj calculation.

PD#173425: add emmc fix adj calculation.

Change-Id: Iab512f0971abe0d0452be4d0b58405c6eba103eb
Signed-off-by: Nan Li <nan.li@amlogic.com>
This commit is contained in:
Nan Li
2018-08-30 19:16:30 +08:00
committed by Jianxin Pan
parent cb4c4510d6
commit a42b76b952
3 changed files with 137 additions and 8 deletions

View 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,

View File

@@ -42,6 +42,71 @@
#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;

View 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;