mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
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:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user