static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) { unsigned int min, max; /* * Start search for minimum tap value at 10, as smaller values are * may wrongly be reported as working but fail at higher speeds, * according to the TRM. */ min = 10; while (min < 255) { tegra_sdhci_set_tap(host, min); if (!mmc_send_tuning(host->mmc, opcode, NULL)) break; min++; } /* Find the maximum tap value that still passes. */ max = min + 1; while (max < 255) { tegra_sdhci_set_tap(host, max); if (mmc_send_tuning(host->mmc, opcode, NULL)) { max--; break; } max++; } /* The TRM states the ideal tap value is at 75% in the passing range. */ tegra_sdhci_set_tap(host, min + ((max - min) * 3 / 4)); return mmc_send_tuning(host->mmc, opcode, NULL); }
static int __maybe_unused sdhci_cdns_execute_tuning(struct udevice *dev, unsigned int opcode) { struct sdhci_cdns_plat *plat = dev_get_platdata(dev); struct mmc *mmc = &plat->mmc; int cur_streak = 0; int max_streak = 0; int end_of_streak = 0; int i; /* * This handler only implements the eMMC tuning that is specific to * this controller. The tuning for SD timing should be handled by the * SDHCI core. */ if (!IS_MMC(mmc)) return -ENOTSUPP; if (WARN_ON(opcode != MMC_CMD_SEND_TUNING_BLOCK_HS200)) return -EINVAL; for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) { if (sdhci_cdns_set_tune_val(plat, i) || mmc_send_tuning(mmc, opcode, NULL)) { /* bad */ cur_streak = 0; } else { /* good */ cur_streak++; if (cur_streak > max_streak) { max_streak = cur_streak; end_of_streak = i; } } } if (!max_streak) { dev_err(dev, "no tuning point found\n"); return -EIO; } return sdhci_cdns_set_tune_val(plat, end_of_streak - max_streak / 2); }
static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) { int tuning_seq_cnt = 3; int phase; u8 tuned_phase_cnt = 0; int rc = 0, longest_range = 0; int start = -1, end = 0, tuning_value = -1, range = 0; u16 clock_setting; struct mmc_host *mmc = host->mmc; clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING); clock_setting &= ~0x3fff; retry: phase = 0; tuned_phase_cnt = 0; do { sdhci_writel(host, clock_setting | phase, SDHCI_CLK_DELAY_SETTING); if (!mmc_send_tuning(mmc, opcode, NULL)) { /* Tuning is successful at this tuning point */ tuned_phase_cnt++; dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", mmc_hostname(mmc), phase); if (start == -1) start = phase; end = phase; range++; if (phase == (SIRF_TUNING_COUNT - 1) && range > longest_range) tuning_value = (start + end) / 2; } else { dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n", mmc_hostname(mmc), phase); if (range > longest_range) { tuning_value = (start + end) / 2; longest_range = range; } start = -1; end = range = 0; } } while (++phase < SIRF_TUNING_COUNT); if (tuned_phase_cnt && tuning_value > 0) { /* * Finally set the selected phase in delay * line hw block. */ phase = tuning_value; sdhci_writel(host, clock_setting | phase, SDHCI_CLK_DELAY_SETTING); dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", mmc_hostname(mmc), phase); } else { if (--tuning_seq_cnt) goto retry; /* Tuning failed */ dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", mmc_hostname(mmc)); rc = -EIO; } return rc; }
static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) { int tuning_seq_cnt = 3; u8 phase, tuned_phases[16], tuned_phase_cnt = 0; int rc; struct mmc_host *mmc = host->mmc; struct mmc_ios ios = host->mmc->ios; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); /* * Tuning is required for SDR104, HS200 and HS400 cards and * if clock frequency is greater than 100MHz in these modes. */ if (host->clock <= CORE_FREQ_100MHZ || !(ios.timing == MMC_TIMING_MMC_HS400 || ios.timing == MMC_TIMING_MMC_HS200 || ios.timing == MMC_TIMING_UHS_SDR104)) return 0; retry: /* First of all reset the tuning block */ rc = msm_init_cm_dll(host); if (rc) return rc; phase = 0; do { /* Set the phase in delay line hw block */ rc = msm_config_cm_dll_phase(host, phase); if (rc) return rc; msm_host->saved_tuning_phase = phase; rc = mmc_send_tuning(mmc, opcode, NULL); if (!rc) { /* Tuning is successful at this tuning point */ tuned_phases[tuned_phase_cnt++] = phase; dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", mmc_hostname(mmc), phase); } } while (++phase < ARRAY_SIZE(tuned_phases)); if (tuned_phase_cnt) { rc = msm_find_most_appropriate_phase(host, tuned_phases, tuned_phase_cnt); if (rc < 0) return rc; else phase = rc; /* * Finally set the selected phase in delay * line hw block. */ rc = msm_config_cm_dll_phase(host, phase); if (rc) return rc; dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", mmc_hostname(mmc), phase); } else { if (--tuning_seq_cnt) goto retry; /* Tuning failed */ dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", mmc_hostname(mmc)); rc = -EIO; } if (!rc) msm_host->tuning_done = true; return rc; }
static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode) { struct dw_mci *host = slot->host; struct dw_mci_rockchip_priv_data *priv = host->priv; struct mmc_host *mmc = slot->mmc; int ret = 0; int i; bool v, prev_v = 0, first_v; struct range_t { int start; int end; /* inclusive */ }; struct range_t *ranges; unsigned int range_count = 0; int longest_range_len = -1; int longest_range = -1; int middle_phase; if (IS_ERR(priv->sample_clk)) { dev_err(host->dev, "Tuning clock (sample_clk) not defined.\n"); return -EIO; } ranges = kmalloc_array(NUM_PHASES / 2 + 1, sizeof(*ranges), GFP_KERNEL); if (!ranges) return -ENOMEM; /* Try each phase and extract good ranges */ for (i = 0; i < NUM_PHASES; ) { clk_set_phase(priv->sample_clk, TUNING_ITERATION_TO_PHASE(i)); v = !mmc_send_tuning(mmc, opcode, NULL); if (i == 0) first_v = v; if ((!prev_v) && v) { range_count++; ranges[range_count-1].start = i; } if (v) { ranges[range_count-1].end = i; i++; } else if (i == NUM_PHASES - 1) { /* No extra skipping rules if we're at the end */ i++; } else { /* * No need to check too close to an invalid * one since testing bad phases is slow. Skip * 20 degrees. */ i += DIV_ROUND_UP(20 * NUM_PHASES, 360); /* Always test the last one */ if (i >= NUM_PHASES) i = NUM_PHASES - 1; } prev_v = v; } if (range_count == 0) { dev_warn(host->dev, "All phases bad!"); ret = -EIO; goto free; } /* wrap around case, merge the end points */ if ((range_count > 1) && first_v && v) { ranges[0].start = ranges[range_count-1].start; range_count--; } if (ranges[0].start == 0 && ranges[0].end == NUM_PHASES - 1) { clk_set_phase(priv->sample_clk, priv->default_sample_phase); dev_info(host->dev, "All phases work, using default phase %d.", priv->default_sample_phase); goto free; } /* Find the longest range */ for (i = 0; i < range_count; i++) { int len = (ranges[i].end - ranges[i].start + 1); if (len < 0) len += NUM_PHASES; if (longest_range_len < len) { longest_range_len = len; longest_range = i; } dev_dbg(host->dev, "Good phase range %d-%d (%d len)\n", TUNING_ITERATION_TO_PHASE(ranges[i].start), TUNING_ITERATION_TO_PHASE(ranges[i].end), len ); } dev_dbg(host->dev, "Best phase range %d-%d (%d len)\n", TUNING_ITERATION_TO_PHASE(ranges[longest_range].start), TUNING_ITERATION_TO_PHASE(ranges[longest_range].end), longest_range_len ); middle_phase = ranges[longest_range].start + longest_range_len / 2; middle_phase %= NUM_PHASES; dev_info(host->dev, "Successfully tuned phase to %d\n", TUNING_ITERATION_TO_PHASE(middle_phase)); clk_set_phase(priv->sample_clk, TUNING_ITERATION_TO_PHASE(middle_phase)); free: kfree(ranges); return ret; }