From: Sean Anderson <seanga2@gmail.com>
To: u-boot@lists.denx.de
Subject: [PATCH v5 07/33] clk: Add K210 clock support
Date: Fri, 28 Feb 2020 16:05:25 -0500 [thread overview]
Message-ID: <20200228210552.615672-8-seanga2@gmail.com> (raw)
In-Reply-To: <20200228210552.615672-1-seanga2@gmail.com>
Due to the large number of clocks, I decided to use the CCF. The overall
structure is modeled after the imx code. Clocks are stored in several
arrays. There are some translation macros (FOOIFY()) which allow for more
dense packing. A possible improvement could be to only store the
parameters we need, instead of the whole CCF struct.
Signed-off-by: Sean Anderson <seanga2@gmail.com>
---
Changes in v5:
- Don't unmap priv->reg
- Remove comment on APB clocks since it has been clarified by Kendryte
- Add i2s mclks
- Reorder clock ids to be continuous
- Rewrite to statically allocate all clocks. This has helped find several bugs
(since it is easy to see when a clock has the wrong register).
- Fix ACLK sometimes having the wrong parent
- Fix SPI3 having the wrong divider
- Prevent being probed multiple times on failure
Changes in v4:
- Reparent aclk before configuring pll0
- Update copyright
- Lint
Changes in v3:
- Removed sysctl struct, replacing it with defines. This is to have the same
interface to sysctl from C as from the device tree.
- Fixed clocks having the same id
- Fixed clocks not using the correct register/bits
- Aligned the defines in headers
Changes in v2:
- Add clk.o to obj-y
- Don't probe before relocation
MAINTAINERS | 7 +
.../mfd/kendryte,k210-sysctl.txt | 33 ++
drivers/clk/kendryte/Kconfig | 2 +-
drivers/clk/kendryte/Makefile | 2 +-
drivers/clk/kendryte/clk.c | 478 ++++++++++++++++++
include/dt-bindings/clock/k210-sysctl.h | 56 ++
include/dt-bindings/mfd/k210-sysctl.h | 38 ++
include/kendryte/clk.h | 35 ++
8 files changed, 649 insertions(+), 2 deletions(-)
create mode 100644 doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt
create mode 100644 drivers/clk/kendryte/clk.c
create mode 100644 include/dt-bindings/clock/k210-sysctl.h
create mode 100644 include/dt-bindings/mfd/k210-sysctl.h
create mode 100644 include/kendryte/clk.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 82e4159bec..8e9e0569ba 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -805,6 +805,13 @@ F: arch/riscv/
F: cmd/riscv/
F: tools/prelink-riscv.c
+RISC-V KENDRYTE
+M: Sean Anderson <seanga2@gmail.com>
+S: Maintained
+F: doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt
+F: drivers/clk/kendryte/
+F: include/kendryte/
+
RNG
M: Sughosh Ganu <sughosh.ganu@linaro.org>
R: Heinrich Schuchardt <xypron.glpk@gmx.de>
diff --git a/doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt b/doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt
new file mode 100644
index 0000000000..5b24abcb62
--- /dev/null
+++ b/doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt
@@ -0,0 +1,33 @@
+Kendryte K210 Sysctl
+
+This binding describes the K210 sysctl device, which contains many miscellaneous
+registers controlling system functionality. This node is a register map and can
+be reference by other bindings which need a phandle to the K210 sysctl regmap.
+
+Required properties:
+- compatible: should be
+ "kendryte,k210-sysctl", "syscon", "simple-mfd"
+- reg: address and length of the sysctl registers
+- reg-io-width: must be <4>
+
+Clock sub-node
+
+This node is a binding for the clock tree driver
+
+Required properties:
+- compatible: should be "kendryte,k210-clk"
+- clocks: phandle to the "in0" external oscillator
+- #clock-cells: must be <1>
+
+Example:
+sysctl: syscon at 50440000 {
+ compatible = "kendryte,k210-sysctl", "syscon", "simple-mfd";
+ reg = <0x50440000 0x100>;
+ reg-io-width = <4>;
+
+ sysclk: clock-controller {
+ compatible = "kendryte,k210-clk";
+ clocks = <&in0>;
+ #clock-cells = <1>;
+ };
+};
diff --git a/drivers/clk/kendryte/Kconfig b/drivers/clk/kendryte/Kconfig
index 7b69c8afaf..073fca0781 100644
--- a/drivers/clk/kendryte/Kconfig
+++ b/drivers/clk/kendryte/Kconfig
@@ -1,6 +1,6 @@
config CLK_K210
bool "Clock support for Kendryte K210"
- depends on CLK && CLK_CCF
+ depends on CLK && CLK_CCF && CLK_COMPOSITE_CCF
help
This enables support clock driver for Kendryte K210 platforms.
diff --git a/drivers/clk/kendryte/Makefile b/drivers/clk/kendryte/Makefile
index 47f682fce3..6fb68253ae 100644
--- a/drivers/clk/kendryte/Makefile
+++ b/drivers/clk/kendryte/Makefile
@@ -1 +1 @@
-obj-y += bypass.o pll.o
+obj-y += bypass.o clk.o pll.o
diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/kendryte/clk.c
new file mode 100644
index 0000000000..b01d246682
--- /dev/null
+++ b/drivers/clk/kendryte/clk.c
@@ -0,0 +1,478 @@
+// 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>
+
+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,
+};
+
+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" };
+
+#define DIV(id, reg, shift, width) DIV_FLAGS(id, reg, 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)
+#define DIV_FLAGS(id, ...) DIVIFY(id),
+enum k210_clk_div_ids {
+ DIV_LIST
+};
+#undef DIV_FLAGS
+
+#define DIV_FLAGS(id, _reg, _shift, _width, _flags) [DIVIFY(id)] = { \
+ .reg = (void *)(_reg), \
+ .shift = (_shift), \
+ .width = (_width), \
+ .flags = (_flags), \
+},
+static struct clk_divider k210_clk_dividers[] = {
+ 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)
+#define GATE(id, ...) GATEIFY(id),
+enum k210_clk_gate_ids {
+ GATE_LIST
+};
+#undef GATE
+
+#define GATE(id, _reg, _idx) [GATEIFY(id)] = { \
+ .reg = (void *)(_reg), \
+ .bit_idx = (_idx), \
+},
+static struct clk_gate k210_clk_gates[] = {
+ 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)
+#define MUX_PARENTS(id, ...) MUXIFY(id),
+enum k210_clk_mux_ids {
+ MUX_LIST
+};
+#undef MUX_PARENTS
+
+#define MUX_PARENTS(id, parents, _reg, _shift, _width) [MUXIFY(id)] = { \
+ .parent_names = (const char * const *)(parents), \
+ .num_parents = ARRAY_SIZE(parents), \
+ .reg = (void *)(_reg), \
+ .shift = (_shift), \
+ .mask = BIT(_width) - 1, \
+},
+static struct clk_mux k210_clk_muxes[] = {
+ MUX_LIST
+};
+#undef MUX_PARENTS
+#undef MUX
+#undef MUX_LIST
+
+#define PLL(_reg, _shift, _width) { \
+ .reg = (void *)(_reg), \
+ .lock = (void *)K210_SYSCTL_PLL_LOCK, \
+ .shift = (_shift), \
+ .width = (_width), \
+}
+static struct k210_pll k210_clk_plls[] = {
+ [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, mux, div, gate) \
+ COMP_FULL(id, &(mux)->clk, &clk_mux_ops, \
+ &(div)->clk, &clk_divider_ops, \
+ &(gate)->clk, &clk_gate_ops)
+#define COMP_ID(id) \
+ COMP(id, &k210_clk_muxes[MUXIFY(id)], \
+ &k210_clk_dividers[DIVIFY(id)], \
+ &k210_clk_gates[GATEIFY(id)])
+#define COMP_NOMUX(id, div, gate) \
+ COMP_FULL(id, NULL, NULL, \
+ &(div)->clk, &clk_divider_ops, \
+ &(gate)->clk, &clk_gate_ops)
+#define COMP_NOMUX_ID(id) \
+ COMP_NOMUX(id, &k210_clk_dividers[DIVIFY(id)], \
+ &k210_clk_gates[GATEIFY(id)])
+#define COMP_LIST \
+ COMP_FULL(K210_CLK_PLL2, \
+ &k210_clk_muxes[MUXIFY(K210_CLK_PLL2)].clk, &clk_mux_ops, \
+ &k210_clk_plls[2].clk, &k210_pll_ops, \
+ &k210_clk_plls[2].clk, &k210_pll_ops) \
+ COMP_FULL(K210_CLK_ACLK, \
+ &k210_clk_muxes[MUXIFY(K210_CLK_ACLK)].clk, &clk_mux_ops, \
+ &k210_clk_dividers[DIVIFY(K210_CLK_ACLK)].clk, \
+ &clk_divider_ops, \
+ NULL, NULL) \
+ COMP_ID(K210_CLK_SPI3) \
+ COMP_ID(K210_CLK_TIMER0) \
+ COMP_ID(K210_CLK_TIMER1) \
+ COMP_ID(K210_CLK_TIMER2) \
+ COMP_NOMUX_ID(K210_CLK_SRAM0) \
+ COMP_NOMUX_ID(K210_CLK_SRAM1) \
+ COMP_NOMUX_ID(K210_CLK_ROM) \
+ COMP_NOMUX_ID(K210_CLK_DVP) \
+ COMP_NOMUX_ID(K210_CLK_APB0) \
+ COMP_NOMUX_ID(K210_CLK_APB1) \
+ COMP_NOMUX_ID(K210_CLK_APB2) \
+ COMP_NOMUX_ID(K210_CLK_AI) \
+ COMP_NOMUX_ID(K210_CLK_I2S0) \
+ COMP_NOMUX_ID(K210_CLK_I2S1) \
+ COMP_NOMUX_ID(K210_CLK_I2S2) \
+ COMP_NOMUX_ID(K210_CLK_WDT0) \
+ COMP_NOMUX_ID(K210_CLK_WDT1) \
+ COMP_NOMUX_ID(K210_CLK_SPI0) \
+ COMP_NOMUX_ID(K210_CLK_SPI1) \
+ COMP_NOMUX_ID(K210_CLK_SPI2) \
+ COMP_NOMUX_ID(K210_CLK_I2C0) \
+ COMP_NOMUX_ID(K210_CLK_I2C1) \
+ COMP_NOMUX_ID(K210_CLK_I2C2)
+
+#define _COMPIFY(id) K210_CLK_COMP_##id
+#define COMPIFY(id) _COMPIFY(id)
+#define COMP_FULL(id, ...) COMPIFY(id),
+enum k210_clk_comp_ids {
+ COMP_LIST
+};
+#undef COMP_FULL
+
+#define COMP_FULL(id, _mux, _mux_ops, _div, _div_ops, _gate, _gate_ops) \
+[COMPIFY(id)] = { \
+ .mux = (_mux), \
+ .mux_ops = (_mux_ops), \
+ .rate = (_div), \
+ .rate_ops = (_div_ops), \
+ .gate = (_gate), \
+ .gate_ops = (_gate_ops), \
+},
+static struct clk_composite k210_clk_comps[] = {
+ COMP_LIST
+};
+#undef COMP_FULL
+#undef COMP
+#undef COMP_ID
+#undef COMP_NOMUX
+#undef COMP_NOMUX_ID
+#undef COMP_LIST
+
+static struct clk *k210_clk_bypass_children = {
+ &k210_clk_comps[COMPIFY(K210_CLK_ACLK)].clk,
+};
+
+static struct clk *k210_clk_bypass_saved_parents = {
+ NULL,
+};
+
+static struct k210_bypass k210_clk_bypass = {
+ .bypassee = &k210_clk_plls[0].clk,
+ .bypassee_ops = &k210_pll_ops,
+ .children = &k210_clk_bypass_children,
+ .child_count = 1,
+ .saved_parents = &k210_clk_bypass_saved_parents,
+};
+
+static bool probed = false;
+
+static int k210_clk_probe(struct udevice *dev)
+{
+ int ret, i;
+ const char *in0;
+ struct clk *in0_clk;
+ void *base;
+
+ /* Only one instance of this driver allowed */
+ if (READ_ONCE(probed))
+ return -ENOTSUPP;
+
+ 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;
+
+ WRITE_ONCE(probed, true);
+
+ aclk_sels[0] = in0;
+ pll2_sels[0] = in0;
+
+ /* Fixup registers to be absolute, rather than relative */
+#define FIXUP_REGS(clocks) \
+ for (i = 0; i < ARRAY_SIZE(clocks); i++) \
+ clocks[i].reg += (ulong)base
+ FIXUP_REGS(k210_clk_dividers);
+ FIXUP_REGS(k210_clk_gates);
+ FIXUP_REGS(k210_clk_muxes);
+#undef FIXUP_REGS
+ for (i = 0; i < ARRAY_SIZE(k210_clk_plls); i++) {
+ k210_clk_plls[i].reg += (ulong)base;
+ k210_clk_plls[i].lock += (ulong)base;
+ }
+
+ /*
+ * All PLLs have a broken bypass, but pll0 has the CPU downstream, so we
+ * need to manually reparent it whenever we configure pll0
+ */
+ k210_clk_bypass.alt = in0_clk;
+ clk_dm(K210_CLK_PLL0,
+ k210_register_bypass_struct("pll0", in0, &k210_clk_bypass));
+ clk_dm(K210_CLK_PLL1,
+ k210_register_pll_struct("pll1", in0, &k210_clk_plls[1]));
+ /* PLL2 is muxed, so set up a composite clock */
+ clk_dm(K210_CLK_PLL2,
+ clk_register_composite_struct("pll2", pll2_sels,
+ ARRAY_SIZE(pll2_sels),
+ &k210_clk_comps[COMPIFY(K210_CLK_PLL2)]));
+
+ /* Half-frequency clocks for "even" dividers */
+ k210_clk_half("in0_half", in0);
+ k210_clk_half("pll0_half", "pll0");
+ k210_clk_half("pll2_half", "pll2");
+
+ /* ACLK has no gate */
+ clk_dm(K210_CLK_ACLK,
+ clk_register_composite_struct("aclk", aclk_sels,
+ ARRAY_SIZE(aclk_sels),
+ &k210_clk_comps[COMPIFY(K210_CLK_ACLK)]));
+
+#define REGISTER_COMP(id, name) \
+ clk_dm(id, clk_register_composite_struct(name, generic_sels, \
+ ARRAY_SIZE(generic_sels), \
+ &k210_clk_comps[COMPIFY(id)]))
+ 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 COMP
+
+ /* Dividing clocks, no mux */
+#define REGISTER_COMP_NOMUX(id, name, _parent) do { \
+ const char *parent = _parent; \
+ clk_dm(id, \
+ clk_register_composite_struct(name, &parent, 1, \
+ &k210_clk_comps[COMPIFY(id)])); \
+} while (false)
+ 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) clk_dm(id, \
+ clk_register_divider_struct(name, parent, \
+ &k210_clk_dividers[DIVIFY(id)]))
+ 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) \
+ clk_dm(id, clk_register_gate_struct(name, parent, \
+ &k210_clk_gates[GATEIFY(id)]))
+ 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
+
+ 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,
+};
diff --git a/include/dt-bindings/clock/k210-sysctl.h b/include/dt-bindings/clock/k210-sysctl.h
new file mode 100644
index 0000000000..16d67b282f
--- /dev/null
+++ b/include/dt-bindings/clock/k210-sysctl.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ */
+
+#ifndef CLOCK_K210_SYSCTL_H
+#define CLOCK_K210_SYSCTL_H
+
+/*
+ * Arbitrary identifiers for clocks.
+ */
+#define K210_CLK_NONE 0
+#define K210_CLK_PLL0 1
+#define K210_CLK_PLL1 2
+#define K210_CLK_PLL2 3
+#define K210_CLK_CPU 4
+#define K210_CLK_SRAM0 5
+#define K210_CLK_SRAM1 6
+#define K210_CLK_APB0 7
+#define K210_CLK_APB1 8
+#define K210_CLK_APB2 9
+#define K210_CLK_ROM 10
+#define K210_CLK_DMA 11
+#define K210_CLK_AI 12
+#define K210_CLK_DVP 13
+#define K210_CLK_FFT 14
+#define K210_CLK_GPIO 15
+#define K210_CLK_SPI0 16
+#define K210_CLK_SPI1 17
+#define K210_CLK_SPI2 18
+#define K210_CLK_SPI3 19
+#define K210_CLK_I2S0 20
+#define K210_CLK_I2S1 21
+#define K210_CLK_I2S2 22
+#define K210_CLK_I2S0_M 23
+#define K210_CLK_I2S1_M 24
+#define K210_CLK_I2S2_M 25
+#define K210_CLK_I2C0 26
+#define K210_CLK_I2C1 27
+#define K210_CLK_I2C2 28
+#define K210_CLK_UART1 29
+#define K210_CLK_UART2 30
+#define K210_CLK_UART3 31
+#define K210_CLK_AES 32
+#define K210_CLK_FPIOA 33
+#define K210_CLK_TIMER0 34
+#define K210_CLK_TIMER1 35
+#define K210_CLK_TIMER2 36
+#define K210_CLK_WDT0 37
+#define K210_CLK_WDT1 38
+#define K210_CLK_SHA 39
+#define K210_CLK_OTP 40
+#define K210_CLK_RTC 41
+#define K210_CLK_ACLK 42
+
+#endif /* CLOCK_K210_SYSCTL_H */
diff --git a/include/dt-bindings/mfd/k210-sysctl.h b/include/dt-bindings/mfd/k210-sysctl.h
new file mode 100644
index 0000000000..e16d7302cd
--- /dev/null
+++ b/include/dt-bindings/mfd/k210-sysctl.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ */
+
+#ifndef K210_SYSCTL_H
+#define K210_SYSCTL_H
+
+/* Taken from kendryte-standalone-sdk/lib/drivers/include/sysctl.h */
+#define K210_SYSCTL_GIT_ID 0x00 /* Git short commit id */
+#define K210_SYSCTL_CLK_FREQ 0x04 /* System clock base frequency */
+#define K210_SYSCTL_PLL0 0x08 /* PLL0 controller */
+#define K210_SYSCTL_PLL1 0x0C /* PLL1 controller */
+#define K210_SYSCTL_PLL2 0x10 /* PLL2 controller */
+#define K210_SYSCTL_PLL_LOCK 0x18 /* PLL lock tester */
+#define K210_SYSCTL_ROM_ERROR 0x1C /* AXI ROM detector */
+#define K210_SYSCTL_SEL0 0x20 /* Clock select controller0 */
+#define K210_SYSCTL_SEL1 0x24 /* Clock select controller1 */
+#define K210_SYSCTL_EN_CENT 0x28 /* Central clock enable */
+#define K210_SYSCTL_EN_PERI 0x2C /* Peripheral clock enable */
+#define K210_SYSCTL_SOFT_RESET 0x30 /* Soft reset ctrl */
+#define K210_SYSCTL_PERI_RESET 0x34 /* Peripheral reset controller */
+#define K210_SYSCTL_THR0 0x38 /* Clock threshold controller 0 */
+#define K210_SYSCTL_THR1 0x3C /* Clock threshold controller 1 */
+#define K210_SYSCTL_THR2 0x40 /* Clock threshold controller 2 */
+#define K210_SYSCTL_THR3 0x44 /* Clock threshold controller 3 */
+#define K210_SYSCTL_THR4 0x48 /* Clock threshold controller 4 */
+#define K210_SYSCTL_THR5 0x4C /* Clock threshold controller 5 */
+#define K210_SYSCTL_THR6 0x50 /* Clock threshold controller 6 */
+#define K210_SYSCTL_MISC 0x54 /* Miscellaneous controller */
+#define K210_SYSCTL_PERI 0x58 /* Peripheral controller */
+#define K210_SYSCTL_SPI_SLEEP 0x5C /* SPI sleep controller */
+#define K210_SYSCTL_RESET_STAT 0x60 /* Reset source status */
+#define K210_SYSCTL_DMA_SEL0 0x64 /* DMA handshake selector */
+#define K210_SYSCTL_DMA_SEL1 0x68 /* DMA handshake selector */
+#define K210_SYSCTL_POWER_SEL 0x6C /* IO Power Mode Select controller */
+
+#endif /* K210_SYSCTL_H */
diff --git a/include/kendryte/clk.h b/include/kendryte/clk.h
new file mode 100644
index 0000000000..9c6245d468
--- /dev/null
+++ b/include/kendryte/clk.h
@@ -0,0 +1,35 @@
+/* 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 */
--
2.25.0
next prev parent reply other threads:[~2020-02-28 21:05 UTC|newest]
Thread overview: 69+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-28 21:05 [PATCH v5 00/33] riscv: Add Sipeed Maix support Sean Anderson
2020-02-28 21:05 ` [PATCH v5 01/33] clk: Always use the supplied struct clk Sean Anderson
2020-02-28 21:05 ` [PATCH v5 02/33] clk: Check that ops of composite clock components exist before calling Sean Anderson
2020-02-28 21:05 ` [PATCH v5 03/33] clk: Unconditionally recursively en-/dis-able clocks Sean Anderson
2020-03-04 6:50 ` Rick Chen
2020-02-28 21:05 ` [PATCH v5 04/33] clk: Add functions to register CCF clock structs Sean Anderson
2020-02-28 21:05 ` [PATCH v5 05/33] clk: Add K210 pll support Sean Anderson
2020-02-28 21:05 ` [PATCH v5 06/33] clk: Add a bypass clock for K210 Sean Anderson
2020-02-28 21:05 ` Sean Anderson [this message]
2020-03-04 6:58 ` [PATCH v5 07/33] clk: Add K210 clock support Rick Chen
2020-03-04 14:54 ` Sean Anderson
2020-02-28 21:05 ` [PATCH v5 08/33] doc: Fix typo in FIT documentation Sean Anderson
2020-03-02 2:21 ` Bin Meng
2020-02-28 21:05 ` [PATCH v5 09/33] dm: Add support for simple-pm-bus Sean Anderson
2020-02-28 21:05 ` [PATCH v5 10/33] dm: Fix error handling for dev_read_addr_ptr Sean Anderson
2020-03-02 2:22 ` Bin Meng
2020-03-02 19:46 ` Simon Glass
2020-02-28 21:05 ` [PATCH v5 11/33] reset: Add generic reset driver Sean Anderson
2020-02-28 21:05 ` [PATCH v5 12/33] lib: Always set errno in hcreate_r Sean Anderson
2020-03-02 2:24 ` Bin Meng
2020-02-28 21:05 ` [PATCH v5 13/33] pinctrl: Add support for Kendryte K210 FPIOA Sean Anderson
2020-03-04 6:47 ` Rick Chen
2020-03-04 15:00 ` Sean Anderson
2020-02-28 21:05 ` [PATCH v5 14/33] gpio: sifive: Use generic reg read function Sean Anderson
2020-03-02 2:24 ` Bin Meng
2020-02-28 21:05 ` [PATCH v5 15/33] gpio: dw: Fix warnings about casting int to pointer Sean Anderson
2020-03-02 2:27 ` Bin Meng
2020-03-02 3:50 ` Sean Anderson
2020-02-28 21:05 ` [PATCH v5 16/33] gpio: dw: Add a trailing underscore to generated name Sean Anderson
2020-02-28 21:05 ` [PATCH v5 17/33] gpio: dw: Return output value when direction is out Sean Anderson
2020-02-28 21:05 ` [PATCH v5 18/33] led: gpio: Default to using node name if label is absent Sean Anderson
2020-02-28 21:05 ` [PATCH v5 19/33] spi: dw: Add device tree properties for fields in CTRL1 Sean Anderson
2020-03-04 6:15 ` Rick Chen
2020-03-04 15:01 ` Sean Anderson
2020-02-28 21:05 ` [PATCH v5 20/33] spi: dw: Rename "cs-gpio" to "cs-gpios" Sean Anderson
2020-02-28 21:05 ` [PATCH v5 21/33] spi: dw: Use generic function to read reg address Sean Anderson
2020-02-28 21:05 ` [PATCH v5 22/33] spi: dw: Speed up transfer loops Sean Anderson
2020-02-28 21:05 ` [PATCH v5 23/33] spi: dw: Properly set rx_end when not recieving Sean Anderson
2020-02-29 17:47 ` Sean Anderson
2020-02-28 21:05 ` [PATCH v5 24/33] spi: dw: Add mem_ops Sean Anderson
2020-02-28 21:05 ` [PATCH v5 25/33] wdt: Move asm/utils.h to log2.h Sean Anderson
2020-02-28 21:46 ` Marek Vasut
2020-02-28 22:43 ` Sean Anderson
2020-02-28 23:27 ` Marek Vasut
2020-03-03 6:58 ` Rick Chen
2020-03-03 14:11 ` Sean Anderson
2020-02-28 21:05 ` [PATCH v5 26/33] riscv: Add headers for asm/global_data.h Sean Anderson
2020-02-28 21:05 ` [PATCH v5 27/33] riscv: Fix race conditions when initializing IPI Sean Anderson
2020-03-02 9:08 ` Rick Chen
2020-03-02 15:43 ` Sean Anderson
2020-03-02 23:15 ` Lukas Auer
2020-03-03 8:27 ` Rick Chen
2020-03-05 2:18 ` Rick Chen
2020-03-02 23:17 ` Lukas Auer
2020-03-02 23:43 ` Sean Anderson
2020-03-03 21:53 ` Lukas Auer
2020-03-03 21:57 ` Sean Anderson
2020-03-04 15:25 ` Lukas Auer
2020-02-28 21:05 ` [PATCH v5 28/33] riscv: Add option to support RISC-V privileged spec 1.9 Sean Anderson
2020-03-04 6:20 ` Rick Chen
2020-02-28 21:05 ` [PATCH v5 29/33] riscv: Allow use of reset drivers Sean Anderson
2020-02-28 21:05 ` [PATCH v5 30/33] riscv: Try to get cpu frequency from a "clocks" node if it exists Sean Anderson
2020-02-28 21:05 ` [PATCH v5 31/33] riscv: Enable cpu clock if it is present Sean Anderson
2020-02-28 21:05 ` [PATCH v5 32/33] riscv: Add device tree for K210 and Sipeed Maix BitM Sean Anderson
2020-02-28 21:05 ` [PATCH v5 33/33] riscv: Add Sipeed Maix support Sean Anderson
2020-03-04 6:04 ` Rick Chen
2020-03-04 7:47 ` Rick Chen
2020-03-04 15:11 ` Sean Anderson
2020-03-05 3:40 ` Bin Meng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200228210552.615672-8-seanga2@gmail.com \
--to=seanga2@gmail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox