Add real clock support for Rockchip's RK3188
Subsystems (5)
Heiko Stübner
maintainerv3 cover Add real clock support for Rockchip's RK3188
This series add a clock driver infrastructure for Rockchip SoCs in general and clock-definitions for the RK3188 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.
This series depends on the patch adding the CLK_DIVIDER_READ_ONLY flag Thomas Abraham reposted today.
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)
@Max: due to the quite deep changes I didn't keep your tags, so re-tag please if you feel they're still appropriate :-)
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 (10):
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 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 | 59 +++ arch/arm/boot/dts/rk3188-clocks.dtsi | 289 ----------- arch/arm/boot/dts/rk3188.dtsi | 59 ++- arch/arm/mach-rockchip/Kconfig | 1 + drivers/clk/clk-composite.c | 60 ++- drivers/clk/rockchip/Makefile | 5 + drivers/clk/rockchip/clk-pll.c | 430 ++++++++++++++++ drivers/clk/rockchip/clk-rk3188.c | 561 +++++++++++++++++++++ drivers/clk/rockchip/clk.c | 238 +++++++++ drivers/clk/rockchip/clk.h | 339 +++++++++++++ drivers/clk/rockchip/softrst.c | 115 +++++ include/dt-bindings/clock/rk3188-cru.h | 78 +++ 12 files changed, 1933 insertions(+), 301 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-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
Signature · 1 line
1.9.0
Heiko Stübner
maintainerPATCH v3 1/11 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.
--- drivers/clk/clk-composite.c | 51 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-)
drivers/clk/clk-composite.c +50 -1
@@ -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
PATCH v3 1/11 clk: composite: support determine_rate using rate_ops->round_rate + mux_ops->set_parent
Hello Heiko,
Quoted 6 lines · Heiko St?bner
From: Boris BREZILLON <[email protected]>
In case the
rate_hwdoes not implementdetermine_rate, but onlyround_ratewe fallback tobest_parentselection ifmux_hwis present and support reparenting.
Quoted 6 lines
Signed-off-by Boris BREZILLON <[email protected]>This also fixes a rate calculation problem when using the standard div and mux ops, as in this case currently only the
mux->determine_rateis used in the composite rate calculation.
[fixed the output to actually return a rate instead of the diff]
Sorry for the delay and thanks for fixing this.
Anyway, when I first proposed this patch, Emilio (added in Cc) told me this should not be automatically done by the composite clk driver, and the driver should instead provide the determine_rate function.
Mike, any opinion on this patch ?
Best Regards,
Boris
Quoted 79 lines
Signed-off-by Heiko Stuebner <[email protected]>--- drivers/clk/clk-composite.c | 51 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-)drivers/clk/clk-composite.c +50
-1@@ -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 · 3 lines
Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
Heiko Stübner
maintainerPATCH v3 1/11 clk: composite: support determine_rate using rate_ops->round_rate + mux_ops->set_parent
Am Montag, 26. Mai 2014, 11:24:44 schrieb Boris BREZILLON:
Quoted 16 lines
Hello Heiko,
Quoted 6 lines · Heiko St?bner
From: Boris BREZILLON <[email protected]>
In case the
rate_hwdoes not implementdetermine_rate, but onlyround_ratewe fallback tobest_parentselection ifmux_hwis present and support reparenting.Quoted 6 lines
Signed-off-by Boris BREZILLON <[email protected]>This also fixes a rate calculation problem when using the standard div and mux ops, as in this case currently only the
mux->determine_rateis used in the composite rate calculation.
[fixed the output to actually return a rate instead of the diff]
Quoted 5 lines
Sorry for the delay and thanks for fixing this.
Anyway, when I first proposed this patch, Emilio (added in Cc) told me this should not be automatically done by the composite clk driver, and the driver should instead provide the
determine_ratefunction.
Just to point out, as I'm not sure if it comes across correctly from my description above, it looks like the composite behaviour is currently broken when using the standard mux and div ops for it.
As only mux_ops provides a determine rate callback, it will always only run
mux_ops->determine_rate
thus returning the parent rate as the target rate.
So when the parents are 600 and 891 MHz and you want 75MHz [which the divider can provide], the clock would always be set to 600MHz, which may be way out of spec - as seen on my rk3188 clock tree.
When looking at the other composite users, only st/clkgen-mux.c uses the same pattern with both the standard mux and div operations. I've added Gabriel, maybe he can check what happens on his arch, when an affected clock is changed.
Quoted 30 lines
Mike, any opinion on this patch ?
Best Regards,
Boris
Quoted 24 lines
Signed-off-by Heiko Stuebner <[email protected]>---
drivers/clk/clk-composite.c | 51++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-)
drivers/clk/clk-composite.c +6
-0@@ -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;
Quoted 4 lines
drivers/clk/clk-composite.c static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
Quoted 4 lines
drivers/clk/clk-composite.c +0
-0if (rate_hw && rate_ops && rate_ops->determine_rate) { rate_hw->clk = hw->clk; return rate_ops->determine_rate(rate_hw, rate,
best_parent_rate,
Quoted 57 lines
Quoted 57 lines
drivers/clk/clk-composite.c +42
-0best_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,>
drivers/clk/clk-composite.c +0
-0composite->rate_hw = rate_hw; composite->rate_ops = rate_ops; clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
Quoted 5 lines
drivers/clk/clk-composite.c struct clk *clk_register_composite(struct device *dev, const char *name,
Quoted 5 lines
drivers/clk/clk-composite.c +2
-1-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;
Quoted 2 lines
Quoted 2 lines
}
PATCH v3 1/11 clk: composite: support determine_rate using rate_ops->round_rate + mux_ops->set_parent
Hi Heiko,
Quoted 21 lines · Heiko St?bner
Am Montag, 26. Mai 2014, 11:24:44 schrieb Boris BREZILLON:
Quoted 15 lines
Hello Heiko,
Quoted 6 lines · Heiko St?bner
From: Boris BREZILLON <[email protected]>
In case the
rate_hwdoes not implementdetermine_rate, but onlyround_ratewe fallback tobest_parentselection ifmux_hwis present and support reparenting.Quoted 6 lines
Signed-off-by Boris BREZILLON <[email protected]>This also fixes a rate calculation problem when using the standard div and mux ops, as in this case currently only the
mux->determine_rateis used in the composite rate calculation.
[fixed the output to actually return a rate instead of the diff]Quoted 5 lines
Sorry for the delay and thanks for fixing this.
Anyway, when I first proposed this patch, Emilio (added in Cc) told me this should not be automatically done by the composite clk driver, and the driver should instead provide the
determine_ratefunction.
Quoted 7 lines
Just to point out, as I'm not sure if it comes across correctly from my description above, it looks like the composite behaviour is currently broken when using the standard mux and div ops for it.
As only
mux_opsprovides a determine rate callback, it will always only runmux_ops->determine_ratethus returning the parent rate as the target rate.
YesI saw this regression for me later, i had planned to propose a correction this patch is therefore highly welcome.
Thanks !
Quoted 8 lines
So when the parents are 600 and 891 MHz and you want 75MHz [which the divider can provide], the clock would always be set to 600MHz, which may be way out of spec - as seen on my rk3188 clock tree.
When looking at the other composite users, only
st/clkgen-mux.cuses the same pattern with both the standard mux and div operations. I've added Gabriel, maybe he can check what happens on his arch, when an affected clock is changed.
I tested this use case with the patch, the good parent is selected (600 Mhz) and make the
division to have 75 Mhz.
But if CLK_SET_RATE_PARENT is set, it will take the 981 Mhz clock and recalculate the parent rate
(because the diff rate is equal or a little better than the 600 Mhz clock)
Which is a shame, all child clocks are affected.
It was the best choice to choose other parent and do just a division (not recalculate the parent rate)
Best Regards
Gabriel.
Quoted 7 lines
Quoted 7 lines
Mike, any opinion on this patch ?
Best Regards,
Boris
Heiko Stübner
maintainerPATCH v3 2/11 clk: composite: allow read-only clocks
In reply to Heiko StübnerThis 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
@@ -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
Heiko Stübner
maintainerPATCH v3 3/11 clk: rockchip: add basic infrastructure for clock branches
In reply to Heiko StübnerThis 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 | 203 ++++++++++++++++++++++++++++++++++ drivers/clk/rockchip/clk.h | 251 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 455 insertions(+) create mode 100644 drivers/clk/rockchip/clk.c create mode 100644 drivers/clk/rockchip/clk.h
drivers/clk/rockchip/Makefile +1 -0
@@ -3,3 +3,4 @@ # obj-y += clk-rockchip.o +obj-y += clk.o
drivers/clk/rockchip/clk.c new file +203 -0
203 lines not on this page · raw message
drivers/clk/rockchip/clk.h new file +251 -0
251 lines not on this page · raw message
Signature · 1 line
1.9.0
Heiko Stübner
maintainerPATCH v3 4/11 clk: rockchip: add clock type for pll clocks and pll used on rk3066
In reply to Heiko StübnerAll 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 | 430 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/rockchip/clk.c | 35 ++++ drivers/clk/rockchip/clk.h | 74 +++++++ 4 files changed, 540 insertions(+) create mode 100644 drivers/clk/rockchip/clk-pll.c
drivers/clk/rockchip/Makefile +1 -0
@@ -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 +430 -0
430 lines not on this page · raw message
drivers/clk/rockchip/clk.c +35 -0
@@ -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 =kzalloc (sizeof (struct clk *) * nr_clks,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
Heiko Stübner
maintainerPATCH v3 5/11 clk: rockchip: add reset controller
In reply to Heiko StübnerAll 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
@@ -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
@@ -322,4 +322,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
Heiko Stübner
maintainerPATCH v3 6/11 dt-bindings: add documentation for rk3188 clock and reset unit
In reply to Heiko StübnerThis add bindings documentation for the clock and reset unit found on rk3188 SoCs from Rockchip.
--- .../bindings/clock/rockchip,rk3188-cru.txt | 59 ++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt
Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt new file +59 -0
@@ -0,0 +1,59 @@ +* 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. +There exist two variants of the rk3188 SoC, the rk3188 and rk3188a, with +slight differences in the pll handling. + +Required Properties: + +- compatible: should be "rockchip,rk3188-cru" or "rockchip,rk3188a-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 dt-bindings/clock/rk3188-cru.h header and can be used +in device tree sources. + +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_hsadc" - external HSADC clock - optional, + - "ext_cif" - 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>; + };
Signature · 1 line
1.9.0
Heiko Stübner
maintainerPATCH v3 7/11 clk: rockchip: add clock driver for rk3188 clocks
In reply to Heiko StübnerThis adds a clock driver that handles the specific muxes, dividers and gates of rk3188 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.
--- drivers/clk/rockchip/Makefile | 2 + drivers/clk/rockchip/clk-rk3188.c | 561 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/rk3188-cru.h | 78 +++++ 3 files changed, 641 insertions(+) create mode 100644 drivers/clk/rockchip/clk-rk3188.c create mode 100644 include/dt-bindings/clock/rk3188-cru.h
drivers/clk/rockchip/Makefile +2 -0
@@ -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 +561 -0
561 lines not on this page · raw message
include/dt-bindings/clock/rk3188-cru.h new file +78 -0
78 lines not on this page · raw message
Signature · 1 line
1.9.0
Heiko Stübner
maintainerPATCH v3 8/11 ARM: rockchip: Select ARCH_HAS_RESET_CONTROLLER
In reply to Heiko StübnerAll 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
@@ -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
Heiko Stübner
maintainerPATCH v3 9/11 ARM: dts: rk3188: add cru node and update device clocks to use it
In reply to Heiko StübnerThis 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.
--- arch/arm/boot/dts/rk3188.dtsi | 46 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-)
arch/arm/boot/dts/rk3188.dtsi +42 -4
@@ -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,41 @@ }; }; + 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>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + pinctrl at 20008000 { compatible = "rockchip,rk3188-pinctrl"; rockchip,grf = <&grf>;
@@ -86,7 +124,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>;
@@ -99,7 +137,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>;
@@ -112,7 +150,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>;
@@ -125,7 +163,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>;
Signature · 1 line
1.9.0
Heiko Stübner
maintainerPATCH v3 10/11 ARM: dts: rockchip: move rk3188 core input clocks into main dtsi
In reply to Heiko StübnerThe 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.
As we do now provide all necessary clocks, the dummy clock can go away too.
--- arch/arm/boot/dts/rk3188-clocks.dtsi | 18 ------------------ arch/arm/boot/dts/rk3188.dtsi | 12 ++++++++++++ 2 files changed, 12 insertions(+), 18 deletions(-)
arch/arm/boot/dts/rk3188-clocks.dtsi +0 -18
@@ -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>;
arch/arm/boot/dts/rk3188.dtsi +12 -0
@@ -52,6 +52,18 @@ }; }; + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + xin24m: xin24m { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + #clock-cells = <0>; + }; + }; + soc { global-timer at 1013c200 { interrupts = <GIC_PPI 11 0xf04>;
Signature · 1 line
1.9.0
Heiko Stübner
maintainerPATCH v3 11/11 ARM: dts: rockchip: remove the now obsolete rk3188-clocks.dtsi
In reply to Heiko StübnerThe clocks.dtsi does not contain any meaningful data anymore and can thus go away, as all clocks are now handled in the main dtsi.
--- 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
arch/arm/boot/dts/rk3188-clocks.dtsi deleted +0 -271
@@ -1,271 +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; - - 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>; - }; - }; - -};
arch/arm/boot/dts/rk3188.dtsi +0 -1
@@ -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