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

mmc: sdhci-esdhc-imx: optimize the manual tuing logic to get the best timing

Current manual tuning logic only get the first pass window, but
this pass window maybe not the best pass window.

Now find all the pass window, and chose the largest pass window,
and use the average value of this largest pass window to get the
best timing.

Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/20230831032647.3128702-1-haibo.chen@nxp.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Haibo Chen and committed by
Ulf Hansson
541a95e6 a5b5006e

+36 -16
+36 -16
drivers/mmc/host/sdhci-esdhc-imx.c
··· 1154 1154 writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 1155 1155 } 1156 1156 1157 + /* 1158 + * find the largest pass window, and use the average delay of this 1159 + * largest window to get the best timing. 1160 + */ 1157 1161 static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) 1158 1162 { 1159 1163 int min, max, avg, ret; 1164 + int win_length, target_min, target_max, target_win_length; 1160 1165 1161 - /* find the mininum delay first which can pass tuning */ 1162 1166 min = ESDHC_TUNE_CTRL_MIN; 1163 - while (min < ESDHC_TUNE_CTRL_MAX) { 1164 - esdhc_prepare_tuning(host, min); 1165 - if (!mmc_send_tuning(host->mmc, opcode, NULL)) 1166 - break; 1167 - min += ESDHC_TUNE_CTRL_STEP; 1168 - } 1169 - 1170 - /* find the maxinum delay which can not pass tuning */ 1171 - max = min + ESDHC_TUNE_CTRL_STEP; 1167 + max = ESDHC_TUNE_CTRL_MIN; 1168 + target_win_length = 0; 1172 1169 while (max < ESDHC_TUNE_CTRL_MAX) { 1173 - esdhc_prepare_tuning(host, max); 1174 - if (mmc_send_tuning(host->mmc, opcode, NULL)) { 1175 - max -= ESDHC_TUNE_CTRL_STEP; 1176 - break; 1170 + /* find the mininum delay first which can pass tuning */ 1171 + while (min < ESDHC_TUNE_CTRL_MAX) { 1172 + esdhc_prepare_tuning(host, min); 1173 + if (!mmc_send_tuning(host->mmc, opcode, NULL)) 1174 + break; 1175 + min += ESDHC_TUNE_CTRL_STEP; 1177 1176 } 1178 - max += ESDHC_TUNE_CTRL_STEP; 1177 + 1178 + /* find the maxinum delay which can not pass tuning */ 1179 + max = min + ESDHC_TUNE_CTRL_STEP; 1180 + while (max < ESDHC_TUNE_CTRL_MAX) { 1181 + esdhc_prepare_tuning(host, max); 1182 + if (mmc_send_tuning(host->mmc, opcode, NULL)) { 1183 + max -= ESDHC_TUNE_CTRL_STEP; 1184 + break; 1185 + } 1186 + max += ESDHC_TUNE_CTRL_STEP; 1187 + } 1188 + 1189 + win_length = max - min + 1; 1190 + /* get the largest pass window */ 1191 + if (win_length > target_win_length) { 1192 + target_win_length = win_length; 1193 + target_min = min; 1194 + target_max = max; 1195 + } 1196 + 1197 + /* continue to find the next pass window */ 1198 + min = max + ESDHC_TUNE_CTRL_STEP; 1179 1199 } 1180 1200 1181 1201 /* use average delay to get the best timing */ 1182 - avg = (min + max) / 2; 1202 + avg = (target_min + target_max) / 2; 1183 1203 esdhc_prepare_tuning(host, avg); 1184 1204 ret = mmc_send_tuning(host->mmc, opcode, NULL); 1185 1205 esdhc_post_tuning(host);