All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] Add real clock support for Rockchip's RK3188
@ 2014-04-16 16:36 Heiko Stübner
  2014-04-16 16:37 ` [PATCH 01/11] clk: divider: add CLK_DIVIDER_READ_ONLY flag Heiko Stübner
                   ` (10 more replies)
  0 siblings, 11 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:36 UTC (permalink / raw)
  To: linux-arm-kernel

This series add a clock driver infrastructure for Rockchip SoCs in
general and clock-definitions for the RK3188 in particular.

Due to the lack of any usable documentation of the RK3188 clocks, the
clock tree is based on my own doc [0] collected by analyzing the
clock_data code in current Rockchip kernels. As a result the gathered
data may contain errors. So to prevent API issues with the clock-ids,
the exported ones are currently limited to well understood or really
measured clocks.

The previous attempt to define parts separately in the devicetree did
not really fit with the clock structure, which became apparent with more
knowledge about the clock tree and this new driver framework, heavily
inspired by the Samsung clock driver, fits very well for clock controllers
in Rockchip SoCs.

The whole structure should support Rockchip SoCs at least down to
the RK28xx (ARM9) which all share a very similar setup of their clock
controllers in PLL, divider and gate handling as well as the included
softreset parts.


[0] https://docs.google.com/document/d/1voaR9Xk3lisCQIG3ThySOSnSHBUequljQYnceFlr53w/edit?usp=sharing

Heiko Stuebner (11):
  clk: divider: add CLK_DIVIDER_READ_ONLY flag
  clk: rockchip: add basic infrastructure
  clk: rockchip: add clock type for pll clocks and pll used on rk3066
  clk: rockchip: add special cpu clock type
  clk: rockchip: add reset controller
  dt-bindings: add documentation for rk3188 clock and reset unit
  clk: rockchip: add clock driver for rk3188 clocks
  ARM: rockchip: Select ARCH_HAS_RESET_CONTROLLER
  ARM: dts: rk3188: add cru node and update device clocks to use it
  ARM: dts: rockchip: move rk3188 core input clocks into main dtsi
  ARM: dts: rockchip: remove the now obsolete rk3188-clocks.dtsi

 .../bindings/clock/rockchip,rk3188-cru.txt         |  72 ++++
 arch/arm/boot/dts/rk3188-clocks.dtsi               | 289 -------------
 arch/arm/boot/dts/rk3188.dtsi                      |  80 +++-
 arch/arm/mach-rockchip/Kconfig                     |   1 +
 drivers/clk/clk-divider.c                          |  10 +-
 drivers/clk/rockchip/Makefile                      |   6 +
 drivers/clk/rockchip/clk-cpu.c                     | 434 +++++++++++++++++++
 drivers/clk/rockchip/clk-pll.c                     | 317 ++++++++++++++
 drivers/clk/rockchip/clk-rk3188.c                  | 457 +++++++++++++++++++++
 drivers/clk/rockchip/clk.c                         | 168 ++++++++
 drivers/clk/rockchip/clk.h                         | 249 +++++++++++
 drivers/clk/rockchip/softrst.c                     | 115 ++++++
 include/dt-bindings/clock/rk3188-cru.h             |  79 ++++
 include/linux/clk-provider.h                       |   4 +
 14 files changed, 1986 insertions(+), 295 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt
 delete mode 100644 arch/arm/boot/dts/rk3188-clocks.dtsi
 create mode 100644 drivers/clk/rockchip/clk-cpu.c
 create mode 100644 drivers/clk/rockchip/clk-pll.c
 create mode 100644 drivers/clk/rockchip/clk-rk3188.c
 create mode 100644 drivers/clk/rockchip/clk.c
 create mode 100644 drivers/clk/rockchip/clk.h
 create mode 100644 drivers/clk/rockchip/softrst.c
 create mode 100644 include/dt-bindings/clock/rk3188-cru.h

-- 
1.9.0

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

* [PATCH 01/11] clk: divider: add CLK_DIVIDER_READ_ONLY flag
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
@ 2014-04-16 16:37 ` Heiko Stübner
  2014-04-16 16:38 ` [PATCH 02/11] clk: rockchip: add basic infrastructure Heiko Stübner
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:37 UTC (permalink / raw)
  To: linux-arm-kernel

Similar to muxes which already have a read-only flag there sometimes
exist dividers which should not be changed by the clock framework
but whose value still should be readable.

Therefore add a READ_ONLY flag similar to the mux-one to clk-divider

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/clk-divider.c    | 10 +++++++++-
 include/linux/clk-provider.h |  4 ++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index ec22112..f7e5df5 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -249,6 +249,11 @@ const struct clk_ops clk_divider_ops = {
 };
 EXPORT_SYMBOL_GPL(clk_divider_ops);
 
+const struct clk_ops clk_divider_ro_ops = {
+	.recalc_rate = clk_divider_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
+
 static struct clk *_register_divider(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 shift, u8 width,
@@ -274,7 +279,10 @@ static struct clk *_register_divider(struct device *dev, const char *name,
 	}
 
 	init.name = name;
-	init.ops = &clk_divider_ops;
+	if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
+		init.ops = &clk_divider_ro_ops;
+	else
+		init.ops = &clk_divider_ops;
 	init.flags = flags | CLK_IS_BASIC;
 	init.parent_names = (parent_name ? &parent_name: NULL);
 	init.num_parents = (parent_name ? 1 : 0);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 5119174..6a72c70 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -312,6 +312,8 @@ struct clk_div_table {
  *   of this register, and mask of divider bits are in higher 16-bit of this
  *   register.  While setting the divider bits, higher 16-bit should also be
  *   updated to indicate changing divider bits.
+ * CLK_DIVIDER_READ_ONLY - The divider settings are preconfigured and should
+ *	not be changed by the clock framework.
  */
 struct clk_divider {
 	struct clk_hw	hw;
@@ -327,8 +329,10 @@ struct clk_divider {
 #define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
 #define CLK_DIVIDER_ALLOW_ZERO		BIT(2)
 #define CLK_DIVIDER_HIWORD_MASK		BIT(3)
+#define CLK_DIVIDER_READ_ONLY		BIT(4)
 
 extern const struct clk_ops clk_divider_ops;
+extern const struct clk_ops clk_divider_ro_ops;
 struct clk *clk_register_divider(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 shift, u8 width,
-- 
1.9.0

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

* [PATCH 02/11] clk: rockchip: add basic infrastructure
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
  2014-04-16 16:37 ` [PATCH 01/11] clk: divider: add CLK_DIVIDER_READ_ONLY flag Heiko Stübner
@ 2014-04-16 16:38 ` Heiko Stübner
  2014-04-16 16:38 ` [PATCH 03/11] clk: rockchip: add clock type for pll clocks and pll used on rk3066 Heiko Stübner
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

This adds infrastructure for registering basic clock types. It is heavily inspired
by the Samsung implementation and fits surprisingly well to the Rockchip clock
controllers.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/rockchip/Makefile |   1 +
 drivers/clk/rockchip/clk.c    | 131 ++++++++++++++++++++++++++++++++++
 drivers/clk/rockchip/clk.h    | 160 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 292 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk.c
 create mode 100644 drivers/clk/rockchip/clk.h

diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 8d3aefa..0068a8b 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-y	+= clk-rockchip.o
+obj-y	+= clk.o
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
new file mode 100644
index 0000000..b71413e
--- /dev/null
+++ b/drivers/clk/rockchip/clk.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * based on
+ *
+ * samsung/clk.c
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include "clk.h"
+
+static DEFINE_SPINLOCK(clk_lock);
+static struct clk **clk_table;
+static void __iomem *reg_base;
+static struct clk_onecell_data clk_data;
+
+void __init rockchip_clk_init(struct device_node *np, void __iomem *base,
+			      unsigned long nr_clks)
+{
+	reg_base = base;
+
+	clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
+	if (!clk_table)
+		pr_err("%s: could not allocate clock lookup table\n", __func__);
+
+	if (!np)
+		return;
+
+#ifdef CONFIG_OF
+	clk_data.clks = clk_table;
+	clk_data.clk_num = nr_clks;
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+#endif
+}
+
+void rockchip_clk_add_lookup(struct clk *clk, unsigned int id)
+{
+	if (clk_table && id)
+		clk_table[id] = clk;
+}
+
+void __init rockchip_clk_register_mux(struct rockchip_mux_clock *list,
+				      unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx;
+
+	for (idx = 0; idx < nr_clk; idx++, list++) {
+		clk = clk_register_mux(NULL, list->name, list->parent_names,
+			list->num_parents, list->flags, reg_base + list->offset,
+			list->shift, list->width, list->mux_flags, &clk_lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+
+		rockchip_clk_add_lookup(clk, list->id);
+	}
+}
+
+void __init rockchip_clk_register_div(struct rockchip_div_clock *list,
+					unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx;
+
+	for (idx = 0; idx < nr_clk; idx++, list++) {
+		if (list->table)
+			clk = clk_register_divider_table(NULL, list->name,
+					list->parent_name, list->flags,
+					reg_base + list->offset, list->shift,
+					list->width, list->div_flags,
+					list->table, &clk_lock);
+		else
+			clk = clk_register_divider(NULL, list->name,
+					list->parent_name, list->flags,
+					reg_base + list->offset, list->shift,
+					list->width, list->div_flags,
+					&clk_lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+
+		rockchip_clk_add_lookup(clk, list->id);
+	}
+}
+
+void __init rockchip_clk_register_gate(struct rockchip_gate_clock *list,
+			       unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx;
+	unsigned long flags;
+
+	for (idx = 0; idx < nr_clk; idx++, list++) {
+		flags = list->flags | CLK_SET_RATE_PARENT;
+
+		/* keep all gates untouched for now */
+		flags |= CLK_IGNORE_UNUSED;
+
+		clk = clk_register_gate(NULL, list->name, list->parent_name,
+				flags, reg_base + list->offset,
+				list->bit_idx, list->gate_flags, &clk_lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+
+		rockchip_clk_add_lookup(clk, list->id);
+	}
+}
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
new file mode 100644
index 0000000..2b42c8b
--- /dev/null
+++ b/drivers/clk/rockchip/clk.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * based on
+ *
+ * samsung/clk.h
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CLK_ROCKCHIP_CLK_H
+#define CLK_ROCKCHIP_CLK_H
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+#define HIWORD_UPDATE(val, mask, shift) \
+		((val) << (shift) | (mask) << ((shift) + 16))
+
+/* register positions shared by RK2928, RK3066 and RK3188 */
+#define RK2928_PLL_CON(x)		(x * 0x4)
+#define RK2928_MODE_CON		0x40
+#define RK2928_CLKSEL_CON(x)	(x * 0x4 + 0x44)
+#define RK2928_CLKGATE_CON(x)	(x * 0x4 + 0xd0)
+#define RK2928_GLB_SRST_FST		0x100
+#define RK2928_GLB_SRST_SND		0x104
+#define RK2928_SOFTRST_CON(x)	(x * 0x4 + 0x110)
+
+#define PNAME(x) static const char *x[] __initconst
+
+/**
+ * struct rockchip_mux_clock: information about mux clock
+ * @id: platform specific id of the clock.
+ * @name: name of this mux clock.
+ * @parent_names: array of pointer to parent clock names.
+ * @num_parents: number of parents listed in @parent_names.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the mux.
+ * @shift: starting bit location of the mux control bit-field in @reg.
+ * @width: width of the mux control bit-field in @reg.
+ * @mux_flags: flags for mux-type clock.
+ */
+struct rockchip_mux_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		**parent_names;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			mux_flags;
+};
+
+#define MUX(_id, cname, pnames, o, s, w, f, mf)			\
+	{							\
+		.id		= _id,				\
+		.name		= cname,			\
+		.parent_names	= pnames,			\
+		.num_parents	= ARRAY_SIZE(pnames),		\
+		.flags		= f,				\
+		.offset		= o,				\
+		.shift		= s,				\
+		.width		= w,				\
+		.mux_flags	= mf,				\
+	}
+
+/**
+ * struct rockchip_div_clock: information about div clock
+ * @id: platform specific id of the clock.
+ * @name: name of this div clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the div.
+ * @shift: starting bit location of the div control bit-field in @reg.
+ * @div_flags: flags for div-type clock.
+ */
+struct rockchip_div_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			div_flags;
+	struct clk_div_table	*table;
+};
+
+#define DIV(_id, cname, pname, o, s, w, f, df, t)		\
+	{							\
+		.id		= _id,				\
+		.name		= cname,			\
+		.parent_name	= pname,			\
+		.flags		= f,				\
+		.offset		= o,				\
+		.shift		= s,				\
+		.width		= w,				\
+		.div_flags	= df,				\
+		.table		= t,				\
+	}
+
+
+/**
+ * struct rockchip_gate_clock: information about gate clock
+ * @id: platform specific id of the clock.
+ * @name: name of this gate clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the gate.
+ * @bit_idx: bit index of the gate control bit-field in @reg.
+ * @gate_flags: flags for gate-type clock.
+ */
+struct rockchip_gate_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			bit_idx;
+	u8			gate_flags;
+};
+
+#define GATE(_id, cname, pname, o, b, f, gf)			\
+	{							\
+		.id		= _id,				\
+		.name		= cname,			\
+		.parent_name	= pname,			\
+		.flags		= f,				\
+		.offset		= o,				\
+		.bit_idx	= b,				\
+		.gate_flags	= gf,				\
+	}
+
+void rockchip_clk_init(struct device_node *np, void __iomem *base,
+		       unsigned long nr_clks);
+
+void rockchip_clk_add_lookup(struct clk *clk, unsigned int id);
+
+void rockchip_clk_register_mux(struct rockchip_mux_clock *clk_list,
+			       unsigned int nr_clk);
+void rockchip_clk_register_div(struct rockchip_div_clock *clk_list,
+			       unsigned int nr_clk);
+void rockchip_clk_register_gate(struct rockchip_gate_clock *clk_list,
+				unsigned int nr_clk);
+
+#endif
-- 
1.9.0

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

* [PATCH 03/11] clk: rockchip: add clock type for pll clocks and pll used on rk3066
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
  2014-04-16 16:37 ` [PATCH 01/11] clk: divider: add CLK_DIVIDER_READ_ONLY flag Heiko Stübner
  2014-04-16 16:38 ` [PATCH 02/11] clk: rockchip: add basic infrastructure Heiko Stübner
@ 2014-04-16 16:38 ` Heiko Stübner
  2014-04-16 16:39 ` [PATCH 04/11] clk: rockchip: add special cpu clock type Heiko Stübner
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

All known Rockchip SoCs down to the RK28xx (ARM9) use a similar pattern to
handle plls. 1 or more pll-dependant setting registers, a shared pll mode
register and the pll lock status in a register somewhere else.

Therefore add shared infrastructure to handle the common pll actions and
also the pll type used in rk3066 and rk3188 Cortex-A9 SoCs.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/rockchip/Makefile  |   1 +
 drivers/clk/rockchip/clk-pll.c | 317 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/rockchip/clk.c     |  19 +++
 drivers/clk/rockchip/clk.h     |  66 +++++++++
 4 files changed, 403 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk-pll.c

diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 0068a8b..2cb9164 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -4,3 +4,4 @@
 
 obj-y	+= clk-rockchip.o
 obj-y	+= clk.o
+obj-y	+= clk-pll.o
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
new file mode 100644
index 0000000..14820d5
--- /dev/null
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/div64.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/clk-private.h>
+#include "clk.h"
+
+struct rockchip_clk_pll {
+	struct clk_hw		hw;
+	void __iomem		*reg_base;
+	void __iomem		*reg_mode;
+	unsigned int		mode_shift;
+	void __iomem		*reg_lock;
+	unsigned int		lock_shift;
+	enum rockchip_pll_type	type;
+	const struct rockchip_pll_rate_table *rate_table;
+	unsigned int		rate_count;
+	spinlock_t		*lock;
+};
+
+#define to_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw)
+
+static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
+			    struct rockchip_clk_pll *pll, unsigned long rate)
+{
+	const struct rockchip_pll_rate_table  *rate_table = pll->rate_table;
+	int i;
+
+	for (i = 0; i < pll->rate_count; i++) {
+		if (rate == rate_table[i].rate)
+			return &rate_table[i];
+	}
+
+	return NULL;
+}
+
+static long rockchip_pll_round_rate(struct clk_hw *hw,
+			    unsigned long drate, unsigned long *prate)
+{
+	struct rockchip_clk_pll *pll = to_clk_pll(hw);
+	const struct rockchip_pll_rate_table *rate_table = pll->rate_table;
+	int i;
+
+	/*
+	 * For anything smaller or equal to the parent rate, we can only
+	 * bypass the pll, so the parent_rate is the lowest we can get.
+	 */
+	if (drate <= *prate)
+		return *prate;
+
+	/* Assumming rate_table is in descending order */
+	for (i = 0; i < pll->rate_count; i++) {
+		if (drate >= rate_table[i].rate)
+			return rate_table[i].rate;
+	}
+
+	/* return minimum supported value */
+	return rate_table[i - 1].rate;
+}
+
+static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll)
+{
+	int delay = 24000000;
+
+	while (delay > 0) {
+		if (readl(pll->reg_lock) & BIT(pll->lock_shift))
+			return 0;
+		delay--;
+	}
+
+	pr_err("%s: timeout waiting for pll to lock\n", __func__);
+	return -ETIMEDOUT;
+}
+
+/**
+ * PLL used in RK3066 and RK3188
+ */
+
+#define RK3066_PLL_MODE_MASK		0x3
+#define RK3066_PLL_MODE_SLOW		0x0
+#define RK3066_PLL_MODE_NORM		0x1
+#define RK3066_PLL_MODE_DEEP		0x2
+
+#define RK3066_PLL_RESET_DELAY(nr)	((nr * 500) / 24 + 1)
+
+#define RK3066_PLLCON(i)		(i * 0x4)
+
+#define RK3066_PLLCON0_OD_MASK		0xf
+#define RK3066_PLLCON0_OD_SHIFT		0
+#define RK3066_PLLCON0_NR_MASK		0x3f
+#define RK3066_PLLCON0_NR_SHIFT		8
+
+#define RK3066_PLLCON1_NF_MASK		0x1fff
+#define RK3066_PLLCON1_NF_SHIFT		0
+
+#define RK3066_PLLCON2_BWADJ_MASK	0xfff
+#define RK3066_PLLCON2_BWADJ_SHIFT	0
+
+#define RK3066_PLLCON3_RESET		(1 << 5)
+#define RK3066_PLLCON3_PWRDOWN		(1 << 1)
+#define RK3066_PLLCON3_BYPASS		(1 << 0)
+
+static unsigned long rockchip_rk3066_pll_recalc_rate(struct clk_hw *hw,
+						     unsigned long prate)
+{
+	struct rockchip_clk_pll *pll = to_clk_pll(hw);
+	u64 nf, nr, no, rate64 = prate;
+	u32 pllcon;
+
+	pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(3));
+	if (pllcon & RK3066_PLLCON3_BYPASS) {
+		pr_debug("%s: pll %s is bypassed\n", __func__,
+			__clk_get_name(hw->clk));
+		return prate;
+	}
+
+	pllcon = readl_relaxed(pll->reg_mode) >> pll->mode_shift;
+	pllcon &= RK3066_PLL_MODE_MASK;
+	switch (pllcon) {
+	case RK3066_PLL_MODE_NORM:
+		/* calculate the PLL rate below */
+		break;
+	case RK3066_PLL_MODE_SLOW:
+		return prate;
+	case RK3066_PLL_MODE_DEEP:
+		pr_warn("%s: deep slow mode for pll %s currently unknown, assuming parent rate\n",
+			__func__, __clk_get_name(hw->clk));
+		return prate;
+	}
+
+	pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(1));
+	nf = (pllcon >> RK3066_PLLCON1_NF_SHIFT) & RK3066_PLLCON1_NF_MASK;
+
+	pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(0));
+	nr = (pllcon >> RK3066_PLLCON0_NR_SHIFT) & RK3066_PLLCON0_NR_MASK;
+	no = (pllcon >> RK3066_PLLCON0_OD_SHIFT) & RK3066_PLLCON0_OD_MASK;
+
+	rate64 *= (nf + 1);
+	do_div(rate64, nr + 1);
+	do_div(rate64, no + 1);
+
+	return (unsigned long)rate64;
+}
+
+static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
+					unsigned long prate)
+{
+	struct rockchip_clk_pll *pll = to_clk_pll(hw);
+	const struct rockchip_pll_rate_table *rate;
+	unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate);
+	int ret;
+
+	pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
+		 __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
+
+	if (drate == prate) {
+		writel(HIWORD_UPDATE(RK3066_PLL_MODE_SLOW, RK3066_PLL_MODE_MASK,
+				     pll->mode_shift),
+		       pll->reg_mode);
+
+		/* powerdown the pll, as it is unused */
+		writel(HIWORD_UPDATE(RK3066_PLLCON3_PWRDOWN,
+				     RK3066_PLLCON3_PWRDOWN, 0),
+		       pll->reg_base + RK3066_PLLCON(3));
+
+		return 0;
+	}
+
+	/* need to powerup the pll first */
+	if (old_rate == prate)
+		writel(HIWORD_UPDATE(0, RK3066_PLLCON3_PWRDOWN, 0),
+		       pll->reg_base + RK3066_PLLCON(3));
+
+	/* Get required rate settings from table */
+	rate = rockchip_get_pll_settings(pll, drate);
+	if (!rate) {
+		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+			drate, __clk_get_name(hw->clk));
+		return -EINVAL;
+	}
+
+	pr_debug("%s: rate settings for %lu (nr, no, nf): (%d, %d, %d)\n",
+		 __func__, rate->rate, rate->nr, rate->no, rate->nf);
+
+	/* put pll in slow mode and enter reset afterwards */
+	writel_relaxed(HIWORD_UPDATE(RK3066_PLL_MODE_SLOW, RK3066_PLL_MODE_MASK,
+					pll->mode_shift), pll->reg_mode);
+	writel(HIWORD_UPDATE(RK3066_PLLCON3_RESET, RK3066_PLLCON3_RESET, 0),
+					pll->reg_base + RK3066_PLLCON(3));
+
+	/* update pll values */
+	writel(HIWORD_UPDATE(rate->nr - 1, RK3066_PLLCON0_NR_MASK,
+					   RK3066_PLLCON0_NR_SHIFT) |
+	       HIWORD_UPDATE(rate->no - 1, RK3066_PLLCON0_OD_MASK,
+					   RK3066_PLLCON0_OD_SHIFT),
+	       pll->reg_base + RK3066_PLLCON(0));
+
+	writel_relaxed(HIWORD_UPDATE(rate->nf - 1, RK3066_PLLCON1_NF_MASK,
+					RK3066_PLLCON1_NF_SHIFT),
+		       pll->reg_base + RK3066_PLLCON(1));
+	writel_relaxed(HIWORD_UPDATE((rate->nf >> 1),
+					RK3066_PLLCON2_BWADJ_MASK,
+					RK3066_PLLCON2_BWADJ_SHIFT),
+		       pll->reg_base + RK3066_PLLCON(2));
+
+	/* leave reset and wait the reset_delay */
+	writel(HIWORD_UPDATE(0, RK3066_PLLCON3_RESET, 0),
+	       pll->reg_base + RK3066_PLLCON(3));
+	udelay(RK3066_PLL_RESET_DELAY(rate->nr));
+
+	/* wait for the pll to lock */
+	ret = rockchip_pll_wait_lock(pll);
+	if (ret) {
+		pr_warn("%s: trying to restore old rate %lu\n",
+			__func__, old_rate);
+		rockchip_rk3066_pll_set_rate(hw, old_rate, prate);
+	}
+
+	/* go back to normal mode */
+	writel(HIWORD_UPDATE(RK3066_PLL_MODE_NORM, RK3066_PLL_MODE_MASK,
+			     pll->mode_shift), pll->reg_mode);
+
+	return ret;
+}
+
+static const struct clk_ops rockchip_rk3066_pll_clk_ro_ops = {
+	.recalc_rate = rockchip_rk3066_pll_recalc_rate,
+};
+
+static const struct clk_ops rockchip_rk3066_pll_clk_ops = {
+	.recalc_rate = rockchip_rk3066_pll_recalc_rate,
+	.round_rate = rockchip_pll_round_rate,
+	.set_rate = rockchip_rk3066_pll_set_rate,
+};
+
+struct clk *rockchip_clk_register_pll(struct rockchip_pll_clock *pll_clk,
+				void __iomem *base, void __iomem *reg_lock,
+				spinlock_t *lock)
+{
+	struct rockchip_clk_pll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+	int len;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll) {
+		pr_err("%s: could not allocate pll clk %s\n",
+			__func__, pll_clk->name);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	init.name = pll_clk->name;
+	init.flags = pll_clk->flags;
+	init.parent_names = &pll_clk->parent_name;
+	init.num_parents = 1;
+
+	if (pll_clk->rate_table) {
+		/* find count of rates in rate_table */
+		for (len = 0; pll_clk->rate_table[len].rate != 0; )
+			len++;
+
+		pll->rate_count = len;
+		pll->rate_table = kmemdup(pll_clk->rate_table,
+					pll->rate_count *
+					sizeof(struct rockchip_pll_rate_table),
+					GFP_KERNEL);
+		WARN(!pll->rate_table,
+			"%s: could not allocate rate table for %s\n",
+			__func__, pll_clk->name);
+	}
+
+	switch (pll_clk->type) {
+	case pll_rk3066:
+		if (!pll->rate_table)
+			init.ops = &rockchip_rk3066_pll_clk_ro_ops;
+		else
+			init.ops = &rockchip_rk3066_pll_clk_ops;
+		break;
+	default:
+		pr_warn("%s: Unknown pll type for pll clk %s\n",
+			__func__, pll_clk->name);
+	}
+
+	pll->hw.init = &init;
+	pll->type = pll_clk->type;
+	pll->reg_base = base + pll_clk->con_offset;
+	pll->reg_mode = base + pll_clk->mode_offset;
+	pll->mode_shift = pll_clk->mode_shift;
+	pll->reg_lock = reg_lock;
+	pll->lock_shift = pll_clk->lock_shift;
+	pll->lock = lock;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register pll clock %s : %ld\n",
+			__func__, pll_clk->name, PTR_ERR(clk));
+		kfree(pll);
+	}
+
+	return clk;
+}
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index b71413e..53e604d 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -55,6 +55,25 @@ void rockchip_clk_add_lookup(struct clk *clk, unsigned int id)
 		clk_table[id] = clk;
 }
 
+void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list,
+				unsigned int nr_pll, void __iomem *reg_lock)
+{
+	struct clk *clk;
+	int idx;
+
+	for (idx = 0; idx < nr_pll; idx++, list++) {
+		clk = rockchip_clk_register_pll(list, reg_base, reg_lock,
+						&clk_lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+
+		rockchip_clk_add_lookup(clk, list->id);
+	}
+}
+
 void __init rockchip_clk_register_mux(struct rockchip_mux_clock *list,
 				      unsigned int nr_clk)
 {
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 2b42c8b..fdb63c2 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -39,6 +39,70 @@
 #define RK2928_GLB_SRST_SND		0x104
 #define RK2928_SOFTRST_CON(x)	(x * 0x4 + 0x110)
 
+enum rockchip_pll_type {
+	pll_rk3066,
+};
+
+#define RK3066_PLL_RATE(_rate, _nr, _nf, _no)	\
+{						\
+	.rate	= _rate##U,			\
+	.nr = _nr,				\
+	.nf = _nf,				\
+	.no = _no,				\
+}
+
+struct rockchip_pll_rate_table {
+	unsigned long rate;
+	unsigned int nr;
+	unsigned int nf;
+	unsigned int no;
+};
+
+/**
+ * struct rockchip_pll_clock: information about pll clock
+ * @id: platform specific id of the clock.
+ * @name: name of this pll clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @con_offset: offset of the register for configuring the PLL.
+ * @mode_offset: offset of the register for configuring the PLL-mode.
+ * @mode_shift: offset inside the mode-register for the mode of this pll.
+ * @lock_shift: offset inside the lock register for the lock status.
+ * @type: Type of PLL to be registered.
+ * @rate_table: Table of usable pll rates
+ */
+struct rockchip_pll_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	int			con_offset;
+	int			mode_offset;
+	int			mode_shift;
+	int			lock_shift;
+	enum rockchip_pll_type	type;
+	const struct rockchip_pll_rate_table *rate_table;
+};
+
+#define PLL(_type, _id, _name, _pname, _flags, _con, _mode, _mshift,	\
+		_lshift, _rtable)					\
+	{								\
+		.id		= _id,					\
+		.type		= _type,				\
+		.name		= _name,				\
+		.parent_name	= _pname,				\
+		.flags		= CLK_GET_RATE_NOCACHE | _flags,	\
+		.con_offset	= _con,					\
+		.mode_offset	= _mode,				\
+		.mode_shift	= _mshift,				\
+		.lock_shift	= _lshift,				\
+		.rate_table	= _rtable,				\
+	}
+
+struct clk *rockchip_clk_register_pll(struct rockchip_pll_clock *pll_clk,
+				void __iomem *base, void __iomem *reg_lock,
+				spinlock_t *lock);
+
 #define PNAME(x) static const char *x[] __initconst
 
 /**
@@ -156,5 +220,7 @@ void rockchip_clk_register_div(struct rockchip_div_clock *clk_list,
 			       unsigned int nr_clk);
 void rockchip_clk_register_gate(struct rockchip_gate_clock *clk_list,
 				unsigned int nr_clk);
+void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list,
+				unsigned int nr_pll, void __iomem *reg_lock);
 
 #endif
-- 
1.9.0

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

* [PATCH 04/11] clk: rockchip: add special cpu clock type
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
                   ` (2 preceding siblings ...)
  2014-04-16 16:38 ` [PATCH 03/11] clk: rockchip: add clock type for pll clocks and pll used on rk3066 Heiko Stübner
@ 2014-04-16 16:39 ` Heiko Stübner
  2014-04-16 16:40 ` [PATCH 05/11] clk: rockchip: add reset controller Heiko Stübner
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:39 UTC (permalink / raw)
  To: linux-arm-kernel

To change the ARMCLK, Rockchip SoCs at least down to the Cortex-A8 RK2918
need special care. This includes reparenting the the armclk to a secondary
parent for the duration of the parent rate-change and also the re-setting
of tightly coupled children clocks.

Therefore define a special clock type for the cpuclk that attaches a notifier
to the parent pll and handles the necessary steps in a clock notifier.

Also implemented are the necessary functions to handle the cpu clock of rk3188.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/rockchip/Makefile  |   1 +
 drivers/clk/rockchip/clk-cpu.c | 434 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/rockchip/clk.c     |  18 ++
 drivers/clk/rockchip/clk.h     |   9 +
 4 files changed, 462 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk-cpu.c

diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 2cb9164..7748062 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -5,3 +5,4 @@
 obj-y	+= clk-rockchip.o
 obj-y	+= clk.o
 obj-y	+= clk-pll.o
+obj-y	+= clk-cpu.o
diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c
new file mode 100644
index 0000000..b149d03
--- /dev/null
+++ b/drivers/clk/rockchip/clk-cpu.c
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * based on clk/samsung/clk-cpu.c
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains the utility functions to register the cpu clocks
+ * for rockchip platforms.
+ */
+
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+
+#include "clk.h"
+
+/**
+ * struct samsung_cpuclk: information about clock supplied to a CPU core.
+ * @hw:		handle between ccf and cpu clock.
+ * @alt_parent:	alternate parent clock to use when switching the speed
+ *		of the primary parent clock.
+ * @reg:	base register for cpu-clock values.
+ * @clk_nb:	clock notifier registered for changes in clock speed of the
+ *		primary parent clock.
+ * @data:	optional data which the acutal instantiation of this clock
+ *		can use.
+ */
+struct rockchip_cpuclk {
+	struct clk_hw		hw;
+	struct clk		*alt_parent;
+	void __iomem		*reg_base;
+	struct notifier_block	clk_nb;
+	void			*data;
+	spinlock_t		*lock;
+};
+
+#define to_rockchip_cpuclk_hw(hw) container_of(hw, struct rockchip_cpuclk, hw)
+#define to_rockchip_cpuclk_nb(nb) \
+			container_of(nb, struct rockchip_cpuclk, clk_nb)
+
+/**
+ * struct rockchip_cpuclk_soc_data: soc specific data for cpu clocks.
+ * @parser:	pointer to a function that can parse SoC specific data.
+ * @ops:	clock operations to be used for this clock.
+ * @clk_cb:	the clock notifier callback to be called for changes in the
+ *		clock rate of the primary parent clock.
+ *
+ * This structure provides SoC specific data for ARM clocks. Based on
+ * the compatible value of the clock controller node, the value of the
+ * fields in this structure can be populated.
+ */
+struct rockchip_cpuclk_soc_data {
+	int			(*parser)(struct device_node *, void **);
+	const struct clk_ops	*ops;
+	int (*clk_cb)(struct notifier_block *nb, unsigned long evt, void *data);
+};
+
+static unsigned long _calc_div(unsigned long prate, unsigned long drate)
+{
+	unsigned long div = prate / drate;
+	return (!(prate % drate)) ? div-- : div;
+}
+
+/**
+ * struct rk2928_cpuclk_data: config data for rk2928/rk3066/rk3188 cpu clocks.
+ * @prate:	frequency of the parent clock.
+ * @clksel0:	value to be programmed in the clksel0 register.
+ * @clksel1:	value to be programmed in the clksel1 register.
+ *
+ * This structure holds the divider configuration data for for core clocks
+ * directly depending on the cpu clockspeed. The parent frequency at which
+ * these values are vaild is specified in @prate.
+ */
+struct rk2928_cpuclk_data {
+	unsigned long		prate;
+	u32			clksel0;
+	u32			clksel1;
+};
+
+/**
+ * struct rk2928_reg_data: describes register offsets and masks of the cpuclock
+ * @div_core_shift:	core divider offset used to divider the pll value
+ * @div_core_mask:	core divider mask
+ * @mux_core_shift:	offset of the core multiplexer
+ */
+struct rk2928_reg_data {
+	u8		div_core_shift;
+	u32		div_core_mask;
+	u8		mux_core_shift;
+};
+
+/*
+ * This clock notifier is called when the frequency of the parent clock
+ * of cpuclk is to be changed. This notifier handles the setting up all
+ * the divider clocks, remux to temporary parent and handling the safe
+ * frequency levels when using temporary parent.
+ */
+static int rk2928_cpuclk_common_notifier_cb(struct notifier_block *nb,
+					unsigned long event, void *data,
+					const struct rk2928_reg_data *reg_data)
+{
+	struct clk_notifier_data *ndata = data;
+	struct rockchip_cpuclk *cpuclk = to_rockchip_cpuclk_nb(nb);
+	struct rk2928_cpuclk_data *cpuclk_data = cpuclk->data;
+	unsigned long alt_prate, alt_div;
+
+	if (!cpuclk_data)
+		return NOTIFY_BAD;
+
+	switch (event) {
+	case PRE_RATE_CHANGE:
+		alt_prate = clk_get_rate(cpuclk->alt_parent);
+
+		/* pre-rate change. find out the divider values */
+		while (cpuclk_data->prate != ndata->new_rate) {
+			if (cpuclk_data->prate == 0)
+				return NOTIFY_BAD;
+			cpuclk_data++;
+		}
+
+		/*
+		 * if the new and old parent clock speed is less than the
+		 * clock speed of the alternate parent, then it should be
+		 * ensured that at no point the cpuclk speed is more than
+		 * the old_prate until the dividers are set.
+		 */
+		if (ndata->old_rate < alt_prate &&
+					ndata->new_rate < alt_prate) {
+			alt_div = _calc_div(alt_prate, ndata->old_rate);
+			writel_relaxed(HIWORD_UPDATE(alt_div,
+						     reg_data->div_core_mask,
+						     reg_data->div_core_shift),
+				      cpuclk->reg_base + RK2928_CLKSEL_CON(0));
+		}
+
+		/* mux to alternate parent */
+		writel(HIWORD_UPDATE(1, 1, reg_data->mux_core_shift),
+		       cpuclk->reg_base + RK2928_CLKSEL_CON(0));
+
+		/* set new divider values for depending clocks */
+		writel(cpuclk_data->clksel0,
+		       cpuclk->reg_base + RK2928_CLKSEL_CON(0));
+		writel_relaxed(cpuclk_data->clksel1,
+		       cpuclk->reg_base + RK2928_CLKSEL_CON(1));
+		break;
+	case POST_RATE_CHANGE:
+		/* post-rate change event, re-mux back to primary parent */
+		writel(HIWORD_UPDATE(0, 1, reg_data->mux_core_shift),
+		       cpuclk->reg_base + RK2928_CLKSEL_CON(0));
+
+		/* remove any core dividers */
+		writel(HIWORD_UPDATE(0, reg_data->div_core_mask,
+				     reg_data->div_core_shift),
+		       cpuclk->reg_base + RK2928_CLKSEL_CON(0));
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+#define RK2928_DIV_CORE_SHIFT		0
+#define RK2928_DIV_CORE_MASK		0x1f
+#define RK2928_MUX_CORE_SHIFT		7
+
+static unsigned long rockchip_rk2928_cpuclk_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct rockchip_cpuclk *cpuclk = to_rockchip_cpuclk_hw(hw);
+	u32 clksel0 = readl_relaxed(cpuclk->reg_base + RK2928_CLKSEL_CON(0));
+
+	clksel0 >>= RK2928_DIV_CORE_SHIFT;
+	clksel0 &= RK2928_DIV_CORE_MASK;
+	return parent_rate / (clksel0 + 1);
+}
+
+static const struct clk_ops rk2928_cpuclk_ops = {
+	.recalc_rate = rockchip_rk2928_cpuclk_recalc_rate,
+};
+
+static const struct rk2928_reg_data rk2928_data = {
+	.div_core_shift = RK2928_DIV_CORE_SHIFT,
+	.div_core_mask = RK2928_DIV_CORE_MASK,
+	.mux_core_shift = RK2928_MUX_CORE_SHIFT,
+};
+
+static int rk2928_cpuclk_notifier_cb(struct notifier_block *nb,
+				     unsigned long event, void *data)
+{
+	return rk2928_cpuclk_common_notifier_cb(nb, event, data, &rk2928_data);
+}
+
+static const struct rockchip_cpuclk_soc_data rk2928_cpuclk_soc_data = {
+	.ops = &rk2928_cpuclk_ops,
+	.clk_cb = rk2928_cpuclk_notifier_cb,
+};
+
+#define RK3066_MUX_CORE_SHIFT		8
+
+static const struct rk2928_reg_data rk3066_data = {
+	.div_core_shift = RK2928_DIV_CORE_SHIFT,
+	.div_core_mask = RK2928_DIV_CORE_MASK,
+	.mux_core_shift = RK3066_MUX_CORE_SHIFT,
+};
+
+static int rk3066_cpuclk_notifier_cb(struct notifier_block *nb,
+				     unsigned long event, void *data)
+{
+	return rk2928_cpuclk_common_notifier_cb(nb, event, data, &rk3066_data);
+}
+
+static const struct rockchip_cpuclk_soc_data rk3066_cpuclk_soc_data = {
+	.ops = &rk2928_cpuclk_ops,
+	.clk_cb = rk3066_cpuclk_notifier_cb,
+};
+
+#define RK3188_DIV_CORE_SHIFT		9
+#define RK3188_DIV_CORE_MASK		0x1f
+#define RK3188_MUX_CORE_SHIFT		8
+#define RK3188_DIV_CORE_PERIPH_MASK	0x3
+#define RK3188_DIV_CORE_PERIPH_SHIFT	6
+#define RK3188_DIV_ACLK_CORE_MASK	0x7
+#define RK3188_DIV_ACLK_CORE_SHIFT	3
+
+#define RK3188_CLKSEL0(div_core_periph) \
+		HIWORD_UPDATE(div_core_periph, RK3188_DIV_CORE_PERIPH_MASK,\
+				 RK3188_DIV_CORE_PERIPH_SHIFT)
+#define RK3188_CLKSEL1(div_aclk_core) \
+		HIWORD_UPDATE(div_aclk_core, RK3188_DIV_ACLK_CORE_MASK,\
+				 RK3188_DIV_ACLK_CORE_SHIFT)
+
+static unsigned long rockchip_rk3188_cpuclk_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct rockchip_cpuclk *cpuclk = to_rockchip_cpuclk_hw(hw);
+	u32 clksel0 = readl_relaxed(cpuclk->reg_base + RK2928_CLKSEL_CON(0));
+
+	clksel0 >>= RK3188_DIV_CORE_SHIFT;
+	clksel0 &= RK3188_DIV_CORE_MASK;
+	return parent_rate / (clksel0 + 1);
+}
+
+static const struct clk_ops rk3188_cpuclk_ops = {
+	.recalc_rate = rockchip_rk3188_cpuclk_recalc_rate,
+};
+
+static const struct rk2928_reg_data rk3188_data = {
+	.div_core_shift = RK3188_DIV_CORE_SHIFT,
+	.div_core_mask = RK3188_DIV_CORE_MASK,
+	.mux_core_shift = RK3188_MUX_CORE_SHIFT,
+};
+
+static int rk3188_cpuclk_notifier_cb(struct notifier_block *nb,
+				unsigned long event, void *data)
+{
+	return rk2928_cpuclk_common_notifier_cb(nb, event, data, &rk3188_data);
+}
+
+/*
+ * parse divider configuration data from dt for all the cpu clock domain
+ * clocks in rk3188 and compatible SoC's.
+ */
+static int __init rk3188_cpuclk_parser(struct device_node *np, void **data)
+{
+	struct rk2928_cpuclk_data *tdata;
+	int proplen, ret, num_rows, i, col;
+	u32 cfg[10], cells;
+
+	ret = of_property_read_u32(np, "#rockchip,armclk-cells", &cells);
+	if (ret)
+		return -EINVAL;
+
+	proplen = of_property_count_u32_elems(np,
+					      "rockchip,armclk-divider-table");
+	if (proplen < 0)
+		return proplen;
+	if (!proplen || proplen % cells)
+		return -EINVAL;
+
+	num_rows = proplen / cells;
+
+	*data = kzalloc(sizeof(*tdata) * (num_rows + 1), GFP_KERNEL);
+	if (!*data)
+		return -ENOMEM;
+
+	tdata = *data;
+
+	for (i = 0; i < num_rows; i++, tdata++) {
+		for (col = 0; col < cells; col++) {
+			ret = of_property_read_u32_index(np,
+					"rockchip,armclk-divider-table",
+					i * cells + col, &cfg[col]);
+			if (ret) {
+				pr_err("%s: failed to read col %d in row %d of %d\n",
+				       __func__, col, i, num_rows);
+				kfree(*data);
+				return ret;
+			}
+		}
+
+		tdata->prate = cfg[0] * 1000;
+		tdata->clksel0 = RK3188_CLKSEL0(cfg[1]);
+		tdata->clksel1 = RK3188_CLKSEL1(cfg[2]);
+	}
+	tdata->prate = 0;
+	return 0;
+}
+
+static const struct rockchip_cpuclk_soc_data rk3188_cpuclk_soc_data = {
+	.parser = rk3188_cpuclk_parser,
+	.ops = &rk3188_cpuclk_ops,
+	.clk_cb = rk3188_cpuclk_notifier_cb,
+};
+
+static const struct of_device_id rockchip_clock_ids_cpuclk[] = {
+	{ .compatible = "rockchip,rk2928-cru",
+			.data = &rk2928_cpuclk_soc_data, },
+	{ .compatible = "rockchip,rk3066-cru",
+			.data = &rk3066_cpuclk_soc_data, },
+	{ .compatible = "rockchip,rk3188-cru",
+			.data = &rk3188_cpuclk_soc_data, },
+	{ /* sentinel */ },
+};
+
+/**
+ * rockchip_clk_register_cpuclk: register arm clock with ccf.
+ * @lookup_id: cpuclk clock output id for the clock controller.
+ * @parent_names: names of the parent clocks for cpuclk.
+ * @num_parents: number of parent clocks
+ * @base: base address of the clock controller from which cpuclk is generated.
+ * @np: device tree node pointer of the clock controller.
+ * @ops: clock ops for this clock (optional)
+ */
+struct clk *rockchip_clk_register_cpuclk(const char *name,
+			const char **parent_names, unsigned int num_parents,
+			void __iomem *reg_base, struct device_node *np,
+			spinlock_t *lock)
+{
+	struct rockchip_cpuclk *cpuclk;
+	struct clk_init_data init;
+	const struct rockchip_cpuclk_soc_data *soc_data;
+	const struct of_device_id *match;
+	struct clk *clk;
+	int ret;
+
+	if (!np) {
+		pr_err("%s: missing device node\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	match = of_match_node(rockchip_clock_ids_cpuclk, np);
+	if (!match) {
+		pr_err("%s: no matching cpuclock found\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	soc_data = match->data;
+
+	if (!soc_data->clk_cb)
+		return ERR_PTR(-EINVAL);
+
+	if (num_parents != 2) {
+		pr_err("%s: missing alternative parent clock\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
+	if (!cpuclk)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.flags = CLK_SET_RATE_PARENT;
+	init.parent_names = parent_names;
+	init.num_parents = 1;
+	init.ops = soc_data->ops;
+
+	cpuclk->hw.init = &init;
+	cpuclk->reg_base = reg_base;
+	cpuclk->lock = lock;
+
+	cpuclk->alt_parent = __clk_lookup(parent_names[1]);
+	if (!cpuclk->alt_parent) {
+		pr_err("%s: could not lookup alternate parent\n",
+		       __func__);
+		ret = -EINVAL;
+		goto free_cpuclk;
+	}
+
+	ret = clk_prepare_enable(cpuclk->alt_parent);
+	if (ret) {
+		pr_err("%s: could not enable alternate parent\n",
+		       __func__);
+		goto free_cpuclk;
+	}
+
+	if (soc_data->parser) {
+		ret = soc_data->parser(np, &cpuclk->data);
+		if (ret) {
+			pr_err("%s: error %d in parsing %s clock data",
+					__func__, ret, name);
+			ret = -EINVAL;
+			goto free_cpuclk;
+		}
+	}
+
+	cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
+	if (clk_notifier_register(__clk_lookup(parent_names[0]),
+			&cpuclk->clk_nb)) {
+		pr_err("%s: failed to register clock notifier for %s\n",
+				__func__, name);
+		goto free_cpuclk_data;
+	}
+
+	clk = clk_register(NULL, &cpuclk->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: could not register cpuclk %s\n", __func__,	name);
+		ret = PTR_ERR(clk);
+		goto free_cpuclk_data;
+	}
+
+	return clk;
+
+free_cpuclk_data:
+	kfree(cpuclk->data);
+free_cpuclk:
+	kfree(cpuclk);
+	return ERR_PTR(ret);
+}
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index 53e604d..4a626f8 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -74,6 +74,24 @@ void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list,
 	}
 }
 
+void __init rockchip_clk_register_armclk(unsigned int lookup_id,
+			const char *name, const char **parent_names,
+			unsigned int num_parents, void __iomem *reg_base,
+			struct device_node *np)
+{
+	struct clk *clk;
+
+	clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents,
+					   reg_base, np, &clk_lock);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register clock %s\n", __func__,
+			name);
+		return;
+	}
+
+	rockchip_clk_add_lookup(clk, lookup_id);
+}
+
 void __init rockchip_clk_register_mux(struct rockchip_mux_clock *list,
 				      unsigned int nr_clk)
 {
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index fdb63c2..a86d058 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -103,6 +103,11 @@ struct clk *rockchip_clk_register_pll(struct rockchip_pll_clock *pll_clk,
 				void __iomem *base, void __iomem *reg_lock,
 				spinlock_t *lock);
 
+struct clk *rockchip_clk_register_cpuclk(const char *name,
+			const char **parent_names, unsigned int num_parents,
+			void __iomem *reg_base, struct device_node *np,
+			spinlock_t *lock);
+
 #define PNAME(x) static const char *x[] __initconst
 
 /**
@@ -222,5 +227,9 @@ void rockchip_clk_register_gate(struct rockchip_gate_clock *clk_list,
 				unsigned int nr_clk);
 void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list,
 				unsigned int nr_pll, void __iomem *reg_lock);
+void rockchip_clk_register_armclk(unsigned int lookup_id,
+			const char *name, const char **parent_names,
+			unsigned int num_parents, void __iomem *reg_base,
+			struct device_node *np);
 
 #endif
-- 
1.9.0

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

* [PATCH 05/11] clk: rockchip: add reset controller
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
                   ` (3 preceding siblings ...)
  2014-04-16 16:39 ` [PATCH 04/11] clk: rockchip: add special cpu clock type Heiko Stübner
@ 2014-04-16 16:40 ` Heiko Stübner
  2014-04-16 16:42   ` Heiko Stübner
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:40 UTC (permalink / raw)
  To: linux-arm-kernel

All Rockchip SoCs at least down to the ARM9-based RK28xx include the reset-
controller for SoC peripherals in their clock controller.
While the older SoCs (ARM9 and Cortex-A8) use a regular scheme to change
register values, the Cortex-A9 SoCs use a hiword-mask making locking unecessary.
To be compatible with both schemes the reset controller takes a flag to
decide which scheme to use.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/rockchip/Makefile  |   1 +
 drivers/clk/rockchip/clk.h     |  14 +++++
 drivers/clk/rockchip/softrst.c | 115 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 130 insertions(+)
 create mode 100644 drivers/clk/rockchip/softrst.c

diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 7748062..7e4a296 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -6,3 +6,4 @@ obj-y	+= clk-rockchip.o
 obj-y	+= clk.o
 obj-y	+= clk-pll.o
 obj-y	+= clk-cpu.o
+obj-$(CONFIG_RESET_CONTROLLER)	+= softrst.o
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index a86d058..9d88c37 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -232,4 +232,18 @@ void rockchip_clk_register_armclk(unsigned int lookup_id,
 			unsigned int num_parents, void __iomem *reg_base,
 			struct device_node *np);
 
+#define ROCKCHIP_SOFTRST_HIWORD_MASK	BIT(0)
+
+#ifdef CONFIG_RESET_CONTROLLER
+void rockchip_register_softrst(struct device_node *np,
+			       unsigned int num_regs,
+			       void __iomem *base, u8 flags);
+#else
+static inline void rockchip_register_softrst(struct device_node *np,
+			       unsigned int num_regs,
+			       void __iomem *base, u8 flags)
+{
+}
+#endif
+
 #endif
diff --git a/drivers/clk/rockchip/softrst.c b/drivers/clk/rockchip/softrst.c
new file mode 100644
index 0000000..e981f6c
--- /dev/null
+++ b/drivers/clk/rockchip/softrst.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
+#include "clk.h"
+
+struct rockchip_softrst {
+	struct reset_controller_dev	rcdev;
+	void __iomem			*reg_base;
+	int				num_regs;
+	int				num_per_reg;
+	u8				flags;
+	spinlock_t			lock;
+};
+
+static int rockchip_softrst_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	struct rockchip_softrst *softrst = container_of(rcdev,
+						     struct rockchip_softrst,
+						     rcdev);
+	int bank = id / softrst->num_per_reg;
+	int offset = id % softrst->num_per_reg;
+
+	if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
+		writel(BIT(offset) | (BIT(offset) << 16),
+		       softrst->reg_base + (bank * 4));
+	} else {
+		unsigned long flags;
+		u32 reg;
+
+		spin_lock_irqsave(&softrst->lock, flags);
+
+		reg = readl(softrst->reg_base + (bank * 4));
+		writel(reg | BIT(offset), softrst->reg_base + (bank * 4));
+
+		spin_unlock_irqrestore(&softrst->lock, flags);
+	}
+
+	return 0;
+}
+
+static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct rockchip_softrst *softrst = container_of(rcdev,
+						     struct rockchip_softrst,
+						     rcdev);
+	int bank = id / BITS_PER_LONG;
+	int offset = id % BITS_PER_LONG;
+
+	if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
+		writel((BIT(offset) << 16), softrst->reg_base + (bank * 4));
+	} else {
+		unsigned long flags;
+		u32 reg;
+
+		spin_lock_irqsave(&softrst->lock, flags);
+
+		reg = readl(softrst->reg_base + (bank * 4));
+		writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4));
+
+		spin_unlock_irqrestore(&softrst->lock, flags);
+	}
+
+	return 0;
+}
+
+static struct reset_control_ops rockchip_softrst_ops = {
+	.assert		= rockchip_softrst_assert,
+	.deassert	= rockchip_softrst_deassert,
+};
+
+void __init rockchip_register_softrst(struct device_node *np,
+				      unsigned int num_regs,
+				      void __iomem *base, u8 flags)
+{
+	struct rockchip_softrst *softrst;
+	int ret;
+
+	softrst = kzalloc(sizeof(*softrst), GFP_KERNEL);
+	if (!softrst)
+		return;
+
+	softrst->reg_base = base;
+	softrst->num_regs = num_regs;
+	softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16
+								      : 32;
+
+	softrst->rcdev.owner = THIS_MODULE;
+	softrst->rcdev.nr_resets =  num_regs * softrst->num_per_reg;
+	softrst->rcdev.ops = &rockchip_softrst_ops;
+	softrst->rcdev.of_node = np;
+	ret = reset_controller_register(&softrst->rcdev);
+	if (ret) {
+		pr_err("%s: could not register reset controller, %d\n",
+		       __func__, ret);
+		kfree(softrst);
+	}
+};
-- 
1.9.0

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

* [PATCH 06/11] dt-bindings: add documentation for rk3188 clock and reset unit
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
@ 2014-04-16 16:42   ` Heiko Stübner
  2014-04-16 16:38 ` [PATCH 02/11] clk: rockchip: add basic infrastructure Heiko Stübner
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:42 UTC (permalink / raw)
  To: Mike Turquette
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA

This add bindings documentation for the clock and reset unit found on
rk3188 SoCs from Rockchip.

Signed-off-by: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
---
 .../bindings/clock/rockchip,rk3188-cru.txt         | 72 ++++++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt

diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt
new file mode 100644
index 0000000..26ad529
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt
@@ -0,0 +1,72 @@
+* Rockchip RK3188 Clock and Reset Unit
+
+The RK3188 clock controller generates and supplies clock to various controllers
+within the SoC and also implements a reset controller for SoC peripherals.
+
+Required Properties:
+
+- compatible: should be "rockchip,rk3188-cru"
+- reg: physical base address of the controller and length of memory mapped
+  region. The first element should be the cru register space and the second
+  element should be the address of the GRF_SOC_STATUS register providing the
+  pll lock status.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+- rockchip,armclk-divider-table: when the frequency of the APLL is changed
+  some core divider clocks also need to be updated. These divider clocks have
+  SoC specific divider clock output requirements for a specific APLL clock
+  speeds. When APLL clock rate is changed, these divider clocks are
+  reprogrammed with pre-determined values in order to maintain the SoC
+  specific divider clock outputs. This property lists the divider values
+  for these clocks for supported APLL clock speeds.
+  The format of each entry included in the arm-frequency-table should be
+  defined as
+
+      cell #1: arm clock parent frequency
+      cell #2 ~ cell 3#: value of clock divider of core_peri and aclk_core.
+
+- #rockchip,armclk-cells: defines the number of cells in
+  rockchip,armclk-divider-table property. The value of this property depends on
+  the SoC type. For RK3188 SoCs it should be 3.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in dt-bindings/clock/rk3188-cru.h header and can be used
+in device tree sources.
+
+External clocks:
+
+The basic input clock is generated outside the SoC. It is expected that it is
+defined using standard clock bindings with a clock-output-name of "xin24m".
+
+Example: Clock controller node:
+
+	cru: cru@20000000 {
+		compatible = "rockchip,rk3188-cru";
+		reg = <0x20000000 0x1000>,
+		      <0x200080ac 0x4>;
+
+		#clock-cells = <1>;
+
+		#rockchip,armclk-cells = <3>;
+		rockchip,armclk-divider-table =	<1608000 2 3>,
+						<1416000 2 3>,
+						<1200000 2 3>,
+						<1008000 2 3>,
+						< 816000 2 3>,
+						< 504000 1 3>,
+						< 312000 0 1>;
+	};
+
+Example: UART controller node that consumes the clock generated by the clock
+  controller:
+
+	uart0: serial@10124000 {
+		compatible = "snps,dw-apb-uart";
+		reg = <0x10124000 0x400>;
+		interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+		reg-shift = <2>;
+		reg-io-width = <1>;
+		clocks = <&cru SCLK_UART0>;
+	};
-- 
1.9.0


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 06/11] dt-bindings: add documentation for rk3188 clock and reset unit
@ 2014-04-16 16:42   ` Heiko Stübner
  0 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

This add bindings documentation for the clock and reset unit found on
rk3188 SoCs from Rockchip.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 .../bindings/clock/rockchip,rk3188-cru.txt         | 72 ++++++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt

diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt
new file mode 100644
index 0000000..26ad529
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt
@@ -0,0 +1,72 @@
+* Rockchip RK3188 Clock and Reset Unit
+
+The RK3188 clock controller generates and supplies clock to various controllers
+within the SoC and also implements a reset controller for SoC peripherals.
+
+Required Properties:
+
+- compatible: should be "rockchip,rk3188-cru"
+- reg: physical base address of the controller and length of memory mapped
+  region. The first element should be the cru register space and the second
+  element should be the address of the GRF_SOC_STATUS register providing the
+  pll lock status.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+- rockchip,armclk-divider-table: when the frequency of the APLL is changed
+  some core divider clocks also need to be updated. These divider clocks have
+  SoC specific divider clock output requirements for a specific APLL clock
+  speeds. When APLL clock rate is changed, these divider clocks are
+  reprogrammed with pre-determined values in order to maintain the SoC
+  specific divider clock outputs. This property lists the divider values
+  for these clocks for supported APLL clock speeds.
+  The format of each entry included in the arm-frequency-table should be
+  defined as
+
+      cell #1: arm clock parent frequency
+      cell #2 ~ cell 3#: value of clock divider of core_peri and aclk_core.
+
+- #rockchip,armclk-cells: defines the number of cells in
+  rockchip,armclk-divider-table property. The value of this property depends on
+  the SoC type. For RK3188 SoCs it should be 3.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in dt-bindings/clock/rk3188-cru.h header and can be used
+in device tree sources.
+
+External clocks:
+
+The basic input clock is generated outside the SoC. It is expected that it is
+defined using standard clock bindings with a clock-output-name of "xin24m".
+
+Example: Clock controller node:
+
+	cru: cru at 20000000 {
+		compatible = "rockchip,rk3188-cru";
+		reg = <0x20000000 0x1000>,
+		      <0x200080ac 0x4>;
+
+		#clock-cells = <1>;
+
+		#rockchip,armclk-cells = <3>;
+		rockchip,armclk-divider-table =	<1608000 2 3>,
+						<1416000 2 3>,
+						<1200000 2 3>,
+						<1008000 2 3>,
+						< 816000 2 3>,
+						< 504000 1 3>,
+						< 312000 0 1>;
+	};
+
+Example: UART controller node that consumes the clock generated by the clock
+  controller:
+
+	uart0: serial at 10124000 {
+		compatible = "snps,dw-apb-uart";
+		reg = <0x10124000 0x400>;
+		interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+		reg-shift = <2>;
+		reg-io-width = <1>;
+		clocks = <&cru SCLK_UART0>;
+	};
-- 
1.9.0

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

* [PATCH 07/11] clk: rockchip: add clock driver for rk3188 clocks
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
                   ` (5 preceding siblings ...)
  2014-04-16 16:42   ` Heiko Stübner
@ 2014-04-16 16:43 ` Heiko Stübner
  2014-04-16 16:44 ` [PATCH 08/11] ARM: rockchip: Select ARCH_HAS_RESET_CONTROLLER Heiko Stübner
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:43 UTC (permalink / raw)
  To: linux-arm-kernel

This adds a clock driver that handles the specific muxes, dividers and gates
of rk3188 SoCs.

Clocks exported to the clock provider are currently limited to well known
or measured ones.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/rockchip/Makefile          |   2 +
 drivers/clk/rockchip/clk-rk3188.c      | 457 +++++++++++++++++++++++++++++++++
 include/dt-bindings/clock/rk3188-cru.h |  79 ++++++
 3 files changed, 538 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk-rk3188.c
 create mode 100644 include/dt-bindings/clock/rk3188-cru.h

diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 7e4a296..a75e625 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -7,3 +7,5 @@ obj-y	+= clk.o
 obj-y	+= clk-pll.o
 obj-y	+= clk-cpu.o
 obj-$(CONFIG_RESET_CONTROLLER)	+= softrst.o
+
+obj-y	+= clk-rk3188.o
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
new file mode 100644
index 0000000..462e0ee
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3188.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <dt-bindings/clock/rk3188-cru.h>
+
+#include "clk.h"
+
+/* list of PLLs to be registered */
+enum rk3188_plls {
+	apll, cpll, dpll, gpll,
+};
+
+struct rockchip_pll_rate_table rk3188_apll_rates[] = {
+	RK3066_PLL_RATE(2208000000, 1, 92, 1),
+	RK3066_PLL_RATE(2184000000, 1, 91, 1),
+	RK3066_PLL_RATE(2160000000, 1, 90, 1),
+	RK3066_PLL_RATE(2136000000, 1, 89, 1),
+	RK3066_PLL_RATE(2112000000, 1, 88, 1),
+	RK3066_PLL_RATE(2088000000, 1, 87, 1),
+	RK3066_PLL_RATE(2064000000, 1, 86, 1),
+	RK3066_PLL_RATE(2040000000, 1, 85, 1),
+	RK3066_PLL_RATE(2016000000, 1, 84, 1),
+	RK3066_PLL_RATE(1992000000, 1, 83, 1),
+	RK3066_PLL_RATE(1968000000, 1, 82, 1),
+	RK3066_PLL_RATE(1944000000, 1, 81, 1),
+	RK3066_PLL_RATE(1920000000, 1, 80, 1),
+	RK3066_PLL_RATE(1896000000, 1, 79, 1),
+	RK3066_PLL_RATE(1872000000, 1, 78, 1),
+	RK3066_PLL_RATE(1848000000, 1, 77, 1),
+	RK3066_PLL_RATE(1824000000, 1, 76, 1),
+	RK3066_PLL_RATE(1800000000, 1, 75, 1),
+	RK3066_PLL_RATE(1776000000, 1, 74, 1),
+	RK3066_PLL_RATE(1752000000, 1, 73, 1),
+	RK3066_PLL_RATE(1728000000, 1, 72, 1),
+	RK3066_PLL_RATE(1704000000, 1, 71, 1),
+	RK3066_PLL_RATE(1680000000, 1, 70, 1),
+	RK3066_PLL_RATE(1656000000, 1, 69, 1),
+	RK3066_PLL_RATE(1632000000, 1, 68, 1),
+	RK3066_PLL_RATE(1608000000, 1, 67, 1),
+	RK3066_PLL_RATE(1560000000, 1, 65, 1),
+	RK3066_PLL_RATE(1512000000, 1, 63, 1),
+	RK3066_PLL_RATE(1488000000, 1, 62, 1),
+	RK3066_PLL_RATE(1464000000, 1, 61, 1),
+	RK3066_PLL_RATE(1440000000, 1, 60, 1),
+	RK3066_PLL_RATE(1416000000, 1, 59, 1),
+	RK3066_PLL_RATE(1392000000, 1, 58, 1),
+	RK3066_PLL_RATE(1368000000, 1, 57, 1),
+	RK3066_PLL_RATE(1344000000, 1, 56, 1),
+	RK3066_PLL_RATE(1320000000, 1, 55, 1),
+	RK3066_PLL_RATE(1296000000, 1, 54, 1),
+	RK3066_PLL_RATE(1272000000, 1, 53, 1),
+	RK3066_PLL_RATE(1248000000, 1, 52, 1),
+	RK3066_PLL_RATE(1224000000, 1, 51, 1),
+	RK3066_PLL_RATE(1200000000, 1, 50, 1),
+	RK3066_PLL_RATE(1176000000, 1, 49, 1),
+	RK3066_PLL_RATE(1128000000, 1, 47, 1),
+	RK3066_PLL_RATE(1104000000, 1, 46, 1),
+	RK3066_PLL_RATE(1008000000, 1, 84, 2),
+	RK3066_PLL_RATE( 912000000, 1, 76, 2),
+	RK3066_PLL_RATE( 888000000, 1, 74, 2),
+	RK3066_PLL_RATE( 816000000, 1, 68, 2),
+	RK3066_PLL_RATE( 792000000, 1, 66, 2),
+	RK3066_PLL_RATE( 696000000, 1, 58, 2),
+	RK3066_PLL_RATE( 600000000, 1, 50, 2),
+	RK3066_PLL_RATE( 504000000, 1, 84, 4),
+	RK3066_PLL_RATE( 408000000, 1, 68, 4),
+	RK3066_PLL_RATE( 312000000, 1, 52, 4),
+	RK3066_PLL_RATE( 252000000, 1, 84, 8),
+	RK3066_PLL_RATE( 216000000, 1, 72, 8),
+	RK3066_PLL_RATE( 126000000, 1, 84, 16),
+	RK3066_PLL_RATE(  48000000, 1, 64, 32),
+	{ /* sentinel */ },
+};
+
+struct rockchip_pll_rate_table rk3188_cpll_rates[] = {
+	RK3066_PLL_RATE(1188000000, 2,  99, 1),
+	RK3066_PLL_RATE( 798000000, 2, 133, 2),
+	RK3066_PLL_RATE( 768000000, 1,  64, 2),
+	RK3066_PLL_RATE( 742500000, 8, 495, 2),
+	RK3066_PLL_RATE( 600000000, 1,  50, 2),
+	RK3066_PLL_RATE( 594000000, 2, 198, 4),
+	RK3066_PLL_RATE( 552000000, 1,  46, 2),
+	RK3066_PLL_RATE( 504000000, 1,  84, 4),
+	RK3066_PLL_RATE( 456000000, 1,  76, 4),
+	RK3066_PLL_RATE( 408000000, 1,  68, 4),
+	RK3066_PLL_RATE( 360000000, 1,  60, 4),
+	{ /* sentinel */ },
+};
+
+struct rockchip_pll_rate_table rk3188_gpll_rates[] = {
+	RK3066_PLL_RATE(1200000000, 1,  50, 1),
+	RK3066_PLL_RATE(1188000000, 2,  99, 1),
+	RK3066_PLL_RATE( 891000000, 8, 594, 2),
+	RK3066_PLL_RATE( 768000000, 1,  64, 2),
+	RK3066_PLL_RATE( 594000000, 2, 198, 4),
+	RK3066_PLL_RATE( 384000000, 2, 128, 4),
+	RK3066_PLL_RATE( 300000000, 1,  50, 4),
+	RK3066_PLL_RATE( 297000000, 2, 198, 8),
+	RK3066_PLL_RATE( 148500000, 2,  99, 8),
+	{ /* sentinel */ },
+};
+
+static struct rockchip_pll_clock rk3188_pll_clks[] __initdata = {
+	[apll] = PLL(pll_rk3066, 0, "apll", "xin24m", 0, RK2928_PLL_CON(0),
+		     RK2928_MODE_CON, 0, 6, rk3188_apll_rates),
+	[dpll] = PLL(pll_rk3066, 0, "dpll", "xin24m", 0, RK2928_PLL_CON(4),
+		     RK2928_MODE_CON, 4, 5, NULL),
+	[cpll] = PLL(pll_rk3066, 0, "cpll", "xin24m", 0, RK2928_PLL_CON(8),
+		     RK2928_MODE_CON, 8, 7, rk3188_cpll_rates),
+	[gpll] = PLL(pll_rk3066, 0, "gpll", "xin24m", 0, RK2928_PLL_CON(12),
+		     RK2928_MODE_CON, 12, 8, rk3188_gpll_rates),
+};
+
+PNAME(mux_pll_src_gpll_cpll_p)	= { "gpll", "cpll" };
+PNAME(mux_pll_src_cpll_gpll_p)	= { "cpll", "gpll" };
+
+PNAME(mux_armclk_p)		= { "apll", "gate_gpll_cpu" };
+PNAME(mux_aclk_cpu_p)		= { "apll", "gpll" };
+
+/* dummy is an undocumented clock called clk12m */
+PNAME(mux_sclk_i2s_p)		= { "gate_div_i2s", "gate_frac_i2s", "dummy" };
+PNAME(mux_sclk_spdif_p)		= { "gate_div_spdif", "gate_frac_spdif", "dummy" };
+
+PNAME(mux_sclk_uart0_p)		= { "gate_div_uart0", "gate_frac_uart0", "xin24m" };
+PNAME(mux_sclk_uart1_p)		= { "gate_div_uart1", "gate_frac_uart1", "xin24m" };
+PNAME(mux_sclk_uart2_p)		= { "gate_div_uart2", "gate_frac_uart2", "xin24m" };
+PNAME(mux_sclk_uart3_p)		= { "gate_div_uart3", "gate_frac_uart3", "xin24m" };
+
+PNAME(mux_mac_p)		= { "gpll", "dpll" };
+PNAME(mux_sclk_mac_p)		= { "gate_div_mac", "rmii_clkin" };
+
+PNAME(mux_hsicphy_p)		= { "gate_otgphy0", "gate_otgphy1", "gpll", "cpll" };
+
+PNAME(mux_ddr_p)		= { "dpll", "gate_gpll_ddr" };
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+static struct rockchip_mux_clock rk3188_mux_clks[] __initdata = {
+	MUX(0, "mux_aclk_cpu", mux_aclk_cpu_p, RK2928_CLKSEL_CON(0), 5, 1, CLK_SET_RATE_NO_REPARENT, MFLAGS),
+	MUX(0, "mux_aclk_peri", mux_pll_src_cpll_gpll_p, RK2928_CLKSEL_CON(10), 15, 1, CLK_SET_RATE_NO_REPARENT, MFLAGS),
+
+	MUX(0, "mux_i2s_pll", mux_pll_src_gpll_cpll_p, RK2928_CLKSEL_CON(2), 15, 1, 0, MFLAGS),
+	MUX(0, "mux_uart_pll", mux_pll_src_gpll_cpll_p, RK2928_CLKSEL_CON(12), 15, 1, 0, MFLAGS),
+
+	MUX(0, "mux_sclk_i2s", mux_sclk_i2s_p, RK2928_CLKSEL_CON(3), 8, 2, 0, MFLAGS),
+	MUX(0, "mux_sclk_spdif", mux_sclk_spdif_p, RK2928_CLKSEL_CON(5), 8, 2, 0, MFLAGS),
+
+	MUX(SCLK_UART0, "mux_sclk_uart0", mux_sclk_uart0_p, RK2928_CLKSEL_CON(13), 8, 2, 0, MFLAGS),
+	MUX(SCLK_UART1, "mux_sclk_uart1", mux_sclk_uart1_p, RK2928_CLKSEL_CON(14), 8, 2, 0, MFLAGS),
+	MUX(SCLK_UART2, "mux_sclk_uart2", mux_sclk_uart2_p, RK2928_CLKSEL_CON(15), 8, 2, 0, MFLAGS),
+	MUX(SCLK_UART3, "mux_sclk_uart3", mux_sclk_uart3_p, RK2928_CLKSEL_CON(16), 8, 2, 0, MFLAGS),
+
+	MUX(0, "mux_hsicphy", mux_hsicphy_p, RK2928_CLKSEL_CON(30), 0, 2, 0, MFLAGS),
+
+	MUX(0, "mux_mac", mux_mac_p, RK2928_CLKSEL_CON(21), 0, 2, 0, MFLAGS),
+	MUX(SCLK_MAC, "mux_sclk_mac", mux_sclk_mac_p, RK2928_CLKSEL_CON(21), 4, 1, 0, MFLAGS),
+
+	MUX(0, "mux_ddr", mux_ddr_p, RK2928_CLKSEL_CON(26), 8, 1, 0, MFLAGS),
+
+	MUX(0, "mux_dclk_lcdc0", mux_pll_src_cpll_gpll_p, RK2928_CLKSEL_CON(27), 0, 1, 0, MFLAGS),
+	MUX(0, "mux_dclk_lcdc1", mux_pll_src_cpll_gpll_p, RK2928_CLKSEL_CON(28), 0, 1, 0, MFLAGS),
+
+	MUX(0, "mux_aclk_lcdc0_pre", mux_pll_src_cpll_gpll_p, RK2928_CLKSEL_CON(31), 7, 1, 0, MFLAGS),
+	MUX(0, "mux_aclk_lcdc1_pre", mux_pll_src_cpll_gpll_p, RK2928_CLKSEL_CON(31), 15, 1, 0, MFLAGS),
+	MUX(0, "mux_aclk_vepu", mux_pll_src_cpll_gpll_p, RK2928_CLKSEL_CON(32), 7, 1, 0, MFLAGS),
+	MUX(0, "mux_aclk_vdpu", mux_pll_src_cpll_gpll_p, RK2928_CLKSEL_CON(32), 15, 1, 0, MFLAGS),
+	MUX(0, "mux_aclk_gpu", mux_pll_src_cpll_gpll_p, RK2928_CLKSEL_CON(34), 7, 1, 0, MFLAGS),
+};
+
+/* 2 ^ (val + 1) */
+static struct clk_div_table div_core_peri_t[] = {
+	{ .val = 0, .div = 2 },
+	{ .val = 1, .div = 4 },
+	{ .val = 2, .div = 8 },
+	{ .val = 3, .div = 16 },
+	{ /* sentinel */},
+};
+
+static struct clk_div_table div_aclk_core_t[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 1, .div = 2 },
+	{ .val = 2, .div = 3 },
+	{ .val = 3, .div = 4 },
+	{ .val = 4, .div = 8 },
+	{ /* sentinel */},
+};
+
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+static struct rockchip_div_clock rk3188_div_clks[] __initdata = {
+	/* these two are set by the cpuclk and should not be changed */
+	DIV(0, "div_core_peri", "armclk", RK2928_CLKSEL_CON(0), 6, 2, 0, DFLAGS | CLK_DIVIDER_READ_ONLY, div_core_peri_t),
+	DIV(0, "div_aclk_core", "armclk", RK2928_CLKSEL_CON(1), 3, 3, 0, DFLAGS | CLK_DIVIDER_READ_ONLY, div_aclk_core_t),
+
+	DIV(0, "div_aclk_cpu", "mux_aclk_cpu", RK2928_CLKSEL_CON(0), 0, 5, 0, DFLAGS, NULL),
+	DIV(0, "div_hclk_cpu", "gate_aclk_cpu", RK2928_CLKSEL_CON(1), 8, 2, 0, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, NULL),
+	DIV(0, "div_pclk_cpu", "gate_aclk_cpu", RK2928_CLKSEL_CON(1), 12, 2, 0, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, NULL),
+	DIV(0, "div_hclk_ahb2apb", "gate_hclk_ahb2apb", RK2928_CLKSEL_CON(1), 14, 2, 0, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, NULL),
+
+	DIV(0, "div_i2s", "mux_i2s_pll", RK2928_CLKSEL_CON(3), 0, 5, 0, DFLAGS, NULL),
+	DIV(0, "div_spdif", "mux_i2s_pll", RK2928_CLKSEL_CON(5), 0, 5, 0, DFLAGS, NULL),
+
+	DIV(0, "div_aclk_peri", "mux_aclk_peri", RK2928_CLKSEL_CON(10), 0, 5, 0, DFLAGS, NULL),
+	DIV(0, "div_hclk_peri", "gate_aclk_peri", RK2928_CLKSEL_CON(10), 8, 2, 0, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, NULL),
+	DIV(0, "div_pclk_peri", "gate_aclk_peri", RK2928_CLKSEL_CON(10), 12, 2, 0, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, NULL),
+
+	DIV(0, "div_uart0", "mux_uart_pll", RK2928_CLKSEL_CON(13), 0, 7, 0, DFLAGS, NULL),
+	DIV(0, "div_uart1", "mux_uart_pll", RK2928_CLKSEL_CON(14), 0, 7, 0, DFLAGS, NULL),
+	DIV(0, "div_uart2", "mux_uart_pll", RK2928_CLKSEL_CON(15), 0, 7, 0, DFLAGS, NULL),
+	DIV(0, "div_uart3", "mux_uart_pll", RK2928_CLKSEL_CON(16), 0, 7, 0, DFLAGS, NULL),
+
+	DIV(0, "div_mmc0", "gate_hclk_peri", RK2928_CLKSEL_CON(11), 0, 6, 0, DFLAGS, NULL),
+	DIV(0, "div_mmc1", "gate_hclk_peri", RK2928_CLKSEL_CON(12), 0, 6, 0, DFLAGS, NULL),
+	DIV(0, "div_mmc2", "gate_hclk_peri", RK2928_CLKSEL_CON(12), 8, 6, 0, DFLAGS, NULL),
+
+	DIV(0, "div_mac", "mux_mac", RK2928_CLKSEL_CON(21), 8, 5, CLK_SET_RATE_PARENT, DFLAGS, NULL),
+
+	DIV(0, "div_hsicphy", "mux_hsicphy", RK2928_CLKGATE_CON(11), 8, 6, 0, DFLAGS, NULL),
+
+	DIV(0, "div_saradc", "xin24m", RK2928_CLKSEL_CON(24), 8, 8, 0, DFLAGS, NULL),
+
+	DIV(0, "div_spi0", "gate_pclk_peri", RK2928_CLKSEL_CON(25), 0, 7, 0, DFLAGS, NULL),
+	DIV(0, "div_spi1", "gate_pclk_peri", RK2928_CLKSEL_CON(25), 8, 7, 0, DFLAGS, NULL),
+
+	DIV(0, "div_ddr", "mux_ddr", RK2928_CLKSEL_CON(26), 0, 2, 0, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, NULL),
+
+	DIV(0, "div_dclk_lcdc0", "mux_dclk_lcdc0", RK2928_CLKSEL_CON(27), 8, 8, 0, DFLAGS, NULL),
+	DIV(0, "div_dclk_lcdc1", "mux_dclk_lcdc1", RK2928_CLKSEL_CON(28), 8, 8, 0, DFLAGS, NULL),
+
+	DIV(0, "div_aclk_lcdc0_pre", "mux_aclk_lcdc0_pre", RK2928_CLKSEL_CON(31), 0, 5, 0, DFLAGS, NULL),
+	DIV(0, "div_aclk_lcdc1_pre", "mux_aclk_lcdc1_pre", RK2928_CLKSEL_CON(31), 8, 5, 0, DFLAGS, NULL),
+	DIV(0, "div_aclk_vepu", "mux_aclk_vepu", RK2928_CLKSEL_CON(32), 0, 5, 0, DFLAGS, NULL),
+	DIV(0, "div_aclk_vdpu", "mux_aclk_vdpu", RK2928_CLKSEL_CON(32), 8, 5, 0, DFLAGS, NULL),
+	DIV(0, "div_aclk_gpu", "mux_aclk_gpu", RK2928_CLKSEL_CON(34), 0, 5, 0, DFLAGS, NULL),
+};
+
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+static struct rockchip_gate_clock rk3188_gate_clks[] __initdata = {
+	/* CLKGATE_CON_0 */
+	GATE(CORE_PERI, "gate_core_peri", "div_core_peri", RK2928_CLKGATE_CON(0), 0, 0, GFLAGS),
+	GATE(0, "gate_gpll_cpu", "gpll", RK2928_CLKGATE_CON(0), 1, 0, GFLAGS),
+	GATE(0, "gate_ddr", "div_ddr", RK2928_CLKGATE_CON(0), 2, 0, GFLAGS),
+	GATE(0, "gate_aclk_cpu", "div_aclk_cpu", RK2928_CLKGATE_CON(0), 3, 0, GFLAGS),
+	GATE(0, "gate_hclk_cpu", "div_hclk_cpu", RK2928_CLKGATE_CON(0), 4, 0, GFLAGS),
+	GATE(0, "gate_pclk_cpu", "div_pclk_cpu", RK2928_CLKGATE_CON(0), 5, 0, GFLAGS),
+	GATE(0, "gate_atclk_cpu", "gate_pclk_cpu", RK2928_CLKGATE_CON(0), 6, 0, GFLAGS),
+	GATE(0, "gate_aclk_core", "div_aclk_core", RK2928_CLKGATE_CON(0), 7, 0, GFLAGS),
+	/* reserved */
+	GATE(0, "gate_div_i2s", "div_i2s", RK2928_CLKGATE_CON(0), 9, 0, GFLAGS),
+	GATE(0, "gate_frac_i2s", "frac_i2s", RK2928_CLKGATE_CON(0), 10, 0, GFLAGS),
+	/* reserved */
+	/* reserved */
+	GATE(0, "gate_div_spdif", "div_spdif", RK2928_CLKGATE_CON(13), 13, 0, GFLAGS),
+	GATE(0, "gate_frac_spdif", "frac_spdif", RK2928_CLKGATE_CON(0), 14, 0, GFLAGS),
+	GATE(0, "gate_testclk", "dummy", RK2928_CLKGATE_CON(0), 15, 0, GFLAGS),
+
+	/* CLKGATE_CON_1 */
+	GATE(0, "gate_timer0", "xin24m", RK2928_CLKGATE_CON(1), 0, 0, GFLAGS),
+	GATE(0, "gate_timer1", "xin24m", RK2928_CLKGATE_CON(1), 1, 0, GFLAGS),
+	GATE(0, "gate_timer3", "xin24m", RK2928_CLKGATE_CON(1), 2, 0, GFLAGS),
+	GATE(0, "gate_jtag", "dummy", RK2928_CLKGATE_CON(1), 3, 0, GFLAGS),
+	GATE(0, "gate_aclk_lcdc1_src", "div_aclk_lcdc1_pre", RK2928_CLKGATE_CON(1), 4, 0, GFLAGS),
+	GATE(0, "gate_otgphy0", "dummy480m", RK2928_CLKGATE_CON(1), 5, 0, GFLAGS),
+	GATE(0, "gate_otgphy1", "dummy480m", RK2928_CLKGATE_CON(1), 6, 0, GFLAGS),
+	GATE(0, "gate_gpll_ddr", "gpll", RK2928_CLKGATE_CON(1), 7, 0, GFLAGS),
+	GATE(0, "gate_div_uart0", "div_uart0", RK2928_CLKGATE_CON(1), 8, 0, GFLAGS),
+	GATE(0, "gate_frac_uart0", "frac_uart0", RK2928_CLKGATE_CON(1), 9, 0, GFLAGS),
+	GATE(0, "gate_div_uart1", "div_uart1", RK2928_CLKGATE_CON(1), 10, 0, GFLAGS),
+	GATE(0, "gate_frac_uart1", "frac_uart1", RK2928_CLKGATE_CON(1), 11, 0, GFLAGS),
+	GATE(0, "gate_div_uart2", "div_uart2", RK2928_CLKGATE_CON(1), 12, 0, GFLAGS),
+	GATE(0, "gate_frac_uart2", "frac_uart2", RK2928_CLKGATE_CON(1), 13, 0, GFLAGS),
+	GATE(0, "gate_div_uart3", "div_uart3", RK2928_CLKGATE_CON(1), 14, 0, GFLAGS),
+	GATE(0, "gate_frac_uart3", "frac_uart3", RK2928_CLKGATE_CON(1), 15, 0, GFLAGS),
+
+	/* CLKGATE_CON_2 */
+	GATE(0, "gate_peri_src", "gate_aclk_peri", RK2928_CLKGATE_CON(2), 0, 0, GFLAGS),
+	GATE(0, "gate_aclk_peri", "div_aclk_peri", RK2928_CLKGATE_CON(2), 1, 0, GFLAGS),
+	GATE(0, "gate_hclk_peri", "div_hclk_peri", RK2928_CLKGATE_CON(2), 2, 0, GFLAGS),
+	GATE(0, "gate_pclk_peri", "div_pclk_peri", RK2928_CLKGATE_CON(2), 3, 0, GFLAGS),
+	GATE(0, "gate_smc", "gate_hclk_peri", RK2928_CLKGATE_CON(2), 4, 0, GFLAGS),
+	GATE(0, "gate_div_mac", "div_mac", RK2928_CLKGATE_CON(2), 5, 0, GFLAGS),
+	GATE(0, "gate_div_hsadc", "div_hsadc", RK2928_CLKGATE_CON(2), 6, 0, GFLAGS),
+	GATE(0, "gate_frac_hsadc", "frac_hsadc", RK2928_CLKGATE_CON(2), 7, 0, GFLAGS),
+	GATE(0, "gate_div_saradc", "div_saradc", RK2928_CLKGATE_CON(2), 8, 0, GFLAGS),
+	GATE(0, "gate_div_spi0", "div_spi0", RK2928_CLKGATE_CON(2), 9, 0, GFLAGS),
+	GATE(0, "gate_div_spi1", "div_spi1", RK2928_CLKGATE_CON(2), 10, 0, GFLAGS),
+	GATE(SCLK_MMC0, "gate_div_mmc0", "div_mmc0", RK2928_CLKGATE_CON(2), 11, 0, GFLAGS),
+	GATE(0, "gate_mac_lbtest", "dummy", RK2928_CLKGATE_CON(2), 12, 0, GFLAGS),
+	GATE(SCLK_MMC1, "gate_div_mmc1", "div_mmc1", RK2928_CLKGATE_CON(2), 13, 0, GFLAGS),
+	GATE(SCLK_MMC2, "gate_div_mmc2", "div_mmc2", RK2928_CLKGATE_CON(2), 14, 0, GFLAGS),
+	/* reserved */
+
+	/* CLKGATE_CON_3 */
+	GATE(0, "gate_aclk_lcdc0_src", "div_aclk_lcdc0_pre", RK2928_CLKGATE_CON(3), 0, 0, GFLAGS),
+	GATE(0, "gate_dclk_lcdc0_src", "div_dclk_lcdc0", RK2928_CLKGATE_CON(3), 1, 0, GFLAGS),
+	GATE(0, "gate_dclk_lcdc1_src", "div_dclk_lcdc1", RK2928_CLKGATE_CON(3), 2, 0, GFLAGS),
+	GATE(0, "gate_pclkin_cif", "dummy", RK2928_CLKGATE_CON(3), 3, 0, GFLAGS),
+	GATE(0, "gate_timer2", "xin24m", RK2928_CLKGATE_CON(3), 4, 0, GFLAGS),
+	GATE(0, "gate_timer4", "xin24m", RK2928_CLKGATE_CON(3), 5, 0, GFLAGS),
+	GATE(0, "gate_hsicphy", "dummy", RK2928_CLKGATE_CON(3), 6, 0, GFLAGS),
+	GATE(0, "gate_div_cif_out", "div_cif_out", RK2928_CLKGATE_CON(3), 7, 0, GFLAGS),
+	GATE(0, "gate_timer5", "xin24m", RK2928_CLKGATE_CON(3), 8, 0, GFLAGS),
+	GATE(0, "gate_div_aclk_vepu", "div_aclk_vepu", RK2928_CLKGATE_CON(3), 9, 0, GFLAGS),
+	GATE(0, "gate_hclk_vepu", "dummy", RK2928_CLKGATE_CON(3), 10, 0, GFLAGS),
+	GATE(0, "gate_div_aclk_vdpu", "div_aclk_vdpu", RK2928_CLKGATE_CON(3), 11, 0, GFLAGS),
+	GATE(0, "gate_hclk_vdpu", "dummy", RK2928_CLKGATE_CON(3), 12, 0, GFLAGS),
+	/* reserved 13 */
+	GATE(0, "gate_timer6", "xin24m", RK2928_CLKGATE_CON(3), 14, 0, GFLAGS),
+	GATE(0, "gate_aclk_gpu_src", "dummy", RK2928_CLKGATE_CON(3), 15, 0, GFLAGS),
+
+	/* CLKGATE_CON_4 */
+	GATE(0, "gate_hclk_peri_axi_matrix", "gate_hclk_peri", RK2928_CLKGATE_CON(4), 0, 0, GFLAGS),
+	GATE(0, "gate_pclk_peri_axi_matrix", "gate_pclk_peri", RK2928_CLKGATE_CON(4), 1, 0, GFLAGS),
+	GATE(0, "gate_aclk_cpu_peri", "gate_aclk_peri", RK2928_CLKGATE_CON(4), 2, 0, GFLAGS),
+	GATE(0, "gate_aclk_peri_axi_matrix", "gate_aclk_peri", RK2928_CLKGATE_CON(4), 3, 0, GFLAGS),
+	GATE(0, "gate_aclk_peri_niu", "gate_aclk_peri", RK2928_CLKGATE_CON(4), 4, 0, GFLAGS),
+	GATE(0, "gate_hclk_peri_usb", "gate_hclk_peri", RK2928_CLKGATE_CON(4), 5, 0, GFLAGS),
+	GATE(0, "gate_hclk_peri_ahb_arbi", "gate_hclk_peri", RK2928_CLKGATE_CON(4), 6, 0, GFLAGS),
+	GATE(0, "gate_hclk_peri_emem", "gate_hclk_peri", RK2928_CLKGATE_CON(4), 7, 0, GFLAGS),
+	GATE(0, "gate_hclk_cpubus", "gate_hclk_cpu", RK2928_CLKGATE_CON(4), 8, 0, GFLAGS),
+	GATE(0, "gate_hclk_ahb2apb", "gate_hclk_cpu", RK2928_CLKGATE_CON(4), 9, 0, GFLAGS),
+	GATE(0, "gate_aclk_strc_sys", "gate_aclk_cpu", RK2928_CLKGATE_CON(4), 10, 0, GFLAGS),
+	/* reserved 11 */
+	GATE(0, "gate_aclk_intmem", "gate_aclk_cpu", RK2928_CLKGATE_CON(4), 12, 0, GFLAGS),
+	/* reserved 13 */
+	GATE(0, "gate_hclk_imem0", "gate_hclk_cpu", RK2928_CLKGATE_CON(4), 14, 0, GFLAGS),
+	GATE(0, "gate_hclk_imem1", "gate_hclk_cpu", RK2928_CLKGATE_CON(4), 15, 0, GFLAGS),
+
+	/* CLKGATE_CON_5 */
+	GATE(ACLK_DMAC0, "gate_aclk_dmac0", "gate_aclk_cpu", RK2928_CLKGATE_CON(5), 0, 0, GFLAGS),
+	GATE(ACLK_DMAC1, "gate_aclk_dmac1", "gate_aclk_peri", RK2928_CLKGATE_CON(5), 1, 0, GFLAGS),
+	GATE(0, "gate_pclk_efuse", "gate_pclk_cpu", RK2928_CLKGATE_CON(5), 2, 0, GFLAGS),
+	GATE(0, "gate_pclk_tzpc", "gate_pclk_cpu", RK2928_CLKGATE_CON(5), 3, 0, GFLAGS),
+	GATE(PCLK_GRF, "gate_pclk_grf", "gate_pclk_cpu", RK2928_CLKGATE_CON(5), 4, 0, GFLAGS),
+	GATE(PCLK_PMU, "gate_pclk_pmu", "gate_pclk_cpu", RK2928_CLKGATE_CON(5), 5, 0, GFLAGS),
+	GATE(0, "gate_hclk_rom", "gate_hclk_cpu", RK2928_CLKGATE_CON(5), 6, 0, GFLAGS),
+	GATE(0, "gate_pclk_ddrupctl", "gate_pclk_cpu", RK2928_CLKGATE_CON(5), 7, 0, GFLAGS),
+	GATE(0, "gate_aclk_smc", "gate_aclk_peri", RK2928_CLKGATE_CON(5), 8, 0, GFLAGS),
+	GATE(0, "gate_hclk_nand", "gate_hclk_peri", RK2928_CLKGATE_CON(5), 9, 0, GFLAGS),
+	GATE(HCLK_MMC0, "gate_hclk_mmc0", "gate_hclk_peri", RK2928_CLKGATE_CON(5), 10, 0, GFLAGS),
+	GATE(HCLK_MMC1, "gate_hclk_mmc1", "gate_hclk_peri", RK2928_CLKGATE_CON(5), 11, 0, GFLAGS),
+	GATE(HCLK_MMC2, "gate_hclk_mmc2", "gate_hclk_peri", RK2928_CLKGATE_CON(5), 12, 0, GFLAGS),
+	GATE(HCLK_OTG0, "gate_hclk_otg0", "gate_hclk_peri_usb", RK2928_CLKGATE_CON(5), 13, 0, GFLAGS),
+	/* reserved 14:15 */
+
+	/* CLKGATE_CON_6 */
+	GATE(0, "gate_aclk_lcdc0", "gate_aclk_vio0", RK2928_CLKGATE_CON(6), 0, 0, GFLAGS),
+	GATE(0, "gate_hclk_lcdc0", "gate_hclk_cpu", RK2928_CLKGATE_CON(6), 1, 0, GFLAGS),
+	GATE(0, "gate_hclk_lcdc1", "gate_aclk_cpu", RK2928_CLKGATE_CON(6), 2, 0, GFLAGS),
+	GATE(0, "gate_aclk_lcdc1", "gate_aclk_vio1", RK2928_CLKGATE_CON(6), 3, 0, GFLAGS),
+	GATE(0, "gate_hclk_cif", "gate_hclk_cpu", RK2928_CLKGATE_CON(6), 4, 0, GFLAGS),
+	GATE(0, "gate_aclk_cif", "gate_aclk_vio0", RK2928_CLKGATE_CON(6), 5, 0, GFLAGS),
+	/* reserved 6:7 */
+	GATE(0, "gate_aclk_ipp", "gate_aclk_vio0", RK2928_CLKGATE_CON(6), 8, 0, GFLAGS),
+	GATE(0, "gate_hclk_ipp", "gate_hclk_cpu", RK2928_CLKGATE_CON(6), 9, 0, GFLAGS),
+	GATE(0, "gate_hclk_rga", "gate_hclk_cpu", RK2928_CLKGATE_CON(6), 10, 0, GFLAGS),
+	GATE(0, "gate_aclk_rga", "gate_aclk_vio1", RK2928_CLKGATE_CON(6), 11, 0, GFLAGS),
+	GATE(0, "gate_hclk_vio_bus", "gate_hclk_cpu", RK2928_CLKGATE_CON(6), 12, 0, GFLAGS),
+	GATE(0, "gate_aclk_vio0", "gate_div_aclk_lcdc0", RK2928_CLKGATE_CON(6), 13, 0, GFLAGS),
+	/* reserved 14:15 */
+
+	/* CLKGATE_CON_7 */
+	GATE(HCLK_EMAC, "gate_hclk_emac", "gate_hclk_peri", RK2928_CLKGATE_CON(7), 0, 0, GFLAGS),
+	GATE(HCLK_SPDIF, "gate_hclk_spdif", "gate_hclk_cpu", RK2928_CLKGATE_CON(7), 1, 0, GFLAGS),
+	GATE(HCLK_I2S, "gate_hclk_i2s", "gate_hclk_cpu", RK2928_CLKGATE_CON(7), 2, 0, GFLAGS),
+	GATE(HCLK_OTG1, "gate_hclk_otg1", "gate_hclk_peri_usb", RK2928_CLKGATE_CON(7), 3, 0, GFLAGS),
+	GATE(HCLK_HSIC, "gate_hclk_hsic", "gate_hclk_peri", RK2928_CLKGATE_CON(7), 4, 0, GFLAGS),
+	GATE(HCLK_HSADC, "gate_hclk_hsadc", "gate_hclk_peri", RK2928_CLKGATE_CON(7), 5, 0, GFLAGS),
+	GATE(HCLK_PIDF, "gate_hclk_pidf", "gate_hclk_peri", RK2928_CLKGATE_CON(7), 6, 0, GFLAGS),
+	GATE(PCLK_TIMER0, "gate_pclk_timer0", "gate_pclk_cpu", RK2928_CLKGATE_CON(7), 7, 0, GFLAGS),
+	/* reserved 8 */
+	GATE(PCLK_TIMER2, "gate_pclk_timer2", "gate_pclk_cpu", RK2928_CLKGATE_CON(7), 9, 0, GFLAGS),
+	GATE(PCLK_PWM01, "gate_pclk_pwm01", "gate_pclk_cpu", RK2928_CLKGATE_CON(7), 10, 0, GFLAGS),
+	GATE(PCLK_PWM23, "gate_pclk_pwm23", "gate_pclk_peri", RK2928_CLKGATE_CON(7), 11, 0, GFLAGS),
+	GATE(PCLK_SPI0, "gate_pclk_spi0", "gate_pclk_peri", RK2928_CLKGATE_CON(7), 12, 0, GFLAGS),
+	GATE(PCLK_SPI1, "gate_pclk_spi1", "gate_pclk_peri", RK2928_CLKGATE_CON(7), 13, 0, GFLAGS),
+	GATE(PCLK_SARADC, "gate_pclk_saradc", "gate_pclk_peri", RK2928_CLKGATE_CON(7), 14, 0, GFLAGS),
+	GATE(PCLK_WDT, "gate_pclk_wdt", "gate_pclk_peri", RK2928_CLKGATE_CON(7), 15, 0, GFLAGS),
+
+	/* CLKGATE_CON_8 */
+	GATE(PCLK_UART0, "gate_pclk_uart0", "div_hclk_ahb2apb", RK2928_CLKGATE_CON(8), 0, 0, GFLAGS),
+	GATE(PCLK_UART1, "gate_pclk_uart1", "div_hclk_ahb2apb", RK2928_CLKGATE_CON(8), 1, 0, GFLAGS),
+	GATE(PCLK_UART2, "gate_pclk_uart2", "gate_pclk_peri", RK2928_CLKGATE_CON(8), 2, 0, GFLAGS),
+	GATE(PCLK_UART3, "gate_pclk_uart3", "gate_pclk_peri", RK2928_CLKGATE_CON(8), 3, 0, GFLAGS),
+	GATE(PCLK_I2C0, "gate_pclk_i2c0", "gate_pclk_cpu", RK2928_CLKGATE_CON(8), 4, 0, GFLAGS),
+	GATE(PCLK_I2C1, "gate_pclk_i2c1", "gate_pclk_cpu", RK2928_CLKGATE_CON(8), 5, 0, GFLAGS),
+	GATE(PCLK_I2C2, "gate_pclk_i2c2", "gate_pclk_peri", RK2928_CLKGATE_CON(8), 6, 0, GFLAGS),
+	GATE(PCLK_I2C3, "gate_pclk_i2c3", "gate_pclk_peri", RK2928_CLKGATE_CON(8), 7, 0, GFLAGS),
+	GATE(PCLK_I2C4, "gate_pclk_i2c4", "gate_pclk_peri", RK2928_CLKGATE_CON(8), 8, 0, GFLAGS),
+	GATE(PCLK_GPIO0, "gate_pclk_gpio0", "gate_pclk_cpu", RK2928_CLKGATE_CON(8), 9, 0, GFLAGS),
+	GATE(PCLK_GPIO1, "gate_pclk_gpio1", "gate_pclk_cpu", RK2928_CLKGATE_CON(8), 10, 0, GFLAGS),
+	GATE(PCLK_GPIO2, "gate_pclk_gpio2", "gate_pclk_cpu", RK2928_CLKGATE_CON(8), 11, 0, GFLAGS),
+	GATE(PCLK_GPIO3, "gate_pclk_gpio3", "gate_pclk_peri", RK2928_CLKGATE_CON(8), 12, 0, GFLAGS),
+	GATE(ACLK_GPS, "gate_aclk_gps", "gate_aclk_peri", RK2928_CLKGATE_CON(8), 13, 0, GFLAGS),
+	/* reserved 14:15 */
+
+	/* CLKGATE_CON_9 */
+	GATE(0, "gate_core_dbg", "armclk", RK2928_CLKGATE_CON(9), 0, 0, GFLAGS),
+	GATE(0, "gate_pclk_dbg", "gate_pclk_cpu", RK2928_CLKGATE_CON(9), 1, 0, GFLAGS),
+	GATE(0, "gate_clk_trace", "dummy", RK2928_CLKGATE_CON(9), 2, 0, GFLAGS),
+	GATE(0, "gate_atclk", "dummy", RK2928_CLKGATE_CON(9), 3, 0, GFLAGS),
+	GATE(CORE_L2C, "gate_core_l2c", "armclk", RK2928_CLKGATE_CON(9), 4, 0, GFLAGS),
+	GATE(0, "gate_aclk_vio1", "div_aclk_lcdc1", RK2928_CLKGATE_CON(9), 5, 0, GFLAGS),
+	GATE(0, "gate_pclk_publ", "gate_pclk_cpu", RK2928_CLKGATE_CON(9), 6, 0, GFLAGS),
+	GATE(0, "gate_aclk_gpu", "div_aclk_gpu", RK2928_CLKGATE_CON(9), 7, 0, GFLAGS),
+	/* reserved 8:15 */
+};
+
+static void __init rk3188_clk_init(struct device_node *np)
+{
+	void __iomem *reg_base, *reg_grf_soc_status;
+
+	reg_base = of_iomap(np, 0);
+	if (!reg_base) {
+		pr_err("%s: could not map cru region\n", __func__);
+		return;
+	}
+
+	reg_grf_soc_status = of_iomap(np, 1);
+	if (!reg_grf_soc_status) {
+		pr_err("%s: could not map soc_status register\n", __func__);
+		return;
+	}
+
+	rockchip_clk_init(np, reg_base, NR_CLKS);
+
+	rockchip_clk_register_plls(rk3188_pll_clks,
+				   ARRAY_SIZE(rk3188_pll_clks),
+				   reg_grf_soc_status);
+
+	rockchip_clk_register_mux(rk3188_mux_clks,
+				  ARRAY_SIZE(rk3188_mux_clks));
+	rockchip_clk_register_div(rk3188_div_clks,
+				  ARRAY_SIZE(rk3188_div_clks));
+	rockchip_clk_register_gate(rk3188_gate_clks,
+				   ARRAY_SIZE(rk3188_gate_clks));
+
+	rockchip_clk_register_armclk(SCLK_ARMCLK, "armclk", mux_armclk_p,
+				     ARRAY_SIZE(mux_armclk_p), reg_base, np);
+
+	rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
+				  ROCKCHIP_SOFTRST_HIWORD_MASK);
+}
+CLK_OF_DECLARE(rk3188_cru, "rockchip,rk3188-cru", rk3188_clk_init);
diff --git a/include/dt-bindings/clock/rk3188-cru.h b/include/dt-bindings/clock/rk3188-cru.h
new file mode 100644
index 0000000..39585a5
--- /dev/null
+++ b/include/dt-bindings/clock/rk3188-cru.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Keep gate clock numbers sorted according to their gate and index.
+ * This also adds space in front for 31 special clocks.
+ */
+#define CLK_GATE(_reg, _bit) ((_reg + 2) * 16 + _bit)
+
+/* special clocks not ending in a gate */
+#define SCLK_ARMCLK	1
+#define SCLK_UART0	2
+#define SCLK_UART1	3
+#define SCLK_UART2	4
+#define SCLK_UART3	5
+#define SCLK_MAC	6
+
+/* gated clock used by peripherals */
+#define CORE_PERI	CLK_GATE(0, 0)
+
+#define SCLK_MMC0	CLK_GATE(2, 11)
+#define SCLK_MMC1	CLK_GATE(2, 13)
+#define SCLK_MMC2	CLK_GATE(2, 14)
+
+#define ACLK_DMAC0	CLK_GATE(5, 0)
+#define ACLK_DMAC1	CLK_GATE(5, 1)
+#define PCLK_GRF	CLK_GATE(5, 4)
+#define PCLK_PMU	CLK_GATE(5, 5)
+#define HCLK_MMC0	CLK_GATE(5, 10)
+#define HCLK_MMC1	CLK_GATE(5, 11)
+#define HCLK_MMC2	CLK_GATE(5, 12)
+#define HCLK_OTG0	CLK_GATE(5, 13)
+
+#define HCLK_EMAC	CLK_GATE(7, 0)
+#define HCLK_SPDIF	CLK_GATE(7, 1)
+#define HCLK_I2S	CLK_GATE(7, 2)
+#define HCLK_OTG1	CLK_GATE(7, 3)
+#define HCLK_HSIC	CLK_GATE(7, 4)
+#define HCLK_HSADC	CLK_GATE(7, 5)
+#define HCLK_PIDF	CLK_GATE(7, 6)
+#define PCLK_TIMER0	CLK_GATE(7, 7)
+#define PCLK_TIMER2	CLK_GATE(7, 9)
+#define PCLK_PWM01	CLK_GATE(7, 10)
+#define PCLK_PWM23	CLK_GATE(7, 11)
+#define PCLK_SPI0	CLK_GATE(7, 12)
+#define PCLK_SPI1	CLK_GATE(7, 13)
+#define PCLK_SARADC	CLK_GATE(7, 14)
+#define PCLK_WDT	CLK_GATE(7, 15)
+
+#define PCLK_UART0	CLK_GATE(8, 0)
+#define PCLK_UART1	CLK_GATE(8, 1)
+#define PCLK_UART2	CLK_GATE(8, 2)
+#define PCLK_UART3	CLK_GATE(8, 3)
+#define PCLK_I2C0	CLK_GATE(8, 4)
+#define PCLK_I2C1	CLK_GATE(8, 5)
+#define PCLK_I2C2	CLK_GATE(8, 6)
+#define PCLK_I2C3	CLK_GATE(8, 7)
+#define PCLK_I2C4	CLK_GATE(8, 8)
+#define PCLK_GPIO0	CLK_GATE(8, 9)
+#define PCLK_GPIO1	CLK_GATE(8, 10)
+#define PCLK_GPIO2	CLK_GATE(8, 11)
+#define PCLK_GPIO3	CLK_GATE(8, 12)
+#define ACLK_GPS	CLK_GATE(8, 13)
+
+#define CORE_L2C	CLK_GATE(9, 4)
+
+#define NR_CLKS		(CORE_L2C + 1)
-- 
1.9.0

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

* [PATCH 08/11] ARM: rockchip: Select ARCH_HAS_RESET_CONTROLLER
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
                   ` (6 preceding siblings ...)
  2014-04-16 16:43 ` [PATCH 07/11] clk: rockchip: add clock driver for rk3188 clocks Heiko Stübner
@ 2014-04-16 16:44 ` Heiko Stübner
  2014-04-16 16:44 ` [PATCH 09/11] ARM: dts: rk3188: add cru node and update device clocks to use it Heiko Stübner
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:44 UTC (permalink / raw)
  To: linux-arm-kernel

All known Rockchip SoCs have a reset controller in their CRUs, so it's
helpful to have the reset controller framework selected by default,
only be deselected by the user in special cases.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/mach-rockchip/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 1caee6d..e4564c2 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -2,6 +2,7 @@ config ARCH_ROCKCHIP
 	bool "Rockchip RK2928 and RK3xxx SOCs" if ARCH_MULTI_V7
 	select PINCTRL
 	select PINCTRL_ROCKCHIP
+	select ARCH_HAS_RESET_CONTROLLER
 	select ARCH_REQUIRE_GPIOLIB
 	select ARM_GIC
 	select CACHE_L2X0
-- 
1.9.0

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

* [PATCH 09/11] ARM: dts: rk3188: add cru node and update device clocks to use it
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
                   ` (7 preceding siblings ...)
  2014-04-16 16:44 ` [PATCH 08/11] ARM: rockchip: Select ARCH_HAS_RESET_CONTROLLER Heiko Stübner
@ 2014-04-16 16:44 ` Heiko Stübner
  2014-04-16 16:45 ` [PATCH 10/11] ARM: dts: rockchip: move rk3188 core input clocks into main dtsi Heiko Stübner
  2014-04-16 16:46 ` [PATCH 11/11] ARM: dts: rockchip: remove the now obsolete rk3188-clocks.dtsi Heiko Stübner
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:44 UTC (permalink / raw)
  To: linux-arm-kernel

This adds a node for the clock and reset unit on rk3188 SoCs and updates
the device nodes retrieve their clocks from there, instead of the previous
gate clock nodes.

As the clocks diverge a bit until rk3066 can catch up, the shared nodes
between rk3066 and rk3188 get separated clocks-properties in the rk3188.dtsi.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/boot/dts/rk3188.dtsi | 55 +++++++++++++++++++++++++++++++++++++++----
 1 file changed, 51 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index bb36596..dc3e986 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -15,6 +15,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/clock/rk3188-cru.h>
 #include "rk3xxx.dtsi"
 #include "rk3188-clocks.dtsi"
 
@@ -54,10 +55,12 @@
 	soc {
 		global-timer at 1013c200 {
 			interrupts = <GIC_PPI 11 0xf04>;
+			clocks = <&cru CORE_PERI>;
 		};
 
 		local-timer at 1013c600 {
 			interrupts = <GIC_PPI 13 0xf04>;
+			clocks = <&cru CORE_PERI>;
 		};
 
 		sram: sram at 10080000 {
@@ -73,6 +76,50 @@
 			};
 		};
 
+		uart0: serial at 10124000 {
+			clocks = <&cru SCLK_UART0>;
+		};
+
+		uart1: serial at 10126000 {
+			clocks = <&cru SCLK_UART1>;
+		};
+
+		uart2: serial at 20064000 {
+			clocks = <&cru SCLK_UART2>;
+		};
+
+		uart3: serial at 20068000 {
+			clocks = <&cru SCLK_UART3>;
+		};
+
+		dwmmc at 10214000 {
+			clocks = <&cru HCLK_MMC0>, <&cru SCLK_MMC0>;
+			clock-names = "biu", "ciu";
+		};
+
+		dwmmc at 10218000 {
+			clocks = <&cru HCLK_MMC1>, <&cru SCLK_MMC1>;
+			clock-names = "biu", "ciu";
+		};
+
+		cru: cru at 20000000 {
+			compatible = "rockchip,rk3188-cru";
+			reg = <0x20000000 0x1000>,
+			      <0x200080ac 0x4>;
+
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+
+			#rockchip,armclk-cells = <3>;
+			rockchip,armclk-divider-table = <1608000 2 3>,
+							<1416000 2 3>,
+							<1200000 2 3>,
+							<1008000 2 3>,
+							< 816000 2 3>,
+							< 504000 1 3>,
+							< 312000 0 1>;
+		};
+
 		pinctrl at 20008000 {
 			compatible = "rockchip,rk3188-pinctrl";
 			reg = <0x20008000 0xa0>,
@@ -87,7 +134,7 @@
 				reg = <0x2000a000 0x100>,
 				      <0x20004064 0x8>;
 				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk_gates8 9>;
+				clocks = <&cru PCLK_GPIO0>;
 
 				gpio-controller;
 				#gpio-cells = <2>;
@@ -100,7 +147,7 @@
 				compatible = "rockchip,gpio-bank";
 				reg = <0x2003c000 0x100>;
 				interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk_gates8 10>;
+				clocks = <&cru PCLK_GPIO1>;
 
 				gpio-controller;
 				#gpio-cells = <2>;
@@ -113,7 +160,7 @@
 				compatible = "rockchip,gpio-bank";
 				reg = <0x2003e000 0x100>;
 				interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk_gates8 11>;
+				clocks = <&cru PCLK_GPIO2>;
 
 				gpio-controller;
 				#gpio-cells = <2>;
@@ -126,7 +173,7 @@
 				compatible = "rockchip,gpio-bank";
 				reg = <0x20080000 0x100>;
 				interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk_gates8 12>;
+				clocks = <&cru PCLK_GPIO3>;
 
 				gpio-controller;
 				#gpio-cells = <2>;
-- 
1.9.0

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

* [PATCH 10/11] ARM: dts: rockchip: move rk3188 core input clocks into main dtsi
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
                   ` (8 preceding siblings ...)
  2014-04-16 16:44 ` [PATCH 09/11] ARM: dts: rk3188: add cru node and update device clocks to use it Heiko Stübner
@ 2014-04-16 16:45 ` Heiko Stübner
  2014-04-16 16:46 ` [PATCH 11/11] ARM: dts: rockchip: remove the now obsolete rk3188-clocks.dtsi Heiko Stübner
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

The clock definitions get a lot shorter due to the soc clocks being handled by
rk3188-cru and only the input clocks remaining. These can not simply live
in the main rk3188.dtsi without affecting readability.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/boot/dts/rk3188-clocks.dtsi | 18 ------------------
 arch/arm/boot/dts/rk3188.dtsi        | 24 ++++++++++++++++++++++++
 2 files changed, 24 insertions(+), 18 deletions(-)

diff --git a/arch/arm/boot/dts/rk3188-clocks.dtsi b/arch/arm/boot/dts/rk3188-clocks.dtsi
index b1b92dc..8c1577a 100644
--- a/arch/arm/boot/dts/rk3188-clocks.dtsi
+++ b/arch/arm/boot/dts/rk3188-clocks.dtsi
@@ -19,24 +19,6 @@
 		#size-cells = <1>;
 		ranges;
 
-		/*
-		 * This is a dummy clock, to be used as placeholder on
-		 * other mux clocks when a specific parent clock is not
-		 * yet implemented. It should be dropped when the driver
-		 * is complete.
-		 */
-		dummy: dummy {
-			compatible = "fixed-clock";
-			clock-frequency = <0>;
-			#clock-cells = <0>;
-		};
-
-		xin24m: xin24m {
-			compatible = "fixed-clock";
-			clock-frequency = <24000000>;
-			#clock-cells = <0>;
-		};
-
 		dummy48m: dummy48m {
 			compatible = "fixed-clock";
 			clock-frequency = <48000000>;
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index dc3e986..c248748 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -52,6 +52,30 @@
 		};
 	};
 
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/*
+		 * This is a dummy clock, to be used as placeholder on
+		 * other mux clocks when a specific parent clock is not
+		 * yet implemented. It should be dropped when the driver
+		 * is complete.
+		 */
+		dummy: dummy {
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+			#clock-cells = <0>;
+		};
+
+		xin24m: xin24m {
+			compatible = "fixed-clock";
+			clock-frequency = <24000000>;
+			#clock-cells = <0>;
+		};
+	};
+
 	soc {
 		global-timer at 1013c200 {
 			interrupts = <GIC_PPI 11 0xf04>;
-- 
1.9.0

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

* [PATCH 11/11] ARM: dts: rockchip: remove the now obsolete rk3188-clocks.dtsi
  2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
                   ` (9 preceding siblings ...)
  2014-04-16 16:45 ` [PATCH 10/11] ARM: dts: rockchip: move rk3188 core input clocks into main dtsi Heiko Stübner
@ 2014-04-16 16:46 ` Heiko Stübner
  10 siblings, 0 replies; 13+ messages in thread
From: Heiko Stübner @ 2014-04-16 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

The clocks.dtsi does not contain any meaningful data anymore and can thus
go away, as all clocks are now handled in the main dtsi.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/boot/dts/rk3188-clocks.dtsi | 271 -----------------------------------
 arch/arm/boot/dts/rk3188.dtsi        |   1 -
 2 files changed, 272 deletions(-)
 delete mode 100644 arch/arm/boot/dts/rk3188-clocks.dtsi

diff --git a/arch/arm/boot/dts/rk3188-clocks.dtsi b/arch/arm/boot/dts/rk3188-clocks.dtsi
deleted file mode 100644
index 8c1577a..0000000
--- a/arch/arm/boot/dts/rk3188-clocks.dtsi
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (c) 2013 MundoReader S.L.
- * Author: Heiko Stuebner <heiko@sntech.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/ {
-	clocks {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		dummy48m: dummy48m {
-			compatible = "fixed-clock";
-			clock-frequency = <48000000>;
-			#clock-cells = <0>;
-		};
-
-		dummy150m: dummy150m {
-			compatible = "fixed-clock";
-			clock-frequency = <150000000>;
-			#clock-cells = <0>;
-		};
-
-		clk_gates0: gate-clk at 200000d0 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000d0 0x4>;
-			clocks = <&dummy150m>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>;
-
-			clock-output-names =
-				"gate_core_periph", "gate_cpu_gpll",
-				"gate_ddrphy", "gate_aclk_cpu",
-				"gate_hclk_cpu", "gate_pclk_cpu",
-				"gate_atclk_cpu", "gate_aclk_core",
-				"reserved", "gate_i2s0",
-				"gate_i2s0_frac", "reserved",
-				"reserved", "gate_spdif",
-				"gate_spdif_frac", "gate_testclk";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates1: gate-clk at 200000d4 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000d4 0x4>;
-			clocks = <&xin24m>, <&xin24m>,
-				 <&xin24m>, <&dummy>,
-				 <&dummy>, <&xin24m>,
-				 <&xin24m>, <&dummy>,
-				 <&xin24m>, <&dummy>,
-				 <&xin24m>, <&dummy>,
-				 <&xin24m>, <&dummy>,
-				 <&xin24m>, <&dummy>;
-
-			clock-output-names =
-				"gate_timer0", "gate_timer1",
-				"gate_timer3", "gate_jtag",
-				"gate_aclk_lcdc1_src", "gate_otgphy0",
-				"gate_otgphy1", "gate_ddr_gpll",
-				"gate_uart0", "gate_frac_uart0",
-				"gate_uart1", "gate_frac_uart1",
-				"gate_uart2", "gate_frac_uart2",
-				"gate_uart3", "gate_frac_uart3";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates2: gate-clk at 200000d8 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000d8 0x4>;
-			clocks = <&clk_gates2 1>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&clk_gates2 3>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy48m>,
-				 <&dummy>, <&dummy48m>,
-				 <&dummy>, <&dummy>;
-
-			clock-output-names =
-				"gate_periph_src", "gate_aclk_periph",
-				"gate_hclk_periph", "gate_pclk_periph",
-				"gate_smc", "gate_mac",
-				"gate_hsadc", "gate_hsadc_frac",
-				"gate_saradc", "gate_spi0",
-				"gate_spi1", "gate_mmc0",
-				"gate_mac_lbtest", "gate_mmc1",
-				"gate_emmc", "reserved";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates3: gate-clk at 200000dc {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000dc 0x4>;
-			clocks = <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&xin24m>, <&xin24m>,
-				 <&dummy>, <&dummy>,
-				 <&xin24m>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&xin24m>, <&dummy>;
-
-			clock-output-names =
-				"gate_aclk_lcdc0_src", "gate_dclk_lcdc0",
-				"gate_dclk_lcdc1", "gate_pclkin_cif0",
-				"gate_timer2", "gate_timer4",
-				"gate_hsicphy", "gate_cif0_out",
-				"gate_timer5", "gate_aclk_vepu",
-				"gate_hclk_vepu", "gate_aclk_vdpu",
-				"gate_hclk_vdpu", "reserved",
-				"gate_timer6", "gate_aclk_gpu_src";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates4: gate-clk at 200000e0 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000e0 0x4>;
-			clocks = <&clk_gates2 2>, <&clk_gates2 3>,
-				 <&clk_gates2 1>, <&clk_gates2 1>,
-				 <&clk_gates2 1>, <&clk_gates2 2>,
-				 <&clk_gates2 2>, <&clk_gates2 2>,
-				 <&clk_gates0 4>, <&clk_gates0 4>,
-				 <&clk_gates0 3>, <&dummy>,
-				 <&clk_gates0 3>, <&dummy>,
-				 <&dummy>, <&dummy>;
-
-			clock-output-names =
-				"gate_hclk_peri_axi_matrix", "gate_pclk_peri_axi_matrix",
-				"gate_aclk_cpu_peri", "gate_aclk_peri_axi_matrix",
-				"gate_aclk_pei_niu", "gate_hclk_usb_peri",
-				"gate_hclk_peri_ahb_arbi", "gate_hclk_emem_peri",
-				"gate_hclk_cpubus", "gate_hclk_ahb2apb",
-				"gate_aclk_strc_sys", "reserved",
-				"gate_aclk_intmem", "reserved",
-				"gate_hclk_imem1", "gate_hclk_imem0";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates5: gate-clk at 200000e4 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000e4 0x4>;
-			clocks = <&clk_gates0 3>, <&clk_gates2 1>,
-				 <&clk_gates0 5>, <&clk_gates0 5>,
-				 <&clk_gates0 5>, <&clk_gates0 5>,
-				 <&clk_gates0 4>, <&clk_gates0 5>,
-				 <&clk_gates2 1>, <&clk_gates2 2>,
-				 <&clk_gates2 2>, <&clk_gates2 2>,
-				 <&clk_gates2 2>, <&clk_gates4 5>;
-
-			clock-output-names =
-				"gate_aclk_dmac1", "gate_aclk_dmac2",
-				"gate_pclk_efuse", "gate_pclk_tzpc",
-				"gate_pclk_grf", "gate_pclk_pmu",
-				"gate_hclk_rom", "gate_pclk_ddrupctl",
-				"gate_aclk_smc", "gate_hclk_nandc",
-				"gate_hclk_mmc0", "gate_hclk_mmc1",
-				"gate_hclk_emmc", "gate_hclk_otg0";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates6: gate-clk at 200000e8 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000e8 0x4>;
-			clocks = <&clk_gates3 0>, <&clk_gates0 4>,
-				 <&clk_gates0 4>, <&clk_gates1 4>,
-				 <&clk_gates0 4>, <&clk_gates3 0>,
-				 <&dummy>, <&dummy>,
-				 <&clk_gates3 0>, <&clk_gates0 4>,
-				 <&clk_gates0 4>, <&clk_gates1 4>,
-				 <&clk_gates0 4>, <&clk_gates3 0>;
-
-			clock-output-names =
-				"gate_aclk_lcdc0", "gate_hclk_lcdc0",
-				"gate_hclk_lcdc1", "gate_aclk_lcdc1",
-				"gate_hclk_cif0", "gate_aclk_cif0",
-				"reserved", "reserved",
-				"gate_aclk_ipp", "gate_hclk_ipp",
-				"gate_hclk_rga", "gate_aclk_rga",
-				"gate_hclk_vio_bus", "gate_aclk_vio0";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates7: gate-clk at 200000ec {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000ec 0x4>;
-			clocks = <&clk_gates2 2>, <&clk_gates0 4>,
-				 <&clk_gates0 4>, <&dummy>,
-				 <&dummy>, <&clk_gates2 2>,
-				 <&clk_gates2 2>, <&clk_gates0 5>,
-				 <&dummy>, <&clk_gates0 5>,
-				 <&clk_gates0 5>, <&clk_gates2 3>,
-				 <&clk_gates2 3>, <&clk_gates2 3>,
-				 <&clk_gates2 3>, <&clk_gates2 3>;
-
-			clock-output-names =
-				"gate_hclk_emac", "gate_hclk_spdif",
-				"gate_hclk_i2s0_2ch", "gate_hclk_otg1",
-				"gate_hclk_hsic", "gate_hclk_hsadc",
-				"gate_hclk_pidf", "gate_pclk_timer0",
-				"reserved", "gate_pclk_timer2",
-				"gate_pclk_pwm01", "gate_pclk_pwm23",
-				"gate_pclk_spi0", "gate_pclk_spi1",
-				"gate_pclk_saradc", "gate_pclk_wdt";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates8: gate-clk at 200000f0 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000f0 0x4>;
-			clocks = <&clk_gates0 5>, <&clk_gates0 5>,
-				 <&clk_gates2 3>, <&clk_gates2 3>,
-				 <&clk_gates0 5>, <&clk_gates0 5>,
-				 <&clk_gates2 3>, <&clk_gates2 3>,
-				 <&clk_gates2 3>, <&clk_gates0 5>,
-				 <&clk_gates0 5>, <&clk_gates0 5>,
-				 <&clk_gates2 3>, <&dummy>;
-
-			clock-output-names =
-				"gate_pclk_uart0", "gate_pclk_uart1",
-				"gate_pclk_uart2", "gate_pclk_uart3",
-				"gate_pclk_i2c0", "gate_pclk_i2c1",
-				"gate_pclk_i2c2", "gate_pclk_i2c3",
-				"gate_pclk_i2c4", "gate_pclk_gpio0",
-				"gate_pclk_gpio1", "gate_pclk_gpio2",
-				"gate_pclk_gpio3", "gate_aclk_gps";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates9: gate-clk at 200000f4 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000f4 0x4>;
-			clocks = <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>;
-
-			clock-output-names =
-				"gate_clk_core_dbg", "gate_pclk_dbg",
-				"gate_clk_trace", "gate_atclk",
-				"gate_clk_l2c", "gate_aclk_vio1",
-				"gate_pclk_publ", "gate_aclk_gpu";
-
-			#clock-cells = <1>;
-		};
-	};
-
-};
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index c248748..ef231f8 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -17,7 +17,6 @@
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/clock/rk3188-cru.h>
 #include "rk3xxx.dtsi"
-#include "rk3188-clocks.dtsi"
 
 / {
 	compatible = "rockchip,rk3188";
-- 
1.9.0

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

end of thread, other threads:[~2014-04-16 16:46 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-16 16:36 [PATCH 00/11] Add real clock support for Rockchip's RK3188 Heiko Stübner
2014-04-16 16:37 ` [PATCH 01/11] clk: divider: add CLK_DIVIDER_READ_ONLY flag Heiko Stübner
2014-04-16 16:38 ` [PATCH 02/11] clk: rockchip: add basic infrastructure Heiko Stübner
2014-04-16 16:38 ` [PATCH 03/11] clk: rockchip: add clock type for pll clocks and pll used on rk3066 Heiko Stübner
2014-04-16 16:39 ` [PATCH 04/11] clk: rockchip: add special cpu clock type Heiko Stübner
2014-04-16 16:40 ` [PATCH 05/11] clk: rockchip: add reset controller Heiko Stübner
2014-04-16 16:42 ` [PATCH 06/11] dt-bindings: add documentation for rk3188 clock and reset unit Heiko Stübner
2014-04-16 16:42   ` Heiko Stübner
2014-04-16 16:43 ` [PATCH 07/11] clk: rockchip: add clock driver for rk3188 clocks Heiko Stübner
2014-04-16 16:44 ` [PATCH 08/11] ARM: rockchip: Select ARCH_HAS_RESET_CONTROLLER Heiko Stübner
2014-04-16 16:44 ` [PATCH 09/11] ARM: dts: rk3188: add cru node and update device clocks to use it Heiko Stübner
2014-04-16 16:45 ` [PATCH 10/11] ARM: dts: rockchip: move rk3188 core input clocks into main dtsi Heiko Stübner
2014-04-16 16:46 ` [PATCH 11/11] ARM: dts: rockchip: remove the now obsolete rk3188-clocks.dtsi Heiko Stübner

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