storage: emmc: Add HS400 busmode support for TL1 [1/1]

PD#SWPL-2311

Problem:
not support HS400 busmode

Solution:
add HS400 busmode support for TL1

Verify:
TL1-T962X2_X301

Change-Id: I95ac19e9c0c5b84c9225602cda6964aaaee4151e
Signed-off-by: Long Yu <long.yu@amlogic.com>
This commit is contained in:
Long Yu
2018-12-14 17:13:36 +08:00
committed by Luke Go
parent 1d2e33a395
commit e6bbfaf869
6 changed files with 148 additions and 30 deletions

View File

@@ -1312,10 +1312,9 @@
"MMC_CAP_HW_RESET",
"MMC_CAP_ERASE",
"MMC_CAP_CMD23";
caps2 = "MMC_CAP2_HS200";
/* "MMC_CAP2_HS400";*/
caps2 = "MMC_CAP2_HS200", "MMC_CAP2_HS400";
f_min = <400000>;
f_max = <200000000>;
f_max = <198000000>;
};
};

View File

@@ -27,7 +27,7 @@
#include "tl1.h"
PNAME(sd_emmc_parent_names) = { "xtal", "fclk_div2",
"fclk_div3", "fclk_div5", "fclk_div7", "mpll2", "mpll3", "gp0" };
"fclk_div3", "fclk_div5", "fclk_div7", "mpll2", "mpll3", "gp0_pll" };
/*sd_emmc B*/
static MUX(sd_emmc_p0_mux_B, HHI_SD_EMMC_CLK_CNTL, 0x7, 25,
sd_emmc_parent_names, CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED);

View File

@@ -2618,7 +2618,7 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
mmc_hostname(host->mmc),
vstat, virqc);
host->status = HOST_RSP_CRC_ERR;
mrq->cmd->error = -EILSEQ;
mrq->cmd->error = -EBADMSG;
} else if (ista->resp_timeout) {
if (host->is_tunning == 0)
pr_err("%s: resp_timeout,vstat:0x%x,virqc:%x\n",
@@ -3606,7 +3606,8 @@ static struct meson_mmc_data mmc_data_tl1 = {
.sdmmc.hs.core_phase = 3,
.sdmmc.ddr.core_phase = 2,
.sdmmc.hs2.core_phase = 2,
.sdmmc.hs4.tx_delay = 0,
.sdmmc.hs4.core_phase = 0,
.sdmmc.hs4.tx_delay = 16,
.sdmmc.sd_hs.core_phase = 2,
.sdmmc.sdr104.core_phase = 2,
};

View File

@@ -240,7 +240,23 @@ static int meson_mmc_clk_set_rate_v3(struct mmc_host *mmc,
src0_clk = devm_clk_get(host->dev, "clkin2");
ret = clk_set_parent(host->mux_parent[0], src0_clk);
if (ret)
pr_warn("set src0: div5 as comp0 parent error\n");
pr_warn("set src0 as comp0 parent error\n");
ret = clk_set_parent(host->mux_clk,
host->mux_parent[0]);
if (ret)
pr_warn("set comp0 as mux_clk parent error\n");
} else if ((host->data->chip_type == MMC_CHIP_TL1)
&& (clk_ios >= 166000000)) {
src0_clk = devm_clk_get(host->dev, "clkin3");
if (ret)
pr_warn("not get GP0\n");
ret = clk_set_rate(src0_clk, 792000000);
pr_warn("set rate gp0>>>>>>>>>clk:%lu\n",
clk_get_rate(src0_clk));
ret = clk_set_parent(host->mux_parent[0],
src0_clk);
if (ret)
pr_warn("set src0 as comp0 parent error\n");
ret = clk_set_parent(host->mux_clk,
host->mux_parent[0]);
if (ret)
@@ -284,7 +300,7 @@ static int meson_mmc_clk_set_rate_v3(struct mmc_host *mmc,
mmc->actual_clock,
readl(host->clksrc_base + (HHI_NAND_CLK_CNTL << 2)));
pr_debug("[%s] after clock: 0x%x\n",
pr_debug("[%s] after clock: 0x%x\n",
__func__, readl(host->base + SD_EMMC_CLOCK_V3));
return ret;
@@ -303,11 +319,21 @@ static void aml_sd_emmc_set_timing_v3(struct amlsd_platform *pdata,
u8 clk_div = 0;
struct para_e *para = &(host->data->sdmmc);
unsigned int fixdiv = 0, ret = 0;
u32 irq_en = readl(host->base + SD_EMMC_IRQ_EN);
vctrl = readl(host->base + SD_EMMC_CFG);
if ((timing == MMC_TIMING_MMC_HS400) ||
(timing == MMC_TIMING_MMC_DDR52) ||
(timing == MMC_TIMING_UHS_DDR50)) {
if (timing == MMC_TIMING_MMC_DDR52) {
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));
}
if (timing == MMC_TIMING_MMC_HS400) {
/*ctrl->chk_ds = 1;*/
if (host->data->chip_type >= MMC_CHIP_TXLX) {
@@ -321,6 +347,17 @@ static void aml_sd_emmc_set_timing_v3(struct amlsd_platform *pdata,
*/
if (pdata->tx_delay != 0)
clkc->tx_delay = pdata->tx_delay;
if ((host->data->chip_type == MMC_CHIP_TL1)
&& aml_card_type_mmc(pdata)) {
clkc->core_phase = para->hs4.core_phase;
clkc->tx_phase = para->hs4.tx_phase;
irq_en |= (1<<17);
writel(irq_en,
host->base + SD_EMMC_IRQ_EN);
/*improve CMD setup time by half SD_CLK cycle*/
}
}
pr_info("%s: try set sd/emmc to HS400 mode\n",
mmc_hostname(host->mmc));
@@ -330,12 +367,6 @@ 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)) {
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;
/* overide co-phase by dts */
@@ -670,7 +701,7 @@ static int emmc_send_cmd(struct mmc_host *mmc, u32 opcode,
err = mmc_wait_for_cmd(mmc, &cmd, 3);
if (err) {
pr_info("[%s][%d] cmd:0x%x send error\n",
pr_debug("[%s][%d] cmd:0x%x send error\n",
__func__, __LINE__, cmd.opcode);
return err;
}
@@ -758,9 +789,10 @@ RETRY:
eyetest_out1 = readl(host->base + SD_EMMC_EYETEST_OUT1);
gintf3->eyetest_on = 0;
writel(intf3, host->base + SD_EMMC_INTF3);
writel(0, host->base + SD_EMMC_ADJUST_V3);
pdata->intf3 = intf3;
pdata->align[line_x] = ((tmp | eyetest_out1) << 32) | eyetest_out0;
pr_debug("d1:0x%x,d2:0x%x,u64eyet:0x%016llx,l_x:%d\n",
pr_info("d1:0x%x,d2:0x%x,u64eyet:0x%016llx,l_x:%d\n",
readl(host->base + SD_EMMC_DELAY1_V3),
readl(host->base + SD_EMMC_DELAY2_V3),
pdata->align[line_x], line_x);
@@ -885,6 +917,25 @@ static void update_all_line_eyetest(struct mmc_host *mmc)
}
}
static unsigned int tl1_emmc_line_timing(struct mmc_host *mmc)
{
struct amlsd_platform *pdata = mmc_priv(mmc);
struct amlsd_host *host = pdata->host;
u32 delay1 = 0, delay2 = 0, count = 12;
delay1 = (count<<0)|(count<<6)|(count<<12)
|(count<<18)|(count<<24);
delay2 = (count<<0)|(count<<6)|(count<<12)
|(pdata->cmd_c<<24);
writel(delay1, host->base + SD_EMMC_DELAY1_V3);
writel(delay2, host->base + SD_EMMC_DELAY2_V3);
pr_info("[%s], delay1: 0x%x, delay2: 0x%x\n",
__func__, readl(host->base + SD_EMMC_DELAY1_V3),
readl(host->base + SD_EMMC_DELAY2_V3));
return 0;
}
static unsigned int get_emmc_cmd_win(struct mmc_host *mmc)
{
struct amlsd_platform *pdata = mmc_priv(mmc);
@@ -1004,20 +1055,12 @@ static int emmc_ds_manual_sht(struct mmc_host *mmc)
struct intf3 *gintf3 = (struct intf3 *)&(intf3);
u32 blksz = 512;
int i, err = 0;
int match[32];
int match[64];
int best_start = -1, best_size = -1;
int cur_start = -1, cur_size = 0;
sd_emmc_debug = 0x2000;
update_all_line_eyetest(mmc);
emmc_ds_core_align(mmc);
update_all_line_eyetest(mmc);
emmc_all_data_line_alignment(mmc);
update_all_line_eyetest(mmc);
emmc_ds_data_alignment(mmc);
update_all_line_eyetest(mmc);
host->is_tunning = 1;
for (i = 0; i < 32; i++) {
for (i = 0; i < 64; i++) {
gintf3->ds_sht_m += 1;
writel(intf3, host->base + SD_EMMC_INTF3);
pdata->intf3 = intf3;
@@ -1031,7 +1074,7 @@ static int emmc_ds_manual_sht(struct mmc_host *mmc)
else
match[i] = -1;
}
for (i = 0; i < 32; i++) {
for (i = 0; i < 64; i++) {
if (match[i] == 0) {
if (cur_start < 0)
cur_start = i;
@@ -1071,11 +1114,31 @@ static int emmc_ds_manual_sht(struct mmc_host *mmc)
gintf3->ds_sht_m, best_size,
readl(host->base + SD_EMMC_INTF3),
readl(host->base + SD_EMMC_CLOCK_V3));
pr_info("adjust:0x%x\n", readl(host->base + SD_EMMC_ADJUST_V3));
host->is_tunning = 0;
return 0;
}
#endif
static void aml_emmc_hs400_general(struct mmc_host *mmc)
{
update_all_line_eyetest(mmc);
emmc_ds_core_align(mmc);
update_all_line_eyetest(mmc);
emmc_all_data_line_alignment(mmc);
update_all_line_eyetest(mmc);
emmc_ds_data_alignment(mmc);
update_all_line_eyetest(mmc);
emmc_ds_manual_sht(mmc);
}
static void aml_emmc_hs400_tl1(struct mmc_host *mmc)
{
tl1_emmc_line_timing(mmc);
emmc_ds_manual_sht(mmc);
}
/* test clock, return delay cells for one cycle
*/
@@ -1392,6 +1455,47 @@ RETRY:
return 0;
}
int aml_emmc_hs200_tl1(struct mmc_host *mmc)
{
struct amlsd_platform *pdata = mmc_priv(mmc);
struct amlsd_host *host = pdata->host;
u32 vclkc = readl(host->base + SD_EMMC_CLOCK_V3);
struct sd_emmc_clock_v3 *clkc = (struct sd_emmc_clock_v3 *)&vclkc;
struct para_e *para = &(host->data->sdmmc);
u32 clk_bak = 0;
u32 delay2 = 0, count = 0;
int i, err = 0;
clk_bak = vclkc;
clkc->core_phase = para->hs4.core_phase;
clkc->tx_delay = para->hs4.tx_delay;
if (pdata->tx_delay != 0)
clkc->tx_delay = pdata->tx_delay;
writel(vclkc, host->base + SD_EMMC_CLOCK_V3);
pr_info("[%s][%d] clk config:0x%x\n",
__func__, __LINE__, readl(host->base + SD_EMMC_CLOCK_V3));
for (i = 0; i < 63; i++) {
delay2 += (1 << 24);
writel(delay2, host->base + SD_EMMC_DELAY2_V3);
err = emmc_eyetest_log(mmc, 9);
if (err)
continue;
count = fbinary(pdata->align[9]);
if (((count >= 10) && (count <= 22))
|| ((count >= 43) && (count <= 56)))
break;
}
if (i == 63)
pr_err("[%s]no find cmd timing\n", __func__);
pdata->cmd_c = (delay2 >> 24);
writel(0, host->base + SD_EMMC_DELAY2_V3);
writel(clk_bak, host->base + SD_EMMC_CLOCK_V3);
pr_info("[%s][%d] clk config:0x%x\n",
__func__, __LINE__, readl(host->base + SD_EMMC_CLOCK_V3));
return 0;
}
int __attribute__((unused)) aml_emmc_hs200_timming(struct mmc_host *mmc)
{
struct amlsd_platform *pdata = mmc_priv(mmc);
@@ -1652,6 +1756,8 @@ int aml_mmc_execute_tuning_v3(struct mmc_host *mmc, u32 opcode)
intf3 |= (1<<22);
writel(intf3, (host->base + SD_EMMC_INTF3));
pdata->intf3 = intf3;
if (host->data->chip_type == MMC_CHIP_TL1)
aml_emmc_hs200_tl1(mmc);
err = 0;
}
@@ -1664,9 +1770,13 @@ int aml_mmc_execute_tuning_v3(struct mmc_host *mmc, u32 opcode)
}
int aml_post_hs400_timming(struct mmc_host *mmc)
{
int ret = 0;
struct amlsd_platform *pdata = mmc_priv(mmc);
struct amlsd_host *host = pdata->host;
aml_sd_emmc_clktest(mmc);
ret = emmc_ds_manual_sht(mmc);
if (host->data->chip_type == MMC_CHIP_TL1)
aml_emmc_hs400_tl1(mmc);
else
aml_emmc_hs400_general(mmc);
return 0;
}

View File

@@ -1192,15 +1192,20 @@ static int mmc_select_hs400(struct mmc_card *card)
pr_info("%s: no support driver strength type 1 and 4\n",
mmc_hostname(host));
}
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
true, true, true);
#else
val = EXT_CSD_TIMING_HS400 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
#endif
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
true, false, true);
#endif
if (err) {
pr_err("%s: switch to hs400 failed, err:%d\n",
mmc_hostname(host), err);
@@ -1211,9 +1216,11 @@ static int mmc_select_hs400(struct mmc_card *card)
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
mmc_set_bus_speed(card);
#ifndef CONFIG_AMLOGIC_MMC
err = mmc_switch_status(card);
if (err)
goto out_err;
#endif
return 0;

View File

@@ -331,6 +331,7 @@ struct amlsd_platform {
u64 align[10];
int base_line;
unsigned int count;
unsigned int cmd_c;
unsigned int delay_cell;
/* int order; */
unsigned int rx_err;