summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/clk/mediatek/clk-mtk.c433
-rw-r--r--drivers/clk/mediatek/clk-mtk.h74
2 files changed, 392 insertions, 115 deletions
diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
index d2c45be30de..66683aeb2d7 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -35,6 +35,68 @@
/* shared functions */
+static int mtk_clk_get_id(struct clk *clk)
+{
+ struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+ int id = clk->id;
+
+ /* Remap the clk ID to the one expected by driver */
+ if (priv->tree->id_offs_map)
+ id = priv->tree->id_offs_map[id];
+
+ return id;
+}
+
+static int mtk_gate_enable(void __iomem *base, const struct mtk_gate *gate)
+{
+ u32 bit = BIT(gate->shift);
+
+ switch (gate->flags & CLK_GATE_MASK) {
+ case CLK_GATE_SETCLR:
+ writel(bit, base + gate->regs->clr_ofs);
+ break;
+ case CLK_GATE_SETCLR_INV:
+ writel(bit, base + gate->regs->set_ofs);
+ break;
+ case CLK_GATE_NO_SETCLR:
+ clrsetbits_le32(base + gate->regs->sta_ofs, bit, 0);
+ break;
+ case CLK_GATE_NO_SETCLR_INV:
+ clrsetbits_le32(base + gate->regs->sta_ofs, bit, bit);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_gate_disable(void __iomem *base, const struct mtk_gate *gate)
+{
+ u32 bit = BIT(gate->shift);
+
+ switch (gate->flags & CLK_GATE_MASK) {
+ case CLK_GATE_SETCLR:
+ writel(bit, base + gate->regs->set_ofs);
+ break;
+ case CLK_GATE_SETCLR_INV:
+ writel(bit, base + gate->regs->clr_ofs);
+ break;
+ case CLK_GATE_NO_SETCLR:
+ clrsetbits_le32(base + gate->regs->sta_ofs, bit, bit);
+ break;
+ case CLK_GATE_NO_SETCLR_INV:
+ clrsetbits_le32(base + gate->regs->sta_ofs, bit, 0);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/*
* In case the rate change propagation to parent clocks is undesirable,
* this function is recursively called to find the parent to calculate
@@ -54,13 +116,27 @@ static ulong mtk_clk_find_parent_rate(struct clk *clk, int id,
}
static int mtk_clk_mux_set_parent(void __iomem *base, u32 parent,
+ u32 parent_type,
const struct mtk_composite *mux)
{
u32 val, index = 0;
- while (mux->parent[index] != parent)
- if (++index == mux->num_parents)
- return -EINVAL;
+ if (mux->flags & CLK_PARENT_MIXED) {
+ /*
+ * Assume parent_type in clk_tree to be always set with
+ * CLK_PARENT_MIXED implementation. If it's not, assume
+ * not parent clk ID clash is possible.
+ */
+ while (mux->parent_flags[index].id != parent ||
+ (parent_type && (mux->parent_flags[index].flags & CLK_PARENT_MASK) !=
+ parent_type))
+ if (++index == mux->num_parents)
+ return -EINVAL;
+ } else {
+ while (mux->parent[index] != parent)
+ if (++index == mux->num_parents)
+ return -EINVAL;
+ }
if (mux->flags & CLK_MUX_SETCLR_UPD) {
val = (mux->mux_mask << mux->mux_shift);
@@ -117,12 +193,14 @@ static unsigned long __mtk_pll_recalc_rate(const struct mtk_pll_data *pll,
* for the integer part and the remaining bits (if present) for the
* fractional part. Also they have a 3 bit power-of-two post divider.
*/
-static void mtk_pll_set_rate_regs(struct clk *clk, u32 pcw, int postdiv)
+static void mtk_pll_set_rate_regs(struct mtk_clk_priv *priv, u32 id,
+ u32 pcw, int postdiv)
{
- struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
- const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+ const struct mtk_pll_data *pll;
u32 val, chg;
+ pll = &priv->tree->plls[id];
+
/* set postdiv */
val = readl(priv->base + pll->pd_reg);
val &= ~(POSTDIV_MASK << pll->pd_shift);
@@ -153,21 +231,24 @@ static void mtk_pll_set_rate_regs(struct clk *clk, u32 pcw, int postdiv)
/**
* mtk_pll_calc_values - calculate good values for a given input frequency.
- * @clk: The clk
+ * @priv: The mtk priv struct
+ * @id: The clk id
* @pcw: The pcw value (output)
* @postdiv: The post divider (output)
* @freq: The desired target frequency
*/
-static void mtk_pll_calc_values(struct clk *clk, u32 *pcw, u32 *postdiv,
- u32 freq)
+static void mtk_pll_calc_values(struct mtk_clk_priv *priv, u32 id,
+ u32 *pcw, u32 *postdiv, u32 freq)
{
- struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
- const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
- unsigned long fmin = pll->fmin ? pll->fmin : 1000 * MHZ;
+ const struct mtk_pll_data *pll;
+ unsigned long fmin;
u64 _pcw;
int ibits;
u32 val;
+ pll = &priv->tree->plls[id];
+ fmin = pll->fmin ? pll->fmin : 1000 * MHZ;
+
if (freq > pll->fmax)
freq = pll->fmax;
@@ -187,11 +268,16 @@ static void mtk_pll_calc_values(struct clk *clk, u32 *pcw, u32 *postdiv,
static ulong mtk_apmixedsys_set_rate(struct clk *clk, ulong rate)
{
+ struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+ int id = mtk_clk_get_id(clk);
u32 pcw = 0;
u32 postdiv;
- mtk_pll_calc_values(clk, &pcw, &postdiv, rate);
- mtk_pll_set_rate_regs(clk, pcw, postdiv);
+ if (priv->tree->gates && id >= priv->tree->gates_offs)
+ return -EINVAL;
+
+ mtk_pll_calc_values(priv, id, &pcw, &postdiv, rate);
+ mtk_pll_set_rate_regs(priv, id, pcw, postdiv);
return 0;
}
@@ -199,10 +285,20 @@ static ulong mtk_apmixedsys_set_rate(struct clk *clk, ulong rate)
static ulong mtk_apmixedsys_get_rate(struct clk *clk)
{
struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
- const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+ const struct mtk_pll_data *pll;
+ int id = mtk_clk_get_id(clk);
+ const struct mtk_gate *gate;
u32 postdiv;
u32 pcw;
+ /* GATE handling */
+ if (priv->tree->gates && id >= priv->tree->gates_offs) {
+ gate = &priv->tree->gates[id - priv->tree->gates_offs];
+ return mtk_clk_find_parent_rate(clk, gate->parent, NULL);
+ }
+
+ pll = &priv->tree->plls[id];
+
postdiv = (readl(priv->base + pll->pd_reg) >> pll->pd_shift) &
POSTDIV_MASK;
postdiv = 1 << postdiv;
@@ -217,9 +313,19 @@ static ulong mtk_apmixedsys_get_rate(struct clk *clk)
static int mtk_apmixedsys_enable(struct clk *clk)
{
struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
- const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+ const struct mtk_pll_data *pll;
+ int id = mtk_clk_get_id(clk);
+ const struct mtk_gate *gate;
u32 r;
+ /* GATE handling */
+ if (priv->tree->gates && id >= priv->tree->gates_offs) {
+ gate = &priv->tree->gates[id - priv->tree->gates_offs];
+ return mtk_gate_enable(priv->base, gate);
+ }
+
+ pll = &priv->tree->plls[id];
+
r = readl(priv->base + pll->pwr_reg) | CON0_PWR_ON;
writel(r, priv->base + pll->pwr_reg);
udelay(1);
@@ -246,9 +352,19 @@ static int mtk_apmixedsys_enable(struct clk *clk)
static int mtk_apmixedsys_disable(struct clk *clk)
{
struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
- const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+ const struct mtk_pll_data *pll;
+ int id = mtk_clk_get_id(clk);
+ const struct mtk_gate *gate;
u32 r;
+ /* GATE handling */
+ if (priv->tree->gates && id >= priv->tree->gates_offs) {
+ gate = &priv->tree->gates[id - priv->tree->gates_offs];
+ return mtk_gate_disable(priv->base, gate);
+ }
+
+ pll = &priv->tree->plls[id];
+
if (pll->flags & HAVE_RST_BAR) {
r = readl(priv->base + pll->reg + REG_CON0);
r &= ~pll->rst_bar_mask;
@@ -324,6 +440,19 @@ static ulong mtk_infrasys_get_factor_rate(struct clk *clk, u32 off)
return mtk_factor_recalc_rate(fdiv, rate);
}
+static ulong mtk_topckgen_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk,
+ const int parent, u16 flags)
+{
+ switch (flags & CLK_PARENT_MASK) {
+ case CLK_PARENT_XTAL:
+ return priv->tree->xtal_rate;
+ case CLK_PARENT_APMIXED:
+ return mtk_clk_find_parent_rate(clk, parent, priv->parent);
+ default:
+ return mtk_clk_find_parent_rate(clk, parent, NULL);
+ }
+}
+
static ulong mtk_topckgen_get_mux_rate(struct clk *clk, u32 off)
{
struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
@@ -334,22 +463,40 @@ static ulong mtk_topckgen_get_mux_rate(struct clk *clk, u32 off)
index &= mux->mux_mask << mux->mux_shift;
index = index >> mux->mux_shift;
- if (mux->parent[index] > 0 ||
- (mux->parent[index] == CLK_XTAL &&
- priv->tree->flags & CLK_BYPASS_XTAL)) {
- switch (mux->flags & CLK_PARENT_MASK) {
- case CLK_PARENT_APMIXED:
- return mtk_clk_find_parent_rate(clk, mux->parent[index],
- priv->parent);
- break;
- default:
- return mtk_clk_find_parent_rate(clk, mux->parent[index],
- NULL);
- break;
- }
+ /*
+ * Parents can be either from APMIXED or TOPCKGEN,
+ * inspect the mtk_parent struct to check the source
+ */
+ if (mux->flags & CLK_PARENT_MIXED) {
+ const struct mtk_parent *parent = &mux->parent_flags[index];
+
+ return mtk_topckgen_find_parent_rate(priv, clk, parent->id,
+ parent->flags);
}
- return priv->tree->xtal_rate;
+ if (mux->parent[index] == CLK_XTAL &&
+ !(priv->tree->flags & CLK_BYPASS_XTAL))
+ return priv->tree->xtal_rate;
+
+ return mtk_topckgen_find_parent_rate(priv, clk, mux->parent[index],
+ mux->flags);
+}
+
+static ulong mtk_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk,
+ const int parent, u16 flags)
+{
+ switch (flags & CLK_PARENT_MASK) {
+ case CLK_PARENT_XTAL:
+ return priv->tree->xtal_rate;
+ /* Assume the second level parent is always APMIXED */
+ case CLK_PARENT_APMIXED:
+ priv = dev_get_priv(priv->parent);
+ fallthrough;
+ case CLK_PARENT_TOPCKGEN:
+ return mtk_clk_find_parent_rate(clk, parent, priv->parent);
+ default:
+ return mtk_clk_find_parent_rate(clk, parent, NULL);
+ }
}
static ulong mtk_infrasys_get_mux_rate(struct clk *clk, u32 off)
@@ -362,51 +509,69 @@ static ulong mtk_infrasys_get_mux_rate(struct clk *clk, u32 off)
index &= mux->mux_mask << mux->mux_shift;
index = index >> mux->mux_shift;
- if (mux->parent[index] > 0 ||
- (mux->parent[index] == CLK_XTAL &&
- priv->tree->flags & CLK_BYPASS_XTAL)) {
- switch (mux->flags & CLK_PARENT_MASK) {
- case CLK_PARENT_TOPCKGEN:
- return mtk_clk_find_parent_rate(clk, mux->parent[index],
- priv->parent);
- break;
- default:
- return mtk_clk_find_parent_rate(clk, mux->parent[index],
- NULL);
- break;
- }
+ /*
+ * Parents can be either from TOPCKGEN or INFRACFG,
+ * inspect the mtk_parent struct to check the source
+ */
+ if (mux->flags & CLK_PARENT_MIXED) {
+ const struct mtk_parent *parent = &mux->parent_flags[index];
+
+ return mtk_find_parent_rate(priv, clk, parent->id, parent->flags);
}
- return 0;
+
+ if (mux->parent[index] == CLK_XTAL &&
+ !(priv->tree->flags & CLK_BYPASS_XTAL))
+ return priv->tree->xtal_rate;
+
+ return mtk_find_parent_rate(priv, clk, mux->parent[index], mux->flags);
}
static ulong mtk_topckgen_get_rate(struct clk *clk)
{
struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+ int id = mtk_clk_get_id(clk);
- if (clk->id < priv->tree->fdivs_offs)
- return priv->tree->fclks[clk->id].rate;
- else if (clk->id < priv->tree->muxes_offs)
- return mtk_topckgen_get_factor_rate(clk, clk->id -
+ if (id < priv->tree->fdivs_offs)
+ return priv->tree->fclks[id].rate;
+ else if (id < priv->tree->muxes_offs)
+ return mtk_topckgen_get_factor_rate(clk, id -
priv->tree->fdivs_offs);
else
- return mtk_topckgen_get_mux_rate(clk, clk->id -
+ return mtk_topckgen_get_mux_rate(clk, id -
priv->tree->muxes_offs);
}
static ulong mtk_infrasys_get_rate(struct clk *clk)
{
struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
-
+ int id = mtk_clk_get_id(clk);
ulong rate;
- if (clk->id < priv->tree->fdivs_offs) {
- rate = priv->tree->fclks[clk->id].rate;
- } else if (clk->id < priv->tree->muxes_offs) {
- rate = mtk_infrasys_get_factor_rate(clk, clk->id -
+ if (id < priv->tree->fdivs_offs) {
+ rate = priv->tree->fclks[id].rate;
+ } else if (id < priv->tree->muxes_offs) {
+ rate = mtk_infrasys_get_factor_rate(clk, id -
priv->tree->fdivs_offs);
- } else {
- rate = mtk_infrasys_get_mux_rate(clk, clk->id -
+ /* No gates defined or ID is a MUX */
+ } else if (!priv->tree->gates || id < priv->tree->gates_offs) {
+ rate = mtk_infrasys_get_mux_rate(clk, id -
priv->tree->muxes_offs);
+ /* Only valid with muxes + gates implementation */
+ } else {
+ struct udevice *parent = NULL;
+ const struct mtk_gate *gate;
+
+ gate = &priv->tree->gates[id - priv->tree->gates_offs];
+ if (gate->flags & CLK_PARENT_TOPCKGEN)
+ parent = priv->parent;
+ /*
+ * Assume xtal_rate to be declared if some gates have
+ * XTAL as parent
+ */
+ else if (gate->flags & CLK_PARENT_XTAL)
+ return priv->tree->xtal_rate;
+
+ rate = mtk_clk_find_parent_rate(clk, gate->parent, parent);
}
return rate;
@@ -416,12 +581,13 @@ static int mtk_clk_mux_enable(struct clk *clk)
{
struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
const struct mtk_composite *mux;
+ int id = mtk_clk_get_id(clk);
u32 val;
- if (clk->id < priv->tree->muxes_offs)
+ if (id < priv->tree->muxes_offs)
return 0;
- mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs];
+ mux = &priv->tree->muxes[id - priv->tree->muxes_offs];
if (mux->gate_shift < 0)
return 0;
@@ -449,12 +615,13 @@ static int mtk_clk_mux_disable(struct clk *clk)
{
struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
const struct mtk_composite *mux;
+ int id = mtk_clk_get_id(clk);
u32 val;
- if (clk->id < priv->tree->muxes_offs)
+ if (id < priv->tree->muxes_offs)
return 0;
- mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs];
+ mux = &priv->tree->muxes[id - priv->tree->muxes_offs];
if (mux->gate_shift < 0)
return 0;
@@ -473,13 +640,20 @@ static int mtk_clk_mux_disable(struct clk *clk)
static int mtk_common_clk_set_parent(struct clk *clk, struct clk *parent)
{
+ struct mtk_clk_priv *parent_priv = dev_get_priv(parent->dev);
struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+ int id = mtk_clk_get_id(clk);
+ u32 parent_type;
+
+ if (id < priv->tree->muxes_offs)
+ return 0;
- if (clk->id < priv->tree->muxes_offs)
+ if (!parent_priv)
return 0;
- return mtk_clk_mux_set_parent(priv->base, parent->id,
- &priv->tree->muxes[clk->id - priv->tree->muxes_offs]);
+ parent_type = parent_priv->tree->flags & CLK_PARENT_MASK;
+ return mtk_clk_mux_set_parent(priv->base, parent->id, parent_type,
+ &priv->tree->muxes[id - priv->tree->muxes_offs]);
}
/* CG functions */
@@ -487,63 +661,88 @@ static int mtk_common_clk_set_parent(struct clk *clk, struct clk *parent)
static int mtk_clk_gate_enable(struct clk *clk)
{
struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
- const struct mtk_gate *gate = &priv->gates[clk->id];
- u32 bit = BIT(gate->shift);
+ int id = mtk_clk_get_id(clk);
+ const struct mtk_gate *gate;
- switch (gate->flags & CLK_GATE_MASK) {
- case CLK_GATE_SETCLR:
- writel(bit, priv->base + gate->regs->clr_ofs);
- break;
- case CLK_GATE_SETCLR_INV:
- writel(bit, priv->base + gate->regs->set_ofs);
- break;
- case CLK_GATE_NO_SETCLR:
- clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, 0);
- break;
- case CLK_GATE_NO_SETCLR_INV:
- clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, bit);
- break;
-
- default:
+ if (id < priv->tree->gates_offs)
return -EINVAL;
- }
- return 0;
+ gate = &priv->gates[id - priv->tree->gates_offs];
+ return mtk_gate_enable(priv->base, gate);
}
-static int mtk_clk_gate_disable(struct clk *clk)
+static int mtk_clk_infrasys_enable(struct clk *clk)
{
struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
- const struct mtk_gate *gate = &priv->gates[clk->id];
- u32 bit = BIT(gate->shift);
+ int id = mtk_clk_get_id(clk);
+ const struct mtk_gate *gate;
- switch (gate->flags & CLK_GATE_MASK) {
- case CLK_GATE_SETCLR:
- writel(bit, priv->base + gate->regs->set_ofs);
- break;
- case CLK_GATE_SETCLR_INV:
- writel(bit, priv->base + gate->regs->clr_ofs);
- break;
- case CLK_GATE_NO_SETCLR:
- clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, bit);
- break;
- case CLK_GATE_NO_SETCLR_INV:
- clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, 0);
- break;
+ /* MUX handling */
+ if (!priv->tree->gates || id < priv->tree->gates_offs)
+ return mtk_clk_mux_enable(clk);
- default:
+ gate = &priv->tree->gates[id - priv->tree->gates_offs];
+ return mtk_gate_enable(priv->base, gate);
+}
+
+static int mtk_clk_gate_disable(struct clk *clk)
+{
+ struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
+ int id = mtk_clk_get_id(clk);
+ const struct mtk_gate *gate;
+
+ if (id < priv->tree->gates_offs)
return -EINVAL;
- }
- return 0;
+ gate = &priv->gates[id - priv->tree->gates_offs];
+ return mtk_gate_disable(priv->base, gate);
+}
+
+static int mtk_clk_infrasys_disable(struct clk *clk)
+{
+ struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
+ int id = mtk_clk_get_id(clk);
+ const struct mtk_gate *gate;
+
+ /* MUX handling */
+ if (!priv->tree->gates || id < priv->tree->gates_offs)
+ return mtk_clk_mux_disable(clk);
+
+ gate = &priv->tree->gates[id - priv->tree->gates_offs];
+ return mtk_gate_disable(priv->base, gate);
}
static ulong mtk_clk_gate_get_rate(struct clk *clk)
{
struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
- const struct mtk_gate *gate = &priv->gates[clk->id];
+ struct udevice *parent = priv->parent;
+ int id = mtk_clk_get_id(clk);
+ const struct mtk_gate *gate;
+
+ if (id < priv->tree->gates_offs)
+ return -EINVAL;
+
+ gate = &priv->gates[id - priv->tree->gates_offs];
+ /*
+ * With requesting a TOPCKGEN parent, make sure the dev parent
+ * is actually topckgen. This might not be the case for an
+ * infracfg-ao implementation where:
+ * parent = infracfg
+ * parent->parent = topckgen
+ */
+ if (gate->flags & CLK_PARENT_TOPCKGEN &&
+ parent->driver != DM_DRIVER_GET(mtk_clk_topckgen)) {
+ priv = dev_get_priv(parent);
+ parent = priv->parent;
+ /*
+ * Assume xtal_rate to be declared if some gates have
+ * XTAL as parent
+ */
+ } else if (gate->flags & CLK_PARENT_XTAL) {
+ return priv->tree->xtal_rate;
+ }
- return mtk_clk_find_parent_rate(clk, gate->parent, priv->parent);
+ return mtk_clk_find_parent_rate(clk, gate->parent, parent);
}
const struct clk_ops mtk_clk_apmixedsys_ops = {
@@ -561,8 +760,8 @@ const struct clk_ops mtk_clk_topckgen_ops = {
};
const struct clk_ops mtk_clk_infrasys_ops = {
- .enable = mtk_clk_mux_enable,
- .disable = mtk_clk_mux_disable,
+ .enable = mtk_clk_infrasys_enable,
+ .disable = mtk_clk_infrasys_disable,
.get_rate = mtk_infrasys_get_rate,
.set_parent = mtk_common_clk_set_parent,
};
@@ -573,8 +772,9 @@ const struct clk_ops mtk_clk_gate_ops = {
.get_rate = mtk_clk_gate_get_rate,
};
-int mtk_common_clk_init(struct udevice *dev,
- const struct mtk_clk_tree *tree)
+static int mtk_common_clk_init_drv(struct udevice *dev,
+ const struct mtk_clk_tree *tree,
+ const struct driver *drv)
{
struct mtk_clk_priv *priv = dev_get_priv(dev);
struct udevice *parent;
@@ -586,8 +786,7 @@ int mtk_common_clk_init(struct udevice *dev,
ret = uclass_get_device_by_phandle(UCLASS_CLK, dev, "clock-parent", &parent);
if (ret || !parent) {
- ret = uclass_get_device_by_driver(UCLASS_CLK,
- DM_DRIVER_GET(mtk_clk_apmixedsys), &parent);
+ ret = uclass_get_device_by_driver(UCLASS_CLK, drv, &parent);
if (ret || !parent)
return -ENOENT;
}
@@ -598,6 +797,20 @@ int mtk_common_clk_init(struct udevice *dev,
return 0;
}
+int mtk_common_clk_init(struct udevice *dev,
+ const struct mtk_clk_tree *tree)
+{
+ return mtk_common_clk_init_drv(dev, tree,
+ DM_DRIVER_GET(mtk_clk_apmixedsys));
+}
+
+int mtk_common_clk_infrasys_init(struct udevice *dev,
+ const struct mtk_clk_tree *tree)
+{
+ return mtk_common_clk_init_drv(dev, tree,
+ DM_DRIVER_GET(mtk_clk_topckgen));
+}
+
int mtk_common_clk_gate_init(struct udevice *dev,
const struct mtk_clk_tree *tree,
const struct mtk_gate *gates)
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
index 48ce16484ec..c1d9901c10b 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -13,7 +13,11 @@
/* flags in struct mtk_clk_tree */
-/* clk id == 0 doesn't mean it's xtal clk */
+/* clk id == 0 doesn't mean it's xtal clk
+ * This doesn't apply when CLK_PARENT_MIXED is defined.
+ * With CLK_PARENT_MIXED declare CLK_PARENT_XTAL for the
+ * relevant parent.
+ */
#define CLK_BYPASS_XTAL BIT(0)
#define HAVE_RST_BAR BIT(0)
@@ -30,7 +34,17 @@
#define CLK_PARENT_TOPCKGEN BIT(5)
#define CLK_PARENT_INFRASYS BIT(6)
#define CLK_PARENT_XTAL BIT(7)
-#define CLK_PARENT_MASK GENMASK(7, 4)
+/*
+ * For CLK_PARENT_MIXED to correctly work, is required to
+ * define in clk_tree flags the clk type using the alias.
+ */
+#define CLK_PARENT_MIXED BIT(8)
+#define CLK_PARENT_MASK GENMASK(8, 4)
+
+/* alias to reference clk type */
+#define CLK_APMIXED CLK_PARENT_APMIXED
+#define CLK_TOPCKGEN CLK_PARENT_TOPCKGEN
+#define CLK_INFRASYS CLK_PARENT_INFRASYS
#define ETHSYS_HIFSYS_RST_CTRL_OFS 0x34
@@ -98,10 +112,30 @@ struct mtk_fixed_factor {
}
/**
+ * struct mtk_parent - clock parent with flags. Needed for MUX that
+ * parent with mixed infracfg and topckgen.
+ *
+ * @id: index of parent clocks
+ * @flags: hardware-specific flags (parent location,
+ * infracfg, topckgen, APMIXED, xtal ...)
+ */
+struct mtk_parent {
+ const int id;
+ u16 flags;
+};
+
+#define PARENT(_id, _flags) { \
+ .id = _id, \
+ .flags = _flags, \
+ }
+
+/**
* struct mtk_composite - aggregate clock of mux, divider and gate clocks
*
* @id: index of clocks
* @parent: index of parnet clocks
+ * @parent: index of parnet clocks
+ * @parent_flags: table of parent clocks with flags
* @mux_reg: hardware-specific mux register
* @gate_reg: hardware-specific gate register
* @mux_mask: mask to the mux bit field
@@ -112,7 +146,10 @@ struct mtk_fixed_factor {
*/
struct mtk_composite {
const int id;
- const int *parent;
+ union {
+ const int *parent;
+ const struct mtk_parent *parent_flags;
+ };
u32 mux_reg;
u32 mux_set_reg;
u32 mux_clr_reg;
@@ -142,7 +179,20 @@ struct mtk_composite {
#define MUX_GATE(_id, _parents, _reg, _shift, _width, _gate) \
MUX_GATE_FLAGS(_id, _parents, _reg, _shift, _width, _gate, 0)
-#define MUX(_id, _parents, _reg, _shift, _width) { \
+#define MUX_MIXED_FLAGS(_id, _parents, _reg, _shift, _width, _flags) { \
+ .id = _id, \
+ .mux_reg = _reg, \
+ .mux_shift = _shift, \
+ .mux_mask = BIT(_width) - 1, \
+ .gate_shift = -1, \
+ .parent_flags = _parents, \
+ .num_parents = ARRAY_SIZE(_parents), \
+ .flags = CLK_PARENT_MIXED | (_flags), \
+ }
+#define MUX_MIXED(_id, _parents, _reg, _shift, _width) \
+ MUX_MIXED_FLAGS(_id, _parents, _reg, _shift, _width, 0)
+
+#define MUX_FLAGS(_id, _parents, _reg, _shift, _width, _flags) { \
.id = _id, \
.mux_reg = _reg, \
.mux_shift = _shift, \
@@ -150,8 +200,10 @@ struct mtk_composite {
.gate_shift = -1, \
.parent = _parents, \
.num_parents = ARRAY_SIZE(_parents), \
- .flags = 0, \
+ .flags = _flags, \
}
+#define MUX(_id, _parents, _reg, _shift, _width) \
+ MUX_FLAGS(_id, _parents, _reg, _shift, _width, 0)
#define MUX_CLR_SET_UPD_FLAGS(_id, _parents, _mux_ofs, _mux_set_ofs,\
_mux_clr_ofs, _shift, _width, _gate, \
@@ -198,12 +250,22 @@ struct mtk_gate {
struct mtk_clk_tree {
unsigned long xtal_rate;
unsigned long xtal2_rate;
+ /*
+ * Clock ID offset are remapped with an auxiliary table.
+ * Enable this by defining .id_offs_map.
+ * This is needed for upstream linux kernel <soc>-clk.h that
+ * have mixed clk ID and doesn't have clear distinction between
+ * ID for factor, mux and gates.
+ */
+ const int *id_offs_map; /* optional, table clk.h to driver ID */
const int fdivs_offs;
const int muxes_offs;
+ const int gates_offs;
const struct mtk_pll_data *plls;
const struct mtk_fixed_clk *fclks;
const struct mtk_fixed_factor *fdivs;
const struct mtk_composite *muxes;
+ const struct mtk_gate *gates;
u32 flags;
};
@@ -227,6 +289,8 @@ extern const struct clk_ops mtk_clk_gate_ops;
int mtk_common_clk_init(struct udevice *dev,
const struct mtk_clk_tree *tree);
+int mtk_common_clk_infrasys_init(struct udevice *dev,
+ const struct mtk_clk_tree *tree);
int mtk_common_clk_gate_init(struct udevice *dev,
const struct mtk_clk_tree *tree,
const struct mtk_gate *gates);