Skip to content

Commit c4ac38c

Browse files
wenbinmei1storulf
authored andcommitted
mmc: mtk-sd: Add HS400 online tuning support
According to JEDEC Spec, there is no need to do tuning under HS400 mode since the Rx signal is aligned with the DS signal. However, MediaTek's IC need set its "DS delay" internally to ensure it can latch Rx signal correctly. In previous version, We provide an "hs400-ds-delay" in device tree to cover different chipset/PCB design, and it works fine in most cases. But, with the development of process technology and the big VCore voltage scale range(may have 0.7V/0.6V/0.55V), it is difficult to find a suitable "hs400-ds-delay" to cover all of IC corner cases(SSSS/TTTT/FFFF). So that We must have the ability to do hs400 online tuning. Signed-off-by: Wenbin Mei <wenbin.mei@mediatek.com> Reviewed-by: Chaotian Jing <chaotian.jing@mediatek.com> Link: https://lore.kernel.org/r/20210917124803.22871-4-wenbin.mei@mediatek.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent f614fb6 commit c4ac38c

File tree

1 file changed

+77
-2
lines changed

1 file changed

+77
-2
lines changed

drivers/mmc/host/mtk-sd.c

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@
259259
#define MSDC_PAD_TUNE_RD_SEL (0x1 << 13) /* RW */
260260
#define MSDC_PAD_TUNE_CMD_SEL (0x1 << 21) /* RW */
261261

262+
#define PAD_DS_TUNE_DLY_SEL (0x1 << 0) /* RW */
262263
#define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */
263264
#define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */
264265
#define PAD_DS_TUNE_DLY3 (0x1f << 12) /* RW */
@@ -302,6 +303,11 @@
302303
#define PAD_CMD_RD_RXDLY_SEL (0x1 << 11) /* RW */
303304
#define PAD_CMD_TX_DLY (0x1f << 12) /* RW */
304305

306+
/* EMMC50_PAD_DS_TUNE mask */
307+
#define PAD_DS_DLY_SEL (0x1 << 16) /* RW */
308+
#define PAD_DS_DLY1 (0x1f << 10) /* RW */
309+
#define PAD_DS_DLY3 (0x1f << 0) /* RW */
310+
305311
#define REQ_CMD_EIO (0x1 << 0)
306312
#define REQ_CMD_TMO (0x1 << 1)
307313
#define REQ_DAT_ERR (0x1 << 2)
@@ -449,11 +455,13 @@ struct msdc_host {
449455
bool vqmmc_enabled;
450456
u32 latch_ck;
451457
u32 hs400_ds_delay;
458+
u32 hs400_ds_dly3;
452459
u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */
453460
u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */
454461
bool hs400_cmd_resp_sel_rising;
455462
/* cmd response sample selection for HS400 */
456463
bool hs400_mode; /* current eMMC will run at hs400 mode */
464+
bool hs400_tuning; /* hs400 mode online tuning */
457465
bool internal_cd; /* Use internal card-detect logic */
458466
bool cqhci; /* support eMMC hw cmdq */
459467
struct msdc_save_para save_para; /* used when gate HCLK */
@@ -1190,7 +1198,8 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
11901198
if (!sbc_error && !(events & MSDC_INT_CMDRDY)) {
11911199
if (events & MSDC_INT_CMDTMO ||
11921200
(cmd->opcode != MMC_SEND_TUNING_BLOCK &&
1193-
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200))
1201+
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
1202+
!host->hs400_tuning))
11941203
/*
11951204
* should not clear fifo/interrupt as the tune data
11961205
* may have alreay come when cmd19/cmd21 gets response
@@ -1287,7 +1296,8 @@ static void msdc_cmd_next(struct msdc_host *host,
12871296
if ((cmd->error &&
12881297
!(cmd->error == -EILSEQ &&
12891298
(cmd->opcode == MMC_SEND_TUNING_BLOCK ||
1290-
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200))) ||
1299+
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
1300+
host->hs400_tuning))) ||
12911301
(mrq->sbc && mrq->sbc->error))
12921302
msdc_request_done(host, mrq);
12931303
else if (cmd == mrq->sbc)
@@ -2251,6 +2261,67 @@ static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
22512261
return 0;
22522262
}
22532263

2264+
static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card)
2265+
{
2266+
struct msdc_host *host = mmc_priv(mmc);
2267+
struct msdc_delay_phase dly1_delay;
2268+
u32 val, result_dly1 = 0;
2269+
u8 *ext_csd;
2270+
int i, ret;
2271+
2272+
if (host->top_base) {
2273+
sdr_set_bits(host->top_base + EMMC50_PAD_DS_TUNE,
2274+
PAD_DS_DLY_SEL);
2275+
if (host->hs400_ds_dly3)
2276+
sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE,
2277+
PAD_DS_DLY3, host->hs400_ds_dly3);
2278+
} else {
2279+
sdr_set_bits(host->base + PAD_DS_TUNE, PAD_DS_TUNE_DLY_SEL);
2280+
if (host->hs400_ds_dly3)
2281+
sdr_set_field(host->base + PAD_DS_TUNE,
2282+
PAD_DS_TUNE_DLY3, host->hs400_ds_dly3);
2283+
}
2284+
2285+
host->hs400_tuning = true;
2286+
for (i = 0; i < PAD_DELAY_MAX; i++) {
2287+
if (host->top_base)
2288+
sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE,
2289+
PAD_DS_DLY1, i);
2290+
else
2291+
sdr_set_field(host->base + PAD_DS_TUNE,
2292+
PAD_DS_TUNE_DLY1, i);
2293+
ret = mmc_get_ext_csd(card, &ext_csd);
2294+
if (!ret)
2295+
result_dly1 |= (1 << i);
2296+
}
2297+
host->hs400_tuning = false;
2298+
2299+
dly1_delay = get_best_delay(host, result_dly1);
2300+
if (dly1_delay.maxlen == 0) {
2301+
dev_err(host->dev, "Failed to get DLY1 delay!\n");
2302+
goto fail;
2303+
}
2304+
if (host->top_base)
2305+
sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE,
2306+
PAD_DS_DLY1, dly1_delay.final_phase);
2307+
else
2308+
sdr_set_field(host->base + PAD_DS_TUNE,
2309+
PAD_DS_TUNE_DLY1, dly1_delay.final_phase);
2310+
2311+
if (host->top_base)
2312+
val = readl(host->top_base + EMMC50_PAD_DS_TUNE);
2313+
else
2314+
val = readl(host->base + PAD_DS_TUNE);
2315+
2316+
dev_info(host->dev, "Fianl PAD_DS_TUNE: 0x%x\n", val);
2317+
2318+
return 0;
2319+
2320+
fail:
2321+
dev_err(host->dev, "Failed to tuning DS pin delay!\n");
2322+
return -EIO;
2323+
}
2324+
22542325
static void msdc_hw_reset(struct mmc_host *mmc)
22552326
{
22562327
struct msdc_host *host = mmc_priv(mmc);
@@ -2381,6 +2452,7 @@ static const struct mmc_host_ops mt_msdc_ops = {
23812452
.card_busy = msdc_card_busy,
23822453
.execute_tuning = msdc_execute_tuning,
23832454
.prepare_hs400_tuning = msdc_prepare_hs400_tuning,
2455+
.execute_hs400_tuning = msdc_execute_hs400_tuning,
23842456
.hw_reset = msdc_hw_reset,
23852457
};
23862458

@@ -2400,6 +2472,9 @@ static void msdc_of_property_parse(struct platform_device *pdev,
24002472
of_property_read_u32(pdev->dev.of_node, "hs400-ds-delay",
24012473
&host->hs400_ds_delay);
24022474

2475+
of_property_read_u32(pdev->dev.of_node, "mediatek,hs400-ds-dly3",
2476+
&host->hs400_ds_dly3);
2477+
24032478
of_property_read_u32(pdev->dev.of_node, "mediatek,hs200-cmd-int-delay",
24042479
&host->hs200_cmd_int_delay);
24052480

0 commit comments

Comments
 (0)