[PATCH 8/8] clk: mediatek: implement dump callbacks

David Lechner dlechner at baylibre.com
Thu Dec 18 18:17:06 CET 2025


Implement dump callbacks for Mediatek clocks. On these platforms, there
are 100s of clocks, so it can be easy to miss mistakes. The dump
callbacks will be useful for debugging and verifying clock configs.

Signed-off-by: David Lechner <dlechner at baylibre.com>
---
 drivers/clk/mediatek/clk-mtk.c | 248 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 248 insertions(+)

diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
index 1539dc6cbcc..a3dd18363f6 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -193,6 +193,108 @@ static int mtk_clk_mux_set_parent(void __iomem *base, u32 parent,
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(CMD_CLK)
+static void mtk_clk_print_dev_parent(struct udevice *parent)
+{
+	printf("Parent device: %s %s\n", parent->driver->name, parent->name);
+}
+
+static void mtk_clk_print_mapped_id(int unmapped_id, int mapped_id, bool has_map)
+{
+	/*
+	 * If there is a ID map, then having unmapped and mapped IDs differ is
+	 * expected. On the other hand, if there is no map, then they should be
+	 * the same, and it is a programming error if they differ.
+	 */
+	if (has_map)
+		printf(", (mapped ID: %u)", mapped_id);
+	else if (unmapped_id != mapped_id)
+		printf(", (error! should be %u)", mapped_id);
+}
+
+static void mtk_clk_print_rate(struct udevice *dev, int mapped_id)
+{
+	struct clk clk = {
+		.dev = dev,
+		.id = mapped_id,
+	};
+	long rate = clk_get_rate(&clk);
+
+	if (rate < 0)
+		printf(", error! clk_get_rate() failed: %ld", rate);
+	else
+		printf(", Rate: %lu Hz", rate);
+}
+
+static void mtk_clk_print_parent(const char *prefix, int parent, u32 flags)
+{
+	const char *parent_type_str;
+
+	switch (flags & CLK_PARENT_MASK) {
+	case CLK_PARENT_APMIXED:
+		parent_type_str = "apmixedsys";
+		break;
+	case CLK_PARENT_TOPCKGEN:
+		parent_type_str = "topckgen";
+		break;
+	case CLK_PARENT_INFRASYS:
+		parent_type_str = "infrasys";
+		break;
+	case CLK_PARENT_XTAL:
+		parent_type_str = "xtal";
+		break;
+	case CLK_PARENT_MIXED:
+		parent_type_str = "mixed";
+		break;
+	default:
+		parent_type_str = "default";
+		break;
+	}
+
+	printf("%s%s-%u", prefix, parent_type_str, parent);
+}
+
+static void mtk_clk_print_single_parent(int parent, u32 flags)
+{
+	mtk_clk_print_parent(", Parent: ", parent, flags);
+}
+
+static void mtk_clk_print_mux_parents(struct mtk_clk_priv *priv,
+				      const struct mtk_composite *mux)
+{
+	const char *prefix = "";
+	u32 selected;
+	int i;
+
+	printf(", Parents: ");
+
+	selected = readl(priv->base + mux->mux_reg);
+	selected &= mux->mux_mask << mux->mux_shift;
+	selected >>= mux->mux_shift;
+
+	/* Print parents separated by "/" and selected parent enclosed in "*"s */
+	for (i = 0; i < mux->num_parents; i++) {
+		if (i == selected) {
+			printf("%s", prefix);
+			prefix = "*";
+		}
+
+		if (mux->flags & CLK_PARENT_MIXED) {
+			const struct mtk_parent *parent = &mux->parent_flags[i];
+
+			mtk_clk_print_parent(prefix, parent->id, parent->flags);
+		} else {
+			mtk_clk_print_parent(prefix, mux->parent[i], mux->flags);
+		}
+
+		prefix = "/";
+
+		if (i == selected)
+			printf("*");
+	}
+}
+#endif
+
 /* apmixedsys functions */
 
 static const int mtk_apmixedsys_of_xlate(struct clk *clk,
@@ -437,6 +539,36 @@ static int mtk_apmixedsys_disable(struct clk *clk)
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(CMD_CLK)
+static void mtk_apmixedsys_dump(struct udevice *dev)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(dev);
+	const struct mtk_clk_tree *tree = priv->tree;
+	u32 i;
+
+	mtk_clk_print_dev_parent(priv->parent);
+
+	for (i = 0; i < tree->num_plls; i++) {
+		const struct mtk_pll_data *pll = &tree->plls[i];
+
+		printf("[PLL%u] DT: %u", i, pll->id);
+		mtk_clk_print_mapped_id(pll->id, i, tree->id_offs_map);
+		mtk_clk_print_rate(dev, i);
+		printf("\n");
+	}
+
+	for (i = 0; i < tree->num_gates; i++) {
+		const struct mtk_gate *gate = &tree->gates[i];
+
+		printf("[GATE%u] DT: %u", i, gate->id);
+		mtk_clk_print_mapped_id(gate->id, i + tree->gates_offs, tree->id_offs_map);
+		mtk_clk_print_rate(dev, i + tree->gates_offs);
+		mtk_clk_print_single_parent(gate->parent, gate->flags);
+		printf("\n");
+	}
+}
+#endif
+
 /* topckgen functions */
 
 static const int mtk_topckgen_of_xlate(struct clk *clk,
@@ -651,6 +783,48 @@ static int mtk_common_clk_set_parent(struct clk *clk, struct clk *parent)
 			&priv->tree->muxes[clk->id - priv->tree->muxes_offs]);
 }
 
+#if CONFIG_IS_ENABLED(CMD_CLK)
+static void mtk_topckgen_dump(struct udevice *dev)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(dev);
+	const struct mtk_clk_tree *tree = priv->tree;
+	u32 i;
+
+	mtk_clk_print_dev_parent(priv->parent);
+
+	for (i = 0; i < tree->num_fclks; i++) {
+		const struct mtk_fixed_clk *fclk = &tree->fclks[i];
+
+		printf("[FCLK%u] DT: %u", i, fclk->id);
+		mtk_clk_print_mapped_id(fclk->id, i, tree->id_offs_map);
+		mtk_clk_print_rate(dev, i);
+		/* FIXME: fclk needs flags to fully determine parent. */
+		mtk_clk_print_single_parent(fclk->parent, 0);
+		printf("\n");
+	}
+
+	for (i = 0; i < tree->num_fdivs; i++) {
+		const struct mtk_fixed_factor *fdiv = &tree->fdivs[i];
+
+		printf("[FDIV%u] DT: %u", i, fdiv->id);
+		mtk_clk_print_mapped_id(fdiv->id, i + tree->fdivs_offs, tree->id_offs_map);
+		mtk_clk_print_rate(dev, i + tree->fdivs_offs);
+		mtk_clk_print_single_parent(fdiv->parent, fdiv->flags);
+		printf(", Mult: %u, Div: %u\n", fdiv->mult, fdiv->div);
+	}
+
+	for (i = 0; i < tree->num_muxes; i++) {
+		const struct mtk_composite *mux = &tree->muxes[i];
+
+		printf("[MUX%u] DT: %u", i, mux->id);
+		mtk_clk_print_mapped_id(mux->id, i + tree->muxes_offs, tree->id_offs_map);
+		mtk_clk_print_rate(dev, i + tree->muxes_offs);
+		mtk_clk_print_mux_parents(priv, mux);
+		printf("\n");
+	}
+}
+#endif
+
 /* infrasys functions */
 
 static const int mtk_infrasys_of_xlate(struct clk *clk,
@@ -793,6 +967,44 @@ static ulong mtk_infrasys_get_rate(struct clk *clk)
 	return rate;
 }
 
+#if CONFIG_IS_ENABLED(CMD_CLK)
+static void mtk_infrasys_dump(struct udevice *dev)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(dev);
+	const struct mtk_clk_tree *tree = priv->tree;
+	u32 i;
+
+	mtk_clk_print_dev_parent(priv->parent);
+
+	for (i = 0; i < tree->num_fdivs; i++) {
+		const struct mtk_fixed_factor *fdiv = &tree->fdivs[i];
+
+		printf("[FDIV%u] DT: %u", i, fdiv->id);
+		mtk_clk_print_mapped_id(fdiv->id, i + tree->fdivs_offs, tree->id_offs_map);
+		mtk_clk_print_single_parent(fdiv->parent, fdiv->flags);
+		printf(", Mult: %u, Div: %u\n", fdiv->mult, fdiv->div);
+	}
+
+	for (i = 0; i < tree->num_muxes; i++) {
+		const struct mtk_composite *mux = &tree->muxes[i];
+
+		printf("[MUX%u] DT: %u", i, mux->id);
+		mtk_clk_print_mapped_id(mux->id, i + tree->muxes_offs, tree->id_offs_map);
+		mtk_clk_print_mux_parents(priv, mux);
+		printf("\n");
+	}
+
+	for (i = 0; i < tree->num_gates; i++) {
+		const struct mtk_gate *gate = &tree->gates[i];
+
+		printf("[GATE%u] DT: %u", i, gate->id);
+		mtk_clk_print_mapped_id(gate->id, i + tree->gates_offs, tree->id_offs_map);
+		mtk_clk_print_single_parent(gate->parent, gate->flags);
+		printf("\n");
+	}
+}
+#endif
+
 /* CG functions */
 
 static const int mtk_clk_gate_of_xlate(struct clk *clk,
@@ -869,12 +1081,36 @@ static ulong mtk_clk_gate_get_rate(struct clk *clk)
 	return mtk_clk_find_parent_rate(clk, gate->parent, parent);
 }
 
+#if CONFIG_IS_ENABLED(CMD_CLK)
+static void mtk_clk_gate_dump(struct udevice *dev)
+{
+	struct mtk_cg_priv *priv = dev_get_priv(dev);
+	const struct mtk_clk_tree *tree = priv->tree;
+	u32 i;
+
+	mtk_clk_print_dev_parent(priv->parent);
+
+	for (i = 0; i < priv->num_gates; i++) {
+		const struct mtk_gate *gate = &priv->gates[i];
+
+		printf("[GATE%u] DT: %u", i, gate->id);
+		mtk_clk_print_mapped_id(gate->id, i + tree->gates_offs, tree->id_offs_map);
+		mtk_clk_print_rate(dev, i + tree->gates_offs);
+		mtk_clk_print_single_parent(gate->parent, gate->flags);
+		printf("\n");
+	}
+}
+#endif
+
 const struct clk_ops mtk_clk_apmixedsys_ops = {
 	.of_xlate = mtk_apmixedsys_of_xlate,
 	.enable = mtk_apmixedsys_enable,
 	.disable = mtk_apmixedsys_disable,
 	.set_rate = mtk_apmixedsys_set_rate,
 	.get_rate = mtk_apmixedsys_get_rate,
+#if CONFIG_IS_ENABLED(CMD_CLK)
+	.dump = mtk_apmixedsys_dump,
+#endif
 };
 
 const struct clk_ops mtk_clk_fixed_pll_ops = {
@@ -882,6 +1118,9 @@ const struct clk_ops mtk_clk_fixed_pll_ops = {
 	.enable = mtk_dummy_enable,
 	.disable = mtk_dummy_enable,
 	.get_rate = mtk_topckgen_get_rate,
+#if CONFIG_IS_ENABLED(CMD_CLK)
+	.dump = mtk_topckgen_dump,
+#endif
 };
 
 const struct clk_ops mtk_clk_topckgen_ops = {
@@ -890,6 +1129,9 @@ const struct clk_ops mtk_clk_topckgen_ops = {
 	.disable = mtk_clk_mux_disable,
 	.get_rate = mtk_topckgen_get_rate,
 	.set_parent = mtk_common_clk_set_parent,
+#if CONFIG_IS_ENABLED(CMD_CLK)
+	.dump = mtk_topckgen_dump,
+#endif
 };
 
 const struct clk_ops mtk_clk_infrasys_ops = {
@@ -898,6 +1140,9 @@ const struct clk_ops mtk_clk_infrasys_ops = {
 	.disable = mtk_clk_infrasys_disable,
 	.get_rate = mtk_infrasys_get_rate,
 	.set_parent = mtk_common_clk_set_parent,
+#if CONFIG_IS_ENABLED(CMD_CLK)
+	.dump = mtk_infrasys_dump,
+#endif
 };
 
 const struct clk_ops mtk_clk_gate_ops = {
@@ -905,6 +1150,9 @@ const struct clk_ops mtk_clk_gate_ops = {
 	.enable = mtk_clk_gate_enable,
 	.disable = mtk_clk_gate_disable,
 	.get_rate = mtk_clk_gate_get_rate,
+#if CONFIG_IS_ENABLED(CMD_CLK)
+	.dump = mtk_clk_gate_dump,
+#endif
 };
 
 static int mtk_common_clk_init_drv(struct udevice *dev,

-- 
2.43.0



More information about the U-Boot mailing list