[SPLIT] sdhci-tegra: fix tuning procedure

This commit is contained in:
2025-12-27 03:00:47 +00:00
parent f7485a509b
commit c29dd5c99e

View File

@@ -415,7 +415,6 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
if (!(mask & SDHCI_RESET_ALL)) if (!(mask & SDHCI_RESET_ALL))
return; return;
if (tegra_get_platform() == TEGRA_PLATFORM_SILICON)
tegra_sdhci_write_prod_settings(host, "prod"); tegra_sdhci_write_prod_settings(host, "prod");
tegra_sdhci_set_tap(host, tegra_host->default_tap); tegra_sdhci_set_tap(host, tegra_host->default_tap);
@@ -985,7 +984,7 @@ static void tegra_sdhci_post_tuning(struct sdhci_host *host)
u32 avg_tap_dly, val, min_tap_dly, max_tap_dly; u32 avg_tap_dly, val, min_tap_dly, max_tap_dly;
u8 fixed_tap, start_tap, end_tap, window_width; u8 fixed_tap, start_tap, end_tap, window_width;
u8 thdupper, thdlower; u8 thdupper, thdlower;
u8 num_iter; u16 num_iter;
u32 clk_rate_mhz, period_ps, bestcase, worstcase; u32 clk_rate_mhz, period_ps, bestcase, worstcase;
/* retain HW tuned tap to use incase if no correction is needed */ /* retain HW tuned tap to use incase if no correction is needed */
@@ -1017,7 +1016,33 @@ static void tegra_sdhci_post_tuning(struct sdhci_host *host)
end_tap = (val >> SDHCI_TEGRA_VNDR_TUN_STATUS1_END_TAP_SHIFT) & end_tap = (val >> SDHCI_TEGRA_VNDR_TUN_STATUS1_END_TAP_SHIFT) &
SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK; SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK;
window_width = end_tap - start_tap; window_width = end_tap - start_tap;
num_iter = host->tuning_loop_count;
num_iter = (sdhci_readl(host, SDHCI_VNDR_TUN_CTRL0_0) &
SDHCI_VNDR_TUN_CTRL0_TUN_ITER_MASK) >>
SDHCI_VNDR_TUN_CTRL0_TUN_ITER_SHIFT;
switch (num_iter) {
case 0:
num_iter = 40;
break;
case 1:
num_iter = 64;
break;
case 2:
num_iter = 128;
break;
case 3:
num_iter = 196;
break;
case 4:
num_iter = 256;
break;
default:
WARN_ON("Invalid value of number of tuning iterations");
}
host->tuning_loop_count = num_iter;
/* /*
* partial window includes edges of the tuning range. * partial window includes edges of the tuning range.
* merged window includes more taps so window width is higher * merged window includes more taps so window width is higher
@@ -1029,6 +1054,8 @@ static void tegra_sdhci_post_tuning(struct sdhci_host *host)
mmc_hostname(host->mmc)); mmc_hostname(host->mmc));
tegra_sdhci_tap_correction(host, thdupper, thdlower, tegra_sdhci_tap_correction(host, thdupper, thdlower,
fixed_tap); fixed_tap);
pr_info("%s: Tap value after applying correction %u\n",
mmc_hostname(host->mmc), tegra_host->tuned_tap_delay);
} }
} }
@@ -1052,12 +1079,12 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
bool set_default_tap = false; bool set_default_tap = false; // opposite of tuning_mode
bool set_num_tun_iter = false;
bool set_dqs_trim = false; bool set_dqs_trim = false;
bool do_hs400_dll_cal = false; bool do_hs400_dll_cal = false;
bool set_padpipe_clk_override = false; bool set_padpipe_clk_override = false;
u8 iter = TRIES_256; u32 ret;
u32 val;
tegra_host->ddr_signaling = false; tegra_host->ddr_signaling = false;
switch (timing) { switch (timing) {
@@ -1066,13 +1093,13 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
case MMC_TIMING_UHS_SDR104: case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_MMC_HS200: case MMC_TIMING_MMC_HS200:
/* Don't set default tap on tunable modes. */ /* Don't set default tap on tunable modes. */
iter = TRIES_128; set_num_tun_iter = true;
break; break;
case MMC_TIMING_MMC_HS400: case MMC_TIMING_MMC_HS400:
set_dqs_trim = true; set_dqs_trim = true;
do_hs400_dll_cal = true; do_hs400_dll_cal = true;
iter = TRIES_128;
set_padpipe_clk_override = true; set_padpipe_clk_override = true;
set_num_tun_iter = true;
break; break;
case MMC_TIMING_MMC_DDR52: case MMC_TIMING_MMC_DDR52:
case MMC_TIMING_UHS_DDR50: case MMC_TIMING_UHS_DDR50:
@@ -1084,18 +1111,6 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
break; break;
} }
val = sdhci_readl(host, SDHCI_VNDR_TUN_CTRL0_0);
val &= ~(SDHCI_VNDR_TUN_CTRL0_TUN_ITER_MASK |
SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_MASK |
SDHCI_VNDR_TUN_CTRL0_MUL_M_MASK);
val |= (iter << SDHCI_VNDR_TUN_CTRL0_TUN_ITER_SHIFT |
0 << SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_SHIFT |
1 << SDHCI_VNDR_TUN_CTRL0_MUL_M_SHIFT);
sdhci_writel(host, val, SDHCI_VNDR_TUN_CTRL0_0);
sdhci_writel(host, 0, SDHCI_TEGRA_VNDR_TUN_CTRL1_0);
host->tuning_loop_count = (iter == TRIES_128) ? 128 : 256;
sdhci_set_uhs_signaling(host, timing); sdhci_set_uhs_signaling(host, timing);
tegra_sdhci_pad_autocalib(host); tegra_sdhci_pad_autocalib(host);
@@ -1107,8 +1122,26 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
/*set padpipe_clk_override*/ /*set padpipe_clk_override*/
if (set_padpipe_clk_override) { if (set_padpipe_clk_override) {
tegra_sdhci_write_prod_settings(host, ret = tegra_prod_set_by_name_partially(&host->ioaddr,
prod_device_states[timing]); prod_device_states[timing], tegra_host->prod_list,
0, SDHCI_TEGRA_VENDOR_CLOCK_CTRL,
SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE);
if (ret < 0)
dev_err(mmc_dev(host->mmc),
"Failed to set padpipe clk override value for timing %d, %d\n",
timing, ret);
}
/* Set number of tuning iterations */
if (set_num_tun_iter) {
ret = tegra_prod_set_by_name_partially(&host->ioaddr,
prod_device_states[timing], tegra_host->prod_list,
0, SDHCI_VNDR_TUN_CTRL0_0,
SDHCI_VNDR_TUN_CTRL0_TUN_WORD_SEL_MASK <<
SDHCI_VNDR_TUN_CTRL0_TUN_ITER_SHIFT);
if (ret < 0)
dev_err(mmc_dev(host->mmc),
"Failed to set number of iterations for timing %d, %d\n",
timing, ret);
} }
if (set_dqs_trim) if (set_dqs_trim)
tegra_sdhci_set_dqs_trim(host, tegra_host->dqs_trim); tegra_sdhci_set_dqs_trim(host, tegra_host->dqs_trim);
@@ -1180,9 +1213,6 @@ static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc,
static int tegra_sdhci_init_pinctrl_info(struct device *dev, static int tegra_sdhci_init_pinctrl_info(struct device *dev,
struct sdhci_tegra *tegra_host) struct sdhci_tegra *tegra_host)
{ {
if (!(tegra_get_platform() == TEGRA_PLATFORM_SILICON))
return 0;
tegra_host->prod_list = devm_tegra_prod_get(dev); tegra_host->prod_list = devm_tegra_prod_get(dev);
if (IS_ERR_OR_NULL(tegra_host->prod_list)) { if (IS_ERR_OR_NULL(tegra_host->prod_list)) {
dev_dbg(dev, "Prod-setting not available\n"); dev_dbg(dev, "Prod-setting not available\n");