Просмотр исходного кода

Merge branch 'next' of https://source.denx.de/u-boot/custodians/u-boot-riscv into next

- K210 updates
Tom Rini 2 лет назад
Родитель
Сommit
e87a933406

+ 2 - 2
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

+ 2 - 0
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;
 				};
 

+ 0 - 2
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

+ 2 - 0
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

+ 2 - 0
configs/sandbox_defconfig

@@ -131,6 +131,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

+ 2 - 0
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

+ 1 - 1
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
@@ -13,6 +12,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

+ 13 - 1
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"

+ 1 - 1
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

+ 17 - 10
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;
@@ -260,10 +261,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;
 
@@ -289,7 +290,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;
@@ -338,10 +340,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;
 
@@ -364,16 +366,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));
 
@@ -844,7 +851,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;
 }

+ 1320 - 0
drivers/clk/clk_kendryte.c

@@ -0,0 +1,1320 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ */
+#define LOG_CATEGORY UCLASS_CLK
+
+#include <common.h>
+#include <clk.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm.h>
+#include <log.h>
+#include <mapmem.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>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * 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.
+ * These parameters are then initialized by the clock which uses them during
+ * probe. To save space, ids are automatically generated for each sub-clock by
+ * using an enum. Instead of storing a parameter struct for each clock, even for
+ * those clocks which don't use a particular type of sub-clock, we can just
+ * store the parameters for the clocks which need them.
+ *
+ * So why do it like this? Arranging all the sub-clocks together makes it very
+ * easy to find bugs in the code.
+ */
+
+/**
+ * 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(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_id {
+#define DIV(id, ...) DIVIFY(id),
+#define DIV_FIXED DIV
+	DIV_LIST
+#undef DIV
+#undef DIV_FIXED
+	K210_CLK_DIV_NONE,
+};
+
+static const struct k210_div_params k210_divs[] = {
+#define DIV(id, _off, _shift, _width, _type) \
+	[DIVIFY(id)] = { \
+		.type = (_type), \
+		.off = (_off), \
+		.shift = (_shift), \
+		.width = (_width), \
+	},
+#define DIV_FIXED(id, _div) \
+	[DIVIFY(id)] = { \
+		.type = K210_DIV_FIXED, \
+		.div = (_div) \
+	},
+	DIV_LIST
+#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) \
+	GATE(K210_CLK_SRAM1,  K210_SYSCTL_EN_CENT,  2) \
+	GATE(K210_CLK_APB0,   K210_SYSCTL_EN_CENT,  3) \
+	GATE(K210_CLK_APB1,   K210_SYSCTL_EN_CENT,  4) \
+	GATE(K210_CLK_APB2,   K210_SYSCTL_EN_CENT,  5) \
+	GATE(K210_CLK_ROM,    K210_SYSCTL_EN_PERI,  0) \
+	GATE(K210_CLK_DMA,    K210_SYSCTL_EN_PERI,  1) \
+	GATE(K210_CLK_AI,     K210_SYSCTL_EN_PERI,  2) \
+	GATE(K210_CLK_DVP,    K210_SYSCTL_EN_PERI,  3) \
+	GATE(K210_CLK_FFT,    K210_SYSCTL_EN_PERI,  4) \
+	GATE(K210_CLK_GPIO,   K210_SYSCTL_EN_PERI,  5) \
+	GATE(K210_CLK_SPI0,   K210_SYSCTL_EN_PERI,  6) \
+	GATE(K210_CLK_SPI1,   K210_SYSCTL_EN_PERI,  7) \
+	GATE(K210_CLK_SPI2,   K210_SYSCTL_EN_PERI,  8) \
+	GATE(K210_CLK_SPI3,   K210_SYSCTL_EN_PERI,  9) \
+	GATE(K210_CLK_I2S0,   K210_SYSCTL_EN_PERI, 10) \
+	GATE(K210_CLK_I2S1,   K210_SYSCTL_EN_PERI, 11) \
+	GATE(K210_CLK_I2S2,   K210_SYSCTL_EN_PERI, 12) \
+	GATE(K210_CLK_I2C0,   K210_SYSCTL_EN_PERI, 13) \
+	GATE(K210_CLK_I2C1,   K210_SYSCTL_EN_PERI, 14) \
+	GATE(K210_CLK_I2C2,   K210_SYSCTL_EN_PERI, 15) \
+	GATE(K210_CLK_UART1,  K210_SYSCTL_EN_PERI, 16) \
+	GATE(K210_CLK_UART2,  K210_SYSCTL_EN_PERI, 17) \
+	GATE(K210_CLK_UART3,  K210_SYSCTL_EN_PERI, 18) \
+	GATE(K210_CLK_AES,    K210_SYSCTL_EN_PERI, 19) \
+	GATE(K210_CLK_FPIOA,  K210_SYSCTL_EN_PERI, 20) \
+	GATE(K210_CLK_TIMER0, K210_SYSCTL_EN_PERI, 21) \
+	GATE(K210_CLK_TIMER1, K210_SYSCTL_EN_PERI, 22) \
+	GATE(K210_CLK_TIMER2, K210_SYSCTL_EN_PERI, 23) \
+	GATE(K210_CLK_WDT0,   K210_SYSCTL_EN_PERI, 24) \
+	GATE(K210_CLK_WDT1,   K210_SYSCTL_EN_PERI, 25) \
+	GATE(K210_CLK_SHA,    K210_SYSCTL_EN_PERI, 26) \
+	GATE(K210_CLK_OTP,    K210_SYSCTL_EN_PERI, 27) \
+	GATE(K210_CLK_RTC,    K210_SYSCTL_EN_PERI, 29)
+
+#define _GATEIFY(id) K210_CLK_GATE_##id
+#define GATEIFY(id) _GATEIFY(id)
+
+enum k210_gate_id {
+#define GATE(id, ...) GATEIFY(id),
+	GATE_LIST
+#undef GATE
+	K210_CLK_GATE_NONE,
+};
+
+static const struct k210_gate_params k210_gates[] = {
+#define GATE(id, _off, _idx) \
+	[GATEIFY(id)] = { \
+		.off = (_off), \
+		.bit_idx = (_idx), \
+	},
+	GATE_LIST
+#undef GATE
+};
+
+#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, reg, shift, width, K210_CLK_IN0, K210_CLK_PLL0)
+#define MUX_LIST \
+	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) \
+	MUX(K210_CLK_TIMER2, K210_SYSCTL_SEL0, 15, 1)
+
+#define _MUXIFY(id) K210_CLK_MUX_##id
+#define MUXIFY(id) _MUXIFY(id)
+
+enum k210_mux_id {
+#define MUX_PARENTS(id, ...) MUXIFY(id),
+	MUX_LIST
+#undef MUX_PARENTS
+	K210_CLK_MUX_NONE,
+};
+
+static const struct k210_mux_params k210_muxes[] = {
+#define MUX_PARENTS(id, _off, _shift, _width, ...) \
+	[MUXIFY(id)] = { \
+		.parents = { __VA_ARGS__ }, \
+		.num_parents = __count_args(__VA_ARGS__), \
+		.off = (_off), \
+		.shift = (_shift), \
+		.width = (_width), \
+	},
+	MUX_LIST
+#undef MUX_PARENTS
+};
+
+#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
+ * @K210_CLKF_PLL: This clock is a PLL
+ */
+enum k210_clk_flags {
+	K210_CLKF_MUX = BIT(0),
+	K210_CLKF_PLL = BIT(1),
+};
+
+/**
+ * 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;
+		};
+	};
+};
+
+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,
+	},
+	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
+};
+
+#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;
+	ulong calc_rate;
+
+	if (rate_in < 0)
+		return 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 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);
+	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);
+
+	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);
+	}
+}
+
+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 (k210_pll_enabled(reg))
+		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)
+{
+	u32 reg = readl(priv->base + off);
+
+	return (reg >> shift) & (BIT(width) - 1);
+}
+
+static void k210_clk_writel(struct k210_clk_priv *priv, u8 off, u8 shift,
+			    u8 width, u32 val)
+{
+	u32 reg = readl(priv->base + off);
+	u32 mask = (BIT(width) - 1) << shift;
+
+	reg &= ~mask;
+	reg |= mask & (val << shift);
+	writel(reg, priv->base + off);
+}
+
+static int k210_clk_get_parent(struct k210_clk_priv *priv, int id)
+{
+	u32 sel;
+	const struct k210_mux_params *mux;
+
+	if (!(k210_clks[id].flags & K210_CLKF_MUX))
+		return k210_clks[id].parent;
+	mux = &k210_muxes[k210_clks[id].mux];
+
+	sel = k210_clk_readl(priv, mux->off, mux->shift, mux->width);
+	assert(sel < mux->num_parents);
+	return mux->parents[sel];
+}
+
+static ulong do_k210_clk_get_rate(struct k210_clk_priv *priv, int id)
+{
+	int parent;
+	u32 val;
+	ulong parent_rate;
+	const struct k210_div_params *div;
+
+	if (id == K210_CLK_IN0)
+		return clk_get_rate(&priv->in0);
+
+	parent = k210_clk_get_parent(priv, id);
+	parent_rate = do_k210_clk_get_rate(priv, parent);
+
+	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;
+	};
+}
+
+static ulong k210_clk_get_rate(struct clk *clk)
+{
+	return do_k210_clk_get_rate(dev_get_priv(clk->dev), clk->id);
+}
+
+static int do_k210_clk_set_parent(struct k210_clk_priv *priv, int id, int new)
+{
+	int i;
+	const struct k210_mux_params *mux;
+
+	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 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);
+	const struct k210_gate_params *gate;
+
+	if (id == K210_CLK_IN0) {
+		if (enable)
+			return clk_enable(&priv->in0);
+		else
+			return clk_disable(&priv->in0);
+	}
+
+	/* 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;
+	}
+
+	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);
+	}
+
+	if (k210_clks[id].gate == K210_CLK_GATE_NONE)
+		return -ENOSYS;
+	gate = &k210_gates[k210_clks[id].gate];
+
+	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;
+	struct k210_clk_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr_ptr(dev_get_parent(dev));
+	if (!priv->base)
+		return -EINVAL;
+
+	ret = clk_get_by_index(dev, 0, &priv->in0);
+	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;
+}
+
+static const struct udevice_id k210_clk_ids[] = {
+	{ .compatible = "kendryte,k210-clk" },
+	{ },
+};
+
+U_BOOT_DRIVER(k210_clk) = {
+	.name = "k210_clk",
+	.id = UCLASS_CLK,
+	.of_match = k210_clk_ids,
+	.ops = &k210_clk_ops,
+	.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

+ 0 - 12
drivers/clk/kendryte/Kconfig

@@ -1,12 +0,0 @@
-config CLK_K210
-	bool "Clock support for Kendryte K210"
-	depends on CLK && CLK_CCF && CLK_COMPOSITE_CCF
-	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.

+ 0 - 1
drivers/clk/kendryte/Makefile

@@ -1 +0,0 @@
-obj-y += bypass.o clk.o pll.o

+ 0 - 273
drivers/clk/kendryte/bypass.c

@@ -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,
-};

+ 0 - 668
drivers/clk/kendryte/clk.c

@@ -1,668 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
- */
-#include <kendryte/clk.h>
-
-#include <asm/io.h>
-#include <dt-bindings/clock/k210-sysctl.h>
-#include <dt-bindings/mfd/k210-sysctl.h>
-#include <dm.h>
-#include <log.h>
-#include <mapmem.h>
-
-#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
- * probe. To save space, ids are automatically generated for each sub-clock by
- * using an enum. Instead of storing a parameter struct for each clock, even for
- * those clocks which don't use a particular type of sub-clock, we can just
- * store the parameters for the clocks which need them.
- *
- * So why do it like this? Arranging all the sub-clocks together makes it very
- * easy to find bugs in the code.
- */
-
-#define DIV(id, off, shift, width) DIV_FLAGS(id, off, shift, width, 0)
-#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)
-
-#define _DIVIFY(id) K210_CLK_DIV_##id
-#define DIVIFY(id) _DIVIFY(id)
-
-enum k210_div_ids {
-#define DIV_FLAGS(id, ...) DIVIFY(id),
-	DIV_LIST
-#undef DIV_FLAGS
-};
-
-struct k210_div_params {
-	u8 off;
-	u8 shift;
-	u8 width;
-	u8 flags;
-};
-
-static const struct k210_div_params k210_divs[] = {
-#define DIV_FLAGS(id, _off, _shift, _width, _flags) \
-	[DIVIFY(id)] = { \
-		.off = (_off), \
-		.shift = (_shift), \
-		.width = (_width), \
-		.flags = (_flags), \
-	},
-	DIV_LIST
-#undef DIV_FLAGS
-};
-
-#undef DIV
-#undef DIV_LIST
-
-#define GATE_LIST \
-	GATE(K210_CLK_CPU,    K210_SYSCTL_EN_CENT,  0) \
-	GATE(K210_CLK_SRAM0,  K210_SYSCTL_EN_CENT,  1) \
-	GATE(K210_CLK_SRAM1,  K210_SYSCTL_EN_CENT,  2) \
-	GATE(K210_CLK_APB0,   K210_SYSCTL_EN_CENT,  3) \
-	GATE(K210_CLK_APB1,   K210_SYSCTL_EN_CENT,  4) \
-	GATE(K210_CLK_APB2,   K210_SYSCTL_EN_CENT,  5) \
-	GATE(K210_CLK_ROM,    K210_SYSCTL_EN_PERI,  0) \
-	GATE(K210_CLK_DMA,    K210_SYSCTL_EN_PERI,  1) \
-	GATE(K210_CLK_AI,     K210_SYSCTL_EN_PERI,  2) \
-	GATE(K210_CLK_DVP,    K210_SYSCTL_EN_PERI,  3) \
-	GATE(K210_CLK_FFT,    K210_SYSCTL_EN_PERI,  4) \
-	GATE(K210_CLK_GPIO,   K210_SYSCTL_EN_PERI,  5) \
-	GATE(K210_CLK_SPI0,   K210_SYSCTL_EN_PERI,  6) \
-	GATE(K210_CLK_SPI1,   K210_SYSCTL_EN_PERI,  7) \
-	GATE(K210_CLK_SPI2,   K210_SYSCTL_EN_PERI,  8) \
-	GATE(K210_CLK_SPI3,   K210_SYSCTL_EN_PERI,  9) \
-	GATE(K210_CLK_I2S0,   K210_SYSCTL_EN_PERI, 10) \
-	GATE(K210_CLK_I2S1,   K210_SYSCTL_EN_PERI, 11) \
-	GATE(K210_CLK_I2S2,   K210_SYSCTL_EN_PERI, 12) \
-	GATE(K210_CLK_I2C0,   K210_SYSCTL_EN_PERI, 13) \
-	GATE(K210_CLK_I2C1,   K210_SYSCTL_EN_PERI, 14) \
-	GATE(K210_CLK_I2C2,   K210_SYSCTL_EN_PERI, 15) \
-	GATE(K210_CLK_UART1,  K210_SYSCTL_EN_PERI, 16) \
-	GATE(K210_CLK_UART2,  K210_SYSCTL_EN_PERI, 17) \
-	GATE(K210_CLK_UART3,  K210_SYSCTL_EN_PERI, 18) \
-	GATE(K210_CLK_AES,    K210_SYSCTL_EN_PERI, 19) \
-	GATE(K210_CLK_FPIOA,  K210_SYSCTL_EN_PERI, 20) \
-	GATE(K210_CLK_TIMER0, K210_SYSCTL_EN_PERI, 21) \
-	GATE(K210_CLK_TIMER1, K210_SYSCTL_EN_PERI, 22) \
-	GATE(K210_CLK_TIMER2, K210_SYSCTL_EN_PERI, 23) \
-	GATE(K210_CLK_WDT0,   K210_SYSCTL_EN_PERI, 24) \
-	GATE(K210_CLK_WDT1,   K210_SYSCTL_EN_PERI, 25) \
-	GATE(K210_CLK_SHA,    K210_SYSCTL_EN_PERI, 26) \
-	GATE(K210_CLK_OTP,    K210_SYSCTL_EN_PERI, 27) \
-	GATE(K210_CLK_RTC,    K210_SYSCTL_EN_PERI, 29)
-
-#define _GATEIFY(id) K210_CLK_GATE_##id
-#define GATEIFY(id) _GATEIFY(id)
-
-enum k210_gate_ids {
-#define GATE(id, ...) GATEIFY(id),
-	GATE_LIST
-#undef GATE
-};
-
-struct k210_gate_params {
-	u8 off;
-	u8 bit_idx;
-};
-
-static const struct k210_gate_params k210_gates[] = {
-#define GATE(id, _off, _idx) \
-	[GATEIFY(id)] = { \
-		.off = (_off), \
-		.bit_idx = (_idx), \
-	},
-	GATE_LIST
-#undef GATE
-};
-
-#undef GATE_LIST
-
-#define MUX(id, reg, shift, width) \
-	MUX_PARENTS(id, generic_sels, reg, shift, width)
-#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(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) \
-	MUX(K210_CLK_TIMER2, K210_SYSCTL_SEL0, 15, 1)
-
-#define _MUXIFY(id) K210_CLK_MUX_##id
-#define MUXIFY(id) _MUXIFY(id)
-
-enum k210_mux_ids {
-#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) \
-	[MUXIFY(id)] = { \
-		.parent_names = (const char * const *)(parents), \
-		.num_parents = ARRAY_SIZE(parents), \
-		.off = (_off), \
-		.shift = (_shift), \
-		.width = (_width), \
-	},
-	MUX_LIST
-#undef MUX_PARENTS
-};
-
-#undef MUX
-#undef MUX_LIST
-
-struct k210_pll_params {
-	u8 off;
-	u8 lock_off;
-	u8 shift;
-	u8 width;
-};
-
-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
-};
-
-#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)] = { \
-		.mux = (_mux), \
-		.div = (_div), \
-		.gate = (_gate), \
-	},
-	COMP_LIST
-#undef COMP_FULL
-};
-
-#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)
-{
-	struct clk_mux *mux = kzalloc(sizeof(*mux), GFP_KERNEL);
-
-	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;
-}
-
-static struct clk_divider *k210_create_div(const struct k210_div_params *params,
-					   void *base)
-{
-	struct clk_divider *div = kzalloc(sizeof(*div), GFP_KERNEL);
-
-	if (!div)
-		return div;
-
-	div->reg = base + params->off;
-	div->shift = params->shift;
-	div->width = params->width;
-	div->flags = params->flags;
-
-	return div;
-}
-
-static struct clk_gate *k210_create_gate(const struct k210_gate_params *params,
-					 void *base)
-{
-	struct clk_gate *gate = kzalloc(sizeof(*gate), GFP_KERNEL);
-
-	if (!gate)
-		return gate;
-
-	gate->reg = base + params->off;
-	gate->bit_idx = params->bit_idx;
-
-	return gate;
-}
-
-static struct k210_pll *k210_create_pll(const struct k210_pll_params *params,
-					void *base)
-{
-	struct k210_pll *pll = kzalloc(sizeof(*pll), GFP_KERNEL);
-
-	if (!pll)
-		return pll;
-
-	pll->reg = base + params->off;
-	pll->lock = base + params->lock_off;
-	pll->shift = params->shift;
-	pll->width = params->width;
-
-	return pll;
-}
-
-/* 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)
-{
-	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;
-
-	if (params->mux == K210_CLK_MUX_NONE) {
-		if (!parent)
-			return ERR_PTR(-EINVAL);
-
-		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);
-
-		parent_names = mux->parent_names;
-		num_parents = mux->num_parents;
-	}
-
-	div = k210_create_div(&k210_divs[params->div], base);
-	if (!div) {
-		comp = ERR_PTR(-ENOMEM);
-		goto cleanup_mux;
-	}
-
-	gate = k210_create_gate(&k210_gates[params->gate], base);
-	if (!gate) {
-		comp = ERR_PTR(-ENOMEM);
-		goto cleanup_div;
-	}
-
-	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;
-
-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;
-	return 0;
-}
-
-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;
-
-	/*
-	 * 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)
-		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);
-	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;
-}
-
-static const struct udevice_id k210_clk_ids[] = {
-	{ .compatible = "kendryte,k210-clk" },
-	{ },
-};
-
-U_BOOT_DRIVER(k210_clk) = {
-	.name = "k210_clk",
-	.id = UCLASS_CLK,
-	.of_match = k210_clk_ids,
-	.ops = &k210_clk_ops,
-	.bind = k210_clk_bind,
-	.probe = k210_clk_probe,
-};

+ 0 - 585
drivers/clk/kendryte/pll.c

@@ -1,585 +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 <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"
-
-#ifdef CONFIG_CLK_K210_SET_RATE
-static int k210_pll_enable(struct clk *clk);
-static int k210_pll_disable(struct clk *clk);
-
-/*
- * 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 clk *clk, ulong rate)
-{
-	int err;
-	long long rate_in = clk_get_parent_rate(clk);
-	struct k210_pll_config config = {};
-	struct k210_pll *pll = to_k210_pll(clk);
-	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(pll->reg);
-	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, pll->reg);
-
-	err = k210_pll_enable(clk);
-	if (err)
-		return err;
-
-	serial_setbrg();
-	return clk_get_rate(clk);
-}
-#endif /* CONFIG_CLK_K210_SET_RATE */
-
-static ulong k210_pll_get_rate(struct clk *clk)
-{
-	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);
-
-	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_pll *pll)
-{
-	u32 mask = GENMASK(pll->width - 1, 0) << pll->shift;
-
-	while (true) {
-		u32 reg = readl(pll->lock);
-
-		if ((reg & mask) == mask)
-			break;
-
-		reg |= BIT(pll->shift + K210_PLL_CLEAR_SLIP);
-		writel(reg, pll->lock);
-	}
-}
-
-/* Adapted from sysctl_pll_enable */
-static int k210_pll_enable(struct clk *clk)
-{
-	struct k210_pll *pll = to_k210_pll(clk);
-	u32 reg = readl(pll->reg);
-
-	if ((reg & K210_PLL_PWRD) && (reg & K210_PLL_EN) &&
-	    !(reg & K210_PLL_RESET))
-		return 0;
-
-	reg |= K210_PLL_PWRD;
-	writel(reg, pll->reg);
-
-	/* Ensure reset is low before asserting it */
-	reg &= ~K210_PLL_RESET;
-	writel(reg, pll->reg);
-	reg |= K210_PLL_RESET;
-	writel(reg, pll->reg);
-	nop();
-	nop();
-	reg &= ~K210_PLL_RESET;
-	writel(reg, pll->reg);
-
-	k210_pll_waitfor_lock(pll);
-
-	reg &= ~K210_PLL_BYPASS;
-	reg |= K210_PLL_EN;
-	writel(reg, pll->reg);
-
-	return 0;
-}
-
-static int k210_pll_disable(struct clk *clk)
-{
-	struct k210_pll *pll = to_k210_pll(clk);
-	u32 reg = readl(pll->reg);
-
-	/*
-	 * 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, pll->reg);
-
-	reg &= ~K210_PLL_PWRD;
-	reg &= ~K210_PLL_EN;
-	writel(reg, pll->reg);
-	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,
-};

+ 1 - 1
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);
 

+ 1 - 1
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;
 	}

+ 1 - 1
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);
 

+ 26 - 4
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)
 {

+ 46 - 48
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 */

+ 0 - 31
include/kendryte/bypass.h

@@ -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 */

+ 0 - 35
include/kendryte/clk.h

@@ -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 */

+ 0 - 34
include/kendryte/pll.h

@@ -5,35 +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 {
-	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;
@@ -44,15 +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
-
-extern const struct clk_ops k210_pll_ops;
-
-struct clk *k210_register_pll_struct(const char *name, const char *parent_name,
-				     struct k210_pll *pll);
 #endif /* K210_PLL_H */