mmc: dw_mmc-rockchip: add v2 tuning support

v2 tuning will inherit pre-stage loader's phase
settings for the first time, and do re-tune if
necessary. Re-tune will still try the rough degrees,
for instance, 90, 180, 270, 360 but continue to do the
fine tuning if sample window isn't good enough.

Change-Id: I593384ee381d09df5b9adfc29a18eb22517b2764
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
This commit is contained in:
Shawn Lin
2020-04-15 09:19:09 +08:00
committed by Tao Huang
parent a95ce73bf7
commit 795e052cc8

View File

@@ -22,6 +22,8 @@ struct dw_mci_rockchip_priv_data {
struct clk *sample_clk;
int default_sample_phase;
int num_phases;
bool use_v2_tuning;
int last_degree;
};
static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
@@ -132,6 +134,42 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
#define TUNING_ITERATION_TO_PHASE(i, num_phases) \
(DIV_ROUND_UP((i) * 360, num_phases))
static int dw_mci_v2_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;
u32 degrees[4] = {90, 180, 270, 360};
int i;
static bool inherit = true;
if (inherit) {
inherit = false;
i = clk_get_phase(priv->sample_clk) / 90 - 1;
goto done;
}
/* v2 only support 4 degrees in theory */
for (i = 0; i < ARRAY_SIZE(degrees); i++) {
if (degrees[i] == priv->last_degree)
continue;
clk_set_phase(priv->sample_clk, degrees[i]);
if (!mmc_send_tuning(mmc, opcode, NULL))
break;
}
if (i == ARRAY_SIZE(degrees)) {
dev_warn(host->dev, "All phases bad!");
return -EIO;
}
done:
dev_info(host->dev, "Successfully tuned phase to %d\n", degrees[i]);
priv->last_degree = degrees[i];
return 0;
}
static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
{
struct dw_mci *host = slot->host;
@@ -155,6 +193,13 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
return -EIO;
}
if (priv->use_v2_tuning) {
ret = dw_mci_v2_execute_tuning(slot, opcode);
if (!ret)
return 0;
/* Otherwise we continue using fine tuning */
}
ranges = kmalloc_array(priv->num_phases / 2 + 1,
sizeof(*ranges), GFP_KERNEL);
if (!ranges)
@@ -275,6 +320,9 @@ static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
&priv->default_sample_phase))
priv->default_sample_phase = 0;
if (of_property_read_bool(np, "rockchip,use-v2-tuning"))
priv->use_v2_tuning = true;
priv->drv_clk = devm_clk_get(host->dev, "ciu-drive");
if (IS_ERR(priv->drv_clk))
dev_dbg(host->dev, "ciu-drive not available\n");