There is a current limitation where parents for a mux can be all declared
as they are from a common source. This is not true as there are some MUX
that can have parent from both infracfg or from topckgen.

To handle this, implement a new flag for the mux, CLK_PARENT_MIXED, and
a new entry for the mux parent_flags.

To use this, CLK_PARENT_MIXED must be used and parent_flags will be used
instead of the parent variable.

Entry in parent_flags are just a struct of ID and flags where it will be
defined where that parent comes from with the usage of
CLK_PARENT_INFRASYS or CLK_PARENT_TOPCKGEN.

This permits to have MUX with parents from infracfg or topckgen.

Notice that with CLK_PARENT_MIXED applied the CLK_BYPASS_XTAL is
ignored.
With CLK_PARENT_MIXED declare CLK_PARENT_XTAL for the relevant parent
instead.

Also alias for the CLK_PARENT macro are provided to better clear their
usage. CLK_PARENT_MIXED require these alias that describe the clk type
to be defined in the clk_tree flags to prevent clk ID clash from
different subsystem that may have equal clk ID.

Signed-off-by: Christian Marangi <ansuels...@gmail.com>
---
 drivers/clk/mediatek/clk-mtk.c | 69 +++++++++++++++++++++++++---------
 drivers/clk/mediatek/clk-mtk.h | 43 +++++++++++++++++++--
 2 files changed, 91 insertions(+), 21 deletions(-)

diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
index 79230fc26e0..4b8a904aa5e 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -54,13 +54,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);
@@ -352,6 +366,19 @@ static ulong mtk_topckgen_get_mux_rate(struct clk *clk, 
u32 off)
        return priv->tree->xtal_rate;
 }
 
+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;
+       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)
 {
        struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
@@ -362,21 +389,21 @@ 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 priv->tree->xtal_rate;
+
+       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)
@@ -490,12 +517,18 @@ 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);
+       u32 parent_type;
 
        if (clk->id < priv->tree->muxes_offs)
                return 0;
 
-       return mtk_clk_mux_set_parent(priv->base, parent->id,
+       if (!parent_priv)
+               return 0;
+
+       parent_type = parent_priv->tree->flags & CLK_PARENT_MASK;
+       return mtk_clk_mux_set_parent(priv->base, parent->id, parent_type,
                        &priv->tree->muxes[clk->id - priv->tree->muxes_offs]);
 }
 
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
index 8dde9e56e81..4423689803a 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
 
@@ -97,11 +111,31 @@ struct mtk_fixed_factor {
                .flags = _flags,                        \
        }
 
+/**
+ * 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;
-- 
2.45.1

Reply via email to