HACK: clks: implement a callback to dump arbitrary clocks

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
diff --git a/cmd/clk.c b/cmd/clk.c
index c7c379d..491f214 100644
--- a/cmd/clk.c
+++ b/cmd/clk.c
@@ -21,6 +21,8 @@
 	struct clk *clkp, *parent;
 	u32 rate;
 
+	clk_dump_clks(dev);
+
 	clkp = dev_get_clk_ptr(dev);
 	if (clkp) {
 		parent = clk_get_parent(clkp);
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 3b5e3f9..2d7d8fe 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -673,6 +673,15 @@
 	return 0;
 }
 
+void clk_dump_clks(struct udevice *dev)
+{
+	const struct clk_ops *ops;
+
+	ops = clk_dev_ops(dev);
+	if (ops && ops->dump_clks)
+		ops->dump_clks(dev);
+}
+
 int clk_enable_bulk(struct clk_bulk *bulk)
 {
 	int i, ret;
diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
index 7c683e5..1576ef6 100644
--- a/drivers/clk/qcom/clock-qcom.c
+++ b/drivers/clk/qcom/clock-qcom.c
@@ -206,9 +206,157 @@
 	return 0;
 }
 
+static void dump_gplls(struct udevice *dev, phys_addr_t base) {
+	static phys_addr_t gplls[] = {
+		0x00100000,
+		0x00101000,
+		0x00102000,
+		0x00103000,
+		0x00176000,
+		0x00174000,
+		0x00113000,
+		0x0011a000,
+		0x0011b000,
+		0x0011c000,
+		0x0011d000,
+		0x0014a000,
+	};
+	uint32_t i;
+	bool locked;
+	uint64_t l, a, xo_rate = 19200000;
+	struct clk clk;
+	int ret;
+	u32 pll_branch = readl(0x00152018);
+
+	ret = clk_get_by_name(dev, "xo_board", &clk);
+	if (ret < 0) {
+		ret = clk_get_by_name(dev, "xo-board", &clk);
+		if (ret < 0)
+			printf("Can't find XO clock, XO_BOARD rate may be wrong\n");
+	}
+
+	if (ret >= 0)
+		xo_rate = clk_get_rate(&clk);
+
+	printf("| GPLL   | LOCKED | GATE | XO_BOARD  |  PLL_L     | ALPHA          |\n");
+	printf("+--------+--------+------+-----------+------------+----------------+\n");
+	for (i = 0; i < ARRAY_SIZE(gplls); i++) {
+		locked = !!(readl(gplls[i]) & BIT(31));
+		l = readl(gplls[i] + 4) & (BIT(16)-1);
+		a = readq(gplls[i] + 40) & (BIT(16)-1);
+		printf("| GPLL%-2d | %-6s | %-4s | %9llu * (%#-9llx + %#-13llx  * 2 ** -40 ) / 1000000\n",
+			i, locked ? "X" : "", pll_branch & BIT(i) ? "X" : "", xo_rate, l, a);
+	}
+}
+
+static void dump_rcgs(void) {
+	static phys_addr_t rcgs[] = {
+		// 0x0010f018, // RB2
+		// 0x0010f030,
+		// 0x0010f05c,
+
+		// RB5
+		// 0x00175024, // GCC_UFS_CARD_AXI_CMD_RCGR
+		// 0x0017506c, // GCC_UFS_CARD_ICE_CORE_CMD_RCGR
+		// 0x00175084, // GCC_UFS_CARD_UNIPRO_CORE_CMD_RCGR
+		// 0x001750a0, // GCC_UFS_CARD_PHY_AUX_CMD_RCGR
+		// 0x00177024, // GCC_UFS_PHY_AXI_CMD_RCGR
+		// 0x0017706c, // GCC_UFS_PHY_ICE_CORE_CMD_RCGR
+		// 0x00177084, // GCC_UFS_PHY_UNIPRO_CORE_CMD_RCGR
+		// 0x001770a0, // GCC_UFS_PHY_PHY_AUX_CMD_RCGR
+		0x0011400c, // GCC_SDCC2_APPS_CMD_RCGR
+		//0x001184D0
+
+		// RB3
+		//0x00118148
+	};
+	static const char * const rcg_names[] = {
+		// "USB30_PRIM_MASTER", // RB2
+		// "USB30_PRIM_MOCK_UTMI",
+		// "USB3_PRIM_PHY_AUX",
+
+		// RB5
+		// "GCC_UFS_CARD_AXI_CMD_RCGR",
+		// "GCC_UFS_CARD_ICE_CORE_CMD_RCGR",
+		// "GCC_UFS_CARD_UNIPRO_CORE_CMD_RCGR",
+		// "GCC_UFS_CARD_PHY_AUX_CMD_RCGR",
+		// "GCC_UFS_PHY_AXI_CMD_RCGR",
+		// "GCC_UFS_PHY_ICE_CORE_CMD_RCGR",
+		// "GCC_UFS_PHY_UNIPRO_CORE_CMD_RCGR",
+		// "GCC_UFS_PHY_PHY_AUX_CMD_RCGR",
+		"GCC_SDCC2_APPS_CMD_RCGR",
+		//"UART",
+	};
+	int i;
+	uint32_t cmd;
+	uint32_t cfg;
+	uint32_t not_n_minus_m;
+	uint32_t src, m, n, div;
+	bool root_on, d_odd;
+	printf("\nRCGs:\n");
+
+	for (i = 0; i < ARRAY_SIZE(rcgs); i++) {
+		cmd = readl(rcgs[i]);
+		cfg = readl(rcgs[i] + 0x4);
+		m = readl(rcgs[i] + 0x8);
+		not_n_minus_m = readl(rcgs[i] + 0xc);
+
+		root_on = !(cmd & BIT(31)); // ROOT_OFF
+		src = (cfg >> 8) & 7;
+
+		if (not_n_minus_m)
+			n = (~not_n_minus_m & 0xffff) + m;
+		else
+			n = 0;
+
+		div = ((cfg & 0b11111) + 1) / 2;
+		d_odd = ((cfg & 0b11111) + 1) % 2 == 1;
+		printf("%#010x %#010x %#010x %#010x %#010x\n", cmd, cfg, m, not_n_minus_m, readl(rcgs[i] + 0x10));
+		printf("%-32s: %-1s src %d | input_freq * (%#x/%#x) * (1/%d%s)",
+			rcg_names[i], root_on ? "X" : "", src, m ?: 1, n ?: 1, div, d_odd ? ".5" : "");
+		printf("  [%#010X]\n", cmd);
+	}
+
+	printf("\n");
+}
+
+static void msm_dump_clks(struct udevice *dev)
+{
+	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(dev);
+	struct msm_clk_priv *priv = dev_get_priv(dev);
+	const struct gate_clk *sclk;
+	const struct qcom_reset_map *rst;
+	int val, i;
+
+	if (!data->clks) {
+		printf("No clocks\n");
+		return;
+	}
+
+	for (i = 0; i < data->num_clks; i++) {
+		sclk = &data->clks[i];
+		if (!sclk->name)
+			continue;
+		printf("%-32s: ", sclk->name);
+		val = readl(priv->base + sclk->reg) & sclk->en_val;
+		printf("%s\n", val ? "ON" : "");
+	}
+
+	for (i = 0; i < data->num_resets; i++) {
+		rst = &data->resets[i];
+		printf("%#05x: ", rst->reg);
+		val = readl(priv->base + rst->reg);
+		printf("%s\n", val > 0 ? "ON" : "");
+	}
+
+	dump_gplls(dev, priv->base);
+	dump_rcgs();
+}
+
 static struct clk_ops msm_clk_ops = {
 	.set_rate = msm_clk_set_rate,
 	.enable = msm_clk_enable,
+	.dump_clks = msm_dump_clks,
 };
 
 U_BOOT_DRIVER(qcom_clk) = {
diff --git a/include/clk-uclass.h b/include/clk-uclass.h
index a22f1a5..e26fce3 100644
--- a/include/clk-uclass.h
+++ b/include/clk-uclass.h
@@ -39,6 +39,7 @@
 	int (*set_parent)(struct clk *clk, struct clk *parent);
 	int (*enable)(struct clk *clk);
 	int (*disable)(struct clk *clk);
+	void (*dump_clks)(struct udevice *dev);
 };
 
 #if 0 /* For documentation only */
diff --git a/include/clk.h b/include/clk.h
index 249c0e0..bfdad96 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -549,6 +549,8 @@
  */
 int clk_disable(struct clk *clk);
 
+void clk_dump_clks(struct udevice *dev);
+
 /**
  * clk_disable_bulk() - Disable (turn off) all clocks in a clock bulk struct.
  * @bulk:	A clock bulk struct that was previously successfully requested