mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
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:
@@ -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;
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user