Skip to contentSkip to conversation

Clock support for rk3066,rk3188 and rk3288

PATCH Superseded Heiko Stübner 4 participants 20 messages Jun 22, 2014 – Jul 1, 2014

Subsystems (5)

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Heiko Stübner

author maintainer
#0 lore raw

v4 cover Clock support for rk3066,rk3188 and rk3288

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

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.

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.

A big change is the move from declaring all mux/dividers/gates individually to declaring them as composite clock branches, making the code better readable and making it possible to keep clocks together in a more natural order.

The changes under drivers/clk apply cleanly to clk-next but the changes in arm/boot/dts require patches from arm-soc, so in the unlikely case of this making it in before the merge window the dts patches should go through arm-soc (or should do so anyway, as they do not directly depend on the drivers/clk changes)

changes since v3:
- add rk3288 clock controller
- add reset controller ids
- fix some incorrect values in rk3188-cru and export some more clocks
- fold new rk3066 clock tree into the rk3188 one, as can be easily seen the differences are not really big between them
- expand the composite fix description to highlight the underlying issue changes since v2:
- drop the special cpuclk type until coordinated range changes matured, as mentioned in the Samsung cpufreq thread.
- add the patch from Boris BREZILLON that reenables correct rate calculations in composite clocks
- change pll handling to better handle the pll output mux and also the enabling/disabling of the pll clock
- change core code to handle composite clock branches instead of individual basic clock definitions
- use the newly defined GRF syscon instead of mapping a grf register individually
changes since v1:
- adapt to apply on current clk-next branch
- add saradc clock
- add rk3188a cru, which has a slightly different handling of one pll value (bwadj)

Boris BREZILLON (1):
clk: composite: support determine_rate using rate_ops->round_rate +

    mux_ops->set_parent

Heiko Stuebner (12):
clk: composite: allow read-only clocks
clk: rockchip: add basic infrastructure for clock branches
clk: rockchip: add clock type for pll clocks and pll used on rk3066
clk: rockchip: add reset controller
dt-bindings: add documentation for rk3188 clock and reset unit
clk: rockchip: add clock driver for rk3188 and rk3066 clocks
ARM: rockchip: Select ARCH_HAS_RESET_CONTROLLER
ARM: dts: rockchip: add cru nodes and update device clocks to use it
ARM: dts: rockchip: move oscillator input clock into main dtsi
arm: dts: rockchip: remove obsolete clock gate definitions
clk: rockchip: add clock controller for rk3288
dt-bindings: add documentation for rk3288 cru

 .../bindings/clock/rockchip,rk3188-cru.txt         |  61 ++
 .../bindings/clock/rockchip,rk3288-cru.txt         |  61 ++
 .../devicetree/bindings/clock/rockchip.txt         |   3 +
 arch/arm/boot/dts/rk3066a-clocks.dtsi              | 299 ---------
 arch/arm/boot/dts/rk3066a.dtsi                     |  30 +-
 arch/arm/boot/dts/rk3188-clocks.dtsi               | 289 ---------
 arch/arm/boot/dts/rk3188.dtsi                      |  19 +-
 arch/arm/boot/dts/rk3xxx.dtsi                      |  22 +-
 arch/arm/mach-rockchip/Kconfig                     |   1 +
 drivers/clk/clk-composite.c                        |  60 +-
 drivers/clk/rockchip/Makefile                      |   6 +
 drivers/clk/rockchip/clk-pll.c                     | 431 +++++++++++++
 drivers/clk/rockchip/clk-rk3188.c                  | 672 +++++++++++++++++++
 drivers/clk/rockchip/clk-rk3288.c                  | 717 +++++++++++++++++++++
 drivers/clk/rockchip/clk.c                         | 237 +++++++
 drivers/clk/rockchip/clk.h                         | 347 ++++++++++
 drivers/clk/rockchip/softrst.c                     | 115 ++++
 include/dt-bindings/clock/rk3066a-cru.h            |  35 +
 include/dt-bindings/clock/rk3188-cru-common.h      | 249 +++++++
 include/dt-bindings/clock/rk3188-cru.h             |  51 ++
 include/dt-bindings/clock/rk3288-cru.h             | 278 ++++++++
 21 files changed, 3365 insertions(+), 618 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt
 create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt
 delete mode 100644 arch/arm/boot/dts/rk3066a-clocks.dtsi
 delete mode 100644 arch/arm/boot/dts/rk3188-clocks.dtsi
 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-rk3288.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/rk3066a-cru.h
 create mode 100644 include/dt-bindings/clock/rk3188-cru-common.h
 create mode 100644 include/dt-bindings/clock/rk3188-cru.h
 create mode 100644 include/dt-bindings/clock/rk3288-cru.h
Signature · 1 line
1.9.0
author maintainer
#1 lore raw

PATCH v4 1/13 clk: composite: support determine_rate using rate_ops->round_rate + mux_ops->set_parent

From: Boris BREZILLON <[email protected]>

In case the rate_hw does not implement determine_rate, but only round_rate we fallback to best_parent selection if mux_hw is present and support reparenting.

This also fixes a rate calculation problem when using the standard div and mux ops, as in this case currently only the mux->determine_rate is used in the composite rate calculation.
So when for example the composite clock has two parents at 600 and 800MHz, the requested rate is 75MHz, which the divider could provide, without this change the rate would be set 600MHz ignoring the divider completely. This may be way out of spec for the component.

[fixed the output to actually return a rate instead of the diff]
---
 drivers/clk/clk-composite.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)
drivers/clk/clk-composite.c +50 -1
index 57a078e..0a4cd21 100644
@@ -64,11 +64,59 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
 	const struct clk_ops *mux_ops = composite->mux_ops;
 	struct clk_hw *rate_hw = composite->rate_hw;
 	struct clk_hw *mux_hw = composite->mux_hw;
+	struct clk *parent;
+	unsigned long parent_rate;
+	long tmp_rate, best_rate;
+	unsigned long rate_diff;
+	unsigned long best_rate_diff = ULONG_MAX;
+	int i;
 
 	if (rate_hw && rate_ops && rate_ops->determine_rate) {
 		rate_hw->clk = hw->clk;
 		return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
 						best_parent_p);
+	} else if (rate_hw && rate_ops && rate_ops->round_rate &&
+		   mux_hw && mux_ops && mux_ops->set_parent) {
+		*best_parent_p = NULL;
+
+		if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) {
+			*best_parent_p = clk_get_parent(mux_hw->clk);
+			*best_parent_rate = __clk_get_rate(*best_parent_p);
+
+			return rate_ops->round_rate(rate_hw, rate,
+						    best_parent_rate);
+		}
+
+		for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) {
+			parent = clk_get_parent_by_index(mux_hw->clk, i);
+			if (!parent)
+				continue;
+
+			parent_rate = __clk_get_rate(parent);
+
+			tmp_rate = rate_ops->round_rate(rate_hw, rate,
+							&parent_rate);
+			if (tmp_rate < 0)
+				continue;
+
+			if (tmp_rate < rate)
+				rate_diff = rate - tmp_rate;
+			else
+				rate_diff = tmp_rate - rate;
+
+			if (!rate_diff || !*best_parent_p
+				       || best_rate_diff > rate_diff) {
+				*best_parent_p = parent;
+				*best_parent_rate = parent_rate;
+				best_rate_diff = rate_diff;
+				best_rate = tmp_rate;
+			}
+
+			if (!rate_diff)
+				return rate;
+		}
+
+		return best_rate;
 	} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
 		mux_hw->clk = hw->clk;
 		return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
@@ -196,7 +244,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
 		composite->rate_hw = rate_hw;
 		composite->rate_ops = rate_ops;
 		clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
-		if (rate_ops->determine_rate)
+		if (rate_ops->determine_rate ||
+		    (rate_ops->round_rate && clk_composite_ops->set_parent))
 			clk_composite_ops->determine_rate = clk_composite_determine_rate;
 	}
 
Signature · 1 line
1.9.0
#2 lore raw

PATCH v4 1/13 clk: composite: support determine_rate using rate_ops->round_rate + mux_ops->set_parent

Hi Heiko,

Seems to be good, tested on stih416 board.

Only small remarks below

Best Regards

Gabriel.

Quoted 59 lines · Heiko St?bner

From: Boris BREZILLON <[email protected]>

In case the rate_hw does not implement determine_rate, but only round_rate we fallback to best_parent selection if mux_hw is present and support reparenting.

This also fixes a rate calculation problem when using the standard div and mux ops, as in this case currently only the mux->determine_rate is used in the composite rate calculation.
So when for example the composite clock has two parents at 600 and 800MHz, the requested rate is 75MHz, which the divider could provide, without this change the rate would be set 600MHz ignoring the divider completely. This may be way out of spec for the component.

[fixed the output to actually return a rate instead of the diff]
---
 drivers/clk/clk-composite.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)
drivers/clk/clk-composite.c +24 -0
index 57a078e..0a4cd21 100644
@@ -64,11 +64,59 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
        const struct clk_ops *mux_ops = composite->mux_ops;
        struct clk_hw *rate_hw = composite->rate_hw;
        struct clk_hw *mux_hw = composite->mux_hw;
+       struct clk *parent;
+       unsigned long parent_rate;
+       long tmp_rate, best_rate;
+       unsigned long rate_diff;
+       unsigned long best_rate_diff = ULONG_MAX;
+       int i;
 
        if (rate_hw && rate_ops && rate_ops->determine_rate) {
                rate_hw->clk = hw->clk;
                return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
                                                best_parent_p);
+       } else if (rate_hw && rate_ops && rate_ops->round_rate &&
+                  mux_hw && mux_ops && mux_ops->set_parent) {
+               *best_parent_p = NULL;
+
+               if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) {
+                       *best_parent_p = clk_get_parent(mux_hw->clk);
+                       *best_parent_rate = __clk_get_rate(*best_parent_p);
+
+                       return rate_ops->round_rate(rate_hw, rate,
+                                                   best_parent_rate);
+               }
+
+               for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) {
+                       parent = clk_get_parent_by_index(mux_hw->clk, i);
+                       if (!parent)
+                               continue;
+
+                       parent_rate = __clk_get_rate(parent);

drivers/clk/clk-composite.c static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, · line 105

Quoted 10 lines
drivers/clk/clk-composite.c +10 -0
+
+                       tmp_rate = rate_ops->round_rate(rate_hw, rate,
+                                                       &parent_rate);
+                       if (tmp_rate < 0)
+                               continue;
+
+                       if (tmp_rate < rate)
+                               rate_diff = rate - tmp_rate;
+                       else
+                               rate_diff = tmp_rate - rate;

rate_dif = abs(rate - tmp_rate) is not better ?

Quoted 4 lines
drivers/clk/clk-composite.c +4 -0
+
+                       if (!rate_diff || !*best_parent_p
+                                      || best_rate_diff > rate_diff) {
+                               *best_parent_p = parent;

drivers/clk/clk-composite.c static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, · line 119

Quoted 10 lines
drivers/clk/clk-composite.c +10 -0
+                               *best_parent_rate = parent_rate;
+                               best_rate_diff = rate_diff;
+                               best_rate = tmp_rate;
+                       }
+
+                       if (!rate_diff)
+                               return rate;
+               }
+
+               return best_rate;

warning compilation: 'best_rate' may be used uninitialized in this function

Quoted 22 lines
drivers/clk/clk-composite.c +2 -2
        } else if (mux_hw && mux_ops && mux_ops->determine_rate) {
                mux_hw->clk = hw->clk;
                return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
@@ -196,7 +244,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
                composite->rate_hw = rate_hw;
                composite->rate_ops = rate_ops;
                clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
-               if (rate_ops->determine_rate)
+               if (rate_ops->determine_rate ||
+                   (rate_ops->round_rate && clk_composite_ops->set_parent))
                        clk_composite_ops->determine_rate = clk_composite_determine_rate;
        }
 
--

1.9.0

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

author maintainer
#3 lore raw

PATCH v4 1/13 clk: composite: support determine_rate using rate_ops->round_rate + mux_ops->set_parent

In case the rate_hw does not implement determine_rate, but only round_rate we fallback to best_parent selection if mux_hw is present and support reparenting.

This also fixes a rate calculation problem when using the standard div and mux ops, as in this case currently only the mux->determine_rate is used in the composite rate calculation.
So when for example the composite clock has two parents at 600 and 800MHz, the requested rate is 75MHz, which the divider could provide, without this change the rate would be set 600MHz ignoring the divider completely. This may be way out of spec for the component.

[fixed the output to actually return a rate instead of the diff]

---
changes since v4:
- address comments from Gabriel Fernandez
- use abs()
- init best_rate

 drivers/clk/clk-composite.c | 48 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)
drivers/clk/clk-composite.c +47 -1
index 57a078e..9548bfc 100644
@@ -64,11 +64,56 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
 	const struct clk_ops *mux_ops = composite->mux_ops;
 	struct clk_hw *rate_hw = composite->rate_hw;
 	struct clk_hw *mux_hw = composite->mux_hw;
+	struct clk *parent;
+	unsigned long parent_rate;
+	long tmp_rate, best_rate = 0;
+	unsigned long rate_diff;
+	unsigned long best_rate_diff = ULONG_MAX;
+	int i;
 
 	if (rate_hw && rate_ops && rate_ops->determine_rate) {
 		rate_hw->clk = hw->clk;
 		return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
 						best_parent_p);
+	} else if (rate_hw && rate_ops && rate_ops->round_rate &&
+		   mux_hw && mux_ops && mux_ops->set_parent) {
+		*best_parent_p = NULL;
+
+		if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) {
+			*best_parent_p = clk_get_parent(mux_hw->clk);
+			*best_parent_rate = __clk_get_rate(*best_parent_p);
+
+			return rate_ops->round_rate(rate_hw, rate,
+						    best_parent_rate);
+		}
+
+		for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) {
+			parent = clk_get_parent_by_index(mux_hw->clk, i);
+			if (!parent)
+				continue;
+
+			parent_rate = __clk_get_rate(parent);
+
+			tmp_rate = rate_ops->round_rate(rate_hw, rate,
+							&parent_rate);
+			if (tmp_rate < 0)
+				continue;
+
+			rate_diff = abs(rate - tmp_rate);
+
+			if (!rate_diff || !*best_parent_p
+				       || best_rate_diff > rate_diff) {
+				*best_parent_p = parent;
+				*best_parent_rate = parent_rate;
+				best_rate_diff = rate_diff;
+				best_rate = tmp_rate;
+			}
+
+			if (!rate_diff)
+				return rate;
+		}
+
+		return best_rate;
 	} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
 		mux_hw->clk = hw->clk;
 		return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
@@ -196,7 +241,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
 		composite->rate_hw = rate_hw;
 		composite->rate_ops = rate_ops;
 		clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
-		if (rate_ops->determine_rate)
+		if (rate_ops->determine_rate ||
+		    (rate_ops->round_rate && clk_composite_ops->set_parent))
 			clk_composite_ops->determine_rate = clk_composite_determine_rate;
 	}
 
Signature · 1 line
1.9.0
author maintainer
#4 lore raw

PATCH v4 1/13 clk: composite: support determine_rate using rate_ops->round_rate + mux_ops->set_parent

In reply to Gabriel Fernandez

From: Boris BREZILLON <[email protected]>

In case the rate_hw does not implement determine_rate, but only round_rate we fallback to best_parent selection if mux_hw is present and support reparenting.

This also fixes a rate calculation problem when using the standard div and mux ops, as in this case currently only the mux->determine_rate is used in the composite rate calculation.
So when for example the composite clock has two parents at 600 and 800MHz, the requested rate is 75MHz, which the divider could provide, without this change the rate would be set 600MHz ignoring the divider completely. This may be way out of spec for the component.

[fixed the output to actually return a rate instead of the diff]

---
changes since v4.1:
- forgot the From override, Boris is the original author

changes since v4:
- address comments from Gabriel Fernandez
- use abs()
- init best_rate

 drivers/clk/clk-composite.c | 48 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)
drivers/clk/clk-composite.c +47 -1
index 57a078e..9548bfc 100644
@@ -64,11 +64,56 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
 	const struct clk_ops *mux_ops = composite->mux_ops;
 	struct clk_hw *rate_hw = composite->rate_hw;
 	struct clk_hw *mux_hw = composite->mux_hw;
+	struct clk *parent;
+	unsigned long parent_rate;
+	long tmp_rate, best_rate = 0;
+	unsigned long rate_diff;
+	unsigned long best_rate_diff = ULONG_MAX;
+	int i;
 
 	if (rate_hw && rate_ops && rate_ops->determine_rate) {
 		rate_hw->clk = hw->clk;
 		return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
 						best_parent_p);
+	} else if (rate_hw && rate_ops && rate_ops->round_rate &&
+		   mux_hw && mux_ops && mux_ops->set_parent) {
+		*best_parent_p = NULL;
+
+		if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) {
+			*best_parent_p = clk_get_parent(mux_hw->clk);
+			*best_parent_rate = __clk_get_rate(*best_parent_p);
+
+			return rate_ops->round_rate(rate_hw, rate,
+						    best_parent_rate);
+		}
+
+		for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) {
+			parent = clk_get_parent_by_index(mux_hw->clk, i);
+			if (!parent)
+				continue;
+
+			parent_rate = __clk_get_rate(parent);
+
+			tmp_rate = rate_ops->round_rate(rate_hw, rate,
+							&parent_rate);
+			if (tmp_rate < 0)
+				continue;
+
+			rate_diff = abs(rate - tmp_rate);
+
+			if (!rate_diff || !*best_parent_p
+				       || best_rate_diff > rate_diff) {
+				*best_parent_p = parent;
+				*best_parent_rate = parent_rate;
+				best_rate_diff = rate_diff;
+				best_rate = tmp_rate;
+			}
+
+			if (!rate_diff)
+				return rate;
+		}
+
+		return best_rate;
 	} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
 		mux_hw->clk = hw->clk;
 		return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
@@ -196,7 +241,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
 		composite->rate_hw = rate_hw;
 		composite->rate_ops = rate_ops;
 		clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
-		if (rate_ops->determine_rate)
+		if (rate_ops->determine_rate ||
+		    (rate_ops->round_rate && clk_composite_ops->set_parent))
 			clk_composite_ops->determine_rate = clk_composite_determine_rate;
 	}
 
Signature · 1 line
1.9.0
author maintainer
#5 lore raw

PATCH v4 2/13 clk: composite: allow read-only clocks

In reply to Heiko Stübner

This allows readl-only composite clocks by making mux_ops->set_parent and divider_ops->round_rate/set_rate optional.

---
 drivers/clk/clk-composite.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
drivers/clk/clk-composite.c +3 -6
index 0a4cd21..046d3f6 100644
@@ -210,7 +210,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
 	clk_composite_ops = &composite->ops;
 
 	if (mux_hw && mux_ops) {
-		if (!mux_ops->get_parent || !mux_ops->set_parent) {
+		if (!mux_ops->get_parent) {
 			clk = ERR_PTR(-EINVAL);
 			goto err;
 		}
@@ -218,7 +218,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
 		composite->mux_hw = mux_hw;
 		composite->mux_ops = mux_ops;
 		clk_composite_ops->get_parent = clk_composite_get_parent;
-		clk_composite_ops->set_parent = clk_composite_set_parent;
+		if (mux_ops->set_parent)
+			clk_composite_ops->set_parent = clk_composite_set_parent;
 		if (mux_ops->determine_rate)
 			clk_composite_ops->determine_rate = clk_composite_determine_rate;
 	}
@@ -235,10 +236,6 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
 			if (rate_ops->set_rate) {
 				clk_composite_ops->set_rate = clk_composite_set_rate;
 			}
-		} else {
-			WARN(rate_ops->set_rate,
-				"%s: missing round_rate op is required\n",
-				__func__);
 		}
 
 		composite->rate_hw = rate_hw;
Signature · 1 line
1.9.0
#6 lore raw

PATCH v4 2/13 clk: composite: allow read-only clocks

Quoting Heiko St?bner (2014-06-22 13:43:35)

Quoted 32 lines

This allows readl-only composite clocks by making mux_ops->set_parent and divider_ops->round_rate/set_rate optional.

---
 drivers/clk/clk-composite.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
drivers/clk/clk-composite.c +3 -2
index 0a4cd21..046d3f6 100644
@@ -210,7 +210,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
        clk_composite_ops = &composite->ops;
 
        if (mux_hw && mux_ops) {
-               if (!mux_ops->get_parent || !mux_ops->set_parent) {
+               if (!mux_ops->get_parent) {
                        clk = ERR_PTR(-EINVAL);
                        goto err;
                }
@@ -218,7 +218,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
                composite->mux_hw = mux_hw;
                composite->mux_ops = mux_ops;
                clk_composite_ops->get_parent = clk_composite_get_parent;
-               clk_composite_ops->set_parent = clk_composite_set_parent;
+               if (mux_ops->set_parent)
+                       clk_composite_ops->set_parent = clk_composite_set_parent;
                if (mux_ops->determine_rate)
                        clk_composite_ops->determine_rate = clk_composite_determine_rate;
        }

drivers/clk/clk-composite.c struct clk *clk_register_composite(struct device *dev, const char *name, · line 241

Quoted 7 lines
drivers/clk/clk-composite.c +0 -4
@@ -235,10 +236,6 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
                        if (rate_ops->set_rate) {
                                clk_composite_ops->set_rate = clk_composite_set_rate;
                        }
-               } else {
-                       WARN(rate_ops->set_rate,
-                               "%s: missing round_rate op is required\n",
-                               __func__);

Getting rid of this WARN isn't such a great solution. How about rolling in the following cleanup?

Quoted 1 line

From 03a08d7e746aedc6ce99228d629752f241383e7f Mon Sep 17 00:00:00 2001

From: Mike Turquette <[email protected]>
Date: Tue, 1 Jul 2014 12:11:38 -0700
Subject: [PATCH] clk: composite: improve rate_hw sanity check logic

The function pointer population and sanity checking logic got a bit ugly with the advent of the .determine_rate callback. Clean it up.

---
 drivers/clk/clk-composite.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)
drivers/clk/clk-composite.c +16 -10
index faf7c32..bdf4f2b 100644
@@ -226,21 +226,27 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
 			clk = ERR_PTR(-EINVAL);
 			goto err;
 		}
+		clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
 
-		/* .round_rate is a prerequisite for .set_rate */
-		if (rate_ops->round_rate) {
-			clk_composite_ops->round_rate = clk_composite_round_rate;
-			if (rate_ops->set_rate) {
-				clk_composite_ops->set_rate = clk_composite_set_rate;
-			}
+		if (rate_ops->determine_rate)
+			clk_composite_ops->determine_rate =
+				clk_composite_determine_rate;
+		else if (rate_ops->round_rate)
+			clk_composite_ops->round_rate =
+				clk_composite_round_rate;
+
+		/* .set_rate requires either .round_rate or .determine_rate */
+		if (rate_ops->set_rate) {
+			if (rate_ops->determine_rate || rate_ops->round_rate)
+				clk_composite_ops->set_rate =
+					clk_composite_set_rate;
+			else
+				WARN(1, "%s: missing round_rate op is required\n",
+						__func__);
 		}
 
 		composite->rate_hw = rate_hw;
 		composite->rate_ops = rate_ops;
-		clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
-		if (rate_ops->determine_rate ||
-		    (rate_ops->round_rate && clk_composite_ops->set_parent))
-			clk_composite_ops->determine_rate = clk_composite_determine_rate;
 	}
 
 	if (gate_hw && gate_ops) {
Signature · 1 line
1.8.3.2
author maintainer
#7 lore raw

PATCH v4 3/13 clk: rockchip: add basic infrastructure for clock branches

In reply to Heiko Stübner

This adds infrastructure for registering clock branches. On Rockchip SoCs most clock branches are a combination of mux,divider and gate components, thus a composite clock is used when appropriate.

Clock branches are supposed to be declared in an array using the COMPOSITE* or MUX, etc makros defined in the header and then registered using rockchip_clk_register_branches.

---
 drivers/clk/rockchip/Makefile |   1 +
 drivers/clk/rockchip/clk.c    | 202 ++++++++++++++++++++++++++++++++++
 drivers/clk/rockchip/clk.h    | 250 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 453 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk.c
 create mode 100644 drivers/clk/rockchip/clk.h
drivers/clk/rockchip/Makefile +1 -0
index 8d3aefa..0068a8b 100644
@@ -3,3 +3,4 @@
 #
 
 obj-y	+= clk-rockchip.o
+obj-y	+= clk.o
drivers/clk/rockchip/clk.c new file +202 -0

202 lines not on this page · raw message

drivers/clk/rockchip/clk.h new file +250 -0

250 lines not on this page · raw message

Signature · 1 line
1.9.0
#8 lore raw

PATCH v4 3/13 clk: rockchip: add basic infrastructure for clock branches

Quoting Heiko St?bner (2014-06-22 13:44:07)

drivers/clk/rockchip/clk.c line 133

Quoted 5 lines
drivers/clk/rockchip/clk.c new file +5 -0
+void __init rockchip_clk_register_branches(
+                                     struct rockchip_clk_branch *list,
+                                     unsigned int nr_clk)
+{
+       struct clk *clk;

clk should be initialized to NULL here, otherwise I get a warning down below ...

Quoted 51 lines
drivers/clk/rockchip/clk.c new file +51 -0
+       unsigned int idx;
+       unsigned long flags;
+
+       for (idx = 0; idx < nr_clk; idx++, list++) {
+               flags = list->flags;
+
+               /* catch simple muxes */
+               switch (list->branch_type) {
+               case branch_mux:
+                       clk = clk_register_mux(NULL, list->name,
+                               list->parent_names, list->num_parents,
+                               flags, reg_base + list->muxdiv_offset,
+                               list->mux_shift, list->mux_width,
+                               list->mux_flags, &clk_lock);
+                       break;
+               case branch_divider:
+                       if (list->div_table)
+                               clk = clk_register_divider_table(NULL,
+                                       list->name, list->parent_names[0],
+                                       flags, reg_base + list->muxdiv_offset,
+                                       list->div_shift, list->div_width,
+                                       list->div_flags, list->div_table,
+                                       &clk_lock);
+                       else
+                               clk = clk_register_divider(NULL, list->name,
+                                       list->parent_names[0], flags,
+                                       reg_base + list->muxdiv_offset,
+                                       list->div_shift, list->div_width,
+                                       list->div_flags, &clk_lock);
+                       break;
+               case branch_fraction_divider:
+                       /* unimplemented */
+                       continue;
+                       break;
+               case branch_gate:
+                       flags |= CLK_SET_RATE_PARENT;
+
+                       /* keep all gates untouched for now */
+                       flags |= CLK_IGNORE_UNUSED;
+
+                       clk = clk_register_gate(NULL, list->name,
+                               list->parent_names[0], flags,
+                               reg_base + list->gate_offset,
+                               list->gate_shift, list->gate_flags, &clk_lock);
+                       break;
+               case branch_composite:
+                       /* keep all gates untouched for now */
+                       flags |= CLK_IGNORE_UNUSED;
+
+                       clk = rockchip_clk_register_branch(list->name,
+                               list->parent_names, list->num_parents,

drivers/clk/rockchip/clk.c line 194

Quoted 10 lines
drivers/clk/rockchip/clk.c new file +10 -0
+                               reg_base, list->muxdiv_offset, list->mux_shift,
+                               list->mux_width, list->mux_flags,
+                               list->div_shift, list->div_width,
+                               list->div_flags, list->div_table,
+                               list->gate_offset, list->gate_shift,
+                               list->gate_flags, flags, &clk_lock);
+                       break;
+               }
+
+               if (IS_ERR(clk)) {

... here. gcc throws:

"""
drivers/clk/rockchip/clk.c: In function ?rockchip_clk_register_branches?:
include/linux/err.h:35:22: warning: ?clk? may be used uninitialized in this function [-Wmaybe-uninitialized]
return IS_ERR_VALUE((unsigned long)ptr);
"""

Regards,
Mike

Quoted 268 lines
drivers/clk/rockchip/clk.c new file +8 -0
+                       pr_err("%s: failed to register clock %s: %ld\n",
+                              __func__, list->name, PTR_ERR(clk));
+                       continue;
+               }
+
+               rockchip_clk_add_lookup(clk, list->id);
+       }
+}
drivers/clk/rockchip/clk.h new file +250 -0
new file mode 100644
index 0000000..5b051b0
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <[email protected]>
+ *
+ * based on
+ *
+ * samsung/clk.h
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <[email protected]>
+ *
+ * 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 RK2928_MISC_CON                0x134
+
+#define PNAME(x) static const char *x[] __initconst
+
+enum rockchip_clk_branch_type {
+       branch_composite,
+       branch_mux,
+       branch_divider,
+       branch_fraction_divider,
+       branch_gate,
+};
+
+struct rockchip_clk_branch {
+       unsigned int                    id;
+       enum rockchip_clk_branch_type   branch_type;
+       const char                      *name;
+       const char                      **parent_names;
+       u8                              num_parents;
+       unsigned long                   flags;
+       int                             muxdiv_offset;
+       u8                              mux_shift;
+       u8                              mux_width;
+       u8                              mux_flags;
+       u8                              div_shift;
+       u8                              div_width;
+       u8                              div_flags;
+       struct clk_div_table            *div_table;
+       int                             gate_offset;
+       u8                              gate_shift;
+       u8                              gate_flags;
+};
+
+#define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\
+                 df, go, gs, gf)                               \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_composite,             \
+               .name           = cname,                        \
+               .parent_names   = pnames,                       \
+               .num_parents    = ARRAY_SIZE(pnames),           \
+               .flags          = f,                            \
+               .muxdiv_offset  = mo,                           \
+               .mux_shift      = ms,                           \
+               .mux_width      = mw,                           \
+               .mux_flags      = mf,                           \
+               .div_shift      = ds,                           \
+               .div_width      = dw,                           \
+               .div_flags      = df,                           \
+               .gate_offset    = go,                           \
+               .gate_shift     = gs,                           \
+               .gate_flags     = gf,                           \
+       }
+
+#define COMPOSITE_NOMUX(_id, cname, pname, f, mo, ds, dw, df,  \
+                       go, gs, gf)                             \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_composite,             \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .muxdiv_offset  = mo,                           \
+               .div_shift      = ds,                           \
+               .div_width      = dw,                           \
+               .div_flags      = df,                           \
+               .gate_offset    = go,                           \
+               .gate_shift     = gs,                           \
+               .gate_flags     = gf,                           \
+       }
+
+#define COMPOSITE_NOMUX_DIVTBL(_id, cname, pname, f, mo, ds, dw,\
+                              df, dt, go, gs, gf)              \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_composite,             \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .muxdiv_offset  = mo,                           \
+               .div_shift      = ds,                           \
+               .div_width      = dw,                           \
+               .div_flags      = df,                           \
+               .div_table      = dt,                           \
+               .gate_offset    = go,                           \
+               .gate_shift     = gs,                           \
+               .gate_flags     = gf,                           \
+       }
+
+#define COMPOSITE_NODIV(_id, cname, pnames, f, mo, ms, mw, mf, \
+                       go, gs, gf)                             \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_composite,             \
+               .name           = cname,                        \
+               .parent_names   = pnames,                       \
+               .num_parents    = ARRAY_SIZE(pnames),           \
+               .flags          = f,                            \
+               .muxdiv_offset  = mo,                           \
+               .mux_shift      = ms,                           \
+               .mux_width      = mw,                           \
+               .mux_flags      = mf,                           \
+               .gate_offset    = go,                           \
+               .gate_shift     = gs,                           \
+               .gate_flags     = gf,                           \
+       }
+
+#define COMPOSITE_NOGATE(_id, cname, pnames, f, mo, ms, mw, mf,        \
+                        ds, dw, df)                            \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_composite,             \
+               .name           = cname,                        \
+               .parent_names   = pnames,                       \
+               .num_parents    = ARRAY_SIZE(pnames),           \
+               .flags          = f,                            \
+               .muxdiv_offset  = mo,                           \
+               .mux_shift      = ms,                           \
+               .mux_width      = mw,                           \
+               .mux_flags      = mf,                           \
+               .div_shift      = ds,                           \
+               .div_width      = dw,                           \
+               .div_flags      = df,                           \
+               .gate_offset    = -1,                           \
+       }
+
+#define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_fraction_divider,      \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .muxdiv_offset  = mo,                           \
+               .div_shift      = 16,                           \
+               .div_width      = 16,                           \
+               .div_flags      = df,                           \
+               .gate_offset    = go,                           \
+               .gate_shift     = gs,                           \
+               .gate_flags     = gf,                           \
+       }
+
+#define MUX(_id, cname, pnames, f, o, s, w, mf)                        \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_mux,                   \
+               .name           = cname,                        \
+               .parent_names   = pnames,                       \
+               .num_parents    = ARRAY_SIZE(pnames),           \
+               .flags          = f,                            \
+               .muxdiv_offset  = o,                            \
+               .mux_shift      = s,                            \
+               .mux_width      = w,                            \
+               .mux_flags      = mf,                           \
+               .gate_offset    = -1,                           \
+       }
+
+#define DIV(_id, cname, pname, f, o, s, w, df)                 \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_divider,               \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .muxdiv_offset  = o,                            \
+               .div_shift      = s,                            \
+               .div_width      = w,                            \
+               .div_flags      = df,                           \
+               .gate_offset    = -1,                           \
+       }
+
+#define DIVTBL(_id, cname, pname, f, o, s, w, df, dt)          \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_divider,               \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .muxdiv_offset  = o,                            \
+               .div_shift      = s,                            \
+               .div_width      = w,                            \
+               .div_flags      = df,                           \
+               .div_table      = dt,                           \
+       }
+
+#define GATE(_id, cname, pname, f, o, b, gf)                   \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_gate,                  \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .gate_offset    = o,                            \
+               .gate_shift     = 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_branches(struct rockchip_clk_branch *clk_list,
+                                   unsigned int nr_clk);
+
+#endif
Signature · 1 line
1.9.0
author maintainer
#9 lore raw

PATCH v4 4/13 clk: rockchip: add clock type for pll clocks and pll used on rk3066

In reply to Heiko Stübner

All known Rockchip SoCs down to the RK28xx (ARM9) use a similar pattern to handle their plls:

                       |--\
xin32k ----------------|mux\
xin24m -----| pll |----|pll|--- pll output
       \---------------|src/
                       |--/

The pll output is sourced from 1 of 3 sources, the actual pll being one of them. To change the pll frequency it is imperative to remux it to another source beforehand. This is done by adding a clock-listener to the pll that handles the remuxing before and after the rate change.

The output mux is implemented as a separate clock to make use of already existing common-clock features for disabling the pll if one of the other two sources is used.

---
 drivers/clk/rockchip/Makefile  |   1 +
 drivers/clk/rockchip/clk-pll.c | 431 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/rockchip/clk.c     |  35 ++++
 drivers/clk/rockchip/clk.h     |  74 +++++++
 4 files changed, 541 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk-pll.c
drivers/clk/rockchip/Makefile +1 -0
index 0068a8b..2cb9164 100644
@@ -4,3 +4,4 @@
 
 obj-y	+= clk-rockchip.o
 obj-y	+= clk.o
+obj-y	+= clk-pll.o
drivers/clk/rockchip/clk-pll.c new file +431 -0

431 lines not on this page · raw message

drivers/clk/rockchip/clk.c +35 -0
index 0bffa1b..44abcce 100644
@@ -23,6 +23,8 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 #include "clk.h"
 
 /**
@@ -105,11 +107,15 @@ static DEFINE_SPINLOCK(clk_lock);
 static struct clk **clk_table;
 static void __iomem *reg_base;
 static struct clk_onecell_data clk_data;
+static struct device_node *cru_node;
+static struct regmap *grf;
 
 void __init rockchip_clk_init(struct device_node *np, void __iomem *base,
 			      unsigned long nr_clks)
 {
 	reg_base = base;
+	cru_node = np;
+	grf = ERR_PTR(-EPROBE_DEFER);
 
 	clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
 	if (!clk_table)
@@ -120,12 +126,41 @@ void __init rockchip_clk_init(struct device_node *np, void __iomem *base,
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
 
+struct regmap *rockchip_clk_get_grf(void)
+{
+	if (IS_ERR(grf))
+		grf = syscon_regmap_lookup_by_phandle(cru_node, "rockchip,grf");
+	return grf;
+}
+
 void rockchip_clk_add_lookup(struct clk *clk, unsigned int id)
 {
 	if (clk_table && id)
 		clk_table[id] = clk;
 }
 
+void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list,
+				unsigned int nr_pll, int grf_lock_offset)
+{
+	struct clk *clk;
+	int idx;
+
+	for (idx = 0; idx < nr_pll; idx++, list++) {
+		clk = rockchip_clk_register_pll(list->type, list->name,
+				list->parent_names, list->num_parents,
+				reg_base, list->con_offset, grf_lock_offset,
+				list->lock_shift, list->mode_offset,
+				list->mode_shift, list->rate_table, &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_branches(
 				      struct rockchip_clk_branch *list,
 				      unsigned int nr_clk)
drivers/clk/rockchip/clk.h +74 -0

88 lines not on this page · raw message

Signature · 1 line
1.9.0
author maintainer
#10 lore raw

PATCH v4 5/13 clk: rockchip: add reset controller

In reply to Heiko Stübner

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, similar to the other HIWORD_MASK flags used in the clock framework.

---
 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
drivers/clk/rockchip/Makefile +1 -0
index 2cb9164..85f8a55 100644
@@ -5,3 +5,4 @@
 obj-y	+= clk-rockchip.o
 obj-y	+= clk.o
 obj-y	+= clk-pll.o
+obj-$(CONFIG_RESET_CONTROLLER)	+= softrst.o
drivers/clk/rockchip/clk.h +14 -0
index fb7ce85..32c334d 100644
@@ -321,4 +321,18 @@ void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list,
 void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list,
 				unsigned int nr_pll, int grf_lock_offset);
 
+#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
drivers/clk/rockchip/softrst.c new file +115 -0

115 lines not on this page · raw message

Signature · 1 line
1.9.0
author maintainer
#11 lore raw

PATCH v4 6/13 dt-bindings: add documentation for rk3188 clock and reset unit

In reply to Heiko Stübner

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

Also deprecate the old gate clock binding, as these shouldn't be used in the future.

---
 .../bindings/clock/rockchip,rk3188-cru.txt         | 61 ++++++++++++++++++++++
 .../devicetree/bindings/clock/rockchip.txt         |  3 ++
 2 files changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt
Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt new file +61 -0
new file mode 100644
index 0000000..0c2bf5e
@@ -0,0 +1,61 @@
+* Rockchip RK3188/RK3066 Clock and Reset Unit
+
+The RK3188/RK3066 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", "rockchip,rk3188a-cru" or
+			"rockchip,rk3066a-cru"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Optional Properties:
+
+- rockchip,grf: phandle to the syscon managing the "general register files"
+  If missing pll rates are not changable, due to the missing pll lock status.
+
+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 the dt-bindings/clock/rk3188-cru.h and
+dt-bindings/clock/rk3066-cru.h headers and can be used in device tree sources.
+Similar macros exist for the reset sources in these files.
+
+External clocks:
+
+There are several clocks that are generated outside the SoC. It is expected
+that they are defined using standard clock bindings with following
+clock-output-names:
+ - "xin24m" - crystal input - required,
+ - "xin32k" - rtc clock - optional,
+ - "xin27m" - 27mhz crystal input on rk3066 - optional,
+ - "ext_hsadc" - external HSADC clock - optional,
+ - "ext_cif0" - external camera clock - optional,
+ - "ext_rmii" - external RMII clock - optional,
+ - "ext_jtag" - externalJTAG clock - optional
+
+Example: Clock controller node:
+
+	cru: cru at 20000000 {
+		compatible = "rockchip,rk3188-cru";
+		reg = <0x20000000 0x1000>;
+		rockchip,grf = <&grf>;
+
+		#clock-cells = <1>;
+		#reset-cells = <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>;
+	};
Documentation/devicetree/bindings/clock/rockchip.txt +3 -0
index a891c82..22f6769 100644
@@ -6,6 +6,9 @@ This binding uses the common clock binding[1].
 
 == Gate clocks ==
 
+These bindings are deprecated!
+Please use the soc specific CRU bindings instead.
+
 The gate registers form a continuos block which makes the dt node
 structure a matter of taste, as either all gates can be put into
 one gate clock spanning all registers or they can be divided into
Signature · 1 line
1.9.0
author maintainer
#12 lore raw

PATCH v4 7/13 clk: rockchip: add clock driver for rk3188 and rk3066 clocks

In reply to Heiko Stübner

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

The structure of the clock list resembles the arrangement of their counterparts in the clock architecture diagrams found in the SoC documentation.

Clocks exported to the clock provider are currently limited to well known or measured ones. So additional clock exports may be necessary in the future.

---
 drivers/clk/rockchip/Makefile                 |   2 +
 drivers/clk/rockchip/clk-rk3188.c             | 672 ++++++++++++++++++++++++++
 include/dt-bindings/clock/rk3066a-cru.h       |  35 ++
 include/dt-bindings/clock/rk3188-cru-common.h | 249 ++++++++++
 include/dt-bindings/clock/rk3188-cru.h        |  51 ++
 5 files changed, 1009 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk-rk3188.c
 create mode 100644 include/dt-bindings/clock/rk3066a-cru.h
 create mode 100644 include/dt-bindings/clock/rk3188-cru-common.h
 create mode 100644 include/dt-bindings/clock/rk3188-cru.h
drivers/clk/rockchip/Makefile +2 -0
index 85f8a55..3eebf72 100644
@@ -6,3 +6,5 @@ obj-y	+= clk-rockchip.o
 obj-y	+= clk.o
 obj-y	+= clk-pll.o
 obj-$(CONFIG_RESET_CONTROLLER)	+= softrst.o
+
+obj-y	+= clk-rk3188.o
drivers/clk/rockchip/clk-rk3188.c new file +672 -0

672 lines not on this page · raw message

include/dt-bindings/clock/rk3066a-cru.h new file +35 -0
new file mode 100644
index 0000000..bc1ed1d
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <[email protected]>
+ *
+ * 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 <dt-bindings/clock/rk3188-cru-common.h>
+
+/* soft-reset indices */
+#define SRST_SRST1		0
+#define SRST_SRST2		1
+
+#define SRST_L2MEM		18
+#define SRST_I2S0		23
+#define SRST_I2S1		24
+#define SRST_I2S2		25
+#define SRST_TIMER2		29
+
+#define SRST_GPIO4		36
+#define SRST_GPIO6		38
+
+#define SRST_TSADC		92
+
+#define SRST_HDMI		96
+#define SRST_HDMI_APB		97
+#define SRST_CIF1		111
include/dt-bindings/clock/rk3188-cru-common.h new file +249 -0

249 lines not on this page · raw message

include/dt-bindings/clock/rk3188-cru.h new file +51 -0

51 lines not on this page · raw message

Signature · 1 line
1.9.0
author maintainer
#13 lore raw

PATCH v4 8/13 ARM: rockchip: Select ARCH_HAS_RESET_CONTROLLER

In reply to Heiko Stübner

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.

---
 arch/arm/mach-rockchip/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/arm/mach-rockchip/Kconfig +1 -0
index 1caee6d..e4564c2 100644
@@ -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
Signature · 1 line
1.9.0
author maintainer
#14 lore raw

PATCH v4 9/13 ARM: dts: rockchip: add cru nodes and update device clocks to use it

In reply to Heiko Stübner

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

---
 arch/arm/boot/dts/rk3066a.dtsi | 29 ++++++++++++++++++++---------
 arch/arm/boot/dts/rk3188.dtsi  | 18 ++++++++++++++----
 arch/arm/boot/dts/rk3xxx.dtsi  | 16 ++++++++--------
 3 files changed, 42 insertions(+), 21 deletions(-)
arch/arm/boot/dts/rk3066a.dtsi +20 -9
index 4387cfd..0b36514 100644
@@ -15,6 +15,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/clock/rk3066a-cru.h>
 #include "rk3xxx.dtsi"
 #include "rk3066a-clocks.dtsi"
 
@@ -45,7 +46,7 @@
 			compatible = "snps,dw-apb-timer-osc";
 			reg = <0x20038000 0x100>;
 			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clk_gates1 0>, <&clk_gates7 7>;
+			clocks = <&cru SCLK_TIMER0>, <&cru PCLK_TIMER0>;
 			clock-names = "timer", "pclk";
 		};
 
@@ -53,7 +54,7 @@
 			compatible = "snps,dw-apb-timer-osc";
 			reg = <0x2003a000 0x100>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clk_gates1 1>, <&clk_gates7 8>;
+			clocks = <&cru SCLK_TIMER1>, <&cru PCLK_TIMER1>;
 			clock-names = "timer", "pclk";
 		};
 
@@ -61,7 +62,7 @@
 			compatible = "snps,dw-apb-timer-osc";
 			reg = <0x2000e000 0x100>;
 			interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clk_gates1 2>, <&clk_gates7 9>;
+			clocks = <&cru SCLK_TIMER2>, <&cru PCLK_TIMER2>;
 			clock-names = "timer", "pclk";
 		};
 
@@ -78,6 +79,16 @@
 			};
 		};
 
+		cru: cru at 20000000 {
+			compatible = "rockchip,rk3066a-cru";
+			reg = <0x20000000 0x1000>;
+
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+
+			rockchip,grf = <&grf>;
+		};
+
 		pinctrl at 20008000 {
 			compatible = "rockchip,rk3066a-pinctrl";
 			rockchip,grf = <&grf>;
@@ -89,7 +100,7 @@
 				compatible = "rockchip,gpio-bank";
 				reg = <0x20034000 0x100>;
 				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk_gates8 9>;
+				clocks = <&cru PCLK_GPIO0>;
 
 				gpio-controller;
 				#gpio-cells = <2>;
@@ -102,7 +113,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>;
@@ -115,7 +126,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>;
@@ -128,7 +139,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>;
@@ -141,7 +152,7 @@
 				compatible = "rockchip,gpio-bank";
 				reg = <0x20084000 0x100>;
 				interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk_gates8 13>;
+				clocks = <&cru PCLK_GPIO4>;
 
 				gpio-controller;
 				#gpio-cells = <2>;
@@ -154,7 +165,7 @@
 				compatible = "rockchip,gpio-bank";
 				reg = <0x2000a000 0x100>;
 				interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk_gates8 15>;
+				clocks = <&cru PCLK_GPIO6>;
 
 				gpio-controller;
 				#gpio-cells = <2>;
arch/arm/boot/dts/rk3188.dtsi +14 -4
index 238c996..d77bc94 100644
@@ -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"
 
@@ -74,6 +75,15 @@
 			};
 		};
 
+		cru: cru at 20000000 {
+			compatible = "rockchip,rk3188-cru";
+			reg = <0x20000000 0x1000>;
+			rockchip,grf = <&grf>;
+
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+		};
+
 		pinctrl at 20008000 {
 			compatible = "rockchip,rk3188-pinctrl";
 			rockchip,grf = <&grf>;
@@ -87,7 +97,7 @@
 				compatible = "rockchip,rk3188-gpio-bank0";
 				reg = <0x2000a000 0x100>;
 				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk_gates8 9>;
+				clocks = <&cru PCLK_GPIO0>;
 
 				gpio-controller;
 				#gpio-cells = <2>;
@@ -100,7 +110,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 +123,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 +136,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>;
arch/arm/boot/dts/rk3xxx.dtsi +8 -8
index 2adf1cc9e..b47d5fe 100644
@@ -60,14 +60,14 @@
 			compatible = "arm,cortex-a9-global-timer";
 			reg = <0x1013c200 0x20>;
 			interrupts = <GIC_PPI 11 0x304>;
-			clocks = <&dummy150m>;
+			clocks = <&cru CORE_PERI>;
 		};
 
 		local-timer at 1013c600 {
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0x1013c600 0x20>;
 			interrupts = <GIC_PPI 13 0x304>;
-			clocks = <&dummy150m>;
+			clocks = <&cru CORE_PERI>;
 		};
 
 		uart0: serial at 10124000 {
@@ -76,7 +76,7 @@
 			interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <1>;
-			clocks = <&clk_gates1 8>;
+			clocks = <&cru SCLK_UART0>;
 			status = "disabled";
 		};
 
@@ -86,7 +86,7 @@
 			interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <1>;
-			clocks = <&clk_gates1 10>;
+			clocks = <&cru SCLK_UART1>;
 			status = "disabled";
 		};
 
@@ -96,7 +96,7 @@
 			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <1>;
-			clocks = <&clk_gates1 12>;
+			clocks = <&cru SCLK_UART2>;
 			status = "disabled";
 		};
 
@@ -106,7 +106,7 @@
 			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <1>;
-			clocks = <&clk_gates1 14>;
+			clocks = <&cru SCLK_UART3>;
 			status = "disabled";
 		};
 
@@ -117,7 +117,7 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 
-			clocks = <&clk_gates5 10>, <&clk_gates2 11>;
+			clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>;
 			clock-names = "biu", "ciu";
 
 			status = "disabled";
@@ -130,7 +130,7 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 
-			clocks = <&clk_gates5 11>, <&clk_gates2 13>;
+			clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>;
 			clock-names = "biu", "ciu";
 
 			status = "disabled";
Signature · 1 line
1.9.0
author maintainer
#15 lore raw

PATCH v4 10/13 ARM: dts: rockchip: move oscillator input clock into main dtsi

In reply to Heiko Stübner

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

---
 arch/arm/boot/dts/rk3066a-clocks.dtsi | 6 ------
 arch/arm/boot/dts/rk3188-clocks.dtsi  | 6 ------
 arch/arm/boot/dts/rk3xxx.dtsi         | 6 ++++++
 3 files changed, 6 insertions(+), 12 deletions(-)
arch/arm/boot/dts/rk3066a-clocks.dtsi +0 -6
index 6e307fc..0d4d667 100644
@@ -31,12 +31,6 @@
 			#clock-cells = <0>;
 		};
 
-		xin24m: xin24m {
-			compatible = "fixed-clock";
-			clock-frequency = <24000000>;
-			#clock-cells = <0>;
-		};
-
 		dummy48m: dummy48m {
 			compatible = "fixed-clock";
 			clock-frequency = <48000000>;
arch/arm/boot/dts/rk3188-clocks.dtsi +0 -6
index b1b92dc..6bc0373 100644
@@ -31,12 +31,6 @@
 			#clock-cells = <0>;
 		};
 
-		xin24m: xin24m {
-			compatible = "fixed-clock";
-			clock-frequency = <24000000>;
-			#clock-cells = <0>;
-		};
-
 		dummy48m: dummy48m {
 			compatible = "fixed-clock";
 			clock-frequency = <48000000>;
arch/arm/boot/dts/rk3xxx.dtsi +6 -0
index b47d5fe..0de3f06 100644
@@ -26,6 +26,12 @@
 		compatible = "simple-bus";
 		ranges;
 
+		xin24m: xin24m {
+			compatible = "fixed-clock";
+			clock-frequency = <24000000>;
+			#clock-cells = <0>;
+		};
+
 		scu at 1013c000 {
 			compatible = "arm,cortex-a9-scu";
 			reg = <0x1013c000 0x100>;
Signature · 1 line
1.9.0
author maintainer
#16 lore raw

PATCH v4 11/13 arm: dts: rockchip: remove obsolete clock gate definitions

In reply to Heiko Stübner

The clock and reset unit is now provided by the rk3188-cru clock driver and thus the old style definitions of the gate clocks can go away.

---
 arch/arm/boot/dts/rk3066a-clocks.dtsi | 293 ----------------------------------
 arch/arm/boot/dts/rk3066a.dtsi        |   1 -
 arch/arm/boot/dts/rk3188-clocks.dtsi  | 283 --------------------------------
 arch/arm/boot/dts/rk3188.dtsi         |   1 -
 4 files changed, 578 deletions(-)
 delete mode 100644 arch/arm/boot/dts/rk3066a-clocks.dtsi
 delete mode 100644 arch/arm/boot/dts/rk3188-clocks.dtsi
arch/arm/boot/dts/rk3066a-clocks.dtsi deleted +0 -293
deleted file mode 100644
index 0d4d667..0000000
@@ -1,293 +0,0 @@
-/*
- * Copyright (c) 2013 MundoReader S.L.
- * Author: Heiko Stuebner <[email protected]>
- *
- * 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;
-
-		/*
-		 * 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>;
-		};
-
-		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 = <&dummy>, <&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_i2s0",
-				"gate_i2s0_frac", "gate_i2s1",
-				"gate_i2s1_frac", "gate_i2s2",
-				"gate_i2s2_frac", "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_timer2", "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", "gate_tsadc";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates3: gate-clk at 200000dc {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000dc 0x4>;
-			clocks = <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>;
-
-			clock-output-names =
-				"gate_aclk_lcdc0_src", "gate_dclk_lcdc0",
-				"gate_dclk_lcdc1", "gate_pclkin_cif0",
-				"gate_pclkin_cif1", "reserved",
-				"reserved", "gate_cif0_out",
-				"gate_cif1_out", "gate_aclk_vepu",
-				"gate_hclk_vepu", "gate_aclk_vdpu",
-				"gate_hclk_vdpu", "gate_gpu_src",
-				"reserved", "gate_xin27m";
-
-			#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>, <&clk_gates0 3>,
-				 <&clk_gates0 3>, <&clk_gates2 3>,
-				 <&clk_gates0 4>;
-
-			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", "gate_aclk_l2mem_con",
-				"gate_aclk_intmem", "gate_pclk_tsadc",
-				"gate_hclk_hdmi";
-
-			#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>,
-				 <&clk_gates4 5>, <&dummy>;
-
-			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",
-				"gate_hclk_otg1", "gate_aclk_gpu";
-
-			#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>,
-				 <&clk_gates0 4>, <&clk_gates1 4>,
-				 <&clk_gates3 0>, <&clk_gates0 4>,
-				 <&clk_gates0 4>, <&clk_gates1 4>,
-				 <&clk_gates0 4>, <&clk_gates3 0>,
-				 <&dummy>, <&dummy>;
-
-			clock-output-names =
-				"gate_aclk_lcdc0", "gate_hclk_lcdc0",
-				"gate_hclk_lcdc1", "gate_aclk_lcdc1",
-				"gate_hclk_cif0", "gate_aclk_cif0",
-				"gate_hclk_cif1", "gate_aclk_cif1",
-				"gate_aclk_ipp", "gate_hclk_ipp",
-				"gate_hclk_rga", "gate_aclk_rga",
-				"gate_hclk_vio_bus", "gate_aclk_vio0",
-				"gate_aclk_vcodec", "gate_shclk_vio_h2h";
-
-			#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>, <&clk_gates0 4>,
-				 <&clk_gates0 4>, <&clk_gates2 2>,
-				 <&clk_gates2 2>, <&clk_gates0 5>,
-				 <&clk_gates0 5>, <&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_i2s1_2ch",
-				"gate_hclk_i2s_8ch", "gate_hclk_hsadc",
-				"gate_hclk_pidf", "gate_pclk_timer0",
-				"gate_pclk_timer1", "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>, <&clk_gates2 3>,
-				 <&dummy>, <&clk_gates0 5>;
-
-			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_pclk_gpio4",
-				"reserved", "gate_pclk_gpio6";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates9: gate-clk at 200000f4 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000f4 0x4>;
-			clocks = <&dummy>, <&clk_gates0 5>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&clk_gates1 4>,
-				 <&clk_gates0 5>, <&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_intmem0",
-				"gate_aclk_intmem1", "gate_aclk_intmem2",
-				"gate_aclk_intmem3";
-
-			#clock-cells = <1>;
-		};
-	};
-
-};
arch/arm/boot/dts/rk3066a.dtsi +0 -1
index 0b36514..b705a60 100644
@@ -17,7 +17,6 @@
 #include <dt-bindings/pinctrl/rockchip.h>
 #include <dt-bindings/clock/rk3066a-cru.h>
 #include "rk3xxx.dtsi"
-#include "rk3066a-clocks.dtsi"
 
 / {
 	compatible = "rockchip,rk3066a";
arch/arm/boot/dts/rk3188-clocks.dtsi deleted +0 -283

283 lines not on this page · raw message

arch/arm/boot/dts/rk3188.dtsi +0 -1
index d77bc94..ddca355 100644
@@ -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";
Signature · 1 line
1.9.0
author maintainer
#17 lore raw

PATCH v4 12/13 clk: rockchip: add clock controller for rk3288

In reply to Heiko Stübner

Add the clock tree definition for the new rk3288 SoC.

---
 drivers/clk/rockchip/Makefile          |   1 +
 drivers/clk/rockchip/clk-rk3288.c      | 717 +++++++++++++++++++++++++++++++++
 drivers/clk/rockchip/clk.h             |   9 +
 include/dt-bindings/clock/rk3288-cru.h | 278 +++++++++++++
 4 files changed, 1005 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk-rk3288.c
 create mode 100644 include/dt-bindings/clock/rk3288-cru.h
drivers/clk/rockchip/Makefile +1 -0
index 3eebf72..ee6b077 100644
@@ -8,3 +8,4 @@ obj-y	+= clk-pll.o
 obj-$(CONFIG_RESET_CONTROLLER)	+= softrst.o
 
 obj-y	+= clk-rk3188.o
+obj-y	+= clk-rk3288.o
drivers/clk/rockchip/clk-rk3288.c new file +717 -0

717 lines not on this page · raw message

drivers/clk/rockchip/clk.h +9 -0
index 32c334d..887cbde 100644
@@ -40,6 +40,15 @@
 #define RK2928_SOFTRST_CON(x)	(x * 0x4 + 0x110)
 #define RK2928_MISC_CON		0x134
 
+#define RK3288_PLL_CON(x)		RK2928_PLL_CON(x)
+#define RK3288_MODE_CON			0x50
+#define RK3288_CLKSEL_CON(x)		(x * 0x4 + 0x60)
+#define RK3288_CLKGATE_CON(x)		(x * 0x4 + 0x160)
+#define RK3288_GLB_SRST_FST		0x1b0
+#define RK3288_GLB_SRST_SND		0x1b4
+#define RK3288_SOFTRST_CON(x)		(x * 0x4 + 0x1b8)
+#define RK3288_MISC_CON			0x1e8
+
 enum rockchip_pll_type {
 	pll_rk3066,
 };
include/dt-bindings/clock/rk3288-cru.h new file +278 -0

278 lines not on this page · raw message

Signature · 1 line
1.9.0
author maintainer
#18 lore raw

PATCH v4 13/13 dt-bindings: add documentation for rk3288 cru

In reply to Heiko Stübner

This adds the dt-binding documentation for the clock and reset unit found on Rockchip rk3288 SoCs.

---
 .../bindings/clock/rockchip,rk3288-cru.txt         | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt
Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt new file +61 -0
new file mode 100644
index 0000000..c9fbb76
@@ -0,0 +1,61 @@
+* Rockchip RK3288 Clock and Reset Unit
+
+The RK3288 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,rk3288-cru"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Optional Properties:
+
+- rockchip,grf: phandle to the syscon managing the "general register files"
+  If missing pll rates are not changable, due to the missing pll lock status.
+
+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 the dt-bindings/clock/rk3288-cru.h headers and can be
+used in device tree sources. Similar macros exist for the reset sources in
+these files.
+
+External clocks:
+
+There are several clocks that are generated outside the SoC. It is expected
+that they are defined using standard clock bindings with following
+clock-output-names:
+ - "xin24m" - crystal input - required,
+ - "xin32k" - rtc clock - optional,
+ - "ext_i2s" - external I2S clock - optional,
+ - "ext_hsadc" - external HSADC clock - optional,
+ - "ext_edp_24m" - external display port clock - optional,
+ - "ext_vip" - external VIP clock - optional,
+ - "ext_isp" - external ISP clock - optional,
+ - "ext_jtag" - external JTAG clock - optional
+
+Example: Clock controller node:
+
+	cru: cru at 20000000 {
+		compatible = "rockchip,rk3188-cru";
+		reg = <0x20000000 0x1000>;
+		rockchip,grf = <&grf>;
+
+		#clock-cells = <1>;
+		#reset-cells = <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>;
+	};
Signature · 1 line
1.9.0
#19 lore raw

v4 cover Clock support for rk3066,rk3188 and rk3288

In reply to Heiko Stübner

Hi Heiko,

Quoted 17 lines · Heiko St?bner

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

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.

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.

A big change is the move from declaring all mux/dividers/gates individually to declaring them as composite clock branches, making the code better readable and making it possible to keep clocks together in a more natural order.

Quoted 5 lines

The changes under drivers/clk apply cleanly to clk-next but the changes in arm/boot/dts require patches from arm-soc, so in the unlikely case of this making it in before the merge window the dts patches should go through arm-soc (or should do so anyway, as they do not directly depend on the drivers/clk changes)

Series:

on Radxa Rock (RK3188).

Cheers,
Max