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>
Signed-off-by: Luan Yuan <luan.yuan@amlogic.com>
This commit is contained in:
Long Yu
2018-12-14 17:13:36 +08:00
committed by Luan Yuan
parent 701ea0f9e7
commit 09146b28cf
7 changed files with 165 additions and 34 deletions

View File

@@ -1120,8 +1120,9 @@
<&clkc CLKID_SD_EMMC_C_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>,
<&clkc CLKID_FCLK_DIV5>,
<&clkc CLKID_GP0_PLL>,
<&xtal>;
clock-names = "core", "clkin0", "clkin1", "clkin2", "xtal";
clock-names = "core","clkin0","clkin1","clkin2","clkin3","xtal";
bus-width = <8>;
cap-sd-highspeed;

View File

@@ -1318,10 +1318,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",
@@ -3327,6 +3327,16 @@ static int meson_mmc_probe(struct platform_device *pdev)
#endif /* CONFIG_MESON_CPU_EMULATOR */
}
pr_info("%s() : success!\n", __func__);
if (host->ctrl_ver >= 3) {
ret = device_create_file(&pdev->dev, &dev_attr_emmc_eyetest);
if (ret)
dev_warn(mmc_dev(host->mmc),
"Unable to creat sysfs attributes\n");
ret = device_create_file(&pdev->dev, &dev_attr_emmc_clktest);
if (ret)
dev_warn(mmc_dev(host->mmc),
"Unable to creat sysfs attributes\n");
}
return 0;
free_host:
@@ -3581,9 +3591,11 @@ static struct meson_mmc_data mmc_data_g12b = {
.sdmmc.hs.core_phase = 1,
.sdmmc.ddr.core_phase = 2,
.sdmmc.ddr.tx_phase = 0,
.sdmmc.hs2.core_phase = 3,
.sdmmc.hs2.core_phase = 2,
.sdmmc.hs2.tx_phase = 0,
.sdmmc.hs4.tx_delay = 0,
.sdmmc.hs4.tx_phase = 0,
.sdmmc.hs4.core_phase = 0,
.sdmmc.hs4.tx_delay = 16,
.sdmmc.sd_hs.core_phase = 2,
.sdmmc.sdr104.core_phase = 2,
.sdmmc.sdr104.tx_phase = 0,
@@ -3604,8 +3616,9 @@ static struct meson_mmc_data mmc_data_tl1 = {
.sdmmc.init.rx_phase = 0,
.sdmmc.hs.core_phase = 1,
.sdmmc.ddr.core_phase = 2,
.sdmmc.hs2.core_phase = 3,
.sdmmc.hs4.tx_delay = 0,
.sdmmc.hs2.core_phase = 2,
.sdmmc.hs4.core_phase = 0,
.sdmmc.hs4.tx_delay = 16,
.sdmmc.sd_hs.core_phase = 2,
.sdmmc.sdr104.core_phase = 2,
};

View File

@@ -234,7 +234,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)
@@ -278,7 +294,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;
@@ -297,11 +313,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) {
@@ -315,6 +341,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));
@@ -324,12 +361,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 */
@@ -658,7 +689,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;
}
@@ -746,9 +777,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);
@@ -873,6 +905,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);
@@ -992,20 +1043,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;
@@ -1019,7 +1062,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;
@@ -1059,11 +1102,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
*/
@@ -1382,6 +1445,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);
@@ -1642,6 +1746,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;
}
@@ -1654,9 +1760,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;