All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF
@ 2021-06-11  4:16 Sean Anderson
  2021-06-11  4:16 ` [PATCH v3 01/11] clk: Allow force setting clock defaults before relocation Sean Anderson
                   ` (12 more replies)
  0 siblings, 13 replies; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot
  Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson,
	Andreas Dannenberg, Lokesh Vutla, Philipp Tomsich

This is something I've been meaning to do for a while but only just got around
to. The CCF has been quite unwieldy in a few ways:

* It is very rigid, and there are not easy ways to hook into it without
  rewriting many things. See e.g. things like the bypass clock and all the _half
  clocks which were created because CCF didn't support the dividers used on the
  k210. While preparing this series, I encountered several edge cases which I
  had initially overlooked (or which were not supported in the initial release).
  These would have been very difficult to fix with CCF, but were much easier to
  address because each funcion is implemented in one place.
* There is a lot of magic going on under the curtains because of all the CCF
  code which lives in many different files. Some things live in drivers, but
  many things live in e.g. clk-uclass.c. So many things live in so many files
  and it can be very difficult to get a handle on what exactly happens.
  Complicating this is that there is a conflation of struct clk as a handle and
  struct clk as a device. In this regard, refcounting is completely broken. IMO
  we should just do away with refcounts and only disable clocks when explicitly
  asked for.
* It is very dependent on runtime initialization. Typically, everything is
  initialized by calling into various register() functions, usually with several
  wrappers to avoid specifying all the arguments. This balloons the runtime
  memory usage since there are so many devices created. It also makes it hard to
  debug, since if you do it the "typical" way it is easy to accidentally assign
  a clock to the wrong register.
* It inflates code size by pulling in not just some dead code (e.g. this driver
  does not use divider tables but they are in clk-divider anyway) but also
  pulling in numerous imx-specific clocks. This could be fixed, but I don't want
  to due to the other reasons listed.

I am very happy to have completely excised it from my driver. IMO there should
be big warning signs on the CCF warning not to use it for new code. This would
hopefully dissuade those like myself who had no idea that CCF was *not* in fact
a good way to write a clock driver.

Overall there is a total savings of 12k from this series.
   text	   data	    bss	    dec	    hex	filename
 292485	  32672	  12624	 337781	  52775	before/u-boot
 283125	  29856	  12624	 325605	  4f7e5	after/u-boot

This series depends on
https://patchwork.ozlabs.org/project/uboot/list/?series=238211

Changes in v3:
- Always define clk_defaults_stage, even if clk_set_defaults is a dummy
- Fix inverted condition for setting defaults
- Fix val not being set for K210_DIV_POWER
- Add CLK_K210_SET_RATE to defconfig so these changes apply

Changes in v2:
- Convert stage to enum
- Only force probe clocks pre-reloc
- Rebase on u-boot/master

Sean Anderson (11):
  clk: Allow force setting clock defaults before relocation
  clk: k210: Rewrite to remove CCF
  clk: k210: Move pll into the rest of the driver
  clk: k210: Implement soc_clk_dump
  clk: k210: Re-add support for setting rate
  clk: k210: Don't set PLL rates if we are already at the correct rate
  clk: k210: Remove bypass driver
  clk: k210: Move k210 clock out of its own subdirectory
  k210: dts: Set PLL1 to the same rate as PLL0
  k210: Don't imply CCF
  test: Add K210 PLL tests to sandbox defconfigs

 MAINTAINERS                             |    4 +-
 arch/riscv/dts/k210.dtsi                |    2 +
 board/sipeed/maix/Kconfig               |    2 -
 configs/sandbox64_defconfig             |    2 +
 configs/sandbox_defconfig               |    2 +
 configs/sandbox_flattree_defconfig      |    2 +
 configs/sipeed_maix_bitm_defconfig      |    2 +-
 drivers/clk/Kconfig                     |   14 +-
 drivers/clk/Makefile                    |    2 +-
 drivers/clk/clk-uclass.c                |   27 +-
 drivers/clk/clk_kendryte.c              | 1320 +++++++++++++++++++++++
 drivers/clk/kendryte/Kconfig            |   12 -
 drivers/clk/kendryte/Makefile           |    1 -
 drivers/clk/kendryte/bypass.c           |  273 -----
 drivers/clk/kendryte/clk.c              |  668 ------------
 drivers/clk/kendryte/pll.c              |  585 ----------
 drivers/clk/rockchip/clk_rk3308.c       |    2 +-
 drivers/core/device.c                   |    2 +-
 drivers/net/gmac_rockchip.c             |    2 +-
 include/clk.h                           |   30 +-
 include/dt-bindings/clock/k210-sysctl.h |   94 +-
 include/kendryte/bypass.h               |   31 -
 include/kendryte/clk.h                  |   35 -
 include/kendryte/pll.h                  |   34 -
 24 files changed, 1437 insertions(+), 1711 deletions(-)
 create mode 100644 drivers/clk/clk_kendryte.c
 delete mode 100644 drivers/clk/kendryte/Kconfig
 delete mode 100644 drivers/clk/kendryte/Makefile
 delete mode 100644 drivers/clk/kendryte/bypass.c
 delete mode 100644 drivers/clk/kendryte/clk.c
 delete mode 100644 drivers/clk/kendryte/pll.c
 delete mode 100644 include/kendryte/bypass.h
 delete mode 100644 include/kendryte/clk.h

-- 
2.31.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v3 01/11] clk: Allow force setting clock defaults before relocation
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-11  4:16 ` [PATCH v3 02/11] clk: k210: Rewrite to remove CCF Sean Anderson
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot
  Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson,
	Simon Glass, Andreas Dannenberg, Lokesh Vutla, Philipp Tomsich

Since 291da96b8e ("clk: Allow clock defaults to be set during re-reloc
state for SPL only") it has been impossible to set clock defaults before
relocation. This is annoying on boards without SPL, since there is no way
to set clock defaults before U-Boot proper. In particular, the aisram rate
must be changed before relocation on the K210, since U-Boot will hang if we
try and change the rate while we are using aisram.

To get around this, extend the stage parameter to allow force setting
defaults, even if they would be otherwise postponed for later. A device
tree property was decided against because of the concerns in the original
commit thread about the overhead of repeatedly parsing the device tree.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Always define clk_defaults_stage, even if clk_set_defaults is a dummy

Changes in v2:
- Convert stage to enum

 drivers/clk/clk-uclass.c          | 27 +++++++++++++++++----------
 drivers/clk/rockchip/clk_rk3308.c |  2 +-
 drivers/core/device.c             |  2 +-
 drivers/net/gmac_rockchip.c       |  2 +-
 include/clk.h                     | 30 ++++++++++++++++++++++++++----
 5 files changed, 46 insertions(+), 17 deletions(-)

diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 53e7be764d..25b6a41855 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -207,7 +207,8 @@ static struct clk *clk_set_default_get_by_id(struct clk *clk)
 	return c;
 }
 
-static int clk_set_default_parents(struct udevice *dev, int stage)
+static int clk_set_default_parents(struct udevice *dev,
+				   enum clk_defaults_stage stage)
 {
 	struct clk clk, parent_clk, *c, *p;
 	int index;
@@ -251,10 +252,10 @@ static int clk_set_default_parents(struct udevice *dev, int stage)
 		 * It cannot be done right now but need to wait after the
 		 * device is probed
 		 */
-		if (stage == 0 && clk.dev == dev)
+		if (stage == CLK_DEFAULTS_PRE && clk.dev == dev)
 			continue;
 
-		if (stage > 0 && clk.dev != dev)
+		if (stage != CLK_DEFAULTS_PRE && clk.dev != dev)
 			/* do not setup twice the parent clocks */
 			continue;
 
@@ -280,7 +281,8 @@ static int clk_set_default_parents(struct udevice *dev, int stage)
 	return 0;
 }
 
-static int clk_set_default_rates(struct udevice *dev, int stage)
+static int clk_set_default_rates(struct udevice *dev,
+				 enum clk_defaults_stage stage)
 {
 	struct clk clk, *c;
 	int index;
@@ -320,10 +322,10 @@ static int clk_set_default_rates(struct udevice *dev, int stage)
 		 * It cannot be done right now but need to wait after the
 		 * device is probed
 		 */
-		if (stage == 0 && clk.dev == dev)
+		if (stage == CLK_DEFAULTS_PRE && clk.dev == dev)
 			continue;
 
-		if (stage > 0 && clk.dev != dev)
+		if (stage != CLK_DEFAULTS_PRE && clk.dev != dev)
 			/* do not setup twice the parent clocks */
 			continue;
 
@@ -346,16 +348,21 @@ fail:
 	return ret;
 }
 
-int clk_set_defaults(struct udevice *dev, int stage)
+int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage)
 {
 	int ret;
 
 	if (!dev_has_ofnode(dev))
 		return 0;
 
-	/* If this not in SPL and pre-reloc state, don't take any action. */
+	/*
+	 * To avoid setting defaults twice, don't set them before relocation.
+	 * However, still set them for SPL. And still set them if explicitly
+	 * asked.
+	 */
 	if (!(IS_ENABLED(CONFIG_SPL_BUILD) || (gd->flags & GD_FLG_RELOC)))
-		return 0;
+		if (stage != CLK_DEFAULTS_POST_FORCE)
+			return 0;
 
 	debug("%s(%s)\n", __func__, dev_read_name(dev));
 
@@ -805,7 +812,7 @@ int clk_uclass_post_probe(struct udevice *dev)
 	 * where the DT is used to setup default parents and rates
 	 * using assigned-clocks
 	 */
-	clk_set_defaults(dev, 1);
+	clk_set_defaults(dev, CLK_DEFAULTS_POST);
 
 	return 0;
 }
diff --git a/drivers/clk/rockchip/clk_rk3308.c b/drivers/clk/rockchip/clk_rk3308.c
index 5a838b9e9a..5248e59685 100644
--- a/drivers/clk/rockchip/clk_rk3308.c
+++ b/drivers/clk/rockchip/clk_rk3308.c
@@ -1014,7 +1014,7 @@ static int rk3308_clk_probe(struct udevice *dev)
 	rk3308_clk_init(dev);
 
 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
-	ret = clk_set_defaults(dev, 1);
+	ret = clk_set_defaults(dev, CLK_DEFAULTS_POST);
 	if (ret)
 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
 
diff --git a/drivers/core/device.c b/drivers/core/device.c
index cb960f8ec4..9f1400768d 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -561,7 +561,7 @@ int device_probe(struct udevice *dev)
 		 * Process 'assigned-{clocks/clock-parents/clock-rates}'
 		 * properties
 		 */
-		ret = clk_set_defaults(dev, 0);
+		ret = clk_set_defaults(dev, CLK_DEFAULTS_PRE);
 		if (ret)
 			goto fail;
 	}
diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c
index f909660484..04008d2b19 100644
--- a/drivers/net/gmac_rockchip.c
+++ b/drivers/net/gmac_rockchip.c
@@ -565,7 +565,7 @@ static int gmac_rockchip_probe(struct udevice *dev)
 	ulong rate;
 	int ret;
 
-	ret = clk_set_defaults(dev, 0);
+	ret = clk_set_defaults(dev, CLK_DEFAULTS_PRE);
 	if (ret)
 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
 
diff --git a/include/clk.h b/include/clk.h
index ca6b85fa6f..f3c88fe68a 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -277,19 +277,41 @@ static inline int clk_release_all(struct clk *clk, int count)
 }
 #endif
 
+/**
+ * enum clk_defaults_stage - What stage clk_set_defaults() is called at
+ * @CLK_DEFAULTS_PRE: Called before probe. Setting of defaults for clocks owned
+ *                    by this clock driver will be defered until after probing.
+ * @CLK_DEFAULTS_POST: Called after probe. Only defaults for clocks owned by
+ *                     this clock driver will be set.
+ * @CLK_DEFAULTS_POST_FORCE: Called after probe, and always set defaults, even
+ *                           before relocation. Usually, defaults are not set
+ *                           pre-relocation to avoid setting them twice (when
+ *                           the device is probed again post-relocation). This
+ *                           may incur a performance cost as device tree
+ *                           properties must be parsed for a second time.
+ *                           However, when not using SPL, pre-relocation may be
+ *                           the only time we can set defaults for some clocks
+ *                           (such as those used for the RAM we will relocate
+ *                           into).
+ */
+enum clk_defaults_stage {
+	CLK_DEFAULTS_PRE = 0,
+	CLK_DEFAULTS_POST = 1,
+	CLK_DEFAULTS_POST_FORCE,
+};
+
 #if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) && \
 	CONFIG_IS_ENABLED(CLK)
+
 /**
  * clk_set_defaults - Process 'assigned-{clocks/clock-parents/clock-rates}'
  *                    properties to configure clocks
  *
  * @dev:        A device to process (the ofnode associated with this device
  *              will be processed).
- * @stage:	A integer. 0 indicates that this is called before the device
- *		is probed. 1 indicates that this is called just after the
- *		device has been probed
+ * @stage:	The stage of the probing process this function is called during.
  */
-int clk_set_defaults(struct udevice *dev, int stage);
+int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage);
 #else
 static inline int clk_set_defaults(struct udevice *dev, int stage)
 {
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 02/11] clk: k210: Rewrite to remove CCF
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
  2021-06-11  4:16 ` [PATCH v3 01/11] clk: Allow force setting clock defaults before relocation Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-16  1:54   ` Leo Liang
  2021-06-11  4:16 ` [PATCH v3 03/11] clk: k210: Move pll into the rest of the driver Sean Anderson
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot; +Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson

This is effectively a complete rewrite to remove all dependency on CCF.
The code is now smaller, and so is the binary. It also takes up less memory
at runtime (since we don't have to create 40 udevices). In general, I am
much happier with this driver as much of the complexity and late binding
has been removed.

The k210_*_params structs which were previously used to initialize CCF
clocks are now used as the complete configuration. Since we can write our
own division logic, we can now do away with several "half" clocks which
only existed to provide constant factors of two.

The clock IDs have been renumbered to remove unused clocks. This may not be
the last time they are renumbered, since we have diverged with Linux. There
are also still a few clocks left out which may need to be added back in.

In general, I have tried to leave out behavioral changes. However, there is
a small bugfix regarding ACLK. According to the technical reference manual,
its mux comes *after* its divider (which is present only for PLL0). This
would have required yet another intermediate clock to fix with CCF, but
with the new driver it is just 2 lines of code :)

Signed-off-by: Sean Anderson <seanga2@gmail.com>
---

(no changes since v1)

 drivers/clk/kendryte/Kconfig            |   2 +-
 drivers/clk/kendryte/clk.c              | 848 +++++++++++-------------
 drivers/clk/kendryte/pll.c              | 114 ++--
 include/dt-bindings/clock/k210-sysctl.h |  94 ++-
 include/kendryte/pll.h                  |  26 +-
 5 files changed, 499 insertions(+), 585 deletions(-)

diff --git a/drivers/clk/kendryte/Kconfig b/drivers/clk/kendryte/Kconfig
index 073fca0781..0dc8e3f889 100644
--- a/drivers/clk/kendryte/Kconfig
+++ b/drivers/clk/kendryte/Kconfig
@@ -1,6 +1,6 @@
 config CLK_K210
 	bool "Clock support for Kendryte K210"
-	depends on CLK && CLK_CCF && CLK_COMPOSITE_CCF
+	depends on CLK
 	help
 	  This enables support clock driver for Kendryte K210 platforms.
 
diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/kendryte/clk.c
index 41c712e03f..34e8e742a6 100644
--- a/drivers/clk/kendryte/clk.c
+++ b/drivers/clk/kendryte/clk.c
@@ -4,7 +4,7 @@
  */
 #include <kendryte/clk.h>
 
-#include <asm/io.h>
+#include <common.h>
 #include <dt-bindings/clock/k210-sysctl.h>
 #include <dt-bindings/mfd/k210-sysctl.h>
 #include <dm.h>
@@ -14,77 +14,6 @@
 #include <kendryte/bypass.h>
 #include <kendryte/pll.h>
 
-/* All methods are delegated to CCF clocks */
-
-static ulong k210_clk_get_rate(struct clk *clk)
-{
-	struct clk *c;
-	int err = clk_get_by_id(clk->id, &c);
-
-	if (err)
-		return err;
-	return clk_get_rate(c);
-}
-
-static ulong k210_clk_set_rate(struct clk *clk, unsigned long rate)
-{
-	struct clk *c;
-	int err = clk_get_by_id(clk->id, &c);
-
-	if (err)
-		return err;
-	return clk_set_rate(c, rate);
-}
-
-static int k210_clk_set_parent(struct clk *clk, struct clk *parent)
-{
-	struct clk *c, *p;
-	int err = clk_get_by_id(clk->id, &c);
-
-	if (err)
-		return err;
-
-	err = clk_get_by_id(parent->id, &p);
-	if (err)
-		return err;
-
-	return clk_set_parent(c, p);
-}
-
-static int k210_clk_endisable(struct clk *clk, bool enable)
-{
-	struct clk *c;
-	int err = clk_get_by_id(clk->id, &c);
-
-	if (err)
-		return err;
-	return enable ? clk_enable(c) : clk_disable(c);
-}
-
-static int k210_clk_enable(struct clk *clk)
-{
-	return k210_clk_endisable(clk, true);
-}
-
-static int k210_clk_disable(struct clk *clk)
-{
-	return k210_clk_endisable(clk, false);
-}
-
-static const struct clk_ops k210_clk_ops = {
-	.set_rate = k210_clk_set_rate,
-	.get_rate = k210_clk_get_rate,
-	.set_parent = k210_clk_set_parent,
-	.enable = k210_clk_enable,
-	.disable = k210_clk_disable,
-};
-
-/* Parents for muxed clocks */
-static const char * const generic_sels[] = { "in0_half", "pll0_half" };
-/* The first clock is in0, which is filled in by k210_clk_probe */
-static const char *aclk_sels[] = { NULL, "pll0_half" };
-static const char *pll2_sels[] = { NULL, "pll0", "pll1" };
-
 /*
  * All parameters for different sub-clocks are collected into parameter arrays.
  * These parameters are then initialized by the clock which uses them during
@@ -97,68 +26,113 @@ static const char *pll2_sels[] = { NULL, "pll0", "pll1" };
  * easy to find bugs in the code.
  */
 
-#define DIV(id, off, shift, width) DIV_FLAGS(id, off, shift, width, 0)
+/**
+ * enum k210_clk_div_type - The type of divider
+ * @K210_DIV_ONE: freq = parent / (reg + 1)
+ * @K210_DIV_EVEN: freq = parent / 2 / (reg + 1)
+ * @K210_DIV_POWER: freq = parent / (2 << reg)
+ * @K210_DIV_FIXED: freq = parent / factor
+ */
+enum k210_clk_div_type {
+	K210_DIV_ONE,
+	K210_DIV_EVEN,
+	K210_DIV_POWER,
+	K210_DIV_FIXED,
+};
+
+/**
+ * struct k210_div_params - Parameters for dividing clocks
+ * @type: An &enum k210_clk_div_type specifying the dividing formula
+ * @off: The offset of the divider from the sysctl base address
+ * @shift: The offset of the LSB of the divider
+ * @width: The number of bits in the divider
+ * @div: The fixed divisor for this divider
+ */
+struct k210_div_params {
+	u8 type;
+	union {
+		struct {
+			u8 off;
+			u8 shift;
+			u8 width;
+		};
+		u8 div;
+	};
+};
+
 #define DIV_LIST \
-	DIV_FLAGS(K210_CLK_ACLK, K210_SYSCTL_SEL0, 1, 2, \
-		  CLK_DIVIDER_POWER_OF_TWO) \
-	DIV(K210_CLK_APB0,   K210_SYSCTL_SEL0,  3,  3) \
-	DIV(K210_CLK_APB1,   K210_SYSCTL_SEL0,  6,  3) \
-	DIV(K210_CLK_APB2,   K210_SYSCTL_SEL0,  9,  3) \
-	DIV(K210_CLK_SRAM0,  K210_SYSCTL_THR0,  0,  4) \
-	DIV(K210_CLK_SRAM1,  K210_SYSCTL_THR0,  4,  4) \
-	DIV(K210_CLK_AI,     K210_SYSCTL_THR0,  8,  4) \
-	DIV(K210_CLK_DVP,    K210_SYSCTL_THR0, 12,  4) \
-	DIV(K210_CLK_ROM,    K210_SYSCTL_THR0, 16,  4) \
-	DIV(K210_CLK_SPI0,   K210_SYSCTL_THR1,  0,  8) \
-	DIV(K210_CLK_SPI1,   K210_SYSCTL_THR1,  8,  8) \
-	DIV(K210_CLK_SPI2,   K210_SYSCTL_THR1, 16,  8) \
-	DIV(K210_CLK_SPI3,   K210_SYSCTL_THR1, 24,  8) \
-	DIV(K210_CLK_TIMER0, K210_SYSCTL_THR2,  0,  8) \
-	DIV(K210_CLK_TIMER1, K210_SYSCTL_THR2,  8,  8) \
-	DIV(K210_CLK_TIMER2, K210_SYSCTL_THR2, 16,  8) \
-	DIV(K210_CLK_I2S0,   K210_SYSCTL_THR3,  0, 16) \
-	DIV(K210_CLK_I2S1,   K210_SYSCTL_THR3, 16, 16) \
-	DIV(K210_CLK_I2S2,   K210_SYSCTL_THR4,  0, 16) \
-	DIV(K210_CLK_I2S0_M, K210_SYSCTL_THR4, 16,  8) \
-	DIV(K210_CLK_I2S1_M, K210_SYSCTL_THR4, 24,  8) \
-	DIV(K210_CLK_I2S2_M, K210_SYSCTL_THR4,  0,  8) \
-	DIV(K210_CLK_I2C0,   K210_SYSCTL_THR5,  8,  8) \
-	DIV(K210_CLK_I2C1,   K210_SYSCTL_THR5, 16,  8) \
-	DIV(K210_CLK_I2C2,   K210_SYSCTL_THR5, 24,  8) \
-	DIV(K210_CLK_WDT0,   K210_SYSCTL_THR6,  0,  8) \
-	DIV(K210_CLK_WDT1,   K210_SYSCTL_THR6,  8,  8)
+	DIV(K210_CLK_ACLK,   K210_SYSCTL_SEL0,  1,  2, K210_DIV_POWER) \
+	DIV(K210_CLK_APB0,   K210_SYSCTL_SEL0,  3,  3, K210_DIV_ONE) \
+	DIV(K210_CLK_APB1,   K210_SYSCTL_SEL0,  6,  3, K210_DIV_ONE) \
+	DIV(K210_CLK_APB2,   K210_SYSCTL_SEL0,  9,  3, K210_DIV_ONE) \
+	DIV(K210_CLK_SRAM0,  K210_SYSCTL_THR0,  0,  4, K210_DIV_ONE) \
+	DIV(K210_CLK_SRAM1,  K210_SYSCTL_THR0,  4,  4, K210_DIV_ONE) \
+	DIV(K210_CLK_AI,     K210_SYSCTL_THR0,  8,  4, K210_DIV_ONE) \
+	DIV(K210_CLK_DVP,    K210_SYSCTL_THR0, 12,  4, K210_DIV_ONE) \
+	DIV(K210_CLK_ROM,    K210_SYSCTL_THR0, 16,  4, K210_DIV_ONE) \
+	DIV(K210_CLK_SPI0,   K210_SYSCTL_THR1,  0,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_SPI1,   K210_SYSCTL_THR1,  8,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_SPI2,   K210_SYSCTL_THR1, 16,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_SPI3,   K210_SYSCTL_THR1, 24,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_TIMER0, K210_SYSCTL_THR2,  0,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_TIMER1, K210_SYSCTL_THR2,  8,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_TIMER2, K210_SYSCTL_THR2, 16,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_I2S0,   K210_SYSCTL_THR3,  0, 16, K210_DIV_EVEN) \
+	DIV(K210_CLK_I2S1,   K210_SYSCTL_THR3, 16, 16, K210_DIV_EVEN) \
+	DIV(K210_CLK_I2S2,   K210_SYSCTL_THR4,  0, 16, K210_DIV_EVEN) \
+	DIV(K210_CLK_I2S0_M, K210_SYSCTL_THR4, 16,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_I2S1_M, K210_SYSCTL_THR4, 24,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_I2S2_M, K210_SYSCTL_THR4,  0,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_I2C0,   K210_SYSCTL_THR5,  8,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_I2C1,   K210_SYSCTL_THR5, 16,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_I2C2,   K210_SYSCTL_THR5, 24,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_WDT0,   K210_SYSCTL_THR6,  0,  8, K210_DIV_EVEN) \
+	DIV(K210_CLK_WDT1,   K210_SYSCTL_THR6,  8,  8, K210_DIV_EVEN) \
+	DIV_FIXED(K210_CLK_CLINT, 50) \
 
 #define _DIVIFY(id) K210_CLK_DIV_##id
 #define DIVIFY(id) _DIVIFY(id)
 
-enum k210_div_ids {
-#define DIV_FLAGS(id, ...) DIVIFY(id),
+enum k210_div_id {
+#define DIV(id, ...) DIVIFY(id),
+#define DIV_FIXED DIV
 	DIV_LIST
-#undef DIV_FLAGS
-};
-
-struct k210_div_params {
-	u8 off;
-	u8 shift;
-	u8 width;
-	u8 flags;
+#undef DIV
+#undef DIV_FIXED
+	K210_CLK_DIV_NONE,
 };
 
 static const struct k210_div_params k210_divs[] = {
-#define DIV_FLAGS(id, _off, _shift, _width, _flags) \
+#define DIV(id, _off, _shift, _width, _type) \
 	[DIVIFY(id)] = { \
+		.type = (_type), \
 		.off = (_off), \
 		.shift = (_shift), \
 		.width = (_width), \
-		.flags = (_flags), \
+	},
+#define DIV_FIXED(id, _div) \
+	[DIVIFY(id)] = { \
+		.type = K210_DIV_FIXED, \
+		.div = (_div) \
 	},
 	DIV_LIST
-#undef DIV_FLAGS
+#undef DIV
+#undef DIV_FIXED
 };
 
 #undef DIV
 #undef DIV_LIST
 
+/**
+ * struct k210_gate_params - Parameters for gated clocks
+ * @off: The offset of the gate from the sysctl base address
+ * @bit_idx: The index of the bit within the register
+ */
+struct k210_gate_params {
+	u8 off;
+	u8 bit_idx;
+};
+
 #define GATE_LIST \
 	GATE(K210_CLK_CPU,    K210_SYSCTL_EN_CENT,  0) \
 	GATE(K210_CLK_SRAM0,  K210_SYSCTL_EN_CENT,  1) \
@@ -199,15 +173,11 @@ static const struct k210_div_params k210_divs[] = {
 #define _GATEIFY(id) K210_CLK_GATE_##id
 #define GATEIFY(id) _GATEIFY(id)
 
-enum k210_gate_ids {
+enum k210_gate_id {
 #define GATE(id, ...) GATEIFY(id),
 	GATE_LIST
 #undef GATE
-};
-
-struct k210_gate_params {
-	u8 off;
-	u8 bit_idx;
+	K210_CLK_GATE_NONE,
 };
 
 static const struct k210_gate_params k210_gates[] = {
@@ -222,11 +192,31 @@ static const struct k210_gate_params k210_gates[] = {
 
 #undef GATE_LIST
 
+/* The most parents is PLL2 */
+#define K210_CLK_MAX_PARENTS 3
+
+/**
+ * struct k210_mux_params - Parameters for muxed clocks
+ * @parents: A list of parent clock ids
+ * @num_parents: The number of parent clocks
+ * @off: The offset of the mux from the base sysctl address
+ * @shift: The offset of the LSB of the mux selector
+ * @width: The number of bits in the mux selector
+ */
+struct k210_mux_params {
+	u8 parents[K210_CLK_MAX_PARENTS];
+	u8 num_parents;
+	u8 off;
+	u8 shift;
+	u8 width;
+};
+
 #define MUX(id, reg, shift, width) \
-	MUX_PARENTS(id, generic_sels, reg, shift, width)
+	MUX_PARENTS(id, reg, shift, width, K210_CLK_IN0, K210_CLK_PLL0)
 #define MUX_LIST \
-	MUX_PARENTS(K210_CLK_PLL2, pll2_sels, K210_SYSCTL_PLL2, 26, 2) \
-	MUX_PARENTS(K210_CLK_ACLK, aclk_sels, K210_SYSCTL_SEL0,  0, 1) \
+	MUX_PARENTS(K210_CLK_PLL2, K210_SYSCTL_PLL2, 26, 2, \
+		    K210_CLK_IN0, K210_CLK_PLL0, K210_CLK_PLL1) \
+	MUX(K210_CLK_ACLK, K210_SYSCTL_SEL0, 0, 1) \
 	MUX(K210_CLK_SPI3,   K210_SYSCTL_SEL0, 12, 1) \
 	MUX(K210_CLK_TIMER0, K210_SYSCTL_SEL0, 13, 1) \
 	MUX(K210_CLK_TIMER1, K210_SYSCTL_SEL0, 14, 1) \
@@ -235,26 +225,18 @@ static const struct k210_gate_params k210_gates[] = {
 #define _MUXIFY(id) K210_CLK_MUX_##id
 #define MUXIFY(id) _MUXIFY(id)
 
-enum k210_mux_ids {
+enum k210_mux_id {
 #define MUX_PARENTS(id, ...) MUXIFY(id),
 	MUX_LIST
 #undef MUX_PARENTS
 	K210_CLK_MUX_NONE,
 };
 
-struct k210_mux_params {
-	const char *const *parent_names;
-	u8 num_parents;
-	u8 off;
-	u8 shift;
-	u8 width;
-};
-
 static const struct k210_mux_params k210_muxes[] = {
-#define MUX_PARENTS(id, parents, _off, _shift, _width) \
+#define MUX_PARENTS(id, _off, _shift, _width, ...) \
 	[MUXIFY(id)] = { \
-		.parent_names = (const char * const *)(parents), \
-		.num_parents = ARRAY_SIZE(parents), \
+		.parents = { __VA_ARGS__ }, \
+		.num_parents = __count_args(__VA_ARGS__), \
 		.off = (_off), \
 		.shift = (_shift), \
 		.width = (_width), \
@@ -266,389 +248,321 @@ static const struct k210_mux_params k210_muxes[] = {
 #undef MUX
 #undef MUX_LIST
 
-struct k210_pll_params {
-	u8 off;
-	u8 lock_off;
-	u8 shift;
-	u8 width;
+/**
+ * enum k210_clk_flags - The type of a K210 clock
+ * @K210_CLKF_MUX: This clock has a mux and not a static parent
+ * @K210_CLKF_PLL: This clock is a PLL
+ */
+enum k210_clk_flags {
+	K210_CLKF_MUX = BIT(0),
+	K210_CLKF_PLL = BIT(1),
 };
 
-static const struct k210_pll_params k210_plls[] = {
-#define PLL(_off, _shift, _width) { \
-	.off = (_off), \
-	.lock_off = K210_SYSCTL_PLL_LOCK, \
-	.shift = (_shift), \
-	.width = (_width), \
-}
-	[0] = PLL(K210_SYSCTL_PLL0,  0, 2),
-	[1] = PLL(K210_SYSCTL_PLL1,  8, 1),
-	[2] = PLL(K210_SYSCTL_PLL2, 16, 1),
-#undef PLL
+/**
+ * struct k210_clk_params - The parameters defining a K210 clock
+ * @name: The name of the clock
+ * @flags: A set of &enum k210_clk_flags defining which fields are valid
+ * @mux: An &enum k210_mux_id of this clock's mux
+ * @parent: The clock id of this clock's parent
+ * @pll: The id of the PLL (if this clock is a PLL)
+ * @div: An &enum k210_div_id of this clock's divider
+ * @gate: An &enum k210_gate_id of this clock's gate
+ */
+struct k210_clk_params {
+#if CONFIG_IS_ENABLED(CMD_CLK)
+	const char *name;
+#endif
+	u8 flags;
+	union {
+		u8 parent;
+		u8 mux;
+	};
+	union {
+		u8 pll;
+		struct {
+			u8 div;
+			u8 gate;
+		};
+	};
 };
 
-#define COMP(id) \
-	COMP_FULL(id, MUXIFY(id), DIVIFY(id), GATEIFY(id))
-#define COMP_NOMUX(id) \
-	COMP_FULL(id, K210_CLK_MUX_NONE, DIVIFY(id), GATEIFY(id))
-#define COMP_LIST \
-	COMP(K210_CLK_SPI3) \
-	COMP(K210_CLK_TIMER0) \
-	COMP(K210_CLK_TIMER1) \
-	COMP(K210_CLK_TIMER2) \
-	COMP_NOMUX(K210_CLK_SRAM0) \
-	COMP_NOMUX(K210_CLK_SRAM1) \
-	COMP_NOMUX(K210_CLK_ROM) \
-	COMP_NOMUX(K210_CLK_DVP) \
-	COMP_NOMUX(K210_CLK_APB0) \
-	COMP_NOMUX(K210_CLK_APB1) \
-	COMP_NOMUX(K210_CLK_APB2) \
-	COMP_NOMUX(K210_CLK_AI) \
-	COMP_NOMUX(K210_CLK_I2S0) \
-	COMP_NOMUX(K210_CLK_I2S1) \
-	COMP_NOMUX(K210_CLK_I2S2) \
-	COMP_NOMUX(K210_CLK_WDT0) \
-	COMP_NOMUX(K210_CLK_WDT1) \
-	COMP_NOMUX(K210_CLK_SPI0) \
-	COMP_NOMUX(K210_CLK_SPI1) \
-	COMP_NOMUX(K210_CLK_SPI2) \
-	COMP_NOMUX(K210_CLK_I2C0) \
-	COMP_NOMUX(K210_CLK_I2C1) \
-	COMP_NOMUX(K210_CLK_I2C2)
 
-#define _COMPIFY(id) K210_CLK_COMP_##id
-#define COMPIFY(id) _COMPIFY(id)
-
-enum k210_comp_ids {
-#define COMP_FULL(id, ...) COMPIFY(id),
-	COMP_LIST
-#undef COMP_FULL
-};
-
-struct k210_comp_params {
-	u8 mux;
-	u8 div;
-	u8 gate;
-};
-
-static const struct k210_comp_params k210_comps[] = {
-#define COMP_FULL(id, _mux, _div, _gate) \
-	[COMPIFY(id)] = { \
+static const struct k210_clk_params k210_clks[] = {
+#if CONFIG_IS_ENABLED(CMD_CLK)
+#define NAME(_name) .name = (_name),
+#else
+#define NAME(name)
+#endif
+#define CLK(id, _name, _parent, _div, _gate) \
+	[id] = { \
+		NAME(_name) \
+		.parent = (_parent), \
+		.div = (_div), \
+		.gate = (_gate), \
+	}
+#define CLK_MUX(id, _name, _mux, _div, _gate) \
+	[id] = { \
+		NAME(_name) \
+		.flags = K210_CLKF_MUX, \
 		.mux = (_mux), \
 		.div = (_div), \
 		.gate = (_gate), \
+	}
+#define CLK_PLL(id, _pll, _parent) \
+	[id] = { \
+		NAME("pll" #_pll) \
+		.flags = K210_CLKF_PLL, \
+		.parent = (_parent), \
+		.pll = (_pll), \
+	}
+#define CLK_FULL(id, name) \
+	CLK_MUX(id, name, MUXIFY(id), DIVIFY(id), GATEIFY(id))
+#define CLK_NOMUX(id, name, parent) \
+	CLK(id, name, parent, DIVIFY(id), GATEIFY(id))
+#define CLK_DIV(id, name, parent) \
+	CLK(id, name, parent, DIVIFY(id), K210_CLK_GATE_NONE)
+#define CLK_GATE(id, name, parent) \
+	CLK(id, name, parent, K210_CLK_DIV_NONE, GATEIFY(id))
+	CLK_PLL(K210_CLK_PLL0, 0, K210_CLK_IN0),
+	CLK_PLL(K210_CLK_PLL1, 1, K210_CLK_IN0),
+	[K210_CLK_PLL2] = {
+		NAME("pll2")
+		.flags = K210_CLKF_MUX | K210_CLKF_PLL,
+		.mux = MUXIFY(K210_CLK_PLL2),
+		.pll = 2,
 	},
-	COMP_LIST
-#undef COMP_FULL
+	CLK_MUX(K210_CLK_ACLK, "aclk", MUXIFY(K210_CLK_ACLK),
+		DIVIFY(K210_CLK_ACLK), K210_CLK_GATE_NONE),
+	CLK_FULL(K210_CLK_SPI3,   "spi3"),
+	CLK_FULL(K210_CLK_TIMER0, "timer0"),
+	CLK_FULL(K210_CLK_TIMER1, "timer1"),
+	CLK_FULL(K210_CLK_TIMER2, "timer2"),
+	CLK_NOMUX(K210_CLK_SRAM0, "sram0",  K210_CLK_ACLK),
+	CLK_NOMUX(K210_CLK_SRAM1, "sram1",  K210_CLK_ACLK),
+	CLK_NOMUX(K210_CLK_ROM,   "rom",    K210_CLK_ACLK),
+	CLK_NOMUX(K210_CLK_DVP,   "dvp",    K210_CLK_ACLK),
+	CLK_NOMUX(K210_CLK_APB0,  "apb0",   K210_CLK_ACLK),
+	CLK_NOMUX(K210_CLK_APB1,  "apb1",   K210_CLK_ACLK),
+	CLK_NOMUX(K210_CLK_APB2,  "apb2",   K210_CLK_ACLK),
+	CLK_NOMUX(K210_CLK_AI,    "ai",     K210_CLK_PLL1),
+	CLK_NOMUX(K210_CLK_I2S0,  "i2s0",   K210_CLK_PLL2),
+	CLK_NOMUX(K210_CLK_I2S1,  "i2s1",   K210_CLK_PLL2),
+	CLK_NOMUX(K210_CLK_I2S2,  "i2s2",   K210_CLK_PLL2),
+	CLK_NOMUX(K210_CLK_WDT0,  "wdt0",   K210_CLK_IN0),
+	CLK_NOMUX(K210_CLK_WDT1,  "wdt1",   K210_CLK_IN0),
+	CLK_NOMUX(K210_CLK_SPI0,  "spi0",   K210_CLK_PLL0),
+	CLK_NOMUX(K210_CLK_SPI1,  "spi1",   K210_CLK_PLL0),
+	CLK_NOMUX(K210_CLK_SPI2,  "spi2",   K210_CLK_PLL0),
+	CLK_NOMUX(K210_CLK_I2C0,  "i2c0",   K210_CLK_PLL0),
+	CLK_NOMUX(K210_CLK_I2C1,  "i2c1",   K210_CLK_PLL0),
+	CLK_NOMUX(K210_CLK_I2C2,  "i2c2",   K210_CLK_PLL0),
+	CLK_DIV(K210_CLK_I2S0_M,  "i2s0_m", K210_CLK_PLL2),
+	CLK_DIV(K210_CLK_I2S1_M,  "i2s1_m", K210_CLK_PLL2),
+	CLK_DIV(K210_CLK_I2S2_M,  "i2s2_m", K210_CLK_PLL2),
+	CLK_DIV(K210_CLK_CLINT,   "clint",  K210_CLK_ACLK),
+	CLK_GATE(K210_CLK_CPU,    "cpu",    K210_CLK_ACLK),
+	CLK_GATE(K210_CLK_DMA,    "dma",    K210_CLK_ACLK),
+	CLK_GATE(K210_CLK_FFT,    "fft",    K210_CLK_ACLK),
+	CLK_GATE(K210_CLK_GPIO,   "gpio",   K210_CLK_APB0),
+	CLK_GATE(K210_CLK_UART1,  "uart1",  K210_CLK_APB0),
+	CLK_GATE(K210_CLK_UART2,  "uart2",  K210_CLK_APB0),
+	CLK_GATE(K210_CLK_UART3,  "uart3",  K210_CLK_APB0),
+	CLK_GATE(K210_CLK_FPIOA,  "fpioa",  K210_CLK_APB0),
+	CLK_GATE(K210_CLK_SHA,    "sha",    K210_CLK_APB0),
+	CLK_GATE(K210_CLK_AES,    "aes",    K210_CLK_APB1),
+	CLK_GATE(K210_CLK_OTP,    "otp",    K210_CLK_APB1),
+	CLK_GATE(K210_CLK_RTC,    "rtc",    K210_CLK_IN0),
+#undef NAME
+#undef CLK_PLL
+#undef CLK
+#undef CLK_FULL
+#undef CLK_NOMUX
+#undef CLK_DIV
+#undef CLK_GATE
+#undef CLK_LIST
 };
 
-#undef COMP
-#undef COMP_ID
-#undef COMP_NOMUX
-#undef COMP_NOMUX_ID
-#undef COMP_LIST
-
-static struct clk *k210_bypass_children __section(".data");
-
-/* Helper functions to create sub-clocks */
-static struct clk_mux *k210_create_mux(const struct k210_mux_params *params,
-				       void *base)
+static u32 k210_clk_readl(struct k210_clk_priv *priv, u8 off, u8 shift,
+			  u8 width)
 {
-	struct clk_mux *mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	u32 reg = readl(priv->base + off);
 
-	if (!mux)
-		return mux;
-
-	mux->reg = base + params->off;
-	mux->mask = BIT(params->width) - 1;
-	mux->shift = params->shift;
-	mux->parent_names = params->parent_names;
-	mux->num_parents = params->num_parents;
-
-	return mux;
+	return (reg >> shift) & (BIT(width) - 1);
 }
 
-static struct clk_divider *k210_create_div(const struct k210_div_params *params,
-					   void *base)
+static void k210_clk_writel(struct k210_clk_priv *priv, u8 off, u8 shift,
+			    u8 width, u32 val)
 {
-	struct clk_divider *div = kzalloc(sizeof(*div), GFP_KERNEL);
+	u32 reg = readl(priv->base + off);
+	u32 mask = (BIT(width) - 1) << shift;
 
-	if (!div)
-		return div;
-
-	div->reg = base + params->off;
-	div->shift = params->shift;
-	div->width = params->width;
-	div->flags = params->flags;
-
-	return div;
+	reg &= ~mask;
+	reg |= mask & (val << shift);
+	writel(reg, priv->base + off);
 }
 
-static struct clk_gate *k210_create_gate(const struct k210_gate_params *params,
-					 void *base)
+static int k210_clk_get_parent(struct k210_clk_priv *priv, int id)
 {
-	struct clk_gate *gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	u32 sel;
+	const struct k210_mux_params *mux;
 
-	if (!gate)
-		return gate;
+	if (!(k210_clks[id].flags & K210_CLKF_MUX))
+		return k210_clks[id].parent;
+	mux = &k210_muxes[k210_clks[id].mux];
 
-	gate->reg = base + params->off;
-	gate->bit_idx = params->bit_idx;
-
-	return gate;
+	sel = k210_clk_readl(priv, mux->off, mux->shift, mux->width);
+	assert(sel < mux->num_parents);
+	return mux->parents[sel];
 }
 
-static struct k210_pll *k210_create_pll(const struct k210_pll_params *params,
-					void *base)
+static ulong do_k210_clk_get_rate(struct k210_clk_priv *priv, int id)
 {
-	struct k210_pll *pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	int parent;
+	u32 val;
+	ulong parent_rate;
+	const struct k210_div_params *div;
 
-	if (!pll)
-		return pll;
+	if (id == K210_CLK_IN0)
+		return clk_get_rate(&priv->in0);
 
-	pll->reg = base + params->off;
-	pll->lock = base + params->lock_off;
-	pll->shift = params->shift;
-	pll->width = params->width;
+	parent = k210_clk_get_parent(priv, id);
+	parent_rate = do_k210_clk_get_rate(priv, parent);
 
-	return pll;
+	if (k210_clks[id].flags & K210_CLKF_PLL)
+		return k210_pll_get_rate(priv, k210_clks[id].pll, parent_rate);
+
+	if (k210_clks[id].div == K210_CLK_DIV_NONE)
+		return parent_rate;
+	div = &k210_divs[k210_clks[id].div];
+
+	if (div->type == K210_DIV_FIXED)
+		return parent_rate / div->div;
+
+	val = k210_clk_readl(priv, div->off, div->shift, div->width);
+	switch (div->type) {
+	case K210_DIV_ONE:
+		return parent_rate / (val + 1);
+	case K210_DIV_EVEN:
+		return parent_rate / 2 / (val + 1);
+	case K210_DIV_POWER:
+		/* This is ACLK, which has no divider on IN0 */
+		if (parent == K210_CLK_IN0)
+			return parent_rate;
+		return parent_rate / (2 << val);
+	default:
+		assert(false);
+		return -EINVAL;
+	};
 }
 
-/* Create all sub-clocks, and then register the composite clock */
-static struct clk *k210_register_comp(const struct k210_comp_params *params,
-				      void *base, const char *name,
-				      const char *parent)
+static ulong k210_clk_get_rate(struct clk *clk)
 {
-	const char *const *parent_names;
-	int num_parents;
-	struct clk *comp;
-	const struct clk_ops *mux_ops;
-	struct clk_mux *mux;
-	struct clk_divider *div;
-	struct clk_gate *gate;
+	return do_k210_clk_get_rate(dev_get_priv(clk->dev), clk->id);
+}
 
-	if (params->mux == K210_CLK_MUX_NONE) {
-		if (!parent)
-			return ERR_PTR(-EINVAL);
+static ulong k210_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	return -ENOSYS;
+}
 
-		mux_ops = NULL;
-		mux = NULL;
-		parent_names = &parent;
-		num_parents = 1;
-	} else {
-		mux_ops = &clk_mux_ops;
-		mux = k210_create_mux(&k210_muxes[params->mux], base);
-		if (!mux)
-			return ERR_PTR(-ENOMEM);
+static int do_k210_clk_set_parent(struct k210_clk_priv *priv, int id, int new)
+{
+	int i;
+	const struct k210_mux_params *mux;
 
-		parent_names = mux->parent_names;
-		num_parents = mux->num_parents;
+	if (!(k210_clks[id].flags & K210_CLKF_MUX))
+		return -ENOSYS;
+	mux = &k210_muxes[k210_clks[id].mux];
+
+	for (i = 0; i < mux->num_parents; i++) {
+		if (mux->parents[i] == new) {
+			k210_clk_writel(priv, mux->off, mux->shift, mux->width,
+					i);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int k210_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return do_k210_clk_set_parent(dev_get_priv(clk->dev), clk->id,
+				      parent->id);
+}
+
+static int k210_clk_endisable(struct k210_clk_priv *priv, int id, bool enable)
+{
+	int parent = k210_clk_get_parent(priv, id);
+	const struct k210_gate_params *gate;
+
+	if (id == K210_CLK_IN0) {
+		if (enable)
+			return clk_enable(&priv->in0);
+		else
+			return clk_disable(&priv->in0);
 	}
 
-	div = k210_create_div(&k210_divs[params->div], base);
-	if (!div) {
-		comp = ERR_PTR(-ENOMEM);
-		goto cleanup_mux;
+	/* Only recursively enable clocks since we don't track refcounts */
+	if (enable) {
+		int ret = k210_clk_endisable(priv, parent, true);
+
+		if (ret && ret != -ENOSYS)
+			return ret;
 	}
 
-	gate = k210_create_gate(&k210_gates[params->gate], base);
-	if (!gate) {
-		comp = ERR_PTR(-ENOMEM);
-		goto cleanup_div;
+	if (k210_clks[id].flags & K210_CLKF_PLL) {
+		if (enable)
+			return k210_pll_enable(priv, k210_clks[id].pll);
+		else
+			return k210_pll_disable(priv, k210_clks[id].pll);
 	}
 
-	comp = clk_register_composite(NULL, name, parent_names, num_parents,
-				      &mux->clk, mux_ops,
-				      &div->clk, &clk_divider_ops,
-				      &gate->clk, &clk_gate_ops, 0);
-	if (IS_ERR(comp))
-		goto cleanup_gate;
-	return comp;
+	if (k210_clks[id].gate == K210_CLK_GATE_NONE)
+		return -ENOSYS;
+	gate = &k210_gates[k210_clks[id].gate];
 
-cleanup_gate:
-	free(gate);
-cleanup_div:
-	free(div);
-cleanup_mux:
-	free(mux);
-	return comp;
-}
-
-static bool __section(".data") probed;
-
-/* reset probed so we will probe again post-relocation */
-static int k210_clk_bind(struct udevice *dev)
-{
-	probed = false;
+	k210_clk_writel(priv, gate->off, gate->bit_idx, 1, enable);
 	return 0;
 }
 
+static int k210_clk_enable(struct clk *clk)
+{
+	return k210_clk_endisable(dev_get_priv(clk->dev), clk->id, true);
+}
+
+static int k210_clk_disable(struct clk *clk)
+{
+	return k210_clk_endisable(dev_get_priv(clk->dev), clk->id, false);
+}
+
+static int k210_clk_request(struct clk *clk)
+{
+	if (clk->id >= ARRAY_SIZE(k210_clks))
+		return -EINVAL;
+	return 0;
+}
+
+static const struct clk_ops k210_clk_ops = {
+	.request = k210_clk_request,
+	.set_rate = k210_clk_set_rate,
+	.get_rate = k210_clk_get_rate,
+	.set_parent = k210_clk_set_parent,
+	.enable = k210_clk_enable,
+	.disable = k210_clk_disable,
+};
+
 static int k210_clk_probe(struct udevice *dev)
 {
 	int ret;
-	const char *in0;
-	struct clk *in0_clk, *bypass;
-	struct clk_mux *mux;
-	struct clk_divider *div;
-	struct k210_pll *pll;
-	void *base;
+	struct k210_clk_priv *priv = dev_get_priv(dev);
 
-	/*
-	 * Only one instance of this driver allowed. This prevents weird bugs
-	 * when the driver fails part-way through probing. Some clocks will
-	 * already have been registered, and re-probing will register them
-	 * again, creating a bunch of duplicates. Better error-handling/cleanup
-	 * could fix this, but it's Probably Not Worth It (TM).
-	 */
-	if (probed)
+	priv->base = dev_read_addr_ptr(dev_get_parent(dev));
+	if (!priv->base)
 		return -EINVAL;
 
-	base = dev_read_addr_ptr(dev_get_parent(dev));
-	if (!base)
-		return -EINVAL;
-
-	in0_clk = kzalloc(sizeof(*in0_clk), GFP_KERNEL);
-	if (!in0_clk)
-		return -ENOMEM;
-
-	ret = clk_get_by_index(dev, 0, in0_clk);
+	ret = clk_get_by_index(dev, 0, &priv->in0);
 	if (ret)
 		return ret;
-	in0 = in0_clk->dev->name;
-
-	probed = true;
-
-	aclk_sels[0] = in0;
-	pll2_sels[0] = in0;
-
-	/*
-	 * All PLLs have a broken bypass, but pll0 has the CPU downstream, so we
-	 * need to manually reparent it whenever we configure pll0
-	 */
-	pll = k210_create_pll(&k210_plls[0], base);
-	if (pll) {
-		bypass = k210_register_bypass("pll0", in0, &pll->clk,
-					      &k210_pll_ops, in0_clk);
-		clk_dm(K210_CLK_PLL0, bypass);
-	} else {
-		return -ENOMEM;
-	}
-
-	pll = k210_create_pll(&k210_plls[1], base);
-	if (pll)
-		clk_dm(K210_CLK_PLL1,
-		       k210_register_pll_struct("pll1", in0, pll));
-
-	/* PLL2 is muxed, so set up a composite clock */
-	mux = k210_create_mux(&k210_muxes[MUXIFY(K210_CLK_PLL2)], base);
-	pll = k210_create_pll(&k210_plls[2], base);
-	if (!mux || !pll) {
-		free(mux);
-		free(pll);
-	} else {
-		clk_dm(K210_CLK_PLL2,
-		       clk_register_composite(NULL, "pll2", pll2_sels,
-					      ARRAY_SIZE(pll2_sels),
-					      &mux->clk, &clk_mux_ops,
-					      &pll->clk, &k210_pll_ops,
-					      &pll->clk, &k210_pll_ops, 0));
-	}
-
-	/* Half-frequency clocks for "even" dividers */
-	clk_dm(K210_CLK_IN0_H,  k210_clk_half("in0_half", in0));
-	clk_dm(K210_CLK_PLL0_H, k210_clk_half("pll0_half", "pll0"));
-	clk_dm(K210_CLK_PLL2_H, k210_clk_half("pll2_half", "pll2"));
-
-	/* ACLK has no gate */
-	mux = k210_create_mux(&k210_muxes[MUXIFY(K210_CLK_ACLK)], base);
-	div = k210_create_div(&k210_divs[DIVIFY(K210_CLK_ACLK)], base);
-	if (!mux || !div) {
-		free(mux);
-		free(div);
-	} else {
-		struct clk *aclk =
-			clk_register_composite(NULL, "aclk", aclk_sels,
-					       ARRAY_SIZE(aclk_sels),
-					       &mux->clk, &clk_mux_ops,
-					       &div->clk, &clk_divider_ops,
-					       NULL, NULL, 0);
-		clk_dm(K210_CLK_ACLK, aclk);
-		if (!IS_ERR(aclk)) {
-			k210_bypass_children = aclk;
-			k210_bypass_set_children(bypass,
-						 &k210_bypass_children, 1);
-		}
-	}
-
-#define REGISTER_COMP(id, name) \
-	clk_dm(id, \
-	       k210_register_comp(&k210_comps[COMPIFY(id)], base, name, NULL))
-	REGISTER_COMP(K210_CLK_SPI3,   "spi3");
-	REGISTER_COMP(K210_CLK_TIMER0, "timer0");
-	REGISTER_COMP(K210_CLK_TIMER1, "timer1");
-	REGISTER_COMP(K210_CLK_TIMER2, "timer2");
-#undef REGISTER_COMP
-
-	/* Dividing clocks, no mux */
-#define REGISTER_COMP_NOMUX(id, name, parent) \
-	clk_dm(id, \
-	       k210_register_comp(&k210_comps[COMPIFY(id)], base, name, parent))
-	REGISTER_COMP_NOMUX(K210_CLK_SRAM0, "sram0", "aclk");
-	REGISTER_COMP_NOMUX(K210_CLK_SRAM1, "sram1", "aclk");
-	REGISTER_COMP_NOMUX(K210_CLK_ROM,   "rom",   "aclk");
-	REGISTER_COMP_NOMUX(K210_CLK_DVP,   "dvp",   "aclk");
-	REGISTER_COMP_NOMUX(K210_CLK_APB0,  "apb0",  "aclk");
-	REGISTER_COMP_NOMUX(K210_CLK_APB1,  "apb1",  "aclk");
-	REGISTER_COMP_NOMUX(K210_CLK_APB2,  "apb2",  "aclk");
-	REGISTER_COMP_NOMUX(K210_CLK_AI,    "ai",    "pll1");
-	REGISTER_COMP_NOMUX(K210_CLK_I2S0,  "i2s0",  "pll2_half");
-	REGISTER_COMP_NOMUX(K210_CLK_I2S1,  "i2s1",  "pll2_half");
-	REGISTER_COMP_NOMUX(K210_CLK_I2S2,  "i2s2",  "pll2_half");
-	REGISTER_COMP_NOMUX(K210_CLK_WDT0,  "wdt0",  "in0_half");
-	REGISTER_COMP_NOMUX(K210_CLK_WDT1,  "wdt1",  "in0_half");
-	REGISTER_COMP_NOMUX(K210_CLK_SPI0,  "spi0",  "pll0_half");
-	REGISTER_COMP_NOMUX(K210_CLK_SPI1,  "spi1",  "pll0_half");
-	REGISTER_COMP_NOMUX(K210_CLK_SPI2,  "spi2",  "pll0_half");
-	REGISTER_COMP_NOMUX(K210_CLK_I2C0,  "i2c0",  "pll0_half");
-	REGISTER_COMP_NOMUX(K210_CLK_I2C1,  "i2c1",  "pll0_half");
-	REGISTER_COMP_NOMUX(K210_CLK_I2C2,  "i2c2",  "pll0_half");
-#undef REGISTER_COMP_NOMUX
-
-	/* Dividing clocks */
-#define REGISTER_DIV(id, name, parent) do {\
-	const struct k210_div_params *params = &k210_divs[DIVIFY(id)]; \
-	clk_dm(id, \
-	       clk_register_divider(NULL, name, parent, 0, base + params->off, \
-				    params->shift, params->width, 0)); \
-} while (false)
-	REGISTER_DIV(K210_CLK_I2S0_M, "i2s0_m", "pll2_half");
-	REGISTER_DIV(K210_CLK_I2S1_M, "i2s1_m", "pll2_half");
-	REGISTER_DIV(K210_CLK_I2S2_M, "i2s2_m", "pll2_half");
-#undef REGISTER_DIV
-
-	/* Gated clocks */
-#define REGISTER_GATE(id, name, parent) do { \
-	const struct k210_gate_params *params = &k210_gates[GATEIFY(id)]; \
-	clk_dm(id, \
-	       clk_register_gate(NULL, name, parent, 0, base + params->off, \
-				 params->bit_idx, 0, NULL)); \
-} while (false)
-	REGISTER_GATE(K210_CLK_CPU,   "cpu",   "aclk");
-	REGISTER_GATE(K210_CLK_DMA,   "dma",   "aclk");
-	REGISTER_GATE(K210_CLK_FFT,   "fft",   "aclk");
-	REGISTER_GATE(K210_CLK_GPIO,  "gpio",  "apb0");
-	REGISTER_GATE(K210_CLK_UART1, "uart1", "apb0");
-	REGISTER_GATE(K210_CLK_UART2, "uart2", "apb0");
-	REGISTER_GATE(K210_CLK_UART3, "uart3", "apb0");
-	REGISTER_GATE(K210_CLK_FPIOA, "fpioa", "apb0");
-	REGISTER_GATE(K210_CLK_SHA,   "sha",   "apb0");
-	REGISTER_GATE(K210_CLK_AES,   "aes",   "apb1");
-	REGISTER_GATE(K210_CLK_OTP,   "otp",   "apb1");
-	REGISTER_GATE(K210_CLK_RTC,   "rtc",   in0);
-#undef REGISTER_GATE
-
-	/* The MTIME register in CLINT runs at one 50th the CPU clock speed */
-	clk_dm(K210_CLK_CLINT,
-	       clk_register_fixed_factor(NULL, "clint", "aclk", 0, 1, 50));
 
 	return 0;
 }
@@ -663,6 +577,6 @@ U_BOOT_DRIVER(k210_clk) = {
 	.id = UCLASS_CLK,
 	.of_match = k210_clk_ids,
 	.ops = &k210_clk_ops,
-	.bind = k210_clk_bind,
 	.probe = k210_clk_probe,
+	.priv_auto = sizeof(struct k210_clk_priv),
 };
diff --git a/drivers/clk/kendryte/pll.c b/drivers/clk/kendryte/pll.c
index 184f37aaf2..1f0275c83f 100644
--- a/drivers/clk/kendryte/pll.c
+++ b/drivers/clk/kendryte/pll.c
@@ -12,17 +12,41 @@
 #include <serial.h>
 #include <asm/io.h>
 #include <dt-bindings/clock/k210-sysctl.h>
+#include <dt-bindings/mfd/k210-sysctl.h>
 #include <kendryte/pll.h>
 #include <linux/bitfield.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 
-#define CLK_K210_PLL "k210_clk_pll"
+/**
+ * struct k210_pll_params - K210 PLL parameters
+ * @off: The offset of the PLL from the base sysctl address
+ * @shift: The offset of the LSB of the lock status
+ * @width: The number of bits in the lock status
+ */
+struct k210_pll_params {
+	u8 off;
+	u8 shift;
+	u8 width;
+};
+
+static const struct k210_pll_params k210_plls[] = {
+#define PLL(_off, _shift, _width) { \
+	.off = (_off), \
+	.shift = (_shift), \
+	.width = (_width), \
+}
+	[0] = PLL(K210_SYSCTL_PLL0,  0, 2),
+	[1] = PLL(K210_SYSCTL_PLL1,  8, 1),
+	[2] = PLL(K210_SYSCTL_PLL2, 16, 1),
+#undef PLL
+};
 
 #ifdef CONFIG_CLK_K210_SET_RATE
-static int k210_pll_enable(struct clk *clk);
-static int k210_pll_disable(struct clk *clk);
+int k210_pll_enable(struct k210_clk_priv *priv, int id);
+int k210_pll_disable(struct k210_clk_priv *priv, int id);
+ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, ulong rate_in);
 
 /*
  * The PLL included with the Kendryte K210 appears to be a True Circuits, Inc.
@@ -423,12 +447,12 @@ TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in,
 	return 0;
 }
 
-static ulong k210_pll_set_rate(struct clk *clk, ulong rate)
+static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
+			       ulong rate_in)
 {
 	int err;
-	long long rate_in = clk_get_parent_rate(clk);
+	const struct k210_pll_params *pll = &k210_plls[id];
 	struct k210_pll_config config = {};
-	struct k210_pll *pll = to_k210_pll(clk);
 	u32 reg;
 
 	if (rate_in < 0)
@@ -447,7 +471,7 @@ static ulong k210_pll_set_rate(struct clk *clk, ulong rate)
 	 */
 	k210_pll_disable(clk);
 
-	reg = readl(pll->reg);
+	reg = readl(priv->base + pll->off);
 	reg &= ~K210_PLL_CLKR
 	    &  ~K210_PLL_CLKF
 	    &  ~K210_PLL_CLKOD
@@ -456,7 +480,7 @@ static ulong k210_pll_set_rate(struct clk *clk, ulong rate)
 	    |  FIELD_PREP(K210_PLL_CLKF, config.f - 1)
 	    |  FIELD_PREP(K210_PLL_CLKOD, config.od - 1)
 	    |  FIELD_PREP(K210_PLL_BWADJ, config.f - 1);
-	writel(reg, pll->reg);
+	writel(reg, priv->base + pll->off);
 
 	err = k210_pll_enable(clk);
 	if (err)
@@ -465,14 +489,18 @@ static ulong k210_pll_set_rate(struct clk *clk, ulong rate)
 	serial_setbrg();
 	return clk_get_rate(clk);
 }
+#else
+ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
+			ulong rate_in)
+{
+	return -ENOSYS;
+}
 #endif /* CONFIG_CLK_K210_SET_RATE */
 
-static ulong k210_pll_get_rate(struct clk *clk)
+ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, ulong rate_in)
 {
-	long long rate_in = clk_get_parent_rate(clk);
-	struct k210_pll *pll = to_k210_pll(clk);
 	u64 r, f, od;
-	u32 reg = readl(pll->reg);
+	u32 reg = readl(priv->base + k210_plls[id].off);
 
 	if (rate_in < 0 || (reg & K210_PLL_BYPASS))
 		return rate_in;
@@ -491,57 +519,58 @@ static ulong k210_pll_get_rate(struct clk *clk)
  * Wait for the PLL to be locked. If the PLL is not locked, try clearing the
  * slip before retrying
  */
-static void k210_pll_waitfor_lock(struct k210_pll *pll)
+void k210_pll_waitfor_lock(struct k210_clk_priv *priv, int id)
 {
+	const struct k210_pll_params *pll = &k210_plls[id];
 	u32 mask = GENMASK(pll->width - 1, 0) << pll->shift;
 
 	while (true) {
-		u32 reg = readl(pll->lock);
+		u32 reg = readl(priv->base + K210_SYSCTL_PLL_LOCK);
 
 		if ((reg & mask) == mask)
 			break;
 
 		reg |= BIT(pll->shift + K210_PLL_CLEAR_SLIP);
-		writel(reg, pll->lock);
+		writel(reg, priv->base + K210_SYSCTL_PLL_LOCK);
 	}
 }
 
 /* Adapted from sysctl_pll_enable */
-static int k210_pll_enable(struct clk *clk)
+int k210_pll_enable(struct k210_clk_priv *priv, int id)
 {
-	struct k210_pll *pll = to_k210_pll(clk);
-	u32 reg = readl(pll->reg);
+	const struct k210_pll_params *pll = &k210_plls[id];
+	u32 reg = readl(priv->base + pll->off);
 
 	if ((reg & K210_PLL_PWRD) && (reg & K210_PLL_EN) &&
 	    !(reg & K210_PLL_RESET))
 		return 0;
 
 	reg |= K210_PLL_PWRD;
-	writel(reg, pll->reg);
+	writel(reg, priv->base + pll->off);
 
 	/* Ensure reset is low before asserting it */
 	reg &= ~K210_PLL_RESET;
-	writel(reg, pll->reg);
+	writel(reg, priv->base + pll->off);
 	reg |= K210_PLL_RESET;
-	writel(reg, pll->reg);
+	writel(reg, priv->base + pll->off);
 	nop();
 	nop();
 	reg &= ~K210_PLL_RESET;
-	writel(reg, pll->reg);
+	writel(reg, priv->base + pll->off);
 
-	k210_pll_waitfor_lock(pll);
+	k210_pll_waitfor_lock(priv, id);
 
 	reg &= ~K210_PLL_BYPASS;
 	reg |= K210_PLL_EN;
-	writel(reg, pll->reg);
+	writel(reg, priv->base + pll->off);
 
 	return 0;
 }
 
-static int k210_pll_disable(struct clk *clk)
+int k210_pll_disable(struct k210_clk_priv *priv, int id)
 {
-	struct k210_pll *pll = to_k210_pll(clk);
-	u32 reg = readl(pll->reg);
+	const struct k210_pll_params *pll = &k210_plls[id];
+	u32 reg = readl(priv->base + pll->off);
 
 	/*
 	 * Bypassing before powering off is important so child clocks don't stop
@@ -549,37 +578,10 @@ static int k210_pll_disable(struct clk *clk)
 	 * of the cpu clock.
 	 */
 	reg |= K210_PLL_BYPASS;
-	writel(reg, pll->reg);
+	writel(reg, priv->base + pll->off);
 
 	reg &= ~K210_PLL_PWRD;
 	reg &= ~K210_PLL_EN;
-	writel(reg, pll->reg);
+	writel(reg, priv->base + pll->off);
 	return 0;
 }
-
-const struct clk_ops k210_pll_ops = {
-	.get_rate = k210_pll_get_rate,
-#ifdef CONFIG_CLK_K210_SET_RATE
-	.set_rate = k210_pll_set_rate,
-#endif
-	.enable = k210_pll_enable,
-	.disable = k210_pll_disable,
-};
-
-struct clk *k210_register_pll_struct(const char *name, const char *parent_name,
-				     struct k210_pll *pll)
-{
-	int ret;
-	struct clk *clk = &pll->clk;
-
-	ret = clk_register(clk, CLK_K210_PLL, name, parent_name);
-	if (ret)
-		return ERR_PTR(ret);
-	return clk;
-}
-
-U_BOOT_DRIVER(k210_pll) = {
-	.name	= CLK_K210_PLL,
-	.id	= UCLASS_CLK,
-	.ops	= &k210_pll_ops,
-};
diff --git a/include/dt-bindings/clock/k210-sysctl.h b/include/dt-bindings/clock/k210-sysctl.h
index fe852bbd92..6b0d5b46f8 100644
--- a/include/dt-bindings/clock/k210-sysctl.h
+++ b/include/dt-bindings/clock/k210-sysctl.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
- * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2019-21 Sean Anderson <seanga2@gmail.com>
  */
 
 #ifndef CLOCK_K210_SYSCTL_H
@@ -9,52 +9,50 @@
 /*
  * Arbitrary identifiers for clocks.
  */
-#define K210_CLK_NONE   0
-#define K210_CLK_IN0_H  1
-#define K210_CLK_PLL0_H 2
-#define K210_CLK_PLL0   3
-#define K210_CLK_PLL1   4
-#define K210_CLK_PLL2   5
-#define K210_CLK_PLL2_H 6
-#define K210_CLK_CPU    7
-#define K210_CLK_SRAM0  8
-#define K210_CLK_SRAM1  9
-#define K210_CLK_APB0   10
-#define K210_CLK_APB1   11
-#define K210_CLK_APB2   12
-#define K210_CLK_ROM    13
-#define K210_CLK_DMA    14
-#define K210_CLK_AI     15
-#define K210_CLK_DVP    16
-#define K210_CLK_FFT    17
-#define K210_CLK_GPIO   18
-#define K210_CLK_SPI0   19
-#define K210_CLK_SPI1   20
-#define K210_CLK_SPI2   21
-#define K210_CLK_SPI3   22
-#define K210_CLK_I2S0   23
-#define K210_CLK_I2S1   24
-#define K210_CLK_I2S2   25
-#define K210_CLK_I2S0_M 26
-#define K210_CLK_I2S1_M 27
-#define K210_CLK_I2S2_M 28
-#define K210_CLK_I2C0   29
-#define K210_CLK_I2C1   30
-#define K210_CLK_I2C2   31
-#define K210_CLK_UART1  32
-#define K210_CLK_UART2  33
-#define K210_CLK_UART3  34
-#define K210_CLK_AES    35
-#define K210_CLK_FPIOA  36
-#define K210_CLK_TIMER0 37
-#define K210_CLK_TIMER1 38
-#define K210_CLK_TIMER2 39
-#define K210_CLK_WDT0   40
-#define K210_CLK_WDT1   41
-#define K210_CLK_SHA    42
-#define K210_CLK_OTP    43
-#define K210_CLK_RTC    44
-#define K210_CLK_ACLK   45
-#define K210_CLK_CLINT  46
+
+#define K210_CLK_PLL0   0
+#define K210_CLK_PLL1   1
+#define K210_CLK_PLL2   2
+#define K210_CLK_CPU    3
+#define K210_CLK_SRAM0  4
+#define K210_CLK_SRAM1  5
+#define K210_CLK_ACLK   6
+#define K210_CLK_CLINT  7
+#define K210_CLK_APB0   8
+#define K210_CLK_APB1   9
+#define K210_CLK_APB2   10
+#define K210_CLK_ROM    11
+#define K210_CLK_DMA    12
+#define K210_CLK_AI     13
+#define K210_CLK_DVP    14
+#define K210_CLK_FFT    15
+#define K210_CLK_GPIO   16
+#define K210_CLK_SPI0   17
+#define K210_CLK_SPI1   18
+#define K210_CLK_SPI2   19
+#define K210_CLK_SPI3   20
+#define K210_CLK_I2S0   21
+#define K210_CLK_I2S1   22
+#define K210_CLK_I2S2   23
+#define K210_CLK_I2S0_M 24
+#define K210_CLK_I2S1_M 25
+#define K210_CLK_I2S2_M 26
+#define K210_CLK_I2C0   27
+#define K210_CLK_I2C1   28
+#define K210_CLK_I2C2   29
+#define K210_CLK_UART1  30
+#define K210_CLK_UART2  31
+#define K210_CLK_UART3  32
+#define K210_CLK_AES    33
+#define K210_CLK_FPIOA  34
+#define K210_CLK_TIMER0 35
+#define K210_CLK_TIMER1 36
+#define K210_CLK_TIMER2 37
+#define K210_CLK_WDT0   38
+#define K210_CLK_WDT1   39
+#define K210_CLK_SHA    40
+#define K210_CLK_OTP    41
+#define K210_CLK_RTC    42
+#define K210_CLK_IN0	43
 
 #endif /* CLOCK_K210_SYSCTL_H */
diff --git a/include/kendryte/pll.h b/include/kendryte/pll.h
index 95b8494f40..16fd5a5b68 100644
--- a/include/kendryte/pll.h
+++ b/include/kendryte/pll.h
@@ -25,16 +25,6 @@
 #define K210_PLL_CLEAR_SLIP 2
 #define K210_PLL_TEST_OUT 3
 
-struct k210_pll {
-	struct clk clk;
-	void __iomem *reg; /* Base PLL register */
-	void __iomem *lock; /* Common PLL lock register */
-	u8 shift; /* Offset of bits in lock register */
-	u8 width; /* Width of lock bits to test against */
-};
-
-#define to_k210_pll(_clk) container_of(_clk, struct k210_pll, clk)
-
 struct k210_pll_config {
 	u8 r;
 	u8 f;
@@ -51,8 +41,18 @@ TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in,
 
 #endif
 
-extern const struct clk_ops k210_pll_ops;
+/**
+ * struct k210_clk_priv - K210 clock driver private data
+ * @base: The base address of the sysctl device
+ * @in0: The "in0" external oscillator
+ */
+struct k210_clk_priv {
+	void __iomem *base;
+	struct clk in0;
+};
 
-struct clk *k210_register_pll_struct(const char *name, const char *parent_name,
-				     struct k210_pll *pll);
+ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate, ulong rate_in);
+ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, ulong rate_in);
+int k210_pll_enable(struct k210_clk_priv *priv, int id);
+int k210_pll_disable(struct k210_clk_priv *priv, int id);
 #endif /* K210_PLL_H */
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 03/11] clk: k210: Move pll into the rest of the driver
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
  2021-06-11  4:16 ` [PATCH v3 01/11] clk: Allow force setting clock defaults before relocation Sean Anderson
  2021-06-11  4:16 ` [PATCH v3 02/11] clk: k210: Rewrite to remove CCF Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-16  1:55   ` Leo Liang
  2021-06-11  4:16 ` [PATCH v3 04/11] clk: k210: Implement soc_clk_dump Sean Anderson
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot; +Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson

Now that there no separate PLL driver, we can no longer make the PLL
functions static. By moving the PLL driver in with the rest of the clock
code, we can make these functions static again. We still keep the pll
header for unit testing, but it is pretty reduced.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
---

(no changes since v1)

 drivers/clk/kendryte/Makefile |   2 +-
 drivers/clk/kendryte/clk.c    | 606 +++++++++++++++++++++++++++++++++-
 drivers/clk/kendryte/pll.c    | 587 --------------------------------
 include/kendryte/clk.h        |  35 --
 include/kendryte/pll.h        |  34 --
 5 files changed, 601 insertions(+), 663 deletions(-)
 delete mode 100644 drivers/clk/kendryte/pll.c
 delete mode 100644 include/kendryte/clk.h

diff --git a/drivers/clk/kendryte/Makefile b/drivers/clk/kendryte/Makefile
index 6fb68253ae..6710a1db72 100644
--- a/drivers/clk/kendryte/Makefile
+++ b/drivers/clk/kendryte/Makefile
@@ -1 +1 @@
-obj-y += bypass.o clk.o pll.o
+obj-y += bypass.o clk.o
diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/kendryte/clk.c
index 34e8e742a6..de9db84361 100644
--- a/drivers/clk/kendryte/clk.c
+++ b/drivers/clk/kendryte/clk.c
@@ -2,17 +2,30 @@
 /*
  * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
  */
-#include <kendryte/clk.h>
+#define LOG_CATEGORY UCLASS_CLK
 
 #include <common.h>
-#include <dt-bindings/clock/k210-sysctl.h>
-#include <dt-bindings/mfd/k210-sysctl.h>
+#include <clk.h>
+#include <clk-uclass.h>
+#include <div64.h>
 #include <dm.h>
 #include <log.h>
 #include <mapmem.h>
-
-#include <kendryte/bypass.h>
+#include <serial.h>
+#include <dt-bindings/clock/k210-sysctl.h>
+#include <dt-bindings/mfd/k210-sysctl.h>
 #include <kendryte/pll.h>
+#include <linux/bitfield.h>
+
+/**
+ * struct k210_clk_priv - K210 clock driver private data
+ * @base: The base address of the sysctl device
+ * @in0: The "in0" external oscillator
+ */
+struct k210_clk_priv {
+	void __iomem *base;
+	struct clk in0;
+};
 
 /*
  * All parameters for different sub-clocks are collected into parameter arrays.
@@ -248,6 +261,30 @@ static const struct k210_mux_params k210_muxes[] = {
 #undef MUX
 #undef MUX_LIST
 
+/**
+ * struct k210_pll_params - K210 PLL parameters
+ * @off: The offset of the PLL from the base sysctl address
+ * @shift: The offset of the LSB of the lock status
+ * @width: The number of bits in the lock status
+ */
+struct k210_pll_params {
+	u8 off;
+	u8 shift;
+	u8 width;
+};
+
+static const struct k210_pll_params k210_plls[] = {
+#define PLL(_off, _shift, _width) { \
+	.off = (_off), \
+	.shift = (_shift), \
+	.width = (_width), \
+}
+	[0] = PLL(K210_SYSCTL_PLL0,  0, 2),
+	[1] = PLL(K210_SYSCTL_PLL1,  8, 1),
+	[2] = PLL(K210_SYSCTL_PLL2, 16, 1),
+#undef PLL
+};
+
 /**
  * enum k210_clk_flags - The type of a K210 clock
  * @K210_CLKF_MUX: This clock has a mux and not a static parent
@@ -286,7 +323,6 @@ struct k210_clk_params {
 	};
 };
 
-
 static const struct k210_clk_params k210_clks[] = {
 #if CONFIG_IS_ENABLED(CMD_CLK)
 #define NAME(_name) .name = (_name),
@@ -382,6 +418,564 @@ static const struct k210_clk_params k210_clks[] = {
 #undef CLK_LIST
 };
 
+#define K210_PLL_CLKR		GENMASK(3, 0)
+#define K210_PLL_CLKF		GENMASK(9, 4)
+#define K210_PLL_CLKOD		GENMASK(13, 10) /* Output Divider */
+#define K210_PLL_BWADJ		GENMASK(19, 14) /* BandWidth Adjust */
+#define K210_PLL_RESET		BIT(20)
+#define K210_PLL_PWRD		BIT(21) /* PoWeReD */
+#define K210_PLL_INTFB		BIT(22) /* Internal FeedBack */
+#define K210_PLL_BYPASS		BIT(23)
+#define K210_PLL_TEST		BIT(24)
+#define K210_PLL_EN		BIT(25)
+#define K210_PLL_TEST_EN	BIT(26)
+
+#define K210_PLL_LOCK		0
+#define K210_PLL_CLEAR_SLIP	2
+#define K210_PLL_TEST_OUT	3
+
+#ifdef CONFIG_CLK_K210_SET_RATE
+static int k210_pll_enable(struct k210_clk_priv *priv, int id);
+static int k210_pll_disable(struct k210_clk_priv *priv, int id);
+static ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, ulong rate_in);
+
+/*
+ * The PLL included with the Kendryte K210 appears to be a True Circuits, Inc.
+ * General-Purpose PLL. The logical layout of the PLL with internal feedback is
+ * approximately the following:
+ *
+ *  +---------------+
+ *  |reference clock|
+ *  +---------------+
+ *          |
+ *          v
+ *        +--+
+ *        |/r|
+ *        +--+
+ *          |
+ *          v
+ *   +-------------+
+ *   |divided clock|
+ *   +-------------+
+ *          |
+ *          v
+ *  +--------------+
+ *  |phase detector|<---+
+ *  +--------------+    |
+ *          |           |
+ *          v   +--------------+
+ *        +---+ |feedback clock|
+ *        |VCO| +--------------+
+ *        +---+         ^
+ *          |    +--+   |
+ *          +--->|/f|---+
+ *          |    +--+
+ *          v
+ *        +---+
+ *        |/od|
+ *        +---+
+ *          |
+ *          v
+ *       +------+
+ *       |output|
+ *       +------+
+ *
+ * The k210 PLLs have three factors: r, f, and od. Because of the feedback mode,
+ * the effect of the division by f is to multiply the input frequency. The
+ * equation for the output rate is
+ *   rate = (rate_in * f) / (r * od).
+ * Moving knowns to one side of the equation, we get
+ *   rate / rate_in = f / (r * od)
+ * Rearranging slightly,
+ *   abs_error = abs((rate / rate_in) - (f / (r * od))).
+ * To get relative, error, we divide by the expected ratio
+ *   error = abs((rate / rate_in) - (f / (r * od))) / (rate / rate_in).
+ * Simplifying,
+ *   error = abs(1 - f / (r * od)) / (rate / rate_in)
+ *   error = abs(1 - (f * rate_in) / (r * od * rate))
+ * Using the constants ratio = rate / rate_in and inv_ratio = rate_in / rate,
+ *   error = abs((f * inv_ratio) / (r * od) - 1)
+ * This is the error used in evaluating parameters.
+ *
+ * r and od are four bits each, while f is six bits. Because r and od are
+ * multiplied together, instead of the full 256 values possible if both bits
+ * were used fully, there are only 97 distinct products. Combined with f, there
+ * are 6208 theoretical settings for the PLL. However, most of these settings
+ * can be ruled out immediately because they do not have the correct ratio.
+ *
+ * In addition to the constraint of approximating the desired ratio, parameters
+ * must also keep internal pll frequencies within acceptable ranges. The divided
+ * clock's minimum and maximum frequencies have a ratio of around 128.  This
+ * leaves fairly substantial room to work with, especially since the only
+ * affected parameter is r. The VCO's minimum and maximum frequency have a ratio
+ * of 5, which is considerably more restrictive.
+ *
+ * The r and od factors are stored in a table. This is to make it easy to find
+ * the next-largest product. Some products have multiple factorizations, but
+ * only when one factor has at least a 2.5x ratio to the factors of the other
+ * factorization. This is because any smaller ratio would not make a difference
+ * when ensuring the VCO's frequency is within spec.
+ *
+ * Throughout the calculation function, fixed point arithmetic is used. Because
+ * the range of rate and rate_in may be up to 1.75 GHz, or around 2^30, 64-bit
+ * 32.32 fixed-point numbers are used to represent ratios. In general, to
+ * implement division, the numerator is first multiplied by 2^32. This gives a
+ * result where the whole number part is in the upper 32 bits, and the fraction
+ * is in the lower 32 bits.
+ *
+ * In general, rounding is done to the closest integer. This helps find the best
+ * approximation for the ratio. Rounding in one direction (e.g down) could cause
+ * the function to miss a better ratio with one of the parameters increased by
+ * one.
+ */
+
+/*
+ * The factors table was generated with the following python code:
+ *
+ * def p(x, y):
+ *    return (1.0*x/y > 2.5) or (1.0*y/x > 2.5)
+ *
+ * factors = {}
+ * for i in range(1, 17):
+ *    for j in range(1, 17):
+ *       fs = factors.get(i*j) or []
+ *       if fs == [] or all([
+ *             (p(i, x) and p(i, y)) or (p(j, x) and p(j, y))
+ *             for (x, y) in fs]):
+ *          fs.append((i, j))
+ *          factors[i*j] = fs
+ *
+ * for k, l in sorted(factors.items()):
+ *    for v in l:
+ *       print("PACK(%s, %s)," % v)
+ */
+#define PACK(r, od) (((((r) - 1) & 0xF) << 4) | (((od) - 1) & 0xF))
+#define UNPACK_R(val) ((((val) >> 4) & 0xF) + 1)
+#define UNPACK_OD(val) (((val) & 0xF) + 1)
+static const u8 factors[] = {
+	PACK(1, 1),
+	PACK(1, 2),
+	PACK(1, 3),
+	PACK(1, 4),
+	PACK(1, 5),
+	PACK(1, 6),
+	PACK(1, 7),
+	PACK(1, 8),
+	PACK(1, 9),
+	PACK(3, 3),
+	PACK(1, 10),
+	PACK(1, 11),
+	PACK(1, 12),
+	PACK(3, 4),
+	PACK(1, 13),
+	PACK(1, 14),
+	PACK(1, 15),
+	PACK(3, 5),
+	PACK(1, 16),
+	PACK(4, 4),
+	PACK(2, 9),
+	PACK(2, 10),
+	PACK(3, 7),
+	PACK(2, 11),
+	PACK(2, 12),
+	PACK(5, 5),
+	PACK(2, 13),
+	PACK(3, 9),
+	PACK(2, 14),
+	PACK(2, 15),
+	PACK(2, 16),
+	PACK(3, 11),
+	PACK(5, 7),
+	PACK(3, 12),
+	PACK(3, 13),
+	PACK(4, 10),
+	PACK(3, 14),
+	PACK(4, 11),
+	PACK(3, 15),
+	PACK(3, 16),
+	PACK(7, 7),
+	PACK(5, 10),
+	PACK(4, 13),
+	PACK(6, 9),
+	PACK(5, 11),
+	PACK(4, 14),
+	PACK(4, 15),
+	PACK(7, 9),
+	PACK(4, 16),
+	PACK(5, 13),
+	PACK(6, 11),
+	PACK(5, 14),
+	PACK(6, 12),
+	PACK(5, 15),
+	PACK(7, 11),
+	PACK(6, 13),
+	PACK(5, 16),
+	PACK(9, 9),
+	PACK(6, 14),
+	PACK(8, 11),
+	PACK(6, 15),
+	PACK(7, 13),
+	PACK(6, 16),
+	PACK(7, 14),
+	PACK(9, 11),
+	PACK(10, 10),
+	PACK(8, 13),
+	PACK(7, 15),
+	PACK(9, 12),
+	PACK(10, 11),
+	PACK(7, 16),
+	PACK(9, 13),
+	PACK(8, 15),
+	PACK(11, 11),
+	PACK(9, 14),
+	PACK(8, 16),
+	PACK(10, 13),
+	PACK(11, 12),
+	PACK(9, 15),
+	PACK(10, 14),
+	PACK(11, 13),
+	PACK(9, 16),
+	PACK(10, 15),
+	PACK(11, 14),
+	PACK(12, 13),
+	PACK(10, 16),
+	PACK(11, 15),
+	PACK(12, 14),
+	PACK(13, 13),
+	PACK(11, 16),
+	PACK(12, 15),
+	PACK(13, 14),
+	PACK(12, 16),
+	PACK(13, 15),
+	PACK(14, 14),
+	PACK(13, 16),
+	PACK(14, 15),
+	PACK(14, 16),
+	PACK(15, 15),
+	PACK(15, 16),
+	PACK(16, 16),
+};
+
+TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in,
+				     struct k210_pll_config *best)
+{
+	int i;
+	s64 error, best_error;
+	u64 ratio, inv_ratio; /* fixed point 32.32 ratio of the rates */
+	u64 max_r;
+	u64 r, f, od;
+
+	/*
+	 * Can't go over 1.75 GHz or under 21.25 MHz due to limitations on the
+	 * VCO frequency. These are not the same limits as below because od can
+	 * reduce the output frequency by 16.
+	 */
+	if (rate > 1750000000 || rate < 21250000)
+		return -EINVAL;
+
+	/* Similar restrictions on the input rate */
+	if (rate_in > 1750000000 || rate_in < 13300000)
+		return -EINVAL;
+
+	ratio = DIV_ROUND_CLOSEST_ULL((u64)rate << 32, rate_in);
+	inv_ratio = DIV_ROUND_CLOSEST_ULL((u64)rate_in << 32, rate);
+	/* Can't increase by more than 64 or reduce by more than 256 */
+	if (rate > rate_in && ratio > (64ULL << 32))
+		return -EINVAL;
+	else if (rate <= rate_in && inv_ratio > (256ULL << 32))
+		return -EINVAL;
+
+	/*
+	 * The divided clock (rate_in / r) must stay between 1.75 GHz and 13.3
+	 * MHz. There is no minimum, since the only way to get a higher input
+	 * clock than 26 MHz is to use a clock generated by a PLL. Because PLLs
+	 * cannot output frequencies greater than 1.75 GHz, the minimum would
+	 * never be greater than one.
+	 */
+	max_r = DIV_ROUND_DOWN_ULL(rate_in, 13300000);
+
+	/* Variables get immediately incremented, so start at -1th iteration */
+	i = -1;
+	f = 0;
+	r = 0;
+	od = 0;
+	best_error = S64_MAX;
+	error = best_error;
+	/* do-while here so we always try at least one ratio */
+	do {
+		/*
+		 * Whether we swapped r and od while enforcing frequency limits
+		 */
+		bool swapped = false;
+		u64 last_od = od;
+		u64 last_r = r;
+
+		/*
+		 * Try the next largest value for f (or r and od) and
+		 * recalculate the other parameters based on that
+		 */
+		if (rate > rate_in) {
+			/*
+			 * Skip factors of the same product if we already tried
+			 * out that product
+			 */
+			do {
+				i++;
+				r = UNPACK_R(factors[i]);
+				od = UNPACK_OD(factors[i]);
+			} while (i + 1 < ARRAY_SIZE(factors) &&
+				 r * od == last_r * last_od);
+
+			/* Round close */
+			f = (r * od * ratio + BIT(31)) >> 32;
+			if (f > 64)
+				f = 64;
+		} else {
+			u64 tmp = ++f * inv_ratio;
+			bool round_up = !!(tmp & BIT(31));
+			u32 goal = (tmp >> 32) + round_up;
+			u32 err, last_err;
+
+			/* Get the next r/od pair in factors */
+			while (r * od < goal && i + 1 < ARRAY_SIZE(factors)) {
+				i++;
+				r = UNPACK_R(factors[i]);
+				od = UNPACK_OD(factors[i]);
+			}
+
+			/*
+			 * This is a case of double rounding. If we rounded up
+			 * above, we need to round down (in cases of ties) here.
+			 * This prevents off-by-one errors resulting from
+			 * choosing X+2 over X when X.Y rounds up to X+1 and
+			 * there is no r * od = X+1. For the converse, when X.Y
+			 * is rounded down to X, we should choose X+1 over X-1.
+			 */
+			err = abs(r * od - goal);
+			last_err = abs(last_r * last_od - goal);
+			if (last_err < err || (round_up && last_err == err)) {
+				i--;
+				r = last_r;
+				od = last_od;
+			}
+		}
+
+		/*
+		 * Enforce limits on internal clock frequencies. If we
+		 * aren't in spec, try swapping r and od. If everything is
+		 * in-spec, calculate the relative error.
+		 */
+		while (true) {
+			/*
+			 * Whether the intermediate frequencies are out-of-spec
+			 */
+			bool out_of_spec = false;
+
+			if (r > max_r) {
+				out_of_spec = true;
+			} else {
+				/*
+				 * There is no way to only divide once; we need
+				 * to examine the frequency with and without the
+				 * effect of od.
+				 */
+				u64 vco = DIV_ROUND_CLOSEST_ULL(rate_in * f, r);
+
+				if (vco > 1750000000 || vco < 340000000)
+					out_of_spec = true;
+			}
+
+			if (out_of_spec) {
+				if (!swapped) {
+					u64 tmp = r;
+
+					r = od;
+					od = tmp;
+					swapped = true;
+					continue;
+				} else {
+					/*
+					 * Try looking ahead to see if there are
+					 * additional factors for the same
+					 * product.
+					 */
+					if (i + 1 < ARRAY_SIZE(factors)) {
+						u64 new_r, new_od;
+
+						i++;
+						new_r = UNPACK_R(factors[i]);
+						new_od = UNPACK_OD(factors[i]);
+						if (r * od == new_r * new_od) {
+							r = new_r;
+							od = new_od;
+							swapped = false;
+							continue;
+						}
+						i--;
+					}
+					break;
+				}
+			}
+
+			error = DIV_ROUND_CLOSEST_ULL(f * inv_ratio, r * od);
+			/* The lower 16 bits are spurious */
+			error = abs((error - BIT(32))) >> 16;
+
+			if (error < best_error) {
+				best->r = r;
+				best->f = f;
+				best->od = od;
+				best_error = error;
+			}
+			break;
+		}
+	} while (f < 64 && i + 1 < ARRAY_SIZE(factors) && error != 0);
+
+	if (best_error == S64_MAX)
+		return -EINVAL;
+
+	log_debug("best error %lld\n", best_error);
+	return 0;
+}
+
+static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
+			       ulong rate_in)
+{
+	int err;
+	const struct k210_pll_params *pll = &k210_plls[id];
+	struct k210_pll_config config = {};
+	u32 reg;
+
+	if (rate_in < 0)
+		return rate_in;
+
+	log_debug("Calculating parameters with rate=%lu and rate_in=%lu\n",
+		  rate, rate_in);
+	err = k210_pll_calc_config(rate, rate_in, &config);
+	if (err)
+		return err;
+	log_debug("Got r=%u f=%u od=%u\n", config.r, config.f, config.od);
+
+	/*
+	 * Don't use clk_disable as it might not actually disable the pll due to
+	 * refcounting
+	 */
+	k210_pll_disable(priv, id);
+
+	reg = readl(priv->base + pll->off);
+	reg &= ~K210_PLL_CLKR
+	    &  ~K210_PLL_CLKF
+	    &  ~K210_PLL_CLKOD
+	    &  ~K210_PLL_BWADJ;
+	reg |= FIELD_PREP(K210_PLL_CLKR, config.r - 1)
+	    |  FIELD_PREP(K210_PLL_CLKF, config.f - 1)
+	    |  FIELD_PREP(K210_PLL_CLKOD, config.od - 1)
+	    |  FIELD_PREP(K210_PLL_BWADJ, config.f - 1);
+	writel(reg, priv->base + pll->off);
+
+	err = k210_pll_enable(priv, id);
+
+	serial_setbrg();
+	return k210_pll_get_rate(priv, id, rate);
+}
+#else
+static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
+			       ulong rate_in)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_CLK_K210_SET_RATE */
+
+static ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id,
+			       ulong rate_in)
+{
+	u64 r, f, od;
+	u32 reg = readl(priv->base + k210_plls[id].off);
+
+	if (rate_in < 0 || (reg & K210_PLL_BYPASS))
+		return rate_in;
+
+	if (!(reg & K210_PLL_PWRD))
+		return 0;
+
+	r = FIELD_GET(K210_PLL_CLKR, reg) + 1;
+	f = FIELD_GET(K210_PLL_CLKF, reg) + 1;
+	od = FIELD_GET(K210_PLL_CLKOD, reg) + 1;
+
+	return DIV_ROUND_DOWN_ULL(((u64)rate_in) * f, r * od);
+}
+
+/*
+ * Wait for the PLL to be locked. If the PLL is not locked, try clearing the
+ * slip before retrying
+ */
+static void k210_pll_waitfor_lock(struct k210_clk_priv *priv, int id)
+{
+	const struct k210_pll_params *pll = &k210_plls[id];
+	u32 mask = (BIT(pll->width) - 1) << pll->shift;
+
+	while (true) {
+		u32 reg = readl(priv->base + K210_SYSCTL_PLL_LOCK);
+
+		if ((reg & mask) == mask)
+			break;
+
+		reg |= BIT(pll->shift + K210_PLL_CLEAR_SLIP);
+		writel(reg, priv->base + K210_SYSCTL_PLL_LOCK);
+	}
+}
+
+/* Adapted from sysctl_pll_enable */
+static int k210_pll_enable(struct k210_clk_priv *priv, int id)
+{
+	const struct k210_pll_params *pll = &k210_plls[id];
+	u32 reg = readl(priv->base + pll->off);
+
+	if ((reg & K210_PLL_PWRD) && (reg & K210_PLL_EN) &&
+	    !(reg & K210_PLL_RESET))
+		return 0;
+
+	reg |= K210_PLL_PWRD;
+	writel(reg, priv->base + pll->off);
+
+	/* Ensure reset is low before asserting it */
+	reg &= ~K210_PLL_RESET;
+	writel(reg, priv->base + pll->off);
+	reg |= K210_PLL_RESET;
+	writel(reg, priv->base + pll->off);
+	nop();
+	nop();
+	reg &= ~K210_PLL_RESET;
+	writel(reg, priv->base + pll->off);
+
+	k210_pll_waitfor_lock(priv, id);
+
+	reg &= ~K210_PLL_BYPASS;
+	reg |= K210_PLL_EN;
+	writel(reg, priv->base + pll->off);
+
+	return 0;
+}
+
+static int k210_pll_disable(struct k210_clk_priv *priv, int id)
+{
+	const struct k210_pll_params *pll = &k210_plls[id];
+	u32 reg = readl(priv->base + pll->off);
+
+	/*
+	 * Bypassing before powering off is important so child clocks don't stop
+	 * working. This is especially important for pll0, the indirect parent
+	 * of the cpu clock.
+	 */
+	reg |= K210_PLL_BYPASS;
+	writel(reg, priv->base + pll->off);
+
+	reg &= ~K210_PLL_PWRD;
+	reg &= ~K210_PLL_EN;
+	writel(reg, priv->base + pll->off);
+	return 0;
+}
+
 static u32 k210_clk_readl(struct k210_clk_priv *priv, u8 off, u8 shift,
 			  u8 width)
 {
diff --git a/drivers/clk/kendryte/pll.c b/drivers/clk/kendryte/pll.c
deleted file mode 100644
index 1f0275c83f..0000000000
--- a/drivers/clk/kendryte/pll.c
+++ /dev/null
@@ -1,587 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
- */
-#define LOG_CATEGORY UCLASS_CLK
-
-#include <common.h>
-#include <dm.h>
-/* For DIV_ROUND_DOWN_ULL, defined in linux/kernel.h */
-#include <div64.h>
-#include <log.h>
-#include <serial.h>
-#include <asm/io.h>
-#include <dt-bindings/clock/k210-sysctl.h>
-#include <dt-bindings/mfd/k210-sysctl.h>
-#include <kendryte/pll.h>
-#include <linux/bitfield.h>
-#include <linux/clk-provider.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-
-/**
- * struct k210_pll_params - K210 PLL parameters
- * @off: The offset of the PLL from the base sysctl address
- * @shift: The offset of the LSB of the lock status
- * @width: The number of bits in the lock status
- */
-struct k210_pll_params {
-	u8 off;
-	u8 shift;
-	u8 width;
-};
-
-static const struct k210_pll_params k210_plls[] = {
-#define PLL(_off, _shift, _width) { \
-	.off = (_off), \
-	.shift = (_shift), \
-	.width = (_width), \
-}
-	[0] = PLL(K210_SYSCTL_PLL0,  0, 2),
-	[1] = PLL(K210_SYSCTL_PLL1,  8, 1),
-	[2] = PLL(K210_SYSCTL_PLL2, 16, 1),
-#undef PLL
-};
-
-#ifdef CONFIG_CLK_K210_SET_RATE
-int k210_pll_enable(struct k210_clk_priv *priv, int id);
-int k210_pll_disable(struct k210_clk_priv *priv, int id);
-ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, ulong rate_in);
-
-/*
- * The PLL included with the Kendryte K210 appears to be a True Circuits, Inc.
- * General-Purpose PLL. The logical layout of the PLL with internal feedback is
- * approximately the following:
- *
- *  +---------------+
- *  |reference clock|
- *  +---------------+
- *          |
- *          v
- *        +--+
- *        |/r|
- *        +--+
- *          |
- *          v
- *   +-------------+
- *   |divided clock|
- *   +-------------+
- *          |
- *          v
- *  +--------------+
- *  |phase detector|<---+
- *  +--------------+    |
- *          |           |
- *          v   +--------------+
- *        +---+ |feedback clock|
- *        |VCO| +--------------+
- *        +---+         ^
- *          |    +--+   |
- *          +--->|/f|---+
- *          |    +--+
- *          v
- *        +---+
- *        |/od|
- *        +---+
- *          |
- *          v
- *       +------+
- *       |output|
- *       +------+
- *
- * The k210 PLLs have three factors: r, f, and od. Because of the feedback mode,
- * the effect of the division by f is to multiply the input frequency. The
- * equation for the output rate is
- *   rate = (rate_in * f) / (r * od).
- * Moving knowns to one side of the equation, we get
- *   rate / rate_in = f / (r * od)
- * Rearranging slightly,
- *   abs_error = abs((rate / rate_in) - (f / (r * od))).
- * To get relative, error, we divide by the expected ratio
- *   error = abs((rate / rate_in) - (f / (r * od))) / (rate / rate_in).
- * Simplifying,
- *   error = abs(1 - f / (r * od)) / (rate / rate_in)
- *   error = abs(1 - (f * rate_in) / (r * od * rate))
- * Using the constants ratio = rate / rate_in and inv_ratio = rate_in / rate,
- *   error = abs((f * inv_ratio) / (r * od) - 1)
- * This is the error used in evaluating parameters.
- *
- * r and od are four bits each, while f is six bits. Because r and od are
- * multiplied together, instead of the full 256 values possible if both bits
- * were used fully, there are only 97 distinct products. Combined with f, there
- * are 6208 theoretical settings for the PLL. However, most of these settings
- * can be ruled out immediately because they do not have the correct ratio.
- *
- * In addition to the constraint of approximating the desired ratio, parameters
- * must also keep internal pll frequencies within acceptable ranges. The divided
- * clock's minimum and maximum frequencies have a ratio of around 128.  This
- * leaves fairly substantial room to work with, especially since the only
- * affected parameter is r. The VCO's minimum and maximum frequency have a ratio
- * of 5, which is considerably more restrictive.
- *
- * The r and od factors are stored in a table. This is to make it easy to find
- * the next-largest product. Some products have multiple factorizations, but
- * only when one factor has at least a 2.5x ratio to the factors of the other
- * factorization. This is because any smaller ratio would not make a difference
- * when ensuring the VCO's frequency is within spec.
- *
- * Throughout the calculation function, fixed point arithmetic is used. Because
- * the range of rate and rate_in may be up to 1.75 GHz, or around 2^30, 64-bit
- * 32.32 fixed-point numbers are used to represent ratios. In general, to
- * implement division, the numerator is first multiplied by 2^32. This gives a
- * result where the whole number part is in the upper 32 bits, and the fraction
- * is in the lower 32 bits.
- *
- * In general, rounding is done to the closest integer. This helps find the best
- * approximation for the ratio. Rounding in one direction (e.g down) could cause
- * the function to miss a better ratio with one of the parameters increased by
- * one.
- */
-
-/*
- * The factors table was generated with the following python code:
- *
- * def p(x, y):
- *    return (1.0*x/y > 2.5) or (1.0*y/x > 2.5)
- *
- * factors = {}
- * for i in range(1, 17):
- *    for j in range(1, 17):
- *       fs = factors.get(i*j) or []
- *       if fs == [] or all([
- *             (p(i, x) and p(i, y)) or (p(j, x) and p(j, y))
- *             for (x, y) in fs]):
- *          fs.append((i, j))
- *          factors[i*j] = fs
- *
- * for k, l in sorted(factors.items()):
- *    for v in l:
- *       print("PACK(%s, %s)," % v)
- */
-#define PACK(r, od) (((((r) - 1) & 0xF) << 4) | (((od) - 1) & 0xF))
-#define UNPACK_R(val) ((((val) >> 4) & 0xF) + 1)
-#define UNPACK_OD(val) (((val) & 0xF) + 1)
-static const u8 factors[] = {
-	PACK(1, 1),
-	PACK(1, 2),
-	PACK(1, 3),
-	PACK(1, 4),
-	PACK(1, 5),
-	PACK(1, 6),
-	PACK(1, 7),
-	PACK(1, 8),
-	PACK(1, 9),
-	PACK(3, 3),
-	PACK(1, 10),
-	PACK(1, 11),
-	PACK(1, 12),
-	PACK(3, 4),
-	PACK(1, 13),
-	PACK(1, 14),
-	PACK(1, 15),
-	PACK(3, 5),
-	PACK(1, 16),
-	PACK(4, 4),
-	PACK(2, 9),
-	PACK(2, 10),
-	PACK(3, 7),
-	PACK(2, 11),
-	PACK(2, 12),
-	PACK(5, 5),
-	PACK(2, 13),
-	PACK(3, 9),
-	PACK(2, 14),
-	PACK(2, 15),
-	PACK(2, 16),
-	PACK(3, 11),
-	PACK(5, 7),
-	PACK(3, 12),
-	PACK(3, 13),
-	PACK(4, 10),
-	PACK(3, 14),
-	PACK(4, 11),
-	PACK(3, 15),
-	PACK(3, 16),
-	PACK(7, 7),
-	PACK(5, 10),
-	PACK(4, 13),
-	PACK(6, 9),
-	PACK(5, 11),
-	PACK(4, 14),
-	PACK(4, 15),
-	PACK(7, 9),
-	PACK(4, 16),
-	PACK(5, 13),
-	PACK(6, 11),
-	PACK(5, 14),
-	PACK(6, 12),
-	PACK(5, 15),
-	PACK(7, 11),
-	PACK(6, 13),
-	PACK(5, 16),
-	PACK(9, 9),
-	PACK(6, 14),
-	PACK(8, 11),
-	PACK(6, 15),
-	PACK(7, 13),
-	PACK(6, 16),
-	PACK(7, 14),
-	PACK(9, 11),
-	PACK(10, 10),
-	PACK(8, 13),
-	PACK(7, 15),
-	PACK(9, 12),
-	PACK(10, 11),
-	PACK(7, 16),
-	PACK(9, 13),
-	PACK(8, 15),
-	PACK(11, 11),
-	PACK(9, 14),
-	PACK(8, 16),
-	PACK(10, 13),
-	PACK(11, 12),
-	PACK(9, 15),
-	PACK(10, 14),
-	PACK(11, 13),
-	PACK(9, 16),
-	PACK(10, 15),
-	PACK(11, 14),
-	PACK(12, 13),
-	PACK(10, 16),
-	PACK(11, 15),
-	PACK(12, 14),
-	PACK(13, 13),
-	PACK(11, 16),
-	PACK(12, 15),
-	PACK(13, 14),
-	PACK(12, 16),
-	PACK(13, 15),
-	PACK(14, 14),
-	PACK(13, 16),
-	PACK(14, 15),
-	PACK(14, 16),
-	PACK(15, 15),
-	PACK(15, 16),
-	PACK(16, 16),
-};
-
-TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in,
-				     struct k210_pll_config *best)
-{
-	int i;
-	s64 error, best_error;
-	u64 ratio, inv_ratio; /* fixed point 32.32 ratio of the rates */
-	u64 max_r;
-	u64 r, f, od;
-
-	/*
-	 * Can't go over 1.75 GHz or under 21.25 MHz due to limitations on the
-	 * VCO frequency. These are not the same limits as below because od can
-	 * reduce the output frequency by 16.
-	 */
-	if (rate > 1750000000 || rate < 21250000)
-		return -EINVAL;
-
-	/* Similar restrictions on the input rate */
-	if (rate_in > 1750000000 || rate_in < 13300000)
-		return -EINVAL;
-
-	ratio = DIV_ROUND_CLOSEST_ULL((u64)rate << 32, rate_in);
-	inv_ratio = DIV_ROUND_CLOSEST_ULL((u64)rate_in << 32, rate);
-	/* Can't increase by more than 64 or reduce by more than 256 */
-	if (rate > rate_in && ratio > (64ULL << 32))
-		return -EINVAL;
-	else if (rate <= rate_in && inv_ratio > (256ULL << 32))
-		return -EINVAL;
-
-	/*
-	 * The divided clock (rate_in / r) must stay between 1.75 GHz and 13.3
-	 * MHz. There is no minimum, since the only way to get a higher input
-	 * clock than 26 MHz is to use a clock generated by a PLL. Because PLLs
-	 * cannot output frequencies greater than 1.75 GHz, the minimum would
-	 * never be greater than one.
-	 */
-	max_r = DIV_ROUND_DOWN_ULL(rate_in, 13300000);
-
-	/* Variables get immediately incremented, so start at -1th iteration */
-	i = -1;
-	f = 0;
-	r = 0;
-	od = 0;
-	best_error = S64_MAX;
-	error = best_error;
-	/* do-while here so we always try at least one ratio */
-	do {
-		/*
-		 * Whether we swapped r and od while enforcing frequency limits
-		 */
-		bool swapped = false;
-		u64 last_od = od;
-		u64 last_r = r;
-
-		/*
-		 * Try the next largest value for f (or r and od) and
-		 * recalculate the other parameters based on that
-		 */
-		if (rate > rate_in) {
-			/*
-			 * Skip factors of the same product if we already tried
-			 * out that product
-			 */
-			do {
-				i++;
-				r = UNPACK_R(factors[i]);
-				od = UNPACK_OD(factors[i]);
-			} while (i + 1 < ARRAY_SIZE(factors) &&
-				 r * od == last_r * last_od);
-
-			/* Round close */
-			f = (r * od * ratio + BIT(31)) >> 32;
-			if (f > 64)
-				f = 64;
-		} else {
-			u64 tmp = ++f * inv_ratio;
-			bool round_up = !!(tmp & BIT(31));
-			u32 goal = (tmp >> 32) + round_up;
-			u32 err, last_err;
-
-			/* Get the next r/od pair in factors */
-			while (r * od < goal && i + 1 < ARRAY_SIZE(factors)) {
-				i++;
-				r = UNPACK_R(factors[i]);
-				od = UNPACK_OD(factors[i]);
-			}
-
-			/*
-			 * This is a case of double rounding. If we rounded up
-			 * above, we need to round down (in cases of ties) here.
-			 * This prevents off-by-one errors resulting from
-			 * choosing X+2 over X when X.Y rounds up to X+1 and
-			 * there is no r * od = X+1. For the converse, when X.Y
-			 * is rounded down to X, we should choose X+1 over X-1.
-			 */
-			err = abs(r * od - goal);
-			last_err = abs(last_r * last_od - goal);
-			if (last_err < err || (round_up && last_err == err)) {
-				i--;
-				r = last_r;
-				od = last_od;
-			}
-		}
-
-		/*
-		 * Enforce limits on internal clock frequencies. If we
-		 * aren't in spec, try swapping r and od. If everything is
-		 * in-spec, calculate the relative error.
-		 */
-		while (true) {
-			/*
-			 * Whether the intermediate frequencies are out-of-spec
-			 */
-			bool out_of_spec = false;
-
-			if (r > max_r) {
-				out_of_spec = true;
-			} else {
-				/*
-				 * There is no way to only divide once; we need
-				 * to examine the frequency with and without the
-				 * effect of od.
-				 */
-				u64 vco = DIV_ROUND_CLOSEST_ULL(rate_in * f, r);
-
-				if (vco > 1750000000 || vco < 340000000)
-					out_of_spec = true;
-			}
-
-			if (out_of_spec) {
-				if (!swapped) {
-					u64 tmp = r;
-
-					r = od;
-					od = tmp;
-					swapped = true;
-					continue;
-				} else {
-					/*
-					 * Try looking ahead to see if there are
-					 * additional factors for the same
-					 * product.
-					 */
-					if (i + 1 < ARRAY_SIZE(factors)) {
-						u64 new_r, new_od;
-
-						i++;
-						new_r = UNPACK_R(factors[i]);
-						new_od = UNPACK_OD(factors[i]);
-						if (r * od == new_r * new_od) {
-							r = new_r;
-							od = new_od;
-							swapped = false;
-							continue;
-						}
-						i--;
-					}
-					break;
-				}
-			}
-
-			error = DIV_ROUND_CLOSEST_ULL(f * inv_ratio, r * od);
-			/* The lower 16 bits are spurious */
-			error = abs((error - BIT(32))) >> 16;
-
-			if (error < best_error) {
-				best->r = r;
-				best->f = f;
-				best->od = od;
-				best_error = error;
-			}
-			break;
-		}
-	} while (f < 64 && i + 1 < ARRAY_SIZE(factors) && error != 0);
-
-	if (best_error == S64_MAX)
-		return -EINVAL;
-
-	log_debug("best error %lld\n", best_error);
-	return 0;
-}
-
-static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
-			       ulong rate_in)
-{
-	int err;
-	const struct k210_pll_params *pll = &k210_plls[id];
-	struct k210_pll_config config = {};
-	u32 reg;
-
-	if (rate_in < 0)
-		return rate_in;
-
-	log_debug("Calculating parameters with rate=%lu and rate_in=%lld\n",
-		  rate, rate_in);
-	err = k210_pll_calc_config(rate, rate_in, &config);
-	if (err)
-		return err;
-	log_debug("Got r=%u f=%u od=%u\n", config.r, config.f, config.od);
-
-	/*
-	 * Don't use clk_disable as it might not actually disable the pll due to
-	 * refcounting
-	 */
-	k210_pll_disable(clk);
-
-	reg = readl(priv->base + pll->off);
-	reg &= ~K210_PLL_CLKR
-	    &  ~K210_PLL_CLKF
-	    &  ~K210_PLL_CLKOD
-	    &  ~K210_PLL_BWADJ;
-	reg |= FIELD_PREP(K210_PLL_CLKR, config.r - 1)
-	    |  FIELD_PREP(K210_PLL_CLKF, config.f - 1)
-	    |  FIELD_PREP(K210_PLL_CLKOD, config.od - 1)
-	    |  FIELD_PREP(K210_PLL_BWADJ, config.f - 1);
-	writel(reg, priv->base + pll->off);
-
-	err = k210_pll_enable(clk);
-	if (err)
-		return err;
-
-	serial_setbrg();
-	return clk_get_rate(clk);
-}
-#else
-ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
-			ulong rate_in)
-{
-	return -ENOSYS;
-}
-#endif /* CONFIG_CLK_K210_SET_RATE */
-
-ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, ulong rate_in)
-{
-	u64 r, f, od;
-	u32 reg = readl(priv->base + k210_plls[id].off);
-
-	if (rate_in < 0 || (reg & K210_PLL_BYPASS))
-		return rate_in;
-
-	if (!(reg & K210_PLL_PWRD))
-		return 0;
-
-	r = FIELD_GET(K210_PLL_CLKR, reg) + 1;
-	f = FIELD_GET(K210_PLL_CLKF, reg) + 1;
-	od = FIELD_GET(K210_PLL_CLKOD, reg) + 1;
-
-	return DIV_ROUND_DOWN_ULL(((u64)rate_in) * f, r * od);
-}
-
-/*
- * Wait for the PLL to be locked. If the PLL is not locked, try clearing the
- * slip before retrying
- */
-void k210_pll_waitfor_lock(struct k210_clk_priv *priv, int id)
-{
-	const struct k210_pll_params *pll = &k210_plls[id];
-	u32 mask = GENMASK(pll->width - 1, 0) << pll->shift;
-
-	while (true) {
-		u32 reg = readl(priv->base + K210_SYSCTL_PLL_LOCK);
-
-		if ((reg & mask) == mask)
-			break;
-
-		reg |= BIT(pll->shift + K210_PLL_CLEAR_SLIP);
-		writel(reg, priv->base + K210_SYSCTL_PLL_LOCK);
-	}
-}
-
-/* Adapted from sysctl_pll_enable */
-int k210_pll_enable(struct k210_clk_priv *priv, int id)
-{
-	const struct k210_pll_params *pll = &k210_plls[id];
-	u32 reg = readl(priv->base + pll->off);
-
-	if ((reg & K210_PLL_PWRD) && (reg & K210_PLL_EN) &&
-	    !(reg & K210_PLL_RESET))
-		return 0;
-
-	reg |= K210_PLL_PWRD;
-	writel(reg, priv->base + pll->off);
-
-	/* Ensure reset is low before asserting it */
-	reg &= ~K210_PLL_RESET;
-	writel(reg, priv->base + pll->off);
-	reg |= K210_PLL_RESET;
-	writel(reg, priv->base + pll->off);
-	nop();
-	nop();
-	reg &= ~K210_PLL_RESET;
-	writel(reg, priv->base + pll->off);
-
-	k210_pll_waitfor_lock(priv, id);
-
-	reg &= ~K210_PLL_BYPASS;
-	reg |= K210_PLL_EN;
-	writel(reg, priv->base + pll->off);
-
-	return 0;
-}
-
-int k210_pll_disable(struct k210_clk_priv *priv, int id)
-{
-	const struct k210_pll_params *pll = &k210_plls[id];
-	u32 reg = readl(priv->base + pll->off);
-
-	/*
-	 * Bypassing before powering off is important so child clocks don't stop
-	 * working. This is especially important for pll0, the indirect parent
-	 * of the cpu clock.
-	 */
-	reg |= K210_PLL_BYPASS;
-	writel(reg, priv->base + pll->off);
-
-	reg &= ~K210_PLL_PWRD;
-	reg &= ~K210_PLL_EN;
-	writel(reg, priv->base + pll->off);
-	return 0;
-}
diff --git a/include/kendryte/clk.h b/include/kendryte/clk.h
deleted file mode 100644
index 9c6245d468..0000000000
--- a/include/kendryte/clk.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
- */
-
-#ifndef K210_CLK_H
-#define K210_CLK_H
-
-#define LOG_CATEGORY UCLASS_CLK
-#include <linux/types.h>
-#include <linux/clk-provider.h>
-
-static inline struct clk *k210_clk_gate(const char *name,
-					const char *parent_name,
-					void __iomem *reg, u8 bit_idx)
-{
-	return clk_register_gate(NULL, name, parent_name, 0, reg, bit_idx, 0,
-				 NULL);
-}
-
-static inline struct clk *k210_clk_half(const char *name,
-					const char *parent_name)
-{
-	return clk_register_fixed_factor(NULL, name, parent_name, 0, 1, 2);
-}
-
-static inline struct clk *k210_clk_div(const char *name,
-				       const char *parent_name,
-				       void __iomem *reg, u8 shift, u8 width)
-{
-	return clk_register_divider(NULL, name, parent_name, 0, reg, shift,
-				    width, 0);
-}
-
-#endif /* K210_CLK_H */
diff --git a/include/kendryte/pll.h b/include/kendryte/pll.h
index 16fd5a5b68..fd16a89cb2 100644
--- a/include/kendryte/pll.h
+++ b/include/kendryte/pll.h
@@ -5,25 +5,7 @@
 #ifndef K210_PLL_H
 #define K210_PLL_H
 
-#include <clk.h>
 #include <test/export.h>
-#include <asm/io.h>
-
-#define K210_PLL_CLKR GENMASK(3, 0)
-#define K210_PLL_CLKF GENMASK(9, 4)
-#define K210_PLL_CLKOD GENMASK(13, 10) /* Output Divider */
-#define K210_PLL_BWADJ GENMASK(19, 14) /* BandWidth Adjust */
-#define K210_PLL_RESET BIT(20)
-#define K210_PLL_PWRD BIT(21) /* PoWeReD */
-#define K210_PLL_INTFB BIT(22) /* Internal FeedBack */
-#define K210_PLL_BYPASS BIT(23)
-#define K210_PLL_TEST BIT(24)
-#define K210_PLL_EN BIT(25)
-#define K210_PLL_TEST_EN BIT(26)
-
-#define K210_PLL_LOCK 0
-#define K210_PLL_CLEAR_SLIP 2
-#define K210_PLL_TEST_OUT 3
 
 struct k210_pll_config {
 	u8 r;
@@ -34,25 +16,9 @@ struct k210_pll_config {
 #ifdef CONFIG_UNIT_TEST
 TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in,
 				     struct k210_pll_config *best);
-
 #ifndef nop
 #define nop()
 #endif
 
 #endif
-
-/**
- * struct k210_clk_priv - K210 clock driver private data
- * @base: The base address of the sysctl device
- * @in0: The "in0" external oscillator
- */
-struct k210_clk_priv {
-	void __iomem *base;
-	struct clk in0;
-};
-
-ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate, ulong rate_in);
-ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, ulong rate_in);
-int k210_pll_enable(struct k210_clk_priv *priv, int id);
-int k210_pll_disable(struct k210_clk_priv *priv, int id);
 #endif /* K210_PLL_H */
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 04/11] clk: k210: Implement soc_clk_dump
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
                   ` (2 preceding siblings ...)
  2021-06-11  4:16 ` [PATCH v3 03/11] clk: k210: Move pll into the rest of the driver Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-16  1:56   ` Leo Liang
  2021-06-11  4:16 ` [PATCH v3 05/11] clk: k210: Re-add support for setting rate Sean Anderson
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot; +Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson

Since we are no longer using CCF we cannot use the default soc_clk_dump.
Instead, implement our own.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
---

(no changes since v1)

 drivers/clk/kendryte/clk.c | 68 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 66 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/kendryte/clk.c
index de9db84361..203d5f741c 100644
--- a/drivers/clk/kendryte/clk.c
+++ b/drivers/clk/kendryte/clk.c
@@ -925,14 +925,19 @@ static void k210_pll_waitfor_lock(struct k210_clk_priv *priv, int id)
 	}
 }
 
+static bool k210_pll_enabled(u32 reg)
+{
+	return (reg & K210_PLL_PWRD) && (reg & K210_PLL_EN) &&
+		!(reg & K210_PLL_RESET);
+}
+
 /* Adapted from sysctl_pll_enable */
 static int k210_pll_enable(struct k210_clk_priv *priv, int id)
 {
 	const struct k210_pll_params *pll = &k210_plls[id];
 	u32 reg = readl(priv->base + pll->off);
 
-	if ((reg & K210_PLL_PWRD) && (reg & K210_PLL_EN) &&
-	    !(reg & K210_PLL_RESET))
+	if (k210_pll_enabled(reg))
 		return 0;
 
 	reg |= K210_PLL_PWRD;
@@ -1174,3 +1179,62 @@ U_BOOT_DRIVER(k210_clk) = {
 	.probe = k210_clk_probe,
 	.priv_auto = sizeof(struct k210_clk_priv),
 };
+
+#if CONFIG_IS_ENABLED(CMD_CLK)
+static char show_enabled(struct k210_clk_priv *priv, int id)
+{
+	bool enabled;
+
+	if (k210_clks[id].flags & K210_CLKF_PLL) {
+		const struct k210_pll_params *pll =
+			&k210_plls[k210_clks[id].pll];
+
+		enabled = k210_pll_enabled(readl(priv->base + pll->off));
+	} else if (k210_clks[id].gate == K210_CLK_GATE_NONE) {
+		return '-';
+	} else {
+		const struct k210_gate_params *gate =
+			&k210_gates[k210_clks[id].gate];
+
+		enabled = k210_clk_readl(priv, gate->off, gate->bit_idx, 1);
+	}
+
+	return enabled ? 'y' : 'n';
+}
+
+static void show_clks(struct k210_clk_priv *priv, int id, int depth)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(k210_clks); i++) {
+		if (k210_clk_get_parent(priv, i) != id)
+			continue;
+
+		printf(" %-9lu %-7c %*s%s\n", do_k210_clk_get_rate(priv, i),
+		       show_enabled(priv, i), depth * 4, "",
+		       k210_clks[i].name);
+
+		show_clks(priv, i, depth + 1);
+	}
+}
+
+int soc_clk_dump(void)
+{
+	int ret;
+	struct udevice *dev;
+	struct k210_clk_priv *priv;
+
+	ret = uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(k210_clk),
+					  &dev);
+	if (ret)
+		return ret;
+	priv = dev_get_priv(dev);
+
+	puts(" Rate      Enabled Name\n");
+	puts("------------------------\n");
+	printf(" %-9lu %-7c %*s%s\n", clk_get_rate(&priv->in0), 'y', 0, "",
+	       priv->in0.dev->name);
+	show_clks(priv, K210_CLK_IN0, 1);
+	return 0;
+}
+#endif
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 05/11] clk: k210: Re-add support for setting rate
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
                   ` (3 preceding siblings ...)
  2021-06-11  4:16 ` [PATCH v3 04/11] clk: k210: Implement soc_clk_dump Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-16  1:57   ` Leo Liang
  2021-06-11  4:16 ` [PATCH v3 06/11] clk: k210: Don't set PLL rates if we are already at the correct rate Sean Anderson
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot; +Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson

This adds support for setting clock rates, which was left out of the
initial CCF expunging. There are several tricky bits here, mostly related
to the PLLS:

* The PLL's bypass is broken. If the PLL is reconfigured, any child clocks
  will be stopped.
* PLL0 is the parent of ACLK which is the CPU and SRAM's clock. To prevent
  stopping the CPU while we configure PLL0's rate, ACLK is reparented
  to IN0 while PLL0 is disabled.
* PLL1 is the parent of the AISRAM clock. This clock cannot be reparented,
  so we instead just disallow changing PLL1's rate after relocation (when
  we are using the AISRAM).

Signed-off-by: Sean Anderson <seanga2@gmail.com>
---

Changes in v3:
- Fix inverted condition for setting defaults
- Fix val not being set for K210_DIV_POWER

Changes in v2:
- Only force probe clocks pre-reloc

 drivers/clk/kendryte/clk.c | 89 +++++++++++++++++++++++++++++++++++---
 1 file changed, 84 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/kendryte/clk.c
index 203d5f741c..a2901f9b96 100644
--- a/drivers/clk/kendryte/clk.c
+++ b/drivers/clk/kendryte/clk.c
@@ -17,6 +17,8 @@
 #include <kendryte/pll.h>
 #include <linux/bitfield.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 /**
  * struct k210_clk_priv - K210 clock driver private data
  * @base: The base address of the sysctl device
@@ -1059,11 +1061,6 @@ static ulong k210_clk_get_rate(struct clk *clk)
 	return do_k210_clk_get_rate(dev_get_priv(clk->dev), clk->id);
 }
 
-static ulong k210_clk_set_rate(struct clk *clk, unsigned long rate)
-{
-	return -ENOSYS;
-}
-
 static int do_k210_clk_set_parent(struct k210_clk_priv *priv, int id, int new)
 {
 	int i;
@@ -1089,6 +1086,81 @@ static int k210_clk_set_parent(struct clk *clk, struct clk *parent)
 				      parent->id);
 }
 
+static ulong k210_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int parent, ret, err;
+	ulong rate_in, val;
+	const struct k210_div_params *div;
+	struct k210_clk_priv *priv = dev_get_priv(clk->dev);
+
+	if (clk->id == K210_CLK_IN0)
+		return clk_set_rate(&priv->in0, rate);
+
+	parent = k210_clk_get_parent(priv, clk->id);
+	rate_in = do_k210_clk_get_rate(priv, parent);
+
+	log_debug("id=%ld rate=%lu rate_in=%lu\n", clk->id, rate, rate_in);
+
+	if (clk->id == K210_CLK_PLL0) {
+		/* Bypass ACLK so the CPU keeps going */
+		ret = do_k210_clk_set_parent(priv, K210_CLK_ACLK, K210_CLK_IN0);
+		if (ret)
+			return ret;
+	} else if (clk->id == K210_CLK_PLL1 && gd->flags & GD_FLG_RELOC) {
+		/*
+		 * We can't bypass the AI clock like we can ACLK, and after
+		 * relocation we are using the AI ram.
+		 */
+		return -EPERM;
+	}
+
+	if (k210_clks[clk->id].flags & K210_CLKF_PLL) {
+		ret = k210_pll_set_rate(priv, k210_clks[clk->id].pll, rate,
+					rate_in);
+		if (!IS_ERR_VALUE(ret) && clk->id == K210_CLK_PLL0) {
+			/*
+			 * This may have the side effect of reparenting ACLK,
+			 * but I don't really want to keep track of what the old
+			 * parent was.
+			 */
+			err = do_k210_clk_set_parent(priv, K210_CLK_ACLK,
+						     K210_CLK_PLL0);
+			if (err)
+				return err;
+		}
+		return ret;
+	}
+
+	if (k210_clks[clk->id].div == K210_CLK_DIV_NONE)
+		return -ENOSYS;
+	div = &k210_divs[k210_clks[clk->id].div];
+
+	switch (div->type) {
+	case K210_DIV_ONE:
+		val = DIV_ROUND_CLOSEST_ULL((u64)rate_in, rate);
+		val = val ? val - 1 : 0;
+		break;
+	case K210_DIV_EVEN:
+		val = DIV_ROUND_CLOSEST_ULL((u64)rate_in, 2 * rate);
+		break;
+	case K210_DIV_POWER:
+		/* This is ACLK, which has no divider on IN0 */
+		if (parent == K210_CLK_IN0)
+			return -ENOSYS;
+
+		val = DIV_ROUND_CLOSEST_ULL((u64)rate_in, rate);
+		val = __ffs(val);
+		break;
+	default:
+		assert(false);
+		return -EINVAL;
+	};
+
+	val = val ? val - 1 : 0;
+	k210_clk_writel(priv, div->off, div->shift, div->width, val);
+	return do_k210_clk_get_rate(priv, clk->id);
+}
+
 static int k210_clk_endisable(struct k210_clk_priv *priv, int id, bool enable)
 {
 	int parent = k210_clk_get_parent(priv, id);
@@ -1163,6 +1235,13 @@ static int k210_clk_probe(struct udevice *dev)
 	if (ret)
 		return ret;
 
+	/*
+	 * Force setting defaults, even before relocation. This is so we can
+	 * set the clock rate for PLL1 before we relocate into aisram.
+	 */
+	if (!(gd->flags & GD_FLG_RELOC))
+		clk_set_defaults(dev, CLK_DEFAULTS_POST_FORCE);
+
 	return 0;
 }
 
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 06/11] clk: k210: Don't set PLL rates if we are already at the correct rate
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
                   ` (4 preceding siblings ...)
  2021-06-11  4:16 ` [PATCH v3 05/11] clk: k210: Re-add support for setting rate Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-16  1:58   ` Leo Liang
  2021-06-11  4:16 ` [PATCH v3 07/11] clk: k210: Remove bypass driver Sean Anderson
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot; +Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson

This speeds up boot by preventing multiple reconfigurations of the PLLs.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
---

(no changes since v1)

 drivers/clk/kendryte/clk.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/kendryte/clk.c
index a2901f9b96..3148756968 100644
--- a/drivers/clk/kendryte/clk.c
+++ b/drivers/clk/kendryte/clk.c
@@ -847,21 +847,22 @@ static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
 	const struct k210_pll_params *pll = &k210_plls[id];
 	struct k210_pll_config config = {};
 	u32 reg;
+	ulong calc_rate;
 
 	if (rate_in < 0)
 		return rate_in;
 
-	log_debug("Calculating parameters with rate=%lu and rate_in=%lu\n",
-		  rate, rate_in);
 	err = k210_pll_calc_config(rate, rate_in, &config);
 	if (err)
 		return err;
 	log_debug("Got r=%u f=%u od=%u\n", config.r, config.f, config.od);
 
-	/*
-	 * Don't use clk_disable as it might not actually disable the pll due to
-	 * refcounting
-	 */
+	/* Don't bother setting the rate if we're already at that rate */
+	calc_rate = DIV_ROUND_DOWN_ULL(((u64)rate_in) * config.f,
+				       config.r * config.od);
+	if (calc_rate == k210_pll_get_rate(priv, id, rate))
+		return calc_rate;
+
 	k210_pll_disable(priv, id);
 
 	reg = readl(priv->base + pll->off);
@@ -875,7 +876,7 @@ static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate,
 	    |  FIELD_PREP(K210_PLL_BWADJ, config.f - 1);
 	writel(reg, priv->base + pll->off);
 
-	err = k210_pll_enable(priv, id);
+	k210_pll_enable(priv, id);
 
 	serial_setbrg();
 	return k210_pll_get_rate(priv, id, rate);
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 07/11] clk: k210: Remove bypass driver
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
                   ` (5 preceding siblings ...)
  2021-06-11  4:16 ` [PATCH v3 06/11] clk: k210: Don't set PLL rates if we are already at the correct rate Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-16  1:59   ` Leo Liang
  2021-06-11  4:16 ` [PATCH v3 08/11] clk: k210: Move k210 clock out of its own subdirectory Sean Anderson
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot; +Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson

This driver no longer serves a purpose now that we have moved away from
CCF. Drop it.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
---

(no changes since v1)

 drivers/clk/kendryte/Makefile |   2 +-
 drivers/clk/kendryte/bypass.c | 273 ----------------------------------
 include/kendryte/bypass.h     |  31 ----
 3 files changed, 1 insertion(+), 305 deletions(-)
 delete mode 100644 drivers/clk/kendryte/bypass.c
 delete mode 100644 include/kendryte/bypass.h

diff --git a/drivers/clk/kendryte/Makefile b/drivers/clk/kendryte/Makefile
index 6710a1db72..0303c0b99c 100644
--- a/drivers/clk/kendryte/Makefile
+++ b/drivers/clk/kendryte/Makefile
@@ -1 +1 @@
-obj-y += bypass.o clk.o
+obj-y += clk.o
diff --git a/drivers/clk/kendryte/bypass.c b/drivers/clk/kendryte/bypass.c
deleted file mode 100644
index bbdbd9a10d..0000000000
--- a/drivers/clk/kendryte/bypass.c
+++ /dev/null
@@ -1,273 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
- */
-
-#define LOG_CATEGORY UCLASS_CLK
-
-#include <common.h>
-#include <clk.h>
-#include <clk-uclass.h>
-#include <dm.h>
-#include <log.h>
-#include <kendryte/bypass.h>
-#include <linux/clk-provider.h>
-#include <linux/err.h>
-
-#define CLK_K210_BYPASS "k210_clk_bypass"
-
-/*
- * This is a small driver to do a software bypass of a clock if hardware bypass
- * is not working. I have tried to write this in a generic fashion, so that it
- * could be potentially broken out of the kendryte code at some future date.
- *
- * Say you have the following clock configuration
- *
- * +---+ +---+
- * |osc| |pll|
- * +---+ +---+
- *         ^
- *        /|
- *       / |
- *      /  |
- *     /   |
- *    /    |
- * +---+ +---+
- * |clk| |clk|
- * +---+ +---+
- *
- * But the pll does not have a bypass, so when you configure the pll, the
- * configuration needs to change to look like
- *
- * +---+ +---+
- * |osc| |pll|
- * +---+ +---+
- *   ^
- *   |\
- *   | \
- *   |  \
- *   |   \
- *   |    \
- * +---+ +---+
- * |clk| |clk|
- * +---+ +---+
- *
- * To set this up, create a bypass clock with bypassee=pll and alt=osc. When
- * creating the child clocks, set their parent to the bypass clock. After
- * creating all the children, call k210_bypass_setchildren().
- */
-
-static int k210_bypass_dobypass(struct k210_bypass *bypass)
-{
-	int ret, i;
-
-	/*
-	 * If we already have saved parents, then the children are already
-	 * bypassed
-	 */
-	if (bypass->child_count && bypass->saved_parents[0])
-		return 0;
-
-	for (i = 0; i < bypass->child_count; i++) {
-		struct clk *child = bypass->children[i];
-		struct clk *parent = clk_get_parent(child);
-
-		if (IS_ERR(parent)) {
-			for (; i; i--)
-				bypass->saved_parents[i] = NULL;
-			return PTR_ERR(parent);
-		}
-		bypass->saved_parents[i] = parent;
-	}
-
-	for (i = 0; i < bypass->child_count; i++) {
-		struct clk *child = bypass->children[i];
-
-		ret = clk_set_parent(child, bypass->alt);
-		if (ret) {
-			for (; i; i--)
-				clk_set_parent(bypass->children[i],
-					       bypass->saved_parents[i]);
-			for (i = 0; i < bypass->child_count; i++)
-				bypass->saved_parents[i] = NULL;
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static int k210_bypass_unbypass(struct k210_bypass *bypass)
-{
-	int err, ret, i;
-
-	if (!bypass->child_count && !bypass->saved_parents[0]) {
-		log_warning("Cannot unbypass children; dobypass not called first\n");
-		return 0;
-	}
-
-	ret = 0;
-	for (i = 0; i < bypass->child_count; i++) {
-		err = clk_set_parent(bypass->children[i],
-				     bypass->saved_parents[i]);
-		if (err)
-			ret = err;
-		bypass->saved_parents[i] = NULL;
-	}
-	return ret;
-}
-
-static ulong k210_bypass_get_rate(struct clk *clk)
-{
-	struct k210_bypass *bypass = to_k210_bypass(clk);
-	const struct clk_ops *ops = bypass->bypassee_ops;
-
-	if (ops->get_rate)
-		return ops->get_rate(bypass->bypassee);
-	else
-		return clk_get_parent_rate(bypass->bypassee);
-}
-
-static ulong k210_bypass_set_rate(struct clk *clk, unsigned long rate)
-{
-	int ret;
-	struct k210_bypass *bypass = to_k210_bypass(clk);
-	const struct clk_ops *ops = bypass->bypassee_ops;
-
-	/* Don't bother bypassing if we aren't going to set the rate */
-	if (!ops->set_rate)
-		return k210_bypass_get_rate(clk);
-
-	ret = k210_bypass_dobypass(bypass);
-	if (ret)
-		return ret;
-
-	ret = ops->set_rate(bypass->bypassee, rate);
-	if (ret < 0)
-		return ret;
-
-	return k210_bypass_unbypass(bypass);
-}
-
-static int k210_bypass_set_parent(struct clk *clk, struct clk *parent)
-{
-	struct k210_bypass *bypass = to_k210_bypass(clk);
-	const struct clk_ops *ops = bypass->bypassee_ops;
-
-	if (ops->set_parent)
-		return ops->set_parent(bypass->bypassee, parent);
-	else
-		return -EINVAL;
-}
-
-/*
- * For these next two functions, do the bypassing even if there is no
- * en-/-disable function, since the bypassing itself can be observed in between
- * calls.
- */
-static int k210_bypass_enable(struct clk *clk)
-{
-	int ret;
-	struct k210_bypass *bypass = to_k210_bypass(clk);
-	const struct clk_ops *ops = bypass->bypassee_ops;
-
-	ret = k210_bypass_dobypass(bypass);
-	if (ret)
-		return ret;
-
-	if (ops->enable)
-		ret = ops->enable(bypass->bypassee);
-	else
-		ret = 0;
-	if (ret)
-		return ret;
-
-	return k210_bypass_unbypass(bypass);
-}
-
-static int k210_bypass_disable(struct clk *clk)
-{
-	int ret;
-	struct k210_bypass *bypass = to_k210_bypass(clk);
-	const struct clk_ops *ops = bypass->bypassee_ops;
-
-	ret = k210_bypass_dobypass(bypass);
-	if (ret)
-		return ret;
-
-	if (ops->disable)
-		return ops->disable(bypass->bypassee);
-	else
-		return 0;
-}
-
-static const struct clk_ops k210_bypass_ops = {
-	.get_rate = k210_bypass_get_rate,
-	.set_rate = k210_bypass_set_rate,
-	.set_parent = k210_bypass_set_parent,
-	.enable = k210_bypass_enable,
-	.disable = k210_bypass_disable,
-};
-
-int k210_bypass_set_children(struct clk *clk, struct clk **children,
-			     size_t child_count)
-{
-	struct k210_bypass *bypass = to_k210_bypass(clk);
-
-	kfree(bypass->saved_parents);
-	if (child_count) {
-		bypass->saved_parents =
-			kcalloc(child_count, sizeof(struct clk *), GFP_KERNEL);
-		if (!bypass->saved_parents)
-			return -ENOMEM;
-	}
-	bypass->child_count = child_count;
-	bypass->children = children;
-
-	return 0;
-}
-
-struct clk *k210_register_bypass_struct(const char *name,
-					const char *parent_name,
-					struct k210_bypass *bypass)
-{
-	int ret;
-	struct clk *clk;
-
-	clk = &bypass->clk;
-
-	ret = clk_register(clk, CLK_K210_BYPASS, name, parent_name);
-	if (ret)
-		return ERR_PTR(ret);
-
-	bypass->bypassee->dev = clk->dev;
-	return clk;
-}
-
-struct clk *k210_register_bypass(const char *name, const char *parent_name,
-				 struct clk *bypassee,
-				 const struct clk_ops *bypassee_ops,
-				 struct clk *alt)
-{
-	struct clk *clk;
-	struct k210_bypass *bypass;
-
-	bypass = kzalloc(sizeof(*bypass), GFP_KERNEL);
-	if (!bypass)
-		return ERR_PTR(-ENOMEM);
-
-	bypass->bypassee = bypassee;
-	bypass->bypassee_ops = bypassee_ops;
-	bypass->alt = alt;
-
-	clk = k210_register_bypass_struct(name, parent_name, bypass);
-	if (IS_ERR(clk))
-		kfree(bypass);
-	return clk;
-}
-
-U_BOOT_DRIVER(k210_bypass) = {
-	.name	= CLK_K210_BYPASS,
-	.id	= UCLASS_CLK,
-	.ops	= &k210_bypass_ops,
-};
diff --git a/include/kendryte/bypass.h b/include/kendryte/bypass.h
deleted file mode 100644
index ab85bbcbfc..0000000000
--- a/include/kendryte/bypass.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
- */
-#ifndef K210_BYPASS_H
-#define K210_BYPASS_H
-
-struct clk;
-
-struct k210_bypass {
-	struct clk clk;
-	struct clk **children; /* Clocks to reparent */
-	struct clk **saved_parents; /* Parents saved over en-/dis-able */
-	struct clk *bypassee; /* Clock to bypass */
-	const struct clk_ops *bypassee_ops; /* Ops of the bypass clock */
-	struct clk *alt; /* Clock to set children to when bypassing */
-	size_t child_count;
-};
-
-#define to_k210_bypass(_clk) container_of(_clk, struct k210_bypass, clk)
-
-int k210_bypass_set_children(struct clk *clk, struct clk **children,
-			     size_t child_count);
-struct clk *k210_register_bypass_struct(const char *name,
-					const char *parent_name,
-					struct k210_bypass *bypass);
-struct clk *k210_register_bypass(const char *name, const char *parent_name,
-				 struct clk *bypassee,
-				 const struct clk_ops *bypassee_ops,
-				 struct clk *alt);
-#endif /* K210_BYPASS_H */
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 08/11] clk: k210: Move k210 clock out of its own subdirectory
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
                   ` (6 preceding siblings ...)
  2021-06-11  4:16 ` [PATCH v3 07/11] clk: k210: Remove bypass driver Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-16  2:01   ` Leo Liang
  2021-06-11  4:16 ` [PATCH v3 09/11] k210: dts: Set PLL1 to the same rate as PLL0 Sean Anderson
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot; +Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson

Now that we have only one clock driver, we don't need to have our own
subdirectory. Move the driver back with the rest of the clock drivers.

The MAINTAINERS for kendryte pinctrl is also fixed since it has always been
wrong.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
---

(no changes since v1)

 MAINTAINERS                                    |  4 ++--
 drivers/clk/Kconfig                            | 14 +++++++++++++-
 drivers/clk/Makefile                           |  2 +-
 drivers/clk/{kendryte/clk.c => clk_kendryte.c} |  0
 drivers/clk/kendryte/Kconfig                   | 12 ------------
 drivers/clk/kendryte/Makefile                  |  1 -
 6 files changed, 16 insertions(+), 17 deletions(-)
 rename drivers/clk/{kendryte/clk.c => clk_kendryte.c} (100%)
 delete mode 100644 drivers/clk/kendryte/Kconfig
 delete mode 100644 drivers/clk/kendryte/Makefile

diff --git a/MAINTAINERS b/MAINTAINERS
index 86ff5e04a6..effcf5469d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -999,8 +999,8 @@ M:	Sean Anderson <seanga2@gmail.com>
 S:	Maintained
 F:	doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt
 F:	doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
-F:	drivers/clk/kendryte/
-F:	drivers/pinctrl/kendryte/
+F:	drivers/clk/clk_kendryte.c
+F:	drivers/pinctrl/pinctrl-kendryte.c
 F:	include/kendryte/
 
 RNG
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 40a5a5dd88..4bc6680121 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -159,11 +159,23 @@ config CLK_SCMI
 	  by a SCMI agent based on SCMI clock protocol communication
 	  with a SCMI server.
 
+config CLK_K210
+	bool "Clock support for Kendryte K210"
+	depends on CLK
+	help
+	  This enables support clock driver for Kendryte K210 platforms.
+
+config CLK_K210_SET_RATE
+	bool "Enable setting the Kendryte K210 PLL rate"
+	depends on CLK_K210
+	help
+	  Add functionality to calculate new rates for K210 PLLs. Enabling this
+	  feature adds around 1K to U-Boot's final size.
+
 source "drivers/clk/analogbits/Kconfig"
 source "drivers/clk/at91/Kconfig"
 source "drivers/clk/exynos/Kconfig"
 source "drivers/clk/imx/Kconfig"
-source "drivers/clk/kendryte/Kconfig"
 source "drivers/clk/meson/Kconfig"
 source "drivers/clk/microchip/Kconfig"
 source "drivers/clk/mvebu/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 645709b855..f06164bb49 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -28,7 +28,7 @@ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
 obj-$(CONFIG_CLK_EXYNOS) += exynos/
 obj-$(CONFIG_$(SPL_TPL_)CLK_INTEL) += intel/
 obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o
-obj-$(CONFIG_CLK_K210) += kendryte/
+obj-$(CONFIG_CLK_K210) += clk_kendryte.o
 obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o
 obj-$(CONFIG_CLK_MPFS) += microchip/
 obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o
diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/clk_kendryte.c
similarity index 100%
rename from drivers/clk/kendryte/clk.c
rename to drivers/clk/clk_kendryte.c
diff --git a/drivers/clk/kendryte/Kconfig b/drivers/clk/kendryte/Kconfig
deleted file mode 100644
index 0dc8e3f889..0000000000
--- a/drivers/clk/kendryte/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-config CLK_K210
-	bool "Clock support for Kendryte K210"
-	depends on CLK
-	help
-	  This enables support clock driver for Kendryte K210 platforms.
-
-config CLK_K210_SET_RATE
-	bool "Enable setting the Kendryte K210 PLL rate"
-	depends on CLK_K210
-	help
-	  Add functionality to calculate new rates for K210 PLLs. Enabling this
-	  feature adds around 1K to U-Boot's final size.
diff --git a/drivers/clk/kendryte/Makefile b/drivers/clk/kendryte/Makefile
deleted file mode 100644
index 0303c0b99c..0000000000
--- a/drivers/clk/kendryte/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-y += clk.o
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 09/11] k210: dts: Set PLL1 to the same rate as PLL0
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
                   ` (7 preceding siblings ...)
  2021-06-11  4:16 ` [PATCH v3 08/11] clk: k210: Move k210 clock out of its own subdirectory Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-16  2:01   ` Leo Liang
  2021-06-11  4:16 ` [PATCH v3 10/11] k210: Don't imply CCF Sean Anderson
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot; +Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson

Linux has had some stability issues when using AISRAM with a different
frequency from SRAM. Mirror their change here now that we relocate into
AISRAM.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
---

Changes in v3:
- Add CLK_K210_SET_RATE to defconfig so these changes apply

 arch/riscv/dts/k210.dtsi           | 2 ++
 configs/sipeed_maix_bitm_defconfig | 1 +
 2 files changed, 3 insertions(+)

diff --git a/arch/riscv/dts/k210.dtsi b/arch/riscv/dts/k210.dtsi
index 2492af8038..8bcd3cebde 100644
--- a/arch/riscv/dts/k210.dtsi
+++ b/arch/riscv/dts/k210.dtsi
@@ -501,6 +501,8 @@
 					#clock-cells = <1>;
 					compatible = "kendryte,k210-clk";
 					clocks = <&in0>;
+					assigned-clocks = <&sysclk K210_CLK_PLL1>;
+					assigned-clock-rates = <390000000>;
 					u-boot,dm-pre-reloc;
 				};
 
diff --git a/configs/sipeed_maix_bitm_defconfig b/configs/sipeed_maix_bitm_defconfig
index bd877cd055..6a06f650ea 100644
--- a/configs/sipeed_maix_bitm_defconfig
+++ b/configs/sipeed_maix_bitm_defconfig
@@ -13,6 +13,7 @@ CONFIG_HUSH_PARSER=y
 CONFIG_MTDIDS_DEFAULT="nor0=spi3:0"
 CONFIG_MTDPARTS_DEFAULT="nor0:1M(u-boot),0x1000@0xfff000(env)"
 # CONFIG_NET is not set
+CONFIG_CLK_K210_SET_RATE=y
 # CONFIG_INPUT is not set
 CONFIG_SF_DEFAULT_BUS=3
 # CONFIG_DM_ETH is not set
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 10/11] k210: Don't imply CCF
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
                   ` (8 preceding siblings ...)
  2021-06-11  4:16 ` [PATCH v3 09/11] k210: dts: Set PLL1 to the same rate as PLL0 Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-16  2:02   ` Leo Liang
  2021-06-11  4:16 ` [PATCH v3 11/11] test: Add K210 PLL tests to sandbox defconfigs Sean Anderson
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot; +Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson

Now that the k210 clock driver does not depend on CCF, we should no longer
imply it (and probably should not have in the first place). We can also
reduce the pre-relocation malloc arena back to something sensible.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
---

(no changes since v1)

 board/sipeed/maix/Kconfig          | 2 --
 configs/sipeed_maix_bitm_defconfig | 1 -
 2 files changed, 3 deletions(-)

diff --git a/board/sipeed/maix/Kconfig b/board/sipeed/maix/Kconfig
index adf6abb572..b1d7a7ad93 100644
--- a/board/sipeed/maix/Kconfig
+++ b/board/sipeed/maix/Kconfig
@@ -37,8 +37,6 @@ config BOARD_SPECIFIC_OPTIONS
 	imply SIFIVE_CLINT
 	imply POWER_DOMAIN
 	imply SIMPLE_PM_BUS
-	imply CLK_CCF
-	imply CLK_COMPOSITE_CCF
 	imply CLK_K210
 	imply DM_RESET
 	imply RESET_SYSCON
diff --git a/configs/sipeed_maix_bitm_defconfig b/configs/sipeed_maix_bitm_defconfig
index 6a06f650ea..33c67c0b54 100644
--- a/configs/sipeed_maix_bitm_defconfig
+++ b/configs/sipeed_maix_bitm_defconfig
@@ -1,5 +1,4 @@
 CONFIG_RISCV=y
-CONFIG_SYS_MALLOC_F_LEN=0x10000
 CONFIG_ENV_SIZE=0x1000
 CONFIG_ENV_OFFSET=0xfff000
 CONFIG_ENV_SECT_SIZE=0x1000
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 11/11] test: Add K210 PLL tests to sandbox defconfigs
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
                   ` (9 preceding siblings ...)
  2021-06-11  4:16 ` [PATCH v3 10/11] k210: Don't imply CCF Sean Anderson
@ 2021-06-11  4:16 ` Sean Anderson
  2021-06-11  8:21 ` [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Lukasz Majewski
  2021-06-11 23:14 ` Sean Anderson
  12 siblings, 0 replies; 25+ messages in thread
From: Sean Anderson @ 2021-06-11  4:16 UTC (permalink / raw)
  To: u-boot
  Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Sean Anderson, Simon Glass

This adds the unit test for the K210 PLL to the sandbox defconfigs.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 configs/sandbox64_defconfig        | 2 ++
 configs/sandbox_defconfig          | 2 ++
 configs/sandbox_flattree_defconfig | 2 ++
 3 files changed, 6 insertions(+)

diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index 9a373bab6f..9cd746107d 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -107,6 +107,8 @@ CONFIG_AXI_SANDBOX=y
 CONFIG_BUTTON=y
 CONFIG_BUTTON_GPIO=y
 CONFIG_CLK=y
+CONFIG_CLK_K210=y
+CONFIG_CLK_K210_SET_RATE=y
 CONFIG_CPU=y
 CONFIG_DM_DEMO=y
 CONFIG_DM_DEMO_SIMPLE=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index bdbf714e2b..f9749dea61 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -130,6 +130,8 @@ CONFIG_BUTTON_GPIO=y
 CONFIG_CLK=y
 CONFIG_CLK_COMPOSITE_CCF=y
 CONFIG_CLK_SCMI=y
+CONFIG_CLK_K210=y
+CONFIG_CLK_K210_SET_RATE=y
 CONFIG_SANDBOX_CLK_CCF=y
 CONFIG_CPU=y
 CONFIG_DM_DEMO=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index 853c9440ea..772230ce47 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -86,6 +86,8 @@ CONFIG_AXI=y
 CONFIG_AXI_SANDBOX=y
 CONFIG_CLK=y
 CONFIG_CLK_COMPOSITE_CCF=y
+CONFIG_CLK_K210=y
+CONFIG_CLK_K210_SET_RATE=y
 CONFIG_SANDBOX_CLK_CCF=y
 CONFIG_CPU=y
 CONFIG_DM_DEMO=y
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
                   ` (10 preceding siblings ...)
  2021-06-11  4:16 ` [PATCH v3 11/11] test: Add K210 PLL tests to sandbox defconfigs Sean Anderson
@ 2021-06-11  8:21 ` Lukasz Majewski
  2021-06-11 13:57   ` Sean Anderson
  2021-06-11 23:14 ` Sean Anderson
  12 siblings, 1 reply; 25+ messages in thread
From: Lukasz Majewski @ 2021-06-11  8:21 UTC (permalink / raw)
  To: Sean Anderson
  Cc: u-boot, Damien Le Moal, Leo Liang, Andreas Dannenberg,
	Lokesh Vutla, Philipp Tomsich

[-- Attachment #1: Type: text/plain, Size: 6376 bytes --]

On Fri, 11 Jun 2021 00:16:06 -0400
Sean Anderson <seanga2@gmail.com> wrote:

> This is something I've been meaning to do for a while but only just
> got around to. The CCF has been quite unwieldy in a few ways:
> 
> * It is very rigid, and there are not easy ways to hook into it
> without rewriting many things. See e.g. things like the bypass clock
> and all the _half clocks which were created because CCF didn't
> support the dividers used on the k210. While preparing this series, I
> encountered several edge cases which I had initially overlooked (or
> which were not supported in the initial release). These would have
> been very difficult to fix with CCF, but were much easier to address
> because each funcion is implemented in one place.
> * There is a lot of magic going on under the curtains because of all
> the CCF code which lives in many different files. Some things live in
> drivers, but many things live in e.g. clk-uclass.c. So many things
> live in so many files and it can be very difficult to get a handle on
> what exactly happens. Complicating this is that there is a conflation
> of struct clk as a handle and struct clk as a device. In this regard,
> refcounting is completely broken. IMO we should just do away with
> refcounts and only disable clocks when explicitly asked for.
> * It is very dependent on runtime initialization. Typically,
> everything is initialized by calling into various register()
> functions, usually with several wrappers to avoid specifying all the
> arguments. This balloons the runtime memory usage since there are so
> many devices created. It also makes it hard to debug, since if you do
> it the "typical" way it is easy to accidentally assign a clock to the
> wrong register.
> * It inflates code size by pulling in not just some dead code (e.g.
> this driver does not use divider tables but they are in clk-divider
> anyway) but also pulling in numerous imx-specific clocks. This could
> be fixed, but I don't want to due to the other reasons listed.
> 
> I am very happy to have completely excised it from my driver. IMO
> there should be big warning signs on the CCF warning not to use it
> for new code. This would hopefully dissuade those like myself who had
> no idea that CCF was *not* in fact a good way to write a clock driver.

You mean for U-Boot or for Linux ?

> 
> Overall there is a total savings of 12k from this series.
>    text	   data	    bss	    dec
> hex	filename 292485	  32672	  12624
> 337781	  52775	before/u-boot 283125
> 29856	  12624	 325605	  4f7e5	after/u-boot
> 

I'm not going to defend CCF to the last breath, I know their issues.

However, the goal for CCF was to have:

1. Ported code from Linux (with some code simplification)
2. Get the standard approach to the clock subsystem.

I'm just wondering if we (as a community) want to have such diversity -
I mean each architecture would have different clock driver (under the
device model)

As fair as I can see - the K210 already has support for CCF in Linux:
drivers/clk/clk-k210.c 
Reading the above comment - it looks like you couldn't simplyfy this
Linux driver to be smaller and fit into U-Boot?

Sean, do you think that other archs can benefit from your work?

> This series depends on
> https://patchwork.ozlabs.org/project/uboot/list/?series=238211
> 
> Changes in v3:
> - Always define clk_defaults_stage, even if clk_set_defaults is a
> dummy
> - Fix inverted condition for setting defaults
> - Fix val not being set for K210_DIV_POWER
> - Add CLK_K210_SET_RATE to defconfig so these changes apply
> 
> Changes in v2:
> - Convert stage to enum
> - Only force probe clocks pre-reloc
> - Rebase on u-boot/master
> 
> Sean Anderson (11):
>   clk: Allow force setting clock defaults before relocation
>   clk: k210: Rewrite to remove CCF
>   clk: k210: Move pll into the rest of the driver
>   clk: k210: Implement soc_clk_dump
>   clk: k210: Re-add support for setting rate
>   clk: k210: Don't set PLL rates if we are already at the correct rate
>   clk: k210: Remove bypass driver
>   clk: k210: Move k210 clock out of its own subdirectory
>   k210: dts: Set PLL1 to the same rate as PLL0
>   k210: Don't imply CCF
>   test: Add K210 PLL tests to sandbox defconfigs
> 
>  MAINTAINERS                             |    4 +-
>  arch/riscv/dts/k210.dtsi                |    2 +
>  board/sipeed/maix/Kconfig               |    2 -
>  configs/sandbox64_defconfig             |    2 +
>  configs/sandbox_defconfig               |    2 +
>  configs/sandbox_flattree_defconfig      |    2 +
>  configs/sipeed_maix_bitm_defconfig      |    2 +-
>  drivers/clk/Kconfig                     |   14 +-
>  drivers/clk/Makefile                    |    2 +-
>  drivers/clk/clk-uclass.c                |   27 +-
>  drivers/clk/clk_kendryte.c              | 1320
> +++++++++++++++++++++++ drivers/clk/kendryte/Kconfig            |
> 12 - drivers/clk/kendryte/Makefile           |    1 -
>  drivers/clk/kendryte/bypass.c           |  273 -----
>  drivers/clk/kendryte/clk.c              |  668 ------------
>  drivers/clk/kendryte/pll.c              |  585 ----------
>  drivers/clk/rockchip/clk_rk3308.c       |    2 +-
>  drivers/core/device.c                   |    2 +-
>  drivers/net/gmac_rockchip.c             |    2 +-
>  include/clk.h                           |   30 +-
>  include/dt-bindings/clock/k210-sysctl.h |   94 +-
>  include/kendryte/bypass.h               |   31 -
>  include/kendryte/clk.h                  |   35 -
>  include/kendryte/pll.h                  |   34 -
>  24 files changed, 1437 insertions(+), 1711 deletions(-)
>  create mode 100644 drivers/clk/clk_kendryte.c
>  delete mode 100644 drivers/clk/kendryte/Kconfig
>  delete mode 100644 drivers/clk/kendryte/Makefile
>  delete mode 100644 drivers/clk/kendryte/bypass.c
>  delete mode 100644 drivers/clk/kendryte/clk.c
>  delete mode 100644 drivers/clk/kendryte/pll.c
>  delete mode 100644 include/kendryte/bypass.h
>  delete mode 100644 include/kendryte/clk.h
> 



Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF
  2021-06-11  8:21 ` [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Lukasz Majewski
@ 2021-06-11 13:57   ` Sean Anderson
  2021-06-13 23:08     ` Damien Le Moal
  0 siblings, 1 reply; 25+ messages in thread
From: Sean Anderson @ 2021-06-11 13:57 UTC (permalink / raw)
  To: Lukasz Majewski
  Cc: u-boot, Damien Le Moal, Leo Liang, Andreas Dannenberg,
	Lokesh Vutla, Philipp Tomsich

On 6/11/21 4:21 AM, Lukasz Majewski wrote:
> On Fri, 11 Jun 2021 00:16:06 -0400
> Sean Anderson <seanga2@gmail.com> wrote:
> 
>> This is something I've been meaning to do for a while but only just
>> got around to. The CCF has been quite unwieldy in a few ways:
>>
>> * It is very rigid, and there are not easy ways to hook into it
>> without rewriting many things. See e.g. things like the bypass clock
>> and all the _half clocks which were created because CCF didn't
>> support the dividers used on the k210. While preparing this series, I
>> encountered several edge cases which I had initially overlooked (or
>> which were not supported in the initial release). These would have
>> been very difficult to fix with CCF, but were much easier to address
>> because each funcion is implemented in one place.
>> * There is a lot of magic going on under the curtains because of all
>> the CCF code which lives in many different files. Some things live in
>> drivers, but many things live in e.g. clk-uclass.c. So many things
>> live in so many files and it can be very difficult to get a handle on
>> what exactly happens. Complicating this is that there is a conflation
>> of struct clk as a handle and struct clk as a device. In this regard,
>> refcounting is completely broken. IMO we should just do away with
>> refcounts and only disable clocks when explicitly asked for.
>> * It is very dependent on runtime initialization. Typically,
>> everything is initialized by calling into various register()
>> functions, usually with several wrappers to avoid specifying all the
>> arguments. This balloons the runtime memory usage since there are so
>> many devices created. It also makes it hard to debug, since if you do
>> it the "typical" way it is easy to accidentally assign a clock to the
>> wrong register.
>> * It inflates code size by pulling in not just some dead code (e.g.
>> this driver does not use divider tables but they are in clk-divider
>> anyway) but also pulling in numerous imx-specific clocks. This could
>> be fixed, but I don't want to due to the other reasons listed.
>>
>> I am very happy to have completely excised it from my driver. IMO
>> there should be big warning signs on the CCF warning not to use it
>> for new code. This would hopefully dissuade those like myself who had
>> no idea that CCF was *not* in fact a good way to write a clock driver.
> 
> You mean for U-Boot or for Linux ?

For U-Boot. I wasn't aware that the CCF was mainly designed for porting
drivers from Linux.

> 
>>
>> Overall there is a total savings of 12k from this series.
>>     text	   data	    bss	    dec
>> hex	filename 292485	  32672	  12624
>> 337781	  52775	before/u-boot 283125
>> 29856	  12624	 325605	  4f7e5	after/u-boot
>>
> 
> I'm not going to defend CCF to the last breath, I know their issues.
> 
> However, the goal for CCF was to have:
> 
> 1. Ported code from Linux (with some code simplification)
> 2. Get the standard approach to the clock subsystem.
> 
> I'm just wondering if we (as a community) want to have such diversity -
> I mean each architecture would have different clock driver (under the
> device model)

If there is already a CCF driver for that arch for Linux, then I think
reusing it is OK. However, I think it generally tends toward larger
drivers, larger runtime memory usage, and awkward design. So if you are
writing a new driver for U-Boot, I think it is better to not use CCF
drivers.

> 
> As fair as I can see - the K210 already has support for CCF in Linux:
> drivers/clk/clk-k210.c

Yes, but it does not really "use" the CCF. For example, things like
composite clocks are absent; all calculations of rate are internal to
the driver. In fact, I took inspiration from Damien's handling of this
driver in Linux.

> Reading the above comment - it looks like you couldn't simplyfy this
> Linux driver to be smaller and fit into U-Boot?

Well, this driver takes major inspiration from the Linux driver, which
was itself based on this code. So in a sense, this is already a
simplification of the Linux driver.

> 
> Sean, do you think that other archs can benefit from your work?

Hm, I don't know. I don't think there is must code which could be
reused. Some of the major savings in disabling CCF were from disabling
imx-specific clocks which are always enabled, even though they are not
designed to be used outside of that arch.

In terms of general improvements, I think that get_parent() should be
part of clk_ops. That would allow me to use the existing clock dump
code. Additionally, I think that enable_count has no business living in
struct clk, as that struct is a "thick pointer" and multiple ones can
exist for the same clock.

--Sean

> 
>> This series depends on
>> https://patchwork.ozlabs.org/project/uboot/list/?series=238211
>>
>> Changes in v3:
>> - Always define clk_defaults_stage, even if clk_set_defaults is a
>> dummy
>> - Fix inverted condition for setting defaults
>> - Fix val not being set for K210_DIV_POWER
>> - Add CLK_K210_SET_RATE to defconfig so these changes apply
>>
>> Changes in v2:
>> - Convert stage to enum
>> - Only force probe clocks pre-reloc
>> - Rebase on u-boot/master
>>
>> Sean Anderson (11):
>>    clk: Allow force setting clock defaults before relocation
>>    clk: k210: Rewrite to remove CCF
>>    clk: k210: Move pll into the rest of the driver
>>    clk: k210: Implement soc_clk_dump
>>    clk: k210: Re-add support for setting rate
>>    clk: k210: Don't set PLL rates if we are already at the correct rate
>>    clk: k210: Remove bypass driver
>>    clk: k210: Move k210 clock out of its own subdirectory
>>    k210: dts: Set PLL1 to the same rate as PLL0
>>    k210: Don't imply CCF
>>    test: Add K210 PLL tests to sandbox defconfigs
>>
>>   MAINTAINERS                             |    4 +-
>>   arch/riscv/dts/k210.dtsi                |    2 +
>>   board/sipeed/maix/Kconfig               |    2 -
>>   configs/sandbox64_defconfig             |    2 +
>>   configs/sandbox_defconfig               |    2 +
>>   configs/sandbox_flattree_defconfig      |    2 +
>>   configs/sipeed_maix_bitm_defconfig      |    2 +-
>>   drivers/clk/Kconfig                     |   14 +-
>>   drivers/clk/Makefile                    |    2 +-
>>   drivers/clk/clk-uclass.c                |   27 +-
>>   drivers/clk/clk_kendryte.c              | 1320
>> +++++++++++++++++++++++ drivers/clk/kendryte/Kconfig            |
>> 12 - drivers/clk/kendryte/Makefile           |    1 -
>>   drivers/clk/kendryte/bypass.c           |  273 -----
>>   drivers/clk/kendryte/clk.c              |  668 ------------
>>   drivers/clk/kendryte/pll.c              |  585 ----------
>>   drivers/clk/rockchip/clk_rk3308.c       |    2 +-
>>   drivers/core/device.c                   |    2 +-
>>   drivers/net/gmac_rockchip.c             |    2 +-
>>   include/clk.h                           |   30 +-
>>   include/dt-bindings/clock/k210-sysctl.h |   94 +-
>>   include/kendryte/bypass.h               |   31 -
>>   include/kendryte/clk.h                  |   35 -
>>   include/kendryte/pll.h                  |   34 -
>>   24 files changed, 1437 insertions(+), 1711 deletions(-)
>>   create mode 100644 drivers/clk/clk_kendryte.c
>>   delete mode 100644 drivers/clk/kendryte/Kconfig
>>   delete mode 100644 drivers/clk/kendryte/Makefile
>>   delete mode 100644 drivers/clk/kendryte/bypass.c
>>   delete mode 100644 drivers/clk/kendryte/clk.c
>>   delete mode 100644 drivers/clk/kendryte/pll.c
>>   delete mode 100644 include/kendryte/bypass.h
>>   delete mode 100644 include/kendryte/clk.h
>>
> 
> 
> 
> Best regards,
> 
> Lukasz Majewski
> 
> --
> 
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF
  2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
                   ` (11 preceding siblings ...)
  2021-06-11  8:21 ` [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Lukasz Majewski
@ 2021-06-11 23:14 ` Sean Anderson
  12 siblings, 0 replies; 25+ messages in thread
From: Sean Anderson @ 2021-06-11 23:14 UTC (permalink / raw)
  To: u-boot
  Cc: Damien Le Moal, Leo Liang, Lukasz Majewski, Andreas Dannenberg,
	Lokesh Vutla, Philipp Tomsich

On 6/11/21 12:16 AM, Sean Anderson wrote:
> This is something I've been meaning to do for a while but only just got around
> to. The CCF has been quite unwieldy in a few ways:
> 
> * It is very rigid, and there are not easy ways to hook into it without
>    rewriting many things. See e.g. things like the bypass clock and all the _half
>    clocks which were created because CCF didn't support the dividers used on the
>    k210. While preparing this series, I encountered several edge cases which I
>    had initially overlooked (or which were not supported in the initial release).
>    These would have been very difficult to fix with CCF, but were much easier to
>    address because each funcion is implemented in one place.
> * There is a lot of magic going on under the curtains because of all the CCF
>    code which lives in many different files. Some things live in drivers, but
>    many things live in e.g. clk-uclass.c. So many things live in so many files
>    and it can be very difficult to get a handle on what exactly happens.
>    Complicating this is that there is a conflation of struct clk as a handle and
>    struct clk as a device. In this regard, refcounting is completely broken. IMO
>    we should just do away with refcounts and only disable clocks when explicitly
>    asked for.
> * It is very dependent on runtime initialization. Typically, everything is
>    initialized by calling into various register() functions, usually with several
>    wrappers to avoid specifying all the arguments. This balloons the runtime
>    memory usage since there are so many devices created. It also makes it hard to
>    debug, since if you do it the "typical" way it is easy to accidentally assign
>    a clock to the wrong register.
> * It inflates code size by pulling in not just some dead code (e.g. this driver
>    does not use divider tables but they are in clk-divider anyway) but also
>    pulling in numerous imx-specific clocks. This could be fixed, but I don't want
>    to due to the other reasons listed.
> 
> I am very happy to have completely excised it from my driver. IMO there should
> be big warning signs on the CCF warning not to use it for new code. This would
> hopefully dissuade those like myself who had no idea that CCF was *not* in fact
> a good way to write a clock driver.
> 
> Overall there is a total savings of 12k from this series.
>     text	   data	    bss	    dec	    hex	filename
>   292485	  32672	  12624	 337781	  52775	before/u-boot
>   283125	  29856	  12624	 325605	  4f7e5	after/u-boot
> 
> This series depends on
> https://patchwork.ozlabs.org/project/uboot/list/?series=238211
> 
> Changes in v3:
> - Always define clk_defaults_stage, even if clk_set_defaults is a dummy
> - Fix inverted condition for setting defaults
> - Fix val not being set for K210_DIV_POWER
> - Add CLK_K210_SET_RATE to defconfig so these changes apply
> 
> Changes in v2:
> - Convert stage to enum
> - Only force probe clocks pre-reloc
> - Rebase on u-boot/master
> 
> Sean Anderson (11):
>    clk: Allow force setting clock defaults before relocation
>    clk: k210: Rewrite to remove CCF
>    clk: k210: Move pll into the rest of the driver
>    clk: k210: Implement soc_clk_dump
>    clk: k210: Re-add support for setting rate
>    clk: k210: Don't set PLL rates if we are already at the correct rate
>    clk: k210: Remove bypass driver
>    clk: k210: Move k210 clock out of its own subdirectory
>    k210: dts: Set PLL1 to the same rate as PLL0
>    k210: Don't imply CCF
>    test: Add K210 PLL tests to sandbox defconfigs
> 
>   MAINTAINERS                             |    4 +-
>   arch/riscv/dts/k210.dtsi                |    2 +
>   board/sipeed/maix/Kconfig               |    2 -
>   configs/sandbox64_defconfig             |    2 +
>   configs/sandbox_defconfig               |    2 +
>   configs/sandbox_flattree_defconfig      |    2 +
>   configs/sipeed_maix_bitm_defconfig      |    2 +-
>   drivers/clk/Kconfig                     |   14 +-
>   drivers/clk/Makefile                    |    2 +-
>   drivers/clk/clk-uclass.c                |   27 +-
>   drivers/clk/clk_kendryte.c              | 1320 +++++++++++++++++++++++
>   drivers/clk/kendryte/Kconfig            |   12 -
>   drivers/clk/kendryte/Makefile           |    1 -
>   drivers/clk/kendryte/bypass.c           |  273 -----
>   drivers/clk/kendryte/clk.c              |  668 ------------
>   drivers/clk/kendryte/pll.c              |  585 ----------
>   drivers/clk/rockchip/clk_rk3308.c       |    2 +-
>   drivers/core/device.c                   |    2 +-
>   drivers/net/gmac_rockchip.c             |    2 +-
>   include/clk.h                           |   30 +-
>   include/dt-bindings/clock/k210-sysctl.h |   94 +-
>   include/kendryte/bypass.h               |   31 -
>   include/kendryte/clk.h                  |   35 -
>   include/kendryte/pll.h                  |   34 -
>   24 files changed, 1437 insertions(+), 1711 deletions(-)
>   create mode 100644 drivers/clk/clk_kendryte.c
>   delete mode 100644 drivers/clk/kendryte/Kconfig
>   delete mode 100644 drivers/clk/kendryte/Makefile
>   delete mode 100644 drivers/clk/kendryte/bypass.c
>   delete mode 100644 drivers/clk/kendryte/clk.c
>   delete mode 100644 drivers/clk/kendryte/pll.c
>   delete mode 100644 include/kendryte/bypass.h
>   delete mode 100644 include/kendryte/clk.h
> 

passing CI: https://dev.azure.com/seanga2/u-boot/_build/results?buildId=70&view=results

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF
  2021-06-11 13:57   ` Sean Anderson
@ 2021-06-13 23:08     ` Damien Le Moal
  0 siblings, 0 replies; 25+ messages in thread
From: Damien Le Moal @ 2021-06-13 23:08 UTC (permalink / raw)
  To: Sean Anderson, Lukasz Majewski
  Cc: u-boot, Leo Liang, Andreas Dannenberg, Lokesh Vutla, Philipp Tomsich

On 2021/06/11 22:57, Sean Anderson wrote:
> On 6/11/21 4:21 AM, Lukasz Majewski wrote:
>> On Fri, 11 Jun 2021 00:16:06 -0400
>> Sean Anderson <seanga2@gmail.com> wrote:
>>
>>> This is something I've been meaning to do for a while but only just
>>> got around to. The CCF has been quite unwieldy in a few ways:
>>>
>>> * It is very rigid, and there are not easy ways to hook into it
>>> without rewriting many things. See e.g. things like the bypass clock
>>> and all the _half clocks which were created because CCF didn't
>>> support the dividers used on the k210. While preparing this series, I
>>> encountered several edge cases which I had initially overlooked (or
>>> which were not supported in the initial release). These would have
>>> been very difficult to fix with CCF, but were much easier to address
>>> because each funcion is implemented in one place.
>>> * There is a lot of magic going on under the curtains because of all
>>> the CCF code which lives in many different files. Some things live in
>>> drivers, but many things live in e.g. clk-uclass.c. So many things
>>> live in so many files and it can be very difficult to get a handle on
>>> what exactly happens. Complicating this is that there is a conflation
>>> of struct clk as a handle and struct clk as a device. In this regard,
>>> refcounting is completely broken. IMO we should just do away with
>>> refcounts and only disable clocks when explicitly asked for.
>>> * It is very dependent on runtime initialization. Typically,
>>> everything is initialized by calling into various register()
>>> functions, usually with several wrappers to avoid specifying all the
>>> arguments. This balloons the runtime memory usage since there are so
>>> many devices created. It also makes it hard to debug, since if you do
>>> it the "typical" way it is easy to accidentally assign a clock to the
>>> wrong register.
>>> * It inflates code size by pulling in not just some dead code (e.g.
>>> this driver does not use divider tables but they are in clk-divider
>>> anyway) but also pulling in numerous imx-specific clocks. This could
>>> be fixed, but I don't want to due to the other reasons listed.
>>>
>>> I am very happy to have completely excised it from my driver. IMO
>>> there should be big warning signs on the CCF warning not to use it
>>> for new code. This would hopefully dissuade those like myself who had
>>> no idea that CCF was *not* in fact a good way to write a clock driver.
>>
>> You mean for U-Boot or for Linux ?
> 
> For U-Boot. I wasn't aware that the CCF was mainly designed for porting
> drivers from Linux.
> 
>>
>>>
>>> Overall there is a total savings of 12k from this series.
>>>     text	   data	    bss	    dec
>>> hex	filename 292485	  32672	  12624
>>> 337781	  52775	before/u-boot 283125
>>> 29856	  12624	 325605	  4f7e5	after/u-boot
>>>
>>
>> I'm not going to defend CCF to the last breath, I know their issues.
>>
>> However, the goal for CCF was to have:
>>
>> 1. Ported code from Linux (with some code simplification)
>> 2. Get the standard approach to the clock subsystem.
>>
>> I'm just wondering if we (as a community) want to have such diversity -
>> I mean each architecture would have different clock driver (under the
>> device model)
> 
> If there is already a CCF driver for that arch for Linux, then I think
> reusing it is OK. However, I think it generally tends toward larger
> drivers, larger runtime memory usage, and awkward design. So if you are
> writing a new driver for U-Boot, I think it is better to not use CCF
> drivers.
> 
>>
>> As fair as I can see - the K210 already has support for CCF in Linux:
>> drivers/clk/clk-k210.c
> 
> Yes, but it does not really "use" the CCF. For example, things like
> composite clocks are absent; all calculations of rate are internal to
> the driver. In fact, I took inspiration from Damien's handling of this
> driver in Linux.

Correct. The initial development versions of the driver were inspired (hmmm...
copied) from Sean CCF based driver, but the composite clocks and some others
were a real pain due to the weird divisors that the K210 clocks use. In the end,
I decided to not use Linux CCF, or rather, to limit its use to simple clocks
only and to implement internally all divisors for the clocks. This ended up
simplifying the code a lot. That is what went upstream.

> 
>> Reading the above comment - it looks like you couldn't simplyfy this
>> Linux driver to be smaller and fit into U-Boot?
> 
> Well, this driver takes major inspiration from the Linux driver, which
> was itself based on this code. So in a sense, this is already a
> simplification of the Linux driver.
> 
>>
>> Sean, do you think that other archs can benefit from your work?
> 
> Hm, I don't know. I don't think there is must code which could be
> reused. Some of the major savings in disabling CCF were from disabling
> imx-specific clocks which are always enabled, even though they are not
> designed to be used outside of that arch.
> 
> In terms of general improvements, I think that get_parent() should be
> part of clk_ops. That would allow me to use the existing clock dump
> code. Additionally, I think that enable_count has no business living in
> struct clk, as that struct is a "thick pointer" and multiple ones can
> exist for the same clock.
> 
> --Sean
> 
>>
>>> This series depends on
>>> https://patchwork.ozlabs.org/project/uboot/list/?series=238211
>>>
>>> Changes in v3:
>>> - Always define clk_defaults_stage, even if clk_set_defaults is a
>>> dummy
>>> - Fix inverted condition for setting defaults
>>> - Fix val not being set for K210_DIV_POWER
>>> - Add CLK_K210_SET_RATE to defconfig so these changes apply
>>>
>>> Changes in v2:
>>> - Convert stage to enum
>>> - Only force probe clocks pre-reloc
>>> - Rebase on u-boot/master
>>>
>>> Sean Anderson (11):
>>>    clk: Allow force setting clock defaults before relocation
>>>    clk: k210: Rewrite to remove CCF
>>>    clk: k210: Move pll into the rest of the driver
>>>    clk: k210: Implement soc_clk_dump
>>>    clk: k210: Re-add support for setting rate
>>>    clk: k210: Don't set PLL rates if we are already at the correct rate
>>>    clk: k210: Remove bypass driver
>>>    clk: k210: Move k210 clock out of its own subdirectory
>>>    k210: dts: Set PLL1 to the same rate as PLL0
>>>    k210: Don't imply CCF
>>>    test: Add K210 PLL tests to sandbox defconfigs
>>>
>>>   MAINTAINERS                             |    4 +-
>>>   arch/riscv/dts/k210.dtsi                |    2 +
>>>   board/sipeed/maix/Kconfig               |    2 -
>>>   configs/sandbox64_defconfig             |    2 +
>>>   configs/sandbox_defconfig               |    2 +
>>>   configs/sandbox_flattree_defconfig      |    2 +
>>>   configs/sipeed_maix_bitm_defconfig      |    2 +-
>>>   drivers/clk/Kconfig                     |   14 +-
>>>   drivers/clk/Makefile                    |    2 +-
>>>   drivers/clk/clk-uclass.c                |   27 +-
>>>   drivers/clk/clk_kendryte.c              | 1320
>>> +++++++++++++++++++++++ drivers/clk/kendryte/Kconfig            |
>>> 12 - drivers/clk/kendryte/Makefile           |    1 -
>>>   drivers/clk/kendryte/bypass.c           |  273 -----
>>>   drivers/clk/kendryte/clk.c              |  668 ------------
>>>   drivers/clk/kendryte/pll.c              |  585 ----------
>>>   drivers/clk/rockchip/clk_rk3308.c       |    2 +-
>>>   drivers/core/device.c                   |    2 +-
>>>   drivers/net/gmac_rockchip.c             |    2 +-
>>>   include/clk.h                           |   30 +-
>>>   include/dt-bindings/clock/k210-sysctl.h |   94 +-
>>>   include/kendryte/bypass.h               |   31 -
>>>   include/kendryte/clk.h                  |   35 -
>>>   include/kendryte/pll.h                  |   34 -
>>>   24 files changed, 1437 insertions(+), 1711 deletions(-)
>>>   create mode 100644 drivers/clk/clk_kendryte.c
>>>   delete mode 100644 drivers/clk/kendryte/Kconfig
>>>   delete mode 100644 drivers/clk/kendryte/Makefile
>>>   delete mode 100644 drivers/clk/kendryte/bypass.c
>>>   delete mode 100644 drivers/clk/kendryte/clk.c
>>>   delete mode 100644 drivers/clk/kendryte/pll.c
>>>   delete mode 100644 include/kendryte/bypass.h
>>>   delete mode 100644 include/kendryte/clk.h
>>>
>>
>>
>>
>> Best regards,
>>
>> Lukasz Majewski
>>
>> --
>>
>> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
>> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
>> Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
>>
> 
> 


-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 02/11] clk: k210: Rewrite to remove CCF
  2021-06-11  4:16 ` [PATCH v3 02/11] clk: k210: Rewrite to remove CCF Sean Anderson
@ 2021-06-16  1:54   ` Leo Liang
  0 siblings, 0 replies; 25+ messages in thread
From: Leo Liang @ 2021-06-16  1:54 UTC (permalink / raw)
  To: Sean Anderson; +Cc: u-boot

On Fri, Jun 11, 2021 at 12:16:08PM +0800, Sean Anderson wrote:
> This is effectively a complete rewrite to remove all dependency on CCF.
> The code is now smaller, and so is the binary. It also takes up less memory
> at runtime (since we don't have to create 40 udevices). In general, I am
> much happier with this driver as much of the complexity and late binding
> has been removed.
> 
> The k210_*_params structs which were previously used to initialize CCF
> clocks are now used as the complete configuration. Since we can write our
> own division logic, we can now do away with several "half" clocks which
> only existed to provide constant factors of two.
> 
> The clock IDs have been renumbered to remove unused clocks. This may not be
> the last time they are renumbered, since we have diverged with Linux. There
> are also still a few clocks left out which may need to be added back in.
> 
> In general, I have tried to leave out behavioral changes. However, there is
> a small bugfix regarding ACLK. According to the technical reference manual,
> its mux comes *after* its divider (which is present only for PLL0). This
> would have required yet another intermediate clock to fix with CCF, but
> with the new driver it is just 2 lines of code :)
> 
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> ---
> 
> (no changes since v1)
> 
>  drivers/clk/kendryte/Kconfig            |   2 +-
>  drivers/clk/kendryte/clk.c              | 848 +++++++++++-------------
>  drivers/clk/kendryte/pll.c              | 114 ++--
>  include/dt-bindings/clock/k210-sysctl.h |  94 ++-
>  include/kendryte/pll.h                  |  26 +-
>  5 files changed, 499 insertions(+), 585 deletions(-)

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 03/11] clk: k210: Move pll into the rest of the driver
  2021-06-11  4:16 ` [PATCH v3 03/11] clk: k210: Move pll into the rest of the driver Sean Anderson
@ 2021-06-16  1:55   ` Leo Liang
  0 siblings, 0 replies; 25+ messages in thread
From: Leo Liang @ 2021-06-16  1:55 UTC (permalink / raw)
  To: Sean Anderson; +Cc: u-boot

On Fri, Jun 11, 2021 at 12:16:09PM +0800, Sean Anderson wrote:
> Now that there no separate PLL driver, we can no longer make the PLL
> functions static. By moving the PLL driver in with the rest of the clock
> code, we can make these functions static again. We still keep the pll
> header for unit testing, but it is pretty reduced.
> 
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> ---
> 
> (no changes since v1)
> 
>  drivers/clk/kendryte/Makefile |   2 +-
>  drivers/clk/kendryte/clk.c    | 606 +++++++++++++++++++++++++++++++++-
>  drivers/clk/kendryte/pll.c    | 587 --------------------------------
>  include/kendryte/clk.h        |  35 --
>  include/kendryte/pll.h        |  34 --
>  5 files changed, 601 insertions(+), 663 deletions(-)
>  delete mode 100644 drivers/clk/kendryte/pll.c
>  delete mode 100644 include/kendryte/clk.h

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 04/11] clk: k210: Implement soc_clk_dump
  2021-06-11  4:16 ` [PATCH v3 04/11] clk: k210: Implement soc_clk_dump Sean Anderson
@ 2021-06-16  1:56   ` Leo Liang
  0 siblings, 0 replies; 25+ messages in thread
From: Leo Liang @ 2021-06-16  1:56 UTC (permalink / raw)
  To: Sean Anderson; +Cc: u-boot

On Fri, Jun 11, 2021 at 12:16:10PM +0800, Sean Anderson wrote:
> Since we are no longer using CCF we cannot use the default soc_clk_dump.
> Instead, implement our own.
> 
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> ---
> 
> (no changes since v1)
> 
>  drivers/clk/kendryte/clk.c | 68 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 66 insertions(+), 2 deletions(-)

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 05/11] clk: k210: Re-add support for setting rate
  2021-06-11  4:16 ` [PATCH v3 05/11] clk: k210: Re-add support for setting rate Sean Anderson
@ 2021-06-16  1:57   ` Leo Liang
  0 siblings, 0 replies; 25+ messages in thread
From: Leo Liang @ 2021-06-16  1:57 UTC (permalink / raw)
  To: Sean Anderson; +Cc: u-boot

On Fri, Jun 11, 2021 at 12:16:11PM +0800, Sean Anderson wrote:
> This adds support for setting clock rates, which was left out of the
> initial CCF expunging. There are several tricky bits here, mostly related
> to the PLLS:
> 
> * The PLL's bypass is broken. If the PLL is reconfigured, any child clocks
>   will be stopped.
> * PLL0 is the parent of ACLK which is the CPU and SRAM's clock. To prevent
>   stopping the CPU while we configure PLL0's rate, ACLK is reparented
>   to IN0 while PLL0 is disabled.
> * PLL1 is the parent of the AISRAM clock. This clock cannot be reparented,
>   so we instead just disallow changing PLL1's rate after relocation (when
>   we are using the AISRAM).
> 
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> ---
> 
> Changes in v3:
> - Fix inverted condition for setting defaults
> - Fix val not being set for K210_DIV_POWER
> 
> Changes in v2:
> - Only force probe clocks pre-reloc
> 
>  drivers/clk/kendryte/clk.c | 89 +++++++++++++++++++++++++++++++++++---
>  1 file changed, 84 insertions(+), 5 deletions(-)

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 06/11] clk: k210: Don't set PLL rates if we are already at the correct rate
  2021-06-11  4:16 ` [PATCH v3 06/11] clk: k210: Don't set PLL rates if we are already at the correct rate Sean Anderson
@ 2021-06-16  1:58   ` Leo Liang
  0 siblings, 0 replies; 25+ messages in thread
From: Leo Liang @ 2021-06-16  1:58 UTC (permalink / raw)
  To: Sean Anderson; +Cc: u-boot

On Fri, Jun 11, 2021 at 12:16:12PM +0800, Sean Anderson wrote:
> This speeds up boot by preventing multiple reconfigurations of the PLLs.
> 
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> ---
> 
> (no changes since v1)
> 
>  drivers/clk/kendryte/clk.c | 15 ++++++++-------
>  1 file changed, 8 insertions(+), 7 deletions(-)

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 07/11] clk: k210: Remove bypass driver
  2021-06-11  4:16 ` [PATCH v3 07/11] clk: k210: Remove bypass driver Sean Anderson
@ 2021-06-16  1:59   ` Leo Liang
  0 siblings, 0 replies; 25+ messages in thread
From: Leo Liang @ 2021-06-16  1:59 UTC (permalink / raw)
  To: Sean Anderson; +Cc: u-boot

On Fri, Jun 11, 2021 at 12:16:13PM +0800, Sean Anderson wrote:
> This driver no longer serves a purpose now that we have moved away from
> CCF. Drop it.
> 
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> ---
> 
> (no changes since v1)
> 
>  drivers/clk/kendryte/Makefile |   2 +-
>  drivers/clk/kendryte/bypass.c | 273 ----------------------------------
>  include/kendryte/bypass.h     |  31 ----
>  3 files changed, 1 insertion(+), 305 deletions(-)
>  delete mode 100644 drivers/clk/kendryte/bypass.c
>  delete mode 100644 include/kendryte/bypass.h
>

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 08/11] clk: k210: Move k210 clock out of its own subdirectory
  2021-06-11  4:16 ` [PATCH v3 08/11] clk: k210: Move k210 clock out of its own subdirectory Sean Anderson
@ 2021-06-16  2:01   ` Leo Liang
  0 siblings, 0 replies; 25+ messages in thread
From: Leo Liang @ 2021-06-16  2:01 UTC (permalink / raw)
  To: Sean Anderson; +Cc: u-boot

On Fri, Jun 11, 2021 at 12:16:14PM +0800, Sean Anderson wrote:
> Now that we have only one clock driver, we don't need to have our own
> subdirectory. Move the driver back with the rest of the clock drivers.
> 
> The MAINTAINERS for kendryte pinctrl is also fixed since it has always been
> wrong.
> 
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> ---
> 
> (no changes since v1)
> 
>  MAINTAINERS                                    |  4 ++--
>  drivers/clk/Kconfig                            | 14 +++++++++++++-
>  drivers/clk/Makefile                           |  2 +-
>  drivers/clk/{kendryte/clk.c => clk_kendryte.c} |  0
>  drivers/clk/kendryte/Kconfig                   | 12 ------------
>  drivers/clk/kendryte/Makefile                  |  1 -
>  6 files changed, 16 insertions(+), 17 deletions(-)
>  rename drivers/clk/{kendryte/clk.c => clk_kendryte.c} (100%)
>  delete mode 100644 drivers/clk/kendryte/Kconfig
>  delete mode 100644 drivers/clk/kendryte/Makefile

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 09/11] k210: dts: Set PLL1 to the same rate as PLL0
  2021-06-11  4:16 ` [PATCH v3 09/11] k210: dts: Set PLL1 to the same rate as PLL0 Sean Anderson
@ 2021-06-16  2:01   ` Leo Liang
  0 siblings, 0 replies; 25+ messages in thread
From: Leo Liang @ 2021-06-16  2:01 UTC (permalink / raw)
  To: Sean Anderson; +Cc: u-boot

On Fri, Jun 11, 2021 at 12:16:15PM +0800, Sean Anderson wrote:
> Linux has had some stability issues when using AISRAM with a different
> frequency from SRAM. Mirror their change here now that we relocate into
> AISRAM.
> 
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> ---
> 
> Changes in v3:
> - Add CLK_K210_SET_RATE to defconfig so these changes apply
> 
>  arch/riscv/dts/k210.dtsi           | 2 ++
>  configs/sipeed_maix_bitm_defconfig | 1 +
>  2 files changed, 3 insertions(+)

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 10/11] k210: Don't imply CCF
  2021-06-11  4:16 ` [PATCH v3 10/11] k210: Don't imply CCF Sean Anderson
@ 2021-06-16  2:02   ` Leo Liang
  0 siblings, 0 replies; 25+ messages in thread
From: Leo Liang @ 2021-06-16  2:02 UTC (permalink / raw)
  To: Sean Anderson; +Cc: u-boot

On Fri, Jun 11, 2021 at 12:16:16PM +0800, Sean Anderson wrote:
> Now that the k210 clock driver does not depend on CCF, we should no longer
> imply it (and probably should not have in the first place). We can also
> reduce the pre-relocation malloc arena back to something sensible.
> 
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> ---
> 
> (no changes since v1)
> 
>  board/sipeed/maix/Kconfig          | 2 --
>  configs/sipeed_maix_bitm_defconfig | 1 -
>  2 files changed, 3 deletions(-)
>

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2021-06-16  2:03 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-11  4:16 [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Sean Anderson
2021-06-11  4:16 ` [PATCH v3 01/11] clk: Allow force setting clock defaults before relocation Sean Anderson
2021-06-11  4:16 ` [PATCH v3 02/11] clk: k210: Rewrite to remove CCF Sean Anderson
2021-06-16  1:54   ` Leo Liang
2021-06-11  4:16 ` [PATCH v3 03/11] clk: k210: Move pll into the rest of the driver Sean Anderson
2021-06-16  1:55   ` Leo Liang
2021-06-11  4:16 ` [PATCH v3 04/11] clk: k210: Implement soc_clk_dump Sean Anderson
2021-06-16  1:56   ` Leo Liang
2021-06-11  4:16 ` [PATCH v3 05/11] clk: k210: Re-add support for setting rate Sean Anderson
2021-06-16  1:57   ` Leo Liang
2021-06-11  4:16 ` [PATCH v3 06/11] clk: k210: Don't set PLL rates if we are already at the correct rate Sean Anderson
2021-06-16  1:58   ` Leo Liang
2021-06-11  4:16 ` [PATCH v3 07/11] clk: k210: Remove bypass driver Sean Anderson
2021-06-16  1:59   ` Leo Liang
2021-06-11  4:16 ` [PATCH v3 08/11] clk: k210: Move k210 clock out of its own subdirectory Sean Anderson
2021-06-16  2:01   ` Leo Liang
2021-06-11  4:16 ` [PATCH v3 09/11] k210: dts: Set PLL1 to the same rate as PLL0 Sean Anderson
2021-06-16  2:01   ` Leo Liang
2021-06-11  4:16 ` [PATCH v3 10/11] k210: Don't imply CCF Sean Anderson
2021-06-16  2:02   ` Leo Liang
2021-06-11  4:16 ` [PATCH v3 11/11] test: Add K210 PLL tests to sandbox defconfigs Sean Anderson
2021-06-11  8:21 ` [PATCH v3 00/11] clk: k210: Rewrite K210 clock without CCF Lukasz Majewski
2021-06-11 13:57   ` Sean Anderson
2021-06-13 23:08     ` Damien Le Moal
2021-06-11 23:14 ` Sean Anderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.