val = mci_readl(host, ENABLE_SHIFT); if (ios->timing == MMC_TIMING_MMC_DDR52
|| ios->timing == MMC_TIMING_UHS_DDR50)
val |= SDMMC_ENABLE_PHASE; else
val &= ~SDMMC_ENABLE_PHASE;
mci_writel(host, ENABLE_SHIFT, val);
val = mci_readl(host, DDR_REG); if (ios->timing == MMC_TIMING_MMC_HS400)
val |= SDMMC_DDR_HS400; else
val &= ~SDMMC_DDR_HS400;
mci_writel(host, DDR_REG, val);
if (clk_set_rate(host->ciu_clk, ios->clock))
dev_warn(host->dev, "Failed to set rate to %u\n", ios->clock); else /* * CLK_MUX_ROUND_NEAREST is enabled for this clock * The actual clock rate is not what we set, but a rounded value * so we should get the rate once again
*/
host->bus_hz = clk_get_rate(host->ciu_clk);
if (phase.valid) {
clk_set_phase(priv->drive_clk, phase.out_deg);
clk_set_phase(priv->sample_clk, phase.in_deg);
} else {
dev_warn(host->dev, "The phase entry for timing mode %d is missing in device tree.\n",
ios->timing);
}
}
staticint dw_mci_hi3798mv200_execute_tuning_mix_mode(struct dw_mci_slot *slot,
u32 opcode)
{ staticconstint degrees[] = { 0, 45, 90, 135, 180, 225, 270, 315 }; struct dw_mci *host = slot->host; struct dw_mci_hi3798mv200_priv *priv = host->priv; int raise_point = -1, fall_point = -1, mid; int err, prev_err = -1; int found = 0; int regval; int i; int ret;
ret = dw_mci_hi3798mv200_enable_tuning(slot); if (ret < 0) return ret;
for (i = 0; i < ARRAY_SIZE(degrees); i++) {
clk_set_phase(priv->sample_clk, degrees[i]);
mci_writel(host, RINTSTS, ALL_INT_CLR);
/* * HiSilicon implemented a tuning mechanism. * It needs special interaction with the DLL. * * Treat edge(flip) found as an error too.
*/
err = mmc_send_tuning(slot->mmc, opcode, NULL);
regval = mci_readl(host, TUNING_CTRL); if (err || (regval & SDMMC_TUNING_FIND_EDGE))
err = 1; else
found = 1;
if (i > 0) { if (err && !prev_err)
fall_point = i - 1; if (!err && prev_err)
raise_point = i;
}
if (raise_point != -1 && fall_point != -1) goto tuning_out;
prev_err = err;
}
tuning_out:
ret = dw_mci_hi3798mv200_disable_tuning(slot); if (ret < 0) return ret;
/* * We don't care what timing we are tuning for, * simply use the same phase for all timing needs tuning.
*/
priv->phase_map.phase[MMC_TIMING_MMC_HS200].in_deg = degrees[mid];
priv->phase_map.phase[MMC_TIMING_MMC_HS400].in_deg = degrees[mid];
priv->phase_map.phase[MMC_TIMING_UHS_SDR104].in_deg = degrees[mid];
clk_set_phase(priv->sample_clk, degrees[mid]);
dev_dbg(host->dev, "Tuning clk_sample[%d, %d], set[%d]\n",
raise_point, fall_point, degrees[mid]);
ret = 0;
} else {
dev_err(host->dev, "No valid clk_sample shift!\n");
ret = -EINVAL;
}
priv->sample_clk = devm_clk_get_enabled(host->dev, "ciu-sample"); if (IS_ERR(priv->sample_clk)) return dev_err_probe(host->dev, PTR_ERR(priv->sample_clk), "failed to get enabled ciu-sample clock\n");
priv->drive_clk = devm_clk_get_enabled(host->dev, "ciu-drive"); if (IS_ERR(priv->drive_clk)) return dev_err_probe(host->dev, PTR_ERR(priv->drive_clk), "failed to get enabled ciu-drive clock\n");
priv->crg_reg = syscon_regmap_lookup_by_phandle_args(np, "hisilicon,sap-dll-reg",
1, &priv->sap_dll_offset); if (IS_ERR(priv->crg_reg)) return dev_err_probe(host->dev, PTR_ERR(priv->crg_reg), "failed to get CRG reg\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.