Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: renesas_sdhi: Avoid bad TAP in HS400

With R-Car Gen3, CRC error occue at the following TAPs.

H3, M3W 1.3, M3N... TAP=2,3,6,7
M3W 3.0 ... TAP=1,3,5,7

(Note: for 4tap SoCs, the numbers get divided by 2)

Do not use these TAPs in HS400, and also don't use auto correction but
manual correction.

We check for bad taps in two places:

1) After tuning HS400: Then, we select a neighbouring TAP. One of them
must be good, because there are never three bad taps in a row.
Retuning won't help because we just finished tuning.

2) After a manual correction request: Here, we can't switch to the
requested TAP. But we can retune (if the HS200 tuning was good)
because the environment might have changed since the last tuning.
If not, we stay on the same TAP.

Signed-off-by: Takeshi Saito <takeshi.saito.xv@renesas.com>
[wsa: refactored to match upstream driver, reworded commit msg]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Link: https://lore.kernel.org/r/20200423130432.9990-3-wsa+renesas@sang-engineering.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Takeshi Saito and committed by
Ulf Hansson
a38c078f f583da40

+48 -8
+1
drivers/mmc/host/renesas_sdhi.h
··· 36 36 struct renesas_sdhi_quirks { 37 37 bool hs400_disabled; 38 38 bool hs400_4taps; 39 + u32 hs400_bad_taps; 39 40 }; 40 41 41 42 struct tmio_mmc_dma {
+47 -8
drivers/mmc/host/renesas_sdhi_core.c
··· 325 325 { 326 326 struct tmio_mmc_host *host = mmc_priv(mmc); 327 327 struct renesas_sdhi *priv = host_to_priv(host); 328 + u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0; 329 + bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; 328 330 329 331 sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & 330 332 sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); ··· 354 352 SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN | 355 353 0x4 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT); 356 354 355 + /* Avoid bad TAP */ 356 + if (bad_taps & BIT(priv->tap_set)) { 357 + u32 new_tap = (priv->tap_set + 1) % priv->tap_num; 357 358 358 - if (priv->quirks && priv->quirks->hs400_4taps) 359 - sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, 360 - priv->tap_set / 2); 359 + if (bad_taps & BIT(new_tap)) 360 + new_tap = (priv->tap_set - 1) % priv->tap_num; 361 + 362 + if (bad_taps & BIT(new_tap)) { 363 + new_tap = priv->tap_set; 364 + dev_dbg(&host->pdev->dev, "Can't handle three bad tap in a row\n"); 365 + } 366 + 367 + priv->tap_set = new_tap; 368 + } 369 + 370 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, 371 + priv->tap_set / (use_4tap ? 2 : 1)); 361 372 362 373 sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, 363 374 SH_MOBILE_SDHI_SCC_CKSEL_DTSEL | ··· 542 527 static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap) 543 528 { 544 529 struct renesas_sdhi *priv = host_to_priv(host); 545 - unsigned int new_tap = priv->tap_set; 530 + unsigned int new_tap = priv->tap_set, error_tap = priv->tap_set; 546 531 u32 val; 547 532 548 533 val = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ); ··· 554 539 /* Change TAP position according to correction status */ 555 540 if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN3_SDMMC && 556 541 host->mmc->ios.timing == MMC_TIMING_MMC_HS400) { 542 + u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0; 557 543 /* 558 544 * With HS400, the DAT signal is based on DS, not CLK. 559 545 * Therefore, use only CMD status. 560 546 */ 561 547 u32 smpcmp = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) & 562 548 SH_MOBILE_SDHI_SCC_SMPCMP_CMD_ERR; 563 - if (!smpcmp) 549 + if (!smpcmp) { 564 550 return false; /* no error in CMD signal */ 565 - else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP) 551 + } else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP) { 566 552 new_tap++; 567 - else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQDOWN) 553 + error_tap--; 554 + } else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQDOWN) { 568 555 new_tap--; 569 - else 556 + error_tap++; 557 + } else { 570 558 return true; /* need retune */ 559 + } 560 + 561 + /* 562 + * When new_tap is a bad tap, we cannot change. Then, we compare 563 + * with the HS200 tuning result. When smpcmp[error_tap] is OK, 564 + * we can at least retune. 565 + */ 566 + if (bad_taps & BIT(new_tap % priv->tap_num)) 567 + return test_bit(error_tap % priv->tap_num, priv->smpcmp); 571 568 } else { 572 569 if (val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) 573 570 return true; /* need retune */ ··· 732 705 733 706 static const struct renesas_sdhi_quirks sdhi_quirks_4tap = { 734 707 .hs400_4taps = true, 708 + .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), 735 709 }; 736 710 737 711 static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = { 738 712 .hs400_disabled = true, 713 + }; 714 + 715 + static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps1357 = { 716 + .hs400_bad_taps = BIT(1) | BIT(3) | BIT(5) | BIT(7), 717 + }; 718 + 719 + static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps2367 = { 720 + .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), 739 721 }; 740 722 741 723 /* ··· 756 720 { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, 757 721 { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_4tap_nohs400 }, 758 722 { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap }, 723 + { .soc_id = "r8a7795", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps2367 }, 759 724 { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, 760 725 { .soc_id = "r8a7796", .revision = "ES1.*", .data = &sdhi_quirks_4tap }, 726 + { .soc_id = "r8a7796", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps1357 }, 727 + { .soc_id = "r8a77965", .data = &sdhi_quirks_bad_taps2367 }, 761 728 { .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 }, 762 729 { /* Sentinel. */ }, 763 730 };